1
0
Prechádzať zdrojové kódy

AST Interpreter: Double dispatch read/write vars.

Herby Vojčík 5 rokov pred
rodič
commit
684fb9b77d
2 zmenil súbory, kde vykonal 343 pridanie a 168 odobranie
  1. 281 149
      lang/src/Compiler-Interpreter.js
  2. 62 19
      lang/src/Compiler-Interpreter.st

+ 281 - 149
lang/src/Compiler-Interpreter.js

@@ -2205,31 +2205,17 @@ selector: "assign:to:",
 protocol: "private",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode", "anObject"],
-source: "assign: aNode to: anObject\x0a\x09aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode identifier put: anObject ]\x0a\x09\x09ifFalse: [ self context localAt: aNode identifier put: anObject ]",
+source: "assign: aNode to: anObject\x0a\x09aNode binding inContext: self context put: anObject",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifTrue:ifFalse:", "isInstanceVar", "binding", "instVarAt:put:", "receiver", "context", "identifier", "localAt:put:"]
+messageSends: ["inContext:put:", "binding", "context"]
 }, function ($methodClass){ return function (aNode,anObject){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv($recv(aNode)._binding())._isInstanceVar();
-if($core.assert($1)){
-$recv($recv([$self._context()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["context"]=1
-//>>excludeEnd("ctx");
-][0])._receiver())._instVarAt_put_([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["identifier"]=1
-//>>excludeEnd("ctx");
-][0],anObject);
-} else {
-$recv($self._context())._localAt_put_($recv(aNode)._identifier(),anObject);
-}
+$recv($recv(aNode)._binding())._inContext_put_($self._context(),anObject);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"assign:to:",{aNode:aNode,anObject:anObject})});
@@ -3408,145 +3394,17 @@ selector: "visitVariableNode:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09aNode binding isExternallyKnownVar ifTrue: [\x0a\x09\x09^ self push: (Platform globals at: aNode identifier ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode identifier ]\x0a\x09\x09ifFalse: [ self context \x0a\x09\x09\x09localAt: (aNode binding isSuper ifTrue: [ 'self' ] ifFalse: [ aNode identifier ])\x0a\x09\x09\x09ifAbsent: [\x0a\x09\x09\x09\x09aNode identifier = 'nil' ifTrue: [ nil ] ifFalse: [\x0a\x09\x09\x09\x09aNode identifier = 'true' ifTrue: [ true ] ifFalse: [\x0a\x09\x09\x09\x09aNode identifier = 'false' ifTrue: [ false ] ifFalse: [\x0a\x09\x09\x09\x09aNode identifier isCapitalized\x0a\x09\x09\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09\x09\x09Smalltalk globals \x0a\x09\x09\x09\x09\x09\x09\x09at: aNode identifier \x0a\x09\x09\x09\x09\x09\x09\x09ifAbsent: [ Platform globals at: aNode identifier ] ] ] ] ] ] ])",
-referencedClasses: ["Platform", "Smalltalk"],
+source: "visitVariableNode: aNode\x0a\x09self push: (aNode binding inContext: self context)",
+referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifTrue:", "isExternallyKnownVar", "binding", "push:", "at:ifAbsent:", "globals", "identifier", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:ifAbsent:", "isSuper", "=", "isCapitalized", "at:"]
+messageSends: ["push:", "inContext:", "binding", "context"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$4,$6,$5,$7,$8,$9,$10,$2;
-$1=$recv([$recv(aNode)._binding()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["binding"]=1
-//>>excludeEnd("ctx");
-][0])._isExternallyKnownVar();
-if($core.assert($1)){
-return [$self._push_([$recv([$recv($globals.Platform)._globals()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["globals"]=1
-//>>excludeEnd("ctx");
-][0])._at_ifAbsent_([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["identifier"]=1
-//>>excludeEnd("ctx");
-][0],(function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $self._error_("Unknown variable");
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}))
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["at:ifAbsent:"]=1
-//>>excludeEnd("ctx");
-][0])
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["push:"]=1
-//>>excludeEnd("ctx");
-][0];
-}
-$3=$recv([$recv(aNode)._binding()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["binding"]=2
-//>>excludeEnd("ctx");
-][0])._isInstanceVar();
-if($core.assert($3)){
-$2=$recv($recv([$self._context()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["context"]=1
-//>>excludeEnd("ctx");
-][0])._receiver())._instVarAt_([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["identifier"]=2
-//>>excludeEnd("ctx");
-][0]);
-} else {
-$4=$self._context();
-$6=$recv($recv(aNode)._binding())._isSuper();
-if($core.assert($6)){
-$5="self";
-} else {
-$5=[$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["identifier"]=3
-//>>excludeEnd("ctx");
-][0];
-}
-$2=$recv($4)._localAt_ifAbsent_($5,(function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$7=[$recv([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["identifier"]=4
-//>>excludeEnd("ctx");
-][0]).__eq("nil")
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["="]=1
-//>>excludeEnd("ctx");
-][0];
-if($core.assert($7)){
-return nil;
-} else {
-$8=[$recv([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["identifier"]=5
-//>>excludeEnd("ctx");
-][0]).__eq("true")
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["="]=2
-//>>excludeEnd("ctx");
-][0];
-if($core.assert($8)){
-return true;
-} else {
-$9=$recv([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["identifier"]=6
-//>>excludeEnd("ctx");
-][0]).__eq("false");
-if($core.assert($9)){
-return false;
-} else {
-$10=$recv([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["identifier"]=7
-//>>excludeEnd("ctx");
-][0])._isCapitalized();
-if($core.assert($10)){
-return $recv([$recv($globals.Smalltalk)._globals()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["globals"]=2
-//>>excludeEnd("ctx");
-][0])._at_ifAbsent_([$recv(aNode)._identifier()
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx2.sendIdx["identifier"]=8
-//>>excludeEnd("ctx");
-][0],(function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx3) {
-//>>excludeEnd("ctx");
-return $recv($recv($globals.Platform)._globals())._at_($recv(aNode)._identifier());
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,15)});
-//>>excludeEnd("ctx");
-}));
-}
-}
-}
-}
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,7)});
-//>>excludeEnd("ctx");
-}));
-}
-$self._push_($2);
+$self._push_($recv($recv(aNode)._binding())._inContext_($self._context()));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode})});
@@ -3832,6 +3690,30 @@ return nil;
 }; }),
 $globals.ASTNode);
 
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09self error: 'Alias variable is internal, it should never appear in normal variable context.'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["error:"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._error_("Alias variable is internal, it should never appear in normal variable context.");
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AliasVar);
+
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",
@@ -3886,6 +3768,45 @@ return nil;
 }; }),
 $globals.BlockNode);
 
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ Smalltalk globals \x0a\x09\x09at: self name \x0a\x09\x09ifAbsent: [ Platform globals at: self name ]",
+referencedClasses: ["Smalltalk", "Platform"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:ifAbsent:", "globals", "name", "at:"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv([$recv($globals.Smalltalk)._globals()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["globals"]=1
+//>>excludeEnd("ctx");
+][0])._at_ifAbsent_([$self._name()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["name"]=1
+//>>excludeEnd("ctx");
+][0],(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv($recv($globals.Platform)._globals())._at_($self._name());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ClassRefVar);
+
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",
@@ -3973,6 +3894,84 @@ catch(e) {if(e===$early)return e[0]; throw e}
 }; }),
 $globals.Evaluator);
 
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ Platform globals at: self name ifAbsent: [ self error: 'Unknown variable' ]",
+referencedClasses: ["Platform"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:ifAbsent:", "globals", "name", "error:"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($recv($globals.Platform)._globals())._at_ifAbsent_($self._name(),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $self._error_("Unknown variable");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ExternallyKnownVar);
+
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ aContext receiver instVarAt: self name",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["instVarAt:", "receiver", "name"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($recv(aContext)._receiver())._instVarAt_($self._name());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.InstanceVar);
+
+$core.addMethod(
+$core.method({
+selector: "inContext:put:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext", "anObject"],
+source: "inContext: aContext put: anObject\x0a\x09aContext receiver instVarAt: self name put: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["instVarAt:put:", "receiver", "name"]
+}, function ($methodClass){ return function (aContext,anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($recv(aContext)._receiver())._instVarAt_put_($self._name(),anObject);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:put:",{aContext:aContext,anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.InstanceVar);
+
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",
@@ -3991,6 +3990,92 @@ return true;
 }; }),
 $globals.JSStatementNode);
 
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ #{'nil'->nil. 'true'->true. 'false'->false}\x0a\x09\x09at: self name\x0a\x09\x09ifAbsent: [ super inContext: aContext ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["at:ifAbsent:", "name", "inContext:"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($globals.HashedCollection._newFromPairs_(["nil",nil,"true",true,"false",false]))._at_ifAbsent_($self._name(),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return [(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.supercall = true,
+//>>excludeEnd("ctx");
+($methodClass.superclass||$boot.nilAsClass).fn.prototype._inContext_.call($self,aContext))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.supercall = false
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.PseudoVar);
+
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ aContext localAt: self name",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["localAt:", "name"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv(aContext)._localAt_($self._name());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ScopeVar);
+
+$core.addMethod(
+$core.method({
+selector: "inContext:put:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext", "anObject"],
+source: "inContext: aContext put: anObject\x0a\x09self error: 'Non-assignable variables should not be changed.'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["error:"]
+}, function ($methodClass){ return function (aContext,anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self._error_("Non-assignable variables should not be changed.");
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:put:",{aContext:aContext,anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ScopeVar);
+
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",
@@ -4009,4 +4094,51 @@ return true;
 }; }),
 $globals.SendNode);
 
