Browse Source

Merge branch 'master' into bowerize

Nicolas Petton 10 years ago
parent
commit
cddfc67e94

+ 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();
           }

+ 1 - 26
bin/amberc

@@ -17,10 +17,8 @@ if (1 > parameters.length) {
 // Get Amber root directory from the location of this script so that
 // we can find the st and js directories etc.
 var amber_dir = path.normalize(path.join(path.dirname(process.argv[1]), '..'));
-// Get default location of compiler.jar
-var closure_jar = path.resolve(path.join(process.env['HOME'], 'compiler.jar'));
 
-var compiler = new amberc.Compiler(amber_dir, closure_jar);
+var compiler = new amberc.Compiler(amber_dir);
 
 var configuration = handle_options(parameters, amber_dir);
 
@@ -53,19 +51,6 @@ function handle_options(optionsArray, amber_dir) {
 			case '-n':
 				defaults.amd_namespace = optionsArray.shift();
 				break;
-			case '-o':
-				defaults.closure = true;
-				defaults.closure_parts = true;
-				break;
-			case '-O':
-				defaults.closure = true;
-				defaults.closure_full = true;
-				break;
-			case '-A':
-				defaults.closure = true;
-				defaults.closure_options = defaults.closure_options + ' --compilation_level ADVANCED_OPTIMIZATIONS';
-				defaults.closure_full = true;
-				break;
 			case '-D':
 				defaults.output_dir = optionsArray.shift();
 				break;
@@ -153,16 +138,6 @@ function print_usage() {
 	console.log('     Export packages with <amd_namespace> as the require.js namespace.');
 	console.log('     Default value is "amber_core".');
 	console.log('');
-	console.log('  -o');
-	console.log('     Optimize each .js file using the Google closure compiler.');
-	console.log('     Using Closure compiler found at ~/compiler.jar');
-	console.log('');
-	console.log('  -O');
-	console.log('     Optimize final <Program>.js using the Google closure compiler.');
-	console.log('     Using Closure compiler found at ~/compiler.jar');
-	console.log('');
-	console.log('  -A Same as -O but use --compilation_level ADVANCED_OPTIMIZATIONS');
-	console.log('');
 	console.log('  -D');
 	console.log('     Specifies the output directory for all generated .js files.');
 	console.log('     The hierarchy of the input files is not maintaned.');

+ 4 - 103
bin/amberc.js

@@ -128,9 +128,8 @@ var path = require('path'),
  * amber_dir: points to the location of an amber installation
  * closure_jar: location of compiler.jar (can be left undefined)
  */
-function AmberC(amber_dir, closure_jar) {
+function AmberC(amber_dir) {
 	this.amber_dir = amber_dir;
-	this.closure_jar = closure_jar || '';
 	this.kernel_libraries = ['@boot', '@smalltalk', '@nil', '@_st', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
 							'Kernel-Collections', 'Kernel-Infrastructure', 'Kernel-Exceptions', 'Kernel-Transcript',
 							'Kernel-Announcements'];
@@ -155,9 +154,6 @@ var createDefaults = function(amber_dir, finished_callback){
 		'jsFiles': [],
 		'jsGlobals': [],
 		'amd_namespace': 'amber_core',
-		'closure': false,
-		'closure_full': false,
-		'closure_options': ' --language_in=ECMASCRIPT5 ',
 		'suffix': '',
 		'loadsuffix': '',
 		'suffix_used': '',
@@ -196,10 +192,7 @@ AmberC.prototype.main = function(configuration, finished_callback) {
 	if (this.check_configuration_ok(configuration)) {
 		this.defaults = configuration;
 		this.defaults.smalltalk = {}; // the evaluated compiler will be stored in this variable (see create_compiler)
-		var self = this;
-		this.check_for_closure_compiler(function(){
-			self.collect_files(self.defaults.stFiles, self.defaults.jsFiles)
-		});
+		this.collect_files(this.defaults.stFiles, this.defaults.jsFiles)
 	}
 };
 
@@ -219,44 +212,6 @@ AmberC.prototype.check_configuration_ok = function(configuration) {
 };
 
 
-/**
- * Checks if the java executable exists and afterwards,
- * if compiler.jar exists at the path stored in this.closure_jar.
- * All closure related entries are set to false upon failure.
- *
- * callback gets called in any case.
- */
-AmberC.prototype.check_for_closure_compiler = function(callback) {
-	var defaults = this.defaults;
-	var self = this;
-	if (defaults.closure) {
-		exec('which java', function(error, stdout, stderr) {
-			// stdout contains path to java executable
-			if (null !== error) {
-				console.warn('java is not installed but is needed for running the Closure compiler (-O, -A or -o flags).');
-				defaults.closure = false;
-				defaults.closure_full = false;
-				callback();
-				return;
-			}
-			fs.exists(self.closure_jar, function(exists) {
-				if (!exists) {
-					console.warn('Can not find Closure compiler at: ' + self.closure_jar);
-					defaults.closure = false;
-					defaults.closure_full = false;
-				} else {
-					console.warn('Closure compiler found at: ' + self.closure_jar);
-				}
-				callback();
-				return;
-			});
-		});
-	} else {
-		callback();
-	}
-};
-
-
 /**
  * Check if the file given as parameter exists in the local directory or in $AMBER/js/.
  * '.js' is appended first.
@@ -543,7 +498,7 @@ AmberC.prototype.category_export = function() {
 
 /**
  * Verify if all .st files have been compiled.
- * Followed by compose_js_files() and optimize().
+ * Followed by compose_js_files().
  */
 AmberC.prototype.verify = function() {
 	console.log('Verifying if all .st files were compiled');
@@ -575,7 +530,6 @@ AmberC.prototype.compose_js_files = function() {
 	var self = this;
 	var programFile = defaults.program;
 	if (undefined === programFile) {
-		self.optimize();
 		return;
 	}
 	if (undefined !== defaults.output_dir) {
@@ -604,7 +558,7 @@ AmberC.prototype.compose_js_files = function() {
 	});
 
 	fileStream.on('close', function(){
-		self.optimize();
+		return;
 	});
 
 	var builder = createConcatenator();
@@ -651,59 +605,6 @@ AmberC.prototype.compose_js_files = function() {
 };
 
 
-/**
- * Optimize created JavaScript files with Google Closure compiler depending
- * on the flag: defaults.closure_full.
- */
-AmberC.prototype.optimize = function() {
-	var defaults = this.defaults;
-	var self = this;
-	var optimization_done = new Combo(function() {
-		console.log = console.ambercLog;
-		console.timeEnd('Compile Time');
-		if (undefined !== defaults.finished_callback) {
-			defaults.finished_callback();
-		}
-	});
-
-	if (defaults.closure_full && (undefined !== defaults.program)) {
-		var programFile = defaults.program;
-		if (undefined !== defaults.output_dir) {
-			programFile = path.join(defaults.output_dir, programFile);
-		}
-		console.log('Compiling ' + programFile + '.js file using Google closure compiler.');
-		self.closure_compile(programFile + '.js', programFile + '.min.js', optimization_done.add());
-	}
-
-	always_resolve(optimization_done.add());
-};
-
-
-/**
- * Compile sourceFile into minifiedFile with Google Closure compiler.
- * callback gets executed once finished.
- */
-AmberC.prototype.closure_compile = function(sourceFile, minifiedFile, callback) {
-	// exec is asynchronous
-	var self = this;
-	exec(
-		'java -jar ' +
-		self.closure_jar + ' ' +
-		self.defaults.closure_options +
-		' --js '+ sourceFile +
-		' --js_output_file '+ minifiedFile,
-		function (error, stdout, stderr) {
-			if (error) {
-				console.log(stderr);
-			} else {
-				console.log(stdout);
-				console.log('Minified: '+ minifiedFile);
-			}
-			callback();
-		}
-	);
-};
-
 module.exports.Compiler = AmberC;
 module.exports.createDefaults = createDefaults;
 module.exports.Combo = Combo;

BIN
browser.png


+ 23 - 13
grunt/tasks/grunt-amberc.js

@@ -5,14 +5,23 @@ module.exports = function(grunt) {
   var amberc = require('../../bin/amberc.js');
 
   /**
-     Full config looks like this:
+     A full example entry for a Gruntfile.js is available below.
+     Please note that the verbose level is either specified globally
+     or on a target specific level.
+     However, it can additionally be triggered on the commandline by
+     adding the '-v' or '--verbose' flag.
+
+     Example Gruntfile.js entry:
+
      amberc: {
-       _config: {
+       options: {
          amber_dir: process.cwd(),     // REQUIRED
-         closure_jar: '',              // optional
          verbose: true                 // optional
        },
        helloWorld: {
+         options: {                             // the 'options' object is optional
+           verbose: true
+         },
          src: ['projects/HelloWorld/st/HelloWorld.st'], // REQUIRED
          output_dir: 'projects/HelloWorld/js',  // optional
          libraries: 'Canvas',                   // optional
@@ -28,25 +37,27 @@ module.exports = function(grunt) {
 
    */
   grunt.registerMultiTask('amberc', 'Compile Smalltalk files with the amberc compiler', function() {
-    // mark required properties
-    this.requiresConfig('amberc.options.amber_dir');
-    this.requiresConfig(['amberc', this.target, 'src']);
+    // mark task as async task
+    var done = this.async();
 
     var options = this.options({
       amber_dir: undefined,
-      closure_jar: '',
       verbose: grunt.option('verbose') || false
     });
     this.data.verbose = options.verbose;
 
-    // mark task as async task
-    var done = this.async();
+    // mark required properties
+    this.requiresConfig('amberc.options.amber_dir');
+    // raise error on missing source files
+    if (this.filesSrc.length === 0) {
+        grunt.fail.fatal('No source files to compile or link.');
+    }
 
     // create and initialize amberc
-    var compiler = new amberc.Compiler(grunt.config('amberc.options.amber_dir'), grunt.config('amberc.options.closure_jar'));
+    var compiler = new amberc.Compiler(grunt.config('amberc.options.amber_dir'));
 
     // generate the amberc configuration out of the given target properties
-    var configuration = generateCompilerConfiguration(this.data, grunt.config('amberc.options.amber_dir'));
+    var configuration = generateCompilerConfiguration(this.data, this.filesSrc, grunt.config('amberc.options.amber_dir'));
 
     // run the compiler and call the async callback once finished
     var self = this;
@@ -57,7 +68,7 @@ module.exports = function(grunt) {
   });
 
 
-  function generateCompilerConfiguration(data, amber_dir) {
+  function generateCompilerConfiguration(data, sourceFiles, amber_dir) {
     var configuration = amberc.createDefaults(amber_dir);
     var parameters = [];
 
@@ -83,7 +94,6 @@ module.exports = function(grunt) {
       configuration.loadsuffix = librarySuffix;
       configuration.suffix_used = librarySuffix;
     }
-    var sourceFiles = data.src;
     if (undefined !== sourceFiles) {
       sourceFiles.forEach(function(currentItem){
         var fileSuffix = path.extname(currentItem);

+ 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())._isCapitalized();
+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 isCapitalized\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:", "isCapitalized", "current", "at:"],
+referencedClasses: ["PlatformInterface", "Smalltalk"]
 }),
 smalltalk.ASTInterpreter);
 

+ 27 - 36
js/Compiler-Semantic.js

@@ -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())._isCapitalized();
+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 isCapitalized\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:", "isCapitalized", "value", "name:", "new", "yourself", "add:", "classReferences", "errorUnknownVariable:", "binding:"],
+referencedClasses: ["ClassRefVar", "UnknownVar"]
 }),
 smalltalk.SemanticAnalyzer);
 

+ 33 - 8
js/Compiler-Tests.js

@@ -515,9 +515,10 @@ self._should_return_("foo ^ false",false);
 self._should_return_("foo ^ #{1->2. 3->4}",smalltalk.HashedCollection._from_([(1).__minus_gt((2)),(3).__minus_gt((4))]));
 self._should_return_("foo ^ #hello","hello");
 self._should_return_("foo ^ -123.456",(-123.456));
+self._should_return_("foo ^ -2.5e4",(-25000));
 return self}, function($ctx1) {$ctx1.fill(self,"testLiterals",{},smalltalk.CodeGeneratorTest)})},
 args: [],
-source: "testLiterals\x0a\x09self should: 'foo ^ 1' return: 1.\x0a\x09self should: 'foo ^ ''hello''' return: 'hello'.\x0a\x09self should: 'foo ^ #(1 2 3 4)' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ {1. [:x | x ] value: 2. 3. [4] value}' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ true' return: true.\x0a\x09self should: 'foo ^ false' return: false.\x0a\x09self should: 'foo ^ #{1->2. 3->4}' return: #{1->2. 3->4}.\x0a\x09self should: 'foo ^ #hello' return: #hello.\x0a\x09self should: 'foo ^ -123.456' return: -123.456",
+source: "testLiterals\x0a\x09self should: 'foo ^ 1' return: 1.\x0a\x09self should: 'foo ^ ''hello''' return: 'hello'.\x0a\x09self should: 'foo ^ #(1 2 3 4)' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ {1. [:x | x ] value: 2. 3. [4] value}' return: #(1 2 3 4).\x0a\x09self should: 'foo ^ true' return: true.\x0a\x09self should: 'foo ^ false' return: false.\x0a\x09self should: 'foo ^ #{1->2. 3->4}' return: #{1->2. 3->4}.\x0a\x09self should: 'foo ^ #hello' return: #hello.\x0a\x09self should: 'foo ^ -123.456' return: -123.456.\x0a\x09self should: 'foo ^ -2.5e4' return: -25000.",
 messageSends: ["should:return:", "->"],
 referencedClasses: []
 }),
@@ -701,6 +702,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 +1058,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);
 

+ 41 - 0
js/Kernel-Collections.js

@@ -3828,6 +3828,29 @@ referencedClasses: []
 }),
 smalltalk.String);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "capitalized",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self._isEmpty();
