Browse Source

Inliner improvements

Nicolas Petton 12 years ago
parent
commit
4bf2dee8fe

+ 46 - 2
js/Compiler-AST.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias', 'canBeInlined'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -66,6 +66,28 @@ return self;}
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_canBeInlined",
+smalltalk.method({
+selector: "canBeInlined",
+fn: function (){
+var self=this;
+return (($receiver = self['@canBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;}
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_canBeInlined_",
+smalltalk.method({
+selector: "canBeInlined:",
+fn: function (aBoolean){
+var self=this;
+(self['@canBeInlined']=aBoolean);
+return self;}
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isAliased",
 smalltalk.method({
@@ -271,6 +293,17 @@ return self;}
 }),
 smalltalk.BlockNode);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_canBeInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_outerScope", []), "_node", []), "_canInlineNonLocalReturns", []);})]);
+return self;}
+}),
+smalltalk.BlockNode);
+
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({
@@ -495,6 +528,17 @@ return self;}
 }),
 smalltalk.MethodNode);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.MethodNode);
+
 smalltalk.addMethod(
 "_classReferences",
 smalltalk.method({
@@ -629,7 +673,7 @@ smalltalk.MethodNode);
 
 
 
-smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn'], 'Compiler-AST');
+smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn', 'canBeInlined'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({

+ 66 - 2
js/Compiler-AST.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'alias', 'canBeInlined'], 'Compiler-AST');
 smalltalk.Node.comment="I am the abstract root class of the abstract syntax tree."
 smalltalk.addMethod(
 "_accept_",
@@ -97,6 +97,38 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
+smalltalk.addMethod(
+"_canBeInlined",
+smalltalk.method({
+selector: "canBeInlined",
+category: 'accessing',
+fn: function (){
+var self=this;
+return (($receiver = self['@canBeInlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return self;},
+args: [],
+source: "canBeInlined\x0a\x09^ canBeInlined ifNil: [ false ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_canBeInlined_",
+smalltalk.method({
+selector: "canBeInlined:",
+category: 'accessing',
+fn: function (aBoolean){
+var self=this;
+(self['@canBeInlined']=aBoolean);
+return self;},
+args: ["aBoolean"],
+source: "canBeInlined: aBoolean\x0a\x09canBeInlined := aBoolean",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 "_isAliased",
 smalltalk.method({
@@ -392,6 +424,22 @@ referencedClasses: []
 }),
 smalltalk.BlockNode);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_canBeInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_outerScope", []), "_node", []), "_canInlineNonLocalReturns", []);})]);
+return self;},
+args: [],
+source: "canInlineNonLocalReturns\x0a\x09^ self canBeInlined and: [\x0a\x09\x09self scope outerScope node canInlineNonLocalReturns]",
+messageSends: ["and:", "canBeInlined", "canInlineNonLocalReturns", "node", "outerScope", "scope"],
+referencedClasses: []
+}),
+smalltalk.BlockNode);
+
 smalltalk.addMethod(
 "_isBlockNode",
 smalltalk.method({
@@ -711,6 +759,22 @@ referencedClasses: []
 }),
 smalltalk.MethodNode);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+category: 'testing',
+fn: function (){
+var self=this;
+return true;
+return self;},
+args: [],
+source: "canInlineNonLocalReturns\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.MethodNode);
+
 smalltalk.addMethod(
 "_classReferences",
 smalltalk.method({
@@ -905,7 +969,7 @@ smalltalk.MethodNode);
 
 
 
-smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn'], 'Compiler-AST');
+smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn', 'canBeInlined'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({

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

@@ -8,6 +8,9 @@ smalltalk.addClass('ParseError', smalltalk.CompilerError, [], 'Compiler-Exceptio
 smalltalk.addClass('SemanticError', smalltalk.CompilerError, [], 'Compiler-Exceptions');
 
 
+smalltalk.addClass('InliningError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+
+
 smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
 smalltalk.addMethod(
 "_variableName",

+ 3 - 0
js/Compiler-Exceptions.js

@@ -9,6 +9,9 @@ smalltalk.addClass('SemanticError', smalltalk.CompilerError, [], 'Compiler-Excep
 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('InliningError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+
+
 smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
 smalltalk.InvalidAssignmentError.comment="I get signaled when a pseudo variable gets assigned."
 smalltalk.addMethod(

+ 132 - 154
js/Compiler-IR.deploy.js

@@ -81,7 +81,7 @@ smalltalk.addMethod(
 "_visitBlockNode_",
 smalltalk.method({
 selector: "visitBlockNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 (function($rec){smalltalk.send($rec, "_with_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_temps", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_tempDeclaration", []), "_name_", [smalltalk.send(each, "_name", [])]);})]);return smalltalk.send(self, "_visitBlockNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);return smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_parameters", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_closure", []));
 return self;}
@@ -92,7 +92,7 @@ smalltalk.addMethod(
 "_visitBlockSequenceNode_",
 smalltalk.method({
 selector: "visitBlockSequenceNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var $1,$2,$3,$4,$5;
 $1=(function(){
@@ -105,7 +105,7 @@ return smalltalk.send($3,"_do_",[$2]);
 $4=smalltalk.send(self,"_builder",[]);
 $5=smalltalk.send($4,"_blockSequence",[]);
 smalltalk.send($5,"_with_",[$1]);
-return self}
+return self;}
 }),
 smalltalk.IRASTTranslator);
 
@@ -124,9 +124,9 @@ smalltalk.addMethod(
 "_visitMethodNode_",
 smalltalk.method({
 selector: "visitMethodNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
-(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(aNode, "_scope", [])]);smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_arguments", [])]);smalltalk.send($rec, "_selector_", [smalltalk.send(aNode, "_selector", [])]);smalltalk.send($rec, "_messageSends_", [smalltalk.send(aNode, "_messageSends", [])]);return smalltalk.send($rec, "_classReferences_", [smalltalk.send(aNode, "_classReferences", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_method", []));
+(function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_arguments", [])]);smalltalk.send($rec, "_selector_", [smalltalk.send(aNode, "_selector", [])]);smalltalk.send($rec, "_messageSends_", [smalltalk.send(aNode, "_messageSends", [])]);return smalltalk.send($rec, "_classReferences_", [smalltalk.send(aNode, "_classReferences", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_method", []));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_temps", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_tempDeclaration", []), "_name_", [smalltalk.send(each, "_name", [])]);})]);
 ((($receiver = smalltalk.send(aNode, "_hasNonLocalReturn", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_nonLocalReturnHandling", []), "_with_", [(function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);})() : (function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_nonLocalReturnHandling", []), "_with_", [(function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);}), (function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]));
 ((($receiver = smalltalk.send(aNode, "_hasLocalReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_return", []), "_with_", [(function(){return smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_pseudoVars", []), "_at_", ["self"])]);})]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_return", []), "_with_", [(function(){return smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_pseudoVars", []), "_at_", ["self"])]);})]);})]));
@@ -149,7 +149,7 @@ smalltalk.addMethod(
 "_visitSendNode_",
 smalltalk.method({
 selector: "visitSendNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var send=nil;
 (send=smalltalk.send(smalltalk.send(self, "_builder", []), "_send", []));
@@ -164,7 +164,7 @@ smalltalk.addMethod(
 "_visitSequenceNode_",
 smalltalk.method({
 selector: "visitSequenceNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_sequence", []), "_with_", [(function(){return smalltalk.send(self, "_visitSequenceNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);
 return self;}
@@ -186,7 +186,7 @@ smalltalk.addMethod(
 "_visitVariableNode_",
 smalltalk.method({
 selector: "visitVariableNode:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(aNode, "_binding", [])]);
 return self;}
@@ -213,7 +213,7 @@ smalltalk.addMethod(
 "_resolve_",
 smalltalk.method({
 selector: "resolve:",
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(aNode, "_isBlockSequenceNode", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_resolve_", [each]);})]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_resolve_", [each]);})]);})]));
 ((($receiver = smalltalk.send(aNode, "_shouldBeAliased", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){var alias=nil;
@@ -287,7 +287,7 @@ smalltalk.addMethod(
 "_alias",
 smalltalk.method({
 selector: "alias",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(self, "_add_", [(smalltalk.IRAlias || IRAlias)]);
 return self;}
@@ -320,7 +320,7 @@ smalltalk.addMethod(
 "_blockSequence",
 smalltalk.method({
 selector: "blockSequence",
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(self, "_add_", [(smalltalk.IRBlockSequence || IRBlockSequence)]);
 return self;}
@@ -661,7 +661,7 @@ smalltalk.addMethod(
 "_isClosure",
 smalltalk.method({
 selector: "isClosure",
-fn: function (){
+fn: function () {
 var self=this;
 return false;
 return self;}
@@ -669,9 +669,9 @@ return self;}
 smalltalk.IRInstruction);
 
 smalltalk.addMethod(
-"_isInlined",
+"_isReturn",
 smalltalk.method({
-selector: "isInlined",
+selector: "isReturn",
 fn: function (){
 var self=this;
 return false;
@@ -722,7 +722,7 @@ smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
 selector: "accept:",
-fn: function (aVisitor){
+fn: function (aVisitor) {
 var self=this;
 smalltalk.send(aVisitor, "_visitIRAlias_", [self]);
 return self;}
@@ -731,75 +731,7 @@ smalltalk.IRAlias);
 
 
 
-smalltalk.addClass('IRNonLocalReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRNonLocalReturn_", [self]);
-return self;}
-}),
-smalltalk.IRNonLocalReturn);
-
-
-
-smalltalk.addClass('IRNonLocalReturnHandling', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRNonLocalReturnHandling_", [self]);
-return self;}
-}),
-smalltalk.IRNonLocalReturnHandling);
-
-
-
-smalltalk.addClass('IRReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRReturn_", [self]);
-return self;}
-}),
-smalltalk.IRReturn);
-
-
-
-smalltalk.addClass('IRScopedInstruction', smalltalk.IRInstruction, ['scope'], 'Compiler-IR');
-smalltalk.addMethod(
-"_scope",
-smalltalk.method({
-selector: "scope",
-fn: function (){
-var self=this;
-return self['@scope'];
-return self;}
-}),
-smalltalk.IRScopedInstruction);
-
-smalltalk.addMethod(
-"_scope_",
-smalltalk.method({
-selector: "scope:",
-fn: function (aScope){
-var self=this;
-smalltalk.send(aScope, "_instruction_", [self]);
-(self['@scope']=aScope);
-return self;}
-}),
-smalltalk.IRScopedInstruction);
-
-
-
-smalltalk.addClass('IRClosure', smalltalk.IRScopedInstruction, ['arguments', 'inlined'], 'Compiler-IR');
+smalltalk.addClass('IRClosure', smalltalk.IRInstruction, ['arguments'], 'Compiler-IR');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -815,9 +747,9 @@ smalltalk.addMethod(
 "_arguments",
 smalltalk.method({
 selector: "arguments",
-fn: function () {
+fn: function (){
 var self=this;
-return self['@arguments'];
+return (($receiver = self['@arguments']) == nil || $receiver == undefined) ? (function(){return [];})() : $receiver;
 return self;}
 }),
 smalltalk.IRClosure);
@@ -833,53 +765,20 @@ return self;}
 }),
 smalltalk.IRClosure);
 
-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.IRClosure);
-
-smalltalk.addMethod(
-"_inlined_",
-smalltalk.method({
-selector: "inlined:",
-fn: function (aBoolean){
-var self=this;
-(self['@inlined']=aBoolean);
-return self;}
-}),
-smalltalk.IRClosure);
-
 smalltalk.addMethod(
 "_isClosure",
 smalltalk.method({
 selector: "isClosure",
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;}
 }),
 smalltalk.IRClosure);
 
-smalltalk.addMethod(
-"_isInlined",
-smalltalk.method({
-selector: "isInlined",
-fn: function (){
-var self=this;
-return smalltalk.send(self, "_inlined", []);
-return self;}
-}),
-smalltalk.IRClosure);
 
 
-
-smalltalk.addClass('IRMethod', smalltalk.IRScopedInstruction, ['source', 'selector', 'classReferences', 'messageSends', 'arguments', 'internalVariables'], 'Compiler-IR');
+smalltalk.addClass('IRMethod', smalltalk.IRInstruction, ['source', 'selector', 'classReferences', 'messageSends', 'arguments', 'internalVariables'], 'Compiler-IR');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -1014,69 +913,89 @@ smalltalk.IRMethod);
 
 
 
-smalltalk.addClass('IRSend', smalltalk.IRInstruction, ['selector', 'classSend', 'inlined'], 'Compiler-IR');
+smalltalk.addClass('IRNonLocalReturnHandling', smalltalk.IRInstruction, [], 'Compiler-IR');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
 selector: "accept:",
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitIRSend_", [self]);
+smalltalk.send(aVisitor, "_visitIRNonLocalReturnHandling_", [self]);
 return self;}
 }),
-smalltalk.IRSend);
+smalltalk.IRNonLocalReturnHandling);
+
 
+
+smalltalk.addClass('IRReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
 smalltalk.addMethod(
-"_classSend",
+"_accept_",
 smalltalk.method({
-selector: "classSend",
+selector: "accept:",
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRReturn_", [self]);
+return self;}
+}),
+smalltalk.IRReturn);
+
+smalltalk.addMethod(
+"_isReturn",
+smalltalk.method({
+selector: "isReturn",
 fn: function (){
 var self=this;
-return self['@classSend'];
+return true;
 return self;}
 }),
-smalltalk.IRSend);
+smalltalk.IRReturn);
+
+
 
+smalltalk.addClass('IRNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-IR');
 smalltalk.addMethod(
-"_classSend_",
+"_accept_",
 smalltalk.method({
-selector: "classSend:",
-fn: function (aClass){
+selector: "accept:",
+fn: function (aVisitor) {
 var self=this;
-(self['@classSend']=aClass);
+smalltalk.send(aVisitor, "_visitIRNonLocalReturn_", [self]);
 return self;}
 }),
-smalltalk.IRSend);
+smalltalk.IRNonLocalReturn);
 
+
+
+smalltalk.addClass('IRSend', smalltalk.IRInstruction, ['selector', 'classSend'], 'Compiler-IR');
 smalltalk.addMethod(
-"_inlined",
+"_accept_",
 smalltalk.method({
-selector: "inlined",
-fn: function (){
+selector: "accept:",
+fn: function (aVisitor) {
 var self=this;
-return (($receiver = self['@inlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+smalltalk.send(aVisitor, "_visitIRSend_", [self]);
 return self;}
 }),
 smalltalk.IRSend);
 
 smalltalk.addMethod(
-"_inlined_",
+"_classSend",
 smalltalk.method({
-selector: "inlined:",
-fn: function (aBoolean){
+selector: "classSend",
+fn: function () {
 var self=this;
-(self['@inlined']=aBoolean);
+return self['@classSend'];
 return self;}
 }),
 smalltalk.IRSend);
 
 smalltalk.addMethod(
-"_isInlined",
+"_classSend_",
 smalltalk.method({
-selector: "isInlined",
-fn: function (){
+selector: "classSend:",
+fn: function (aClass) {
 var self=this;
-return smalltalk.send(self, "_inlined", []);
+(self['@classSend']=aClass);
 return self;}
 }),
 smalltalk.IRSend);
@@ -1135,7 +1054,7 @@ smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
 selector: "accept:",
-fn: function (aVisitor){
+fn: function (aVisitor) {
 var self=this;
 smalltalk.send(aVisitor, "_visitIRBlockSequence_", [self]);
 return self;}
@@ -1156,6 +1075,17 @@ return self;}
 }),
 smalltalk.IRStatement);
 
+smalltalk.addMethod(
+"_isReturn",
+smalltalk.method({
+selector: "isReturn",
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), "_isReturn", []);
+return self;}
+}),
+smalltalk.IRStatement);
+
 smalltalk.addMethod(
 "_pc",
 smalltalk.method({
@@ -1329,7 +1259,7 @@ smalltalk.addMethod(
 "_visitIRAlias_",
 smalltalk.method({
 selector: "visitIRAlias:",
-fn: function (anIRAlias){
+fn: function (anIRAlias) {
 var self=this;
 smalltalk.send(self, "_visitIRAssignment_", [anIRAlias]);
 return self;}
@@ -1351,7 +1281,7 @@ smalltalk.addMethod(
 "_visitIRBlockSequence_",
 smalltalk.method({
 selector: "visitIRBlockSequence:",
-fn: function (anIRBlockSequence){
+fn: function (anIRBlockSequence) {
 var self=this;
 smalltalk.send(self, "_visitIRSequence_", [anIRBlockSequence]);
 return self;}
@@ -1369,6 +1299,39 @@ return self;}
 }),
 smalltalk.IRVisitor);
 
+smalltalk.addMethod(
+"_visitIRInlinedClosure_",
+smalltalk.method({
+selector: "visitIRInlinedClosure:",
+fn: function (anIRClosure){
+var self=this;
+smalltalk.send(self, "_visitIRClosure_", [anIRClosure]);
+return self;}
+}),
+smalltalk.IRVisitor);
+
+smalltalk.addMethod(
+"_visitIRInlinedIfTrue_",
+smalltalk.method({
+selector: "visitIRInlinedIfTrue:",
+fn: function (anIRInlinedIfTrue) {
+var self=this;
+smalltalk.send(self, "_visitIRInlinedSend_", [anIRInlinedIfTrue]);
+return self;}
+}),
+smalltalk.IRVisitor);
+
+smalltalk.addMethod(
+"_visitIRInlinedSend_",
+smalltalk.method({
+selector: "visitIRInlinedSend:",
+fn: function (anIRInlinedSend) {
+var self=this;
+smalltalk.send(self, "_visitIRSend_", [anIRInlinedSend]);
+return self;}
+}),
+smalltalk.IRVisitor);
+
 smalltalk.addMethod(
 "_visitIRInstruction_",
 smalltalk.method({
@@ -1542,7 +1505,7 @@ smalltalk.addMethod(
 "_stream_",
 smalltalk.method({
 selector: "stream:",
-fn: function (aStream){
+fn: function (aStream) {
 var self=this;
 (self['@stream']=aStream);
 return self;}
@@ -1568,7 +1531,7 @@ smalltalk.method({
 selector: "visitIRBlockSequence:",
 fn: function (anIRBlockSequence){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutSequenceWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})]));})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutSequenceWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", []), "_isReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", []), "_isReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})]));})]);
 return self;}
 }),
 smalltalk.IRJSTranslator);
@@ -1632,7 +1595,7 @@ smalltalk.addMethod(
 "_visitIRSend_",
 smalltalk.method({
 selector: "visitIRSend:",
-fn: function (anIRSend){
+fn: function (anIRSend) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["smalltalk.send("]);
 smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRSend, "_instructions", []), "_first", [])]);
@@ -1812,6 +1775,21 @@ return self;}
 }),
 smalltalk.JSStream);
 
