Browse Source

Remove ClassReferenceNode.

Matthias Springer 10 years ago
parent
commit
17e810c689

+ 91 - 231
bin/amber-cli.js

@@ -1130,7 +1130,6 @@ function RuntimeBrik(brikz, st) {
 				return inContext(worker, setup);
 			} catch(error) {
 				handleError(error);
-			} finally {
 				st.thisContext = null;
 			}
 		}
@@ -20248,24 +20247,6 @@ referencedClasses: []
 }),
 smalltalk.NodeVisitor);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._visitVariableNode_(aNode);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.NodeVisitor)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09^ self visitVariableNode: aNode",
-messageSends: ["visitVariableNode:"],
-referencedClasses: []
-}),
-smalltalk.NodeVisitor);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitDynamicArrayNode:",
@@ -22645,28 +22626,6 @@ referencedClasses: []
 smalltalk.VariableNode);
 
 
-
-smalltalk.addClass('ClassReferenceNode', smalltalk.VariableNode, [], 'Compiler-AST');
-smalltalk.ClassReferenceNode.comment="I represent an class reference node.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(aVisitor)._visitClassReferenceNode_(self);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"accept:",{aVisitor:aVisitor},smalltalk.ClassReferenceNode)})},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09^ aVisitor visitClassReferenceNode: self",
-messageSends: ["visitClassReferenceNode:"],
-referencedClasses: []
-}),
-smalltalk.ClassReferenceNode);
-
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isNode",
@@ -27880,7 +27839,7 @@ smalltalk.InliningCodeGenerator);
 
 });
 
-define("amber_core/Compiler-Semantic", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function(smalltalk,nil,_st){
+define("amber_core/Compiler-Semantic", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Compiler-Core", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st){
 smalltalk.addPackage('Compiler-Semantic');
 smalltalk.packages["Compiler-Semantic"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -29530,28 +29489,6 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-function $ClassRefVar(){return smalltalk.ClassRefVar||(typeof ClassRefVar=="undefined"?nil:ClassRefVar)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-_st(self._classReferences())._add_(_st(aNode)._value());
-$1=_st($ClassRefVar())._new();
-_st($1)._name_(_st(aNode)._value());
-$2=_st($1)._yourself();
-_st(aNode)._binding_($2);
-return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self classReferences add: aNode value.\x0a\x09aNode binding: (ClassRefVar new name: aNode value; yourself)",
-messageSends: ["add:", "classReferences", "value", "binding:", "name:", "new", "yourself"],
-referencedClasses: ["ClassRefVar"]
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitMethodNode:",
@@ -29678,26 +29615,39 @@ selector: "visitVariableNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
+var binding;
+function $ClassRefVar(){return smalltalk.ClassRefVar||(typeof ClassRefVar=="undefined"?nil:ClassRefVar)}
 function $UnknownVar(){return smalltalk.UnknownVar||(typeof UnknownVar=="undefined"?nil:UnknownVar)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$5,$2;
-$1=aNode;
-$3=_st(self["@currentScope"])._lookupVariable_(aNode);
-if(($receiver = $3) == nil || $receiver == null){
+var $1,$2,$3,$4,$5,$6;
+binding=_st(self["@currentScope"])._lookupVariable_(aNode);
+$1=binding;
+if(($receiver = $1) == nil || $receiver == null){
+$2=_st(_st(aNode)._value())._beginsWithCapital();
+if(smalltalk.assert($2)){
+$3=_st($ClassRefVar())._new();
+_st($3)._name_(_st(aNode)._value());
+$4=_st($3)._yourself();
+binding=$4;
+binding;
+_st(self._classReferences())._add_(_st(aNode)._value());
+} else {
 self._errorUnknownVariable_(aNode);
-$4=_st($UnknownVar())._new();
-_st($4)._name_(_st(aNode)._value());
-$5=_st($4)._yourself();
-$2=$5;
+$5=_st($UnknownVar())._new();
+_st($5)._name_(_st(aNode)._value());
+$6=_st($5)._yourself();
+binding=$6;
+binding;
+};
 } else {
-$2=$3;
+$1;
 };
-_st($1)._binding_($2);
-return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
+_st(aNode)._binding_(binding);
+return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode,binding:binding},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error\x22\x0a\x0a\x09aNode binding: ((currentScope lookupVariable: aNode) ifNil: [\x0a\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09UnknownVar new name: aNode value; yourself ])",
-messageSends: ["binding:", "ifNil:", "lookupVariable:", "errorUnknownVariable:", "name:", "new", "value", "yourself"],
-referencedClasses: ["UnknownVar"]
+source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error.\x22\x0a\x0a\x09| binding |\x0a\x09binding := currentScope lookupVariable: aNode.\x0a\x09\x0a\x09binding ifNil: [\x0a\x09\x09aNode value beginsWithCapital\x0a\x09\x09\x09ifTrue: [ \x22Capital letter variables might be globals.\x22\x0a\x09\x09\x09\x09binding := ClassRefVar new name: aNode value; yourself.\x0a\x09\x09\x09\x09self classReferences add: aNode value]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09\x09\x09binding := UnknownVar new name: aNode value; yourself ] ].\x0a\x09\x09\x0a\x09aNode binding: binding.",
+messageSends: ["lookupVariable:", "ifNil:", "ifTrue:ifFalse:", "beginsWithCapital", "value", "name:", "new", "yourself", "add:", "classReferences", "errorUnknownVariable:", "binding:"],
+referencedClasses: ["ClassRefVar", "UnknownVar"]
 }),
 smalltalk.SemanticAnalyzer);
 
@@ -29723,6 +29673,24 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "beginsWithCapital",
+category: '*Compiler-Semantic',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self._first())._asUppercase()).__eq_eq(self._first());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"beginsWithCapital",{},smalltalk.String)})},
+args: [],
+source: "beginsWithCapital\x0a\x09^ self first asUppercase == self first",
+messageSends: ["==", "asUppercase", "first"],
+referencedClasses: []
+}),
+smalltalk.String);
+
 });
 
 define("amber_core/Compiler-Interpreter", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Methods", "amber_core/Kernel-Objects", "amber_core/Compiler-Core", "amber_core/Kernel-Exceptions", "amber_core/Compiler-AST"], function(smalltalk,nil,_st){
@@ -30264,6 +30232,34 @@ referencedClasses: []
 }),
 smalltalk.AIContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "localAt:ifAbsent:",
