| 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! !
 |