Compiler-AST.st 13 KB

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