Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate if locals/args exist when adding a type declaration #603

Merged
Merged
6 changes: 6 additions & 0 deletions smalltalksrc/Slang-Tests/SLBasicTestDeclarationClass.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Class {
#category : #'Slang-Tests'
}

{ #category : #translation }
SLBasicTestDeclarationClass class >> typeForSelf [

^#implicit
]
Comment on lines +7 to +11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Is it not always implicit (except for structs)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inherited behaviour from SlangClass is to return nil. Or are you saying that at some point that nil defaults to #implicit?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just asking for understanding, because this definition is in the tests, but maybe could be in a more general place? I don't know.
Anyway, it is out of the scope of this PR, so we can continue with our life.


{ #category : #'as yet unclassified' }
SLBasicTestDeclarationClass >> methodWithBlockLocalDeclaration [

Expand Down
16 changes: 16 additions & 0 deletions smalltalksrc/Slang-Tests/SLTestDeclarations.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ SLTestDeclarations >> setUp [
ccg addClass: SLBasicTestDeclarationClass
]

{ #category : #tests }
SLTestDeclarations >> testAddTypeForSelfWithDeclarationsDoesNotThrowError [

| method |
method := ccg methodNamed: #methodWithNonExistingLocalDeclaration.
self shouldnt: [ method addTypeForSelf ] raise: TranslationError
]

{ #category : #tests }
SLTestDeclarations >> testAllLocalsReturnsBlockLocals [

Expand Down Expand Up @@ -69,3 +77,11 @@ SLTestDeclarations >> testLocalsReturnsDirectLocals [
assertCollection: (ccg methodNamed: #methodWithLocal) locals
hasSameElements: #( 'var' )
]

{ #category : #tests }
SLTestDeclarations >> testUndefinedLocalWithDeclarationsThrowsError [

| method |
method := ccg methodNamed: #methodWithNonExistingLocalDeclaration.
self should: [ method recordDeclarationsIn: ccg ] raise: TranslationError
]
114 changes: 75 additions & 39 deletions smalltalksrc/Slang-Tests/SlangBasicTranslationTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -4259,7 +4259,9 @@ SlangBasicTranslationTest >> testSendIntegerObjectOfConstantValue [
SlangBasicTranslationTest >> testSendIntegerObjectOfSignedValue [

| translation send |
generator currentMethod declarationAt: 'var' put: 'long'.

generator currentMethod addLocal: 'var'; declarationAt: 'var' put: 'long'.

send := TSendNode new
setSelector: #integerObjectOf:
receiver: (TVariableNode named: 'self')
Expand All @@ -4273,7 +4275,7 @@ SlangBasicTranslationTest >> testSendIntegerObjectOfSignedValue [
SlangBasicTranslationTest >> testSendIntegerObjectOfUnsignedSmallValue [

| translation send |
generator currentMethod declarationAt: 'var' put: 'unsigned short'.
generator currentMethod addLocal: 'var'; declarationAt: 'var' put: 'unsigned short'.
send := TSendNode new
setSelector: #integerObjectOf:
receiver: (TVariableNode named: 'self')
Expand All @@ -4287,14 +4289,18 @@ SlangBasicTranslationTest >> testSendIntegerObjectOfUnsignedSmallValue [
SlangBasicTranslationTest >> testSendIntegerObjectOfUnsignedValue [

| translation send |
generator currentMethod declarationAt: 'var' put: 'unsigned long'.
generator currentMethod
addLocal: 'var';
declarationAt: 'var' put: 'unsigned long'.
send := TSendNode new
setSelector: #integerObjectOf:
receiver: (TVariableNode named: 'self')
arguments: { TVariableNode named: 'var' }.
setSelector: #integerObjectOf:
receiver: (TVariableNode named: 'self')
arguments: { (TVariableNode named: 'var') }.
translation := self translate: send.

self assert: translation equals: '((var << ', numSmallIntegerTagBits asString, ') | 1)'
self
assert: translation
equals: '((var << ' , numSmallIntegerTagBits asString , ') | 1)'
]

{ #category : #'tests-builtins' }
Expand Down Expand Up @@ -4395,7 +4401,7 @@ SlangBasicTranslationTest >> testSendLeftBitShifNegativeLitteralIntegerOverflow
SlangBasicTranslationTest >> testSendLeftBitShift [

| translation send |
generator currentMethod declarationAt: 'a' put: 'sqInt'.
generator currentMethod addLocal:'a'; declarationAt: 'a' put: 'sqInt'.
send := TSendNode new
setSelector: #<<
receiver: (TVariableNode new setName: 'a')
Expand All @@ -4409,10 +4415,12 @@ SlangBasicTranslationTest >> testSendLeftBitShift [
SlangBasicTranslationTest >> testSendLeftBitShiftByVariable [

| translation send |
generator currentMethod declarationAt: 'a' put: 'unsigned short'.

generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'unsigned short'.

send := TSendNode new
setSelector: #<<
setSelector: #'<<'
PalumboN marked this conversation as resolved.
Show resolved Hide resolved
receiver: (TConstantNode value: 3)
arguments: { (TVariableNode new setName: 'a') }.
translation := self translate: send.
Expand All @@ -4424,9 +4432,11 @@ SlangBasicTranslationTest >> testSendLeftBitShiftByVariable [
SlangBasicTranslationTest >> testSendLeftBitShiftByVariableIn32Bits [

| translation send |
generator currentMethod declarationAt: 'a' put: 'sqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'sqInt'.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TConstantNode value: 3)
arguments: { (TVariableNode new setName: 'a') }.
translation := self translate: send.
Expand All @@ -4438,10 +4448,12 @@ SlangBasicTranslationTest >> testSendLeftBitShiftByVariableIn32Bits [
SlangBasicTranslationTest >> testSendLeftBitShiftByVariableIn64Bits [

| translation send |
generator currentMethod declarationAt: 'a' put: 'sqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'sqInt'.
generator wordSize: 8.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TConstantNode value: 3)
arguments: { (TVariableNode new setName: 'a') }.
translation := self translate: send.
Expand All @@ -4453,9 +4465,11 @@ SlangBasicTranslationTest >> testSendLeftBitShiftByVariableIn64Bits [
SlangBasicTranslationTest >> testSendLeftBitShiftLong [

| translation send |
generator currentMethod declarationAt: 'a' put: 'sqLong'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'sqLong'.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand All @@ -4467,9 +4481,11 @@ SlangBasicTranslationTest >> testSendLeftBitShiftLong [
SlangBasicTranslationTest >> testSendLeftBitShiftShortType [

| translation send |
generator currentMethod declarationAt: 'a' put: 'short'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'short'.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand All @@ -4481,9 +4497,11 @@ SlangBasicTranslationTest >> testSendLeftBitShiftShortType [
SlangBasicTranslationTest >> testSendLeftBitShiftUnsigned [

| translation send |
generator currentMethod declarationAt: 'a' put: 'usqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'usqInt'.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand All @@ -4495,9 +4513,11 @@ SlangBasicTranslationTest >> testSendLeftBitShiftUnsigned [
SlangBasicTranslationTest >> testSendLeftBitShiftUnsignedShortType [

| translation send |
generator currentMethod declarationAt: 'a' put: 'unsigned short'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'unsigned short'.
send := TSendNode new
setSelector: #<<
setSelector: #'<<'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand Down Expand Up @@ -4729,17 +4749,21 @@ SlangBasicTranslationTest >> testSendPerformWith [
SlangBasicTranslationTest >> testSendPerformWithAccessor [

| translation send |
generator currentMethod declarationAt: 'aPrimitiveDescriptor' put: #'PrimitiveDescriptor *'.
generator currentMethod
addLocal: 'aPrimitiveDescriptor';
declarationAt: 'aPrimitiveDescriptor' put: #'PrimitiveDescriptor *'.
send := TSendNode new
setSelector: #perform:
receiver: (TVariableNode named: 'objectRepresentation')
arguments: { TSendNode new
setSelector: #primitiveGenerator
receiver: (TVariableNode named: 'aPrimitiveDescriptor')
arguments: #() }.
arguments: { (TSendNode new
setSelector: #primitiveGenerator
receiver: (TVariableNode named: 'aPrimitiveDescriptor')
arguments: #( )) }.
translation := self translate: send.

self assert: translation equals: '(primitiveGenerator(aPrimitiveDescriptor))()'
self
assert: translation
equals: '(primitiveGenerator(aPrimitiveDescriptor))()'
]

{ #category : #'tests-builtins' }
Expand Down Expand Up @@ -4878,10 +4902,12 @@ SlangBasicTranslationTest >> testSendRepeat [
SlangBasicTranslationTest >> testSendRightBitShiftSignedIn64Bits [

| translation send |
generator currentMethod declarationAt: 'a' put: 'sqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'sqInt'.
generator wordSize: 8.
send := TSendNode new
setSelector: #>>
setSelector: #'>>'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand All @@ -4893,9 +4919,11 @@ SlangBasicTranslationTest >> testSendRightBitShiftSignedIn64Bits [
SlangBasicTranslationTest >> testSendRightBitShiftUnsigned [

| translation send |
generator currentMethod declarationAt: 'a' put: 'usqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'usqInt'.
send := TSendNode new
setSelector: #>>
setSelector: #'>>'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand All @@ -4907,10 +4935,12 @@ SlangBasicTranslationTest >> testSendRightBitShiftUnsigned [
SlangBasicTranslationTest >> testSendRightBitShiftUnsignedIn64Bits [

| translation send |
generator currentMethod declarationAt: 'a' put: 'usqInt'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'usqInt'.
generator wordSize: 8.
send := TSendNode new
setSelector: #>>
setSelector: #'>>'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand Down Expand Up @@ -5178,9 +5208,11 @@ SlangBasicTranslationTest >> testSendSignedIntToShort [
SlangBasicTranslationTest >> testSendSignedRightBitShiftVariable64Bits [

| translation send |
generator currentMethod declarationAt: 'a' put: 'long long'.
generator currentMethod
addLocal: 'a';
declarationAt: 'a' put: 'long long'.
send := TSendNode new
setSelector: #>>>
setSelector: #'>>>'
receiver: (TVariableNode new setName: 'a')
arguments: { (TConstantNode value: 3) }.
translation := self translate: send.
Expand Down Expand Up @@ -6205,7 +6237,9 @@ SlangBasicTranslationTest >> testSwitchStatementInAssignmentAddAssignmentToEndOf
SlangBasicTranslationTest >> testSwitchStatementInAssignmentAddAssignmentToEndOfCasesWithNoDefaultStatement [

| translation |
generator currentMethod declarationAt: 'toto' put: 'int toto'.
generator currentMethod
addLocal: 'toto';
declarationAt: 'toto' put: 'int toto'.
translation := self translate: (TAssignmentNode new
setVariable: (TVariableNode named: 'toto')
expression: (TSwitchStmtNode new
Expand Down Expand Up @@ -6239,7 +6273,9 @@ SlangBasicTranslationTest >> testSwitchStatementInAssignmentAddAssignmentToEndOf
SlangBasicTranslationTest >> testSwitchStatementInAssignmentAddAssignmentToEndOfCasesWithNoDefaultStatementAndAssignmentVariableIsPointer [

| translation |
generator currentMethod declarationAt: 'toto' put: 'int* toto'.
generator currentMethod
addLocal: 'toto';
declarationAt: 'toto' put: 'int* toto'.
translation := self translate: (TAssignmentNode new
setVariable: (TVariableNode named: 'toto')
expression: (TSwitchStmtNode new
Expand Down
48 changes: 40 additions & 8 deletions smalltalksrc/Slang/TMethod.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ TMethod >> addLocal: aString [
self locals add: aString
]

{ #category : #adding }
TMethod >> addLocals: locals [
locals do: [ :local | self addLocal: local ]
]

{ #category : #initialization }
TMethod >> addTypeForSelf [
"If self should be typed then add a suitable type declaration.
Expand All @@ -109,10 +114,12 @@ TMethod >> addTypeForSelf [
TMethod >> addVarsDeclarationsAndLabelsOf: methodToBeInlined except: doNotRename [
"Prepare to inline the body of the given method into the receiver by making the args and locals of the argument to the receiver be locals of the receiver. Record any type declarations for these variables. Record labels. Assumes that the variables have already be renamed to avoid name clashes."

self locals
addAll: (methodToBeInlined args reject: [ :v | doNotRename includes: v]);
addAll: (methodToBeInlined locals reject: [ :v | doNotRename includes: v]);
yourself.
| newLocals |

newLocals := methodToBeInlined args , methodToBeInlined allLocals asOrderedCollection .

self addLocals: (newLocals copyWithoutAll: doNotRename).

methodToBeInlined declarations keysAndValuesDo:
[ :v :decl |
(doNotRename includes: v) ifFalse:
Expand Down Expand Up @@ -651,9 +658,11 @@ TMethod >> declarationAt: aVariableName ifPresent: presentBlock [
]

{ #category : #accessing }
TMethod >> declarationAt: aVariableName "<String>" put: aDeclaration [ "<String>" "^aDeclaration"
TMethod >> declarationAt: aVariableName put: aDeclaration [

^declarations at: aVariableName put: aDeclaration
self validateVariableDeclarationExists: aVariableName.

^ declarations at: aVariableName put: aDeclaration
]

{ #category : #accessing }
Expand All @@ -679,6 +688,15 @@ TMethod >> declareNonConflictingLocalNamedLike: aString [
^ newVarName
]

{ #category : #testing }
TMethod >> declaresVariableWithName: aVariableName [

| referencesInScope |
referencesInScope := self allLocals , self args.

^ referencesInScope includes: aVariableName
]

{ #category : #testing }
TMethod >> definedAsComplexMacro [
^properties notNil and: [(properties includesKey: #cmacro:)]
Expand Down Expand Up @@ -2784,7 +2802,7 @@ TMethod >> setSelector: sel definingClass: class args: argList locals: localList
definingClass := class.
args := argList asOrderedCollection collect: [:arg | arg name].
declarations := Dictionary new.
self addTypeForSelf.

primitive := aNumber.
properties := methodProperties.
comment := aComment.
Expand All @@ -2797,7 +2815,7 @@ TMethod >> setSelector: sel definingClass: class args: argList locals: localList

self parseTree: (aBlockNode asTranslatorNodeIn: self).
self locals: tempParseTree locals, (localList collect: [:arg | arg name]).

self addTypeForSelf.

self validateReservedWords.

Expand Down Expand Up @@ -3277,6 +3295,20 @@ TMethod >> usesVariableUninlinably: argName in: aCodeGen [
subNode isVariable and: [ subNode name = argName ] ] ] ] ] ]
]

{ #category : #accessing }
TMethod >> validateVariableDeclarationExists: aVariableName [

| shouldCheckVariable |
shouldCheckVariable := (aVariableName beginsWithAnyOf:
#( #self #cascade #toDoLimit )) not.

(shouldCheckVariable and: [
(self declaresVariableWithName: aVariableName) not]) ifTrue: [
TranslationError signal:
'Undefined local or argument ' , aVariableName
, ' type declaration' ]
]

{ #category : #'C code generation' }
TMethod >> validateReservedWords [
"Validates if there are no reserved words being used as arguments or selector"
Expand Down