Skip to content

Commit

Permalink
Merge pull request #228 from moosetechnology/local-resolver
Browse files Browse the repository at this point in the history
Local resolver
  • Loading branch information
NicolasAnquetil authored Mar 8, 2024
2 parents 09f319a + 0fc8c52 commit 9b2743e
Show file tree
Hide file tree
Showing 3 changed files with 274 additions and 99 deletions.
292 changes: 194 additions & 98 deletions src/FAST-Java-Tools-Tests/FASTJavaLocalResolverVisitorTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -13,117 +13,213 @@ FASTJavaLocalResolverVisitorTest >> setUp [
super setUp.

builder := FASTJavaTestNodeBuilder new.
localResolver := FASTLocalResolverVisitor new
localResolver := FASTJavaLocalResolverVisitor new
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testAddNonLocalDeclaration [
"testing helper method #addNonLocalDeclaration:"
localResolver resetScopes.
localResolver pushScope.

localResolver scopeAddNonLocalDeclaration: 'blah'.

"second scope is empty"
self assert: localResolver popScope isEmpty.

"first scope contains NonLocalDeclaration"
self assert: (localResolver findDeclaration: 'blah') class equals: FASTNonLocalDeclaration
FASTJavaLocalResolverVisitorTest >> testBindToDeclaration [
"
void meth() {
int x;
x = 5;
}
"

| varAccess body ast |

ast := FASTJavaMethodEntity new
type: (FASTJavaVoidTypeExpression new name: 'void');
name: 'meth';
statementBlock: (FASTJavaStatementBlock new
statements: {
(FASTJavaVarDeclStatement new
type: (FASTJavaIntTypeExpression new name: 'int');
declarators: { FASTJavaVariableDeclarator new
variable: (FASTJavaVariableExpression new name: 'x') } ;
startPos: 1).
(FASTJavaExpressionStatement new
expression: (FASTJavaAssignmentExpression new
variable: (FASTJavaVariableExpression new name: 'x');
expression: (FASTJavaIntegerLiteral new primitiveValue: '5') ;
operator: '=');
startPos: 2) }).

localResolver on: ast.

body := ast statementBlock statements.
varAccess := body second expression variable.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'x'.
self assert: varAccess localDeclaration equals: body first declarators first.

self assert: body first declarators first localUses size equals: 1
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testFindDeclarationInCurrentScope [
|node|
node := builder declarator: nil init: nil.
localResolver resetScopes.
localResolver scopeAdd: 'blah' declaration: node.

self assert: (localResolver findDeclaration: 'blah') equals: node
FASTJavaLocalResolverVisitorTest >> testBindToLoopVariable [
"
void meth() {
for (int i=1; i<2; i++)
i--;
}
"

| varAccess loop ast |

ast := FASTJavaMethodEntity new
type: (FASTJavaVoidTypeExpression new name: 'void');
name: 'meth' ;
statementBlock: (FASTJavaStatementBlock new
statements: {
(FASTJavaForStatement new
initializer: (FASTJavaVarDeclStatement new
type: (FASTJavaIntTypeExpression new
name: 'int');
declarators: { (FASTJavaVariableDeclarator new
variable: (FASTJavaVariableExpression new
name: 'i');
expression: (FASTJavaIntegerLiteral new
primitiveValue: '1')) });
condition: (FASTJavaInfixOperation new
leftOperand: (FASTJavaVariableExpression new name: 'i');
rightOperand: (FASTJavaIntegerLiteral new primitiveValue: '2');
operator: '<');
incrementor: (FASTJavaExpressionStatement new
expression: (FASTJavaUnaryExpression new
expression: (FASTJavaVariableExpression new name: 'i');
operator: '++'));
body: (FASTJavaExpressionStatement new
expression: (FASTJavaUnaryExpression new
expression: (FASTJavaVariableExpression new name: 'i');
operator: '--'));
startPos: 1) }).

localResolver on: ast.

loop := ast statementBlock statements first.
varAccess := loop condition leftOperand.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'i'.
self assert: varAccess localDeclaration equals: loop initializer declarators first.
varAccess := loop incrementor expression expression.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'i'.
self assert: varAccess localDeclaration equals: loop initializer declarators first.

varAccess := loop body expression expression.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'i'.
self assert: varAccess localDeclaration equals: loop initializer declarators first.

self assert: loop initializer declarators first localUses size equals: 3
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testFindDeclarationInEmptyScope [
localResolver resetScopes.
self assert: (localResolver findDeclaration: 'blah') equals: nil.

FASTJavaLocalResolverVisitorTest >> testBindToParameter [
"
void meth(int x) {
x = 5;
}
"

| varAccess body ast |

ast := FASTJavaMethodEntity new
type: (FASTJavaVoidTypeExpression new name: 'void');
name: 'meth';
parameters: { (FASTJavaParameter new
variable: (FASTJavaVariableExpression new name: 'x');
type: (FASTJavaIntTypeExpression new name: 'int')) };
statementBlock: (FASTJavaStatementBlock new
statements: {
(FASTJavaExpressionStatement new
expression: (FASTJavaAssignmentExpression new
variable: (FASTJavaVariableExpression new name: 'x');
expression: (FASTJavaIntegerLiteral new primitiveValue: '5') ;
operator: '=');
startPos: 2) }).

localResolver on: ast.

body := ast statementBlock statements.
varAccess := body first expression variable.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'x'.
self assert: varAccess localDeclaration equals: ast parameters first
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testFindDeclarationInParentScope [
|node|
node := builder declarator: nil init: nil.
localResolver resetScopes.
localResolver scopeAdd: 'blah' declaration: node.
localResolver pushScope.

self assert: (localResolver findDeclaration: 'blah') equals: node
FASTJavaLocalResolverVisitorTest >> testBindingNotFound [
"
void meth() {
x = 5;
}
"

| varAccess body ast |

ast := FASTJavaMethodEntity new
type: (FASTJavaVoidTypeExpression new name: 'void');
name: 'meth';
statementBlock: (FASTJavaStatementBlock new
statements: {
(FASTJavaExpressionStatement new
expression: (FASTJavaAssignmentExpression new
variable: (FASTJavaVariableExpression new name: 'x');
expression: (FASTJavaIntegerLiteral new primitiveValue: '5') ;
operator: '=');
startPos: 2) }).

localResolver on: ast.

body := ast statementBlock statements.
varAccess := body first expression variable.
self assert: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration name equals: 'x'.
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testFindDeclarationNotInScope [
|node|
node := builder declarator: nil init: nil.
localResolver resetScopes.
localResolver scopeAdd: 'blah' declaration: node.

self assert: (localResolver findDeclaration: 'blih') equals: nil.

]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testHasScopes [
self deny: localResolver hasScopes
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testLocalDeclarationFor [
"testing helper method #localDeclaration:for:"
| declNode refNode |
declNode := builder declarator: nil init: nil.
refNode := builder var: nil.
declNode resetLocalUses.
localResolver localDeclaration: declNode for: refNode.

self assert: refNode localDeclaration notNil.
self assert: refNode localDeclaration equals: declNode.

self assert: declNode localUses size equals: 1.
self assert: declNode localUses first equals: refNode
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testResetScopes [
localResolver resetScopes.
self assert: localResolver hasScopes.

]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testScopeAddDeclarationTwiceRaisesError [
|node|
node := builder declarator: nil init: nil.
localResolver resetScopes.

localResolver scopeAdd: 'blah' declaration: node.

self assert: localResolver currentScope size equals: 1.

self
should: [ localResolver scopeAdd: 'blah' declaration: node ]
raise: DuplicatedVariableError
]

{ #category : #tests }
FASTJavaLocalResolverVisitorTest >> testScopeAddNonLocalDeclarationTwiceRaisesError [
|node|
node := builder declarator: nil init: nil.
localResolver resetScopes.

localResolver scopeAddNonLocalDeclaration: 'blah'.

self assert: localResolver currentScope size equals: 1.

self
should: [ localResolver scopeAddNonLocalDeclaration: 'blah' ]
raise: DuplicatedVariableError
FASTJavaLocalResolverVisitorTest >> testLoopVariableHidesParameter [
"
void meth(int i) {
for (int i=1; ;)
i++;
}
"

| varAccess loop ast |

ast := FASTJavaMethodEntity new
type: (FASTJavaVoidTypeExpression new name: 'void');
name: 'meth' ;
parameters: { (FASTJavaParameter new
variable: (FASTJavaVariableExpression new name: 'i');
type: (FASTJavaIntTypeExpression new name: 'int')) };
statementBlock: (FASTJavaStatementBlock new
statements: {
(FASTJavaForStatement new
initializer: (FASTJavaVarDeclStatement new
type: (FASTJavaIntTypeExpression new
name: 'int');
declarators: { (FASTJavaVariableDeclarator new
variable: (FASTJavaVariableExpression new
name: 'i');
expression: (FASTJavaIntegerLiteral new
primitiveValue: '1')) });
body: (FASTJavaExpressionStatement new
expression: (FASTJavaUnaryExpression new
expression: (FASTJavaVariableExpression new name: 'i');
operator: '++'));
startPos: 1) }).

localResolver on: ast.

loop := ast statementBlock statements first.
varAccess := loop body expression expression.
self deny: varAccess localDeclaration isNonLocalDeclaration.
self assert: varAccess localDeclaration variable name equals: 'i'.
self assert: varAccess localDeclaration equals: loop initializer declarators first.

self assert: loop initializer declarators first localUses size equals: 1.
self assert: ast parameters first localUses size equals: 0
]
2 changes: 1 addition & 1 deletion src/FAST-Java-Tools/FASTJavaExportVisitor.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ FASTJavaExportVisitor >> visitFASTJavaTypeParameter: aFASTJavaTypeParameterExpre
self unindented: ' extends '.
typeArgumentSuperclasses
do: [ :node | node accept: self ]
separatedBy: [ self unindented: ' & ' ]
separatedBy: [ self << ' & ' ]
]
]
]
Expand Down
Loading

0 comments on commit 9b2743e

Please sign in to comment.