+smalltalk.addMethod(
+"_nextPutIf_with_",
+smalltalk.method({
+selector: "nextPutIf:with:",
+fn: function (aBlock, anotherBlock){
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["if("]);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(anotherBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["}"]);
+return self;}
+}),
+smalltalk.JSStream);
+
 smalltalk.addMethod(
 "_nextPutMethodDeclaration_with_",
 smalltalk.method({
@@ -1844,11 +1822,11 @@ smalltalk.addMethod(
 "_nextPutNonLocalReturnWith_",
 smalltalk.method({
 selector: "nextPutNonLocalReturnWith:",
-fn: function (aBlock) {
+fn: function (aBlock){
 var self=this;
-smalltalk.send(self['@stream'], "_nextPutAll_", ["(function(){throw $early=["]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["throw $early=["]);
 smalltalk.send(aBlock, "_value", []);
-smalltalk.send(self['@stream'], "_nextPutAll_", ["]})()"]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["]"]);
 return self;}
 }),
 smalltalk.JSStream);

+ 192 - 224
js/Compiler-IR.js

@@ -118,7 +118,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitBlockNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 (function($rec){smalltalk.send($rec, "_with_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_temps", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_tempDeclaration", []), "_name_", [smalltalk.send(each, "_name", [])]);})]);return smalltalk.send(self, "_visitBlockNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);return smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_parameters", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_closure", []));
 return self;},
@@ -134,7 +134,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitBlockSequenceNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var $1,$2,$3,$4,$5;
 $1=(function(){
@@ -147,7 +147,7 @@ return smalltalk.send($3,"_do_",[$2]);
 $4=smalltalk.send(self,"_builder",[]);
 $5=smalltalk.send($4,"_blockSequence",[]);
 smalltalk.send($5,"_with_",[$1]);
-return self},
+return self;},
 args: ["aNode"],
 source: "visitBlockSequenceNode: aNode\x0a\x09self builder blockSequence with: [\x0a\x09\x09aNode nodes do: [ :each | self visit: each ]]",
 messageSends: ["with:", "do:", "visit:", "nodes", "blockSequence", "builder"],
@@ -176,16 +176,16 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitMethodNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
-(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(aNode, "_scope", [])]);smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_arguments", [])]);smalltalk.send($rec, "_selector_", [smalltalk.send(aNode, "_selector", [])]);smalltalk.send($rec, "_messageSends_", [smalltalk.send(aNode, "_messageSends", [])]);return smalltalk.send($rec, "_classReferences_", [smalltalk.send(aNode, "_classReferences", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_method", []));
+(function($rec){smalltalk.send($rec, "_source_", [smalltalk.send(self, "_source", [])]);smalltalk.send($rec, "_arguments_", [smalltalk.send(aNode, "_arguments", [])]);smalltalk.send($rec, "_selector_", [smalltalk.send(aNode, "_selector", [])]);smalltalk.send($rec, "_messageSends_", [smalltalk.send(aNode, "_messageSends", [])]);return smalltalk.send($rec, "_classReferences_", [smalltalk.send(aNode, "_classReferences", [])]);})(smalltalk.send(smalltalk.send(self, "_builder", []), "_method", []));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_temps", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_tempDeclaration", []), "_name_", [smalltalk.send(each, "_name", [])]);})]);
 ((($receiver = smalltalk.send(aNode, "_hasNonLocalReturn", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_nonLocalReturnHandling", []), "_with_", [(function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);})() : (function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_nonLocalReturnHandling", []), "_with_", [(function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);}), (function(){return smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]));
 ((($receiver = smalltalk.send(aNode, "_hasLocalReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_return", []), "_with_", [(function(){return smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_pseudoVars", []), "_at_", ["self"])]);})]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_return", []), "_with_", [(function(){return smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_scope", []), "_pseudoVars", []), "_at_", ["self"])]);})]);})]));
 return self;},
 args: ["aNode"],
-source: "visitMethodNode: aNode\x0a\x09self builder method \x0a\x09\x09scope: aNode scope;\x0a\x09\x09source: self source;\x0a\x09\x09arguments: aNode arguments;\x0a\x09\x09selector: aNode selector;\x0a\x09\x09messageSends: aNode messageSends;\x0a\x09\x09classReferences: aNode classReferences.\x0a\x0a\x09aNode scope temps do: [ :each |\x0a\x09\x09self builder tempDeclaration name: each name ].\x0a\x09aNode hasNonLocalReturn \x0a\x09\x09ifTrue: [ self builder nonLocalReturnHandling with: [\x0a\x09\x09\x09super visitMethodNode: aNode ]]\x0a\x09\x09ifFalse: [ super visitMethodNode: aNode ].\x0a\x0a\x09aNode hasLocalReturn ifFalse: [\x0a\x09\x09self builder return with: [\x0a\x09\x09\x09self builder variable: (aNode scope pseudoVars at: 'self') ]]",
-messageSends: ["scope:", "scope", "source:", "source", "arguments:", "arguments", "selector:", "selector", "messageSends:", "messageSends", "classReferences:", "classReferences", "method", "builder", "do:", "temps", "name:", "tempDeclaration", "name", "ifTrue:ifFalse:", "hasNonLocalReturn", "with:", "nonLocalReturnHandling", "visitMethodNode:", "ifFalse:", "hasLocalReturn", "return", "variable:", "at:", "pseudoVars"],
+source: "visitMethodNode: aNode\x0a\x09self builder method \x0a\x09\x09source: self source;\x0a\x09\x09arguments: aNode arguments;\x0a\x09\x09selector: aNode selector;\x0a\x09\x09messageSends: aNode messageSends;\x0a\x09\x09classReferences: aNode classReferences.\x0a\x0a\x09aNode scope temps do: [ :each |\x0a\x09\x09self builder tempDeclaration name: each name ].\x0a\x09aNode hasNonLocalReturn \x0a\x09\x09ifTrue: [ self builder nonLocalReturnHandling with: [\x0a\x09\x09\x09super visitMethodNode: aNode ]]\x0a\x09\x09ifFalse: [ super visitMethodNode: aNode ].\x0a\x0a\x09aNode hasLocalReturn ifFalse: [\x0a\x09\x09self builder return with: [\x0a\x09\x09\x09self builder variable: (aNode scope pseudoVars at: 'self') ]]",
+messageSends: ["source:", "source", "arguments:", "arguments", "selector:", "selector", "messageSends:", "messageSends", "classReferences:", "classReferences", "method", "builder", "do:", "temps", "scope", "name:", "tempDeclaration", "name", "ifTrue:ifFalse:", "hasNonLocalReturn", "with:", "nonLocalReturnHandling", "visitMethodNode:", "ifFalse:", "hasLocalReturn", "return", "variable:", "at:", "pseudoVars"],
 referencedClasses: []
 }),
 smalltalk.IRASTTranslator);
@@ -211,7 +211,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitSendNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 var send=nil;
 (send=smalltalk.send(smalltalk.send(self, "_builder", []), "_send", []));
@@ -231,7 +231,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitSequenceNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_builder", []), "_sequence", []), "_with_", [(function(){return smalltalk.send(self, "_visitSequenceNode_", [aNode], smalltalk.IRASTTranslator.superclass || nil);})]);
 return self;},
@@ -263,7 +263,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitVariableNode:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_builder", []), "_variable_", [smalltalk.send(aNode, "_binding", [])]);
 return self;},
@@ -301,7 +301,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "resolve:",
 category: 'visiting',
-fn: function (aNode){
+fn: function (aNode) {
 var self=this;
 ((($receiver = smalltalk.send(aNode, "_isBlockSequenceNode", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_resolve_", [each]);})]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_do_", [(function(each){return smalltalk.send(self, "_resolve_", [each]);})]);})]));
 ((($receiver = smalltalk.send(aNode, "_shouldBeAliased", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){var alias=nil;
@@ -406,7 +406,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "alias",
 category: 'building',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(self, "_add_", [(smalltalk.IRAlias || IRAlias)]);
 return self;},
@@ -454,7 +454,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "blockSequence",
 category: 'building',
-fn: function (){
+fn: function () {
 var self=this;
 return smalltalk.send(self, "_add_", [(smalltalk.IRBlockSequence || IRBlockSequence)]);
 return self;},
@@ -946,7 +946,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "isClosure",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return false;
 return self;},
@@ -958,16 +958,16 @@ referencedClasses: []
 smalltalk.IRInstruction);
 
 smalltalk.addMethod(
-"_isInlined",
+"_isReturn",
 smalltalk.method({
-selector: "isInlined",
+selector: "isReturn",
 category: 'testing',
 fn: function (){
 var self=this;
 return false;
 return self;},
 args: [],
-source: "isInlined\x0a\x09^ false",
+source: "isReturn\x0a\x09^ false",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1032,7 +1032,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "accept:",
 category: 'visiting',
-fn: function (aVisitor){
+fn: function (aVisitor) {
 var self=this;
 smalltalk.send(aVisitor, "_visitIRAlias_", [self]);
 return self;},
@@ -1045,103 +1045,7 @@ smalltalk.IRAlias);
 
 
 
-smalltalk.addClass('IRNonLocalReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.IRNonLocalReturn.comment="I am a non local return instruction.\x0aNon local returns are handled using a try/catch JS statement.\x0a\x0aSee IRNonLocalReturnHandling class"
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRNonLocalReturn_", [self]);
-return self;},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitIRNonLocalReturn: self",
-messageSends: ["visitIRNonLocalReturn:"],
-referencedClasses: []
-}),
-smalltalk.IRNonLocalReturn);
-
-
-
-smalltalk.addClass('IRNonLocalReturnHandling', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.IRNonLocalReturnHandling.comment="I represent a non local return handling instruction.\x0aNon local returns are handled with a try/catch statement"
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRNonLocalReturnHandling_", [self]);
-return self;},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitIRNonLocalReturnHandling: self",
-messageSends: ["visitIRNonLocalReturnHandling:"],
-referencedClasses: []
-}),
-smalltalk.IRNonLocalReturnHandling);
-
-
-
-smalltalk.addClass('IRReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
-smalltalk.IRReturn.comment="I am a local return instruction."
-smalltalk.addMethod(
-"_accept_",
-smalltalk.method({
-selector: "accept:",
-category: 'visiting',
-fn: function (aVisitor) {
-var self=this;
-smalltalk.send(aVisitor, "_visitIRReturn_", [self]);
-return self;},
-args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitIRReturn: self",
-messageSends: ["visitIRReturn:"],
-referencedClasses: []
-}),
-smalltalk.IRReturn);
-
-
-
-smalltalk.addClass('IRScopedInstruction', smalltalk.IRInstruction, ['scope'], 'Compiler-IR');
-smalltalk.addMethod(
-"_scope",
-smalltalk.method({
-selector: "scope",
-category: 'accessing',
-fn: function (){
-var self=this;
-return self['@scope'];
-return self;},
-args: [],
-source: "scope\x0a\x09^ scope",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.IRScopedInstruction);
-
-smalltalk.addMethod(
-"_scope_",
-smalltalk.method({
-selector: "scope:",
-category: 'accessing',
-fn: function (aScope){
-var self=this;
-smalltalk.send(aScope, "_instruction_", [self]);
-(self['@scope']=aScope);
-return self;},
-args: ["aScope"],
-source: "scope: aScope\x0a\x09aScope instruction: self.\x0a\x09scope := aScope",
-messageSends: ["instruction:"],
-referencedClasses: []
-}),
-smalltalk.IRScopedInstruction);
-
-
-
-smalltalk.addClass('IRClosure', smalltalk.IRScopedInstruction, ['arguments', 'inlined'], 'Compiler-IR');
+smalltalk.addClass('IRClosure', smalltalk.IRInstruction, ['arguments'], 'Compiler-IR');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -1163,13 +1067,13 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "arguments",
 category: 'accessing',
-fn: function () {
+fn: function (){
 var self=this;
-return self['@arguments'];
+return (($receiver = self['@arguments']) == nil || $receiver == undefined) ? (function(){return [];})() : $receiver;
 return self;},
 args: [],
-source: "arguments\x0a\x09^ arguments",
-messageSends: [],
+source: "arguments\x0a\x09^ arguments ifNil: [ #() ]",
+messageSends: ["ifNil:"],
 referencedClasses: []
 }),
 smalltalk.IRClosure);
@@ -1190,44 +1094,12 @@ referencedClasses: []
 }),
 smalltalk.IRClosure);
 
