Compiler-Interpreter.st 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. Smalltalk createPackage: 'Compiler-Interpreter'!
  2. BlockClosure subclass: #AIBlockClosure
  3. slots: {#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 sequenceNode 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. Object subclass: #AIContext
  76. slots: {#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. home
  93. ^ nil
  94. !
  95. index
  96. ^ index ifNil: [ 0 ]
  97. !
  98. index: anInteger
  99. index := anInteger
  100. !
  101. innerContext
  102. ^ innerContext
  103. !
  104. innerContext: anAIContext
  105. innerContext := anAIContext
  106. !
  107. localAt: aString
  108. "Lookup the local value up to the method context"
  109. | context |
  110. context := self lookupContextForLocal: aString.
  111. ^ context basicLocalAt: aString
  112. !
  113. localAt: aString ifAbsent: aBlock
  114. "Lookup the local value up to the method context"
  115. | context |
  116. context := self
  117. lookupContextForLocal: aString
  118. ifNone: [ ^ aBlock value ].
  119. ^ context basicLocalAt: aString
  120. !
  121. localAt: aString put: anObject
  122. | context |
  123. context := self lookupContextForLocal: aString.
  124. context basicLocalAt: aString put: anObject
  125. !
  126. locals
  127. locals ifNil: [ self initializeLocals ].
  128. ^ locals
  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;
  166. enterNode;
  167. proceed;
  168. result
  169. ! !
  170. !AIContext methodsFor: 'factory'!
  171. newInnerContext
  172. ^ self class new
  173. outerContext: self;
  174. yourself
  175. ! !
  176. !AIContext methodsFor: 'initialization'!
  177. initializeAST
  178. ast := self method ast.
  179. (SemanticAnalyzer on: self method origin)
  180. visit: ast
  181. !
  182. initializeFromMethodContext: aMethodContext
  183. self
  184. evaluatedSelector: aMethodContext evaluatedSelector;
  185. index: aMethodContext index;
  186. sendIndexes: aMethodContext sendIndexes;
  187. receiver: aMethodContext receiver;
  188. supercall: aMethodContext supercall;
  189. selector: aMethodContext selector.
  190. aMethodContext outerContext ifNotNil: [ :outer |
  191. "If the method context is nil, the block was defined in JS, so ignore it"
  192. outer methodContext ifNotNil: [
  193. self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
  194. aMethodContext locals keysAndValuesDo: [ :key :value |
  195. self locals at: key put: value ] ]
  196. !
  197. initializeInterpreter
  198. interpreter := ASTInterpreter new
  199. context: self;
  200. yourself.
  201. self innerContext ifNotNil: [
  202. self setupInterpreter: interpreter ]
  203. !
  204. initializeLocals
  205. locals := Dictionary new.
  206. locals at: 'thisContext' put: self.
  207. ! !
  208. !AIContext methodsFor: 'interpreting'!
  209. arguments
  210. ^ self ast arguments collect: [ :each |
  211. self localAt: each ifAbsent: [ self error: 'Argument not in context' ] ]
  212. !
  213. ast
  214. self isBlockContext ifTrue: [
  215. ^ self outerContext ifNotNil: [ :context | context ast ] ].
  216. ast ifNil: [ self initializeAST ].
  217. ^ ast
  218. !
  219. basicReceiver
  220. ^ self localAt: 'self'
  221. !
  222. interpreter
  223. interpreter ifNil: [ self initializeInterpreter ].
  224. ^ interpreter
  225. !
  226. interpreter: anInterpreter
  227. interpreter := anInterpreter
  228. !
  229. receiver: anObject
  230. self locals at: 'self' put: anObject
  231. !
  232. setupInterpreter: anInterpreter
  233. | currentNode |
  234. "Retrieve the current node"
  235. currentNode := ASTPCNodeVisitor new
  236. selector: self evaluatedSelector;
  237. index: (self sendIndexAt: self evaluatedSelector);
  238. visit: self ast;
  239. currentNode.
  240. "Define locals for the context"
  241. self ast sequenceNode ifNotNil: [ :sequence |
  242. sequence temps do: [ :each |
  243. self defineLocal: each ] ].
  244. anInterpreter node: currentNode.
  245. "Push the send args and receiver to the interpreter stack"
  246. self innerContext arguments reversed do: [ :each |
  247. anInterpreter push: each ].
  248. anInterpreter push: (self innerContext receiver)
  249. !
  250. supercall
  251. ^ supercall ifNil: [ false ]
  252. !
  253. supercall: aBoolean
  254. supercall := aBoolean
  255. ! !
  256. !AIContext methodsFor: 'private'!
  257. basicLocalAt: aString
  258. ^ self locals at: aString
  259. !
  260. basicLocalAt: aString put: anObject
  261. self locals at: aString put: anObject
  262. !
  263. lookupContextForLocal: aString
  264. "Lookup the context defining the local named `aString`
  265. up to the method context"
  266. ^ self
  267. lookupContextForLocal: aString
  268. ifNone: [ self variableNotFound ]
  269. !
  270. lookupContextForLocal: aString ifNone: aBlock
  271. "Lookup the context defining the local named `aString`
  272. up to the method context"
  273. ^ self locals
  274. at: aString
  275. ifPresent: [ self ]
  276. ifAbsent: [
  277. self outerContext
  278. ifNil: aBlock
  279. ifNotNil: [ :context |
  280. context lookupContextForLocal: aString ifNone: aBlock ] ]
  281. ! !
  282. !AIContext methodsFor: 'testing'!
  283. isTopContext
  284. ^ self innerContext isNil
  285. ! !
  286. !AIContext class methodsFor: 'instance creation'!
  287. fromMethodContext: aMethodContext
  288. ^ self new
  289. initializeFromMethodContext: aMethodContext;
  290. yourself
  291. ! !
  292. SemanticAnalyzer subclass: #AISemanticAnalyzer
  293. slots: {#context}
  294. package: 'Compiler-Interpreter'!
  295. !AISemanticAnalyzer commentStamp!
  296. I perform the same semantic analysis than `SemanticAnalyzer`, with the difference that provided an `AIContext` context, variables are bound with the context variables.!
  297. !AISemanticAnalyzer methodsFor: 'accessing'!
  298. context
  299. ^ context
  300. !
  301. context: anAIContext
  302. context := anAIContext
  303. ! !
  304. !AISemanticAnalyzer methodsFor: 'visiting'!
  305. visitVariableNode: aNode
  306. self context
  307. localAt: aNode identifier
  308. ifAbsent: [ ^ super visitVariableNode: aNode ].
  309. aNode binding: ASTContextVar new
  310. ! !
  311. ScopeVar subclass: #ASTContextVar
  312. slots: {#context}
  313. package: 'Compiler-Interpreter'!
  314. !ASTContextVar commentStamp!
  315. I am a variable defined in a `context`.!
  316. !ASTContextVar methodsFor: 'accessing'!
  317. context
  318. ^ context
  319. !
  320. context: anObject
  321. context := anObject
  322. ! !
  323. Object subclass: #ASTDebugger
  324. slots: {#interpreter. #context. #result}
  325. package: 'Compiler-Interpreter'!
  326. !ASTDebugger commentStamp!
  327. I am a stepping debugger interface for Amber code.
  328. I internally use an instance of `ASTInterpreter` to actually step through node and interpret them.
  329. My instances are created from an `AIContext` with `ASTDebugger class >> context:`.
  330. They hold an `AIContext` instance internally, recursive copy of the `MethodContext`.
  331. ## API
  332. Use the methods of the `'stepping'` protocol to do stepping.!
  333. !ASTDebugger methodsFor: 'accessing'!
  334. context
  335. ^ context
  336. !
  337. context: aContext
  338. context := aContext
  339. !
  340. interpreter
  341. ^ self context ifNotNil: [ :ctx |
  342. ctx interpreter ]
  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. slots: {#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. visitDagNode: aNode
  417. ^ aNode dagChildren
  418. ifEmpty: [ aNode ]
  419. ifNotEmpty: [ :nodes | self visit: nodes first ]
  420. !
  421. visitSequenceNode: aNode
  422. aNode temps do: [ :each |
  423. self interpreter context defineLocal: each ].
  424. ^ super visitSequenceNode: aNode
  425. ! !
  426. !ASTEnterNode class methodsFor: 'instance creation'!
  427. on: anInterpreter
  428. ^ self new
  429. interpreter: anInterpreter;
  430. yourself
  431. ! !
  432. NodeVisitor subclass: #ASTInterpreter
  433. slots: {#node. #context. #stack. #returnValue. #returned. #forceAtEnd}
  434. package: 'Compiler-Interpreter'!
  435. !ASTInterpreter commentStamp!
  436. I visit an AST, interpreting (evaluating) nodes one after the other, using a small stack machine.
  437. ## API
  438. While my instances should be used from within an `ASTDebugger`, which provides a more high level interface,
  439. you can use methods from the `interpreting` protocol:
  440. - `#step` evaluates the current `node` only
  441. - `#stepOver` evaluates the AST from the current `node` up to the next stepping node (most likely the next send node)
  442. - `#proceed` evaluates eagerly the AST
  443. - `#restart` select the first node of the AST
  444. - `#skip` skips the current node, moving to the next one if any!
  445. !ASTInterpreter methodsFor: 'accessing'!
  446. context
  447. ^ context
  448. !
  449. context: aContext
  450. context := aContext
  451. !
  452. node
  453. "Answer the next node, ie the node to be evaluated in the next step"
  454. ^ node
  455. !
  456. node: aNode
  457. node := aNode
  458. !
  459. result
  460. ^ self hasReturned
  461. ifTrue: [ self returnValue ]
  462. ifFalse: [ self context receiver ]
  463. !
  464. returnValue
  465. ^ returnValue
  466. !
  467. returnValue: anObject
  468. returnValue := anObject
  469. !
  470. stack
  471. ^ stack ifNil: [ stack := OrderedCollection new ]
  472. ! !
  473. !ASTInterpreter methodsFor: 'initialization'!
  474. initialize
  475. super initialize.
  476. forceAtEnd := false
  477. ! !
  478. !ASTInterpreter methodsFor: 'interpreting'!
  479. enterNode
  480. self node: ((ASTEnterNode on: self) visit: self node)
  481. !
  482. interpret
  483. "Interpret the next node to be evaluated"
  484. self visit: self node
  485. !
  486. next
  487. | nd parent |
  488. nd := self node.
  489. parent := nd parent.
  490. (parent ifNotNil: [ parent nextSiblingNode: nd ])
  491. ifNil: [ self node: parent ]
  492. ifNotNil: [ :sibling | self node: sibling; enterNode ]
  493. !
  494. proceed
  495. "Eagerly evaluate the ast"
  496. [ self atEnd ]
  497. whileFalse: [ self step ]
  498. !
  499. restart
  500. self node: self context ast; enterNode
  501. !
  502. setNonLocalReturnFromContext: aContext
  503. aContext interpreter hasReturned ifTrue: [
  504. returned := true.
  505. self returnValue: aContext interpreter returnValue ]
  506. !
  507. skip
  508. self next
  509. !
  510. step
  511. self
  512. interpret;
  513. next
  514. !
  515. stepOver
  516. self step.
  517. [ self node isNil or: [ self node isSteppingNode ] ] whileFalse: [
  518. self step ]
  519. ! !
  520. !ASTInterpreter methodsFor: 'private'!
  521. assign: aNode to: anObject
  522. aNode binding inContext: self context put: anObject
  523. !
  524. eval: aString
  525. "Evaluate aString as JS source inside an JS function.
  526. aString is not sandboxed."
  527. | source function |
  528. source := String streamContents: [ :str |
  529. str nextPutAll: '0,(function('.
  530. self context locals keys
  531. do: [ :each | str nextPutAll: each ]
  532. separatedBy: [ str nextPutAll: ',' ].
  533. str
  534. nextPutAll: '){ return (function() {';
  535. nextPutAll: aString;
  536. nextPutAll: '})()})' ].
  537. function := Compiler eval: source.
  538. ^ function valueWithPossibleArguments: self context locals values
  539. !
  540. messageFromSendNode: aSendNode arguments: anArray
  541. ^ Message selector: aSendNode selector arguments: anArray
  542. !
  543. messageNotUnderstood: aMessage receiver: anObject
  544. MessageNotUnderstood new
  545. message: aMessage;
  546. receiver: anObject;
  547. signal
  548. !
  549. sendJavaScript: aString superMessage: aMessage switcher: aJSFunction to: anObject
  550. | methodBlock parent |
  551. parent := self context method methodClass superPrototype.
  552. parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  553. methodBlock := (parent at: aString)
  554. ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  555. ^ methodBlock applyTo: anObject arguments: (aJSFunction applyTo: nil arguments: aMessage arguments)
  556. !
  557. sendJavaScript: aString superMessage: aMessage to: anObject
  558. | methodBlock parent |
  559. parent := self context method methodClass superPrototype.
  560. parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  561. methodBlock := (parent at: aString)
  562. ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  563. ^ methodBlock applyTo: anObject arguments: aMessage arguments
  564. !
  565. sendSuperMessage: aMessage to: anObject
  566. | method parent |
  567. parent := self context method methodClass superclass.
  568. parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  569. method := (parent lookupSelector: aMessage selector)
  570. ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  571. ^ method sendTo: anObject arguments: aMessage arguments
  572. ! !
  573. !ASTInterpreter methodsFor: 'stack'!
  574. peek
  575. "Peek the top object of the context stack"
  576. self stack ifEmpty: [ ^ nil ].
  577. ^ self stack last
  578. !
  579. pop
  580. "Pop an object from the context stack"
  581. | peekedValue |
  582. peekedValue := self peek.
  583. self stack removeLast.
  584. ^ peekedValue
  585. !
  586. push: anObject
  587. "Push an object to the context stack"
  588. ^ self stack add: anObject
  589. ! !
  590. !ASTInterpreter methodsFor: 'testing'!
  591. atEnd
  592. ^ forceAtEnd or: [ self hasReturned or: [ self node isNil ] ]
  593. !
  594. hasReturned
  595. ^ returned ifNil: [ false ]
  596. ! !
  597. !ASTInterpreter methodsFor: 'visiting'!
  598. visit: aNode
  599. self hasReturned ifFalse: [ super visit: aNode ]
  600. !
  601. visitAssignmentNode: aNode
  602. | poppedValue |
  603. poppedValue := self pop.
  604. "Pop the left side of the assignment.
  605. It already has been visited, and we don't need its value."
  606. self pop.
  607. self push: poppedValue.
  608. self assign: aNode left to: poppedValue
  609. !
  610. visitBlockNode: aNode
  611. "Do not evaluate the block node.
  612. Instead, put all instructions into a block that we push to the stack for later evaluation"
  613. | block |
  614. block := AIBlockClosure forContext: self context node: aNode.
  615. self push: block
  616. !
  617. visitBlockSequenceNode: aNode
  618. "If the receiver is actually visiting a BlockSequenceNode,
  619. it means the the context is a block context. Evaluation should
  620. stop right after evaluating the block sequence and the outer
  621. context's interpreter should take over.
  622. Therefore we force #atEnd."
  623. super visitBlockSequenceNode: aNode.
  624. forceAtEnd := true
  625. !
  626. visitDagNode: aNode
  627. "Do nothing by default. Especially, do not visit children recursively."
  628. !
  629. visitDynamicArrayNode: aNode
  630. | array |
  631. array := #().
  632. aNode dagChildren do: [ :each |
  633. array addFirst: self pop ].
  634. self push: array
  635. !
  636. visitDynamicDictionaryNode: aNode
  637. | keyValueList |
  638. keyValueList := OrderedCollection new.
  639. aNode dagChildren 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. visitReturnNode: aNode
  648. returned := true.
  649. self returnValue: self pop
  650. !
  651. visitSendNode: aNode
  652. | receiver args message result |
  653. args := aNode arguments collect: [ :each | self pop ].
  654. receiver := self peek.
  655. message := self
  656. messageFromSendNode: aNode
  657. arguments: args reversed.
  658. result := aNode superSend
  659. ifFalse: [ message sendTo: receiver ]
  660. ifTrue: [ aNode receiver binding isJavaScriptSuper
  661. ifFalse: [ self sendSuperMessage: message to: receiver ]
  662. ifTrue: [ aNode argumentSwitcher
  663. ifNil: [ self sendJavaScript: aNode javaScriptSelector superMessage: message to: receiver ]
  664. ifNotNil: [ :switcher | self sendJavaScript: aNode javaScriptSelector superMessage: message switcher: switcher to: receiver ] ] ].
  665. "For cascade sends, push the reciever if the send is not the last one"
  666. aNode isSideEffect ifFalse: [ self pop; push: result ]
  667. !
  668. visitValueNode: aNode
  669. self push: aNode value
  670. !
  671. visitVariableNode: aNode
  672. self push: (aNode binding inContext: self context)
  673. ! !
  674. Error subclass: #ASTInterpreterError
  675. slots: {}
  676. package: 'Compiler-Interpreter'!
  677. !ASTInterpreterError commentStamp!
  678. I get signaled when an AST interpreter is unable to interpret a node.!
  679. NodeVisitor subclass: #ASTPCNodeVisitor
  680. slots: {#index. #trackedIndex. #selector. #currentNode}
  681. package: 'Compiler-Interpreter'!
  682. !ASTPCNodeVisitor commentStamp!
  683. I visit an AST until I get to the current node for the `context` and answer it.
  684. ## API
  685. My instances must be filled with a context object using `#context:`.
  686. After visiting the AST the current node is answered by `#currentNode`!
  687. !ASTPCNodeVisitor methodsFor: 'accessing'!
  688. currentNode
  689. ^ currentNode
  690. !
  691. increaseTrackedIndex
  692. trackedIndex := self trackedIndex + 1
  693. !
  694. index
  695. ^ index
  696. !
  697. index: aNumber
  698. index := aNumber
  699. !
  700. selector
  701. ^ selector
  702. !
  703. selector: aString
  704. selector := aString
  705. !
  706. trackedIndex
  707. ^ trackedIndex ifNil: [ trackedIndex := 0 ]
  708. ! !
  709. !ASTPCNodeVisitor methodsFor: 'visiting'!
  710. visitJSStatementNode: aNode
  711. "If a JSStatementNode is encountered, it always is the current node.
  712. Stop visiting the AST there"
  713. currentNode := aNode
  714. !
  715. visitSendNode: aNode
  716. super visitSendNode: aNode.
  717. self selector = aNode selector ifTrue: [
  718. self trackedIndex = self index ifTrue: [ currentNode := aNode ].
  719. self increaseTrackedIndex ]
  720. ! !
  721. AIContext setTraitComposition: {TMethodContext} asTraitComposition!
  722. ! !
  723. !ASTNode methodsFor: '*Compiler-Interpreter'!
  724. isSteppingNode
  725. ^ false
  726. !
  727. nextSiblingNode: aNode
  728. "Answer the next node after aNode or nil"
  729. ^ self dagChildren
  730. at: (self dagChildren indexOf: aNode) + 1
  731. ifAbsent: [ nil ]
  732. ! !
  733. !AliasVar methodsFor: '*Compiler-Interpreter'!
  734. inContext: aContext
  735. self error: 'Alias variable is internal, it should never appear in normal variable context.'
  736. ! !
  737. !AssignmentNode methodsFor: '*Compiler-Interpreter'!
  738. isSteppingNode
  739. ^ true
  740. ! !
  741. !BlockNode methodsFor: '*Compiler-Interpreter'!
  742. isSteppingNode
  743. ^ true
  744. !
  745. nextSiblingNode: aNode
  746. "Answer nil as we want to avoid eager evaluation"
  747. "In fact, this should not have been called, ever. IMO. -- herby"
  748. ^ nil
  749. ! !
  750. !ClassRefVar methodsFor: '*Compiler-Interpreter'!
  751. inContext: aContext
  752. ^ Smalltalk globals
  753. at: self name
  754. ifAbsent: [ Platform globals at: self name ]
  755. ! !
  756. !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
  757. isSteppingNode
  758. ^ true
  759. ! !
  760. !DynamicDictionaryNode methodsFor: '*Compiler-Interpreter'!
  761. isSteppingNode
  762. ^ true
  763. ! !
  764. !Evaluator methodsFor: '*Compiler-Interpreter'!
  765. evaluate: aString context: aContext
  766. "Similar to #evaluate:for:, with the following differences:
  767. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  768. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  769. | compiler ast |
  770. compiler := Compiler new.
  771. [ ast := compiler parseExpression: aString ]
  772. on: Error
  773. do: [ :ex | ^ Terminal alert: ex messageText ].
  774. (AISemanticAnalyzer on: aContext receiver class)
  775. context: aContext;
  776. visit: ast.
  777. ^ aContext evaluateNode: ast
  778. ! !
  779. !ExternallyKnownVar methodsFor: '*Compiler-Interpreter'!
  780. inContext: aContext
  781. ^ Platform globals at: self name ifAbsent: [ self error: 'Unknown variable' ]
  782. ! !
  783. !JSStatementNode methodsFor: '*Compiler-Interpreter'!
  784. isSteppingNode
  785. ^ true
  786. ! !
  787. !JavaScriptSuperVar methodsFor: '*Compiler-Interpreter'!
  788. isJavaScriptSuper
  789. ^ true
  790. ! !
  791. !PseudoVar methodsFor: '*Compiler-Interpreter'!
  792. inContext: aContext
  793. ^ #{'nil'->nil. 'true'->true. 'false'->false}
  794. at: self name
  795. ifAbsent: [ super inContext: aContext ]
  796. ! !
  797. !ScopeVar methodsFor: '*Compiler-Interpreter'!
  798. inContext: aContext
  799. ^ aContext localAt: self name
  800. !
  801. inContext: aContext put: anObject
  802. self error: 'Non-assignable variables should not be changed.'
  803. ! !
  804. !SendNode methodsFor: '*Compiler-Interpreter'!
  805. isSteppingNode
  806. ^ true
  807. ! !
  808. !SlotVar methodsFor: '*Compiler-Interpreter'!
  809. inContext: aContext
  810. ^ aContext receiver instVarNamed: self name
  811. !
  812. inContext: aContext put: anObject
  813. aContext receiver instVarNamed: self name put: anObject
  814. ! !
  815. !SuperVar methodsFor: '*Compiler-Interpreter'!
  816. inContext: aContext
  817. ^ aContext localAt: 'self'
  818. !
  819. isJavaScriptSuper
  820. ^ false
  821. ! !
  822. !TempVar methodsFor: '*Compiler-Interpreter'!
  823. inContext: aContext put: anObject
  824. aContext localAt: self name put: anObject
  825. ! !