+if(smalltalk.assert($2)){
+$1=self;
+} else {
+$1=_st(_st(self._first())._asUppercase()).__comma(self._allButFirst());
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"capitalized",{},smalltalk.String)})},
+args: [],
+source: "capitalized\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: [ self ]\x0a\x09\x09ifFalse: [ self first asUppercase, self allButFirst ]",
+messageSends: ["ifTrue:ifFalse:", "isEmpty", ",", "asUppercase", "first", "allButFirst"],
+referencedClasses: []
+}),
+smalltalk.String);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "charCodeAt:",
@@ -3945,6 +3968,24 @@ referencedClasses: []
 }),
 smalltalk.String);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isCapitalized",
+category: 'testing',
+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,"isCapitalized",{},smalltalk.String)})},
+args: [],
+source: "isCapitalized\x0a\x09^ self first asUppercase == self first",
+messageSends: ["==", "asUppercase", "first"],
+referencedClasses: []
+}),
+smalltalk.String);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isImmutable",

+ 240 - 2
js/Kernel-Objects.js

@@ -2229,6 +2229,24 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "**",
+category: 'mathematical functions',
+fn: function (exponent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._raisedTo_(exponent);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"**",{exponent:exponent},smalltalk.Number)})},
+args: ["exponent"],
+source: "** exponent\x0a\x09^self raisedTo: exponent",
+messageSends: ["raisedTo:"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "+",
@@ -2277,6 +2295,24 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "//",
+category: 'arithmetic',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self.__slash(aNumber))._floor();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"//",{aNumber:aNumber},smalltalk.Number)})},
+args: ["aNumber"],
+source: "// aNumber\x0a\x09^(self / aNumber) floor",
+messageSends: ["floor", "/"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "<",
@@ -2413,6 +2449,54 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "arcCos",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.acos(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"arcCos",{},smalltalk.Number)})},
+args: [],
+source: "arcCos\x0a\x09<return Math.acos(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "arcSin",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.asin(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"arcSin",{},smalltalk.Number)})},
+args: [],
+source: "arcSin\x0a\x09<return Math.asin(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "arcTan",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.atan(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"arcTan",{},smalltalk.Number)})},
+args: [],
+source: "arcTan\x0a\x09<return Math.atan(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asJSON",
@@ -2555,6 +2639,22 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cos",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.cos(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"cos",{},smalltalk.Number)})},
+args: [],
+source: "cos\x0a\x09<return Math.cos(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "deepCopy",
@@ -2675,6 +2775,54 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "ln",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.log(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"ln",{},smalltalk.Number)})},
+args: [],
+source: "ln\x0a\x09<return Math.log(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "log",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.log(self) / Math.LN10;;
+return self}, function($ctx1) {$ctx1.fill(self,"log",{},smalltalk.Number)})},
+args: [],
+source: "log\x0a\x09<return Math.log(self) / Math.LN10;>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "log:",
+category: 'mathematical functions',
+fn: function (aNumber){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.log(self) / Math.log(aNumber);;
+return self}, function($ctx1) {$ctx1.fill(self,"log:",{aNumber:aNumber},smalltalk.Number)})},
+args: ["aNumber"],
+source: "log: aNumber\x0a\x09<return Math.log(self) / Math.log(aNumber);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "max:",
@@ -2811,6 +2959,22 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "raisedTo:",
+category: 'mathematical functions',
+fn: function (exponent){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.pow(self, exponent);;
+return self}, function($ctx1) {$ctx1.fill(self,"raisedTo:",{exponent:exponent},smalltalk.Number)})},
+args: ["exponent"],
+source: "raisedTo: exponent\x0a\x09<return Math.pow(self, exponent);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "rounded",
@@ -2827,10 +2991,52 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "sign",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self._isZero();
+if(smalltalk.assert($1)){
+return (0);
+};
+$2=self._positive();
+if(smalltalk.assert($2)){
+return (1);
+} else {
+return (-1);
+};
+return self}, function($ctx1) {$ctx1.fill(self,"sign",{},smalltalk.Number)})},
+args: [],
+source: "sign\x0a\x09self isZero \x0a\x09\x09ifTrue: [ ^ 0 ].\x0a\x09self positive\x0a\x09\x09ifTrue: [ ^ 1 ]\x0a\x09\x09ifFalse: [ ^ -1 ].",
+messageSends: ["ifTrue:", "isZero", "ifTrue:ifFalse:", "positive"],
+referencedClasses: []
+}),
+smalltalk.Number);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "sin",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.sin(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"sin",{},smalltalk.Number)})},
+args: [],
+source: "sin\x0a\x09<return Math.sin(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "sqrt",
-category: 'arithmetic',
+category: 'mathematical functions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -2846,7 +3052,7 @@ smalltalk.Number);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "squared",
-category: 'arithmetic',
+category: 'mathematical functions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -2861,6 +3067,22 @@ referencedClasses: []
 }),
 smalltalk.Number);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "tan",
