Compiler-Interpreter.st 19 KB

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