+category: 'accessing',
+fn: function (aString,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$1=_st(self._locals())._at_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+$2=self._outerContext();
+if(($receiver = $2) == nil || $receiver == null){
+return _st(aBlock)._value();
+} else {
+var context;
+context=$receiver;
+return _st(context)._localAt_ifAbsent_(aString,aBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"localAt:ifAbsent:",{aString:aString,aBlock:aBlock},smalltalk.AIContext)})},
+args: ["aString", "aBlock"],
+source: "localAt: aString ifAbsent: aBlock\x0a\x09\x22Lookup the local value up to the method context\x22\x0a\x0a\x09^ self locals at: aString ifAbsent: [ \x0a\x09\x09self outerContext \x0a\x09\x09\x09ifNotNil: [ :context | context localAt: aString ifAbsent: aBlock ]\x0a\x09\x09\x09ifNil: [aBlock value] ]",
+messageSends: ["at:ifAbsent:", "locals", "ifNotNil:ifNil:", "outerContext", "localAt:ifAbsent:", "value"],
+referencedClasses: []
+}),
+smalltalk.AIContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "localAt:put:",
@@ -31494,27 +31490,6 @@ referencedClasses: ["AIBlockClosure"]
 }),
 smalltalk.ASTInterpreter);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
-function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
-return smalltalk.withContext(function($ctx1) { 
-self._push_(_st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
-return smalltalk.withContext(function($ctx2) {
-return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})));
-return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.ASTInterpreter)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self push: (Smalltalk current \x0a\x09\x09at: aNode value \x0a\x09\x09ifAbsent: [ PlatformInterface globals at: aNode value ])",
-messageSends: ["push:", "at:ifAbsent:", "current", "value", "at:", "globals"],
-referencedClasses: ["Smalltalk", "PlatformInterface"]
-}),
-smalltalk.ASTInterpreter);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitDynamicArrayNode:",
@@ -31672,8 +31647,9 @@ category: 'visiting',
 fn: function (aNode){
 var self=this;
 function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
+function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$5,$4;
+var $1,$2,$3,$5,$6,$4;
 $1=_st(_st(aNode)._binding())._isUnknownVar();
 if(smalltalk.assert($1)){
 $2=self._push_(_st(_st($PlatformInterface())._globals())._at_ifAbsent_(_st(aNode)._value(),(function(){
@@ -31687,14 +31663,23 @@ $5=_st(_st(aNode)._binding())._isInstanceVar();
 if(smalltalk.assert($5)){
 $4=_st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
 } else {
-$4=_st(self._context())._localAt_(_st(aNode)._value());
+$4=_st(self._context())._localAt_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx2) {
+$6=_st(_st(aNode)._value())._beginsWithCapital();
+if(smalltalk.assert($6)){
+return _st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,7)})}));
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 };
 _st($3)._push_($4);
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.ASTInterpreter)})},
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value ])",
-messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"],
-referencedClasses: ["PlatformInterface"]
+source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context \x0a\x09\x09\x09localAt: aNode value\x0a\x09\x09\x09ifAbsent: [\x0a\x09\x09\x09\x09aNode value beginsWithCapital\x0a\x09\x09\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09\x09\x09Smalltalk current \x0a\x09\x09\x09\x09\x09\x09\x09at: aNode value \x0a\x09\x09\x09\x09\x09\x09\x09ifAbsent: [ PlatformInterface globals at: aNode value ]]]])",
+messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:ifAbsent:", "beginsWithCapital", "current", "at:"],
+referencedClasses: ["PlatformInterface", "Smalltalk"]
 }),
 smalltalk.ASTInterpreter);
 
