1
0

Compiler-Semantic.st 9.7 KB

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