+category: 'mathematical functions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.tan(self);;
+return self}, function($ctx1) {$ctx1.fill(self,"tan",{},smalltalk.Number)})},
+args: [],
+source: "tan\x0a\x09<return Math.tan(self);>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "timesRepeat:",
@@ -3081,6 +3303,22 @@ referencedClasses: []
 smalltalk.Number);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "e",
+category: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return Math.E;;
+return self}, function($ctx1) {$ctx1.fill(self,"e",{},smalltalk.Number.klass)})},
+args: [],
+source: "e\x0a\x09<return Math.E;>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Number.klass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "heliosClass",

+ 102 - 2
js/Kernel-Tests.js

@@ -2299,6 +2299,26 @@ referencedClasses: ["Error"]
 }),
 smalltalk.StringTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testCapitalized",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_("test"._capitalized(),"Test");
+self._assert_equals_("Test"._capitalized(),"Test");
+self._assert_equals_(""._capitalized(),"");
+self._assert_equals_("Test"._isCapitalized(),true);
+self._assert_equals_("test"._isCapitalized(),false);
+return self}, function($ctx1) {$ctx1.fill(self,"testCapitalized",{},smalltalk.StringTest)})},
+args: [],
+source: "testCapitalized\x0a\x09self assert: 'test' capitalized equals: 'Test'.\x0a\x09self assert: 'Test' capitalized equals: 'Test'.\x0a\x09self assert: '' capitalized equals: ''.\x0a\x09self assert: 'Test' isCapitalized equals: true.\x0a\x09self assert: 'test' isCapitalized equals: false.",
+messageSends: ["assert:equals:", "capitalized", "isCapitalized"],
+referencedClasses: []
+}),
+smalltalk.StringTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testCollect",
@@ -3458,12 +3478,14 @@ self._assert_equals_((2).__minus((1)),(1));
 self._assert_equals_((-2).__minus((1)),(-3));
 self._assert_equals_((12).__slash((2)),(6));
 self._assert_equals_((3).__star((4)),(12));