@@ -32109,7 +32094,6 @@ smalltalk.parser = (function(){
         "comments": parse_comments,
         "ws": parse_ws,
         "identifier": parse_identifier,
-        "varIdentifier": parse_varIdentifier,
         "keyword": parse_keyword,
         "selector": parse_selector,
         "className": parse_className,
@@ -32130,8 +32114,6 @@ smalltalk.parser = (function(){
         "runtimeLiteral": parse_runtimeLiteral,
         "literal": parse_literal,
         "variable": parse_variable,
-        "classReference": parse_classReference,
-        "reference": parse_reference,
         "keywordPair": parse_keywordPair,
         "binarySelector": parse_binarySelector,
         "keywordPattern": parse_keywordPattern,
@@ -32532,75 +32514,6 @@ smalltalk.parser = (function(){
         return result0;
       }
       
-      function parse_varIdentifier() {
-        var cacheKey = "varIdentifier@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0, result1, result2;
-        var pos0, pos1;
-        
-        pos0 = clone(pos);
-        pos1 = clone(pos);
-        if (/^[a-z]/.test(input.charAt(pos.offset))) {
-          result0 = input.charAt(pos.offset);
-          advance(pos, 1);
-        } else {
-          result0 = null;
-          if (reportFailures === 0) {
-            matchFailed("[a-z]");
-          }
-        }
-        if (result0 !== null) {
-          result1 = [];
-          if (/^[a-zA-Z0-9]/.test(input.charAt(pos.offset))) {
-            result2 = input.charAt(pos.offset);
-            advance(pos, 1);
-          } else {
-            result2 = null;
-            if (reportFailures === 0) {
-              matchFailed("[a-zA-Z0-9]");
-            }
-          }
-          while (result2 !== null) {
-            result1.push(result2);
-            if (/^[a-zA-Z0-9]/.test(input.charAt(pos.offset))) {
-              result2 = input.charAt(pos.offset);
-              advance(pos, 1);
-            } else {
-              result2 = null;
-              if (reportFailures === 0) {
-                matchFailed("[a-zA-Z0-9]");
-              }
-            }
-          }
-          if (result1 !== null) {
-            result0 = [result0, result1];
-          } else {
-            result0 = null;
-            pos = clone(pos1);
-          }
-        } else {
-          result0 = null;
-          pos = clone(pos1);
-        }
-        if (result0 !== null) {
-          result0 = (function(offset, line, column, first, others) {return first + others.join("");})(pos0.offset, pos0.line, pos0.column, result0[0], result0[1]);
-        }
-        if (result0 === null) {
-          pos = clone(pos0);
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
       function parse_keyword() {
         var cacheKey = "keyword@" + pos.offset;
         var cachedResult = cache[cacheKey];
@@ -33882,7 +33795,7 @@ smalltalk.parser = (function(){
         var pos0;
         
         pos0 = clone(pos);
-        result0 = parse_varIdentifier();
+        result0 = parse_identifier();
         if (result0 !== null) {
           result0 = (function(offset, line, column, identifier) {
                              return smalltalk.VariableNode._new()
@@ -33901,59 +33814,6 @@ smalltalk.parser = (function(){
         return result0;
       }
       
-      function parse_classReference() {
-        var cacheKey = "classReference@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0;
-        var pos0;
-        
-        pos0 = clone(pos);
-        result0 = parse_className();
-        if (result0 !== null) {
-          result0 = (function(offset, line, column, className) {
-                             return smalltalk.ClassReferenceNode._new()
-                                    ._position_((line).__at(column))
-                                    ._value_(className);
-                         })(pos0.offset, pos0.line, pos0.column, result0);
-        }
-        if (result0 === null) {
-          pos = clone(pos0);
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
-      function parse_reference() {
-        var cacheKey = "reference@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0;
-        
-        result0 = parse_variable();
-        if (result0 === null) {
-          result0 = parse_classReference();
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
       function parse_keywordPair() {
         var cacheKey = "keywordPair@" + pos.offset;
         var cachedResult = cache[cacheKey];
@@ -35277,7 +35137,7 @@ smalltalk.parser = (function(){
         
         result0 = parse_literal();
         if (result0 === null) {
-          result0 = parse_reference();
+          result0 = parse_variable();
           if (result0 === null) {
             result0 = parse_subexpression();
           }

+ 0 - 22
js/Compiler-AST.js

@@ -2194,28 +2194,6 @@ referencedClasses: []
 smalltalk.VariableNode);
 
 
-
-smalltalk.addClass('ClassReferenceNode', smalltalk.VariableNode, [], 'Compiler-AST');
-smalltalk.ClassReferenceNode.comment="I represent an class reference node.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(aVisitor)._visitClassReferenceNode_(self);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"accept:",{aVisitor:aVisitor},smalltalk.ClassReferenceNode)})},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09^ aVisitor visitClassReferenceNode: self",
-messageSends: ["visitClassReferenceNode:"],
-referencedClasses: []
-}),
-smalltalk.ClassReferenceNode);
-
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isNode",

+ 0 - 18
js/Compiler-Core.js

@@ -823,24 +823,6 @@ referencedClasses: []
 }),
 smalltalk.NodeVisitor);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._visitVariableNode_(aNode);
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.NodeVisitor)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09^ self visitVariableNode: aNode",
-messageSends: ["visitVariableNode:"],
-referencedClasses: []
-}),
-smalltalk.NodeVisitor);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitDynamicArrayNode:",

+ 43 - 26
js/Compiler-Interpreter.js

@@ -537,6 +537,34 @@ referencedClasses: []
 }),
 smalltalk.AIContext);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "localAt:ifAbsent:",
+category: 'accessing',
+fn: function (aString,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$1=_st(self._locals())._at_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+$2=self._outerContext();
+if(($receiver = $2) == nil || $receiver == null){
+return _st(aBlock)._value();
+} else {
+var context;
+context=$receiver;
+return _st(context)._localAt_ifAbsent_(aString,aBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"localAt:ifAbsent:",{aString:aString,aBlock:aBlock},smalltalk.AIContext)})},
+args: ["aString", "aBlock"],
+source: "localAt: aString ifAbsent: aBlock\x0a\x09\x22Lookup the local value up to the method context\x22\x0a\x0a\x09^ self locals at: aString ifAbsent: [ \x0a\x09\x09self outerContext \x0a\x09\x09\x09ifNotNil: [ :context | context localAt: aString ifAbsent: aBlock ]\x0a\x09\x09\x09ifNil: [aBlock value] ]",
+messageSends: ["at:ifAbsent:", "locals", "ifNotNil:ifNil:", "outerContext", "localAt:ifAbsent:", "value"],
+referencedClasses: []
+}),
+smalltalk.AIContext);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "localAt:put:",
@@ -1767,27 +1795,6 @@ referencedClasses: ["AIBlockClosure"]
 }),
 smalltalk.ASTInterpreter);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
-function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
-return smalltalk.withContext(function($ctx1) { 
-self._push_(_st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
-return smalltalk.withContext(function($ctx2) {
-return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})));
-return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.ASTInterpreter)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self push: (Smalltalk current \x0a\x09\x09at: aNode value \x0a\x09\x09ifAbsent: [ PlatformInterface globals at: aNode value ])",
-messageSends: ["push:", "at:ifAbsent:", "current", "value", "at:", "globals"],
-referencedClasses: ["Smalltalk", "PlatformInterface"]
-}),
-smalltalk.ASTInterpreter);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitDynamicArrayNode:",
@@ -1945,8 +1952,9 @@ category: 'visiting',
 fn: function (aNode){
 var self=this;
 function $PlatformInterface(){return smalltalk.PlatformInterface||(typeof PlatformInterface=="undefined"?nil:PlatformInterface)}
+function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$5,$4;
+var $1,$2,$3,$5,$6,$4;
 $1=_st(_st(aNode)._binding())._isUnknownVar();
 if(smalltalk.assert($1)){
 $2=self._push_(_st(_st($PlatformInterface())._globals())._at_ifAbsent_(_st(aNode)._value(),(function(){
@@ -1960,14 +1968,23 @@ $5=_st(_st(aNode)._binding())._isInstanceVar();
 if(smalltalk.assert($5)){
 $4=_st(_st(self._context())._receiver())._instVarAt_(_st(aNode)._value());
 } else {
-$4=_st(self._context())._localAt_(_st(aNode)._value());
+$4=_st(self._context())._localAt_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx2) {
+$6=_st(_st(aNode)._value())._beginsWithCapital();
+if(smalltalk.assert($6)){
+return _st(_st($Smalltalk())._current())._at_ifAbsent_(_st(aNode)._value(),(function(){
+return smalltalk.withContext(function($ctx3) {
+return _st(_st($PlatformInterface())._globals())._at_(_st(aNode)._value());
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,7)})}));
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
 };
 _st($3)._push_($4);
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.ASTInterpreter)})},
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value ])",
-messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:"],
-referencedClasses: ["PlatformInterface"]
+source: "visitVariableNode: aNode\x0a\x09aNode binding isUnknownVar ifTrue: [\x0a\x09\x09^ self push: (PlatformInterface globals at: aNode value ifAbsent: [ self error: 'Unknown variable' ]) ].\x0a\x09\x09\x0a\x09self push: (aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09ifFalse: [ self context \x0a\x09\x09\x09localAt: aNode value\x0a\x09\x09\x09ifAbsent: [\x0a\x09\x09\x09\x09aNode value beginsWithCapital\x0a\x09\x09\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09\x09\x09Smalltalk current \x0a\x09\x09\x09\x09\x09\x09\x09at: aNode value \x0a\x09\x09\x09\x09\x09\x09\x09ifAbsent: [ PlatformInterface globals at: aNode value ]]]])",
+messageSends: ["ifTrue:", "isUnknownVar", "binding", "push:", "at:ifAbsent:", "globals", "value", "error:", "ifTrue:ifFalse:", "isInstanceVar", "instVarAt:", "receiver", "context", "localAt:ifAbsent:", "beginsWithCapital", "current", "at:"],
+referencedClasses: ["PlatformInterface", "Smalltalk"]
 }),
 smalltalk.ASTInterpreter);
 