-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.IRClosure);
-
-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.IRClosure);
-
 smalltalk.addMethod(
 "_isClosure",
 smalltalk.method({
 selector: "isClosure",
 category: 'testing',
-fn: function (){
+fn: function () {
 var self=this;
 return true;
 return self;},
@@ -1238,25 +1110,9 @@ referencedClasses: []
 }),
 smalltalk.IRClosure);
 
-smalltalk.addMethod(
-"_isInlined",
-smalltalk.method({
-selector: "isInlined",
-category: 'testing',
-fn: function (){
-var self=this;
-return smalltalk.send(self, "_inlined", []);
-return self;},
-args: [],
-source: "isInlined\x0a\x09^ self inlined",
-messageSends: ["inlined"],
-referencedClasses: []
-}),
-smalltalk.IRClosure);
 
 
-
-smalltalk.addClass('IRMethod', smalltalk.IRScopedInstruction, ['source', 'selector', 'classReferences', 'messageSends', 'arguments', 'internalVariables'], 'Compiler-IR');
+smalltalk.addClass('IRMethod', smalltalk.IRInstruction, ['source', 'selector', 'classReferences', 'messageSends', 'arguments', 'internalVariables'], 'Compiler-IR');
 smalltalk.IRMethod.comment="I am a method instruction"
 smalltalk.addMethod(
 "_accept_",
@@ -1452,8 +1308,8 @@ smalltalk.IRMethod);
 
 
 
-smalltalk.addClass('IRSend', smalltalk.IRInstruction, ['selector', 'classSend', 'inlined'], 'Compiler-IR');
-smalltalk.IRSend.comment="I am a message send instruction. "
+smalltalk.addClass('IRNonLocalReturnHandling', smalltalk.IRInstruction, [], 'Compiler-IR');
+smalltalk.IRNonLocalReturnHandling.comment="I represent a non local return handling instruction.\x0aNon local returns are handled with a try/catch statement"
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -1461,91 +1317,119 @@ selector: "accept:",
 category: 'visiting',
 fn: function (aVisitor) {
 var self=this;
-smalltalk.send(aVisitor, "_visitIRSend_", [self]);
+smalltalk.send(aVisitor, "_visitIRNonLocalReturnHandling_", [self]);
 return self;},
 args: ["aVisitor"],
-source: "accept: aVisitor\x0a\x09aVisitor visitIRSend: self",
-messageSends: ["visitIRSend:"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRNonLocalReturnHandling: self",
+messageSends: ["visitIRNonLocalReturnHandling:"],
 referencedClasses: []
 }),