+self._assert_equals_((7).__slash_slash((2)),(3));
+self._assert_equals_((7).__backslash_backslash((2)),(1));
 self._assert_equals_(_st((1).__plus((2))).__star((3)),(9));
 self._assert_equals_((1).__plus((2).__star((3))),(7));
 return self}, function($ctx1) {$ctx1.fill(self,"testArithmetic",{},smalltalk.NumberTest)})},
 args: [],
-source: "testArithmetic\x0a\x09\x0a\x09\x22We rely on JS here, so we won't test complex behavior, just check if\x0a\x09message sends are corrects\x22\x0a\x0a\x09self assert: 1.5 + 1 equals: 2.5.\x0a\x09self assert: 2 - 1 equals: 1.\x0a\x09self assert: -2 - 1 equals: -3.\x0a\x09self assert: 12 / 2 equals: 6.\x0a\x09self assert: 3 * 4 equals: 12.\x0a\x0a\x09\x22Simple parenthesis and execution order\x22\x0a\x09self assert: 1 + 2 * 3 equals: 9.\x0a\x09self assert: 1 + (2 * 3) equals: 7",
-messageSends: ["assert:equals:", "+", "-", "/", "*"],
+source: "testArithmetic\x0a\x09\x0a\x09\x22We rely on JS here, so we won't test complex behavior, just check if\x0a\x09message sends are corrects\x22\x0a\x0a\x09self assert: 1.5 + 1 equals: 2.5.\x0a\x09self assert: 2 - 1 equals: 1.\x0a\x09self assert: -2 - 1 equals: -3.\x0a\x09self assert: 12 / 2 equals: 6.\x0a\x09self assert: 3 * 4 equals: 12.\x0a\x09self assert: 7 // 2 equals: 3.\x0a\x09self assert: 7 \x5c\x5c 2 equals: 1.\x0a\x0a\x09\x22Simple parenthesis and execution order\x22\x0a\x09self assert: 1 + 2 * 3 equals: 9.\x0a\x09self assert: 1 + (2 * 3) equals: 7",
+messageSends: ["assert:equals:", "+", "-", "/", "*", "//", "\x5c\x5c"],
 referencedClasses: []
 }),
 smalltalk.NumberTest);