+ 46 - 37
js/Compiler-Semantic.js

@@ -1,4 +1,4 @@
-define("amber_core/Compiler-Semantic", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function(smalltalk,nil,_st){
+define("amber_core/Compiler-Semantic", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Compiler-Core", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st){
 smalltalk.addPackage('Compiler-Semantic');
 smalltalk.packages["Compiler-Semantic"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -1648,28 +1648,6 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "visitClassReferenceNode:",
-category: 'visiting',
-fn: function (aNode){
-var self=this;
-function $ClassRefVar(){return smalltalk.ClassRefVar||(typeof ClassRefVar=="undefined"?nil:ClassRefVar)}
-return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-_st(self._classReferences())._add_(_st(aNode)._value());
-$1=_st($ClassRefVar())._new();
-_st($1)._name_(_st(aNode)._value());
-$2=_st($1)._yourself();
-_st(aNode)._binding_($2);
-return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-args: ["aNode"],
-source: "visitClassReferenceNode: aNode\x0a\x09self classReferences add: aNode value.\x0a\x09aNode binding: (ClassRefVar new name: aNode value; yourself)",
-messageSends: ["add:", "classReferences", "value", "binding:", "name:", "new", "yourself"],
-referencedClasses: ["ClassRefVar"]
-}),
-smalltalk.SemanticAnalyzer);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "visitMethodNode:",
@@ -1796,26 +1774,39 @@ selector: "visitVariableNode:",
 category: 'visiting',
 fn: function (aNode){
 var self=this;
+var binding;
+function $ClassRefVar(){return smalltalk.ClassRefVar||(typeof ClassRefVar=="undefined"?nil:ClassRefVar)}
 function $UnknownVar(){return smalltalk.UnknownVar||(typeof UnknownVar=="undefined"?nil:UnknownVar)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$5,$2;
-$1=aNode;
-$3=_st(self["@currentScope"])._lookupVariable_(aNode);
-if(($receiver = $3) == nil || $receiver == null){
+var $1,$2,$3,$4,$5,$6;
+binding=_st(self["@currentScope"])._lookupVariable_(aNode);
+$1=binding;
+if(($receiver = $1) == nil || $receiver == null){
+$2=_st(_st(aNode)._value())._beginsWithCapital();
+if(smalltalk.assert($2)){
+$3=_st($ClassRefVar())._new();
+_st($3)._name_(_st(aNode)._value());
+$4=_st($3)._yourself();
+binding=$4;
+binding;
+_st(self._classReferences())._add_(_st(aNode)._value());
+} else {
 self._errorUnknownVariable_(aNode);
-$4=_st($UnknownVar())._new();
-_st($4)._name_(_st(aNode)._value());
-$5=_st($4)._yourself();
-$2=$5;
+$5=_st($UnknownVar())._new();
+_st($5)._name_(_st(aNode)._value());
+$6=_st($5)._yourself();
+binding=$6;
+binding;
+};
 } else {
-$2=$3;
+$1;
 };
-_st($1)._binding_($2);
-return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
+_st(aNode)._binding_(binding);
+return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode,binding:binding},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
-source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error\x22\x0a\x0a\x09aNode binding: ((currentScope lookupVariable: aNode) ifNil: [\x0a\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09UnknownVar new name: aNode value; yourself ])",
-messageSends: ["binding:", "ifNil:", "lookupVariable:", "errorUnknownVariable:", "name:", "new", "value", "yourself"],
-referencedClasses: ["UnknownVar"]
+source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error.\x22\x0a\x0a\x09| binding |\x0a\x09binding := currentScope lookupVariable: aNode.\x0a\x09\x0a\x09binding ifNil: [\x0a\x09\x09aNode value beginsWithCapital\x0a\x09\x09\x09ifTrue: [ \x22Capital letter variables might be globals.\x22\x0a\x09\x09\x09\x09binding := ClassRefVar new name: aNode value; yourself.\x0a\x09\x09\x09\x09self classReferences add: aNode value]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09\x09\x09binding := UnknownVar new name: aNode value; yourself ] ].\x0a\x09\x09\x0a\x09aNode binding: binding.",
+messageSends: ["lookupVariable:", "ifNil:", "ifTrue:ifFalse:", "beginsWithCapital", "value", "name:", "new", "yourself", "add:", "classReferences", "errorUnknownVariable:", "binding:"],
+referencedClasses: ["ClassRefVar", "UnknownVar"]
 }),
 smalltalk.SemanticAnalyzer);
 
