Compiler-Semantic.st 10 KB

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