+$core.addMethod(
+$core.method({
+selector: "inContext:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext"],
+source: "inContext: aContext\x0a\x09^ aContext localAt: 'self'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["localAt:"]
+}, function ($methodClass){ return function (aContext){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv(aContext)._localAt_("self");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:",{aContext:aContext})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.SuperVar);
+
+$core.addMethod(
+$core.method({
+selector: "inContext:put:",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aContext", "anObject"],
+source: "inContext: aContext put: anObject\x0a\x09aContext localAt: self name put: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["localAt:put:", "name"]
+}, function ($methodClass){ return function (aContext,anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(aContext)._localAt_put_($self._name(),anObject);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"inContext:put:",{aContext:aContext,anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.TempVar);
+
 });

+ 62 - 19
lang/src/Compiler-Interpreter.st

@@ -701,9 +701,7 @@ stepOver
 !ASTInterpreter methodsFor: 'private'!
 
 assign: aNode to: anObject
-	aNode binding isInstanceVar
-		ifTrue: [ self context receiver instVarAt: aNode identifier put: anObject ]
-		ifFalse: [ self context localAt: aNode identifier put: anObject ]
+	aNode binding inContext: self context put: anObject
 !
 
 eval: aString
@@ -885,22 +883,7 @@ visitValueNode: aNode
 !
 
 visitVariableNode: aNode
-	aNode binding isExternallyKnownVar ifTrue: [
-		^ self push: (Platform globals at: aNode identifier ifAbsent: [ self error: 'Unknown variable' ]) ].
-		
-	self push: (aNode binding isInstanceVar
-		ifTrue: [ self context receiver instVarAt: aNode identifier ]
-		ifFalse: [ self context 
-			localAt: (aNode binding isSuper ifTrue: [ 'self' ] ifFalse: [ aNode identifier ])
-			ifAbsent: [
-				aNode identifier = 'nil' ifTrue: [ nil ] ifFalse: [
-				aNode identifier = 'true' ifTrue: [ true ] ifFalse: [
-				aNode identifier = 'false' ifTrue: [ false ] ifFalse: [
-				aNode identifier isCapitalized
-					ifTrue: [
-						Smalltalk globals 
-							at: aNode identifier 
-							ifAbsent: [ Platform globals at: aNode identifier ] ] ] ] ] ] ])
+	self push: (aNode binding inContext: self context)
 ! !
 
 Error subclass: #ASTInterpreterError
@@ -985,6 +968,12 @@ nextSiblingNode: aNode
 		ifAbsent: [ nil ]
 ! !
 
+!AliasVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	self error: 'Alias variable is internal, it should never appear in normal variable context.'
+! !
+
 !AssignmentNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
@@ -1005,6 +994,14 @@ nextSiblingNode: aNode
 	^ nil
 ! !
 
+!ClassRefVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ Smalltalk globals 
+		at: self name 
+		ifAbsent: [ Platform globals at: self name ]
+! !
+
 !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
@@ -1038,15 +1035,61 @@ evaluate: aString context: aContext
 	^ aContext evaluateNode: ast
 ! !
 
+!ExternallyKnownVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ Platform globals at: self name ifAbsent: [ self error: 'Unknown variable' ]
+! !
+
+!InstanceVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext receiver instVarAt: self name
+!
+
+inContext: aContext put: anObject
+	aContext receiver instVarAt: self name put: anObject
+! !
+
 !JSStatementNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
 	^ true
 ! !
 
+!PseudoVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ #{'nil'->nil. 'true'->true. 'false'->false}
+		at: self name
+		ifAbsent: [ super inContext: aContext ]
+! !
+
+!ScopeVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext localAt: self name
+!
+
+inContext: aContext put: anObject
+	self error: 'Non-assignable variables should not be changed.'
+! !
+
 !SendNode methodsFor: '*Compiler-Interpreter'!
 
 isSteppingNode
 	^ true
 ! !
 
+!SuperVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext
+	^ aContext localAt: 'self'
+! !
+
+!TempVar methodsFor: '*Compiler-Interpreter'!
+
+inContext: aContext put: anObject
+	aContext localAt: self name put: anObject
+! !
+