-smalltalk.IRSend);
+smalltalk.IRNonLocalReturnHandling);
+
 
+
+smalltalk.addClass('IRReturn', smalltalk.IRInstruction, [], 'Compiler-IR');
+smalltalk.IRReturn.comment="I am a local return instruction."
 smalltalk.addMethod(
-"_classSend",
+"_accept_",
 smalltalk.method({
-selector: "classSend",
-category: 'accessing',
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
+var self=this;
+smalltalk.send(aVisitor, "_visitIRReturn_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRReturn: self",
+messageSends: ["visitIRReturn:"],
+referencedClasses: []
+}),
+smalltalk.IRReturn);
+
+smalltalk.addMethod(
+"_isReturn",
+smalltalk.method({
+selector: "isReturn",
+category: 'testing',
 fn: function (){
 var self=this;
-return self['@classSend'];
+return true;
 return self;},
 args: [],
-source: "classSend\x0a\x09^ classSend",
+source: "isReturn\x0a\x09^ true",
 messageSends: [],
 referencedClasses: []
 }),
-smalltalk.IRSend);
+smalltalk.IRReturn);
+
 
+
+smalltalk.addClass('IRNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-IR');
+smalltalk.IRNonLocalReturn.comment="I am a non local return instruction.\x0aNon local returns are handled using a try/catch JS statement.\x0a\x0aSee IRNonLocalReturnHandling class"
 smalltalk.addMethod(
-"_classSend_",
+"_accept_",
 smalltalk.method({
-selector: "classSend:",
-category: 'accessing',
-fn: function (aClass){
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
 var self=this;
-(self['@classSend']=aClass);
+smalltalk.send(aVisitor, "_visitIRNonLocalReturn_", [self]);
 return self;},
-args: ["aClass"],
-source: "classSend: aClass\x0a\x09classSend := aClass",
-messageSends: [],
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRNonLocalReturn: self",
+messageSends: ["visitIRNonLocalReturn:"],
 referencedClasses: []
 }),
-smalltalk.IRSend);
+smalltalk.IRNonLocalReturn);
+
 