@@ -3809,6 +3831,25 @@ referencedClasses: ["MessageNotUnderstood"]
 }),
 smalltalk.NumberTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testLog",
+category: 'tests',
+fn: function (){
+var self=this;
+function $Number(){return smalltalk.Number||(typeof Number=="undefined"?nil:Number)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_((10000)._log(),(4));
+self._assert_equals_((512)._log_((2)),(9));
+self._assert_equals_(_st(_st($Number())._e())._ln(),(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testLog",{},smalltalk.NumberTest)})},
+args: [],
+source: "testLog\x0a\x09self assert: 10000 log equals: 4.\x0a\x09self assert: (512 log: 2) equals: 9.\x0a\x09self assert: Number e ln equals: 1.",
+messageSends: ["assert:equals:", "log", "log:", "ln", "e"],
+referencedClasses: ["Number"]
+}),
+smalltalk.NumberTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testMinMax",
@@ -3871,6 +3912,26 @@ referencedClasses: []
 }),
 smalltalk.NumberTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testRaisedTo",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_((2)._raisedTo_((4)),(16));
+self._assert_equals_((2)._raisedTo_((0)),(1));
+self._assert_equals_((2)._raisedTo_((-3)),(0.125));
+self._assert_equals_((4)._raisedTo_((0.5)),(2));
+self._assert_equals_((2).__star_star((4)),(16));
+return self}, function($ctx1) {$ctx1.fill(self,"testRaisedTo",{},smalltalk.NumberTest)})},
+args: [],
+source: "testRaisedTo\x0a\x09self assert: (2 raisedTo: 4) equals: 16.\x0a\x09self assert: (2 raisedTo: 0) equals: 1.\x0a\x09self assert: (2 raisedTo: -3) equals: 0.125.\x0a\x09self assert: (4 raisedTo: 0.5) equals: 2.\x0a\x09\x0a\x09self assert: 2 ** 4 equals: 16.",
+messageSends: ["assert:equals:", "raisedTo:", "**"],
+referencedClasses: []
+}),
+smalltalk.NumberTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testRounded",
@@ -3889,6 +3950,24 @@ referencedClasses: []
 }),
 smalltalk.NumberTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testSign",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_((5)._sign(),(1));
