| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | 
							- Smalltalk current createPackage: 'Compiler-Interpreter' properties: #{}!
 
- NodeVisitor subclass: #AIContext
 
- 	instanceVariableNames: 'outerContext pc locals receiver selector'
 
- 	package: 'Compiler-Interpreter'!
 
- !AIContext methodsFor: 'accessing'!
 
- initializeFromMethodContext: aMethodContext
 
- 	self pc: aMethodContext pc.
 
-     self receiver: aMethodContext receiver.
 
-     self selector: aMethodContext selector.
 
-     aMethodContext outerContext ifNotNil: [
 
- 		self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
 
-     aMethodContext locals keysAndValuesDo: [ :key :value |
 
-     	self locals at: key put: value ]
 
- !
 
- localAt: aString
 
- 	^ self locals at: aString ifAbsent: [ nil ]
 
- !
 
- localAt: aString put: anObject
 
- 	self locals at: aString put: anObject
 
- !
 
- locals
 
- 	^ locals ifNil: [ locals := Dictionary new ]
 
- !
 
- outerContext
 
- 	^ outerContext
 
- !
 
- outerContext: anAIContext
 
- 	outerContext := anAIContext
 
- !
 
- pc
 
- 	^ pc ifNil: [ pc := 0 ]
 
- !
 
- pc: anInteger
 
- 	pc := anInteger
 
- !
 
- receiver
 
- 	^ receiver
 
- !
 
- receiver: anObject
 
- 	receiver := anObject
 
- !
 
- selector
 
- 	^ selector
 
- !
 
- selector: aString
 
- 	selector := aString
 
- ! !
 
- !AIContext class methodsFor: 'instance creation'!
 
- fromMethodContext: aMethodContext
 
- 	^ self new 
 
-     	initializeFromMethodContext: aMethodContext;
 
-         yourself
 
- ! !
 
- NodeVisitor subclass: #ASTInterpreter
 
- 	instanceVariableNames: 'currentNode context shouldReturn currentValue'
 
- 	package: 'Compiler-Interpreter'!
 
- !ASTInterpreter methodsFor: 'accessing'!
 
- context
 
- 	^ context ifNil: [ context := AIContext new ]
 
- !
 
- context: anAIContext
 
- 	context := anAIContext
 
- !
 
- currentValue
 
- 	^ currentValue
 
- ! !
 
- !ASTInterpreter methodsFor: 'initialization'!
 
- initialize
 
- 	super initialize.
 
-     shouldReturn := false
 
- ! !
 
- !ASTInterpreter methodsFor: 'interpreting'!
 
- assign: aNode to: anObject
 
- 	^ aNode binding isInstanceVar 
 
-     	ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]
 
-       	ifFalse: [ self context localAt: aNode value put: anObject ]
 
- !
 
- continue: anObject
 
- 	currentValue := anObject
 
- !
 
- eval: aString
 
- 	"Evaluate aString as JS source inside an JS function. 
 
-     aString is not sandboxed."
 
-     
 
-     | source function |
 
-     
 
-     source := String streamContents: [ :str |
 
-     	str nextPutAll: '(function('.
 
-         self context locals keys 
 
-         	do: [ :each | str nextPutAll: each ]
 
-           	separatedBy: [ str nextPutAll: ',' ].
 
-         str 
 
-         	nextPutAll: '){ return (function() {';
 
-         	nextPutAll: aString;
 
-             nextPutAll: '})() })' ].
 
-             
 
- 	function := Compiler new eval: source.
 
-     
 
- 	^ function valueWithPossibleArguments: self context locals values
 
- !
 
- interpret: aNode
 
- 	shouldReturn := false.
 
-     self interpret: aNode continue: [ :value |
 
-     	currentValue := value ]
 
- !
 
- interpret: aNode continue: aBlock
 
- 	shouldReturn ifTrue: [ ^ self ].
 
- 	aNode isNode 
 
-     	ifTrue: [ self visit: aNode ]
 
-         ifFalse: [ currentValue := aNode ].
 
- 	aBlock value: self currentValue
 
- !
 
