Compiler-Interpreter.st 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. Smalltalk createPackage: 'Compiler-Interpreter'!
  2. BlockClosure subclass: #AIBlockClosure
  3. instanceVariableNames: 'node outerContext'
  4. package: 'Compiler-Interpreter'!
  5. !AIBlockClosure commentStamp!
  6. I am a special `BlockClosure` subclass used by an interpreter to interpret a block node.
  7. While I am polymorphic with `BlockClosure`, some methods such as `#new` will raise interpretation errors. Unlike a `BlockClosure`, my instance are not JavaScript functions.
  8. Evaluating an instance will result in interpreting the `node` instance variable (instance of `BlockNode`).!
  9. !AIBlockClosure methodsFor: 'accessing'!
  10. compiledSource
  11. "Unlike blocks, the receiver doesn't represent a JS function"
  12. ^ '[ AST Block closure ]'
  13. !
  14. numArgs
  15. ^ node temps size
  16. ! !
  17. !AIBlockClosure methodsFor: 'converting'!
  18. currySelf
  19. self interpreterError
  20. ! !
  21. !AIBlockClosure methodsFor: 'error handling'!
  22. interpreterError
  23. ASTInterpreterError signal: 'Method cannot be interpreted by the interpreter.'
  24. ! !
  25. !AIBlockClosure methodsFor: 'evaluating'!
  26. applyTo: anObject arguments: aCollection
  27. self interpreterError
  28. !
  29. value
  30. ^ self valueWithPossibleArguments: #()
  31. !
  32. value: anArgument
  33. ^ self valueWithPossibleArguments: {anArgument}
  34. !
  35. value: firstArgument value: secondArgument
  36. ^ self valueWithPossibleArguments: {firstArgument . secondArgument}
  37. !
  38. value: firstArgument value: secondArgument value: thirdArgument
  39. ^ self valueWithPossibleArguments: {firstArgument . secondArgument . thirdArgument}
  40. !
  41. valueWithPossibleArguments: aCollection
  42. | context sequenceNode |
  43. context := outerContext newInnerContext.
  44. "Interpret a copy of the sequence node to avoid creating a new AIBlockClosure"
  45. sequenceNode := node nodes first copy
  46. parent: nil;
  47. yourself.
  48. "Define locals in the context"
  49. sequenceNode temps do: [ :each |
  50. context defineLocal: each ].
  51. "Populate the arguments into the context locals"
  52. node parameters withIndexDo: [ :each :index |
  53. context defineLocal: each.
  54. context localAt: each put: (aCollection at: index ifAbsent: [ nil ]) ].
  55. "Interpret the first node of the BlockSequenceNode"
  56. context interpreter
  57. node: sequenceNode;
  58. enterNode;
  59. proceed.
  60. outerContext interpreter
  61. setNonLocalReturnFromContext: context.
  62. ^ context interpreter pop
  63. ! !
  64. !AIBlockClosure methodsFor: 'initialization'!
  65. initializeWithContext: aContext node: aNode
  66. node := aNode.
  67. outerContext := aContext
  68. ! !
  69. !AIBlockClosure class methodsFor: 'instance creation'!
  70. forContext: aContext node: aNode
  71. ^ self new
  72. initializeWithContext: aContext node: aNode;
  73. yourself
  74. ! !
  75. MethodContext subclass: #AIContext
  76. instanceVariableNames: 'outerContext innerContext pc locals selector index sendIndexes evaluatedSelector ast interpreter supercall'
  77. package: 'Compiler-Interpreter'!
  78. !AIContext commentStamp!
  79. I am like a `MethodContext`, used by the `ASTInterpreter`.
  80. Unlike a `MethodContext`, my instances are not read-only.
  81. When debugging, my instances are created by copying the current `MethodContext` (thisContext)!
  82. !AIContext methodsFor: 'accessing'!
  83. defineLocal: aString
  84. self locals at: aString put: nil
  85. !
  86. evaluatedSelector
  87. ^ evaluatedSelector
  88. !
  89. evaluatedSelector: aString
  90. evaluatedSelector := aString
  91. !
  92. index
  93. ^ index ifNil: [ 0 ]
  94. !
  95. index: anInteger
  96. index := anInteger
  97. !
  98. innerContext
  99. ^ innerContext
  100. !
  101. innerContext: anAIContext
  102. innerContext := anAIContext
  103. !
  104. localAt: aString
  105. "Lookup the local value up to the method context"
  106. | context |
  107. context := self lookupContextForLocal: aString.
  108. ^ context basicLocalAt: aString
  109. !
  110. localAt: aString ifAbsent: aBlock
  111. "Lookup the local value up to the method context"
  112. | context |
  113. context := self
  114. lookupContextForLocal: aString
  115. ifNone: [ ^ aBlock value ].
  116. ^ context basicLocalAt: aString
  117. !
  118. localAt: aString put: anObject
  119. | context |
  120. context := self lookupContextForLocal: aString.
  121. context basicLocalAt: aString put: anObject
  122. !
  123. locals
  124. locals ifNil: [ self initializeLocals ].
  125. ^ locals
  126. !
  127. outerContext
  128. ^ outerContext
  129. !
  130. outerContext: anAIContext
  131. outerContext := anAIContext.
  132. outerContext ifNotNil: [ :context |
  133. context innerContext: self ]
  134. !
  135. selector
  136. ^ selector
  137. !
  138. selector: aString
  139. selector := aString
  140. !
  141. sendIndexAt: aString
  142. ^ self sendIndexes at: aString ifAbsent: [ 0 ]
  143. !
  144. sendIndexes
  145. ^ sendIndexes ifNil: [ Dictionary new ]
  146. !
  147. sendIndexes: aDictionary
  148. sendIndexes := aDictionary
  149. ! !
  150. !AIContext methodsFor: 'error handling'!
  151. variableNotFound
  152. "Error thrown whenever a variable lookup fails"
  153. self error: 'Variable missing'
  154. ! !
  155. !AIContext methodsFor: 'evaluating'!
  156. evaluate: aString on: anEvaluator
  157. ^ anEvaluator evaluate: aString context: self
  158. !
  159. evaluateNode: aNode
  160. ^ ASTInterpreter new
  161. context: self;
  162. node: aNode;
  163. enterNode;
  164. proceed;
  165. result
  166. ! !
  167. !AIContext methodsFor: 'factory'!
  168. newInnerContext
  169. ^ self class new
  170. outerContext: self;
  171. yourself
  172. ! !
  173. !AIContext methodsFor: 'initialization'!
  174. initializeAST
  175. ast := self method ast.
  176. (SemanticAnalyzer on: self method methodClass)
  177. visit: ast
  178. !
  179. initializeFromMethodContext: aMethodContext
  180. self
  181. evaluatedSelector: aMethodContext evaluatedSelector;
  182. index: aMethodContext index;
  183. sendIndexes: aMethodContext sendIndexes;
  184. receiver: aMethodContext receiver;
  185. supercall: aMethodContext supercall;
  186. selector: aMethodContext selector.
  187. aMethodContext outerContext ifNotNil: [ :outer |
  188. "If the method context is nil, the block was defined in JS, so ignore it"
  189. outer methodContext ifNotNil: [
  190. self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
  191. aMethodContext locals keysAndValuesDo: [ :key :value |
  192. self locals at: key put: value ] ]
  193. !
  194. initializeInterpreter
  195. interpreter := ASTInterpreter new
  196. context: self;
  197. yourself.
  198. self innerContext ifNotNil: [
  199. self setupInterpreter: interpreter ]
  200. !
  201. initializeLocals
  202. locals := Dictionary new.
  203. locals at: 'thisContext' put: self.
  204. ! !
  205. !AIContext methodsFor: 'interpreting'!
  206. arguments
  207. ^ self ast arguments collect: [ :each |
  208. self localAt: each ifAbsent: [ self error: 'Argument not in context' ] ]
  209. !
  210. ast
  211. self isBlockContext ifTrue: [
  212. ^ self outerContext ifNotNil: [ :context | context ast ] ].
  213. ast ifNil: [ self initializeAST ].
  214. ^ ast
  215. !
  216. basicReceiver
  217. ^ self localAt: 'self'
  218. !
  219. interpreter
  220. interpreter ifNil: [ self initializeInterpreter ].
  221. ^ interpreter
  222. !
  223. interpreter: anInterpreter
  224. interpreter := anInterpreter
  225. !
  226. receiver: anObject
  227. self locals at: 'self' put: anObject
  228. !
  229. setupInterpreter: anInterpreter
  230. | currentNode |
  231. "Retrieve the current node"
  232. currentNode := ASTPCNodeVisitor new
  233. selector: self evaluatedSelector;
  234. context: self;
  235. visit: self ast;
  236. currentNode.
  237. "Define locals for the context"
  238. self ast sequenceNode ifNotNil: [ :sequence |
  239. sequence temps do: [ :each |
  240. self defineLocal: each ] ].
  241. anInterpreter node: currentNode.
  242. "Push the send args and receiver to the interpreter stack"
  243. self innerContext arguments reversed do: [ :each |
  244. anInterpreter push: each ].
  245. anInterpreter push: (self innerContext receiver)
  246. !
  247. supercall
  248. ^ supercall ifNil: [ false ]
  249. !
  250. supercall: aBoolean
  251. supercall := aBoolean
  252. ! !
  253. !AIContext methodsFor: 'private'!
  254. basicLocalAt: aString
  255. ^ self locals at: aString
  256. !
  257. basicLocalAt: aString put: anObject
  258. self locals at: aString put: anObject
  259. !
  260. lookupContextForLocal: aString
  261. "Lookup the context defining the local named `aString`
  262. up to the method context"
  263. ^ self
  264. lookupContextForLocal: aString
  265. ifNone: [ self variableNotFound ]
  266. !
  267. lookupContextForLocal: aString ifNone: aBlock
  268. "Lookup the context defining the local named `aString`
  269. up to the method context"
  270. ^ self locals
  271. at: aString
  272. ifPresent: [ self ]
  273. ifAbsent: [
  274. self outerContext
  275. ifNil: aBlock
  276. ifNotNil: [ :context |
  277. context lookupContextForLocal: aString ] ]
  278. ! !
  279. !AIContext methodsFor: 'testing'!
  280. isTopContext
  281. ^ self innerContext isNil
  282. ! !
  283. !AIContext class methodsFor: 'instance creation'!
  284. fromMethodContext: aMethodContext
  285. ^ self new
  286. initializeFromMethodContext: aMethodContext;
  287. yourself
  288. ! !
  289. SemanticAnalyzer subclass: #AISemanticAnalyzer
  290. instanceVariableNames: 'context'
  291. package: 'Compiler-Interpreter'!
  292. !AISemanticAnalyzer commentStamp!
  293. I perform the same semantic analysis than `SemanticAnalyzer`, with the difference that provided an `AIContext` context, variables are bound with the context variables.!
  294. !AISemanticAnalyzer methodsFor: 'accessing'!
  295. context
  296. ^ context
  297. !
  298. context: anAIContext
  299. context := anAIContext
  300. ! !
  301. !AISemanticAnalyzer methodsFor: 'visiting'!
  302. visitVariableNode: aNode
  303. self context
  304. localAt: aNode value
  305. ifAbsent: [ ^ super visitVariableNode: aNode ].
  306. aNode binding: ASTContextVar new
  307. ! !
  308. ScopeVar subclass: #ASTContextVar
  309. instanceVariableNames: 'context'
  310. package: 'Compiler-Interpreter'!
  311. !ASTContextVar commentStamp!
  312. I am a variable defined in a `context`.!
  313. !ASTContextVar methodsFor: 'accessing'!
  314. context
  315. ^ context
  316. !
  317. context: anObject
  318. context := anObject
  319. ! !
  320. Object subclass: #ASTDebugger
  321. instanceVariableNames: 'interpreter context result'
  322. package: 'Compiler-Interpreter'!
  323. !ASTDebugger commentStamp!
  324. I am a stepping debugger interface for Amber code.
  325. I internally use an instance of `ASTInterpreter` to actually step through node and interpret them.
  326. My instances are created from an `AIContext` with `ASTDebugger class >> context:`.
  327. They hold an `AIContext` instance internally, recursive copy of the `MethodContext`.
  328. ## API
  329. Use the methods of the `'stepping'` protocol to do stepping.!
  330. !ASTDebugger methodsFor: 'accessing'!
  331. context
  332. ^ context
  333. !
  334. context: aContext
  335. context := aContext
  336. !
  337. interpreter
  338. ^ self context ifNotNil: [ :ctx |
  339. ctx interpreter ]
  340. !
  341. method
  342. ^ self context method
  343. !
  344. node
  345. ^ self interpreter ifNotNil: [
  346. self interpreter node ]
  347. !
  348. result
  349. ^ result
  350. ! !
  351. !ASTDebugger methodsFor: 'actions'!
  352. flushInnerContexts
  353. "When stepping, the inner contexts are not relevent anymore,
  354. and can be flushed"
  355. self context ifNotNil: [ :cxt |
  356. cxt innerContext: nil ]
  357. ! !
  358. !ASTDebugger methodsFor: 'private'!
  359. onStep
  360. "After each step, check if the interpreter is at the end,
  361. and if it is move to its outer context if any, skipping its
  362. current node (which was just evaluated by the current
  363. interpreter).
  364. After each step we also flush inner contexts."
  365. result := self interpreter result.
  366. self interpreter atEnd ifTrue: [
  367. self context outerContext ifNotNil: [ :outerContext |
  368. self context: outerContext ].
  369. self interpreter atEnd ifFalse: [ self interpreter skip ] ].
  370. self flushInnerContexts
  371. ! !
  372. !ASTDebugger methodsFor: 'stepping'!
  373. proceed
  374. [ self atEnd ] whileFalse: [ self stepOver ]
  375. !
  376. restart
  377. self interpreter restart.
  378. self flushInnerContexts
  379. !
  380. stepInto
  381. self shouldBeImplemented
  382. !
  383. stepOver
  384. self context isTopContext
  385. ifFalse: [ self interpreter skip ]
  386. ifTrue: [ self interpreter stepOver ].
  387. self onStep
  388. ! !
  389. !ASTDebugger methodsFor: 'testing'!
  390. atEnd
  391. self context ifNil: [ ^ true ].
  392. ^ self interpreter atEnd and: [
  393. self context isTopContext ]
  394. ! !
  395. !ASTDebugger class methodsFor: 'instance creation'!
  396. context: aContext
  397. ^ self new
  398. context: aContext;
  399. yourself
  400. ! !
  401. NodeVisitor subclass: #ASTEnterNode
  402. instanceVariableNames: 'interpreter'
  403. package: 'Compiler-Interpreter'!
  404. !ASTEnterNode methodsFor: 'accessing'!
  405. interpreter
  406. ^ interpreter
  407. !
  408. interpreter: anObject
  409. interpreter := anObject
  410. ! !
  411. !ASTEnterNode methodsFor: 'visiting'!
  412. visitBlockNode: aNode
  413. "Answer the node as we want to avoid eager evaluation"
  414. ^ aNode
  415. !
  416. visitNode: aNode
  417. aNode nodes
  418. ifEmpty: [ ^ aNode ]
  419. ifNotEmpty: [ :nodes | ^ self visit: nodes first ]
  420. !
  421. visitRefNode: aNode
  422. | ref |
  423. ref := aNode node.
  424. self interpreter refResults at: ref nodeId
  425. ifPresent: [ ^ aNode ]
  426. ifAbsent: [ ref parent: aNode. ^ super visitRefNode: aNode ]
  427. !
  428. visitSequenceNode: aNode
  429. aNode temps do: [ :each |
  430. self interpreter context defineLocal: each ].
  431. ^ super visitSequenceNode: aNode
  432. ! !
  433. !ASTEnterNode class methodsFor: 'instance creation'!
  434. on: anInterpreter
  435. ^ self new
  436. interpreter: anInterpreter;
  437. yourself
  438. ! !
  439. NodeVisitor subclass: #ASTInterpreter
  440. instanceVariableNames: 'node context stack returnValue returned forceAtEnd refResults'
  441. package: 'Compiler-Interpreter'!
  442. !ASTInterpreter commentStamp!
  443. I visit an AST, interpreting (evaluating) nodes one after the other, using a small stack machine.
  444. ## API
  445. While my instances should be used from within an `ASTDebugger`, which provides a more high level interface,
  446. you can use methods from the `interpreting` protocol:
  447. - `#step` evaluates the current `node` only
  448. - `#stepOver` evaluates the AST from the current `node` up to the next stepping node (most likely the next send node)
  449. - `#proceed` evaluates eagerly the AST
  450. - `#restart` select the first node of the AST
  451. - `#skip` skips the current node, moving to the next one if any!
  452. !ASTInterpreter methodsFor: 'accessing'!
  453. context
  454. ^ context
  455. !
  456. context: aContext
  457. context := aContext
  458. !
  459. node
  460. "Answer the next node, ie the node to be evaluated in the next step"
  461. ^ node
  462. !
  463. node: aNode
  464. node := aNode
  465. !
  466. refResults
  467. ^ refResults
  468. !
  469. result
  470. ^ self hasReturned
  471. ifTrue: [ self returnValue ]
  472. ifFalse: [ self context receiver ]
  473. !
  474. returnValue
  475. ^ returnValue
  476. !
  477. returnValue: anObject
  478. returnValue := anObject
  479. !
  480. stack
  481. ^ stack ifNil: [ stack := OrderedCollection new ]
  482. ! !
  483. !ASTInterpreter methodsFor: 'initialization'!
  484. initialize
  485. super initialize.
  486. refResults := #{}.
  487. forceAtEnd := false
  488. ! !
  489. !ASTInterpreter methodsFor: 'interpreting'!
  490. enterNode
  491. self node: ((ASTEnterNode on: self) visit: self node)
  492. !
  493. interpret
  494. "Interpret the next node to be evaluated"
  495. self visit: self node
  496. !
  497. next
  498. | nd nextNode |
  499. nd := self node.
  500. nextNode := nd parent ifNotNil: [ :parent |
  501. (parent nextSiblingNode: nd)
  502. ifNil: [ parent ]
  503. ifNotNil: [ :sibling | (ASTEnterNode on: self) visit: sibling ] ].
  504. self node: nextNode
  505. !
  506. proceed
  507. "Eagerly evaluate the ast"
  508. [ self atEnd ]
  509. whileFalse: [ self step ]
  510. !
  511. restart
  512. self node: self context ast; enterNode
  513. !
  514. setNonLocalReturnFromContext: aContext
  515. aContext interpreter hasReturned ifTrue: [
  516. returned := true.
  517. self returnValue: aContext interpreter returnValue ]
  518. !
  519. skip
  520. self next
  521. !
  522. step
  523. self
  524. interpret;
  525. next
  526. !
  527. stepOver
  528. self step.
  529. [ self node isNil or: [ self node isSteppingNode ] ] whileFalse: [
  530. self step ]
  531. ! !
  532. !ASTInterpreter methodsFor: 'private'!
  533. assign: aNode to: anObject
  534. aNode binding isInstanceVar
  535. ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]
  536. ifFalse: [ self context localAt: aNode value put: anObject ]
  537. !
  538. eval: aString
  539. "Evaluate aString as JS source inside an JS function.
  540. aString is not sandboxed."
  541. | source function |
  542. source := String streamContents: [ :str |
  543. str nextPutAll: '0,(function('.
  544. self context locals keys
  545. do: [ :each | str nextPutAll: each ]
  546. separatedBy: [ str nextPutAll: ',' ].
  547. str
  548. nextPutAll: '){ return (function() {';
  549. nextPutAll: aString;
  550. nextPutAll: '})()})' ].
  551. function := Compiler new eval: source.
  552. ^ function valueWithPossibleArguments: self context locals values
  553. !
  554. messageFromSendNode: aSendNode arguments: aCollection
  555. ^ Message new
  556. selector: aSendNode selector;
  557. arguments: aCollection;
  558. yourself
  559. !
  560. messageNotUnderstood: aMessage receiver: anObject
  561. MessageNotUnderstood new
  562. message: aMessage;
  563. receiver: anObject;
  564. signal
  565. !
  566. sendMessage: aMessage to: anObject superSend: aBoolean
  567. | method |
  568. aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].
  569. anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  570. method := anObject class superclass methodDictionary
  571. at: aMessage selector
  572. ifAbsent: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  573. ^ method sendTo: anObject arguments: aMessage arguments
  574. ! !
  575. !ASTInterpreter methodsFor: 'stack'!
  576. peek
  577. "Peek the top object of the context stack"
  578. self stack ifEmpty: [ ^ nil ].
  579. ^ self stack last
  580. !
  581. pop
  582. "Pop an object from the context stack"
  583. | peekedValue |
  584. peekedValue := self peek.
  585. self stack removeLast.
  586. ^ peekedValue
  587. !
  588. push: anObject
  589. "Push an object to the context stack"
  590. ^ self stack add: anObject
  591. ! !
  592. !ASTInterpreter methodsFor: 'testing'!
  593. atEnd
  594. forceAtEnd ifTrue: [ ^ true ].
  595. ^ self hasReturned or: [ self node isNil ]
  596. !
  597. hasReturned
  598. ^ returned ifNil: [ false ]
  599. ! !
  600. !ASTInterpreter methodsFor: 'visiting'!
  601. visit: aNode
  602. self hasReturned ifFalse: [ super visit: aNode ]
  603. !
  604. visitAssignmentNode: aNode
  605. | poppedValue |
  606. poppedValue := self pop.
  607. "Pop the left side of the assignment.
  608. It already has been visited, and we don't need its value."
  609. self pop.
  610. self push: poppedValue.
  611. self assign: aNode left to: poppedValue
  612. !
  613. visitBlockNode: aNode
  614. "Do not evaluate the block node.
  615. Instead, put all instructions into a block that we push to the stack for later evaluation"
  616. | block |
  617. block := AIBlockClosure forContext: self context node: aNode.
  618. self push: block
  619. !
  620. visitBlockSequenceNode: aNode
  621. "If the receiver is actually visiting a BlockSequenceNode,
  622. it means the the context is a block context. Evaluation should
  623. stop right after evaluating the block sequence and the outer
  624. context's interpreter should take over.
  625. Therefore we force #atEnd."
  626. super visitBlockSequenceNode: aNode.
  627. forceAtEnd := true
  628. !
  629. visitDynamicArrayNode: aNode
  630. | array |
  631. array := #().
  632. aNode nodes do: [ :each |
  633. array addFirst: self pop ].
  634. self push: array
  635. !
  636. visitDynamicDictionaryNode: aNode
  637. | keyValueList |
  638. keyValueList := OrderedCollection new.
  639. aNode nodes do: [ :each |
  640. keyValueList add: self pop ].
  641. self push: (HashedCollection newFromPairs: keyValueList reversed)
  642. !
  643. visitJSStatementNode: aNode
  644. returned := true.
  645. self returnValue: (self eval: aNode source)
  646. !
  647. visitNode: aNode
  648. "Do nothing by default. Especially, do not visit children recursively."
  649. !
  650. visitRefNode: aNode
  651. | ref refid |
  652. ref := aNode node.
  653. refid := ref nodeId.
  654. self refResults at: refid ifAbsentPut: [ self pop ].
  655. self push: (self refResults at: refid)
  656. !
  657. visitReturnNode: aNode
  658. returned := true.
  659. self returnValue: self pop
  660. !
  661. visitSendNode: aNode
  662. | receiver args message result |
  663. args := aNode arguments collect: [ :each | self pop ].
  664. receiver := self pop.
  665. message := self
  666. messageFromSendNode: aNode
  667. arguments: args reversed.
  668. result := self sendMessage: message to: receiver superSend: aNode superSend.
  669. "For cascade sends, push the reciever if the send is not the last one"
  670. (aNode isCascadeSendNode and: [ aNode isLastChild not ])
  671. ifFalse: [ self push: result ]
  672. !
  673. visitValueNode: aNode
  674. self push: aNode value
  675. !
  676. visitVariableNode: aNode
  677. aNode binding isUnknownVar ifTrue: [
  678. ^ self push: (Platform globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].
  679. self push: (aNode binding isInstanceVar
  680. ifTrue: [ self context receiver instVarAt: aNode value ]
  681. ifFalse: [ self context
  682. localAt: aNode value
  683. ifAbsent: [
  684. aNode value isCapitalized
  685. ifTrue: [
  686. Smalltalk globals
  687. at: aNode value
  688. ifAbsent: [ Platform globals at: aNode value ] ] ] ])
  689. ! !
  690. Error subclass: #ASTInterpreterError
  691. instanceVariableNames: ''
  692. package: 'Compiler-Interpreter'!
  693. !ASTInterpreterError commentStamp!
  694. I get signaled when an AST interpreter is unable to interpret a node.!
  695. NodeVisitor subclass: #ASTPCNodeVisitor
  696. instanceVariableNames: 'context index selector currentNode'
  697. package: 'Compiler-Interpreter'!
  698. !ASTPCNodeVisitor commentStamp!
  699. I visit an AST until I get to the current node for the `context` and answer it.
  700. ## API
  701. My instances must be filled with a context object using `#context:`.
  702. After visiting the AST the current node is answered by `#currentNode`!
  703. !ASTPCNodeVisitor methodsFor: 'accessing'!
  704. context
  705. ^ context
  706. !
  707. context: aContext
  708. context := aContext
  709. !
  710. currentNode
  711. ^ currentNode
  712. !
  713. increaseIndex
  714. index := self index + 1
  715. !
  716. index
  717. ^ index ifNil: [ index := 0 ]
  718. !
  719. selector
  720. ^ selector
  721. !
  722. selector: aString
  723. selector := aString
  724. ! !
  725. !ASTPCNodeVisitor methodsFor: 'visiting'!
  726. visitJSStatementNode: aNode
  727. "If a JSStatementNode is encountered, it always is the current node.
  728. Stop visiting the AST there"
  729. currentNode := aNode
  730. !
  731. visitSendNode: aNode
  732. | sendIndex |
  733. sendIndex := self context sendIndexAt: self selector.
  734. super visitSendNode: aNode.
  735. self selector = aNode selector ifTrue: [
  736. self index = sendIndex ifTrue: [ currentNode := aNode ].
  737. self increaseIndex ]
  738. ! !
  739. !AssignmentNode methodsFor: '*Compiler-Interpreter'!
  740. isSteppingNode
  741. ^ true
  742. ! !
  743. !BlockNode methodsFor: '*Compiler-Interpreter'!
  744. isSteppingNode
  745. ^ true
  746. !
  747. nextSiblingNode: aNode
  748. "Answer nil as we want to avoid eager evaluation"
  749. "In fact, this should not have been called, ever. IMO. -- herby"
  750. ^ nil
  751. ! !
  752. !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
  753. isSteppingNode
  754. ^ true
  755. ! !
  756. !DynamicDictionaryNode methodsFor: '*Compiler-Interpreter'!
  757. isSteppingNode
  758. ^ true
  759. ! !
  760. !JSStatementNode methodsFor: '*Compiler-Interpreter'!
  761. isSteppingNode
  762. ^ true
  763. ! !
  764. !Node methodsFor: '*Compiler-Interpreter'!
  765. isSteppingNode
  766. ^ false
  767. !
  768. nextSiblingNode: aNode
  769. "Answer the next node after aNode or nil"
  770. ^ self nodes
  771. at: (self nodes indexOf: aNode) + 1
  772. ifAbsent: [ ^ nil ]
  773. ! !
  774. !RefNode methodsFor: '*Compiler-Interpreter'!
  775. nextSiblingNode: aNode
  776. "no siblings in ref node"
  777. ^ nil
  778. ! !
  779. !SendNode methodsFor: '*Compiler-Interpreter'!
  780. isSteppingNode
  781. ^ true
  782. ! !