+self._assert_equals_((0)._sign(),(0));
+self._assert_equals_((-1.4)._sign(),(-1));
+return self}, function($ctx1) {$ctx1.fill(self,"testSign",{},smalltalk.NumberTest)})},
+args: [],
+source: "testSign\x0a\x09self assert: 5 sign equals: 1.\x0a\x09self assert: 0 sign equals: 0.\x0a\x09self assert: -1.4 sign equals: -1.",
+messageSends: ["assert:equals:", "sign"],
+referencedClasses: []
+}),
+smalltalk.NumberTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testSqrt",
@@ -3988,6 +4067,27 @@ referencedClasses: ["Error"]
 }),
 smalltalk.NumberTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testTrigonometry",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_((0)._cos(),(1));
+self._assert_equals_((0)._sin(),(0));
+self._assert_equals_((0)._tan(),(0));
+self._assert_equals_((1)._arcCos(),(0));
+self._assert_equals_((0)._arcSin(),(0));
+self._assert_equals_((0)._arcTan(),(0));
+return self}, function($ctx1) {$ctx1.fill(self,"testTrigonometry",{},smalltalk.NumberTest)})},
+args: [],
+source: "testTrigonometry\x0a\x09self assert: 0 cos equals: 1.\x0a\x09self assert: 0 sin equals: 0.\x0a\x09self assert: 0 tan equals: 0.\x0a\x09self assert: 1 arcCos equals: 0.\x0a\x09self assert: 0 arcSin equals: 0.\x0a\x09self assert: 0 arcTan equals: 0.",
+messageSends: ["assert:equals:", "cos", "sin", "tan", "arcCos", "arcSin", "arcTan"],
+referencedClasses: []
+}),
+smalltalk.NumberTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testTruncated",

+ 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

@@ -129,6 +129,15 @@ localAt: aString
 			context localAt: 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] ]
+!
+
 localAt: aString put: anObject
 	self locals at: aString put: anObject
 !
@@ -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 isCapitalized
+					ifTrue: [
+						Smalltalk current 
+							at: aNode value 
+							ifAbsent: [ PlatformInterface globals at: aNode value ]]]])
 ! !
 
 Error subclass: #ASTInterpreterError

+ 14 - 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 isCapitalized
+			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'!

+ 63 - 50
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'.
@@ -212,7 +222,8 @@ testLiterals
 	self should: 'foo ^ false' return: false.
 	self should: 'foo ^ #{1->2. 3->4}' return: #{1->2. 3->4}.
 	self should: 'foo ^ #hello' return: #hello.
-	self should: 'foo ^ -123.456' return: -123.456
+	self should: 'foo ^ -123.456' return: -123.456.
+	self should: 'foo ^ -2.5e4' return: -25000.
 !
 
 testLocalReturn