+
+smalltalk.addClass('IRSend', smalltalk.IRInstruction, ['selector', 'classSend'], 'Compiler-IR');
+smalltalk.IRSend.comment="I am a message send instruction. "
 smalltalk.addMethod(
-"_inlined",
+"_accept_",
 smalltalk.method({
-selector: "inlined",
-category: 'accessing',
-fn: function (){
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor) {
 var self=this;
-return (($receiver = self['@inlined']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+smalltalk.send(aVisitor, "_visitIRSend_", [self]);
 return self;},
-args: [],
-source: "inlined\x0a\x09^ inlined ifNil: [ false ]",
-messageSends: ["ifNil:"],
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRSend: self",
+messageSends: ["visitIRSend:"],
 referencedClasses: []
 }),
 smalltalk.IRSend);
 
 smalltalk.addMethod(
-"_inlined_",
+"_classSend",
 smalltalk.method({
-selector: "inlined:",
+selector: "classSend",
 category: 'accessing',
-fn: function (aBoolean){
+fn: function () {
 var self=this;
-(self['@inlined']=aBoolean);
+return self['@classSend'];
 return self;},
-args: ["aBoolean"],
-source: "inlined: aBoolean\x0a\x09inlined := aBoolean",
+args: [],
+source: "classSend\x0a\x09^ classSend",
 messageSends: [],
 referencedClasses: []
 }),
 smalltalk.IRSend);
 
 smalltalk.addMethod(
-"_isInlined",
+"_classSend_",
 smalltalk.method({
-selector: "isInlined",
-category: 'testing',
-fn: function (){
+selector: "classSend:",
+category: 'accessing',
+fn: function (aClass) {
 var self=this;
-return smalltalk.send(self, "_inlined", []);
+(self['@classSend']=aClass);
 return self;},
-args: [],
-source: "isInlined\x0a\x09^ self inlined",
-messageSends: ["inlined"],
+args: ["aClass"],
+source: "classSend: aClass\x0a\x09classSend := aClass",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.IRSend);
@@ -1625,7 +1509,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "accept:",
 category: 'visiting',
-fn: function (aVisitor){
+fn: function (aVisitor) {
 var self=this;
 smalltalk.send(aVisitor, "_visitIRBlockSequence_", [self]);
 return self;},
@@ -1656,6 +1540,22 @@ referencedClasses: []
 }),
 smalltalk.IRStatement);
 
+smalltalk.addMethod(
+"_isReturn",
+smalltalk.method({
+selector: "isReturn",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_instructions", []), "_first", []), "_isReturn", []);
+return self;},
+args: [],
+source: "isReturn\x0a\x09^ self instructions first isReturn",
+messageSends: ["isReturn", "first", "instructions"],
+referencedClasses: []
+}),
+smalltalk.IRStatement);
+
 smalltalk.addMethod(
 "_pc",
 smalltalk.method({
@@ -1903,7 +1803,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitIRAlias:",
 category: 'visiting',
-fn: function (anIRAlias){
+fn: function (anIRAlias) {
 var self=this;
 smalltalk.send(self, "_visitIRAssignment_", [anIRAlias]);
 return self;},
@@ -1935,7 +1835,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitIRBlockSequence:",
 category: 'visiting',
-fn: function (anIRBlockSequence){
+fn: function (anIRBlockSequence) {
 var self=this;
 smalltalk.send(self, "_visitIRSequence_", [anIRBlockSequence]);
 return self;},
@@ -1962,6 +1862,54 @@ referencedClasses: []
 }),
 smalltalk.IRVisitor);
 
+smalltalk.addMethod(
+"_visitIRInlinedClosure_",
+smalltalk.method({
+selector: "visitIRInlinedClosure:",
+category: 'visiting',
+fn: function (anIRClosure){
+var self=this;
+smalltalk.send(self, "_visitIRClosure_", [anIRClosure]);
+return self;},
+args: ["anIRClosure"],
+source: "visitIRInlinedClosure: anIRClosure\x0a\x09self visitIRClosure: anIRClosure",
+messageSends: ["visitIRClosure:"],
+referencedClasses: []
+}),
+smalltalk.IRVisitor);
+
+smalltalk.addMethod(
+"_visitIRInlinedIfTrue_",
+smalltalk.method({
+selector: "visitIRInlinedIfTrue:",
+category: 'visiting',
+fn: function (anIRInlinedIfTrue) {
+var self=this;
+smalltalk.send(self, "_visitIRInlinedSend_", [anIRInlinedIfTrue]);
+return self;},
+args: ["anIRInlinedIfTrue"],
+source: "visitIRInlinedIfTrue: anIRInlinedIfTrue\x0a\x09self visitIRInlinedSend: anIRInlinedIfTrue",
+messageSends: ["visitIRInlinedSend:"],
+referencedClasses: []
+}),
+smalltalk.IRVisitor);
+
+smalltalk.addMethod(
+"_visitIRInlinedSend_",
+smalltalk.method({
+selector: "visitIRInlinedSend:",
+category: 'visiting',
+fn: function (anIRInlinedSend) {
+var self=this;
+smalltalk.send(self, "_visitIRSend_", [anIRInlinedSend]);
+return self;},
+args: ["anIRInlinedSend"],
+source: "visitIRInlinedSend: anIRInlinedSend\x0a\x09self visitIRSend: anIRInlinedSend",
+messageSends: ["visitIRSend:"],
+referencedClasses: []
+}),
+smalltalk.IRVisitor);
+
 smalltalk.addMethod(
 "_visitIRInstruction_",
 smalltalk.method({
@@ -2211,7 +2159,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "stream:",
 category: 'accessing',
-fn: function (aStream){
+fn: function (aStream) {
 var self=this;
 (self['@stream']=aStream);
 return self;},
@@ -2247,11 +2195,11 @@ selector: "visitIRBlockSequence:",
 category: 'visiting',
 fn: function (anIRBlockSequence){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutSequenceWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})]));})]);
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutSequenceWith_", [(function(){return ((($receiver = smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_notEmpty", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", []), "_isReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", []), "_isReturn", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutReturn", []);})]));return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRBlockSequence, "_instructions", []), "_last", [])]);})]));})]);
 return self;},
 args: ["anIRBlockSequence"],
-source: "visitIRBlockSequence: anIRBlockSequence\x0a\x09self stream nextPutSequenceWith: [\x0a\x09\x09anIRBlockSequence instructions notEmpty ifTrue: [\x0a\x09\x09\x09anIRBlockSequence instructions allButLast do: [ :each | \x0a\x09\x09\x09\x09self visit: each ].\x0a\x09\x09\x09self stream nextPutReturn.\x0a\x09\x09\x09self visit: anIRBlockSequence instructions last ]]",
-messageSends: ["nextPutSequenceWith:", "stream", "ifTrue:", "notEmpty", "instructions", "do:", "allButLast", "visit:", "nextPutReturn", "last"],
+source: "visitIRBlockSequence: anIRBlockSequence\x0a\x09self stream nextPutSequenceWith: [\x0a\x09\x09anIRBlockSequence instructions notEmpty ifTrue: [\x0a\x09\x09\x09anIRBlockSequence instructions allButLast do: [ :each | \x0a\x09\x09\x09\x09self visit: each ].\x0a\x09\x09\x09anIRBlockSequence instructions last isReturn ifFalse: [\x0a\x09\x09\x09\x09self stream nextPutReturn ].\x0a\x09\x09\x09self visit: anIRBlockSequence instructions last ]]",
+messageSends: ["nextPutSequenceWith:", "stream", "ifTrue:", "notEmpty", "instructions", "do:", "allButLast", "visit:", "ifFalse:", "isReturn", "last", "nextPutReturn"],
 referencedClasses: []
 }),
 smalltalk.IRJSTranslator);
@@ -2341,7 +2289,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitIRSend:",
 category: 'visiting',
-fn: function (anIRSend){
+fn: function (anIRSend) {
 var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["smalltalk.send("]);
 smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRSend, "_instructions", []), "_first", [])]);
@@ -2595,6 +2543,26 @@ referencedClasses: []
 }),
 smalltalk.JSStream);
 
