Compiler-Semantic.st 10 KB

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