Compiler-Interpreter.st 14 KB

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