- interpretAll: aCollection continue: aBlock
 
- 	self 
 
-     	interpretAll: aCollection 
 
-         continue: aBlock 
 
-         result: OrderedCollection new
 
- !
 
- interpretAll: nodes continue: aBlock result: aCollection
 
- 	nodes isEmpty 
 
-     	ifTrue: [ aBlock value: aCollection ]
 
-     	ifFalse: [
 
-     		self interpret: nodes first continue: [:value |
 
-     			self 
 
-                 	interpretAll: nodes allButFirst 
 
-                     continue: aBlock
 
-   					result: aCollection, { value } ] ]
 
- !
 
- messageFromSendNode: aSendNode do: aBlock
 
- 	self interpretAll: aSendNode arguments continue: [ :args |
 
-     	aBlock value: (Message new
 
-     		selector: aSendNode selector;
 
-         	arguments: args;
 
-         	yourself) ]
 
- ! !
 
- !ASTInterpreter methodsFor: 'visiting'!
 
- visitAssignmentNode: aNode
 
- 	self interpret: aNode right continue: [ :value |
 
-     	self continue: (self assign: aNode left to: value) ]
 
- !
 
- visitBlockNode: aNode
 
- 	"TODO: Context should be set"
 
-     self continue: [ self interpret: aNode nodes first; currentValue ]
 
- !
 
- visitCascadeNode: aNode
 
- 	"TODO: Handle super sends"
 
- 	
 
-     self interpret: aNode receiver continue: [ :receiver |
 
- 		"Only interpret the receiver once"
 
-         aNode nodes do: [ :each | each receiver: receiver ].
 
-   
 
-     	self 
 
-         	interpretAll: aNode nodes allButLast
 
-     		continue: [
 
-               	self 
 
-                 	interpret: aNode nodes last
 
-                 	continue: [ :val | self continue: val ] ] ]
 
- !
 
- visitClassReferenceNode: aNode
 
- 	self continue: (Smalltalk current at: aNode value)
 
- !
 
- visitDynamicArrayNode: aNode
 
- 	self interpretAll: aNode nodes continue: [ :array |
 
-     	self continue: array ]
 
- !
 
- visitDynamicDictionaryNode: aNode
 
- 	
 
-     self interpretAll: aNode nodes continue: [ :array | | hashedCollection |
 
-     	hashedCollection := HashedCollection new.
 
-         array do: [ :each | hashedCollection add: each ].
 
-         self continue: hashedCollection ]
 
- !
 
- visitJSStatementNode: aNode
 
- 	shouldReturn := true.
 
- 	self continue: (self eval: aNode source)
 
- !
 
- visitReturnNode: aNode
 
-     self interpret: aNode nodes first continue: [ :value |
 
-     	shouldReturn := true.
 
- 		self continue: value ]
 
- !
 
- visitSendNode: aNode
 
- 	"TODO: Handle super sends"
 
-     
 
-     self interpret: aNode receiver continue: [ :receiver |
 
-     	self messageFromSendNode: aNode do: [ :message |
 
-         	self context pc: self context pc + 1.
 
-         	self continue: (message sendTo: receiver) ] ]
 
- !
 
- visitSequenceNode: aNode
 
- 	self interpretAll: aNode nodes continue: [ :array |
 
-     	self continue: array last ]
 
- !
 
- visitValueNode: aNode
 
- 	self continue: aNode value
 
- ! !
 
- ASTInterpreter subclass: #ASTDebugger
 
- 	instanceVariableNames: 'continuation'
 
- 	package: 'Compiler-Interpreter'!
 
- !ASTDebugger methodsFor: 'initialization'!
 
- initialize
 
- 	super initialize.
 
-     continuation := [  ]
 
- ! !
 
- !ASTDebugger methodsFor: 'interpreting'!
 
- interpret: aNode continue: aBlock
 
- 	continuation := [ super interpret: aNode continue: aBlock ]
 
- ! !
 
- !ASTDebugger methodsFor: 'stepping'!
 
- stepOver
 
- 	continuation value
 
- ! !
 
 
  |