Compiler-IR.st 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. Smalltalk current createPackage: 'Compiler-IR' properties: #{}!
  2. NodeVisitor subclass: #IRASTTranslator
  3. instanceVariableNames: 'builder source'
  4. package: 'Compiler-IR'!
  5. !IRASTTranslator commentStamp!
  6. I an the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.
  7. I rely on a builder object, instance of IRBuilder.!
  8. !IRASTTranslator methodsFor: 'accessing'!
  9. builder
  10. ^ builder ifNil: [ builder := IRBuilder new ]
  11. !
  12. builder: aBuilder
  13. builder := aBuilder
  14. !
  15. source
  16. ^ source
  17. !
  18. source: aString
  19. source := aString
  20. ! !
  21. !IRASTTranslator methodsFor: 'visiting'!
  22. visitAssignmentNode: aNode
  23. self builder assignment
  24. with: [ self visit: aNode left ];
  25. with: [ self visit: aNode right ]
  26. !
  27. visitBlockNode: aNode
  28. self builder closure
  29. with: [ super visitBlockNode: aNode ];
  30. arguments: aNode parameters
  31. !
  32. visitJSStatementNode: aNode
  33. self builder verbatim: aNode source
  34. !
  35. visitMethodNode: aNode
  36. self builder method
  37. source: self source;
  38. arguments: aNode arguments;
  39. selector: aNode selector;
  40. messageSends: aNode messageSends;
  41. classReferences: aNode classReferences.
  42. aNode scope temps do: [ :each |
  43. self builder tempDeclaration name: each name ].
  44. aNode hasNonLocalReturn
  45. ifTrue: [ self builder nonLocalReturnHandling with: [
  46. super visitMethodNode: aNode ]]
  47. ifFalse: [ super visitMethodNode: aNode ]
  48. !
  49. visitReturnNode: aNode
  50. (aNode nonLocalReturn
  51. ifTrue: [ self builder nonLocalReturn ]
  52. ifFalse: [ self builder return ]) with: [ super visitReturnNode: aNode ]
  53. !
  54. visitSendNode: aNode
  55. self builder send
  56. selector: aNode selector;
  57. with: [
  58. self visit: aNode receiver.
  59. (aNode arguments do: [ :each | self visit: each ]) ]
  60. !
  61. visitSequenceNode: aNode
  62. self builder sequence with: [
  63. super visitSequenceNode: aNode ]
  64. !
  65. visitValueNode: aNode
  66. self builder value: aNode value
  67. !
  68. visitVariableNode: aNode
  69. self builder variable: aNode binding
  70. ! !
  71. IRASTTranslator subclass: #IRASTResolver
  72. instanceVariableNames: 'nextAlias'
  73. package: 'Compiler-IR'!
  74. !IRASTResolver commentStamp!
  75. I resolve nodes by creating an alias variable when appropriate, to flatten the AST.
  76. Nodes referenced in other nodes are aliased, except for some specific nodes such as variable or value nodes.!
  77. !IRASTResolver methodsFor: 'accessing'!
  78. nextAlias
  79. "Message sends are assigned, or 'aliased', to internal variables.
  80. Internal variable names are unique, and attached to the annotated send node"
  81. nextAlias ifNil: [nextAlias := 0].
  82. nextAlias := nextAlias + 1.
  83. ^ '$_', nextAlias asString
  84. ! !
  85. !IRASTResolver methodsFor: 'visiting'!
  86. resolve: aNode
  87. aNode isBlockSequenceNode ifFalse: [
  88. aNode nodes do: [ :each | self resolve: each ]].
  89. aNode shouldBeAliased ifTrue: [
  90. | alias |
  91. alias := self nextAlias.
  92. self builder method internalVariables add: alias.
  93. self builder assignment
  94. with: [ self builder variable: (AliasVar new name: alias) ];
  95. with: [ self visit: aNode resolving: false ].
  96. aNode alias: alias ]
  97. !
  98. visit: aNode
  99. self visit: aNode resolving: aNode canAliasChildren
  100. !
  101. visit: aNode resolving: aBoolean
  102. aBoolean ifTrue: [ self resolve: aNode ].
  103. aNode isAliased
  104. ifTrue: [ self visitAliased: aNode ]
  105. ifFalse: [ super visit: aNode ]
  106. !
  107. visitAliased: aNode
  108. ^ self builder variable: (AliasVar new name: aNode alias)
  109. ! !
  110. Object subclass: #IRBuilder
  111. instanceVariableNames: 'method root nextPc'
  112. package: 'Compiler-IR'!
  113. !IRBuilder commentStamp!
  114. I am responsible for building the IR (Intermatiate Representation) graph, composed of IRInstruction objects.!
  115. !IRBuilder methodsFor: 'accessing'!
  116. method
  117. ^ method
  118. !
  119. nextPc
  120. nextPc ifNil: [ nextPc := 0 ].
  121. nextPc := nextPc + 1.
  122. ^ nextPc
  123. !
  124. root
  125. ^ root
  126. !
  127. root: anIRInstruction
  128. root := anIRInstruction
  129. ! !
  130. !IRBuilder methodsFor: 'building'!
  131. add: aClass
  132. ^ self root append: (aClass on: self)
  133. !
  134. append: anObject
  135. ^root append: anObject
  136. !
  137. assignment
  138. ^ self add: IRAssignment
  139. !
  140. closure
  141. ^ self add: IRClosure
  142. !
  143. nonLocalReturn
  144. ^ self add: IRNonLocalReturn
  145. !
  146. nonLocalReturnHandling
  147. ^ self add: IRNonLocalReturnHandling
  148. !
  149. return
  150. ^ self add: IRReturn
  151. !
  152. send
  153. ^ self add: IRSend
  154. !
  155. sequence
  156. ^ self add: IRSequence
  157. !
  158. statement
  159. ^ self add: IRStatement
  160. !
  161. tempDeclaration
  162. ^ self add: IRTempDeclaration
  163. !
  164. value
  165. ^ self add: IRValue
  166. !
  167. value: aString
  168. ^ self value
  169. value: aString;
  170. yourself
  171. !
  172. variable
  173. ^ self add: IRVariable
  174. !
  175. variable: aScopeVariable
  176. ^ self variable
  177. variable: aScopeVariable;
  178. yourself
  179. !
  180. verbatim: aString
  181. ^(self add: IRVerbatim)
  182. source: aString;
  183. yourself
  184. !
  185. with: anObject
  186. self root with: anObject
  187. ! !
  188. !IRBuilder methodsFor: 'emiting'!
  189. emitOn: aStream
  190. method emitOn: aStream
  191. ! !
  192. !IRBuilder methodsFor: 'initialization'!
  193. initialize
  194. super initialize.
  195. root := method := IRMethod on: self
  196. ! !
  197. Object subclass: #IRInstruction
  198. instanceVariableNames: 'builder instructions'
  199. package: 'Compiler-IR'!
  200. !IRInstruction commentStamp!
  201. I am the abstract root class of the IR (intermediate representation) instructions class hierarchy.
  202. The IR graph is used to emit JavaScript code using a JSStream.!
  203. !IRInstruction methodsFor: 'accessing'!
  204. builder
  205. ^ builder
  206. !
  207. builder: aBuilder
  208. builder := aBuilder
  209. !
  210. instructions
  211. ^ instructions ifNil: [ instructions := OrderedCollection new ]
  212. ! !
  213. !IRInstruction methodsFor: 'building'!
  214. append: anObject
  215. anObject appendToInstruction: self.
  216. ^ anObject
  217. !
  218. appendBlock: aBlock
  219. | root |
  220. root := self builder root.
  221. self builder root: self.
  222. aBlock value.
  223. self builder root: root
  224. !
  225. appendInstruction: anIRInstruction
  226. self instructions add: anIRInstruction
  227. !
  228. appendString: aString
  229. self append: (self builder value: aString)
  230. !
  231. appendToInstruction: anIRInstruction
  232. anIRInstruction appendInstruction: self
  233. !
  234. with: anObject
  235. anObject appendToInstruction: self
  236. ! !
  237. !IRInstruction methodsFor: 'emiting'!
  238. emitOn: aStream
  239. "Just emit all sub instructions to aStream.
  240. Subclasses should not forget to call `super emitOn:`"
  241. self instructions do: [ :each |
  242. each emitOn: aStream ]
  243. ! !
  244. !IRInstruction class methodsFor: 'instance creation'!
  245. on: aBuilder
  246. ^ self new
  247. builder: aBuilder;
  248. yourself
  249. ! !
  250. IRInstruction subclass: #IRAssignment
  251. instanceVariableNames: 'left right'
  252. package: 'Compiler-IR'!
  253. !IRAssignment methodsFor: 'emiting'!
  254. emitOn: aStream
  255. aStream
  256. nextPutAssignment: self instructions first
  257. to: self instructions second
  258. ! !
  259. IRInstruction subclass: #IRClosure
  260. instanceVariableNames: 'arguments'
  261. package: 'Compiler-IR'!
  262. !IRClosure methodsFor: 'accessing'!
  263. arguments
  264. ^ arguments
  265. !
  266. arguments: aCollection
  267. arguments := aCollection
  268. ! !
  269. !IRClosure methodsFor: 'emiting'!
  270. emitOn: aStream
  271. aStream
  272. nextPutClosureWith: [ super emitOn: aStream ]
  273. arguments: (self arguments collect: [ :each | each asVariableName ])
  274. ! !
  275. IRInstruction subclass: #IRMethod
  276. instanceVariableNames: 'source selector classReferences messageSends arguments internalVariables source'
  277. package: 'Compiler-IR'!
  278. !IRMethod commentStamp!
  279. I am a method instruction!
  280. !IRMethod methodsFor: 'accessing'!
  281. arguments
  282. ^ arguments
  283. !
  284. arguments: aCollection
  285. arguments := aCollection
  286. !
  287. classReferences
  288. ^ classReferences
  289. !
  290. classReferences: aCollection
  291. classReferences := aCollection
  292. !
  293. internalVariables
  294. ^ internalVariables ifNil: [ internalVariables := Set new ]
  295. !
  296. messageSends
  297. ^ messageSends
  298. !
  299. messageSends: aCollection
  300. messageSends := aCollection
  301. !
  302. selector
  303. ^ selector
  304. !
  305. selector: aString
  306. selector := aString
  307. !
  308. source
  309. ^ source
  310. !
  311. source: aString
  312. source := aString
  313. ! !
  314. !IRMethod methodsFor: 'emiting'!
  315. emitOn: aStream
  316. aStream
  317. nextPutMethodDeclaration: self
  318. with: [
  319. aStream
  320. nextPutFunctionWith: [
  321. self internalVariables notEmpty ifTrue: [
  322. aStream nextPutVars: self internalVariables ].
  323. super emitOn: aStream ]
  324. arguments: (self arguments collect: [ :each | each asVariableName ]) ]
  325. ! !
  326. IRInstruction subclass: #IRNonLocalReturn
  327. instanceVariableNames: ''
  328. package: 'Compiler-IR'!
  329. !IRNonLocalReturn commentStamp!
  330. I am a non local return instruction.
  331. Non local returns are handled using a try/catch JS statement.
  332. See IRNonLocalReturnHandling class!
  333. !IRNonLocalReturn methodsFor: 'emiting'!
  334. emitOn: aStream
  335. aStream nextPutNonLocalReturnWith: [
  336. super emitOn: aStream ]
  337. ! !
  338. IRInstruction subclass: #IRNonLocalReturnHandling
  339. instanceVariableNames: ''
  340. package: 'Compiler-IR'!
  341. !IRNonLocalReturnHandling commentStamp!
  342. I represent a non local return handling instruction.
  343. Non local returns are handled with a try/catch statement!
  344. !IRNonLocalReturnHandling methodsFor: 'emiting'!
  345. emitOn: aStream
  346. aStream nextPutNonLocalReturnHandlingWith: [
  347. super emitOn: aStream ]
  348. ! !
  349. IRInstruction subclass: #IRReturn
  350. instanceVariableNames: ''
  351. package: 'Compiler-IR'!
  352. !IRReturn commentStamp!
  353. I am a local return instruction.!
  354. !IRReturn methodsFor: 'emiting'!
  355. emitOn: aStream
  356. aStream nextPutReturnWith: [
  357. super emitOn: aStream ]
  358. ! !
  359. IRInstruction subclass: #IRSend
  360. instanceVariableNames: 'selector superSend'
  361. package: 'Compiler-IR'!
  362. !IRSend commentStamp!
  363. I am a message send instruction.!
  364. !IRSend methodsFor: 'accessing'!
  365. emitOn: aStream
  366. aStream nextPutAll: 'smalltalk.send('.
  367. self instructions first emitOn: aStream.
  368. aStream nextPutAll: ',"', self selector asSelector, '", ['.
  369. self instructions allButFirst
  370. do: [ :each | each emitOn: aStream ]
  371. separatedBy: [ aStream nextPutAll: ',' ].
  372. aStream nextPutAll: '])'
  373. !
  374. selector
  375. ^ selector
  376. !
  377. selector: aString
  378. selector := aString
  379. !
  380. superSend
  381. ^ superSend ifNil: [ false ]
  382. !
  383. superSend: aBoolean
  384. superSend := aBoolean
  385. ! !
  386. IRInstruction subclass: #IRSequence
  387. instanceVariableNames: ''
  388. package: 'Compiler-IR'!
  389. !IRSequence methodsFor: 'emiting'!
  390. appendInstruction: anIRInstruction
  391. self instructions add: ((IRStatement on: self builder) with: anIRInstruction)
  392. !
  393. emitOn: aStream
  394. aStream nextPutSequenceWith: [
  395. "self instructions do: [ :each |
  396. ((IRStatement on: self builder)
  397. pc: self builder nextPc;
  398. with: each;
  399. yourself) emitOn: aStream ]"
  400. super emitOn: aStream ]
  401. ! !
  402. IRInstruction subclass: #IRStatement
  403. instanceVariableNames: 'pc'
  404. package: 'Compiler-IR'!
  405. !IRStatement methodsFor: 'accessing'!
  406. pc
  407. ^ pc ifNil: [pc := self builder nextPc]
  408. ! !
  409. !IRStatement methodsFor: 'emiting'!
  410. emitOn: aStream
  411. aStream nextPutStatement: self pc with: [
  412. super emitOn: aStream ]
  413. ! !
  414. IRInstruction subclass: #IRTempDeclaration
  415. instanceVariableNames: 'name'
  416. package: 'Compiler-IR'!
  417. !IRTempDeclaration commentStamp!
  418. I am a temporary variable declaration instruction!
  419. !IRTempDeclaration methodsFor: 'accessing'!
  420. name
  421. ^ name
  422. !
  423. name: aString
  424. name := aString
  425. ! !
  426. !IRTempDeclaration methodsFor: 'emiting'!
  427. emitOn: aStream
  428. aStream nextPutVar: self name asVariableName
  429. ! !
  430. IRInstruction subclass: #IRValue
  431. instanceVariableNames: 'value'
  432. package: 'Compiler-IR'!
  433. !IRValue commentStamp!
  434. I am the simplest possible instruction. I represent a value.!
  435. !IRValue methodsFor: 'accessing'!
  436. value
  437. ^value
  438. !
  439. value: aString
  440. value := aString
  441. ! !
  442. !IRValue methodsFor: 'emiting'!
  443. emitOn: aStream
  444. aStream nextPutAll: self value asJavascript
  445. ! !
  446. IRInstruction subclass: #IRVariable
  447. instanceVariableNames: 'variable'
  448. package: 'Compiler-IR'!
  449. !IRVariable methodsFor: 'accessing'!
  450. variable
  451. ^ variable
  452. !
  453. variable: aScopeVariable
  454. variable := aScopeVariable
  455. ! !
  456. !IRVariable methodsFor: 'emiting'!
  457. emitOn: aStream
  458. aStream nextPutAll: self variable alias
  459. ! !
  460. IRInstruction subclass: #IRVerbatim
  461. instanceVariableNames: 'source'
  462. package: 'Compiler-IR'!
  463. !IRVerbatim methodsFor: 'accessing'!
  464. source
  465. ^ source
  466. !
  467. source: aString
  468. source := aString
  469. ! !
  470. !IRVerbatim methodsFor: 'emiting'!
  471. emitOn: aStream
  472. aStream nextPutAll: self source, ';'
  473. ! !
  474. !BlockClosure methodsFor: '*Compiler-IR'!
  475. appendToInstruction: anIRInstruction
  476. anIRInstruction appendBlock: self
  477. ! !
  478. !String methodsFor: '*Compiler-IR'!
  479. appendToInstruction: anInstruction
  480. anInstruction appendString: self
  481. !
  482. asVariableName
  483. ^ (Smalltalk current reservedWords includes: self)
  484. ifTrue: [ self, '_' ]
  485. ifFalse: [ self ]
  486. !
  487. emitOn: aStream
  488. aStream nextPutAll: self
  489. ! !