1
0

Compiler-Semantic.st 8.7 KB

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