@@ -1841,4 +1832,22 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer.klass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "beginsWithCapital",
+category: '*Compiler-Semantic',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self._first())._asUppercase()).__eq_eq(self._first());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"beginsWithCapital",{},smalltalk.String)})},
+args: [],
+source: "beginsWithCapital\x0a\x09^ self first asUppercase == self first",
+messageSends: ["==", "asUppercase", "first"],
+referencedClasses: []
+}),
+smalltalk.String);
+
 });

+ 31 - 7
js/Compiler-Tests.js

@@ -701,6 +701,27 @@ referencedClasses: []
 }),
 smalltalk.CodeGeneratorTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testTempVariables",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._should_return_("foo | a | ^ a",nil);
+self._should_return_("foo | AVariable | ^ AVariable",nil);
+self._should_return_("foo | a b c | ^ c",nil);
+self._should_return_("foo | a | [ | d | ^ d ] value",nil);
+self._should_return_("foo | a | a:= 1. ^ a",(1));
+self._should_return_("foo | AVariable | AVariable := 1. ^ AVariable",(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testTempVariables",{},smalltalk.CodeGeneratorTest)})},
+args: [],
+source: "testTempVariables\x0a\x09self should: 'foo | a | ^ a' return: nil.\x0a\x09self should: 'foo | AVariable | ^ AVariable' return: nil.\x0a\x09self should: 'foo | a b c | ^ c' return: nil.\x0a\x09self should: 'foo | a | [ | d | ^ d ] value' return: nil.\x0a\x09\x0a\x09self should: 'foo | a | a:= 1. ^ a' return: 1.\x0a\x09self should: 'foo | AVariable | AVariable := 1. ^ AVariable' return: 1.\x09",
+messageSends: ["should:return:"],
+referencedClasses: []
+}),
+smalltalk.CodeGeneratorTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testThisContext",
@@ -1036,21 +1057,24 @@ category: 'tests',
 fn: function (){
 var self=this;
 var node;
-function $ClassReferenceNode(){return smalltalk.ClassReferenceNode||(typeof ClassReferenceNode=="undefined"?nil:ClassReferenceNode)}
+function $VariableNode(){return smalltalk.VariableNode||(typeof VariableNode=="undefined"?nil:VariableNode)}
 function $SemanticAnalyzer(){return smalltalk.SemanticAnalyzer||(typeof SemanticAnalyzer=="undefined"?nil:SemanticAnalyzer)}
+function $MethodLexicalScope(){return smalltalk.MethodLexicalScope||(typeof MethodLexicalScope=="undefined"?nil:MethodLexicalScope)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
-$1=_st($ClassReferenceNode())._new();
+var $1,$2,$3,$4;
+$1=_st($VariableNode())._new();
 _st($1)._value_("Object");
 $2=_st($1)._yourself();
 node=$2;
-_st(_st($SemanticAnalyzer())._new())._visit_(node);
+$3=_st($SemanticAnalyzer())._new();
+_st($3)._pushScope_(_st($MethodLexicalScope())._new());
+$4=_st($3)._visit_(node);
 self._assert_(_st(_st(node)._binding())._isClassRefVar());
 return self}, function($ctx1) {$ctx1.fill(self,"testClassRefVar",{node:node},smalltalk.ScopeVarTest)})},
 args: [],
-source: "testClassRefVar\x0a\x09| node |\x0a\x09node := ClassReferenceNode new\x0a\x09\x09value: 'Object';\x0a\x09\x09yourself.\x0a\x09SemanticAnalyzer new visit: node.\x0a\x09self assert: node binding isClassRefVar",
-messageSends: ["value:", "new", "yourself", "visit:", "assert:", "isClassRefVar", "binding"],
-referencedClasses: ["ClassReferenceNode", "SemanticAnalyzer"]
+source: "testClassRefVar\x0a\x09| node |\x0a\x09node := VariableNode new\x0a\x09\x09value: 'Object';\x0a\x09\x09yourself.\x0a\x09SemanticAnalyzer new \x0a\x09\x09pushScope: MethodLexicalScope new;\x0a\x09\x09visit: node.\x0a\x09self assert: node binding isClassRefVar",
+messageSends: ["value:", "new", "yourself", "pushScope:", "visit:", "assert:", "isClassRefVar", "binding"],
+referencedClasses: ["VariableNode", "SemanticAnalyzer", "MethodLexicalScope"]
 }),
 smalltalk.ScopeVarTest);
 

+ 0 - 12
st/Compiler-AST.st

