Compiler-IR.st 15 KB

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