Compiler-Semantic.st 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. Smalltalk current createPackage: 'Compiler-Semantic' properties: #{}!
  2. SemanticError subclass: #InvalidAssignmentError
  3. instanceVariableNames: 'variableName'
  4. package: 'Compiler-Semantic'!
  5. !InvalidAssignmentError commentStamp!
  6. I get signaled when a pseudo variable gets assigned.!
  7. !InvalidAssignmentError methodsFor: 'accessing'!
  8. variableName
  9. ^ variableName
  10. !
  11. variableName: aString
  12. variableName := aString
  13. ! !
  14. Object subclass: #LexicalScope
  15. instanceVariableNames: 'node temps args outerScope'
  16. package: 'Compiler-Semantic'!
  17. !LexicalScope commentStamp!
  18. I represent a lexical scope where variable names are associated with ScopeVars
  19. Instances are used for block scopes. Method scopes are instances of MethodLexicalScope.
  20. I am attached to a ScopeVar and method/block nodes.
  21. Each context (method/closure) get a fresh scope that inherits from its outer scope.!
  22. !LexicalScope methodsFor: 'accessing'!
  23. allVariableNames
  24. ^ self args keys, self temps keys
  25. !
  26. args
  27. ^ args ifNil: [ args := Dictionary new ]
  28. !
  29. bindingFor: aStringOrNode
  30. ^ self args at: aStringOrNode value ifAbsent: [
  31. self temps at: aStringOrNode value ifAbsent: [ nil ]]
  32. !
  33. lookupVariable: aNode
  34. | lookup |
  35. lookup := (self bindingFor: aNode).
  36. lookup ifNil: [
  37. lookup := self outerScope ifNotNil: [
  38. (self outerScope lookupVariable: aNode) ]].
  39. ^ lookup
  40. !
  41. methodScope
  42. ^ self outerScope ifNotNil: [
  43. self outerScope methodScope ]
  44. !
  45. node
  46. "Answer the node in which I am defined"
  47. ^ node
  48. !
  49. node: aNode
  50. node := aNode
  51. !
  52. outerScope
  53. ^ outerScope
  54. !
  55. outerScope: aLexicalScope
  56. outerScope := aLexicalScope
  57. !
  58. scopeLevel
  59. ^ (self outerScope
  60. ifNil: [ 0 ]
  61. ifNotNil: [ self outerScope scopeLevel ]) + 1
  62. !
  63. temps
  64. ^ temps ifNil: [ temps := Dictionary new ]
  65. ! !
  66. !LexicalScope methodsFor: 'adding'!
  67. addArg: aString
  68. self args at: aString put: (ArgVar on: aString).
  69. (self args at: aString) scope: self
  70. !
  71. addTemp: aString
  72. self temps at: aString put: (TempVar on: aString).
  73. (self temps at: aString) scope: self
  74. ! !
  75. !LexicalScope methodsFor: 'testing'!
  76. isMethodScope
  77. ^ false
  78. ! !
  79. LexicalScope subclass: #MethodLexicalScope
  80. instanceVariableNames: 'iVars unknownVariables nonLocalReturn'
  81. package: 'Compiler-Semantic'!
  82. !MethodLexicalScope commentStamp!
  83. I represent a method scope.!
  84. !MethodLexicalScope methodsFor: 'accessing'!
  85. allVariableNames
  86. ^ super allVariableNames, self iVars keys
  87. !
  88. bindingFor: aNode
  89. ^ (super bindingFor: aNode) ifNil: [
  90. self iVars at: aNode value ifAbsent: [ nil ]]
  91. !
  92. iVars
  93. ^ iVars ifNil: [ iVars := Dictionary new ]
  94. !
  95. methodScope
  96. ^ self
  97. !
  98. nonLocalReturn
  99. ^ nonLocalReturn ifNil: [ false ]
  100. !
  101. nonLocalReturn: aBoolean
  102. nonLocalReturn := aBoolean
  103. !
  104. unknownVariables
  105. ^ unknownVariables ifNil: [ unknownVariables := OrderedCollection new ]
  106. ! !
  107. !MethodLexicalScope methodsFor: 'adding'!
  108. addIvar: aString
  109. self iVars at: aString put: (InstanceVar on: aString).
  110. (self iVars at: aString) scope: self
  111. ! !
  112. !MethodLexicalScope methodsFor: 'testing'!
  113. hasNonLocalReturn
  114. ^ self nonLocalReturn
  115. !
  116. isMethodScope
  117. ^ true
  118. ! !
  119. Object subclass: #ScopeVar
  120. instanceVariableNames: 'scope name'
  121. package: 'Compiler-Semantic'!
  122. !ScopeVar commentStamp!
  123. I am an entry in a LexicalScope that gets associated with variable nodes of the same name.
  124. There are 4 different subclasses of vars: temp vars, local vars, args, and unknown/global vars.!
  125. !ScopeVar methodsFor: 'accessing'!
  126. alias
  127. ^ self name asVariableName
  128. !
  129. name
  130. ^ name
  131. !
  132. name: aString
  133. name := aString
  134. !
  135. scope
  136. ^ scope
  137. !
  138. scope: aScope
  139. scope := aScope
  140. ! !
  141. !ScopeVar methodsFor: 'testing'!
  142. isArgVar
  143. ^ false
  144. !
  145. isInstanceVar
  146. ^ false
  147. !
  148. isTempVar
  149. ^ false
  150. !
  151. isUnknownVar
  152. ^ false
  153. ! !
  154. !ScopeVar class methodsFor: 'instance creation'!
  155. on: aString
  156. ^ self new
  157. name: aString;
  158. yourself
  159. ! !
  160. ScopeVar subclass: #AliasVar
  161. instanceVariableNames: ''
  162. package: 'Compiler-Semantic'!
  163. !AliasVar commentStamp!
  164. I am an internally defined variable by the compiler!
  165. ScopeVar subclass: #ArgVar
  166. instanceVariableNames: ''
  167. package: 'Compiler-Semantic'!
  168. !ArgVar commentStamp!
  169. I am an argument of a method or block.!
  170. !ArgVar methodsFor: 'testing'!
  171. isArgVar
  172. ^ true
  173. ! !
  174. ScopeVar subclass: #ClassRefVar
  175. instanceVariableNames: ''
  176. package: 'Compiler-Semantic'!
  177. !ClassRefVar commentStamp!
  178. I am an class reference variable!
  179. !ClassRefVar methodsFor: 'accessing'!
  180. alias
  181. ^ '(Smalltalk.', self name, ' || ', self name, ')'
  182. ! !
  183. ScopeVar subclass: #InstanceVar
  184. instanceVariableNames: ''
  185. package: 'Compiler-Semantic'!
  186. !InstanceVar commentStamp!
  187. I am an instance variable of a method or block.!
  188. !InstanceVar methodsFor: 'testing'!
  189. alias
  190. ^ 'self["@', self name, ']'
  191. !
  192. isInstanceVar
  193. ^ true
  194. ! !
  195. ScopeVar subclass: #TempVar
  196. instanceVariableNames: ''
  197. package: 'Compiler-Semantic'!
  198. !TempVar commentStamp!
  199. I am an temporary variable of a method or block.!
  200. !TempVar methodsFor: 'testing'!
  201. isTempVar
  202. ^ true
  203. ! !
  204. ScopeVar subclass: #UnknownVar
  205. instanceVariableNames: ''
  206. package: 'Compiler-Semantic'!
  207. !UnknownVar commentStamp!
  208. I am an unknown variable. Amber uses unknown variables as JavaScript globals!
  209. !UnknownVar methodsFor: 'testing'!
  210. isUnknownVar
  211. ^ true
  212. ! !
  213. NodeVisitor subclass: #SemanticAnalyzer
  214. instanceVariableNames: 'currentScope theClass classReferences messageSends'
  215. package: 'Compiler-Semantic'!
  216. !SemanticAnalyzer commentStamp!
  217. I semantically analyze the abstract syntax tree and annotate it with informations such as non local returns and variable scopes.!
  218. !SemanticAnalyzer methodsFor: 'accessing'!
  219. classReferences
  220. ^ classReferences ifNil: [ classReferences := Set new ]
  221. !
  222. messageSends
  223. ^ messageSends ifNil: [ messageSends := Set new ]
  224. !
  225. pseudoVariables
  226. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  227. !
  228. theClass
  229. ^ theClass
  230. !
  231. theClass: aClass
  232. theClass := aClass
  233. ! !
  234. !SemanticAnalyzer methodsFor: 'error handling'!
  235. errorInvalidAssignment: aString
  236. InvalidAssignmentError new
  237. variableName: aString;
  238. signal
  239. !
  240. errorShadowingVariable: aString
  241. ShadowingVariableError new
  242. variableName: aString;
  243. signal
  244. !
  245. errorUnknownVariable: aNode
  246. self allowUnknownVariables
  247. ifTrue: [ currentScope methodScope unknownVariables add: aNode value ]
  248. ifFalse: [
  249. UnknownVariableError new
  250. variableName: aNode value;
  251. signal ]
  252. ! !
  253. !SemanticAnalyzer methodsFor: 'factory'!
  254. newBlockScope
  255. ^ self newScopeOfClass: LexicalScope
  256. !
  257. newMethodScope
  258. ^ self newScopeOfClass: MethodLexicalScope
  259. !
  260. newScopeOfClass: aLexicalScopeClass
  261. ^ aLexicalScopeClass new
  262. outerScope: currentScope;
  263. yourself
  264. ! !
  265. !SemanticAnalyzer methodsFor: 'scope'!
  266. popScope
  267. currentScope ifNotNil: [
  268. currentScope := currentScope outerScope ]
  269. !
  270. pushScope: aScope
  271. aScope outerScope: currentScope.
  272. currentScope := aScope
  273. !
  274. validateVariableScope: aString
  275. "Validate the variable scope in by doing a recursive lookup, up to the method scope"
  276. (currentScope lookupVariable: aString) ifNotNil: [
  277. self errorShadowingVariable: aString ]
  278. ! !
  279. !SemanticAnalyzer methodsFor: 'testing'!
  280. allowUnknownVariables
  281. ^ true
  282. ! !
  283. !SemanticAnalyzer methodsFor: 'visiting'!
  284. visitAssignmentNode: aNode
  285. (self pseudoVariables includes: aNode left value) ifTrue: [
  286. self errorInvalidAssignment: aNode left ].
  287. aNode left beAssigned.
  288. aNode right beUsed.
  289. super visitAssignmentNode: aNode
  290. !
  291. visitBlockNode: aNode
  292. self pushScope: self newBlockScope.
  293. aNode scope: currentScope.
  294. aNode parameters do: [ :each |
  295. self validateVariableScope: each.
  296. currentScope addArg: each ].
  297. super visitBlockNode: aNode.
  298. self popScope
  299. !
  300. visitCascadeNode: aNode
  301. "Populate the receiver into all children"
  302. aNode nodes do: [ :each | each receiver: aNode receiver ].
  303. super visitCascadeNode: aNode
  304. !
  305. visitClassReferenceNode: aNode
  306. self classReferences add: aNode value.
  307. aNode binding: (ClassRefVar new name: aNode value; yourself)
  308. !
  309. visitMethodNode: aNode
  310. self pushScope: self newMethodScope.
  311. aNode scope: currentScope.
  312. self theClass allInstanceVariableNames do: [:each |
  313. currentScope addIVar: each ].
  314. aNode arguments do: [ :each |
  315. self validateVariableScope: each.
  316. currentScope addArg: each ].
  317. super visitMethodNode: aNode.
  318. aNode
  319. classReferences: self classReferences;
  320. messageSends: self messageSends.
  321. self popScope
  322. !
  323. visitReturnNode: aNode
  324. currentScope isMethodScope ifFalse: [
  325. currentScope methodScope nonLocalReturn: true.
  326. aNode nonLocalReturn: true ].
  327. aNode nodes first beUsed.
  328. super visitReturnNode: aNode
  329. !
  330. visitSendNode: aNode
  331. self messageSends add: aNode selector.
  332. aNode receiver ifNotNil: [
  333. aNode receiver beUsed ].
  334. aNode arguments do: [ :each |
  335. each beUsed ].
  336. super visitSendNode: aNode
  337. !
  338. visitSequenceNode: aNode
  339. aNode temps do: [ :each |
  340. self validateVariableScope: each.
  341. currentScope addTemp: each ].
  342. super visitSequenceNode: aNode
  343. !
  344. visitVariableNode: aNode
  345. "Bind a ScopeVar to aNode by doing a lookup in the current scope.
  346. If no ScopeVar is found, bind a UnknowVar and throw an error"
  347. aNode binding: ((currentScope lookupVariable: aNode) ifNil: [
  348. self errorUnknownVariable: aNode.
  349. UnknownVar new name: aNode value; yourself ])
  350. ! !
  351. !SemanticAnalyzer class methodsFor: 'instance creation'!
  352. on: aClass
  353. ^ self new
  354. theClass: aClass;
  355. yourself
  356. ! !