@@ -681,18 +681,6 @@ accept: aVisitor
 	^ aVisitor visitVariableNode: self
 ! !
 
-VariableNode subclass: #ClassReferenceNode
-	instanceVariableNames: ''
-	package: 'Compiler-AST'!
-!ClassReferenceNode commentStamp!
-I represent an class reference node.!
-
-!ClassReferenceNode methodsFor: 'visiting'!
-
-accept: aVisitor
-	^ aVisitor visitClassReferenceNode: self
-! !
-
 !Object methodsFor: '*Compiler-AST'!
 
 isNode

+ 0 - 4
st/Compiler-Core.st

@@ -258,10 +258,6 @@ visitCascadeNode: aNode
 	^ self visitNode: aNode
 !
 
-visitClassReferenceNode: aNode
-	^ self visitVariableNode: aNode
-!
-
 visitDynamicArrayNode: aNode
 	^ self visitNode: aNode
 !

+ 17 - 7
st/Compiler-Interpreter.st

@@ -159,6 +159,15 @@ selector
 
 selector: aString
 	selector := aString
+!
+
+localAt: aString ifAbsent: aBlock
+	"Lookup the local value up to the method context"
+
+	^ self locals at: aString ifAbsent: [ 
+		self outerContext 
+			ifNotNil: [ :context | context localAt: aString ifAbsent: aBlock ]
+			ifNil: [aBlock value] ]
 ! !
 
 !AIContext methodsFor: 'factory'!
@@ -613,12 +622,6 @@ visitBlockNode: aNode
 	self push: block
 !
 
-visitClassReferenceNode: aNode
-	self push: (Smalltalk current 
-		at: aNode value 
-		ifAbsent: [ PlatformInterface globals at: aNode value ])
-!
-
 visitDynamicArrayNode: aNode
 	| array |
 	
@@ -688,7 +691,14 @@ visitVariableNode: aNode
 		
 	self push: (aNode binding isInstanceVar
 		ifTrue: [ self context receiver instVarAt: aNode value ]
-		ifFalse: [ self context localAt: aNode value ])
+		ifFalse: [ self context 
+			localAt: aNode value
+			ifAbsent: [
+				aNode value beginsWithCapital
+					ifTrue: [
+						Smalltalk current 
+							at: aNode value 
+							ifAbsent: [ PlatformInterface globals at: aNode value ]]]])
 ! !
 
 Error subclass: #ASTInterpreterError

+ 20 - 9
st/Compiler-Semantic.st

@@ -522,11 +522,6 @@ visitCascadeNode: aNode
 		aNode nodes do: [ :each | each superSend: true ] ]
 !
 
-visitClassReferenceNode: aNode
-	self classReferences add: aNode value.
-	aNode binding: (ClassRefVar new name: aNode value; yourself)
-!
-
 visitMethodNode: aNode
 	self pushScope: self newMethodScope.
 	aNode scope: currentScope.
@@ -586,11 +581,21 @@ visitSequenceNode: aNode
 
 visitVariableNode: aNode
 	"Bind a ScopeVar to aNode by doing a lookup in the current scope.
-	If no ScopeVar is found, bind a UnknowVar and throw an error"
+	If no ScopeVar is found, bind a UnknowVar and throw an error."
 
-	aNode binding: ((currentScope lookupVariable: aNode) ifNil: [
-		self errorUnknownVariable: aNode.
-		UnknownVar new name: aNode value; yourself ])
+	| binding |
+	binding := currentScope lookupVariable: aNode.
+	
+	binding ifNil: [
+		aNode value beginsWithCapital
+			ifTrue: [ "Capital letter variables might be globals."
+				binding := ClassRefVar new name: aNode value; yourself.
+				self classReferences add: aNode value]
+			ifFalse: [
+				self errorUnknownVariable: aNode.
+				binding := UnknownVar new name: aNode value; yourself ] ].
+		
+	aNode binding: binding.
 ! !
 
 !SemanticAnalyzer class methodsFor: 'instance creation'!
@@ -601,3 +606,9 @@ on: aClass
 		yourself
 ! !
 
+!String methodsFor: '*Compiler-Semantic'!
+
+beginsWithCapital
+	^ self first asUppercase == self first
+! !
+

+ 59 - 47
st/Compiler-Tests.st

@@ -121,13 +121,6 @@ tearDown
 
 !CodeGeneratorTest methodsFor: 'testing'!
 
-should: aString return: anObject
-	^ self 
-		should: aString 
-		receiver: receiver 
-		return: anObject
-!
-
 should: aString receiver: anObject return: aResult
 	| method result |
 
@@ -136,6 +129,13 @@ should: aString receiver: anObject return: aResult
 	result := receiver perform: method selector.
 	anObject class removeCompiledMethod: method.
 	self assert: aResult equals: result
+!
+
+should: aString return: anObject
+	^ self 
+		should: aString 
+		receiver: receiver 
+		return: anObject
 ! !
 
 !CodeGeneratorTest methodsFor: 'tests'!
@@ -180,6 +180,12 @@ testDynamicDictionaryElementsOrdered
 ' return: #{'foo'->1. 'bar'->2}.
 !
 
+testGlobalVar
+	self should: 'foo ^ eval class' return: BlockClosure.
+	self should: 'foo ^ Math cos: 0' return: 1.
+	self should: 'foo ^ NonExistingVar' return: nil
+!
+
 testInnerTemporalDependentElementsOrdered
 	self should: 'foo
 	| x |
@@ -203,6 +209,10 @@ testInnerTemporalDependentElementsOrdered
 ' return: #{'foo'->1. 'bar'->2}.
 !
 
+testJSStatement
+	self should: 'foo <return 2+3>' return: 5
+!
+
 testLiterals
 	self should: 'foo ^ 1' return: 1.
 	self should: 'foo ^ ''hello''' return: 'hello'.
