Explorar el Código

More improvements of the compiler.

- Better packages
- Bug fixes for cascade nodes
- scope level annotations for blocks
Nicolas Petton hace 12 años
padre
commit
bb1b9e419d

+ 1 - 23
js/Compiler-AST.deploy.js

@@ -259,7 +259,7 @@ smalltalk.AssignmentNode);
 
 
 
-smalltalk.addClass('BlockNode', smalltalk.Node, ['parameters', 'scope', 'inlined'], 'Compiler-AST');
+smalltalk.addClass('BlockNode', smalltalk.Node, ['parameters', 'scope'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -271,28 +271,6 @@ return self;}
 }),
 smalltalk.BlockNode);
 
-smalltalk.addMethod(
-"_inlined",
-smalltalk.method({
-selector: "inlined",
-fn: function () {
-var self=this;
-return (($receiver = self['@inlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;}
-}),
-smalltalk.BlockNode);
-
-smalltalk.addMethod(
-"_inlined_",
-smalltalk.method({
-selector: "inlined:",
-fn: function (aBoolean) {
-var self=this;
-(self['@inlined']=aBoolean);
-return self;}
-}),
-smalltalk.BlockNode);
-
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({

+ 1 - 33
js/Compiler-AST.js

@@ -375,7 +375,7 @@ smalltalk.AssignmentNode);
 
 
 
-smalltalk.addClass('BlockNode', smalltalk.Node, ['parameters', 'scope', 'inlined'], 'Compiler-AST');
+smalltalk.addClass('BlockNode', smalltalk.Node, ['parameters', 'scope'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -392,38 +392,6 @@ referencedClasses: []
 }),
 smalltalk.BlockNode);
 
-smalltalk.addMethod(
-"_inlined",
-smalltalk.method({
-selector: "inlined",
-category: 'accessing',
-fn: function () {
-var self=this;
-return (($receiver = self['@inlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;},
-args: [],
-source: "inlined\x0a\x09^inlined ifNil: [false]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-smalltalk.BlockNode);
-
-smalltalk.addMethod(
-"_inlined_",
-smalltalk.method({
-selector: "inlined:",
-category: 'accessing',
-fn: function (aBoolean) {
-var self=this;
-(self['@inlined']=aBoolean);
-return self;},
-args: ["aBoolean"],
-source: "inlined: aBoolean\x0a\x09inlined := aBoolean",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.BlockNode);
-
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 322 - 87
js/Compiler-Core.deploy.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 292 - 307
js/Compiler-Core.js


+ 60 - 0
js/Compiler-Exceptions.deploy.js

@@ -0,0 +1,60 @@
+smalltalk.addPackage('Compiler-Exceptions', {});
+smalltalk.addClass('CompilerError', smalltalk.Error, [], 'Compiler-Exceptions');
+
+
+smalltalk.addClass('ParseError', smalltalk.CompilerError, [], 'Compiler-Exceptions');
+
+
+smalltalk.addClass('SemanticError', smalltalk.CompilerError, [], 'Compiler-Exceptions');
+
+
+smalltalk.addClass('ShadowingVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;}
+}),
+smalltalk.ShadowingVariableError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;}
+}),
+smalltalk.ShadowingVariableError);
+
+
+
+smalltalk.addClass('UnknownVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;}
+}),
+smalltalk.UnknownVariableError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;}
+}),
+smalltalk.UnknownVariableError);
+
+
+

+ 83 - 0
js/Compiler-Exceptions.js

@@ -0,0 +1,83 @@
+smalltalk.addPackage('Compiler-Exceptions', {});
+smalltalk.addClass('CompilerError', smalltalk.Error, [], 'Compiler-Exceptions');
+
+
+smalltalk.addClass('ParseError', smalltalk.CompilerError, [], 'Compiler-Exceptions');
+
+
+smalltalk.addClass('SemanticError', smalltalk.CompilerError, [], 'Compiler-Exceptions');
+smalltalk.SemanticError.comment="I represent an abstract semantic error thrown by the SemanticAnalyzer.\x0aSemantic errors can be unknown variable errors, etc.\x0aSee my subclasses for concrete errors.\x0a\x0aThe IDE should catch instances of Semantic error to deal with them when compiling"
+
+
+smalltalk.addClass('ShadowingVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.ShadowingVariableError.comment="I get signaled when a variable in a block or method scope shadows a variable of the same name in an outer scope."
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;},
+args: [],
+source: "variableName\x0a\x09^ variableName",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ShadowingVariableError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+category: 'accessing',
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;},
+args: ["aString"],
+source: "variableName: aString\x0a\x09variableName := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ShadowingVariableError);
+
+
+
+smalltalk.addClass('UnknownVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.UnknownVariableError.comment="I get signaled when a variable is not defined.\x0aThe default behavior is to allow it, as this is how Amber currently is able to seamlessly send messages to JavaScript objects."
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;},
+args: [],
+source: "variableName\x0a\x09^ variableName",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.UnknownVariableError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+category: 'accessing',
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;},
+args: ["aString"],
+source: "variableName: aString\x0a\x09variableName := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.UnknownVariableError);
+
+
+

+ 223 - 4
js/Compiler-IR.deploy.js

@@ -156,7 +156,7 @@ fn: function () {
 var self=this;
 (($receiver = self['@nextAlias']) == nil || $receiver == undefined) ? (function(){return (self['@nextAlias']=(0));})() : $receiver;
 (self['@nextAlias']=((($receiver = self['@nextAlias']).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)])));
-return smalltalk.send("$_", "__comma", [smalltalk.send(self['@nextAlias'], "_asString", [])]);
+return smalltalk.send("$", "__comma", [smalltalk.send(self['@nextAlias'], "_asString", [])]);
 return self;}
 }),
 smalltalk.IRASTResolver);
@@ -606,7 +606,7 @@ smalltalk.method({
 selector: "emitOn:",
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutAssignment_to_", [smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), smalltalk.send(smalltalk.send(self, "_instructions", []), "_second", [])]);
+smalltalk.send(aStream, "_nextPutAssignment_to_", [smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), smalltalk.send(smalltalk.send(self, "_instructions", []), "_last", [])]);
 return self;}
 }),
 smalltalk.IRAssignment);
@@ -642,7 +642,7 @@ smalltalk.method({
 selector: "emitOn:",
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutClosureWith_arguments_", [(function(){return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRClosure.superclass || nil);}), smalltalk.send(smalltalk.send(self, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_asVariableName", []);})])]);
+smalltalk.send(aStream, "_nextPutClosureWith_arguments_", [(function(){return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRClosure.superclass || nil);}), smalltalk.send(self, "_arguments", [])]);
 return self;}
 }),
 smalltalk.IRClosure);
@@ -700,7 +700,7 @@ smalltalk.method({
 selector: "emitOn:",
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutMethodDeclaration_with_", [self, (function(){return smalltalk.send(aStream, "_nextPutFunctionWith_arguments_", [(function(){((($receiver = smalltalk.send(smalltalk.send(self, "_internalVariables", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})]));return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRMethod.superclass || nil);}), smalltalk.send(smalltalk.send(self, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_asVariableName", []);})])]);})]);
+smalltalk.send(aStream, "_nextPutMethodDeclaration_with_", [self, (function(){return smalltalk.send(aStream, "_nextPutFunctionWith_arguments_", [(function(){((($receiver = smalltalk.send(smalltalk.send(self, "_internalVariables", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})]));return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRMethod.superclass || nil);}), smalltalk.send(self, "_arguments", [])]);})]);
 return self;}
 }),
 smalltalk.IRMethod);
@@ -1082,6 +1082,225 @@ smalltalk.IRVerbatim);
 
 
 
+smalltalk.addClass('JSStream', smalltalk.Object, ['stream'], 'Compiler-IR');
+smalltalk.addMethod(
+"_contents",
+smalltalk.method({
+selector: "contents",
+fn: function () {
+var self=this;
+return smalltalk.send(self['@stream'], "_contents", []);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function () {
+var self=this;
+smalltalk.send(self, "_initialize", [], smalltalk.JSStream.superclass || nil);
+(self['@stream']=smalltalk.send("", "_writeStream", []));
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_lf",
+smalltalk.method({
+selector: "lf",
+fn: function () {
+var self=this;
+smalltalk.send(self['@stream'], "_lf", []);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPut_",
+smalltalk.method({
+selector: "nextPut:",
+fn: function (aString) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPut_", [aString]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutAll_",
+smalltalk.method({
+selector: "nextPutAll:",
+fn: function (aString) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", [aString]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutAssignment_to_",
+smalltalk.method({
+selector: "nextPutAssignment:to:",
+fn: function (varInstruction, valueInstruction) {
+var self=this;
+smalltalk.send(varInstruction, "_emitOn_", [self]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["="]);
+smalltalk.send(valueInstruction, "_emitOn_", [self]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutClosureWith_arguments_",
+smalltalk.method({
+selector: "nextPutClosureWith:arguments:",
+fn: function (aBlock, anArray) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["(function("]);
+smalltalk.send(anArray, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asVariableName", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPut_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["})"]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutFunctionWith_arguments_",
+smalltalk.method({
+selector: "nextPutFunctionWith:arguments:",
+fn: function (aBlock, anArray) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["fn: function("]);
+smalltalk.send(anArray, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asVariableName", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPut_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(self, "_nextPutVar_", ["$return"]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["var self=this;"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["return $return || self;}"]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutMethodDeclaration_with_",
+smalltalk.method({
+selector: "nextPutMethodDeclaration:with:",
+fn: function (aMethod, aBlock) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["smalltalk.method({"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("selector: \x22", "__comma", [smalltalk.send(aMethod, "_selector", [])]), "__comma", ["\x22,"])]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("source: ", "__comma", [smalltalk.send(smalltalk.send(aMethod, "_source", []), "_asJavascript", [])]), "__comma", [","])]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(",", "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", ["messageSends: "])]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aMethod, "_messageSends", []), "_asArray", []), "_asJavascript", []), "__comma", [","])]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("args: ", "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aMethod, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_value", []);})]), "_asArray", []), "_asJavascript", [])]), "__comma", [","])]);smalltalk.send($rec, "_lf", []);return smalltalk.send($rec, "_nextPutAll_", ["referencedClasses: ["]);})(self['@stream']);
+smalltalk.send(smalltalk.send(aMethod, "_classReferences", []), "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asJavascript", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["]"]);return smalltalk.send($rec, "_nextPutAll_", ["})"]);})(self['@stream']);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutNonLocalReturnHandlingWith_",
+smalltalk.method({
+selector: "nextPutNonLocalReturnHandlingWith:",
+fn: function (aBlock) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["var $early={};"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", ["try {"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["}"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", ["catch(e) {if(e===$early)return e[0]; throw e}"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutNonLocalReturnWith_",
+smalltalk.method({
+selector: "nextPutNonLocalReturnWith:",
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["(function(){throw $early=["]);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["]})()"]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutReturnWith_",
+smalltalk.method({
+selector: "nextPutReturnWith:",
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["$return="]);
+smalltalk.send(aBlock, "_value", []);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutSendTo_selector_arguments_",
+smalltalk.method({
+selector: "nextPutSendTo:selector:arguments:",
+fn: function (receiver, selector, arguments) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["smalltalk.send("]);
+smalltalk.send(receiver, "_emitOn_", [self]);
+smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(smalltalk.send(",\x22", "__comma", [smalltalk.send(selector, "_asSelector", [])]), "__comma", ["\x22,["])]);
+smalltalk.send(arguments, "_do_separatedBy_", [(function(each){return smalltalk.send(each, "_emitOn_", [self]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["])"]);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutSequenceWith_",
+smalltalk.method({
+selector: "nextPutSequenceWith:",
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value", []);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutStatement_with_",
+smalltalk.method({
+selector: "nextPutStatement:with:",
+fn: function (anInteger, aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [";"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutVar_",
+smalltalk.method({
+selector: "nextPutVar:",
+fn: function (aString) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("var ", "__comma", [aString]), "__comma", [";"])]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;}
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutVars_",
+smalltalk.method({
+selector: "nextPutVars:",
+fn: function (aCollection) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["var "]);
+smalltalk.send(aCollection, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [each]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [";"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;}
+}),
+smalltalk.JSStream);
+
+
+
 smalltalk.addMethod(
 "_appendToInstruction_",
 smalltalk.method({

+ 318 - 12
js/Compiler-IR.js

@@ -1,6 +1,6 @@
 smalltalk.addPackage('Compiler-IR', {});
 smalltalk.addClass('IRASTTranslator', smalltalk.NodeVisitor, ['builder', 'source'], 'Compiler-IR');
-smalltalk.IRASTTranslator.comment="I an the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.\x0aI rely on a builder object, instance of IRBuilder."
+smalltalk.IRASTTranslator.comment="I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.\x0aI rely on a builder object, instance of IRBuilder.\x0a\x0aI am myself unable to produce a valid IR as nodes are not resolved. \x0aSee concrete subclasses."
 smalltalk.addMethod(
 "_builder",
 smalltalk.method({
@@ -224,10 +224,10 @@ fn: function () {
 var self=this;
 (($receiver = self['@nextAlias']) == nil || $receiver == undefined) ? (function(){return (self['@nextAlias']=(0));})() : $receiver;
 (self['@nextAlias']=((($receiver = self['@nextAlias']).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)])));
-return smalltalk.send("$_", "__comma", [smalltalk.send(self['@nextAlias'], "_asString", [])]);
+return smalltalk.send("$", "__comma", [smalltalk.send(self['@nextAlias'], "_asString", [])]);
 return self;},
 args: [],
-source: "nextAlias\x0a\x09\x22Message sends are assigned, or 'aliased', to internal variables.\x0a\x09Internal variable names are unique, and attached to the annotated send node\x22\x0a\x0a\x09nextAlias ifNil: [nextAlias := 0].\x0a\x09nextAlias := nextAlias + 1.\x0a\x09^ '$_', nextAlias asString",
+source: "nextAlias\x0a\x09\x22Message sends are assigned, or 'aliased', to internal variables.\x0a\x09Internal variable names are unique, and attached to the annotated send node\x22\x0a\x0a\x09nextAlias ifNil: [ nextAlias := 0 ].\x0a\x09nextAlias := nextAlias + 1.\x0a\x09^ '$', nextAlias asString",
 messageSends: ["ifNil:", "+", ",", "asString"],
 referencedClasses: []
 }),
@@ -871,11 +871,11 @@ selector: "emitOn:",
 category: 'emiting',
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutAssignment_to_", [smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), smalltalk.send(smalltalk.send(self, "_instructions", []), "_second", [])]);
+smalltalk.send(aStream, "_nextPutAssignment_to_", [smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), smalltalk.send(smalltalk.send(self, "_instructions", []), "_last", [])]);
 return self;},
 args: ["aStream"],
-source: "emitOn: aStream\x0a\x09aStream \x0a\x09\x09nextPutAssignment: self instructions first\x0a\x09\x09to: self instructions second",
-messageSends: ["nextPutAssignment:to:", "first", "instructions", "second"],
+source: "emitOn: aStream\x0a\x09aStream \x0a\x09\x09nextPutAssignment: self instructions first \x0a\x09\x09to: self instructions last",
+messageSends: ["nextPutAssignment:to:", "first", "instructions", "last"],
 referencedClasses: []
 }),
 smalltalk.IRAssignment);
@@ -922,11 +922,11 @@ selector: "emitOn:",
 category: 'emiting',
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutClosureWith_arguments_", [(function(){return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRClosure.superclass || nil);}), smalltalk.send(smalltalk.send(self, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_asVariableName", []);})])]);
+smalltalk.send(aStream, "_nextPutClosureWith_arguments_", [(function(){return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRClosure.superclass || nil);}), smalltalk.send(self, "_arguments", [])]);
 return self;},
 args: ["aStream"],
-source: "emitOn: aStream\x0a\x09aStream \x0a\x09\x09nextPutClosureWith: [ super emitOn: aStream ]\x0a\x09\x09arguments: (self arguments collect: [ :each | each asVariableName ])",
-messageSends: ["nextPutClosureWith:arguments:", "emitOn:", "collect:", "arguments", "asVariableName"],
+source: "emitOn: aStream\x0a\x09aStream \x0a\x09\x09nextPutClosureWith: [ super emitOn: aStream ] \x0a\x09\x09arguments: self arguments",
+messageSends: ["nextPutClosureWith:arguments:", "emitOn:", "arguments"],
 referencedClasses: []
 }),
 smalltalk.IRClosure);
