Compiler-Interpreter.st 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. Smalltalk current createPackage: 'Compiler-Interpreter'!
  2. NodeVisitor subclass: #AIContext
  3. instanceVariableNames: 'methodContext outerContext pc locals method'
  4. package: 'Compiler-Interpreter'!
  5. !AIContext commentStamp!
  6. I am like a `MethodContext`, used by the `ASTInterpreter`.
  7. Unlike a `MethodContext`, my instances are not read-only.
  8. When debugging, my instances are created by copying the current `MethodContext` (thisContext)!
  9. !AIContext methodsFor: 'accessing'!
  10. home
  11. ^ self isBlockContext
  12. ifTrue: [ self outerContext methodContext ]
  13. ifFalse: [ self ]
  14. !
  15. localAt: aString
  16. ^ self locals at: aString ifAbsent: [ nil ]
  17. !
  18. localAt: aString put: anObject
  19. self locals at: aString put: anObject
  20. !
  21. locals
  22. locals ifNil: [ self initializeLocals ].
  23. ^ locals
  24. !
  25. method
  26. ^ method
  27. !
  28. method: aCompiledMethod
  29. method := aCompiledMethod
  30. !
  31. outerContext
  32. ^ outerContext
  33. !
  34. outerContext: anAIContext
  35. outerContext := anAIContext
  36. !
  37. pc
  38. ^ pc ifNil: [ pc := 0 ]
  39. !
  40. pc: anInteger
  41. pc := anInteger
  42. !
  43. receiver
  44. ^ self localAt: 'self'
  45. !
  46. receiver: anObject
  47. self localAt: 'self' put: anObject
  48. !
  49. selector
  50. ^ self method
  51. ifNotNil: [ self method selector ]
  52. ! !
  53. !AIContext methodsFor: 'converting'!
  54. asString
  55. ^ methodContext asString
  56. ! !
  57. !AIContext methodsFor: 'initialization'!
  58. initializeFromMethodContext: aMethodContext
  59. methodContext := aMethodContext.
  60. self pc: aMethodContext pc.
  61. self receiver: aMethodContext receiver.
  62. self method: aMethodContext method.
  63. aMethodContext outerContext ifNotNil: [
  64. self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
  65. aMethodContext locals keysAndValuesDo: [ :key :value |
  66. self locals at: key put: value ]
  67. !
  68. initializeLocals
  69. locals := Dictionary new.
  70. locals at: 'thisContext' put: self.
  71. ! !
  72. !AIContext methodsFor: 'testing'!
  73. isBlockContext
  74. ^ methodContext isBlockContext
  75. ! !
  76. !AIContext class methodsFor: 'instance creation'!
  77. fromMethodContext: aMethodContext
  78. ^ self new
  79. initializeFromMethodContext: aMethodContext;
  80. yourself
  81. ! !
  82. Object subclass: #ASTDebugger
  83. instanceVariableNames: 'interpreter context'
  84. package: 'Compiler-Interpreter'!
  85. !ASTDebugger commentStamp!
  86. I am a stepping debugger interface for Amber code.
  87. I internally use an instance of `ASTSteppingInterpreter` to actually step through node and interpret them.
  88. My instances are created from a `MethodContext` with `ASTDebugger class >> context:`.
  89. They hold an `AIContext` instance internally, recursive copy of the `MethodContext`.
  90. ## API
  91. Use the methods of the `'stepping'` protocol to do stepping.!
  92. !ASTDebugger methodsFor: 'accessing'!
  93. context
  94. ^ context
  95. !
  96. context: aContext
  97. context := AIContext new.
  98. !
  99. interpreter
  100. ^ interpreter ifNil: [ interpreter := self defaultInterpreterClass new ]
  101. !
  102. interpreter: anInterpreter
  103. interpreter := anInterpreter
  104. !
  105. method
  106. ^ self context method
  107. ! !
  108. !ASTDebugger methodsFor: 'defaults'!
  109. defaultInterpreterClass
  110. ^ ASTSteppingInterpreter
  111. ! !
  112. !ASTDebugger methodsFor: 'initialization'!
  113. buildAST
  114. "Build the AST tree from the method source code.
  115. The AST is annotated with a SemanticAnalyzer,
  116. to know the semantics and bindings of each node needed for later debugging"
  117. | ast |
  118. ast := Smalltalk current parse: self method source.
  119. (SemanticAnalyzer on: self context receiver class)
  120. visit: ast.
  121. ^ ast
  122. !
  123. initializeInterpreter
  124. self interpreter interpret: self buildAST nodes first
  125. !
  126. initializeWithContext: aMethodContext
  127. "TODO: do we need to handle block contexts?"
  128. self context: (AIContext fromMethodContext: aMethodContext).
  129. self initializeInterpreter
  130. ! !
  131. !ASTDebugger methodsFor: 'stepping'!
  132. proceed
  133. self shouldBeImplemented
  134. !
  135. restart
  136. self shouldBeImplemented
  137. !
  138. step
  139. "The ASTSteppingInterpreter stops at each node interpretation.
  140. One step will interpret nodes until:
  141. - we get at the end
  142. - the next node is a stepping node (send, assignment, etc.)"
  143. [ (self interpreter nextNode notNil and: [ self interpreter nextNode stopOnStepping ])
  144. or: [ self interpreter atEnd not ] ]
  145. whileFalse: [
  146. self interpreter step.
  147. self step ]
  148. !
  149. stepInto
  150. self shouldBeImplemented
  151. !
  152. stepOver
  153. self step
  154. ! !
  155. !ASTDebugger methodsFor: 'testing'!
  156. atEnd
  157. ^ self interpreter atEnd
  158. ! !
  159. !ASTDebugger class methodsFor: 'instance creation'!
  160. context: aMethodContext
  161. ^ self new
  162. initializeWithContext: aMethodContext;
  163. yourself
  164. ! !
  165. Object subclass: #ASTInterpreter
  166. instanceVariableNames: 'currentNode context shouldReturn result'
  167. package: 'Compiler-Interpreter'!
  168. !ASTInterpreter commentStamp!
  169. I am like a `NodeVisitor`, interpreting nodes one after each other.
  170. I am built using Continuation Passing Style for stepping purposes.
  171. ## Usage example:
  172. | ast interpreter |
  173. ast := Smalltalk current parse: 'foo 1+2+4'.
  174. (SemanticAnalyzer on: Object) visit: ast.
  175. ASTInterpreter new
  176. interpret: ast nodes first;
  177. result "Answers 7"!
  178. !ASTInterpreter methodsFor: 'accessing'!
  179. context
  180. ^ context ifNil: [ context := AIContext new ]
  181. !
  182. context: anAIContext
  183. context := anAIContext
  184. !
  185. currentNode
  186. ^ currentNode
  187. !
  188. result
  189. ^ result
  190. ! !
  191. !ASTInterpreter methodsFor: 'initialization'!
  192. initialize
  193. super initialize.
  194. shouldReturn := false
  195. ! !
  196. !ASTInterpreter methodsFor: 'interpreting'!
  197. interpret: aNode
  198. shouldReturn := false.
  199. self interpret: aNode continue: [ :value |
  200. result := value ]
  201. !
  202. interpret: aNode continue: aBlock
  203. shouldReturn ifTrue: [ ^ self ].
  204. aNode isNode
  205. ifTrue: [
  206. currentNode := aNode.
  207. self interpretNode: aNode continue: [ :value |
  208. self continue: aBlock value: value ] ]
  209. ifFalse: [ self continue: aBlock value: aNode ]
  210. !
  211. interpretAssignmentNode: aNode continue: aBlock
  212. self interpret: aNode right continue: [ :value |
  213. self
  214. continue: aBlock
  215. value: (self assign: aNode left to: value) ]
  216. !
  217. interpretBlockNode: aNode continue: aBlock
  218. self
  219. continue: aBlock
  220. value: [
  221. self withBlockContext: [
  222. self interpret: aNode nodes first; result ] ]
  223. !
  224. interpretBlockSequenceNode: aNode continue: aBlock
  225. self interpretSequenceNode: aNode continue: aBlock
  226. !
  227. interpretCascadeNode: aNode continue: aBlock
  228. "TODO: Handle super sends"
  229. self interpret: aNode receiver continue: [ :receiver |
  230. "Only interpret the receiver once"
  231. aNode nodes do: [ :each | each receiver: receiver ].
  232. self
  233. interpretAll: aNode nodes allButLast
  234. continue: [
  235. self
  236. interpret: aNode nodes last
  237. continue: [ :val | self continue: aBlock value: val ] ] ]
  238. !
  239. interpretClassReferenceNode: aNode continue: aBlock
  240. self continue: aBlock value: (Smalltalk current at: aNode value)
  241. !
  242. interpretDynamicArrayNode: aNode continue: aBlock
  243. self interpretAll: aNode nodes continue: [ :array |
  244. self
  245. continue: aBlock
  246. value: array ]
  247. !
  248. interpretDynamicDictionaryNode: aNode continue: aBlock
  249. self interpretAll: aNode nodes continue: [ :array | | hashedCollection |
  250. hashedCollection := HashedCollection new.
  251. array do: [ :each | hashedCollection add: each ].
  252. self
  253. continue: aBlock
  254. value: hashedCollection ]
  255. !
  256. interpretJSStatementNode: aNode continue: aBlock
  257. shouldReturn := true.
  258. self continue: aBlock value: (self eval: aNode source)
  259. !
  260. interpretMethodNode: aNode continue: aBlock
  261. self interpretAll: aNode nodes continue: [ :array |
  262. self continue: aBlock value: array first ]
  263. !
  264. interpretNode: aNode continue: aBlock
  265. aNode interpreter: self continue: aBlock
  266. !
  267. interpretReturnNode: aNode continue: aBlock
  268. self interpret: aNode nodes first continue: [ :value |
  269. shouldReturn := true.
  270. self continue: aBlock value: value ]
  271. !
  272. interpretSendNode: aNode continue: aBlock
  273. self interpret: aNode receiver continue: [ :receiver |
  274. self interpretAll: aNode arguments continue: [ :args |
  275. self
  276. messageFromSendNode: aNode
  277. arguments: args
  278. do: [ :message |
  279. self context pc: self context pc + 1.
  280. self
  281. continue: aBlock
  282. value: (self sendMessage: message to: receiver superSend: aNode superSend) ] ] ]
  283. !
  284. interpretSequenceNode: aNode continue: aBlock
  285. self interpretAll: aNode nodes continue: [ :array |
  286. self continue: aBlock value: array last ]
  287. !
  288. interpretValueNode: aNode continue: aBlock
  289. self continue: aBlock value: aNode value
  290. !
  291. interpretVariableNode: aNode continue: aBlock
  292. self
  293. continue: aBlock
  294. value: (aNode binding isInstanceVar
  295. ifTrue: [ self context receiver instVarAt: aNode value ]
  296. ifFalse: [ self context localAt: aNode value ])
  297. ! !
  298. !ASTInterpreter methodsFor: 'private'!
  299. assign: aNode to: anObject
  300. ^ aNode binding isInstanceVar
  301. ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]
  302. ifFalse: [ self context localAt: aNode value put: anObject ]
  303. !
  304. continue: aBlock value: anObject
  305. result := anObject.
  306. aBlock value: anObject
  307. !
  308. eval: aString
  309. "Evaluate aString as JS source inside an JS function.
  310. aString is not sandboxed."
  311. | source function |
  312. source := String streamContents: [ :str |
  313. str nextPutAll: '(function('.
  314. self context locals keys
  315. do: [ :each | str nextPutAll: each ]
  316. separatedBy: [ str nextPutAll: ',' ].
  317. str
  318. nextPutAll: '){ return (function() {';
  319. nextPutAll: aString;
  320. nextPutAll: '})() })' ].
  321. function := Compiler new eval: source.
  322. ^ function valueWithPossibleArguments: self context locals values
  323. !
  324. interpretAll: aCollection continue: aBlock
  325. self
  326. interpretAll: aCollection
  327. continue: aBlock
  328. result: OrderedCollection new
  329. !
  330. interpretAll: nodes continue: aBlock result: aCollection
  331. nodes isEmpty
  332. ifTrue: [ self continue: aBlock value: aCollection ]
  333. ifFalse: [
  334. self interpret: nodes first continue: [:value |
  335. self
  336. interpretAll: nodes allButFirst
  337. continue: aBlock
  338. result: aCollection, { value } ] ]
  339. !
  340. messageFromSendNode: aSendNode arguments: aCollection do: aBlock
  341. self
  342. continue: aBlock
  343. value: (Message new
  344. selector: aSendNode selector;
  345. arguments: aCollection;
  346. yourself)
  347. !
  348. sendMessage: aMessage to: anObject superSend: aBoolean
  349. | method |
  350. aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].
  351. anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  352. method := anObject class superclass methodDictionary
  353. at: aMessage selector
  354. ifAbsent: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
  355. ^ method fn applyTo: anObject arguments: aMessage arguments
  356. !
  357. withBlockContext: aBlock
  358. "Evaluate aBlock with a BlockContext:
  359. - a context is pushed before aBlock evaluation.
  360. - the context is poped after aBlock evaluation
  361. - the result of aBlock evaluation is answered"
  362. | blockResult |
  363. self context: (AIContext new
  364. outerContext: self context;
  365. yourself).
  366. blockResult := aBlock value.
  367. self context: self context outerContext.
  368. ^ blockResult
  369. ! !
  370. !ASTInterpreter methodsFor: 'testing'!
  371. shouldReturn
  372. ^ shouldReturn ifNil: [ false ]
  373. ! !
  374. ASTInterpreter subclass: #ASTSteppingInterpreter
  375. instanceVariableNames: 'continuation nextNode'
  376. package: 'Compiler-Interpreter'!
  377. !ASTSteppingInterpreter commentStamp!
  378. I am an interpreter with stepping capabilities. The higher level `ASTDebugger` class should be used as a debugger model, as it provides convenience methods for debugging.
  379. ## API
  380. Use `#step` to actually interpret the next node. Interpretation stops at each node evaluation, weither it's a message node or not.
  381. ## Usage example:
  382. | ast interpreter |
  383. ast := Smalltalk current parse: 'foo 1+2+4'.
  384. (SemanticAnalyzer on: Object) visit: ast.
  385. interpreter := ASTSteppingInterpreter new
  386. interpret: ast nodes first;
  387. yourself.
  388. interpreter step; step.
  389. interpreter step; step.
  390. interpreter result."Answers 1"
  391. interpreter step.
  392. interpreter result. "Answers 3"
  393. interpreter step.
  394. interpreter result. "Answers 7"!
  395. !ASTSteppingInterpreter methodsFor: 'accessing'!
  396. nextNode
  397. ^ nextNode
  398. ! !
  399. !ASTSteppingInterpreter methodsFor: 'initialization'!
  400. initialize
  401. super initialize.
  402. continuation := []
  403. ! !
  404. !ASTSteppingInterpreter methodsFor: 'interpreting'!
  405. interpret: aNode continue: aBlock
  406. nextNode := aNode.
  407. continuation := [
  408. super interpret: aNode continue: aBlock ]
  409. ! !
  410. !ASTSteppingInterpreter methodsFor: 'stepping'!
  411. step
  412. continuation value
  413. ! !
  414. !ASTSteppingInterpreter methodsFor: 'testing'!
  415. atEnd
  416. ^ self shouldReturn or: [ self nextNode == self currentNode ]
  417. ! !
  418. !Node methodsFor: '*Compiler-Interpreter'!
  419. interpreter: anInterpreter continue: aBlock
  420. ^ anInterpreter interpretNode: self continue: aBlock
  421. !
  422. isSteppingNode
  423. ^ false
  424. ! !
  425. !AssignmentNode methodsFor: '*Compiler-Interpreter'!
  426. interpreter: anInterpreter continue: aBlock
  427. ^ anInterpreter interpretAssignmentNode: self continue: aBlock
  428. !
  429. isSteppingNode
  430. ^ true
  431. ! !
  432. !BlockNode methodsFor: '*Compiler-Interpreter'!
  433. interpreter: anInterpreter continue: aBlock
  434. ^ anInterpreter interpretBlockNode: self continue: aBlock
  435. !
  436. isSteppingNode
  437. ^ true
  438. ! !
  439. !CascadeNode methodsFor: '*Compiler-Interpreter'!
  440. interpreter: anInterpreter continue: aBlock
  441. ^ anInterpreter interpretCascadeNode: self continue: aBlock
  442. ! !
  443. !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
  444. interpreter: anInterpreter continue: aBlock
  445. ^ anInterpreter interpretDynamicArrayNode: self continue: aBlock
  446. !
  447. isSteppingNode
  448. ^ true
  449. ! !
  450. !DynamicDictionaryNode methodsFor: '*Compiler-Interpreter'!
  451. interpreter: anInterpreter continue: aBlock
  452. ^ anInterpreter interpretDynamicDictionaryNode: self continue: aBlock
  453. !
  454. isSteppingNode
  455. ^ true
  456. ! !
  457. !JSStatementNode methodsFor: '*Compiler-Interpreter'!
  458. interpreter: anInterpreter continue: aBlock
  459. ^ anInterpreter interpretJSStatementNode: self continue: aBlock
  460. !
  461. isSteppingNode
  462. ^ true
  463. ! !
  464. !MethodNode methodsFor: '*Compiler-Interpreter'!
  465. interpreter: anInterpreter continue: aBlock
  466. ^ anInterpreter interpretMethodNode: self continue: aBlock
  467. ! !
  468. !ReturnNode methodsFor: '*Compiler-Interpreter'!
  469. interpreter: anInterpreter continue: aBlock
  470. ^ anInterpreter interpretReturnNode: self continue: aBlock
  471. ! !
  472. !SendNode methodsFor: '*Compiler-Interpreter'!
  473. interpreter: anInterpreter continue: aBlock
  474. ^ anInterpreter interpretSendNode: self continue: aBlock
  475. !
  476. isSteppingNode
  477. ^ true
  478. ! !
  479. !SequenceNode methodsFor: '*Compiler-Interpreter'!
  480. interpreter: anInterpreter continue: aBlock
  481. ^ anInterpreter interpretSequenceNode: self continue: aBlock
  482. ! !
  483. !BlockSequenceNode methodsFor: '*Compiler-Interpreter'!
  484. interpreter: anInterpreter continue: aBlock
  485. ^ anInterpreter interpretBlockSequenceNode: self continue: aBlock
  486. ! !
  487. !ValueNode methodsFor: '*Compiler-Interpreter'!
  488. interpreter: anInterpreter continue: aBlock
  489. ^ anInterpreter interpretValueNode: self continue: aBlock
  490. ! !
  491. !VariableNode methodsFor: '*Compiler-Interpreter'!
  492. interpreter: anInterpreter continue: aBlock
  493. ^ anInterpreter interpretVariableNode: self continue: aBlock
  494. ! !
  495. !ClassReferenceNode methodsFor: '*Compiler-Interpreter'!
  496. interpreter: anInterpreter continue: aBlock
  497. ^ anInterpreter interpretClassReferenceNode: self continue: aBlock
  498. ! !