@@ -233,6 +243,10 @@ testMessageSends
 	self should: 'foo ^ 1 to: 5 by: 2' return: #(1 3 5)
 !
 
+testMultipleSequences
+	self should: 'foo | a b c | a := 2. b := 3. c := a + b. ^ c * 6' return: 30
+!
+
 testMutableLiterals
 	"Mutable literals must be aliased in cascades.
 	See https://github.com/amber-smalltalk/amber/issues/428"
@@ -250,6 +264,10 @@ testNestedIfTrue
 	self should: 'foo true ifTrue: [ false ifTrue: [ ^ 1 ] ]' return: receiver.
 !
 
+testNestedSends
+	self should: 'foo ^ (Point x: (Point x: 2 y: 3) y: 4) asString' return: (Point x: (2@3) y: 4) asString
+!
+
 testNonLocalReturn
 	self should: 'foo [ ^ 1 ] value' return: 1.
 	self should: 'foo [ ^ 1 + 1 ] value' return: 2.
@@ -276,6 +294,17 @@ testSendReceiverAndArgumentsOrdered
 ' return: {Array. 2}.
 !
 
+testSuperSend
+	self 
+		should: 'foo ^ super isBoolean' 
+		receiver: true
+		return: false
+!
+
+testThisContext
+	self should: 'foo ^ [ thisContext ] value outerContext == thisContext' return: true
+!
+
 testifFalse
 	self should: 'foo true ifFalse: [ ^ 1 ]' return: receiver.
 	self should: 'foo false ifFalse: [ ^ 2 ]' return: 2.
@@ -343,33 +372,14 @@ testifTrueIfFalse
 	self should: 'foo ^ true ifTrue: [ 2 ] ifFalse: [ 1 ]' return: 2.
 !
 
-testGlobalVar
-	self should: 'foo ^ eval class' return: BlockClosure.
-	self should: 'foo ^ Math cos: 0' return: 1.
-	self should: 'foo ^ NonExistingVar' return: nil
-!
-
-testJSStatement
-	self should: 'foo <return 2+3>' return: 5
-!
-
-testMultipleSequences
-	self should: 'foo | a b c | a := 2. b := 3. c := a + b. ^ c * 6' return: 30
-!
-
-testNestedSends
-	self should: 'foo ^ (Point x: (Point x: 2 y: 3) y: 4) asString' return: (Point x: (2@3) y: 4) asString
-!
-
-testSuperSend
-	self 
-		should: 'foo ^ super isBoolean' 
-		receiver: true
-		return: false
-!
-
-testThisContext
-	self should: 'foo ^ [ thisContext ] value outerContext == thisContext' return: true
+testTempVariables
+	self should: 'foo | a | ^ a' return: nil.
+	self should: 'foo | AVariable | ^ AVariable' return: nil.
+	self should: 'foo | a b c | ^ c' return: nil.
+	self should: 'foo | a | [ | d | ^ d ] value' return: nil.
+	
+	self should: 'foo | a | a:= 1. ^ a' return: 1.
+	self should: 'foo | AVariable | AVariable := 1. ^ AVariable' return: 1.
 ! !
 
 CodeGeneratorTest subclass: #InliningCodeGeneratorTest
@@ -388,10 +398,6 @@ CodeGeneratorTest subclass: #InterpreterTest
 
 !InterpreterTest methodsFor: 'parsing'!
 
-parse: aString forClass: aClass
-	^ self analyze: (self parse: aString) forClass: aClass
-!
-
 analyze: aNode forClass: aClass
 	(SemanticAnalyzer on: aClass) visit: aNode.
 	^ aNode
@@ -399,6 +405,10 @@ analyze: aNode forClass: aClass
 
 parse: aString
 	^ Smalltalk current parse: aString
+!
+
+parse: aString forClass: aClass
+	^ self analyze: (self parse: aString) forClass: aClass
 ! !
 
 !InterpreterTest methodsFor: 'private'!
@@ -426,19 +436,19 @@ interpret: aString receiver: anObject withArguments: aDictionary
 
 !InterpreterTest methodsFor: 'testing'!
 