@@ -233,6 +244,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 +265,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 +295,27 @@ testSendReceiverAndArgumentsOrdered
 ' return: {Array. 2}.
 !
 
+testSuperSend
+	self 
+		should: 'foo ^ super isBoolean' 
+		receiver: true
+		return: false
+!
+
+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.
+!
+
+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.
@@ -341,35 +381,6 @@ testifTrueIfFalse
 	
 	self should: 'foo ^ false ifTrue: [ 2 ] ifFalse: [ 1 ]' return: 1.
 	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
 ! !
 
 CodeGeneratorTest subclass: #InliningCodeGeneratorTest
@@ -388,10 +399,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 +406,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 +437,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 +460,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
 !
 

+ 14 - 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();>
 ! !
@@ -1309,6 +1309,12 @@ asUppercase
 	<return self.toUpperCase()>
 !
 
+capitalized
+	^ self isEmpty
+		ifTrue: [ self ]
+		ifFalse: [ self first asUppercase, self allButFirst ]
+!
+
 crlfSanitized
 	^self lines join: String lf
 !
@@ -1488,6 +1494,10 @@ includesSubString: subString
 	< return self.indexOf(subString) !!= -1 >
 !
 
+isCapitalized
+	^ self first asUppercase == self first
+!
+
 isImmutable
 	^ true
 !

+ 68 - 6
st/Kernel-Objects.st

@@ -775,12 +775,8 @@ negated
 	^0 - self
 !
 
-sqrt
-	<return Math.sqrt(self)>
-!
-
-squared
-	^self * self
+// aNumber
+	^(self / aNumber) floor
 ! !
 
 !Number methodsFor: 'comparing'!
@@ -948,6 +944,68 @@ to: stop do: aBlock
 			nextValue := nextValue + 1]
 ! !
 
+!Number methodsFor: 'mathematical functions'!
+
+sqrt
+	<return Math.sqrt(self)>
+!
+
+squared
+	^self * self
+!
+
+cos
+	<return Math.cos(self);>
+!
+
+sin
+	<return Math.sin(self);>
+!
+
+tan
+	<return Math.tan(self);>
+!
+
+arcCos
+	<return Math.acos(self);>
+!
+
+arcSin
+	<return Math.asin(self);>
+!
+
+arcTan
+	<return Math.atan(self);>
+!
+
+log
+	<return Math.log(self) / Math.LN10;>
+!
+
+log: aNumber
+	<return Math.log(self) / Math.log(aNumber);>
+!
+
+raisedTo: exponent
+	<return Math.pow(self, exponent);>
+!
+
+sign
+	self isZero 
+		ifTrue: [ ^ 0 ].
+	self positive
+		ifTrue: [ ^ 1 ]
+		ifFalse: [ ^ -1 ].
+!
+
+** exponent
+	^self raisedTo: exponent
+!
+
+ln
+	<return Math.log(self);>
+! !
+
 !Number methodsFor: 'printing'!
 
 printOn: aStream
@@ -1002,6 +1060,10 @@ heliosClass
 
 pi
 	<return Math.PI>
+!
+
+e
+	<return Math.E;>
 ! !
 
 Object subclass: #Point

+ 40 - 0
st/Kernel-Tests.st

@@ -967,6 +967,14 @@ testStreamContents
 				nextPutAll: 'hello'; space;
 				nextPutAll: 'world' ])
 		equals: 'hello world'
+!
+
+testCapitalized
+	self assert: 'test' capitalized equals: 'Test'.
+	self assert: 'Test' capitalized equals: 'Test'.
+	self assert: '' capitalized equals: ''.
+	self assert: 'Test' isCapitalized equals: true.
+	self assert: 'test' isCapitalized equals: false.
 ! !
 
 !StringTest class methodsFor: 'accessing'!
@@ -1301,6 +1309,8 @@ testArithmetic
 	self assert: -2 - 1 equals: -3.
 	self assert: 12 / 2 equals: 6.
 	self assert: 3 * 4 equals: 12.
+	self assert: 7 // 2 equals: 3.
+	self assert: 7 \\ 2 equals: 1.
 
 	"Simple parenthesis and execution order"
 	self assert: 1 + 2 * 3 equals: 9.
@@ -1496,6 +1506,36 @@ testTruncated
 	self assert: 3 truncated equals: 3.
 	self assert: 3.212 truncated equals: 3.
 	self assert: 3.51 truncated equals: 3