+smalltalk.addMethod(
+"_nextPutIf_with_",
+smalltalk.method({
+selector: "nextPutIf:with:",
+category: 'streaming',
+fn: function (aBlock, anotherBlock){
+var self=this;
+smalltalk.send(self['@stream'], "_nextPutAll_", ["if("]);
+smalltalk.send(aBlock, "_value", []);
+(function($rec){smalltalk.send($rec, "_nextPutAll_", ["){"]);return smalltalk.send($rec, "_lf", []);})(self['@stream']);
+smalltalk.send(anotherBlock, "_value", []);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["}"]);
+return self;},
+args: ["aBlock", "anotherBlock"],
+source: "nextPutIf: aBlock with: anotherBlock\x0a\x09stream nextPutAll: 'if('.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: '){'; lf.\x0a\x09anotherBlock value.\x0a\x09stream nextPutAll: '}'",
+messageSends: ["nextPutAll:", "value", "lf"],
+referencedClasses: []
+}),
+smalltalk.JSStream);
+
 smalltalk.addMethod(
 "_nextPutMethodDeclaration_with_",
 smalltalk.method({
@@ -2638,14 +2606,14 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "nextPutNonLocalReturnWith:",
 category: 'streaming',
-fn: function (aBlock) {
+fn: function (aBlock){
 var self=this;
-smalltalk.send(self['@stream'], "_nextPutAll_", ["(function(){throw $early=["]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["throw $early=["]);
 smalltalk.send(aBlock, "_value", []);
-smalltalk.send(self['@stream'], "_nextPutAll_", ["]})()"]);
+smalltalk.send(self['@stream'], "_nextPutAll_", ["]"]);
 return self;},
 args: ["aBlock"],
-source: "nextPutNonLocalReturnWith: aBlock\x0a\x09stream nextPutAll: '(function(){throw $early=['.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: ']})()'",
+source: "nextPutNonLocalReturnWith: aBlock\x0a\x09stream nextPutAll: 'throw $early=['.\x0a\x09aBlock value.\x0a\x09stream nextPutAll: ']'",
 messageSends: ["nextPutAll:", "value"],
 referencedClasses: []
 }),

+ 44 - 9
js/Compiler-Semantic.deploy.js

@@ -194,7 +194,7 @@ smalltalk.LexicalScope);
 
 
 
-smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturn'], 'Compiler-Semantic');
+smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturns'], 'Compiler-Semantic');
 smalltalk.addMethod(
 "_addIVar_",
 smalltalk.method({
@@ -207,6 +207,17 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_addNonLocalReturn_",
+smalltalk.method({
+selector: "addNonLocalReturn:",
+fn: function (aNode){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_allVariableNames",
 smalltalk.method({
@@ -244,9 +255,9 @@ smalltalk.addMethod(
 "_hasNonLocalReturn",
 smalltalk.method({
 selector: "hasNonLocalReturn",
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(self, "_nonLocalReturn", []);
+return smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_notEmpty", []);
 return self;}
 }),
 smalltalk.MethodLexicalScope);
@@ -328,6 +339,17 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_nonLocalReturns",
+smalltalk.method({
+selector: "nonLocalReturns",
+fn: function (){
+var self=this;
+return (($receiver = self['@nonLocalReturns']) == nil || $receiver == undefined) ? (function(){return (self['@nonLocalReturns']=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection), "_new", []));})() : $receiver;
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_pseudoVars",
 smalltalk.method({
@@ -340,6 +362,17 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_removeNonLocalReturn_",
+smalltalk.method({
+selector: "removeNonLocalReturn:",
+fn: function (aNode){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_unknownVariables",
 smalltalk.method({
@@ -814,10 +847,11 @@ smalltalk.addMethod(
 "_visitBlockNode_",
 smalltalk.method({
 selector: "visitBlockNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newBlockScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
+smalltalk.send(self['@currentScope'], "_node_", [aNode]);
 smalltalk.send(smalltalk.send(aNode, "_parameters", []), "_do_", [(function(each){smalltalk.send(self, "_validateVariableScope_", [each]);return smalltalk.send(self['@currentScope'], "_addArg_", [each]);})]);
 smalltalk.send(self, "_visitBlockNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(self, "_popScope", []);
@@ -870,10 +904,11 @@ smalltalk.addMethod(
 "_visitMethodNode_",
 smalltalk.method({
 selector: "visitMethodNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newMethodScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
+smalltalk.send(self['@currentScope'], "_node_", [aNode]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_theClass", []), "_allInstanceVariableNames", []), "_do_", [(function(each){return smalltalk.send(self['@currentScope'], "_addIVar_", [each]);})]);
 smalltalk.send(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){smalltalk.send(self, "_validateVariableScope_", [each]);return smalltalk.send(self['@currentScope'], "_addArg_", [each]);})]);
 smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
@@ -887,9 +922,9 @@ smalltalk.addMethod(
 "_visitReturnNode_",
 smalltalk.method({
 selector: "visitReturnNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
-((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
@@ -900,12 +935,12 @@ smalltalk.addMethod(
 "_visitSendNode_",
 smalltalk.method({
 selector: "visitSendNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})]));
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);
 (($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(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isSendNode", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(each, "_beUsed", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(each, "_beUsed", []);})]));})]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
 }),

+ 69 - 19
js/Compiler-Semantic.js

@@ -280,7 +280,7 @@ smalltalk.LexicalScope);
 
 
 
-smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturn'], 'Compiler-Semantic');
+smalltalk.addClass('MethodLexicalScope', smalltalk.LexicalScope, ['iVars', 'unknownVariables', 'localReturn', 'nonLocalReturns'], 'Compiler-Semantic');
 smalltalk.MethodLexicalScope.comment="I represent a method scope."
 smalltalk.addMethod(
 "_addIVar_",
@@ -299,6 +299,22 @@ referencedClasses: ["InstanceVar"]
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_addNonLocalReturn_",
+smalltalk.method({
+selector: "addNonLocalReturn:",
+category: 'adding',
+fn: function (aNode){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
+return self;},
+args: ["aNode"],
+source: "addNonLocalReturn: aNode\x0a\x09self nonLocalReturns add: aNode",
+messageSends: ["add:", "nonLocalReturns"],
+referencedClasses: []
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_allVariableNames",
 smalltalk.method({
@@ -352,13 +368,13 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "hasNonLocalReturn",
 category: 'testing',
-fn: function () {
+fn: function (){
 var self=this;
-return smalltalk.send(self, "_nonLocalReturn", []);
+return smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_notEmpty", []);
 return self;},
 args: [],
-source: "hasNonLocalReturn\x0a\x09^ self nonLocalReturn",
-messageSends: ["nonLocalReturn"],
+source: "hasNonLocalReturn\x0a\x09^ self nonLocalReturns notEmpty",
+messageSends: ["notEmpty", "nonLocalReturns"],
 referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
@@ -475,6 +491,22 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_nonLocalReturns",
+smalltalk.method({
+selector: "nonLocalReturns",
+category: 'accessing',
+fn: function (){
+var self=this;
+return (($receiver = self['@nonLocalReturns']) == nil || $receiver == undefined) ? (function(){return (self['@nonLocalReturns']=smalltalk.send((smalltalk.OrderedCollection || OrderedCollection), "_new", []));})() : $receiver;
+return self;},
+args: [],
+source: "nonLocalReturns\x0a\x09^ nonLocalReturns ifNil: [ nonLocalReturns := OrderedCollection new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["OrderedCollection"]
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_pseudoVars",
 smalltalk.method({
@@ -492,6 +524,22 @@ referencedClasses: ["Dictionary", "Smalltalk", "PseudoVar"]
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_removeNonLocalReturn_",
+smalltalk.method({
+selector: "removeNonLocalReturn:",
+category: 'adding',
+fn: function (aNode){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
+return self;},
+args: ["aNode"],
+source: "removeNonLocalReturn: aNode\x0a\x09self nonLocalReturns remove: aNode ifAbsent: []",
+messageSends: ["remove:ifAbsent:", "nonLocalReturns"],
+referencedClasses: []
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_unknownVariables",
 smalltalk.method({
@@ -1176,17 +1224,18 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitBlockNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newBlockScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
+smalltalk.send(self['@currentScope'], "_node_", [aNode]);
 smalltalk.send(smalltalk.send(aNode, "_parameters", []), "_do_", [(function(each){smalltalk.send(self, "_validateVariableScope_", [each]);return smalltalk.send(self['@currentScope'], "_addArg_", [each]);})]);
 smalltalk.send(self, "_visitBlockNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(self, "_popScope", []);
 return self;},
 args: ["aNode"],
-source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09\x0a\x09aNode parameters do: [ :each | \x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
-messageSends: ["pushScope:", "newBlockScope", "scope:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"],
+source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x09\x0a\x09aNode parameters do: [ :each | \x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
+messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1247,10 +1296,11 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitMethodNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_pushScope_", [smalltalk.send(self, "_newMethodScope", [])]);
 smalltalk.send(aNode, "_scope_", [self['@currentScope']]);
+smalltalk.send(self['@currentScope'], "_node_", [aNode]);
 smalltalk.send(smalltalk.send(smalltalk.send(self, "_theClass", []), "_allInstanceVariableNames", []), "_do_", [(function(each){return smalltalk.send(self['@currentScope'], "_addIVar_", [each]);})]);
 smalltalk.send(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){smalltalk.send(self, "_validateVariableScope_", [each]);return smalltalk.send(self['@currentScope'], "_addArg_", [each]);})]);
 smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
@@ -1258,8 +1308,8 @@ smalltalk.send(self, "_visitMethodNode_", [aNode], smalltalk.SemanticAnalyzer.su
 smalltalk.send(self, "_popScope", []);
 return self;},
 args: ["aNode"],
-source: "visitMethodNode: aNode\x0a\x09self pushScope: self newMethodScope.\x0a\x09aNode scope: currentScope.\x0a\x0a\x09self theClass allInstanceVariableNames do: [:each | \x0a\x09\x09currentScope addIVar: each ].\x0a\x09aNode arguments do: [ :each | \x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitMethodNode: aNode.\x0a\x0a\x09aNode \x0a\x09\x09classReferences: self classReferences;\x0a\x09\x09messageSends: self messageSends.\x0a\x09self popScope",
-messageSends: ["pushScope:", "newMethodScope", "scope:", "do:", "allInstanceVariableNames", "theClass", "addIVar:", "arguments", "validateVariableScope:", "addArg:", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "messageSends", "popScope"],
+source: "visitMethodNode: aNode\x0a\x09self pushScope: self newMethodScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x0a\x09self theClass allInstanceVariableNames do: [:each | \x0a\x09\x09currentScope addIVar: each ].\x0a\x09aNode arguments do: [ :each | \x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitMethodNode: aNode.\x0a\x0a\x09aNode \x0a\x09\x09classReferences: self classReferences;\x0a\x09\x09messageSends: self messageSends.\x0a\x09self popScope",
+messageSends: ["pushScope:", "newMethodScope", "scope:", "node:", "do:", "allInstanceVariableNames", "theClass", "addIVar:", "arguments", "validateVariableScope:", "addArg:", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "messageSends", "popScope"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1269,15 +1319,15 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitReturnNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
-((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_nonLocalReturn_", [true]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);})() : (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(self['@currentScope'], "_localReturn_", [true]);}), (function(){smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [aNode]);return smalltalk.send(aNode, "_nonLocalReturn_", [true]);})]));
 smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_nodes", []), "_first", []), "_beUsed", []);
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope \x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope nonLocalReturn: true.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09aNode nodes first beUsed.\x0a\x09super visitReturnNode: aNode",
-messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "nonLocalReturn:", "methodScope", "beUsed", "first", "nodes", "visitReturnNode:"],
+source: "visitReturnNode: aNode\x0a\x09currentScope isMethodScope \x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope addNonLocalReturn: aNode.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09aNode nodes first beUsed.\x0a\x09super visitReturnNode: aNode",
+messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "nonLocalReturn:", "beUsed", "first", "nodes", "visitReturnNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1287,17 +1337,17 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitSendNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value", []), "__eq", ["super"])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(aNode, "_superSend_", [true]);return smalltalk.send(smalltalk.send(aNode, "_receiver", []), "_value_", ["self"]);})]));
 smalltalk.send(smalltalk.send(self, "_messageSends", []), "_add_", [smalltalk.send(aNode, "_selector", [])]);
 (($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(smalltalk.send(aNode, "_arguments", []), "_do_", [(function(each){return ((($receiver = smalltalk.send(each, "_isSendNode", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(each, "_beUsed", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){return smalltalk.send(each, "_beUsed", []);})]));})]);
 smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;},
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' ifTrue: [\x0a\x09\x09aNode superSend: true.\x0a\x09\x09aNode receiver value: 'self'].\x0a\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: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "add:", "messageSends", "selector", "ifNotNil:", "beUsed", "do:", "arguments", "visitSendNode:"],
+source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super' ifTrue: [\x0a\x09\x09aNode superSend: true.\x0a\x09\x09aNode receiver value: 'self'].\x0a\x0a\x09self messageSends add: aNode selector.\x0a\x09aNode receiver ifNotNil: [\x0a\x09\x09aNode receiver beUsed ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09each isSendNode ifTrue: [ each beUsed ]].\x0a\x09super visitSendNode: aNode",
+messageSends: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "add:", "messageSends", "selector", "ifNotNil:", "beUsed", "do:", "arguments", "isSendNode", "visitSendNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);

+ 5 - 4
js/Kernel-Collections.deploy.js

@@ -1428,19 +1428,20 @@ return self;}
 smalltalk.Array);
 
 smalltalk.addMethod(
-"_remove_",
+"_remove_ifAbsent_",
 smalltalk.method({
-selector: "remove:",
-fn: function (anObject) {
+selector: "remove:ifAbsent:",
+fn: function (anObject, aBlock){
 var self=this;
 
 		for(var i=0;i<self.length;i++) {
 			if(self[i] == anObject) {
 				self.splice(i,1);
-				break;
+				return self;
 			}
 		}
 	;
+smalltalk.send(aBlock, "_value", []);
 return self;}
 }),
 smalltalk.Array);

+ 8 - 7
js/Kernel-Collections.js

@@ -2014,24 +2014,25 @@ referencedClasses: []
 smalltalk.Array);
 
 smalltalk.addMethod(
-"_remove_",
+"_remove_ifAbsent_",
 smalltalk.method({
-selector: "remove:",
+selector: "remove:ifAbsent:",
 category: 'adding/removing',
-fn: function (anObject) {
+fn: function (anObject, aBlock){
 var self=this;
 
 		for(var i=0;i<self.length;i++) {
 			if(self[i] == anObject) {
 				self.splice(i,1);
-				break;
+				return self;
 			}
 		}
 	;
+smalltalk.send(aBlock, "_value", []);
 return self;},
-args: ["anObject"],
-source: "remove: anObject\x0a\x09<\x0a\x09\x09for(var i=0;i<self.length;i++) {\x0a\x09\x09\x09if(self[i] == anObject) {\x0a\x09\x09\x09\x09self.splice(i,1);\x0a\x09\x09\x09\x09break;\x0a\x09\x09\x09}\x0a\x09\x09}\x0a\x09>",
-messageSends: [],
+args: ["anObject", "aBlock"],
+source: "remove: anObject ifAbsent: aBlock\x0a\x09<\x0a\x09\x09for(var i=0;i<self.length;i++) {\x0a\x09\x09\x09if(self[i] == anObject) {\x0a\x09\x09\x09\x09self.splice(i,1);\x0a\x09\x09\x09\x09return self;\x0a\x09\x09\x09}\x0a\x09\x09}\x0a\x09>.\x0a\x09aBlock value",
+messageSends: ["value"],
 referencedClasses: []
 }),
 smalltalk.Array);

+ 1 - 0
js/amber.js

@@ -90,6 +90,7 @@ amber = (function() {
 				'Compiler-AST',
 				'Compiler-Semantic',
 				'Compiler-IR',
+				'Compiler-Inlining',
 				'Compiler-Tests',
 				'parser',
 				'IDE',

+ 19 - 2
st/Compiler-AST.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-AST' properties: #{}!
 Object subclass: #Node
-	instanceVariableNames: 'nodes used alias'
+	instanceVariableNames: 'nodes used alias canBeInlined'
 	package: 'Compiler-AST'!
 !Node commentStamp!
 I am the abstract root class of the abstract syntax tree.!
@@ -23,6 +23,14 @@ beUsed
 	used := true
 !
 
+canBeInlined
+	^ canBeInlined ifNil: [ false ]
+!
+
+canBeInlined: aBoolean
+	canBeInlined := aBoolean
+!
+
 nodes
 	^nodes ifNil: [nodes := Array new]
 !
@@ -138,6 +146,11 @@ scope: aLexicalScope
 
 !BlockNode methodsFor: 'testing'!
 
+canInlineNonLocalReturns
+	^ self canBeInlined and: [
+		self scope outerScope node canInlineNonLocalReturns]
+!
+
 isBlockNode
 	^true
 ! !
@@ -276,6 +289,10 @@ canAliasChildren
 	^ false
 !
 
+canInlineNonLocalReturns
+	^ true
+!
+
 hasLocalReturn
 	^ self scope
 		ifNil: [ false ]
@@ -295,7 +312,7 @@ accept: aVisitor
 ! !
 
 Node subclass: #ReturnNode
-	instanceVariableNames: 'nonLocalReturn'
+	instanceVariableNames: 'nonLocalReturn canBeInlined'
 	package: 'Compiler-AST'!
 
 !ReturnNode methodsFor: 'accessing'!

+ 4 - 0
st/Compiler-Exceptions.st

@@ -17,6 +17,10 @@ See my subclasses for concrete errors.
 
 The IDE should catch instances of Semantic error to deal with them when compiling!
 
+SemanticError subclass: #InliningError
+	instanceVariableNames: 'variableName'
+	package: 'Compiler-Exceptions'!
+
 SemanticError subclass: #InvalidAssignmentError
 	instanceVariableNames: 'variableName'
 	package: 'Compiler-Exceptions'!

+ 82 - 91
st/Compiler-IR.st

@@ -60,7 +60,6 @@ visitJSStatementNode: aNode
 
 visitMethodNode: aNode
 	self builder method 
-		scope: aNode scope;
 		source: self source;
 		arguments: aNode arguments;
 		selector: aNode selector;
@@ -352,7 +351,7 @@ isClosure
 	^ false
 !
 
-isInlined
+isReturn
 	^ false
 ! !
 
@@ -390,91 +389,24 @@ accept: aVisitor
 	aVisitor visitIRAlias: self
 ! !
 
-IRInstruction subclass: #IRNonLocalReturn
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRNonLocalReturn commentStamp!
-I am a non local return instruction.
-Non local returns are handled using a try/catch JS statement.
-
-See IRNonLocalReturnHandling class!
-
-!IRNonLocalReturn methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRNonLocalReturn: self
-! !
-
-IRInstruction subclass: #IRNonLocalReturnHandling
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRNonLocalReturnHandling commentStamp!
-I represent a non local return handling instruction.
-Non local returns are handled with a try/catch statement!
-
-!IRNonLocalReturnHandling methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRNonLocalReturnHandling: self
-! !
-
-IRInstruction subclass: #IRReturn
-	instanceVariableNames: ''
-	package: 'Compiler-IR'!
-!IRReturn commentStamp!
-I am a local return instruction.!
-
-!IRReturn methodsFor: 'visiting'!
-
-accept: aVisitor
-	aVisitor visitIRReturn: self
-! !
-
-IRInstruction subclass: #IRScopedInstruction
-	instanceVariableNames: 'scope'
-	package: 'Compiler-IR'!
-
-!IRScopedInstruction methodsFor: 'accessing'!
-
-scope
-	^ scope
-!
-
-scope: aScope
-	aScope instruction: self.
-	scope := aScope
-! !
-
-IRScopedInstruction subclass: #IRClosure
-	instanceVariableNames: 'arguments inlined'
+IRInstruction subclass: #IRClosure
+	instanceVariableNames: 'arguments'
 	package: 'Compiler-IR'!
 
 !IRClosure methodsFor: 'accessing'!
 
 arguments
-	^ arguments
+	^ arguments ifNil: [ #() ]
 !
 
 arguments: aCollection
 	arguments := aCollection
-!
-
-inlined
-	^ inlined ifNil: [ false ]
-!
-
-inlined: aBoolean
-	inlined := aBoolean
 ! !
 
 !IRClosure methodsFor: 'testing'!
 
 isClosure
 	^ true
-!
-
-isInlined
-	^ self inlined
 ! !
 
 !IRClosure methodsFor: 'visiting'!
@@ -483,7 +415,7 @@ accept: aVisitor
 	aVisitor visitIRClosure: self
 ! !
 
-IRScopedInstruction subclass: #IRMethod
+IRInstruction subclass: #IRMethod
 	instanceVariableNames: 'source selector classReferences messageSends arguments internalVariables'
 	package: 'Compiler-IR'!
 !IRMethod commentStamp!
@@ -541,8 +473,54 @@ accept: aVisitor
 	aVisitor visitIRMethod: self
 ! !
 
+IRInstruction subclass: #IRNonLocalReturnHandling
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRNonLocalReturnHandling commentStamp!
+I represent a non local return handling instruction.
+Non local returns are handled with a try/catch statement!
+
+!IRNonLocalReturnHandling methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRNonLocalReturnHandling: self
+! !
+
+IRInstruction subclass: #IRReturn
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRReturn commentStamp!
+I am a local return instruction.!
+
+!IRReturn methodsFor: 'testing'!
+
+isReturn
+	^ true
+! !
+
+!IRReturn methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRReturn: self
+! !
+
+IRReturn subclass: #IRNonLocalReturn
+	instanceVariableNames: ''
+	package: 'Compiler-IR'!
+!IRNonLocalReturn commentStamp!
+I am a non local return instruction.
+Non local returns are handled using a try/catch JS statement.
+
+See IRNonLocalReturnHandling class!
+
+!IRNonLocalReturn methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRNonLocalReturn: self
+! !
+
 IRInstruction subclass: #IRSend
-	instanceVariableNames: 'selector classSend inlined'
+	instanceVariableNames: 'selector classSend'
 	package: 'Compiler-IR'!
 !IRSend commentStamp!
 I am a message send instruction.!
@@ -557,14 +535,6 @@ classSend: aClass
 	classSend := aClass
 !
 
-inlined
-	^ inlined ifNil: [ false ]
-!
-
-inlined: aBoolean
-	inlined := aBoolean
-!
-
 selector
 	^ selector
 !
@@ -573,12 +543,6 @@ selector: aString
 	selector := aString
 ! !
 
-!IRSend methodsFor: 'testing'!
-
-isInlined
-	^ self inlined
-! !
-
 !IRSend methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -624,6 +588,12 @@ pc
 	^ pc ifNil: [pc := self builder nextPc]
 ! !
 
+!IRStatement methodsFor: 'testing'!
+
+isReturn
+	^ self instructions first isReturn
+! !
+
 !IRStatement methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -742,6 +712,18 @@ visitIRClosure: anIRClosure
 	self visitIRInstruction: anIRClosure
 !
 
+visitIRInlinedClosure: anIRClosure
+	self visitIRClosure: anIRClosure
+!
+
+visitIRInlinedIfTrue: anIRInlinedIfTrue
+	self visitIRInlinedSend: anIRInlinedIfTrue
+!
+
+visitIRInlinedSend: anIRInlinedSend
+	self visitIRSend: anIRInlinedSend
+!
+
 visitIRInstruction: anIRInstruction
 	anIRInstruction instructions do: [ :each | self visit: each ]
 !
@@ -828,7 +810,8 @@ visitIRBlockSequence: anIRBlockSequence
 		anIRBlockSequence instructions notEmpty ifTrue: [
 			anIRBlockSequence instructions allButLast do: [ :each | 
 				self visit: each ].
-			self stream nextPutReturn.
+			anIRBlockSequence instructions last isReturn ifFalse: [
+				self stream nextPutReturn ].
 			self visit: anIRBlockSequence instructions last ]]
 !
 
@@ -965,6 +948,14 @@ nextPutFunctionWith: aBlock arguments: anArray
 	stream nextPutAll: '}'
 !
 
+nextPutIf: aBlock with: anotherBlock
+	stream nextPutAll: 'if('.
+	aBlock value.
+	stream nextPutAll: '){'; lf.
+	anotherBlock value.
+	stream nextPutAll: '}'
+!
+
 nextPutMethodDeclaration: aMethod with: aBlock
 	stream 
 		nextPutAll: 'smalltalk.method({'; lf;
@@ -995,9 +986,9 @@ nextPutNonLocalReturnHandlingWith: aBlock
 !
 
 nextPutNonLocalReturnWith: aBlock
-	stream nextPutAll: '(function(){throw $early=['.
+	stream nextPutAll: 'throw $early=['.
 	aBlock value.
-	stream nextPutAll: ']})()'
+	stream nextPutAll: ']'
 !
 
 nextPutReturn

+ 18 - 4
st/Compiler-Semantic.st

@@ -98,7 +98,7 @@ isMethodScope
 ! !
 
 LexicalScope subclass: #MethodLexicalScope
-	instanceVariableNames: 'iVars unknownVariables localReturn nonLocalReturn'
+	instanceVariableNames: 'iVars unknownVariables localReturn nonLocalReturns'
 	package: 'Compiler-Semantic'!
 !MethodLexicalScope commentStamp!
 I represent a method scope.!
@@ -138,6 +138,10 @@ nonLocalReturn: aBoolean
 	nonLocalReturn := aBoolean
 !
 
+nonLocalReturns
+	^ nonLocalReturns ifNil: [ nonLocalReturns := OrderedCollection new ]
+!
+
 pseudoVars
 	pseudoVars ifNil: [
 		pseudoVars := Dictionary new.
@@ -157,6 +161,14 @@ unknownVariables
 addIVar: aString
 	self iVars at: aString put: (InstanceVar on: aString).
 	(self iVars at: aString) scope: self
+!
+
+addNonLocalReturn: aNode
+	self nonLocalReturns add: aNode
+!
+
+removeNonLocalReturn: aNode
+	self nonLocalReturns remove: aNode ifAbsent: []
 ! !
 
 !MethodLexicalScope methodsFor: 'testing'!
@@ -166,7 +178,7 @@ hasLocalReturn
 !
 
 hasNonLocalReturn
-	^ self nonLocalReturn
+	^ self nonLocalReturns notEmpty
 !
 
 isMethodScope
@@ -446,6 +458,7 @@ visitAssignmentNode: aNode
 visitBlockNode: aNode
 	self pushScope: self newBlockScope.
 	aNode scope: currentScope.
+	currentScope node: aNode.
 	
 	aNode parameters do: [ :each | 
 		self validateVariableScope: each.
@@ -472,6 +485,7 @@ visitClassReferenceNode: aNode
 visitMethodNode: aNode
 	self pushScope: self newMethodScope.
 	aNode scope: currentScope.
+	currentScope node: aNode.
 
 	self theClass allInstanceVariableNames do: [:each | 
 		currentScope addIVar: each ].
@@ -491,7 +505,7 @@ visitReturnNode: aNode
 	currentScope isMethodScope 
 		ifTrue: [ currentScope localReturn: true ]
 		ifFalse: [
-			currentScope methodScope nonLocalReturn: true.
+			currentScope methodScope addNonLocalReturn: aNode.
 			aNode nonLocalReturn: true ].
 	aNode nodes first beUsed.
 	super visitReturnNode: aNode
@@ -507,7 +521,7 @@ visitSendNode: aNode
 	aNode receiver ifNotNil: [
 		aNode receiver beUsed ].
 	aNode arguments do: [ :each |
-		each beUsed ].
+		each isSendNode ifTrue: [ each beUsed ]].
 	super visitSendNode: aNode
 !
 

+ 4 - 3
st/Kernel-Collections.st

@@ -775,15 +775,16 @@ add: anObject
 	<self.push(anObject); return anObject;>
 !
 
-remove: anObject
+remove: anObject ifAbsent: aBlock
 	<
 		for(var i=0;i<self.length;i++) {
 			if(self[i] == anObject) {
 				self.splice(i,1);
-				break;
+				return self;
 			}
 		}
-	>
+	>.
+	aBlock value
 !
 
 removeFrom: aNumber to: anotherNumber