-should: aString return: anObject
-	^ self 
-		should: aString
-		receiver: receiver
-		return: anObject
-!
-
 should: aString receiver: anObject return: aResult
 	receiver := anObject.
 	
 	^ self 
 		assert: (self interpret: aString receiver: receiver withArguments: #{})
 		equals: aResult
+!
+
+should: aString return: anObject
+	^ self 
+		should: aString
+		receiver: receiver
+		return: anObject
 ! !
 
 TestCase subclass: #ScopeVarTest
@@ -449,10 +459,12 @@ TestCase subclass: #ScopeVarTest
 
 testClassRefVar
 	| node |
-	node := ClassReferenceNode new
+	node := VariableNode new
 		value: 'Object';
 		yourself.
-	SemanticAnalyzer new visit: node.
+	SemanticAnalyzer new 
+		pushScope: MethodLexicalScope new;
+		visit: node.
 	self assert: node binding isClassRefVar
 !
 

+ 4 - 4
st/Kernel-Collections.st

@@ -978,6 +978,10 @@ add: anObject
 	<self.push(anObject); return anObject;>
 !
 
+addFirst: anObject
+	<self.unshift(anObject); return anObject;>
+!
+
 remove: anObject ifAbsent: aBlock
 	<
 		for(var i=0;i<self.length;i++) {
@@ -998,10 +1002,6 @@ removeIndex: anInteger
 	<self.splice(anInteger - 1, 1)>
 !
 
-addFirst: anObject
-	<self.unshift(anObject); return anObject;>
-!
-
 removeLast
 	<return self.pop();>
 ! !

+ 2 - 127
support/parser.js

@@ -42,7 +42,6 @@ smalltalk.parser = (function(){
         "comments": parse_comments,
         "ws": parse_ws,
         "identifier": parse_identifier,
-        "varIdentifier": parse_varIdentifier,
         "keyword": parse_keyword,
         "selector": parse_selector,
         "className": parse_className,
@@ -63,8 +62,6 @@ smalltalk.parser = (function(){
         "runtimeLiteral": parse_runtimeLiteral,
         "literal": parse_literal,
         "variable": parse_variable,
-        "classReference": parse_classReference,
-        "reference": parse_reference,
         "keywordPair": parse_keywordPair,
         "binarySelector": parse_binarySelector,
         "keywordPattern": parse_keywordPattern,
@@ -465,75 +462,6 @@ smalltalk.parser = (function(){
         return result0;
       }
       
-      function parse_varIdentifier() {
-        var cacheKey = "varIdentifier@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0, result1, result2;
-        var pos0, pos1;
-        
-        pos0 = clone(pos);
-        pos1 = clone(pos);
-        if (/^[a-z]/.test(input.charAt(pos.offset))) {
-          result0 = input.charAt(pos.offset);
-          advance(pos, 1);
-        } else {
-          result0 = null;
-          if (reportFailures === 0) {
-            matchFailed("[a-z]");
-          }
-        }
-        if (result0 !== null) {
-          result1 = [];
-          if (/^[a-zA-Z0-9]/.test(input.charAt(pos.offset))) {
-            result2 = input.charAt(pos.offset);
-            advance(pos, 1);
-          } else {
-            result2 = null;
-            if (reportFailures === 0) {
-              matchFailed("[a-zA-Z0-9]");
-            }
-          }
-          while (result2 !== null) {
-            result1.push(result2);
-            if (/^[a-zA-Z0-9]/.test(input.charAt(pos.offset))) {
-              result2 = input.charAt(pos.offset);
-              advance(pos, 1);
-            } else {
-              result2 = null;
-              if (reportFailures === 0) {
-                matchFailed("[a-zA-Z0-9]");
-              }
-            }
-          }
-          if (result1 !== null) {
-            result0 = [result0, result1];
-          } else {
-            result0 = null;
-            pos = clone(pos1);
-          }
-        } else {
-          result0 = null;
-          pos = clone(pos1);
-        }
-        if (result0 !== null) {
-          result0 = (function(offset, line, column, first, others) {return first + others.join("");})(pos0.offset, pos0.line, pos0.column, result0[0], result0[1]);
-        }
-        if (result0 === null) {
-          pos = clone(pos0);
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
       function parse_keyword() {
         var cacheKey = "keyword@" + pos.offset;
         var cachedResult = cache[cacheKey];
@@ -1815,7 +1743,7 @@ smalltalk.parser = (function(){
         var pos0;
         
         pos0 = clone(pos);
-        result0 = parse_varIdentifier();
+        result0 = parse_identifier();
         if (result0 !== null) {
           result0 = (function(offset, line, column, identifier) {
                              return smalltalk.VariableNode._new()
@@ -1834,59 +1762,6 @@ smalltalk.parser = (function(){
         return result0;
       }
       
-      function parse_classReference() {
-        var cacheKey = "classReference@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0;
-        var pos0;
-        
-        pos0 = clone(pos);
-        result0 = parse_className();
-        if (result0 !== null) {
-          result0 = (function(offset, line, column, className) {
-                             return smalltalk.ClassReferenceNode._new()
-                                    ._position_((line).__at(column))
-                                    ._value_(className);
-                         })(pos0.offset, pos0.line, pos0.column, result0);
-        }
-        if (result0 === null) {
-          pos = clone(pos0);
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
-      function parse_reference() {
-        var cacheKey = "reference@" + pos.offset;
-        var cachedResult = cache[cacheKey];
-        if (cachedResult) {
-          pos = clone(cachedResult.nextPos);
-          return cachedResult.result;
-        }
-        
-        var result0;
-        
-        result0 = parse_variable();
-        if (result0 === null) {
-          result0 = parse_classReference();
-        }
-        
-        cache[cacheKey] = {
-          nextPos: clone(pos),
-          result:  result0
-        };
-        return result0;
-      }
-      
       function parse_keywordPair() {
         var cacheKey = "keywordPair@" + pos.offset;
         var cachedResult = cache[cacheKey];
@@ -3210,7 +3085,7 @@ smalltalk.parser = (function(){
         
         result0 = parse_literal();
         if (result0 === null) {
-          result0 = parse_reference();
+          result0 = parse_variable();
           if (result0 === null) {
             result0 = parse_subexpression();
           }

+ 2 - 8
support/parser.pegjs

@@ -4,7 +4,6 @@ separator      = [ \t\v\f\u00A0\uFEFF\n\r\u2028\u2029]+
 comments       = (["][^"]*["])+
 ws             = (separator / comments)*
 identifier     = first:[a-zA-Z] others:[a-zA-Z0-9]* {return first + others.join("");}
-varIdentifier  = first:[a-z] others:[a-zA-Z0-9]* {return first + others.join("");}
 keyword        = first:identifier last:[:] {return first + last;}
 selector      = first:[a-zA-Z] others:[a-zA-Z0-9\:]* {return first + others.join("");}
 className      = first:[A-Z] others:[a-zA-Z0-9]* {return first + others.join("");}
@@ -59,18 +58,13 @@ runtimeLiteral        = dynamicDictionary / dynamicArray / block
 literal        = runtimeLiteral / parseTimeLiteral
 
 
-variable       = identifier:varIdentifier {
+variable       = identifier:identifier {
                      return smalltalk.VariableNode._new()
                             ._position_((line).__at(column))
                             ._value_(identifier);
                  }
-classReference = className:className {
-                     return smalltalk.ClassReferenceNode._new()
-                            ._position_((line).__at(column))
-                            ._value_(className);
-                 }
 
-reference      = variable / classReference
+reference      = variable
 
 keywordPair    = key:keyword ws arg:binarySend ws {return {key:key, arg: arg};}