+!
+
+testTrigonometry
+	self assert: 0 cos equals: 1.
+	self assert: 0 sin equals: 0.
+	self assert: 0 tan equals: 0.
+	self assert: 1 arcCos equals: 0.
+	self assert: 0 arcSin equals: 0.
+	self assert: 0 arcTan equals: 0.
+!
+
+testLog
+	self assert: 10000 log equals: 4.
+	self assert: (512 log: 2) equals: 9.
+	self assert: Number e ln equals: 1.
+!
+
+testRaisedTo
+	self assert: (2 raisedTo: 4) equals: 16.
+	self assert: (2 raisedTo: 0) equals: 1.
+	self assert: (2 raisedTo: -3) equals: 0.125.
+	self assert: (4 raisedTo: 0.5) equals: 2.
+	
+	self assert: 2 ** 4 equals: 16.
+!
+
+testSign
+	self assert: 5 sign equals: 1.
+	self assert: 0 sign equals: 0.
+	self assert: -1.4 sign equals: -1.
 ! !
 
 Object subclass: #ObjectMock

+ 66 - 130
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,
@@ -50,6 +49,7 @@ smalltalk.parser = (function(){
         "symbol": parse_symbol,
         "bareSymbol": parse_bareSymbol,
         "number": parse_number,
+        "numberExp": parse_numberExp,
         "hex": parse_hex,
         "float": parse_float,
         "integer": parse_integer,
@@ -63,8 +63,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 +463,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];
@@ -947,11 +876,14 @@ smalltalk.parser = (function(){
         var pos0;
         
         pos0 = clone(pos);
-        result0 = parse_hex();
+        result0 = parse_numberExp();
         if (result0 === null) {
-          result0 = parse_float();
+          result0 = parse_hex();
           if (result0 === null) {
-            result0 = parse_integer();
+            result0 = parse_float();
+            if (result0 === null) {
+              result0 = parse_integer();
+            }
           }
         }
         if (result0 !== null) {
@@ -972,6 +904,63 @@ smalltalk.parser = (function(){
         return result0;
       }
       
+      function parse_numberExp() {
+        var cacheKey = "numberExp@" + 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);
+        result0 = parse_float();
+        if (result0 === null) {
+          result0 = parse_integer();
+        }
+        if (result0 !== null) {
+          if (input.charCodeAt(pos.offset) === 101) {
+            result1 = "e";
+            advance(pos, 1);
+          } else {
+            result1 = null;
+            if (reportFailures === 0) {
+              matchFailed("\"e\"");
+            }
+          }
+          if (result1 !== null) {
+            result2 = parse_integer();
+            if (result2 !== null) {
+              result0 = [result0, result1, result2];
+            } else {
+              result0 = null;
+              pos = clone(pos1);
+            }
+          } else {
+            result0 = null;
+            pos = clone(pos1);
+          }
+        } else {
+          result0 = null;
+          pos = clone(pos1);
+        }
+        if (result0 !== null) {
+          result0 = (function(offset, line, column, n) {return parseFloat(n.join(""));})(pos0.offset, pos0.line, pos0.column, result0);
+        }
+        if (result0 === null) {
+          pos = clone(pos0);
+        }
+        
+        cache[cacheKey] = {
+          nextPos: clone(pos),
+          result:  result0
+        };
+        return result0;
+      }
+      
       function parse_hex() {
         var cacheKey = "hex@" + pos.offset;
         var cachedResult = cache[cacheKey];
@@ -1815,7 +1804,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 +1823,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 +3146,7 @@ smalltalk.parser = (function(){
         
         result0 = parse_literal();
         if (result0 === null) {
-          result0 = parse_reference();
+          result0 = parse_variable();
           if (result0 === null) {
             result0 = parse_subexpression();
           }

+ 5 - 9
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("");}
@@ -21,14 +20,16 @@ bareSymbol         = val:(selector / binarySelector / node:string {return node._
                              ._position_((line).__at(column))
                              ._value_(val);
                   }
-number         = n:(hex / float / integer) {
+number         = n:(numberExp / hex / float / integer) {
                      return smalltalk.ValueNode._new()
                             ._position_((line).__at(column))
                             ._value_(n);
                  }
+numberExp      = n:((float / integer) "e" integer) {return parseFloat(n.join(""));}
 hex            = neg:[-]? "16r" num:[0-9a-fA-F]+ {return parseInt((neg + num.join("")), 16);}
 float          = neg:[-]?digits:[0-9]+ "." dec:[0-9]+ {return parseFloat((neg + digits.join("") + "." + dec.join("")), 10);}
 integer        = neg:[-]?digits:[0-9]+ {return (parseInt(neg+digits.join(""), 10));}
+
 literalArray   = "#(" rest:literalArrayRest {return rest;}
 bareLiteralArray   = "(" rest:literalArrayRest {return rest;}
 literalArrayRest   = ws lits:(lit:(parseTimeLiteral / bareLiteralArray / bareSymbol) ws {return lit._value();})* ws ")" {
@@ -59,18 +60,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};}