Compiler-AST.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. Smalltalk createPackage: 'Compiler-AST'!
  2. DagParentNode subclass: #ASTNode
  3. instanceVariableNames: 'parent position source shouldBeAliased'
  4. package: 'Compiler-AST'!
  5. !ASTNode commentStamp!
  6. I am the abstract root class of the abstract syntax tree.
  7. Concrete classes should implement `#accept:` to allow visiting.
  8. `position` holds a point containing line and column number of the symbol location in the original source file.!
  9. !ASTNode methodsFor: 'accessing'!
  10. location: aLocation
  11. self position: aLocation start line @ aLocation start column
  12. !
  13. method
  14. ^ self parent ifNotNil: [ :node | node method ]
  15. !
  16. navigationNodeAt: aPoint ifAbsent: aBlock
  17. "Answer the navigation node in the receiver's tree at aPoint
  18. or nil if no navigation node was found.
  19. See `node >> isNaviationNode`"
  20. | children |
  21. children := self allDagChildren select: [ :each |
  22. each isNavigationNode and: [ each inPosition: aPoint ] ].
  23. children ifEmpty: [ ^ aBlock value ].
  24. ^ (children asArray sort: [ :a :b |
  25. (a positionStart dist: aPoint) <=
  26. (b positionStart dist: aPoint) ]) first
  27. !
  28. parent
  29. ^ parent
  30. !
  31. parent: aNode
  32. parent := aNode
  33. !
  34. position
  35. "answer the line and column of the receiver in the source code"
  36. ^ position ifNil: [
  37. self parent ifNotNil: [ :node | node position ] ]
  38. !
  39. position: aPosition
  40. position := aPosition
  41. !
  42. positionEnd
  43. ^ self positionStart + ((self source lines size - 1) @ (self source lines last size - 1))
  44. !
  45. positionStart
  46. ^ self position
  47. !
  48. shouldBeAliased
  49. ^ shouldBeAliased ifNil: [ false ]
  50. !
  51. shouldBeAliased: aBoolean
  52. shouldBeAliased := aBoolean
  53. !
  54. size
  55. ^ self source size
  56. !
  57. source
  58. ^ source ifNil: [ '' ]
  59. !
  60. source: aString
  61. source := aString
  62. ! !
  63. !ASTNode methodsFor: 'building'!
  64. withTail: aCollection
  65. ^ aCollection inject: self into: [
  66. :receiver :send | SendNode new
  67. position: send position;
  68. source: send source;
  69. receiver: receiver;
  70. selector: send selector;
  71. arguments: send arguments;
  72. yourself ]
  73. ! !
  74. !ASTNode methodsFor: 'testing'!
  75. inPosition: aPoint
  76. ^ (self positionStart <= aPoint and: [
  77. self positionEnd >= aPoint ])
  78. !
  79. isAssignmentNode
  80. ^ false
  81. !
  82. isBlockNode
  83. ^ false
  84. !
  85. isBlockSequenceNode
  86. ^ false
  87. !
  88. isCascadeNode
  89. ^ false
  90. !
  91. isImmutable
  92. ^ false
  93. !
  94. isJSStatementNode
  95. ^ false
  96. !
  97. isNavigationNode
  98. "Answer true if the node can be navigated to"
  99. ^ false
  100. !
  101. isReturnNode
  102. ^ false
  103. !
  104. isSendNode
  105. ^ false
  106. !
  107. isSequenceNode
  108. ^ false
  109. !
  110. isSuperKeyword
  111. ^ false
  112. !
  113. isValueNode
  114. ^ false
  115. !
  116. isVariableNode
  117. ^ false
  118. !
  119. requiresSmalltalkContext
  120. "Answer true if the receiver requires a smalltalk context.
  121. Only send nodes require a context.
  122. If no node requires a context, the method will be compiled without one.
  123. See `IRJSTranslator` and `JSStream` for context creation"
  124. ^ (self dagChildren
  125. detect: [ :each | each requiresSmalltalkContext ]
  126. ifNone: [ nil ]) notNil
  127. ! !
  128. ASTNode subclass: #AssignmentNode
  129. instanceVariableNames: 'left right'
  130. package: 'Compiler-AST'!
  131. !AssignmentNode commentStamp!
  132. I represent an assignment node.!
  133. !AssignmentNode methodsFor: 'accessing'!
  134. dagChildren
  135. ^ Array with: self left with: self right
  136. !
  137. left
  138. ^ left
  139. !
  140. left: aNode
  141. left := aNode
  142. !
  143. right
  144. ^ right
  145. !
  146. right: aNode
  147. right := aNode
  148. ! !
  149. !AssignmentNode methodsFor: 'testing'!
  150. isAssignmentNode
  151. ^ true
  152. ! !
  153. !AssignmentNode methodsFor: 'visiting'!
  154. acceptDagVisitor: aVisitor
  155. ^ aVisitor visitAssignmentNode: self
  156. ! !
  157. ASTNode subclass: #BlockNode
  158. instanceVariableNames: 'parameters scope'
  159. package: 'Compiler-AST'!
  160. !BlockNode commentStamp!
  161. I represent an block closure node.!
  162. !BlockNode methodsFor: 'accessing'!
  163. parameters
  164. ^ parameters ifNil: [ parameters := Array new ]
  165. !
  166. parameters: aCollection
  167. parameters := aCollection
  168. !
  169. scope
  170. ^ scope
  171. !
  172. scope: aLexicalScope
  173. scope := aLexicalScope
  174. ! !
  175. !BlockNode methodsFor: 'testing'!
  176. isBlockNode
  177. ^ true
  178. ! !
  179. !BlockNode methodsFor: 'visiting'!
  180. acceptDagVisitor: aVisitor
  181. ^ aVisitor visitBlockNode: self
  182. ! !
  183. ASTNode subclass: #CascadeNode
  184. instanceVariableNames: 'receiver'
  185. package: 'Compiler-AST'!
  186. !CascadeNode commentStamp!
  187. I represent an cascade node.!
  188. !CascadeNode methodsFor: 'accessing'!
  189. receiver
  190. ^ receiver
  191. !
  192. receiver: aNode
  193. receiver := aNode
  194. ! !
  195. !CascadeNode methodsFor: 'testing'!
  196. isCascadeNode
  197. ^ true
  198. ! !
  199. !CascadeNode methodsFor: 'visiting'!
  200. acceptDagVisitor: aVisitor
  201. ^ aVisitor visitCascadeNode: self
  202. ! !
  203. ASTNode subclass: #DynamicArrayNode
  204. instanceVariableNames: ''
  205. package: 'Compiler-AST'!
  206. !DynamicArrayNode commentStamp!
  207. I represent an dynamic array node.!
  208. !DynamicArrayNode methodsFor: 'visiting'!
  209. acceptDagVisitor: aVisitor
  210. ^ aVisitor visitDynamicArrayNode: self
  211. ! !
  212. ASTNode subclass: #DynamicDictionaryNode
  213. instanceVariableNames: ''
  214. package: 'Compiler-AST'!
  215. !DynamicDictionaryNode commentStamp!
  216. I represent an dynamic dictionary node.!
  217. !DynamicDictionaryNode methodsFor: 'visiting'!
  218. acceptDagVisitor: aVisitor
  219. ^ aVisitor visitDynamicDictionaryNode: self
  220. ! !
  221. ASTNode subclass: #JSStatementNode
  222. instanceVariableNames: ''
  223. package: 'Compiler-AST'!
  224. !JSStatementNode commentStamp!
  225. I represent an JavaScript statement node.!
  226. !JSStatementNode methodsFor: 'testing'!
  227. isJSStatementNode
  228. ^ true
  229. !
  230. requiresSmalltalkContext
  231. ^ true
  232. ! !
  233. !JSStatementNode methodsFor: 'visiting'!
  234. acceptDagVisitor: aVisitor
  235. ^ aVisitor visitJSStatementNode: self
  236. ! !
  237. ASTNode subclass: #MethodNode
  238. instanceVariableNames: 'selector arguments source scope classReferences sendIndexes'
  239. package: 'Compiler-AST'!
  240. !MethodNode commentStamp!
  241. I represent an method node.
  242. A method node must be the root and only method node of a valid AST.!
  243. !MethodNode methodsFor: 'accessing'!
  244. arguments
  245. ^ arguments ifNil: [ #() ]
  246. !
  247. arguments: aCollection
  248. arguments := aCollection
  249. !
  250. classReferences
  251. ^ classReferences
  252. !
  253. classReferences: aCollection
  254. classReferences := aCollection
  255. !
  256. messageSends
  257. ^ self sendIndexes keys
  258. !
  259. method
  260. ^ self
  261. !
  262. scope
  263. ^ scope
  264. !
  265. scope: aMethodScope
  266. scope := aMethodScope
  267. !
  268. selector
  269. ^ selector
  270. !
  271. selector: aString
  272. selector := aString
  273. !
  274. sendIndexes
  275. ^ sendIndexes
  276. !
  277. sendIndexes: aDictionary
  278. sendIndexes := aDictionary
  279. !
  280. sequenceNode
  281. self dagChildren do: [ :each |
  282. each isSequenceNode ifTrue: [ ^ each ] ].
  283. ^ nil
  284. !
  285. source
  286. ^ source
  287. !
  288. source: aString
  289. source := aString
  290. ! !
  291. !MethodNode methodsFor: 'visiting'!
  292. acceptDagVisitor: aVisitor
  293. ^ aVisitor visitMethodNode: self
  294. ! !
  295. ASTNode subclass: #ReturnNode
  296. instanceVariableNames: 'scope'
  297. package: 'Compiler-AST'!
  298. !ReturnNode commentStamp!
  299. I represent an return node. At the AST level, there is not difference between a local return or non-local return.!
  300. !ReturnNode methodsFor: 'accessing'!
  301. scope
  302. ^ scope
  303. !
  304. scope: aLexicalScope
  305. scope := aLexicalScope
  306. ! !
  307. !ReturnNode methodsFor: 'testing'!
  308. isReturnNode
  309. ^ true
  310. !
  311. nonLocalReturn
  312. ^ self scope isMethodScope not
  313. ! !
  314. !ReturnNode methodsFor: 'visiting'!
  315. acceptDagVisitor: aVisitor
  316. ^ aVisitor visitReturnNode: self
  317. ! !
  318. ASTNode subclass: #SendNode
  319. instanceVariableNames: 'selector arguments receiver index shouldBeInlined'
  320. package: 'Compiler-AST'!
  321. !SendNode commentStamp!
  322. I represent an message send node.!
  323. !SendNode methodsFor: 'accessing'!
  324. arguments
  325. ^ arguments ifNil: [ arguments := #() ]
  326. !
  327. arguments: aCollection
  328. arguments := aCollection
  329. !
  330. dagChildren
  331. self receiver ifNil: [ ^ self arguments copy ].
  332. ^ (Array with: self receiver)
  333. addAll: self arguments;
  334. yourself
  335. !
  336. index
  337. ^ index
  338. !
  339. index: anInteger
  340. index := anInteger
  341. !
  342. navigationLink
  343. ^ self selector
  344. !
  345. receiver
  346. ^ receiver
  347. !
  348. receiver: aNode
  349. receiver := aNode
  350. !
  351. selector
  352. ^ selector
  353. !
  354. selector: aString
  355. selector := aString
  356. !
  357. shouldBeInlined
  358. ^ shouldBeInlined ifNil: [ false ]
  359. !
  360. shouldBeInlined: aBoolean
  361. shouldBeInlined := aBoolean
  362. !
  363. superSend
  364. ^ self receiver notNil and: [ self receiver isSuperKeyword ]
  365. ! !
  366. !SendNode methodsFor: 'testing'!
  367. isNavigationNode
  368. ^ true
  369. !
  370. isSendNode
  371. ^ true
  372. !
  373. requiresSmalltalkContext
  374. ^ true
  375. ! !
  376. !SendNode methodsFor: 'visiting'!
  377. acceptDagVisitor: aVisitor
  378. ^ aVisitor visitSendNode: self
  379. ! !
  380. ASTNode subclass: #SequenceNode
  381. instanceVariableNames: 'temps pragmas scope'
  382. package: 'Compiler-AST'!
  383. !SequenceNode commentStamp!
  384. I represent an sequence node. A sequence represent a set of instructions inside the same scope (the method scope or a block scope).!
  385. !SequenceNode methodsFor: 'accessing'!
  386. pragmas
  387. ^ pragmas ifNil: [ #() ]
  388. !
  389. pragmas: aCollection
  390. pragmas := aCollection
  391. !
  392. scope
  393. ^ scope
  394. !
  395. scope: aLexicalScope
  396. scope := aLexicalScope
  397. !
  398. temps
  399. ^ temps ifNil: [ #() ]
  400. !
  401. temps: aCollection
  402. temps := aCollection
  403. ! !
  404. !SequenceNode methodsFor: 'building'!
  405. asBlockSequenceNode
  406. ^ BlockSequenceNode new
  407. position: self position;
  408. source: self source;
  409. dagChildren: self dagChildren;
  410. temps: self temps;
  411. pragmas: self pragmas;
  412. yourself
  413. ! !
  414. !SequenceNode methodsFor: 'testing'!
  415. isSequenceNode
  416. ^ true
  417. ! !
  418. !SequenceNode methodsFor: 'visiting'!
  419. acceptDagVisitor: aVisitor
  420. ^ aVisitor visitSequenceNode: self
  421. ! !
  422. SequenceNode subclass: #BlockSequenceNode
  423. instanceVariableNames: ''
  424. package: 'Compiler-AST'!
  425. !BlockSequenceNode commentStamp!
  426. I represent an special sequence node for block scopes.!
  427. !BlockSequenceNode methodsFor: 'testing'!
  428. isBlockSequenceNode
  429. ^ true
  430. ! !
  431. !BlockSequenceNode methodsFor: 'visiting'!
  432. acceptDagVisitor: aVisitor
  433. ^ aVisitor visitBlockSequenceNode: self
  434. !
  435. pragmas: aCollection
  436. aCollection ifNotEmpty: [
  437. self error: 'Block must have no pragmas.' ].
  438. ^ super pragmas: aCollection
  439. ! !
  440. ASTNode subclass: #ValueNode
  441. instanceVariableNames: 'value'
  442. package: 'Compiler-AST'!
  443. !ValueNode commentStamp!
  444. I represent a value node.!
  445. !ValueNode methodsFor: 'accessing'!
  446. value
  447. ^ value
  448. !
  449. value: anObject
  450. value := anObject
  451. ! !
  452. !ValueNode methodsFor: 'testing'!
  453. isImmutable
  454. ^ self value isImmutable
  455. !
  456. isValueNode
  457. ^ true
  458. ! !
  459. !ValueNode methodsFor: 'visiting'!
  460. acceptDagVisitor: aVisitor
  461. ^ aVisitor visitValueNode: self
  462. ! !
  463. ValueNode subclass: #VariableNode
  464. instanceVariableNames: 'assigned binding'
  465. package: 'Compiler-AST'!
  466. !VariableNode commentStamp!
  467. I represent an variable node.!
  468. !VariableNode methodsFor: 'accessing'!
  469. alias
  470. ^ self binding alias
  471. !
  472. assigned
  473. ^ assigned ifNil: [ false ]
  474. !
  475. assigned: aBoolean
  476. assigned := aBoolean
  477. !
  478. beAssigned
  479. self binding validateAssignment.
  480. assigned := true
  481. !
  482. binding
  483. ^ binding
  484. !
  485. binding: aScopeVar
  486. binding := aScopeVar
  487. !
  488. navigationLink
  489. ^ self value
  490. ! !
  491. !VariableNode methodsFor: 'testing'!
  492. isArgument
  493. ^ self binding isArgVar
  494. !
  495. isImmutable
  496. ^ self binding isImmutable
  497. !
  498. isNavigationNode
  499. ^ true
  500. !
  501. isSuperKeyword
  502. ^ self value = 'super'
  503. !
  504. isVariableNode
  505. ^ true
  506. ! !
  507. !VariableNode methodsFor: 'visiting'!
  508. acceptDagVisitor: aVisitor
  509. ^ aVisitor visitVariableNode: self
  510. ! !
  511. PathDagVisitor subclass: #ParentFakingPathDagVisitor
  512. instanceVariableNames: 'setParentSelector'
  513. package: 'Compiler-AST'!
  514. !ParentFakingPathDagVisitor commentStamp!
  515. I am base class of `DagNode` visitor.
  516. I hold the path of ancestors up to actual node
  517. in `self path`.!
  518. !ParentFakingPathDagVisitor methodsFor: 'visiting'!
  519. visit: aNode
  520. self path ifNotEmpty: [ :p | aNode parent: p last ].
  521. ^ super visit: aNode
  522. ! !
  523. ParentFakingPathDagVisitor subclass: #NodeVisitor
  524. instanceVariableNames: ''
  525. package: 'Compiler-AST'!
  526. !NodeVisitor commentStamp!
  527. I am the abstract super class of all AST node visitors.!
  528. !NodeVisitor methodsFor: 'visiting'!
  529. visitAssignmentNode: aNode
  530. ^ self visitDagNode: aNode
  531. !
  532. visitBlockNode: aNode
  533. ^ self visitDagNode: aNode
  534. !
  535. visitBlockSequenceNode: aNode
  536. ^ self visitSequenceNode: aNode
  537. !
  538. visitCascadeNode: aNode
  539. ^ self visitDagNode: aNode
  540. !
  541. visitDagNode: aNode
  542. ^ self visitDagNodeVariantSimple: aNode
  543. !
  544. visitDynamicArrayNode: aNode
  545. ^ self visitDagNode: aNode
  546. !
  547. visitDynamicDictionaryNode: aNode
  548. ^ self visitDagNode: aNode
  549. !
  550. visitJSStatementNode: aNode
  551. ^ self visitDagNode: aNode
  552. !
  553. visitMethodNode: aNode
  554. ^ self visitDagNode: aNode
  555. !
  556. visitReturnNode: aNode
  557. ^ self visitDagNode: aNode
  558. !
  559. visitSendNode: aNode
  560. ^ self visitDagNode: aNode
  561. !
  562. visitSequenceNode: aNode
  563. ^ self visitDagNode: aNode
  564. !
  565. visitValueNode: aNode
  566. ^ self visitDagNode: aNode
  567. !
  568. visitVariableNode: aNode
  569. ^ self visitDagNode: aNode
  570. ! !
  571. NodeVisitor subclass: #Pragmator
  572. instanceVariableNames: 'methodNode sequenceNode'
  573. package: 'Compiler-AST'!
  574. !Pragmator commentStamp!
  575. I am abstract superclass for pragma-processing transformer.
  576. My subclasses should implement messages for each pragma
  577. they process. Pragma processing checks if a message is known
  578. to a class but not to its superclass. IOW, each and only those
  579. pragmas are processed which are defined as methods in the subclass.
  580. These messages can access sequence node in which
  581. a pragma occurred and its containing method node
  582. as `self sequenceNode` and `self methodNode`.
  583. See `EarlyPragmator` for an example.!
  584. !Pragmator methodsFor: 'accessing'!
  585. methodNode
  586. ^ methodNode
  587. !
  588. methodNode: anObject
  589. methodNode := anObject
  590. !
  591. sequenceNode
  592. ^ sequenceNode
  593. !
  594. sequenceNode: anObject
  595. sequenceNode := anObject
  596. ! !
  597. !Pragmator methodsFor: 'pragma processing'!
  598. canProcessPragma: aMessage
  599. | selector |
  600. selector := aMessage selector.
  601. ^ (self respondsTo: selector) and: [
  602. (self class superclass canUnderstand: selector) not]
  603. !
  604. processPragma: aMessage
  605. (self canProcessPragma: aMessage) ifTrue: [
  606. ^ aMessage sendTo: self ]
  607. !
  608. visitMethodNode: aNode
  609. self methodNode: aNode.
  610. ^ super visitMethodNode: aNode
  611. !
  612. visitSequenceNode: aNode
  613. self sequenceNode: aNode.
  614. aNode pragmas do: [ :each | self processPragma: each ].
  615. ^ super visitSequenceNode: aNode
  616. ! !
  617. Pragmator subclass: #EarlyPragmator
  618. instanceVariableNames: ''
  619. package: 'Compiler-AST'!
  620. !EarlyPragmator methodsFor: 'pragmas'!
  621. inlineJS: aString
  622. self sequenceNode dagChildren ifNotEmpty: [
  623. self error: 'inlineJS: does not allow smalltalk statements' ].
  624. self sequenceNode addDagChild: (
  625. JSStatementNode new
  626. source: aString;
  627. yourself)
  628. ! !
  629. !CompiledMethod methodsFor: '*Compiler-AST'!
  630. ast
  631. self source ifEmpty: [ self error: 'Method source is empty' ].
  632. ^ Smalltalk parse: self source
  633. ! !