@@ -1006,11 +1006,11 @@ selector: "emitOn:",
 category: 'emiting',
 fn: function (aStream) {
 var self=this;
-smalltalk.send(aStream, "_nextPutMethodDeclaration_with_", [self, (function(){return smalltalk.send(aStream, "_nextPutFunctionWith_arguments_", [(function(){((($receiver = smalltalk.send(smalltalk.send(self, "_internalVariables", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})]));return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRMethod.superclass || nil);}), smalltalk.send(smalltalk.send(self, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_asVariableName", []);})])]);})]);
+smalltalk.send(aStream, "_nextPutMethodDeclaration_with_", [self, (function(){return smalltalk.send(aStream, "_nextPutFunctionWith_arguments_", [(function(){((($receiver = smalltalk.send(smalltalk.send(self, "_internalVariables", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(aStream, "_nextPutVars_", [smalltalk.send(self, "_internalVariables", [])]);})]));return smalltalk.send(self, "_emitOn_", [aStream], smalltalk.IRMethod.superclass || nil);}), smalltalk.send(self, "_arguments", [])]);})]);
 return self;},
 args: ["aStream"],
-source: "emitOn: aStream\x0a\x09aStream \x0a\x09\x09nextPutMethodDeclaration: self\x0a\x09\x09with: [\x0a\x09\x09\x09aStream \x0a\x09\x09\x09\x09nextPutFunctionWith: [ \x0a\x09\x09\x09\x09\x09self internalVariables notEmpty ifTrue: [\x0a\x09\x09\x09\x09\x09\x09aStream nextPutVars: self internalVariables ].\x0a\x09\x09\x09\x09\x09super emitOn: aStream ]\x0a\x09\x09\x09\x09arguments: (self arguments collect: [ :each | each asVariableName ]) ]",
-messageSends: ["nextPutMethodDeclaration:with:", "nextPutFunctionWith:arguments:", "ifTrue:", "notEmpty", "internalVariables", "nextPutVars:", "emitOn:", "collect:", "arguments", "asVariableName"],
+source: "emitOn: aStream\x0a\x09aStream\x0a\x09\x09nextPutMethodDeclaration: self \x0a\x09\x09with: [\x0a\x09\x09\x09aStream \x0a\x09\x09\x09\x09nextPutFunctionWith: [ \x0a\x09\x09\x09\x09\x09self internalVariables notEmpty ifTrue: [\x0a\x09\x09\x09\x09\x09\x09aStream nextPutVars: self internalVariables ].\x0a\x09\x09\x09\x09\x09super emitOn: aStream ]\x0a\x09\x09\x09arguments: self arguments ]",
+messageSends: ["nextPutMethodDeclaration:with:", "nextPutFunctionWith:arguments:", "ifTrue:", "notEmpty", "internalVariables", "nextPutVars:", "emitOn:", "arguments"],
 referencedClasses: []
 }),
 smalltalk.IRMethod);
@@ -1313,6 +1313,7 @@ smalltalk.IRSequence);
 
 
 smalltalk.addClass('IRStatement', smalltalk.IRInstruction, ['pc'], 'Compiler-IR');
+smalltalk.IRStatement.comment="I am a statement instruction. \x0aStatements can be used to control the PC count, among other things."
 smalltalk.addMethod(
 "_emitOn_",
 smalltalk.method({
@@ -1452,6 +1453,7 @@ smalltalk.IRValue);
 
 
 smalltalk.addClass('IRVariable', smalltalk.IRInstruction, ['variable'], 'Compiler-IR');
+smalltalk.IRVariable.comment="I am a variable instruction."
 smalltalk.addMethod(
 "_emitOn_",
 smalltalk.method({
@@ -1553,6 +1555,310 @@ smalltalk.IRVerbatim);
 
 
 
+smalltalk.addClass('JSStream', smalltalk.Object, ['stream'], 'Compiler-IR');
+smalltalk.addMethod(
+"_contents",
+smalltalk.method({
+selector: "contents",
+category: 'accessing',
+fn: function () {
+var self=this;
+return smalltalk.send(self['@stream'], "_contents", []);
+return self;},
+args: [],
+source: "contents\x0a\x09^ stream contents",
+messageSends: ["contents"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function () {
+var self=this;
+smalltalk.send(self, "_initialize", [], smalltalk.JSStream.superclass || nil);
+(self['@stream']=smalltalk.send("", "_writeStream", []));
+return self;},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09stream := '' writeStream.",
+messageSends: ["initialize", "writeStream"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_lf",
+smalltalk.method({
+selector: "lf",
+category: 'streaming',
+fn: function () {
+var self=this;
+smalltalk.send(self['@stream'], "_lf", []);
+return self;},
+args: [],
+source: "lf\x0a\x09stream lf",
+messageSends: ["lf"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPut_",
+smalltalk.method({
+selector: "nextPut:",
+category: 'streaming',
+fn: function (aString) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPut_", [aString]);
+return self;},
+args: ["aString"],
+source: "nextPut: aString\x0a\x09stream nextPut: aString",
+messageSends: ["nextPut:"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutAll_",
+smalltalk.method({
+selector: "nextPutAll:",
+category: 'streaming',
+fn: function (aString) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", [aString]);
+return self;},
+args: ["aString"],
+source: "nextPutAll: aString\x0a\x09stream nextPutAll: aString",
+messageSends: ["nextPutAll:"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutAssignment_to_",
+smalltalk.method({
+selector: "nextPutAssignment:to:",
+category: 'streaming',
+fn: function (varInstruction, valueInstruction) {
+var self=this;
+smalltalk.send(varInstruction, "_emitOn_", [self]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["="]);
+smalltalk.send(valueInstruction, "_emitOn_", [self]);
+return self;},
+args: ["varInstruction", "valueInstruction"],
+source: "nextPutAssignment: varInstruction to: valueInstruction\x0a\x09varInstruction emitOn: self.\x0a\x09stream nextPutAll: '='.\x0a\x09valueInstruction emitOn: self",
+messageSends: ["emitOn:", "nextPutAll:"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutClosureWith_arguments_",
+smalltalk.method({
+selector: "nextPutClosureWith:arguments:",
+category: 'streaming',
+fn: function (aBlock, anArray) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["(function("]);
+smalltalk.send(anArray, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asVariableName", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPut_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["})"]);
+return self;},
+args: ["aBlock", "anArray"],
+source: "nextPutClosureWith: aBlock arguments: anArray\x0a\x09stream nextPutAll: '(function('.\x0a\x09anArray \x0a\x09\x09do: [ :each | stream nextPutAll: each asVariableName ]\x0a\x09\x09separatedBy: [ stream nextPut: ',' ].\x0a\x09stream nextPutAll: '){'; lf.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: '})'",
+messageSends: ["nextPutAll:", "do:separatedBy:", "asVariableName", "nextPut:", "lf", "value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutFunctionWith_arguments_",
+smalltalk.method({
+selector: "nextPutFunctionWith:arguments:",
+category: 'streaming',
+fn: function (aBlock, anArray) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["fn: function("]);
+smalltalk.send(anArray, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asVariableName", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPut_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(self, "_nextPutVar_", ["$return"]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["var self=this;"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["return $return || self;}"]);
+return self;},
+args: ["aBlock", "anArray"],
+source: "nextPutFunctionWith: aBlock arguments: anArray\x0a\x09stream nextPutAll: 'fn: function('.\x0a\x09anArray \x0a\x09\x09do: [ :each | stream nextPutAll: each asVariableName ]\x0a\x09\x09separatedBy: [ stream nextPut: ',' ].\x0a\x09stream nextPutAll: '){'; lf.\x0a\x09self nextPutVar: '$return'.\x0a\x09stream nextPutAll: 'var self=this;'; lf.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: 'return $return || self;}'",
+messageSends: ["nextPutAll:", "do:separatedBy:", "asVariableName", "nextPut:", "lf", "nextPutVar:", "value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutMethodDeclaration_with_",
+smalltalk.method({
+selector: "nextPutMethodDeclaration:with:",
+category: 'streaming',
+fn: function (aMethod, aBlock) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["smalltalk.method({"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("selector: \x22", "__comma", [smalltalk.send(aMethod, "_selector", [])]), "__comma", ["\x22,"])]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("source: ", "__comma", [smalltalk.send(smalltalk.send(aMethod, "_source", []), "_asJavascript", [])]), "__comma", [","])]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(",", "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", ["messageSends: "])]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aMethod, "_messageSends", []), "_asArray", []), "_asJavascript", []), "__comma", [","])]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("args: ", "__comma", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aMethod, "_arguments", []), "_collect_", [(function(each){return smalltalk.send(each, "_value", []);})]), "_asArray", []), "_asJavascript", [])]), "__comma", [","])]);smalltalk.send($rec, "_lf", []);return smalltalk.send($rec, "_nextPutAll_", ["referencedClasses: ["]);})(self['@stream']);
+smalltalk.send(smalltalk.send(aMethod, "_classReferences", []), "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(each, "_asJavascript", [])]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["]"]);return smalltalk.send($rec, "_nextPutAll_", ["})"]);})(self['@stream']);
+return self;},
+args: ["aMethod", "aBlock"],
+source: "nextPutMethodDeclaration: aMethod with: aBlock\x0a\x09stream \x0a\x09\x09nextPutAll: 'smalltalk.method({'; lf;\x0a\x09\x09nextPutAll: 'selector: \x22', aMethod selector, '\x22,'; lf;\x0a\x09\x09nextPutAll: 'source: ', aMethod source asJavascript, ',';lf.\x0a\x09aBlock value.\x0a\x09stream \x0a\x09\x09nextPutAll: ',', String lf, 'messageSends: ';\x0a\x09\x09nextPutAll: aMethod messageSends asArray asJavascript, ','; lf;\x0a          \x09nextPutAll: 'args: ', (aMethod arguments collect: [ :each | each value ]) asArray asJavascript, ','; lf;\x0a\x09\x09nextPutAll: 'referencedClasses: ['.\x0a\x09aMethod classReferences \x0a\x09\x09do: [:each | stream nextPutAll: each asJavascript]\x0a\x09\x09separatedBy: [stream nextPutAll: ','].\x0a\x09stream \x0a\x09\x09nextPutAll: ']';\x0a\x09\x09nextPutAll: '})'",
+messageSends: ["nextPutAll:", "lf", ",", "selector", "asJavascript", "source", "value", "asArray", "messageSends", "collect:", "arguments", "do:separatedBy:", "classReferences"],
+referencedClasses: ["String"]
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutNonLocalReturnHandlingWith_",
+smalltalk.method({
+selector: "nextPutNonLocalReturnHandlingWith:",
+category: 'streaming',
+fn: function (aBlock) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["var $early={};"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", ["try {"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["}"]);smalltalk.send($rec, "_lf", []);smalltalk.send($rec, "_nextPutAll_", ["catch(e) {if(e===$early)return e[0]; throw e}"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;},
+args: ["aBlock"],
+source: "nextPutNonLocalReturnHandlingWith: aBlock\x0a\x09stream \x0a\x09\x09nextPutAll: 'var $early={};'; lf;\x0a\x09\x09nextPutAll: 'try {'; lf.\x0a\x09aBlock value.\x0a\x09stream \x0a\x09\x09nextPutAll: '}'; lf;\x0a\x09\x09nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf",
+messageSends: ["nextPutAll:", "lf", "value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutNonLocalReturnWith_",
+smalltalk.method({
+selector: "nextPutNonLocalReturnWith:",
+category: 'streaming',
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["(function(){throw $early=["]);
+smalltalk.send(aBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["]})()"]);
+return self;},
+args: ["aBlock"],
+source: "nextPutNonLocalReturnWith: aBlock\x0a\x09stream nextPutAll: '(function(){throw $early=['.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: ']})()'",
+messageSends: ["nextPutAll:", "value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutReturnWith_",
+smalltalk.method({
+selector: "nextPutReturnWith:",
+category: 'streaming',
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["$return="]);
+smalltalk.send(aBlock, "_value", []);
+return self;},
+args: ["aBlock"],
+source: "nextPutReturnWith: aBlock\x0a\x09stream nextPutAll: '$return='.\x0a\x09aBlock value",
+messageSends: ["nextPutAll:", "value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutSendTo_selector_arguments_",
+smalltalk.method({
+selector: "nextPutSendTo:selector:arguments:",
+category: 'streaming',
+fn: function (receiver, selector, arguments) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["smalltalk.send("]);
+smalltalk.send(receiver, "_emitOn_", [self]);
+smalltalk.send(self['@stream'], "_nextPutAll_", [smalltalk.send(smalltalk.send(",\x22", "__comma", [smalltalk.send(selector, "_asSelector", [])]), "__comma", ["\x22,["])]);
+smalltalk.send(arguments, "_do_separatedBy_", [(function(each){return smalltalk.send(each, "_emitOn_", [self]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["])"]);
+return self;},
+args: ["receiver", "selector", "arguments"],
+source: "nextPutSendTo: receiver selector: selector arguments: arguments\x0a\x09stream nextPutAll: 'smalltalk.send('.\x0a\x09receiver emitOn: self. \x0a\x09stream nextPutAll: ',\x22', selector asSelector, '\x22,['.\x0a\x09arguments \x0a\x09\x09do: [ :each | each emitOn: self ]\x0a\x09\x09separatedBy: [ stream nextPutAll: ',' ].\x0a\x09stream nextPutAll: '])'",
+messageSends: ["nextPutAll:", "emitOn:", ",", "asSelector", "do:separatedBy:"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutSequenceWith_",
+smalltalk.method({
+selector: "nextPutSequenceWith:",
+category: 'streaming',
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value", []);
+return self;},
+args: ["aBlock"],
+source: "nextPutSequenceWith: aBlock\x0a\x09\x22stream \x0a\x09\x09nextPutAll: 'switch(smalltalk.thisContext.pc){'; lf.\x22\x0a\x09aBlock value.\x0a\x09\x22stream \x0a\x09\x09nextPutAll: '};'; lf\x22",
+messageSends: ["value"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutStatement_with_",
+smalltalk.method({
+selector: "nextPutStatement:with:",
+category: 'streaming',
+fn: function (anInteger, aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [";"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;},
+args: ["anInteger", "aBlock"],
+source: "nextPutStatement: anInteger with: aBlock\x0a\x09\x22stream \x0a\x09\x09nextPutAll: 'case ', anInteger asString, ':'; lf.\x22\x0a\x09aBlock value.\x0a\x09stream \x0a\x09\x09nextPutAll: ';'; lf\x22;\x0a\x09\x09nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf\x22",
+messageSends: ["value", "nextPutAll:", "lf"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutVar_",
+smalltalk.method({
+selector: "nextPutVar:",
+category: 'streaming',
+fn: function (aString) {
+var self=this;
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send("var ", "__comma", [aString]), "__comma", [";"])]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;},
+args: ["aString"],
+source: "nextPutVar: aString\x0a\x09stream nextPutAll: 'var ', aString, ';'; lf",
+messageSends: ["nextPutAll:", ",", "lf"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+smalltalk.addMethod(
+"_nextPutVars_",
+smalltalk.method({
+selector: "nextPutVars:",
+category: 'streaming',
+fn: function (aCollection) {
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["var "]);
+smalltalk.send(aCollection, "_do_separatedBy_", [(function(each){return smalltalk.send(self['@stream'], "_nextPutAll_", [each]);}), (function(){return smalltalk.send(self['@stream'], "_nextPutAll_", [","]);})]);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", [";"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+return self;},
+args: ["aCollection"],
+source: "nextPutVars: aCollection\x0a\x09stream nextPutAll: 'var '.\x0a\x09aCollection \x0a\x09\x09do: [ :each | stream nextPutAll: each ]\x0a\x09\x09separatedBy: [ stream nextPutAll: ',' ].\x0a\x09stream nextPutAll: ';'; lf",
+messageSends: ["nextPutAll:", "do:separatedBy:", "lf"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
+
+
 smalltalk.addMethod(
 "_appendToInstruction_",
 smalltalk.method({

+ 72 - 80
js/Compiler-Semantic.deploy.js

@@ -1,5 +1,30 @@
 smalltalk.addPackage('Compiler-Semantic', {});
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;}
+}),
+smalltalk.InvalidAssignmentError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;}
+}),
+smalltalk.InvalidAssignmentError);
+
+
+
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
 smalltalk.addMethod(
 "_addArg_",
 smalltalk.method({
@@ -93,6 +118,28 @@ return self;}
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_node",
+smalltalk.method({
+selector: "node",
+fn: function () {
+var self=this;
+return self['@node'];
+return self;}
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_node_",
+smalltalk.method({
+selector: "node:",
+fn: function (aNode) {
+var self=this;
+(self['@node']=aNode);
+return self;}
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_outerScope",
 smalltalk.method({
@@ -115,6 +162,17 @@ return self;}
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_scopeLevel",
+smalltalk.method({
+selector: "scopeLevel",
+fn: function () {
+var self=this;
+return ((($receiver = (($receiver = smalltalk.send(self, "_outerScope", [])) == nil || $receiver == undefined) ? (function(){return (0);})() : (function(){return smalltalk.send(smalltalk.send(self, "_outerScope", []), "_scopeLevel", []);})()).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)]));
+return self;}
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_temps",
 smalltalk.method({
@@ -635,6 +693,18 @@ return self;}
 }),
 smalltalk.SemanticAnalyzer);
 
+smalltalk.addMethod(
+"_visitCascadeNode_",
+smalltalk.method({
+selector: "visitCascadeNode:",
+fn: function (aNode) {
+var self=this;
+smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_receiver_", [smalltalk.send(aNode, "_receiver", [])]);})]);
+smalltalk.send(self, "_visitCascadeNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
+return self;}
+}),
+smalltalk.SemanticAnalyzer);
+
 smalltalk.addMethod(
 "_visitClassReferenceNode_",
 smalltalk.method({
@@ -684,7 +754,7 @@ selector: "visitSendNode:",
 fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);
-smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_beUsed", []);
+(($receiver = smalltalk.send(aNode, "_receiver", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_beUsed", []);})() : nil;
 smalltalk.send(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
@@ -727,81 +797,3 @@ return self;}
 smalltalk.SemanticAnalyzer.klass);
 
 
-smalltalk.addClass('SemanticError', smalltalk.Error, [], 'Compiler-Semantic');
-
-
-smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;}
-}),
-smalltalk.InvalidAssignmentError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;}
-}),
-smalltalk.InvalidAssignmentError);
-
-
-
-smalltalk.addClass('ShadowingVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;}
-}),
-smalltalk.ShadowingVariableError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;}
-}),
-smalltalk.ShadowingVariableError);
-
-
-
-smalltalk.addClass('UnknownVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;}
-}),
-smalltalk.UnknownVariableError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;}
-}),
-smalltalk.UnknownVariableError);
-
-
-

+ 106 - 116
js/Compiler-Semantic.js

@@ -1,5 +1,41 @@
 smalltalk.addPackage('Compiler-Semantic', {});
-smalltalk.addClass('LexicalScope', smalltalk.Object, ['temps', 'args', 'outerScope'], 'Compiler-Semantic');
+smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
+smalltalk.InvalidAssignmentError.comment="I get signaled when a pseudo variable gets assigned."
+smalltalk.addMethod(
+"_variableName",
+smalltalk.method({
+selector: "variableName",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@variableName'];
+return self;},
+args: [],
+source: "variableName\x0a\x09^ variableName",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.InvalidAssignmentError);
+
+smalltalk.addMethod(
+"_variableName_",
+smalltalk.method({
+selector: "variableName:",
+category: 'accessing',
+fn: function (aString) {
+var self=this;
+(self['@variableName']=aString);
+return self;},
+args: ["aString"],
+source: "variableName: aString\x0a\x09variableName := aString",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.InvalidAssignmentError);
+
+
+
+smalltalk.addClass('LexicalScope', smalltalk.Object, ['node', 'temps', 'args', 'outerScope'], 'Compiler-Semantic');
 smalltalk.LexicalScope.comment="I represent a lexical scope where variable names are associated with ScopeVars\x0aInstances are used for block scopes. Method scopes are instances of MethodLexicalScope.\x0a\x0aI am attached to a ScopeVar and method/block nodes.\x0aEach context (method/closure) get a fresh scope that inherits from its outer scope."
 smalltalk.addMethod(
 "_addArg_",
@@ -134,6 +170,38 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_node",
+smalltalk.method({
+selector: "node",
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@node'];
+return self;},
+args: [],
+source: "node\x0a\x09\x22Answer the node in which I am defined\x22\x0a\x09\x0a\x09^ node",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
+smalltalk.addMethod(
+"_node_",
+smalltalk.method({
+selector: "node:",
+category: 'accessing',
+fn: function (aNode) {
+var self=this;
+(self['@node']=aNode);
+return self;},
+args: ["aNode"],
+source: "node: aNode\x0a\x09node := aNode",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_outerScope",
 smalltalk.method({
@@ -166,6 +234,22 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_scopeLevel",
+smalltalk.method({
+selector: "scopeLevel",
+category: 'accessing',
+fn: function () {
+var self=this;
+return ((($receiver = (($receiver = smalltalk.send(self, "_outerScope", [])) == nil || $receiver == undefined) ? (function(){return (0);})() : (function(){return smalltalk.send(smalltalk.send(self, "_outerScope", []), "_scopeLevel", []);})()).klass === smalltalk.Number) ? $receiver +(1) : smalltalk.send($receiver, "__plus", [(1)]));
+return self;},
+args: [],
+source: "scopeLevel\x0a\x09^ (self outerScope \x0a\x09\x09ifNil: [ 0 ]\x0a\x09\x09ifNotNil: [ self outerScope scopeLevel ]) + 1",
+messageSends: ["+", "ifNil:ifNotNil:", "outerScope", "scopeLevel"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_temps",
 smalltalk.method({
@@ -538,6 +622,7 @@ smalltalk.ArgVar);
 
 
 smalltalk.addClass('ClassRefVar', smalltalk.ScopeVar, [], 'Compiler-Semantic');
+smalltalk.ClassRefVar.comment="I am an class reference variable"
 smalltalk.addMethod(
 "_alias",
 smalltalk.method({
@@ -914,6 +999,23 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
 
+smalltalk.addMethod(
+"_visitCascadeNode_",
+smalltalk.method({
+selector: "visitCascadeNode:",
+category: 'visiting',
+fn: function (aNode) {
+var self=this;
+smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_receiver_", [smalltalk.send(aNode, "_receiver", [])]);})]);
+smalltalk.send(self, "_visitCascadeNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
+return self;},
+args: ["aNode"],
+source: "visitCascadeNode: aNode\x0a\x09\x22Populate the receiver into all children\x22\x0a\x09aNode nodes do: [ :each | each receiver: aNode receiver ].\x0a\x09super visitCascadeNode: aNode",
+messageSends: ["do:", "nodes", "receiver:", "receiver", "visitCascadeNode:"],
+referencedClasses: []
+}),
+smalltalk.SemanticAnalyzer);
+
 smalltalk.addMethod(
 "_visitClassReferenceNode_",
 smalltalk.method({
@@ -979,13 +1081,13 @@ category: 'visiting',
 fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);
-smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_beUsed", []);
+(($receiver = smalltalk.send(aNode, "_receiver", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_beUsed", []);})() : nil;
 smalltalk.send(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09self messageSends add: aNode selector.\x0a\x09aNode receiver beUsed.\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09each beUsed ].\x0a\x09super visitSendNode: aNode",
-messageSends: ["add:", "messageSends", "selector", "beUsed", "receiver", "do:", "arguments", "visitSendNode:"],
+source: "visitSendNode: aNode\x0a\x09self messageSends add: aNode selector.\x0a\x09aNode receiver ifNotNil: [\x0a\x09\x09aNode receiver beUsed ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09each beUsed ].\x0a\x09super visitSendNode: aNode",
+messageSends: ["add:", "messageSends", "selector", "ifNotNil:", "receiver", "beUsed", "do:", "arguments", "visitSendNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1041,115 +1143,3 @@ referencedClasses: []
 smalltalk.SemanticAnalyzer.klass);
 
 
-smalltalk.addClass('SemanticError', smalltalk.Error, [], 'Compiler-Semantic');
-smalltalk.SemanticError.comment="I represent an abstract semantic error thrown by the SemanticAnalyzer.\x0aSemantic errors can be unknown variable errors, etc.\x0aSee my subclasses for concrete errors.\x0a\x0aThe IDE should catch instances of Semantic error to deal with them when compiling"
-
-
-smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.InvalidAssignmentError.comment="I get signaled when a pseudo variable gets assigned."
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;},
-args: [],
-source: "variableName\x0a\x09^ variableName",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.InvalidAssignmentError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-category: 'accessing',
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;},
-args: ["aString"],
-source: "variableName: aString\x0a\x09variableName := aString",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.InvalidAssignmentError);
-
-
-
-smalltalk.addClass('ShadowingVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.ShadowingVariableError.comment="I get signaled when a variable in a block or method scope shadows a variable of the same name in an outer scope."
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;},
-args: [],
-source: "variableName\x0a\x09^ variableName",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.ShadowingVariableError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-category: 'accessing',
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;},
-args: ["aString"],
-source: "variableName: aString\x0a\x09variableName := aString",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.ShadowingVariableError);
-
-
-
-smalltalk.addClass('UnknownVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Semantic');
-smalltalk.UnknownVariableError.comment="I get signaled when a variable is not defined.\x0aThe default behavior is to allow it, as this is how Amber currently is able to seamlessly send messages to JavaScript objects."
-smalltalk.addMethod(
-"_variableName",
-smalltalk.method({
-selector: "variableName",
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@variableName'];
-return self;},
-args: [],
-source: "variableName\x0a\x09^ variableName",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.UnknownVariableError);
-
-smalltalk.addMethod(
-"_variableName_",
-smalltalk.method({
-selector: "variableName:",
-category: 'accessing',
-fn: function (aString) {
-var self=this;
-(self['@variableName']=aString);
-return self;},
-args: ["aString"],
-source: "variableName: aString\x0a\x09variableName := aString",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.UnknownVariableError);
-
-
-

+ 17 - 0
js/Compiler-Tests.deploy.js

@@ -90,6 +90,23 @@ return self;}
 }),
 smalltalk.SemanticAnalyzerTest);
 
+smalltalk.addMethod(
+"_testScopeLevel",
+smalltalk.method({
+selector: "testScopeLevel",
+fn: function () {
+var self=this;
+var src=nil;
+var ast=nil;
+(src="foo | a | a + 1. [ [ | b | b := a ] ]");
+(ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
+smalltalk.send(self['@analyzer'], "_visit_", [ast]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send(ast, "_scope", []), "_scopeLevel", []), "__eq", [(1)])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(ast, "_nodes", []), "_first", []), "_nodes", []), "_last", []), "_nodes", []), "_first", []), "_nodes", []), "_first", []), "_scope", []), "_scopeLevel", []), "__eq", [(3)])]);
+return self;}
+}),
+smalltalk.SemanticAnalyzerTest);
+
 smalltalk.addMethod(
 "_testUnknownVariables",
 smalltalk.method({

+ 22 - 0
js/Compiler-Tests.js

@@ -120,6 +120,28 @@ referencedClasses: []
 }),
 smalltalk.SemanticAnalyzerTest);
 
+smalltalk.addMethod(
+"_testScopeLevel",
+smalltalk.method({
+selector: "testScopeLevel",
+category: 'tests',
+fn: function () {
+var self=this;
+var src=nil;
+var ast=nil;
+(src="foo | a | a + 1. [ [ | b | b := a ] ]");
+(ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
+smalltalk.send(self['@analyzer'], "_visit_", [ast]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send(ast, "_scope", []), "_scopeLevel", []), "__eq", [(1)])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(ast, "_nodes", []), "_first", []), "_nodes", []), "_last", []), "_nodes", []), "_first", []), "_nodes", []), "_first", []), "_scope", []), "_scopeLevel", []), "__eq", [(3)])]);
+return self;},
+args: [],
+source: "testScopeLevel\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self assert: ast scope scopeLevel = 1.\x0a\x09self assert: ast nodes first nodes last nodes first nodes first scope scopeLevel = 3",
+messageSends: ["parse:", "visit:", "assert:", "=", "scopeLevel", "scope", "first", "nodes", "last"],
+referencedClasses: []
+}),
+smalltalk.SemanticAnalyzerTest);
+
 smalltalk.addMethod(
 "_testUnknownVariables",
 smalltalk.method({

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 196
js/Compiler-Visitors.deploy.js


La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 272
js/Compiler-Visitors.js


+ 73 - 23
js/Kernel-Exceptions.deploy.js

@@ -4,7 +4,7 @@ smalltalk.addMethod(
 "_context",
 smalltalk.method({
 selector: "context",
-fn: function (){
+fn: function () {
 var self=this;
 return self.context;
 return self;}
@@ -15,7 +15,7 @@ smalltalk.addMethod(
 "_isSmalltalkError",
 smalltalk.method({
 selector: "isSmalltalkError",
-fn: function (){
+fn: function () {
 var self=this;
 return self.smalltalkError === true;
 return self;}
@@ -26,7 +26,7 @@ smalltalk.addMethod(
 "_jsStack",
 smalltalk.method({
 selector: "jsStack",
-fn: function (){
+fn: function () {
 var self=this;
 return self.stack;
 return self;}
@@ -37,7 +37,7 @@ smalltalk.addMethod(
 "_messageText",
 smalltalk.method({
 selector: "messageText",
-fn: function (){
+fn: function () {
 var self=this;
 return self['@messageText'];
 return self;}
@@ -48,7 +48,7 @@ smalltalk.addMethod(
 "_messageText_",
 smalltalk.method({
 selector: "messageText:",
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 (self['@messageText']=aString);
 return self;}
@@ -59,7 +59,7 @@ smalltalk.addMethod(
 "_signal",
 smalltalk.method({
 selector: "signal",
-fn: function (){
+fn: function () {
 var self=this;
 self.context = smalltalk.getThisContext(); self.smalltalkError = true; throw(self);
 return self;}
@@ -70,7 +70,7 @@ smalltalk.addMethod(
 "_signal_",
 smalltalk.method({
 selector: "signal:",
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send(self, "_messageText_", [aString]);
 smalltalk.send(self, "_signal", []);
@@ -83,7 +83,7 @@ smalltalk.addMethod(
 "_signal",
 smalltalk.method({
 selector: "signal",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_new", []), "_signal", []);
 return self;}
@@ -94,7 +94,7 @@ smalltalk.addMethod(
 "_signal_",
 smalltalk.method({
 selector: "signal:",
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_new", []), "_signal_", [aString]);
 return self;}
@@ -102,12 +102,62 @@ return self;}
 smalltalk.Error.klass);
 
 
+smalltalk.addClass('Continuation', smalltalk.Error, ['context'], 'Kernel-Exceptions');
+smalltalk.addMethod(
+"_initializeFromContext_",
+smalltalk.method({
+selector: "initializeFromContext:",
+fn: function (aContext) {
+var self=this;
+smalltalk.send(self, "_initialize", [], smalltalk.Continuation.superclass || nil);
+(self['@context']=aContext);
+smalltalk.send(self, "_basicAt_put_", ["cc", true]);
+return self;}
+}),
+smalltalk.Continuation);
+
+smalltalk.addMethod(
+"_restore",
+smalltalk.method({
+selector: "restore",
+fn: function () {
+var self=this;
+smalltalk.send(self['@context'], "_resume", []);
+return self;}
+}),
+smalltalk.Continuation);
+
+smalltalk.addMethod(
+"_value_",
+smalltalk.method({
+selector: "value:",
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value_", [self]);
+smalltalk.send(self, "_signal", []);
+return self;}
+}),
+smalltalk.Continuation);
+
+
+smalltalk.addMethod(
+"_currentDo_",
+smalltalk.method({
+selector: "currentDo:",
+fn: function (aBlock) {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_initializeWithContext_", [smalltalk.send((smalltalk.getThisContext()), "_home", [])]);return smalltalk.send($rec, "_value_", [aBlock]);})(smalltalk.send(self, "_new", []));
+return self;}
+}),
+smalltalk.Continuation.klass);
+
+
 smalltalk.addClass('MessageNotUnderstood', smalltalk.Error, ['message', 'receiver'], 'Kernel-Exceptions');
 smalltalk.addMethod(
 "_message",
 smalltalk.method({
 selector: "message",
-fn: function (){
+fn: function () {
 var self=this;
 return self['@message'];
 return self;}
@@ -118,7 +168,7 @@ smalltalk.addMethod(
 "_message_",
 smalltalk.method({
 selector: "message:",
-fn: function (aMessage){
+fn: function (aMessage) {
 var self=this;
 (self['@message']=aMessage);
 return self;}
@@ -129,7 +179,7 @@ smalltalk.addMethod(
 "_messageText",
 smalltalk.method({
 selector: "messageText",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_receiver", []), "_asString", []), "__comma", [" does not understand #"]), "__comma", [smalltalk.send(smalltalk.send(self, "_message", []), "_selector", [])]);
 return self;}
@@ -140,7 +190,7 @@ smalltalk.addMethod(
 "_receiver",
 smalltalk.method({
 selector: "receiver",
-fn: function (){
+fn: function () {
 var self=this;
 return self['@receiver'];
 return self;}
@@ -151,7 +201,7 @@ smalltalk.addMethod(
 "_receiver_",
 smalltalk.method({
 selector: "receiver:",
-fn: function (anObject){
+fn: function (anObject) {
 var self=this;
 (self['@receiver']=anObject);
 return self;}
@@ -165,7 +215,7 @@ smalltalk.addMethod(
 "_handleError_",
 smalltalk.method({
 selector: "handleError:",
-fn: function (anError){
+fn: function (anError) {
 var self=this;
 (($receiver = smalltalk.send(anError, "_context", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logErrorContext_", [smalltalk.send(anError, "_context", [])]);})() : nil;
 smalltalk.send(self, "_logError_", [anError]);
@@ -177,7 +227,7 @@ smalltalk.addMethod(
 "_log_",
 smalltalk.method({
 selector: "log:",
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [aString]);
 return self;}
@@ -188,7 +238,7 @@ smalltalk.addMethod(
 "_logContext_",
 smalltalk.method({
 selector: "logContext:",
-fn: function (aContext){
+fn: function (aContext) {
 var self=this;
 (($receiver = smalltalk.send(aContext, "_home", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logContext_", [smalltalk.send(aContext, "_home", [])]);})() : nil;
 smalltalk.send(self, "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aContext, "_receiver", []), "_asString", []), "__comma", [">>"]), "__comma", [smalltalk.send(aContext, "_selector", [])])]);
@@ -200,7 +250,7 @@ smalltalk.addMethod(
 "_logError_",
 smalltalk.method({
 selector: "logError:",
-fn: function (anError){
+fn: function (anError) {
 var self=this;
 smalltalk.send(self, "_log_", [smalltalk.send(anError, "_messageText", [])]);
 return self;}
@@ -211,7 +261,7 @@ smalltalk.addMethod(
 "_logErrorContext_",
 smalltalk.method({
 selector: "logErrorContext:",
-fn: function (aContext){
+fn: function (aContext) {
 var self=this;
 (($receiver = aContext) != nil && $receiver != undefined) ? (function(){return (($receiver = smalltalk.send(aContext, "_home", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logContext_", [smalltalk.send(aContext, "_home", [])]);})() : nil;})() : nil;
 return self;}
@@ -224,7 +274,7 @@ smalltalk.addMethod(
 "_current",
 smalltalk.method({
 selector: "current",
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@current']) == nil || $receiver == undefined) ? (function(){return (self['@current']=smalltalk.send(self, "_new", []));})() : $receiver;
 return self;}
@@ -235,7 +285,7 @@ smalltalk.addMethod(
 "_initialize",
 smalltalk.method({
 selector: "initialize",
-fn: function (){
+fn: function () {
 var self=this;
 smalltalk.send(self, "_register", []);
 return self;}
@@ -246,7 +296,7 @@ smalltalk.addMethod(
 "_register",
 smalltalk.method({
 selector: "register",
-fn: function (){
+fn: function () {
 var self=this;
 smalltalk.send((smalltalk.ErrorHandler || ErrorHandler), "_setCurrent_", [smalltalk.send(self, "_new", [])]);
 return self;}
@@ -257,7 +307,7 @@ smalltalk.addMethod(
 "_setCurrent_",
 smalltalk.method({
 selector: "setCurrent:",
-fn: function (anHandler){
+fn: function (anHandler) {
 var self=this;
 (self['@current']=anHandler);
 return self;}

+ 93 - 23
js/Kernel-Exceptions.js

@@ -5,7 +5,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "context",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self.context;
 return self;},
@@ -21,7 +21,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "isSmalltalkError",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return self.smalltalkError === true;
 return self;},
@@ -37,7 +37,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "jsStack",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self.stack;
 return self;},
@@ -53,7 +53,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "messageText",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self['@messageText'];
 return self;},
@@ -69,7 +69,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "messageText:",
 category: 'accessing',
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 (self['@messageText']=aString);
 return self;},
@@ -85,7 +85,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "signal",
 category: 'signaling',
-fn: function (){
+fn: function () {
 var self=this;
 self.context = smalltalk.getThisContext(); self.smalltalkError = true; throw(self);
 return self;},
@@ -101,7 +101,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "signal:",
 category: 'signaling',
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send(self, "_messageText_", [aString]);
 smalltalk.send(self, "_signal", []);
@@ -119,7 +119,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "signal",
 category: 'instance creation',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_new", []), "_signal", []);
 return self;},
@@ -135,7 +135,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "signal:",
 category: 'instance creation',
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 return smalltalk.send(smalltalk.send(self, "_new", []), "_signal_", [aString]);
 return self;},
@@ -147,13 +147,83 @@ referencedClasses: []
 smalltalk.Error.klass);
 
 
+smalltalk.addClass('Continuation', smalltalk.Error, ['context'], 'Kernel-Exceptions');
+smalltalk.addMethod(
+"_initializeFromContext_",
+smalltalk.method({
+selector: "initializeFromContext:",
+category: 'initialization',
+fn: function (aContext) {
+var self=this;
+smalltalk.send(self, "_initialize", [], smalltalk.Continuation.superclass || nil);
+(self['@context']=aContext);
+smalltalk.send(self, "_basicAt_put_", ["cc", true]);
+return self;},
+args: ["aContext"],
+source: "initializeFromContext: aContext\x0a\x09\x22Add a cc flag to the error object so Smalltalk knows how to handle it\x22\x0a\x0a\x09super initialize.\x0a\x09context := aContext.\x0a\x09self basicAt: 'cc' put: true",
+messageSends: ["initialize", "basicAt:put:"],
+referencedClasses: []
+}),
+smalltalk.Continuation);
+
+smalltalk.addMethod(
+"_restore",
+smalltalk.method({
+selector: "restore",
+category: 'initialization',
+fn: function () {
+var self=this;
+smalltalk.send(self['@context'], "_resume", []);
+return self;},
+args: [],
+source: "restore\x0a\x09context resume",
+messageSends: ["resume"],
+referencedClasses: []
+}),
+smalltalk.Continuation);
+
+smalltalk.addMethod(
+"_value_",
+smalltalk.method({
+selector: "value:",
+category: 'initialization',
+fn: function (aBlock) {
+var self=this;
+smalltalk.send(aBlock, "_value_", [self]);
+smalltalk.send(self, "_signal", []);
+return self;},
+args: ["aBlock"],
+source: "value: aBlock\x0a\x09aBlock value: self.\x0a\x09self signal",
+messageSends: ["value:", "signal"],
+referencedClasses: []
+}),
+smalltalk.Continuation);
+
+
+smalltalk.addMethod(
+"_currentDo_",
+smalltalk.method({
+selector: "currentDo:",
+category: 'instance creation',
+fn: function (aBlock) {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_initializeWithContext_", [smalltalk.send((smalltalk.getThisContext()), "_home", [])]);return smalltalk.send($rec, "_value_", [aBlock]);})(smalltalk.send(self, "_new", []));
+return self;},
+args: ["aBlock"],
+source: "currentDo: aBlock\x0a\x09^ self new \x0a\x09\x09initializeWithContext: thisContext home;\x0a\x09\x09value: aBlock",
+messageSends: ["initializeWithContext:", "home", "value:", "new"],
+referencedClasses: []
+}),
+smalltalk.Continuation.klass);
+
+
 smalltalk.addClass('MessageNotUnderstood', smalltalk.Error, ['message', 'receiver'], 'Kernel-Exceptions');
 smalltalk.addMethod(
 "_message",
 smalltalk.method({
 selector: "message",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self['@message'];
 return self;},
@@ -169,7 +239,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "message:",
 category: 'accessing',
-fn: function (aMessage){
+fn: function (aMessage) {
 var self=this;
 (self['@message']=aMessage);
 return self;},
@@ -185,7 +255,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "messageText",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_receiver", []), "_asString", []), "__comma", [" does not understand #"]), "__comma", [smalltalk.send(smalltalk.send(self, "_message", []), "_selector", [])]);
 return self;},
@@ -201,7 +271,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "receiver",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return self['@receiver'];
 return self;},
@@ -217,7 +287,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "receiver:",
 category: 'accessing',
-fn: function (anObject){
+fn: function (anObject) {
 var self=this;
 (self['@receiver']=anObject);
 return self;},
@@ -236,7 +306,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "handleError:",
 category: 'error handling',
-fn: function (anError){
+fn: function (anError) {
 var self=this;
 (($receiver = smalltalk.send(anError, "_context", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logErrorContext_", [smalltalk.send(anError, "_context", [])]);})() : nil;
 smalltalk.send(self, "_logError_", [anError]);
@@ -253,7 +323,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "log:",
 category: 'private',
-fn: function (aString){
+fn: function (aString) {
 var self=this;
 smalltalk.send((typeof console == 'undefined' ? nil : console), "_log_", [aString]);
 return self;},
@@ -269,7 +339,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "logContext:",
 category: 'private',
-fn: function (aContext){
+fn: function (aContext) {
 var self=this;
 (($receiver = smalltalk.send(aContext, "_home", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logContext_", [smalltalk.send(aContext, "_home", [])]);})() : nil;
 smalltalk.send(self, "_log_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(aContext, "_receiver", []), "_asString", []), "__comma", [">>"]), "__comma", [smalltalk.send(aContext, "_selector", [])])]);
@@ -286,7 +356,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "logError:",
 category: 'private',
-fn: function (anError){
+fn: function (anError) {
 var self=this;
 smalltalk.send(self, "_log_", [smalltalk.send(anError, "_messageText", [])]);
 return self;},
@@ -302,7 +372,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "logErrorContext:",
 category: 'private',
-fn: function (aContext){
+fn: function (aContext) {
 var self=this;
 (($receiver = aContext) != nil && $receiver != undefined) ? (function(){return (($receiver = smalltalk.send(aContext, "_home", [])) != nil && $receiver != undefined) ? (function(){return smalltalk.send(self, "_logContext_", [smalltalk.send(aContext, "_home", [])]);})() : nil;})() : nil;
 return self;},
@@ -320,7 +390,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "current",
 category: 'accessing',
-fn: function (){
+fn: function () {
 var self=this;
 return (($receiver = self['@current']) == nil || $receiver == undefined) ? (function(){return (self['@current']=smalltalk.send(self, "_new", []));})() : $receiver;
 return self;},
@@ -336,7 +406,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "initialize",
 category: 'initialization',
-fn: function (){
+fn: function () {
 var self=this;
 smalltalk.send(self, "_register", []);
 return self;},
@@ -352,7 +422,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "register",
 category: 'initialization',
-fn: function (){
+fn: function () {
 var self=this;
 smalltalk.send((smalltalk.ErrorHandler || ErrorHandler), "_setCurrent_", [smalltalk.send(self, "_new", [])]);
 return self;},
@@ -368,7 +438,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "setCurrent:",
 category: 'accessing',
-fn: function (anHandler){
+fn: function (anHandler) {
 var self=this;
 (self['@current']=anHandler);
 return self;},

+ 1 - 1
js/Kernel-Objects.deploy.js

@@ -2587,7 +2587,7 @@ row = anException.line;
 (badLine=smalltalk.send(smalltalk.send(smalltalk.send(badLine, "_copyFrom_to_", [(1), ((($receiver = col).klass === smalltalk.Number) ? $receiver -(1) : smalltalk.send($receiver, "__minus", [(1)]))]), "__comma", [" ===>"]), "__comma", [smalltalk.send(badLine, "_copyFrom_to_", [col, smalltalk.send(badLine, "_size", [])])]));
 smalltalk.send(lines, "_at_put_", [row, badLine]);
 (code=smalltalk.send((smalltalk.String || String), "_streamContents_", [(function(s){return smalltalk.send(lines, "_withIndexDo_", [(function(l, i){return smalltalk.send(s, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(i, "_asString", []), "__comma", [": "]), "__comma", [l]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])])]);})]);})]));
-return smalltalk.send(smalltalk.send((smalltalk.Error || Error), "_new", []), "_messageText_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("Parse error on line ", "__comma", [row]), "__comma", [" column "]), "__comma", [col]), "__comma", [" : "]), "__comma", [message]), "__comma", [" Below is code with line numbers and ===> marker inserted:"]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", [code])]);
+return smalltalk.send(smalltalk.send((smalltalk.ParseError || ParseError), "_new", []), "_messageText_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("Parse error on line ", "__comma", [row]), "__comma", [" column "]), "__comma", [col]), "__comma", [" : "]), "__comma", [message]), "__comma", [" Below is code with line numbers and ===> marker inserted:"]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", [code])]);
 return self;}
 }),
 smalltalk.Smalltalk);

+ 3 - 3
js/Kernel-Objects.js

@@ -3692,12 +3692,12 @@ row = anException.line;
 (badLine=smalltalk.send(smalltalk.send(smalltalk.send(badLine, "_copyFrom_to_", [(1), ((($receiver = col).klass === smalltalk.Number) ? $receiver -(1) : smalltalk.send($receiver, "__minus", [(1)]))]), "__comma", [" ===>"]), "__comma", [smalltalk.send(badLine, "_copyFrom_to_", [col, smalltalk.send(badLine, "_size", [])])]));
 smalltalk.send(lines, "_at_put_", [row, badLine]);
 (code=smalltalk.send((smalltalk.String || String), "_streamContents_", [(function(s){return smalltalk.send(lines, "_withIndexDo_", [(function(l, i){return smalltalk.send(s, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(i, "_asString", []), "__comma", [": "]), "__comma", [l]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])])]);})]);})]));
-return smalltalk.send(smalltalk.send((smalltalk.Error || Error), "_new", []), "_messageText_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("Parse error on line ", "__comma", [row]), "__comma", [" column "]), "__comma", [col]), "__comma", [" : "]), "__comma", [message]), "__comma", [" Below is code with line numbers and ===> marker inserted:"]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", [code])]);
+return smalltalk.send(smalltalk.send((smalltalk.ParseError || ParseError), "_new", []), "_messageText_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send("Parse error on line ", "__comma", [row]), "__comma", [" column "]), "__comma", [col]), "__comma", [" : "]), "__comma", [message]), "__comma", [" Below is code with line numbers and ===> marker inserted:"]), "__comma", [smalltalk.send((smalltalk.String || String), "_lf", [])]), "__comma", [code])]);
 return self;},
 args: ["anException", "aString"],
-source: "parseError: anException parsing: aString\x0a\x09| row col message lines badLine code |\x0a\x09<row = anException.line;\x0a\x09col = anException.column;\x0a\x09message = anException.message;>.\x0a\x09lines := aString lines.\x0a\x09badLine := lines at: row.\x0a\x09badLine := (badLine copyFrom: 1 to: col - 1), ' ===>', (badLine copyFrom:  col to: badLine size).\x0a\x09lines at: row put: badLine.\x0a\x09code := String streamContents: [:s |\x0a                  lines withIndexDo: [:l :i |\x0a                     s nextPutAll: i asString, ': ', l, String lf]].\x0a\x09^ Error new messageText: ('Parse error on line ' , row , ' column ' , col , ' : ' , message , ' Below is code with line numbers and ===> marker inserted:' , String lf, code)",
+source: "parseError: anException parsing: aString\x0a\x09| row col message lines badLine code |\x0a\x09<row = anException.line;\x0a\x09col = anException.column;\x0a\x09message = anException.message;>.\x0a\x09lines := aString lines.\x0a\x09badLine := lines at: row.\x0a\x09badLine := (badLine copyFrom: 1 to: col - 1), ' ===>', (badLine copyFrom:  col to: badLine size).\x0a\x09lines at: row put: badLine.\x0a\x09code := String streamContents: [:s |\x0a                  lines withIndexDo: [:l :i |\x0a                     s nextPutAll: i asString, ': ', l, String lf]].\x0a\x09^ ParseError new messageText: ('Parse error on line ' , row , ' column ' , col , ' : ' , message , ' Below is code with line numbers and ===> marker inserted:' , String lf, code)",
 messageSends: ["lines", "at:", ",", "copyFrom:to:", "-", "size", "at:put:", "streamContents:", "withIndexDo:", "nextPutAll:", "asString", "lf", "messageText:", "new"],
-referencedClasses: ["String", "Error"]
+referencedClasses: ["String", "ParseError"]
 }),
 smalltalk.Smalltalk);
 

+ 1 - 0
js/amber.js

@@ -85,6 +85,7 @@ amber = (function() {
 				'Canvas',
 				'SUnit',
 				'Importer-Exporter',
+				'Compiler-Exceptions',
 				'Compiler-Core',
 				'Compiler-AST',
 				'Compiler-Visitors',

+ 24 - 14
js/boot.js

@@ -359,7 +359,7 @@ function Smalltalk(){
 		}
 		imp = klass ? klass.fn.prototype[selector] : receiver.klass && receiver[selector];
 		if(imp) {
-			var context = pushContext(receiver, selector, args);
+			var context = pushContext(receiver, selector, imp, args);
 			call = imp.apply(receiver, args);
 			popContext(context);
 			return call;
@@ -372,8 +372,10 @@ function Smalltalk(){
 	   (See the Smalltalk class ErrorHandler and its subclasses */
 
 	function handleError(error) {
-		st.thisContext = undefined;
-		smalltalk.ErrorHandler._current()._handleError_(error);
+        //Do not handle continuation exceptions
+        if(!error.cc) {
+		    smalltalk.ErrorHandler._current()._handleError_(error);
+        }
 	};
 
 	/* Handles #dnu: *and* JavaScript method calls.
@@ -437,21 +439,21 @@ function Smalltalk(){
 	st.getThisContext = function() {
 		if(st.thisContext) {
 			return st.thisContext.copy();
-		}/* else { // this is the default
-			return undefined;
-		}*/
+		}
 	};
 
-	function pushContext(receiver, selector, temps) {
+	function pushContext(receiver, selector, method, temps) {
 		var c = st.oldContext, tc = st.thisContext;
 		if (!c) {
-			return st.thisContext = new SmalltalkMethodContext(receiver, selector, temps, tc);
+			return st.thisContext = new SmalltalkMethodContext(receiver, selector, method, temps, tc);
 		}
 		st.oldContext = null;
 		c.homeContext = tc;
-		c.receiver = receiver;
-		c.selector = selector;
-		c.temps = temps || {};
+        c.pc          = 1;
+		c.receiver    = receiver;
+        c.selector    = selector;
+		c.method      = method;
+		c.temps       = temps || {};
 		return st.thisContext = c;
 	};
 
@@ -512,12 +514,19 @@ function Smalltalk(){
 	};
 };
 
-function SmalltalkMethodContext(receiver, selector, temps, home, pc) {
+function SmalltalkMethodContext(receiver, selector, method, temps, home, pc) {
 	this.receiver    = receiver;
-	this.selector    = selector;
+    this.selector    = selector;
+	this.method      = method;
 	this.temps       = temps || {};
 	this.homeContext = home;
     this.pc          = pc || 1;
+
+    this.resume = function() {
+        //Brutally set the receiver as thisContext, then re-enter the function
+        smalltalk.thisContext = this;
+        return this.method.apply(receiver, temps);
+    };
 };
 
 SmalltalkMethodContext.prototype.copy = function() {
@@ -525,7 +534,8 @@ SmalltalkMethodContext.prototype.copy = function() {
 	if(home) {home = home.copy()}
 	return new SmalltalkMethodContext(
 		this.receiver, 
-		this.selector, 
+        this.selector,
+		this.method, 
 		this.temps, 
 		home,
         this.pc

+ 1 - 9
st/Compiler-AST.st

@@ -115,19 +115,11 @@ accept: aVisitor
 ! !
 
 Node subclass: #BlockNode
-	instanceVariableNames: 'parameters scope inlined'
+	instanceVariableNames: 'parameters scope'
 	package: 'Compiler-AST'!
 
 !BlockNode methodsFor: 'accessing'!
 
-inlined
-	^inlined ifNil: [false]
-!
-
-inlined: aBoolean
-	inlined := aBoolean
-!
-
 parameters
 	^parameters ifNil: [parameters := Array new]
 !

+ 606 - 125
st/Compiler-Core.st

@@ -79,6 +79,14 @@ evaluateExpression: aString
 	^result
 !
 
+install: aString forClass: aBehavior category: anotherString
+	| compiled |
+	compiled := self eval: (self compile: aString forClass: aBehavior).
+	compiled category: anotherString.
+	aBehavior addCompiledMethod: compiled.
+	^compiled
+!
+
 parse: aString
     ^Smalltalk current parse: aString
 !
@@ -119,215 +127,688 @@ Object subclass: #DoIt
 	instanceVariableNames: ''
 	package: 'Compiler-Core'!
 
-Object subclass: #JSStream
-	instanceVariableNames: 'stream'
+Object subclass: #NodeVisitor
+	instanceVariableNames: ''
 	package: 'Compiler-Core'!
 
-!JSStream methodsFor: 'accessing'!
+!NodeVisitor methodsFor: 'visiting'!
 
-contents
-	^ stream contents
-! !
+visit: aNode
+	aNode accept: self
+!
 
-!JSStream methodsFor: 'initialization'!
+visitAll: aCollection
+	aCollection do: [ :each | self visit: each ]
+!
 
-initialize
-	super initialize.
-	stream := '' writeStream.
-! !
+visitAssignmentNode: aNode
+	self visitNode: aNode
+!
 
-!JSStream methodsFor: 'streaming'!
+visitBlockNode: aNode
+	self visitNode: aNode
+!
 
-lf
-	stream lf
+visitBlockSequenceNode: aNode
+	self visitSequenceNode: aNode
 !
 
-nextPut: aString
-	stream nextPut: aString
+visitCascadeNode: aNode
+	self visitNode: aNode
 !
 
-nextPutAll: aString
-	stream nextPutAll: aString
+visitClassReferenceNode: aNode
+	self visitNode: aNode
 !
 
-nextPutAssignment: varInstruction to: valueInstruction
-	varInstruction emitOn: self.
-	stream nextPutAll: '='.
-	valueInstruction emitOn: self
+visitDynamicArrayNode: aNode
+	self visitNode: aNode
 !
 
-nextPutClosureWith: aBlock arguments: anArray
-	stream nextPutAll: '(function('.
-	anArray 
-		do: [ :each | stream nextPutAll: each ]
-		separatedBy: [ stream nextPut: ',' ].
-	stream nextPutAll: '){'; lf.
-	aBlock value.
-	stream nextPutAll: '})'
+visitDynamicDictionaryNode: aNode
+	self visitNode: aNode
 !
 
-nextPutFunctionWith: aBlock arguments: anArray
-	stream nextPutAll: 'fn: function('.
-	anArray 
-		do: [ :each | stream nextPutAll: each ]
-		separatedBy: [ stream nextPut: ',' ].
-	stream nextPutAll: '){'; lf.
-	self nextPutVar: '$return'.
-	stream nextPutAll: 'var self=this;'; lf.
-	aBlock value.
-	stream nextPutAll: 'return $return || self;}'
+visitJSStatementNode: aNode
+	self visitNode: aNode
 !
 
-nextPutMethodDeclaration: aMethod with: aBlock
-	stream 
-		nextPutAll: 'smalltalk.method({'; lf;
-		nextPutAll: 'selector: "', aMethod selector, '",'; lf;
-		nextPutAll: 'source: ', aMethod source asJavascript, ',';lf.
-	aBlock value.
-	stream 
-		nextPutAll: ',', String lf, 'messageSends: ';
-		nextPutAll: aMethod messageSends asArray asJavascript, ','; lf;
-          	nextPutAll: 'args: ', (aMethod arguments collect: [ :each | each value ]) asArray asJavascript, ','; lf;
-		nextPutAll: 'referencedClasses: ['.
-	aMethod classReferences 
-		do: [:each | stream nextPutAll: each asJavascript]
-		separatedBy: [stream nextPutAll: ','].
-	stream 
-		nextPutAll: ']';
-		nextPutAll: '})'
+visitMethodNode: aNode
+	self visitNode: aNode
 !
 
-nextPutNonLocalReturnHandlingWith: aBlock
-	stream 
-		nextPutAll: 'var $early={};'; lf;
-		nextPutAll: 'try {'; lf.
-	aBlock value.
-	stream 
-		nextPutAll: '}'; lf;
-		nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf
+visitNode: aNode
+	aNode nodes do: [ :each | self visit: each ]
 !
 
-nextPutNonLocalReturnWith: aBlock
-	stream nextPutAll: '(function(){throw $early=['.
-	aBlock value.
-	stream nextPutAll: ']})()'
+visitReturnNode: aNode
+	self visitNode: aNode
 !
 
-nextPutReturnWith: aBlock
-	stream nextPutAll: '$return='.
-	aBlock value
+visitSendNode: aNode
+	self visitNode: aNode
 !
 
-nextPutSendTo: receiver selector: selector arguments: arguments
-	stream nextPutAll: 'smalltalk.send('.
-	receiver emitOn: self. 
-	stream nextPutAll: ',"', selector asSelector, '",['.
-	arguments 
-		do: [ :each | each emitOn: self ]
-		separatedBy: [ stream nextPutAll: ',' ].
-	stream nextPutAll: '])'
+visitSequenceNode: aNode
+	self visitNode: aNode
 !
 
-nextPutSequenceWith: aBlock
-	stream 
-		nextPutAll: 'switch(smalltalk.thisContext.pc){'; lf.
-	aBlock value.
-	stream 
-		nextPutAll: '};'; lf
+visitValueNode: aNode
+	self visitNode: aNode
 !
 
-nextPutStatement: anInteger with: aBlock
-	stream 
-		nextPutAll: 'case ', anInteger asString, ':'; lf.
-	aBlock value.
-	stream 
-		nextPutAll: ';'; lf;
-		nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf
+visitVariableNode: aNode
+	self visitNode: aNode
+! !
+
+NodeVisitor subclass: #AbstractCodeGenerator
+	instanceVariableNames: 'currentClass source'
+	package: 'Compiler-Core'!
+
+!AbstractCodeGenerator methodsFor: 'accessing'!
+
+classNameFor: aClass
+	^aClass isMetaclass
+	    ifTrue: [aClass instanceClass name, '.klass']
+	    ifFalse: [
+		aClass isNil
+		    ifTrue: ['nil']
+		    ifFalse: [aClass name]]
 !
 
-nextPutVar: aString
-	stream nextPutAll: 'var ', aString, ';'; lf
+currentClass
+	^currentClass
 !
 
-nextPutVars: aCollection
-	stream nextPutAll: 'var '.
-	aCollection 
-		do: [ :each | stream nextPutAll: each ]
-		separatedBy: [ stream nextPutAll: ',' ].
-	stream nextPutAll: ';'; lf
+currentClass: aClass
+	currentClass := aClass
+!
+
+pseudoVariables
+	^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
+!
+
+safeVariableNameFor: aString
+	^(Smalltalk current reservedWords includes: aString)
+		ifTrue: [aString, '_']
+		ifFalse: [aString]
+!
+
+source
+	^source ifNil: ['']
+!
+
+source: aString
+	source := aString
 ! !
 
-Object subclass: #NodeVisitor
+!AbstractCodeGenerator methodsFor: 'compiling'!
+
+compileNode: aNode
+	self subclassResponsibility
+! !
+
+AbstractCodeGenerator subclass: #CodeGenerator
 	instanceVariableNames: ''
 	package: 'Compiler-Core'!
 
-!NodeVisitor methodsFor: 'visiting'!
+!CodeGenerator methodsFor: 'compiling'!
 
-visit: aNode
-	aNode accept: self
+compileNode: aNode
+	| ir stream |
+	self semanticAnalyzer visit: aNode.
+	ir := self translator visit: aNode; builder.
+	stream := JSStream new.
+	ir emitOn: stream.
+	^ stream contents
 !
 
-visitAll: aCollection
-	aCollection do: [ :each | self visit: each ]
+semanticAnalyzer
+	^ SemanticAnalyzer on: self currentClass
+!
+
+translator
+	^ IRASTResolver new
+		source: self source;
+		yourself
+! !
+
+AbstractCodeGenerator subclass: #FunCodeGenerator
+	instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables'
+	package: 'Compiler-Core'!
+
+!FunCodeGenerator methodsFor: 'accessing'!
+
+argVariables
+	^argVariables copy
+!
+
+knownVariables
+	^self pseudoVariables 
+		addAll: self tempVariables;
+		addAll: self argVariables;
+		yourself
+!
+
+tempVariables
+	^tempVariables copy
+!
+
+unknownVariables
+	^unknownVariables copy
+! !
+
+!FunCodeGenerator methodsFor: 'compiling'!
+
+compileNode: aNode
+	stream := '' writeStream.
+	self visit: aNode.
+	^stream contents
+! !
+
+!FunCodeGenerator methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	stream := '' writeStream. 
+	unknownVariables := #().
+	tempVariables := #().
+	argVariables := #().
+	messageSends := #().
+	classReferenced := #()
+! !
+
+!FunCodeGenerator methodsFor: 'optimizations'!
+
+checkClass: aClassName for: receiver
+        stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
+!
+
+inline: aSelector receiver: receiver argumentNodes: aCollection
+        | inlined |
+        inlined := false.
+
+	"-- Booleans --"
+
+	(aSelector = 'ifFalse:') ifTrue: [
+		aCollection first isBlockNode ifTrue: [
+                	self checkClass: 'Boolean' for: receiver.
+                	stream nextPutAll: '(!! $receiver ? '.
+                	self visit: aCollection first.
+          		stream nextPutAll: '() : nil)'.
+                	inlined := true]].
+
+	(aSelector = 'ifTrue:') ifTrue: [
+		aCollection first isBlockNode ifTrue: [
+                	self checkClass: 'Boolean' for: receiver.
+                	stream nextPutAll: '($receiver ? '.
+                	self visit: aCollection first.
+          		stream nextPutAll: '() : nil)'.
+                	inlined := true]].
+
+	(aSelector = 'ifTrue:ifFalse:') ifTrue: [
+		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
+                	self checkClass: 'Boolean' for: receiver.
+                	stream nextPutAll: '($receiver ? '.
+                	self visit: aCollection first.
+          		stream nextPutAll: '() : '.
+          		self visit: aCollection second.
+          		stream nextPutAll: '())'.
+                	inlined := true]].
+
+	(aSelector = 'ifFalse:ifTrue:') ifTrue: [
+		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
+                	self checkClass: 'Boolean' for: receiver.
+                	stream nextPutAll: '(!! $receiver ? '.
+                	self visit: aCollection first.
+          		stream nextPutAll: '() : '.
+          		self visit: aCollection second.
+          		stream nextPutAll: '())'.
+                	inlined := true]].
+
+	"-- Numbers --"
+
+	(aSelector = '<') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver <'.
+                self visit: aCollection first.
+                inlined := true].
+
+	(aSelector = '<=') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver <='.
+                self visit: aCollection first.
+                inlined := true].
+
+	(aSelector = '>') ifTrue: [ 
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver >'.
+                self visit: aCollection first.
+                inlined := true].
+
+	(aSelector = '>=') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver >='.
+                self visit: aCollection first.
+                inlined := true].
+
+        (aSelector = '+') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver +'.
+                self visit: aCollection first.
+                inlined := true].
+
+        (aSelector = '-') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver -'.
+                self visit: aCollection first.
+                inlined := true].
+
+        (aSelector = '*') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver *'.
+                self visit: aCollection first.
+                inlined := true].
+
+        (aSelector = '/') ifTrue: [
+                self checkClass: 'Number' for: receiver.
+                stream nextPutAll: '$receiver /'.
+                self visit: aCollection first.
+                inlined := true].
+
+        ^inlined
+!
+
+inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
+        | inlined |
+        inlined := false.
+ 
+	"-- BlockClosures --"
+
+	(aSelector = 'whileTrue:') ifTrue: [
+          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
+                	stream nextPutAll: '(function(){while('.
+                  	self visit: anObject.
+                  	stream nextPutAll: '()) {'.
+                	self visit: aCollection first.
+          		stream nextPutAll: '()}})()'.
+                	inlined := true]].
+
+	(aSelector = 'whileFalse:') ifTrue: [
+          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
+                	stream nextPutAll: '(function(){while(!!'.
+                  	self visit: anObject.
+                  	stream nextPutAll: '()) {'.
+                	self visit: aCollection first.
+          		stream nextPutAll: '()}})()'.
+                	inlined := true]].
+
+	(aSelector = 'whileTrue') ifTrue: [
+          	anObject isBlockNode ifTrue: [
+                	stream nextPutAll: '(function(){while('.
+                  	self visit: anObject.
+                  	stream nextPutAll: '()) {}})()'.
+                	inlined := true]].
+
+	(aSelector = 'whileFalse') ifTrue: [
+          	anObject isBlockNode ifTrue: [
+                	stream nextPutAll: '(function(){while(!!'.
+                  	self visit: anObject.
+                  	stream nextPutAll: '()) {}})()'.
+                	inlined := true]].
+
+	"-- Numbers --"
+
+	(aSelector = '+') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' + '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '-') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' - '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '*') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' * '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '/') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' / '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '<') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' < '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '<=') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' <= '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '>') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' > '.
+                	self visit: aCollection first.
+                	inlined := true]].
+
+	(aSelector = '>=') ifTrue: [
+          	(self isNode: anObject ofClass: Number) ifTrue: [
+                  	self visit: anObject.
+                  	stream nextPutAll: ' >= '.
+                	self visit: aCollection first.
+                	inlined := true]].
+                	   
+	"-- UndefinedObject --"
+
+	(aSelector = 'ifNil:') ifTrue: [
+		aCollection first isBlockNode ifTrue: [
+          		stream nextPutAll: '(($receiver = '.
+          		self visit: anObject.
+          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
+                  	self visit: aCollection first.
+                  	stream nextPutAll: '() : $receiver'.
+                  	inlined := true]].
+
+	(aSelector = 'ifNotNil:') ifTrue: [
+		aCollection first isBlockNode ifTrue: [
+          		stream nextPutAll: '(($receiver = '.
+          		self visit: anObject.
+          		stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
+                  	self visit: aCollection first.
+                  	stream nextPutAll: '() : nil'.
+                  	inlined := true]].
+
+	(aSelector = 'ifNil:ifNotNil:') ifTrue: [
+		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
+          		stream nextPutAll: '(($receiver = '.
+          		self visit: anObject.
+          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
+                  	self visit: aCollection first.
+                  	stream nextPutAll: '() : '.
+                  	self visit: aCollection second.
+                  	stream nextPutAll: '()'.
+                  	inlined := true]].
+
+	(aSelector = 'ifNotNil:ifNil:') ifTrue: [
+		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
+          		stream nextPutAll: '(($receiver = '.
+          		self visit: anObject.
+          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
+                  	self visit: aCollection second.
+                  	stream nextPutAll: '() : '.
+                  	self visit: aCollection first.
+                  	stream nextPutAll: '()'.
+                  	inlined := true]].
+                 
+        ^inlined
+!
+
+isNode: aNode ofClass: aClass
+	^aNode isValueNode and: [
+          	aNode value class = aClass or: [
+          		aNode value = 'self' and: [self currentClass = aClass]]]
+! !
+
+!FunCodeGenerator methodsFor: 'testing'!
+
+performOptimizations
+	^self class performOptimizations
+! !
+
+!FunCodeGenerator methodsFor: 'visiting'!
+
+send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
+	^String streamContents: [:str || tmp |
+        	tmp := stream.
+		str nextPutAll: 'smalltalk.send('.
+		str nextPutAll: aReceiver.
+		str nextPutAll: ', "', aSelector asSelector, '", ['.
+                stream := str.
+		aCollection
+	    		do: [:each | self visit: each]
+	    		separatedBy: [stream nextPutAll: ', '].
+                stream := tmp.
+                str nextPutAll: ']'.
+		aBoolean ifTrue: [
+			str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass), '.superclass || nil'].
+		str nextPutAll: ')']
+!
+
+visit: aNode
+	aNode accept: self
 !
 
 visitAssignmentNode: aNode
-	self visitNode: aNode
+	stream nextPutAll: '('.
+	self visit: aNode left.
+	stream nextPutAll: '='.
+	self visit: aNode right.
+	stream nextPutAll: ')'
 !
 
 visitBlockNode: aNode
-	self visitNode: aNode
+	stream nextPutAll: '(function('.
+	aNode parameters 
+	    do: [:each |
+		tempVariables add: each.
+		stream nextPutAll: each]
+	    separatedBy: [stream nextPutAll: ', '].
+	stream nextPutAll: '){'.
+	aNode nodes do: [:each | self visit: each].
+	stream nextPutAll: '})'
 !
 
 visitBlockSequenceNode: aNode
-	self visitSequenceNode: aNode
+	| index |
+	nestedBlocks := nestedBlocks + 1.
+	aNode nodes isEmpty
+	    ifTrue: [
+		stream nextPutAll: 'return nil;']
+	    ifFalse: [
+		aNode temps do: [:each | | temp |
+                    temp := self safeVariableNameFor: each.
+		    tempVariables add: temp.
+		    stream nextPutAll: 'var ', temp, '=nil;'; lf].
+		index := 0.
+		aNode nodes do: [:each |
+		    index := index + 1.
+		    index = aNode nodes size ifTrue: [
+			stream nextPutAll: 'return '].
+		    self visit: each.
+		    stream nextPutAll: ';']].
+	nestedBlocks := nestedBlocks - 1
 !
 
 visitCascadeNode: aNode
-	self visitNode: aNode
+	| index |
+	index := 0.
+	(tempVariables includes: '$rec') ifFalse: [
+		tempVariables add: '$rec'].
+	stream nextPutAll: '(function($rec){'.
+	aNode nodes do: [:each |
+	    index := index + 1.
+	    index = aNode nodes size ifTrue: [
+		stream nextPutAll: 'return '].
+	    each receiver: (VariableNode new value: '$rec').
+	    self visit: each.
+	    stream nextPutAll: ';'].
+	stream nextPutAll: '})('.
+	self visit: aNode receiver.
+	stream nextPutAll: ')'
 !
 
 visitClassReferenceNode: aNode
-	self visitNode: aNode
+	(referencedClasses includes: aNode value) ifFalse: [
+		referencedClasses add: aNode value].
+	stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
 !
 
 visitDynamicArrayNode: aNode
-	self visitNode: aNode
+	stream nextPutAll: '['.
+	aNode nodes 
+		do: [:each | self visit: each]
+		separatedBy: [stream nextPutAll: ','].
+	stream nextPutAll: ']'
 !
 
 visitDynamicDictionaryNode: aNode
-	self visitNode: aNode
+	stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
+		aNode nodes 
+			do: [:each | self visit: each]
+			separatedBy: [stream nextPutAll: ','].
+		stream nextPutAll: '])'
 !
 
-visitJSStatementNode: aNode
-	self visitNode: aNode
+visitFailure: aFailure
+	self error: aFailure asString
 !
 
-visitMethodNode: aNode
-	self visitNode: aNode
+visitJSStatementNode: aNode
+	stream nextPutAll: aNode source
 !
 
-visitNode: aNode
-	aNode nodes do: [ :each | self visit: each ]
+visitMethodNode: aNode
+	| str currentSelector | 
+	currentSelector := aNode selector asSelector.
+	nestedBlocks := 0.
+	earlyReturn := false.
+	messageSends := #().
+	referencedClasses := #().
+	unknownVariables := #().
+	tempVariables := #().
+	argVariables := #().
+	stream 
+	    nextPutAll: 'smalltalk.method({'; lf;
+	    nextPutAll: 'selector: "', aNode selector, '",'; lf.
+	stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
+	stream nextPutAll: 'fn: function('.
+	aNode arguments 
+	    do: [:each | 
+		argVariables add: each.
+		stream nextPutAll: each]
+	    separatedBy: [stream nextPutAll: ', '].
+	stream 
+	    nextPutAll: '){'; lf;
+	    nextPutAll: 'var self=this;'; lf.
+	str := stream.
+	stream := '' writeStream.
+	aNode nodes do: [:each |
+	    self visit: each].
+	earlyReturn ifTrue: [
+	    str nextPutAll: 'var $early={};'; lf; nextPutAll: 'try{'].
+	str nextPutAll: stream contents.
+	stream := str.
+	stream 
+	    lf; 
+	    nextPutAll: 'return self;'.
+	earlyReturn ifTrue: [
+	    stream lf; nextPutAll: '} catch(e) {if(e===$early)return e[0]; throw e}'].
+	stream nextPutAll: '}'.
+	stream 
+		nextPutAll: ',', String lf, 'messageSends: ';
+		nextPutAll: messageSends asJavascript, ','; lf;
+          	nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
+		nextPutAll: 'referencedClasses: ['.
+	referencedClasses 
+		do: [:each | stream nextPutAll: each printString]
+		separatedBy: [stream nextPutAll: ','].
+	stream nextPutAll: ']'.
+	stream nextPutAll: '})'
 !
 
 visitReturnNode: aNode
-	self visitNode: aNode
+	nestedBlocks > 0 ifTrue: [
+	    earlyReturn := true].
+	nestedBlocks > 0
+	    ifTrue: [
+		stream
+		    nextPutAll: '(function(){throw $early=[']
+	    ifFalse: [stream nextPutAll: 'return '].
+	aNode nodes do: [:each |
+	    self visit: each].
+	nestedBlocks > 0 ifTrue: [
+	    stream nextPutAll: ']})()']
 !
 
 visitSendNode: aNode
-	self visitNode: aNode
+        | str receiver superSend inlined |
+        str := stream.
+        (messageSends includes: aNode selector) ifFalse: [
+                messageSends add: aNode selector].
+        stream := '' writeStream.
+        self visit: aNode receiver.
+        superSend := stream contents = 'super'.
+        receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
+        stream := str.
+	
+	self performOptimizations 
+		ifTrue: [
+			(self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
+				(self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
+                			ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
+                			ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
+		ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
 !
 
 visitSequenceNode: aNode
-	self visitNode: aNode
+	aNode temps do: [:each || temp |
+            temp := self safeVariableNameFor: each.
+	    tempVariables add: temp.
+	    stream nextPutAll: 'var ', temp, '=nil;'; lf].
+	aNode nodes do: [:each |
+	    self visit: each.
+	    stream nextPutAll: ';']
+	    separatedBy: [stream lf]
 !
 
 visitValueNode: aNode
-	self visitNode: aNode
+	stream nextPutAll: aNode value asJavascript
 !
 
 visitVariableNode: aNode
-	self visitNode: aNode
+	| varName |
+	(self currentClass allInstanceVariableNames includes: aNode value) 
+		ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
+		ifFalse: [
+                  	varName := self safeVariableNameFor: aNode value.
+			(self knownVariables includes: varName) 
+                  		ifFalse: [
+                                  	unknownVariables add: aNode value.
+                                  	aNode assigned 
+                                  		ifTrue: [stream nextPutAll: varName]
+                                  		ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
+                  		ifTrue: [
+                                  	aNode value = 'thisContext'
+                                  		ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
+                				ifFalse: [stream nextPutAll: varName]]]
+! !
+
+FunCodeGenerator class instanceVariableNames: 'performOptimizations'!
+
+!FunCodeGenerator class methodsFor: 'accessing'!
+
+performOptimizations
+	^performOptimizations ifNil: [true]
+!
+
+performOptimizations: aBoolean
+	performOptimizations := aBoolean
 ! !
 

+ 52 - 0
st/Compiler-Exceptions.st

@@ -0,0 +1,52 @@
+Smalltalk current createPackage: 'Compiler-Exceptions' properties: #{}!
+Error subclass: #CompilerError
+	instanceVariableNames: ''
+	package: 'Compiler-Exceptions'!
+
+CompilerError subclass: #ParseError
+	instanceVariableNames: ''
+	package: 'Compiler-Exceptions'!
+
+CompilerError subclass: #SemanticError
+	instanceVariableNames: ''
+	package: 'Compiler-Exceptions'!
+!SemanticError commentStamp!
+I represent an abstract semantic error thrown by the SemanticAnalyzer.
+Semantic errors can be unknown variable errors, etc.
+See my subclasses for concrete errors.
+
+The IDE should catch instances of Semantic error to deal with them when compiling!
+
+SemanticError subclass: #ShadowingVariableError
+	instanceVariableNames: 'variableName'
+	package: 'Compiler-Exceptions'!
+!ShadowingVariableError commentStamp!
+I get signaled when a variable in a block or method scope shadows a variable of the same name in an outer scope.!
+
+!ShadowingVariableError methodsFor: 'accessing'!
+
+variableName
+	^ variableName
+!
+
+variableName: aString
+	variableName := aString
+! !
+
+SemanticError subclass: #UnknownVariableError
+	instanceVariableNames: 'variableName'
+	package: 'Compiler-Exceptions'!
+!UnknownVariableError commentStamp!
+I get signaled when a variable is not defined.
+The default behavior is to allow it, as this is how Amber currently is able to seamlessly send messages to JavaScript objects.!
+
+!UnknownVariableError methodsFor: 'accessing'!
+
+variableName
+	^ variableName
+!
+
+variableName: aString
+	variableName := aString
+! !
+

+ 157 - 11
st/Compiler-IR.st

@@ -3,8 +3,11 @@ NodeVisitor subclass: #IRASTTranslator
 	instanceVariableNames: 'builder source'
 	package: 'Compiler-IR'!
 !IRASTTranslator commentStamp!
-I an the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.
-I rely on a builder object, instance of IRBuilder.!
+I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.
+I rely on a builder object, instance of IRBuilder.
+
+I am myself unable to produce a valid IR as nodes are not resolved. 
+See concrete subclasses.!
 
 !IRASTTranslator methodsFor: 'accessing'!
 
@@ -98,9 +101,9 @@ nextAlias
 	"Message sends are assigned, or 'aliased', to internal variables.
 	Internal variable names are unique, and attached to the annotated send node"
 
-	nextAlias ifNil: [nextAlias := 0].
+	nextAlias ifNil: [ nextAlias := 0 ].
 	nextAlias := nextAlias + 1.
-	^ '$_', nextAlias asString
+	^ '$', nextAlias asString
 ! !
 
 !IRASTResolver methodsFor: 'visiting'!
@@ -326,8 +329,8 @@ IRInstruction subclass: #IRAssignment
 
 emitOn: aStream
 	aStream 
-		nextPutAssignment: self instructions first
-		to: self instructions second
+		nextPutAssignment: self instructions first 
+		to: self instructions last
 ! !
 
 IRInstruction subclass: #IRClosure
@@ -348,8 +351,8 @@ arguments: aCollection
 
 emitOn: aStream
 	aStream 
-		nextPutClosureWith: [ super emitOn: aStream ]
-		arguments: (self arguments collect: [ :each | each asVariableName ])
+		nextPutClosureWith: [ super emitOn: aStream ] 
+		arguments: self arguments
 ! !
 
 IRInstruction subclass: #IRMethod
@@ -407,15 +410,15 @@ source: aString
 !IRMethod methodsFor: 'emiting'!
 
 emitOn: aStream
-	aStream 
-		nextPutMethodDeclaration: self
+	aStream
+		nextPutMethodDeclaration: self 
 		with: [
 			aStream 
 				nextPutFunctionWith: [ 
 					self internalVariables notEmpty ifTrue: [
 						aStream nextPutVars: self internalVariables ].
 					super emitOn: aStream ]
-				arguments: (self arguments collect: [ :each | each asVariableName ]) ]
+			arguments: self arguments ]
 ! !
 
 IRInstruction subclass: #IRNonLocalReturn
@@ -519,6 +522,9 @@ emitOn: aStream
 IRInstruction subclass: #IRStatement
 	instanceVariableNames: 'pc'
 	package: 'Compiler-IR'!
+!IRStatement commentStamp!
+I am a statement instruction. 
+Statements can be used to control the PC count, among other things.!
 
 !IRStatement methodsFor: 'accessing'!
 
@@ -580,6 +586,8 @@ emitOn: aStream
 IRInstruction subclass: #IRVariable
 	instanceVariableNames: 'variable'
 	package: 'Compiler-IR'!
+!IRVariable commentStamp!
+I am a variable instruction.!
 
 !IRVariable methodsFor: 'accessing'!
 
@@ -617,6 +625,144 @@ emitOn: aStream
 	aStream nextPutAll: self source, ';'
 ! !
 
+Object subclass: #JSStream
+	instanceVariableNames: 'stream'
+	package: 'Compiler-IR'!
+
+!JSStream methodsFor: 'accessing'!
+
+contents
+	^ stream contents
+! !
+
+!JSStream methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	stream := '' writeStream.
+! !
+
+!JSStream methodsFor: 'streaming'!
+
+lf
+	stream lf
+!
+
+nextPut: aString
+	stream nextPut: aString
+!
+
+nextPutAll: aString
+	stream nextPutAll: aString
+!
+
+nextPutAssignment: varInstruction to: valueInstruction
+	varInstruction emitOn: self.
+	stream nextPutAll: '='.
+	valueInstruction emitOn: self
+!
+
+nextPutClosureWith: aBlock arguments: anArray
+	stream nextPutAll: '(function('.
+	anArray 
+		do: [ :each | stream nextPutAll: each asVariableName ]
+		separatedBy: [ stream nextPut: ',' ].
+	stream nextPutAll: '){'; lf.
+	aBlock value.
+	stream nextPutAll: '})'
+!
+
+nextPutFunctionWith: aBlock arguments: anArray
+	stream nextPutAll: 'fn: function('.
+	anArray 
+		do: [ :each | stream nextPutAll: each asVariableName ]
+		separatedBy: [ stream nextPut: ',' ].
+	stream nextPutAll: '){'; lf.
+	self nextPutVar: '$return'.
+	stream nextPutAll: 'var self=this;'; lf.
+	aBlock value.
+	stream nextPutAll: 'return $return || self;}'
+!
+
+nextPutMethodDeclaration: aMethod with: aBlock
+	stream 
+		nextPutAll: 'smalltalk.method({'; lf;
+		nextPutAll: 'selector: "', aMethod selector, '",'; lf;
+		nextPutAll: 'source: ', aMethod source asJavascript, ',';lf.
+	aBlock value.
+	stream 
+		nextPutAll: ',', String lf, 'messageSends: ';
+		nextPutAll: aMethod messageSends asArray asJavascript, ','; lf;
+          	nextPutAll: 'args: ', (aMethod arguments collect: [ :each | each value ]) asArray asJavascript, ','; lf;
+		nextPutAll: 'referencedClasses: ['.
+	aMethod classReferences 
+		do: [:each | stream nextPutAll: each asJavascript]
+		separatedBy: [stream nextPutAll: ','].
+	stream 
+		nextPutAll: ']';
+		nextPutAll: '})'
+!
+
+nextPutNonLocalReturnHandlingWith: aBlock
+	stream 
+		nextPutAll: 'var $early={};'; lf;
+		nextPutAll: 'try {'; lf.
+	aBlock value.
+	stream 
+		nextPutAll: '}'; lf;
+		nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf
+!
+
+nextPutNonLocalReturnWith: aBlock
+	stream nextPutAll: '(function(){throw $early=['.
+	aBlock value.
+	stream nextPutAll: ']})()'
+!
+
+nextPutReturnWith: aBlock
+	stream nextPutAll: '$return='.
+	aBlock value
+!
+
+nextPutSendTo: receiver selector: selector arguments: arguments
+	stream nextPutAll: 'smalltalk.send('.
+	receiver emitOn: self. 
+	stream nextPutAll: ',"', selector asSelector, '",['.
+	arguments 
+		do: [ :each | each emitOn: self ]
+		separatedBy: [ stream nextPutAll: ',' ].
+	stream nextPutAll: '])'
+!
+
+nextPutSequenceWith: aBlock
+	"stream 
+		nextPutAll: 'switch(smalltalk.thisContext.pc){'; lf."
+	aBlock value.
+	"stream 
+		nextPutAll: '};'; lf"
+!
+
+nextPutStatement: anInteger with: aBlock
+	"stream 
+		nextPutAll: 'case ', anInteger asString, ':'; lf."
+	aBlock value.
+	stream 
+		nextPutAll: ';'; lf";
+		nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf"
+!
+
+nextPutVar: aString
+	stream nextPutAll: 'var ', aString, ';'; lf
+!
+
+nextPutVars: aCollection
+	stream nextPutAll: 'var '.
+	aCollection 
+		do: [ :each | stream nextPutAll: each ]
+		separatedBy: [ stream nextPutAll: ',' ].
+	stream nextPutAll: ';'; lf
+! !
+
 !BlockClosure methodsFor: '*Compiler-IR'!
 
 appendToInstruction: anIRInstruction

+ 43 - 61
st/Compiler-Semantic.st

@@ -1,6 +1,22 @@
 Smalltalk current createPackage: 'Compiler-Semantic' properties: #{}!
+SemanticError subclass: #InvalidAssignmentError
+	instanceVariableNames: 'variableName'
+	package: 'Compiler-Semantic'!
+!InvalidAssignmentError commentStamp!
+I get signaled when a pseudo variable gets assigned.!
+
+!InvalidAssignmentError methodsFor: 'accessing'!
+
+variableName
+	^ variableName
+!
+
+variableName: aString
+	variableName := aString
+! !
+
 Object subclass: #LexicalScope
-	instanceVariableNames: 'temps args outerScope'
+	instanceVariableNames: 'node temps args outerScope'
 	package: 'Compiler-Semantic'!
 !LexicalScope commentStamp!
 I represent a lexical scope where variable names are associated with ScopeVars
@@ -38,6 +54,16 @@ methodScope
 		self outerScope methodScope ]
 !
 
+node
+	"Answer the node in which I am defined"
+	
+	^ node
+!
+
+node: aNode
+	node := aNode
+!
+
 outerScope
 	^ outerScope
 !
@@ -46,6 +72,12 @@ outerScope: aLexicalScope
 	outerScope := aLexicalScope
 !
 
+scopeLevel
+	^ (self outerScope 
+		ifNil: [ 0 ]
+		ifNotNil: [ self outerScope scopeLevel ]) + 1
+!
+
 temps
 	^ temps ifNil: [ temps := Dictionary new ]
 ! !
@@ -198,6 +230,8 @@ isArgVar
 ScopeVar subclass: #ClassRefVar
 	instanceVariableNames: ''
 	package: 'Compiler-Semantic'!
+!ClassRefVar commentStamp!
+I am an class reference variable!
 
 !ClassRefVar methodsFor: 'accessing'!
 
@@ -359,6 +393,12 @@ visitBlockNode: aNode
 	self popScope
 !
 
+visitCascadeNode: aNode
+	"Populate the receiver into all children"
+	aNode nodes do: [ :each | each receiver: aNode receiver ].
+	super visitCascadeNode: aNode
+!
+
 visitClassReferenceNode: aNode
 	self classReferences add: aNode value.
 	aNode binding: (ClassRefVar new name: aNode value; yourself)
@@ -392,7 +432,8 @@ visitReturnNode: aNode
 
 visitSendNode: aNode
 	self messageSends add: aNode selector.
-	aNode receiver beUsed.
+	aNode receiver ifNotNil: [
+		aNode receiver beUsed ].
 	aNode arguments do: [ :each |
 		each beUsed ].
 	super visitSendNode: aNode
@@ -423,62 +464,3 @@ on: aClass
 		yourself
 ! !
 
-Error subclass: #SemanticError
-	instanceVariableNames: ''
-	package: 'Compiler-Semantic'!
-!SemanticError commentStamp!
-I represent an abstract semantic error thrown by the SemanticAnalyzer.
-Semantic errors can be unknown variable errors, etc.
-See my subclasses for concrete errors.
-
-The IDE should catch instances of Semantic error to deal with them when compiling!
-
-SemanticError subclass: #InvalidAssignmentError
-	instanceVariableNames: 'variableName'
-	package: 'Compiler-Semantic'!
-!InvalidAssignmentError commentStamp!
-I get signaled when a pseudo variable gets assigned.!
-
-!InvalidAssignmentError methodsFor: 'accessing'!
-
-variableName
-	^ variableName
-!
-
-variableName: aString
-	variableName := aString
-! !
-
-SemanticError subclass: #ShadowingVariableError
-	instanceVariableNames: 'variableName'
-	package: 'Compiler-Semantic'!
-!ShadowingVariableError commentStamp!
-I get signaled when a variable in a block or method scope shadows a variable of the same name in an outer scope.!
-
-!ShadowingVariableError methodsFor: 'accessing'!
-
-variableName
-	^ variableName
-!
-
-variableName: aString
-	variableName := aString
-! !
-
-SemanticError subclass: #UnknownVariableError
-	instanceVariableNames: 'variableName'
-	package: 'Compiler-Semantic'!
-!UnknownVariableError commentStamp!
-I get signaled when a variable is not defined.
-The default behavior is to allow it, as this is how Amber currently is able to seamlessly send messages to JavaScript objects.!
-
-!UnknownVariableError methodsFor: 'accessing'!
-
-variableName
-	^ variableName
-!
-
-variableName: aString
-	variableName := aString
-! !
-

+ 11 - 0
st/Compiler-Tests.st

@@ -59,6 +59,17 @@ testScope2
 	self deny: ast nodes first nodes last nodes first nodes first scope == ast scope.
 !
 
+testScopeLevel
+	| src ast |
+
+	src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.
+	ast := smalltalk parse: src.
+	analyzer visit: ast.
+
+	self assert: ast scope scopeLevel = 1.
+	self assert: ast nodes first nodes last nodes first nodes first scope scopeLevel = 3
+!
+
 testUnknownVariables
 	| src ast |
 

+ 0 - 611
st/Compiler-Visitors.st

@@ -1,615 +1,4 @@
 Smalltalk current createPackage: 'Compiler-Visitors' properties: #{}!
-NodeVisitor subclass: #AbstractCodeGenerator
-	instanceVariableNames: 'currentClass source'
-	package: 'Compiler-Visitors'!
-
-!AbstractCodeGenerator methodsFor: 'accessing'!
-
-classNameFor: aClass
-	^aClass isMetaclass
-	    ifTrue: [aClass instanceClass name, '.klass']
-	    ifFalse: [
-		aClass isNil
-		    ifTrue: ['nil']
-		    ifFalse: [aClass name]]
-!
-
-currentClass
-	^currentClass
-!
-
-currentClass: aClass
-	currentClass := aClass
-!
-
-pseudoVariables
-	^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
-!
-
-safeVariableNameFor: aString
-	^(Smalltalk current reservedWords includes: aString)
-		ifTrue: [aString, '_']
-		ifFalse: [aString]
-!
-
-source
-	^source ifNil: ['']
-!
-
-source: aString
-	source := aString
-! !
-
-!AbstractCodeGenerator methodsFor: 'compiling'!
-
-compileNode: aNode
-	self subclassResponsibility
-! !
-
-AbstractCodeGenerator subclass: #CodeGenerator
-	instanceVariableNames: ''
-	package: 'Compiler-Visitors'!
-
-!CodeGenerator methodsFor: 'compiling'!
-
-compileNode: aNode
-	| ir stream |
-	self semanticAnalyzer visit: aNode.
-	ir := self translator visit: aNode; builder.
-	stream := JSStream new.
-	ir emitOn: stream.
-	^ stream contents
-!
-
-semanticAnalyzer
-	^ SemanticAnalyzer on: self currentClass
-!
-
-translator
-	^ IRASTResolver new
-		source: self source;
-		yourself
-! !
-
-AbstractCodeGenerator subclass: #FunCodeGenerator
-	instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables'
-	package: 'Compiler-Visitors'!
-
-!FunCodeGenerator methodsFor: 'accessing'!
-
-argVariables
-	^argVariables copy
-!
-
-knownVariables
-	^self pseudoVariables 
-		addAll: self tempVariables;
-		addAll: self argVariables;
-		yourself
-!
-
-tempVariables
-	^tempVariables copy
-!
-
-unknownVariables
-	^unknownVariables copy
-! !
-
-!FunCodeGenerator methodsFor: 'compiling'!
-
-compileNode: aNode
-	stream := '' writeStream.
-	self visit: aNode.
-	^stream contents
-! !
-
-!FunCodeGenerator methodsFor: 'initialization'!
-
-initialize
-	super initialize.
-	stream := '' writeStream. 
-	unknownVariables := #().
-	tempVariables := #().
-	argVariables := #().
-	messageSends := #().
-	classReferenced := #()
-! !
-
-!FunCodeGenerator methodsFor: 'optimizations'!
-
-checkClass: aClassName for: receiver
-        stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
-!
-
-inline: aSelector receiver: receiver argumentNodes: aCollection
-        | inlined |
-        inlined := false.
-
-	"-- Booleans --"
-
-	(aSelector = 'ifFalse:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-                	self checkClass: 'Boolean' for: receiver.
-                	stream nextPutAll: '(!! $receiver ? '.
-                	self visit: aCollection first.
-          		stream nextPutAll: '() : nil)'.
-                	inlined := true]].
-
-	(aSelector = 'ifTrue:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-                	self checkClass: 'Boolean' for: receiver.
-                	stream nextPutAll: '($receiver ? '.
-                	self visit: aCollection first.
-          		stream nextPutAll: '() : nil)'.
-                	inlined := true]].
-
-	(aSelector = 'ifTrue:ifFalse:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-                	self checkClass: 'Boolean' for: receiver.
-                	stream nextPutAll: '($receiver ? '.
-                	self visit: aCollection first.
-          		stream nextPutAll: '() : '.
-          		self visit: aCollection second.
-          		stream nextPutAll: '())'.
-                	inlined := true]].
-
-	(aSelector = 'ifFalse:ifTrue:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-                	self checkClass: 'Boolean' for: receiver.
-                	stream nextPutAll: '(!! $receiver ? '.
-                	self visit: aCollection first.
-          		stream nextPutAll: '() : '.
-          		self visit: aCollection second.
-          		stream nextPutAll: '())'.
-                	inlined := true]].
-
-	"-- Numbers --"
-
-	(aSelector = '<') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver <'.
-                self visit: aCollection first.
-                inlined := true].
-
-	(aSelector = '<=') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver <='.
-                self visit: aCollection first.
-                inlined := true].
-
-	(aSelector = '>') ifTrue: [ 
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver >'.
-                self visit: aCollection first.
-                inlined := true].
-
-	(aSelector = '>=') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver >='.
-                self visit: aCollection first.
-                inlined := true].
-
-        (aSelector = '+') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver +'.
-                self visit: aCollection first.
-                inlined := true].
-
-        (aSelector = '-') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver -'.
-                self visit: aCollection first.
-                inlined := true].
-
-        (aSelector = '*') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver *'.
-                self visit: aCollection first.
-                inlined := true].
-
-        (aSelector = '/') ifTrue: [
-                self checkClass: 'Number' for: receiver.
-                stream nextPutAll: '$receiver /'.
-                self visit: aCollection first.
-                inlined := true].
-
-        ^inlined
-!
-
-inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
-        | inlined |
-        inlined := false.
- 
-	"-- BlockClosures --"
-
-	(aSelector = 'whileTrue:') ifTrue: [
-          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
-                	stream nextPutAll: '(function(){while('.
-                  	self visit: anObject.
-                  	stream nextPutAll: '()) {'.
-                	self visit: aCollection first.
-          		stream nextPutAll: '()}})()'.
-                	inlined := true]].
-
-	(aSelector = 'whileFalse:') ifTrue: [
-          	(anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
-                	stream nextPutAll: '(function(){while(!!'.
-                  	self visit: anObject.
-                  	stream nextPutAll: '()) {'.
-                	self visit: aCollection first.
-          		stream nextPutAll: '()}})()'.
-                	inlined := true]].
-
-	(aSelector = 'whileTrue') ifTrue: [
-          	anObject isBlockNode ifTrue: [
-                	stream nextPutAll: '(function(){while('.
-                  	self visit: anObject.
-                  	stream nextPutAll: '()) {}})()'.
-                	inlined := true]].
-
-	(aSelector = 'whileFalse') ifTrue: [
-          	anObject isBlockNode ifTrue: [
-                	stream nextPutAll: '(function(){while(!!'.
-                  	self visit: anObject.
-                  	stream nextPutAll: '()) {}})()'.
-                	inlined := true]].
-
-	"-- Numbers --"
-
-	(aSelector = '+') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' + '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '-') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' - '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '*') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' * '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '/') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' / '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '<') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' < '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '<=') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' <= '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '>') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' > '.
-                	self visit: aCollection first.
-                	inlined := true]].
-
-	(aSelector = '>=') ifTrue: [
-          	(self isNode: anObject ofClass: Number) ifTrue: [
-                  	self visit: anObject.
-                  	stream nextPutAll: ' >= '.
-                	self visit: aCollection first.
-                	inlined := true]].
-                	   
-	"-- UndefinedObject --"
-
-	(aSelector = 'ifNil:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-          		stream nextPutAll: '(($receiver = '.
-          		self visit: anObject.
-          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
-                  	self visit: aCollection first.
-                  	stream nextPutAll: '() : $receiver'.
-                  	inlined := true]].
-
-	(aSelector = 'ifNotNil:') ifTrue: [
-		aCollection first isBlockNode ifTrue: [
-          		stream nextPutAll: '(($receiver = '.
-          		self visit: anObject.
-          		stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
-                  	self visit: aCollection first.
-                  	stream nextPutAll: '() : nil'.
-                  	inlined := true]].
-
-	(aSelector = 'ifNil:ifNotNil:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-          		stream nextPutAll: '(($receiver = '.
-          		self visit: anObject.
-          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
-                  	self visit: aCollection first.
-                  	stream nextPutAll: '() : '.
-                  	self visit: aCollection second.
-                  	stream nextPutAll: '()'.
-                  	inlined := true]].
-
-	(aSelector = 'ifNotNil:ifNil:') ifTrue: [
-		(aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
-          		stream nextPutAll: '(($receiver = '.
-          		self visit: anObject.
-          		stream nextPutAll: ') == nil || $receiver == undefined) ? '.
-                  	self visit: aCollection second.
-                  	stream nextPutAll: '() : '.
-                  	self visit: aCollection first.
-                  	stream nextPutAll: '()'.
-                  	inlined := true]].
-                 
-        ^inlined
-!
-
-isNode: aNode ofClass: aClass
-	^aNode isValueNode and: [
-          	aNode value class = aClass or: [
-          		aNode value = 'self' and: [self currentClass = aClass]]]
-! !
-
-!FunCodeGenerator methodsFor: 'testing'!
-
-performOptimizations
-	^self class performOptimizations
-! !
-
-!FunCodeGenerator methodsFor: 'visiting'!
-
-send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
-	^String streamContents: [:str || tmp |
-        	tmp := stream.
-		str nextPutAll: 'smalltalk.send('.
-		str nextPutAll: aReceiver.
-		str nextPutAll: ', "', aSelector asSelector, '", ['.
-                stream := str.
-		aCollection
-	    		do: [:each | self visit: each]
-	    		separatedBy: [stream nextPutAll: ', '].
-                stream := tmp.
-                str nextPutAll: ']'.
-		aBoolean ifTrue: [
-			str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass), '.superclass || nil'].
-		str nextPutAll: ')']
-!
-
-visit: aNode
-	aNode accept: self
-!
-
-visitAssignmentNode: aNode
-	stream nextPutAll: '('.
-	self visit: aNode left.
-	stream nextPutAll: '='.
-	self visit: aNode right.
-	stream nextPutAll: ')'
-!
-
-visitBlockNode: aNode
-	stream nextPutAll: '(function('.
-	aNode parameters 
-	    do: [:each |
-		tempVariables add: each.
-		stream nextPutAll: each]
-	    separatedBy: [stream nextPutAll: ', '].
-	stream nextPutAll: '){'.
-	aNode nodes do: [:each | self visit: each].
-	stream nextPutAll: '})'
-!
-
-visitBlockSequenceNode: aNode
-	| index |
-	nestedBlocks := nestedBlocks + 1.
-	aNode nodes isEmpty
-	    ifTrue: [
-		stream nextPutAll: 'return nil;']
-	    ifFalse: [
-		aNode temps do: [:each | | temp |
-                    temp := self safeVariableNameFor: each.
-		    tempVariables add: temp.
-		    stream nextPutAll: 'var ', temp, '=nil;'; lf].
-		index := 0.
-		aNode nodes do: [:each |
-		    index := index + 1.
-		    index = aNode nodes size ifTrue: [
-			stream nextPutAll: 'return '].
-		    self visit: each.
-		    stream nextPutAll: ';']].
-	nestedBlocks := nestedBlocks - 1
-!
-
-visitCascadeNode: aNode
-	| index |
-	index := 0.
-	(tempVariables includes: '$rec') ifFalse: [
-		tempVariables add: '$rec'].
-	stream nextPutAll: '(function($rec){'.
-	aNode nodes do: [:each |
-	    index := index + 1.
-	    index = aNode nodes size ifTrue: [
-		stream nextPutAll: 'return '].
-	    each receiver: (VariableNode new value: '$rec').
-	    self visit: each.
-	    stream nextPutAll: ';'].
-	stream nextPutAll: '})('.
-	self visit: aNode receiver.
-	stream nextPutAll: ')'
-!
-
-visitClassReferenceNode: aNode
-	(referencedClasses includes: aNode value) ifFalse: [
-		referencedClasses add: aNode value].
-	stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
-!
-
-visitDynamicArrayNode: aNode
-	stream nextPutAll: '['.
-	aNode nodes 
-		do: [:each | self visit: each]
-		separatedBy: [stream nextPutAll: ','].
-	stream nextPutAll: ']'
-!
-
-visitDynamicDictionaryNode: aNode
-	stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
-		aNode nodes 
-			do: [:each | self visit: each]
-			separatedBy: [stream nextPutAll: ','].
-		stream nextPutAll: '])'
-!
-
-visitFailure: aFailure
-	self error: aFailure asString
-!
-
-visitJSStatementNode: aNode
-	stream nextPutAll: aNode source
-!
-
-visitMethodNode: aNode
-	| str currentSelector | 
-	currentSelector := aNode selector asSelector.
-	nestedBlocks := 0.
-	earlyReturn := false.
-	messageSends := #().
-	referencedClasses := #().
-	unknownVariables := #().
-	tempVariables := #().
-	argVariables := #().
-	stream 
-	    nextPutAll: 'smalltalk.method({'; lf;
-	    nextPutAll: 'selector: "', aNode selector, '",'; lf.
-	stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
-	stream nextPutAll: 'fn: function('.
-	aNode arguments 
-	    do: [:each | 
-		argVariables add: each.
-		stream nextPutAll: each]
-	    separatedBy: [stream nextPutAll: ', '].
-	stream 
-	    nextPutAll: '){'; lf;
-	    nextPutAll: 'var self=this;'; lf.
-	str := stream.
-	stream := '' writeStream.
-	aNode nodes do: [:each |
-	    self visit: each].
-	earlyReturn ifTrue: [
-	    str nextPutAll: 'var $early={};'; lf; nextPutAll: 'try{'].
-	str nextPutAll: stream contents.
-	stream := str.
-	stream 
-	    lf; 
-	    nextPutAll: 'return self;'.
-	earlyReturn ifTrue: [
-	    stream lf; nextPutAll: '} catch(e) {if(e===$early)return e[0]; throw e}'].
-	stream nextPutAll: '}'.
-	stream 
-		nextPutAll: ',', String lf, 'messageSends: ';
-		nextPutAll: messageSends asJavascript, ','; lf;
-          	nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
-		nextPutAll: 'referencedClasses: ['.
-	referencedClasses 
-		do: [:each | stream nextPutAll: each printString]
-		separatedBy: [stream nextPutAll: ','].
-	stream nextPutAll: ']'.
-	stream nextPutAll: '})'
-!
-
-visitReturnNode: aNode
-	nestedBlocks > 0 ifTrue: [
-	    earlyReturn := true].
-	nestedBlocks > 0
-	    ifTrue: [
-		stream
-		    nextPutAll: '(function(){throw $early=[']
-	    ifFalse: [stream nextPutAll: 'return '].
-	aNode nodes do: [:each |
-	    self visit: each].
-	nestedBlocks > 0 ifTrue: [
-	    stream nextPutAll: ']})()']
-!
-
-visitSendNode: aNode
-        | str receiver superSend inlined |
-        str := stream.
-        (messageSends includes: aNode selector) ifFalse: [
-                messageSends add: aNode selector].
-        stream := '' writeStream.
-        self visit: aNode receiver.
-        superSend := stream contents = 'super'.
-        receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
-        stream := str.
-	
-	self performOptimizations 
-		ifTrue: [
-			(self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
-				(self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
-                			ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
-                			ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
-		ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
-!
-
-visitSequenceNode: aNode
-	aNode temps do: [:each || temp |
-            temp := self safeVariableNameFor: each.
-	    tempVariables add: temp.
-	    stream nextPutAll: 'var ', temp, '=nil;'; lf].
-	aNode nodes do: [:each |
-	    self visit: each.
-	    stream nextPutAll: ';']
-	    separatedBy: [stream lf]
-!
-
-visitValueNode: aNode
-	stream nextPutAll: aNode value asJavascript
-!
-
-visitVariableNode: aNode
-	| varName |
-	(self currentClass allInstanceVariableNames includes: aNode value) 
-		ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
-		ifFalse: [
-                  	varName := self safeVariableNameFor: aNode value.
-			(self knownVariables includes: varName) 
-                  		ifFalse: [
-                                  	unknownVariables add: aNode value.
-                                  	aNode assigned 
-                                  		ifTrue: [stream nextPutAll: varName]
-                                  		ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
-                  		ifTrue: [
-                                  	aNode value = 'thisContext'
-                                  		ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
-                				ifFalse: [stream nextPutAll: varName]]]
-! !
-
-FunCodeGenerator class instanceVariableNames: 'performOptimizations'!
-
-!FunCodeGenerator class methodsFor: 'accessing'!
-
-performOptimizations
-	^performOptimizations ifNil: [true]
-!
-
-performOptimizations: aBoolean
-	performOptimizations := aBoolean
-! !
-
 AbstractCodeGenerator subclass: #ImpCodeGenerator
 	instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables mutables target lazyVars realVarNames'
 	package: 'Compiler-Visitors'!

+ 31 - 0
st/Kernel-Exceptions.st

@@ -49,6 +49,37 @@ signal: aString
 		signal: aString
 ! !
 
+Error subclass: #Continuation
+	instanceVariableNames: 'context'
+	package: 'Kernel-Exceptions'!
+
+!Continuation methodsFor: 'initialization'!
+
+initializeFromContext: aContext
+	"Add a cc flag to the error object so Smalltalk knows how to handle it"
+
+	super initialize.
+	context := aContext.
+	self basicAt: 'cc' put: true
+!
+
+restore
+	context resume
+!
+
+value: aBlock
+	aBlock value: self.
+	self signal
+! !
+
+!Continuation class methodsFor: 'instance creation'!
+
+currentDo: aBlock
+	^ self new 
+		initializeWithContext: thisContext home;
+		value: aBlock
+! !
+
 Error subclass: #MessageNotUnderstood
 	instanceVariableNames: 'message receiver'
 	package: 'Kernel-Exceptions'!

+ 1 - 1
st/Kernel-Objects.st

@@ -1387,7 +1387,7 @@ parseError: anException parsing: aString
 	code := String streamContents: [:s |
                   lines withIndexDo: [:l :i |
                      s nextPutAll: i asString, ': ', l, String lf]].
-	^ Error new messageText: ('Parse error on line ' , row , ' column ' , col , ' : ' , message , ' Below is code with line numbers and ===> marker inserted:' , String lf, code)
+	^ ParseError new messageText: ('Parse error on line ' , row , ' column ' , col , ' : ' , message , ' Below is code with line numbers and ===> marker inserted:' , String lf, code)
 !
 
 readJSObject: anObject

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio