Compiler-Semantic.st 11 KB

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