Browse Source

- Working inliner
- Inlning #ifTrue: and #ifFalse:
- Boolean check still missing

Nicolas Petton 12 years ago
parent
commit
f05d8333e8

+ 13 - 256
js/Compiler-AST.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'assignedTo', 'alias', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -22,105 +22,6 @@ return self;}
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_alias",
-smalltalk.method({
-selector: "alias",
-fn: function () {
-var self=this;
-return self['@alias'];
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_alias_",
-smalltalk.method({
-selector: "alias:",
-fn: function (aString) {
-var self=this;
-(self['@alias']=aString);
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_assignedTo",
-smalltalk.method({
-selector: "assignedTo",
-fn: function () {
-var self=this;
-return self['@assignedTo'];
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_assignedTo_",
-smalltalk.method({
-selector: "assignedTo:",
-fn: function (aScopeVar) {
-var self=this;
-(self['@assignedTo']=aScopeVar);
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_beUsed",
-smalltalk.method({
-selector: "beUsed",
-fn: function () {
-var self=this;
-(self['@used']=true);
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-fn: function () {
-var self=this;
-return true;
-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({
-selector: "isAliased",
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(self, "_alias", []), "_notNil", []);
-return self;}
-}),
-smalltalk.Node);
-
 smalltalk.addMethod(
 "_isAssignmentNode",
 smalltalk.method({
@@ -165,17 +66,6 @@ return self;}
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_isUsed",
-smalltalk.method({
-selector: "isUsed",
-fn: function () {
-var self=this;
-return smalltalk.send(self, "_used", []);
-return self;}
-}),
-smalltalk.Node);
-
 smalltalk.addMethod(
 "_isValueNode",
 smalltalk.method({
@@ -209,39 +99,6 @@ return self;}
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_shouldBeAliased",
-smalltalk.method({
-selector: "shouldBeAliased",
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(self, "_isUsed", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_alias", []), "_isNil", []);})]);
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_used",
-smalltalk.method({
-selector: "used",
-fn: function () {
-var self=this;
-return (($receiver = self['@used']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;}
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_used_",
-smalltalk.method({
-selector: "used:",
-fn: function (aBoolean) {
-var self=this;
-(self['@used']=aBoolean);
-return self;}
-}),
-smalltalk.Node);
-
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');
@@ -282,10 +139,9 @@ smalltalk.addMethod(
 "_left_",
 smalltalk.method({
 selector: "left:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 (self['@left']=aNode);
-smalltalk.send(self['@left'], "_assigned_", [true]);
 return self;}
 }),
 smalltalk.AssignmentNode);
@@ -337,17 +193,6 @@ 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({
@@ -417,28 +262,6 @@ return self;}
 }),
 smalltalk.CascadeNode);
 
-smalltalk.addMethod(
-"_alias",
-smalltalk.method({
-selector: "alias",
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(self, "_nodes", []), "_last", []), "_alias", []);
-return self;}
-}),
-smalltalk.CascadeNode);
-
-smalltalk.addMethod(
-"_beUsed",
-smalltalk.method({
-selector: "beUsed",
-fn: function () {
-var self=this;
-smalltalk.send(smalltalk.send(self, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
-return self;}
-}),
-smalltalk.CascadeNode);
-
 smalltalk.addMethod(
 "_receiver",
 smalltalk.method({
@@ -561,28 +384,6 @@ return self;}
 }),
 smalltalk.MethodNode);
 
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-fn: function () {
-var self=this;
-return false;
-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({
@@ -605,28 +406,6 @@ return self;}
 }),
 smalltalk.MethodNode);
 
-smalltalk.addMethod(
-"_hasLocalReturn",
-smalltalk.method({
-selector: "hasLocalReturn",
-fn: function () {
-var self=this;
-return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasLocalReturn", []);})();
-return self;}
-}),
-smalltalk.MethodNode);
-
-smalltalk.addMethod(
-"_hasNonLocalReturn",
-smalltalk.method({
-selector: "hasNonLocalReturn",
-fn: function () {
-var self=this;
-return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasNonLocalReturn", []);})();
-return self;}
-}),
-smalltalk.MethodNode);
-
 smalltalk.addMethod(
 "_messageSends",
 smalltalk.method({
@@ -717,7 +496,7 @@ smalltalk.MethodNode);
 
 
 
-smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('ReturnNode', smalltalk.Node, ['scope'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -733,31 +512,31 @@ smalltalk.addMethod(
 "_nonLocalReturn",
 smalltalk.method({
 selector: "nonLocalReturn",
-fn: function () {
+fn: function (){
 var self=this;
-return (($receiver = self['@nonLocalReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_isMethodScope", []), "_not", []);
 return self;}
 }),
 smalltalk.ReturnNode);
 
 smalltalk.addMethod(
-"_nonLocalReturn_",
+"_scope",
 smalltalk.method({
-selector: "nonLocalReturn:",
-fn: function (aBoolean) {
+selector: "scope",
+fn: function (){
 var self=this;
-(self['@nonLocalReturn']=aBoolean);
+return self['@scope'];
 return self;}
 }),
 smalltalk.ReturnNode);
 
 smalltalk.addMethod(
-"_shouldBeAliased",
+"_scope_",
 smalltalk.method({
-selector: "shouldBeAliased",
-fn: function () {
+selector: "scope:",
+fn: function (aLexicalScope){
 var self=this;
-return false;
+(self['@scope']=aLexicalScope);
 return self;}
 }),
 smalltalk.ReturnNode);
@@ -935,17 +714,6 @@ return self;}
 }),
 smalltalk.SequenceNode);
 
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-fn: function () {
-var self=this;
-return false;
-return self;}
-}),
-smalltalk.SequenceNode);
-
 smalltalk.addMethod(
 "_scope",
 smalltalk.method({
@@ -1040,17 +808,6 @@ return self;}
 }),
 smalltalk.ValueNode);
 
-smalltalk.addMethod(
-"_shouldBeAliased",
-smalltalk.method({
-selector: "shouldBeAliased",
-fn: function () {
-var self=this;
-return false;
-return self;}
-}),
-smalltalk.ValueNode);
-
 smalltalk.addMethod(
 "_value",
 smalltalk.method({

+ 23 - 376
js/Compiler-AST.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-AST', {});
-smalltalk.addClass('Node', smalltalk.Object, ['nodes', 'used', 'assignedTo', 'alias', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('Node', smalltalk.Object, ['nodes'], 'Compiler-AST');
 smalltalk.Node.comment="I am the abstract root class of the abstract syntax tree."
 smalltalk.addMethod(
 "_accept_",
@@ -33,150 +33,6 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_alias",
-smalltalk.method({
-selector: "alias",
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@alias'];
-return self;},
-args: [],
-source: "alias\x0a\x09^ alias",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_alias_",
-smalltalk.method({
-selector: "alias:",
-category: 'accessing',
-fn: function (aString) {
-var self=this;
-(self['@alias']=aString);
-return self;},
-args: ["aString"],
-source: "alias: aString\x0a\x09alias := aString",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_assignedTo",
-smalltalk.method({
-selector: "assignedTo",
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@assignedTo'];
-return self;},
-args: [],
-source: "assignedTo\x0a\x09^ assignedTo",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_assignedTo_",
-smalltalk.method({
-selector: "assignedTo:",
-category: 'accessing',
-fn: function (aScopeVar) {
-var self=this;
-(self['@assignedTo']=aScopeVar);
-return self;},
-args: ["aScopeVar"],
-source: "assignedTo: aScopeVar\x0a\x09assignedTo := aScopeVar",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_beUsed",
-smalltalk.method({
-selector: "beUsed",
-category: 'accessing',
-fn: function () {
-var self=this;
-(self['@used']=true);
-return self;},
-args: [],
-source: "beUsed\x0a\x09used := true",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-category: 'testing',
-fn: function () {
-var self=this;
-return true;
-return self;},
-args: [],
-source: "canAliasChildren\x0a\x09^ true",
-messageSends: [],
-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({
-selector: "isAliased",
-category: 'testing',
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(self, "_alias", []), "_notNil", []);
-return self;},
-args: [],
-source: "isAliased\x0a\x09^ self alias notNil",
-messageSends: ["notNil", "alias"],
-referencedClasses: []
-}),
-smalltalk.Node);
-
 smalltalk.addMethod(
 "_isAssignmentNode",
 smalltalk.method({
@@ -241,22 +97,6 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_isUsed",
-smalltalk.method({
-selector: "isUsed",
-category: 'testing',
-fn: function () {
-var self=this;
-return smalltalk.send(self, "_used", []);
-return self;},
-args: [],
-source: "isUsed\x0a\x09^ self used",
-messageSends: ["used"],
-referencedClasses: []
-}),
-smalltalk.Node);
-
 smalltalk.addMethod(
 "_isValueNode",
 smalltalk.method({
@@ -305,54 +145,6 @@ referencedClasses: []
 }),
 smalltalk.Node);
 
-smalltalk.addMethod(
-"_shouldBeAliased",
-smalltalk.method({
-selector: "shouldBeAliased",
-category: 'testing',
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(self, "_isUsed", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_alias", []), "_isNil", []);})]);
-return self;},
-args: [],
-source: "shouldBeAliased\x0a\x09^ self isUsed and: [ self alias isNil ]",
-messageSends: ["and:", "isUsed", "isNil", "alias"],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_used",
-smalltalk.method({
-selector: "used",
-category: 'accessing',
-fn: function () {
-var self=this;
-return (($receiver = self['@used']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;},
-args: [],
-source: "used\x0a\x09^ used ifNil: [ false ]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-smalltalk.Node);
-
-smalltalk.addMethod(
-"_used_",
-smalltalk.method({
-selector: "used:",
-category: 'accessing',
-fn: function (aBoolean) {
-var self=this;
-(self['@used']=aBoolean);
-return self;},
-args: ["aBoolean"],
-source: "used: aBoolean\x0a\x09used := aBoolean",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Node);
-
 
 
 smalltalk.addClass('AssignmentNode', smalltalk.Node, ['left', 'right'], 'Compiler-AST');
@@ -409,14 +201,13 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "left:",
 category: 'accessing',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 (self['@left']=aNode);
-smalltalk.send(self['@left'], "_assigned_", [true]);
 return self;},
 args: ["aNode"],
-source: "left: aNode\x0a\x09left := aNode.\x0a\x09left assigned: true",
-messageSends: ["assigned:"],
+source: "left: aNode\x0a\x09left := aNode",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.AssignmentNode);
@@ -488,22 +279,6 @@ 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({
@@ -603,38 +378,6 @@ referencedClasses: []
 }),
 smalltalk.CascadeNode);
 
-smalltalk.addMethod(
-"_alias",
-smalltalk.method({
-selector: "alias",
-category: 'accessing',
-fn: function () {
-var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(self, "_nodes", []), "_last", []), "_alias", []);
-return self;},
-args: [],
-source: "alias\x0a\x09^self nodes last alias",
-messageSends: ["alias", "last", "nodes"],
-referencedClasses: []
-}),
-smalltalk.CascadeNode);
-
-smalltalk.addMethod(
-"_beUsed",
-smalltalk.method({
-selector: "beUsed",
-category: 'accessing',
-fn: function () {
-var self=this;
-smalltalk.send(smalltalk.send(self, "_nodes", []), "_do_", [(function(each){return smalltalk.send(each, "_beUsed", []);})]);
-return self;},
-args: [],
-source: "beUsed\x0a\x09self nodes do: [ :each | each beUsed ]",
-messageSends: ["do:", "nodes", "beUsed"],
-referencedClasses: []
-}),
-smalltalk.CascadeNode);
-
 smalltalk.addMethod(
 "_receiver",
 smalltalk.method({
@@ -807,38 +550,6 @@ referencedClasses: []
 }),
 smalltalk.MethodNode);
 
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-category: 'testing',
-fn: function () {
-var self=this;
-return false;
-return self;},
-args: [],
-source: "canAliasChildren\x0a\x09^ false",
-messageSends: [],
-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({
@@ -871,38 +582,6 @@ referencedClasses: []
 }),
 smalltalk.MethodNode);
 
-smalltalk.addMethod(
-"_hasLocalReturn",
-smalltalk.method({
-selector: "hasLocalReturn",
-category: 'testing',
-fn: function () {
-var self=this;
-return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasLocalReturn", []);})();
-return self;},
-args: [],
-source: "hasLocalReturn\x0a\x09^ self scope\x0a\x09\x09ifNil: [ false ]\x0a\x09\x09ifNotNil: [ self scope hasLocalReturn ]",
-messageSends: ["ifNil:ifNotNil:", "scope", "hasLocalReturn"],
-referencedClasses: []
-}),
-smalltalk.MethodNode);
-
-smalltalk.addMethod(
-"_hasNonLocalReturn",
-smalltalk.method({
-selector: "hasNonLocalReturn",
-category: 'testing',
-fn: function () {
-var self=this;
-return (($receiver = smalltalk.send(self, "_scope", [])) == nil || $receiver == undefined) ? (function(){return false;})() : (function(){return smalltalk.send(smalltalk.send(self, "_scope", []), "_hasNonLocalReturn", []);})();
-return self;},
-args: [],
-source: "hasNonLocalReturn\x0a\x09^ self scope\x0a\x09\x09ifNil: [ false ]\x0a\x09\x09ifNotNil: [ self scope hasNonLocalReturn ]",
-messageSends: ["ifNil:ifNotNil:", "scope", "hasNonLocalReturn"],
-referencedClasses: []
-}),
-smalltalk.MethodNode);
-
 smalltalk.addMethod(
 "_messageSends",
 smalltalk.method({
@@ -1033,7 +712,7 @@ smalltalk.MethodNode);
 
 
 
-smalltalk.addClass('ReturnNode', smalltalk.Node, ['nonLocalReturn', 'canBeInlined'], 'Compiler-AST');
+smalltalk.addClass('ReturnNode', smalltalk.Node, ['scope'], 'Compiler-AST');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -1054,45 +733,45 @@ smalltalk.addMethod(
 "_nonLocalReturn",
 smalltalk.method({
 selector: "nonLocalReturn",
-category: 'accessing',
-fn: function () {
+category: 'testing',
+fn: function (){
 var self=this;
-return (($receiver = self['@nonLocalReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_scope", []), "_isMethodScope", []), "_not", []);
 return self;},
 args: [],
-source: "nonLocalReturn\x0a\x09^ nonLocalReturn ifNil: [ false ]",
-messageSends: ["ifNil:"],
+source: "nonLocalReturn\x0a\x09^ self scope isMethodScope not",
+messageSends: ["not", "isMethodScope", "scope"],
 referencedClasses: []
 }),
 smalltalk.ReturnNode);
 
 smalltalk.addMethod(
-"_nonLocalReturn_",
+"_scope",
 smalltalk.method({
-selector: "nonLocalReturn:",
+selector: "scope",
 category: 'accessing',
-fn: function (aBoolean) {
+fn: function (){
 var self=this;
-(self['@nonLocalReturn']=aBoolean);
+return self['@scope'];
 return self;},
-args: ["aBoolean"],
-source: "nonLocalReturn: aBoolean\x0a\x09nonLocalReturn := aBoolean",
+args: [],
+source: "scope\x0a\x09^ scope",
 messageSends: [],
 referencedClasses: []
 }),
 smalltalk.ReturnNode);
 
 smalltalk.addMethod(
-"_shouldBeAliased",
+"_scope_",
 smalltalk.method({
-selector: "shouldBeAliased",
-category: 'testing',
-fn: function () {
+selector: "scope:",
+category: 'accessing',
+fn: function (aLexicalScope){
 var self=this;
-return false;
+(self['@scope']=aLexicalScope);
 return self;},
-args: [],
-source: "shouldBeAliased\x0a\x09^ false",
+args: ["aLexicalScope"],
+source: "scope: aLexicalScope\x0a\x09scope := aLexicalScope",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1346,22 +1025,6 @@ referencedClasses: ["BlockSequenceNode"]
 }),
 smalltalk.SequenceNode);
 
-smalltalk.addMethod(
-"_canAliasChildren",
-smalltalk.method({
-selector: "canAliasChildren",
-category: 'testing',
-fn: function () {
-var self=this;
-return false;
-return self;},
-args: [],
-source: "canAliasChildren\x0a\x09^ false",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.SequenceNode);
-
 smalltalk.addMethod(
 "_scope",
 smalltalk.method({
@@ -1496,22 +1159,6 @@ referencedClasses: []
 }),
 smalltalk.ValueNode);
 
-smalltalk.addMethod(
-"_shouldBeAliased",
-smalltalk.method({
-selector: "shouldBeAliased",
-category: 'testing',
-fn: function () {
-var self=this;
-return false;
-return self;},
-args: [],
-source: "shouldBeAliased\x0a\x09^ false",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.ValueNode);
-
 smalltalk.addMethod(
 "_value",
 smalltalk.method({

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

@@ -12,6 +12,17 @@ smalltalk.addClass('InliningError', smalltalk.SemanticError, ['variableName'], '
 
 
 smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.addMethod(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+fn: function (){
+var self=this;
+return smalltalk.send(" Invalid assignment to variable: ", "__comma", [smalltalk.send(self, "_variableName", [])]);
+return self;}
+}),
+smalltalk.InvalidAssignmentError);
+
 smalltalk.addMethod(
 "_variableName",
 smalltalk.method({
@@ -37,6 +48,17 @@ smalltalk.InvalidAssignmentError);
 
 
 smalltalk.addClass('ShadowingVariableError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
+smalltalk.addMethod(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send("Variable shadowing error: ", "__comma", [smalltalk.send(self, "_variableName", [])]), "__comma", [" is already defined"]);
+return self;}
+}),
+smalltalk.ShadowingVariableError);
+
 smalltalk.addMethod(
 "_variableName",
 smalltalk.method({

+ 32 - 0
js/Compiler-Exceptions.js

@@ -14,6 +14,22 @@ smalltalk.addClass('InliningError', smalltalk.SemanticError, ['variableName'], '
 
 smalltalk.addClass('InvalidAssignmentError', smalltalk.SemanticError, ['variableName'], 'Compiler-Exceptions');
 smalltalk.InvalidAssignmentError.comment="I get signaled when a pseudo variable gets assigned."
+smalltalk.addMethod(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.send(" Invalid assignment to variable: ", "__comma", [smalltalk.send(self, "_variableName", [])]);
+return self;},
+args: [],
+source: "messageText\x0a\x09^ ' Invalid assignment to variable: ', self variableName",
+messageSends: [",", "variableName"],
+referencedClasses: []
+}),
+smalltalk.InvalidAssignmentError);
+
 smalltalk.addMethod(
 "_variableName",
 smalltalk.method({
@@ -50,6 +66,22 @@ smalltalk.InvalidAssignmentError);
 
 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(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send("Variable shadowing error: ", "__comma", [smalltalk.send(self, "_variableName", [])]), "__comma", [" is already defined"]);
+return self;},
+args: [],
+source: "messageText\x0a\x09^ 'Variable shadowing error: ', self variableName, ' is already defined'",
+messageSends: [",", "variableName"],
+referencedClasses: []
+}),
+smalltalk.ShadowingVariableError);
+
 smalltalk.addMethod(
 "_variableName",
 smalltalk.method({

File diff suppressed because it is too large
+ 128 - 41
js/Compiler-IR.deploy.js


File diff suppressed because it is too large
+ 191 - 65
js/Compiler-IR.js


+ 76 - 16
js/Compiler-Inlining.deploy.js

@@ -71,7 +71,7 @@ smalltalk.IRInlinedClosure);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRNonLocalReturn, [], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -121,6 +121,20 @@ smalltalk.IRInlinedSend);
 
 
 
+smalltalk.addClass('IRInlinedIfFalse', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+fn: function (aVisitor){
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedIfFalse_", [self]);
+return self;}
+}),
+smalltalk.IRInlinedIfFalse);
+
+
+
 smalltalk.addClass('IRInlinedIfTrue', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
@@ -186,29 +200,31 @@ smalltalk.method({
 selector: "visitIRAssignment:",
 fn: function (anIRAssignment){
 var self=this;
-return ((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
+((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
 return self;}
 }),
 smalltalk.IRInliner);
 
 smalltalk.addMethod(
-"_visitIRSend_",
+"_visitIRNonLocalReturn_",
 smalltalk.method({
-selector: "visitIRSend:",
-fn: function (anIRSend){
+selector: "visitIRNonLocalReturn:",
+fn: function (anIRNonLocalReturn){
 var self=this;
-return ((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
+var localReturn=nil;
+((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})]));
+smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
 return self;}
 }),
 smalltalk.IRInliner);
 
 smalltalk.addMethod(
-"_visitSendNode_",
+"_visitIRSend_",
 smalltalk.method({
-selector: "visitSendNode:",
-fn: function (aNode) {
+selector: "visitIRSend:",
+fn: function (anIRSend){
 var self=this;
-((($receiver = smalltalk.send(aNode, "_canBeInlined", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);})() : (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);}), (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})]));
+((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
 return self;}
 }),
 smalltalk.IRInliner);
@@ -234,17 +250,28 @@ selector: "visitIRInlinedClosure:",
 fn: function (anIRInlinedClosure){
 var self=this;
 smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
-(($receiver = smalltalk.send(anIRInlinedClosure, "_assignTo", [])) != nil && $receiver != undefined) ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil;
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_notNil", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", []), "_canBeAssigned", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})]));
 smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);
 return self;}
 }),
 smalltalk.IRInliningJSTranslator);
 
+smalltalk.addMethod(
+"_visitIRInlinedIfFalse_",
+smalltalk.method({
+selector: "visitIRInlinedIfFalse:",
+fn: function (anIRInlinedIfFalse){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["!"]);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_last", [])]);})]);
+return self;}
+}),
+smalltalk.IRInliningJSTranslator);
+
 smalltalk.addMethod(
 "_visitIRInlinedIfTrue_",
 smalltalk.method({
 selector: "visitIRInlinedIfTrue:",
-fn: function (anIRInlinedIfTrue) {
+fn: function (anIRInlinedIfTrue){
 var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_last", [])]);})]);
 return self;}
@@ -254,6 +281,25 @@ smalltalk.IRInliningJSTranslator);
 
 
 smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_ifFalse_",
+smalltalk.method({
+selector: "ifFalse:",
+fn: function (anIRInstruction){
+var self=this;
+var inlinedSend=nil;
+var inlinedClosure=nil;
+((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
+(inlinedClosure=smalltalk.send(self, "_inlineClosure_", [anIRInstruction]));
+(inlinedSend=smalltalk.send((smalltalk.IRInlinedIfFalse || IRInlinedIfFalse), "_new", []));
+(function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
+smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
+return inlinedSend;
+return self;}
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_ifTrue_",
 smalltalk.method({
@@ -264,8 +310,7 @@ var inlinedSend=nil;
 var inlinedClosure=nil;
 ((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
-(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
-smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_do_", [(function(each){(instruction=smalltalk.send(smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each]), "_first", []));return smalltalk.send(inlinedClosure, "_add_", [(typeof instruction == 'undefined' ? nil : instruction)]);})]);
+(inlinedClosure=smalltalk.send(self, "_inlineClosure_", [anIRInstruction]));
 (inlinedSend=smalltalk.send((smalltalk.IRInlinedIfTrue || IRInlinedIfTrue), "_new", []));
 (function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
 smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
@@ -274,6 +319,21 @@ return self;}
 }),
 smalltalk.IRSendInliner);
 
+smalltalk.addMethod(
+"_inlineClosure_",
+smalltalk.method({
+selector: "inlineClosure:",
+fn: function (anIRClosure){
+var self=this;
+var inlinedClosure=nil;
+(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
+smalltalk.send(inlinedClosure, "_scope_", [smalltalk.send(anIRClosure, "_scope", [])]);
+smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_first", []), "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedClosure, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);
+return inlinedClosure;
+return self;}
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_inlineSend_",
 smalltalk.method({
@@ -357,9 +417,9 @@ smalltalk.addMethod(
 "_inlinedSelectors",
 smalltalk.method({
 selector: "inlinedSelectors",
-fn: function () {
+fn: function (){
 var self=this;
-return ["ifTrue:"];
+return ["ifTrue:", "ifFalse:"];
 return self;}
 }),
 smalltalk.IRSendInliner.klass);

+ 109 - 29
js/Compiler-Inlining.js

@@ -101,7 +101,7 @@ smalltalk.IRInlinedClosure);
 
 
 
-smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRNonLocalReturn, [], 'Compiler-Inlining');
+smalltalk.addClass('IRInlinedNonLocalReturn', smalltalk.IRReturn, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
 smalltalk.method({
@@ -171,6 +171,25 @@ smalltalk.IRInlinedSend);
 
 
 
+smalltalk.addClass('IRInlinedIfFalse', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
+smalltalk.addMethod(
+"_accept_",
+smalltalk.method({
+selector: "accept:",
+category: 'visiting',
+fn: function (aVisitor){
+var self=this;
+smalltalk.send(aVisitor, "_visitIRInlinedIfFalse_", [self]);
+return self;},
+args: ["aVisitor"],
+source: "accept: aVisitor\x0a\x09aVisitor visitIRInlinedIfFalse: self",
+messageSends: ["visitIRInlinedIfFalse:"],
+referencedClasses: []
+}),
+smalltalk.IRInlinedIfFalse);
+
+
+
 smalltalk.addClass('IRInlinedIfTrue', smalltalk.IRInlinedSend, [], 'Compiler-Inlining');
 smalltalk.addMethod(
 "_accept_",
@@ -262,43 +281,45 @@ selector: "visitIRAssignment:",
 category: 'visiting',
 fn: function (anIRAssignment){
 var self=this;
-return ((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
+((($receiver = smalltalk.send(self, "_shouldInlineAssignment_", [anIRAssignment])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);})() : (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_assignmentInliner", []), "_inlineAssignment_", [anIRAssignment]);}), (function(){return smalltalk.send(self, "_visitIRAssignment_", [anIRAssignment], smalltalk.IRInliner.superclass || nil);})]));
 return self;},
 args: ["anIRAssignment"],
-source: "visitIRAssignment: anIRAssignment\x0a\x09^ (self shouldInlineAssignment: anIRAssignment) \x0a\x09\x09ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]\x0a\x09\x09ifFalse: [ super visitIRAssignment: anIRAssignment ]",
+source: "visitIRAssignment: anIRAssignment\x0a\x09(self shouldInlineAssignment: anIRAssignment) \x0a\x09\x09ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]\x0a\x09\x09ifFalse: [ super visitIRAssignment: anIRAssignment ]",
 messageSends: ["ifTrue:ifFalse:", "shouldInlineAssignment:", "inlineAssignment:", "assignmentInliner", "visitIRAssignment:"],
 referencedClasses: []
 }),
 smalltalk.IRInliner);
 
 smalltalk.addMethod(
-"_visitIRSend_",
+"_visitIRNonLocalReturn_",
 smalltalk.method({
-selector: "visitIRSend:",
+selector: "visitIRNonLocalReturn:",
 category: 'visiting',
-fn: function (anIRSend){
+fn: function (anIRNonLocalReturn){
 var self=this;
-return ((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
+var localReturn=nil;
+((($receiver = smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_canInlineNonLocalReturns", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_scope", []), "_methodScope", []), "_removeNonLocalReturn_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);(localReturn=(function($rec){smalltalk.send($rec, "_scope_", [smalltalk.send(anIRNonLocalReturn, "_scope", [])]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send((smalltalk.IRInlinedNonLocalReturn || IRInlinedNonLocalReturn), "_new", [])));smalltalk.send(smalltalk.send(anIRNonLocalReturn, "_instructions", []), "_do_", [(function(each){return smalltalk.send(localReturn, "_add_", [each]);})]);return smalltalk.send(anIRNonLocalReturn, "_replaceWith_", [localReturn]);})]));
+smalltalk.send(self, "_visitIRNonLocalReturn_", [anIRNonLocalReturn], smalltalk.IRInliner.superclass || nil);
 return self;},
-args: ["anIRSend"],
-source: "visitIRSend: anIRSend\x0a\x09^ (self shouldInlineSend: anIRSend)\x0a\x09\x09ifTrue: [ self sendInliner inlineSend: anIRSend ]\x0a\x09\x09ifFalse: [ super visitIRSend: anIRSend ]",
-messageSends: ["ifTrue:ifFalse:", "shouldInlineSend:", "inlineSend:", "sendInliner", "visitIRSend:"],
-referencedClasses: []
+args: ["anIRNonLocalReturn"],
+source: "visitIRNonLocalReturn: anIRNonLocalReturn\x0a\x09| localReturn |\x0a\x09anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [\x0a\x09\x09anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.\x0a\x09\x09localReturn := IRInlinedNonLocalReturn new\x0a\x09\x09\x09scope: anIRNonLocalReturn scope;\x0a\x09\x09\x09yourself.\x0a\x09\x09anIRNonLocalReturn instructions do: [ :each |\x0a\x09\x09\x09localReturn add: each ].\x0a\x09\x09anIRNonLocalReturn replaceWith: localReturn ].\x0a\x09super visitIRNonLocalReturn: anIRNonLocalReturn",
+messageSends: ["ifTrue:", "canInlineNonLocalReturns", "scope", "removeNonLocalReturn:", "methodScope", "scope:", "yourself", "new", "do:", "instructions", "add:", "replaceWith:", "visitIRNonLocalReturn:"],
+referencedClasses: ["IRInlinedNonLocalReturn"]
 }),
 smalltalk.IRInliner);
 
 smalltalk.addMethod(
-"_visitSendNode_",
+"_visitIRSend_",
 smalltalk.method({
-selector: "visitSendNode:",
+selector: "visitIRSend:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (anIRSend){
 var self=this;
-((($receiver = smalltalk.send(aNode, "_canBeInlined", [])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);})() : (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [aNode]);}), (function(){return smalltalk.send(self, "_visitSendNode_", [aNode], smalltalk.IRInliningASTResolver.superclass || nil);})]));
+((($receiver = smalltalk.send(self, "_shouldInlineSend_", [anIRSend])).klass === smalltalk.Boolean) ? ($receiver ? (function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);})() : (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})()) : smalltalk.send($receiver, "_ifTrue_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self, "_sendInliner", []), "_inlineSend_", [anIRSend]);}), (function(){return smalltalk.send(self, "_visitIRSend_", [anIRSend], smalltalk.IRInliner.superclass || nil);})]));
 return self;},
-args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09aNode canBeInlined\x0a\x09\x09ifTrue: [ self sendInliner inlineSend: aNode ]\x0a\x09\x09ifFalse: [ super visitSendNode: aNode ]",
-messageSends: ["ifTrue:ifFalse:", "canBeInlined", "inlineSend:", "sendInliner", "visitSendNode:"],
+args: ["anIRSend"],
+source: "visitIRSend: anIRSend\x0a\x09(self shouldInlineSend: anIRSend)\x0a\x09\x09ifTrue: [ self sendInliner inlineSend: anIRSend ]\x0a\x09\x09ifFalse: [ super visitIRSend: anIRSend ]",
+messageSends: ["ifTrue:ifFalse:", "shouldInlineSend:", "inlineSend:", "sendInliner", "visitIRSend:"],
 referencedClasses: []
 }),
 smalltalk.IRInliner);
@@ -330,12 +351,28 @@ category: 'visiting',
 fn: function (anIRInlinedClosure){
 var self=this;
 smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_allButLast", []), "_do_", [(function(each){return smalltalk.send(self, "_visit_", [each]);})]);
-(($receiver = smalltalk.send(anIRInlinedClosure, "_assignTo", [])) != nil && $receiver != undefined) ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil;
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_notNil", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", []), "_canBeAssigned", []);})])).klass === smalltalk.Boolean) ? ($receiver ? (function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})() : nil) : smalltalk.send($receiver, "_ifTrue_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.send(anIRInlinedClosure, "_assignTo", []), "_variable", []), "_alias", [])]);return smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAssignment", []);})]));
 smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedClosure, "_instructions", []), "_last", [])]);
 return self;},
 args: ["anIRInlinedClosure"],
-source: "visitIRInlinedClosure: anIRInlinedClosure\x0a\x09anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].\x0a\x09anIRInlinedClosure assignTo ifNotNil: [\x0a\x09\x09self stream nextPutAll: anIRInlinedClosure assignTo variable alias.\x0a\x09\x09self stream nextPutAssignment ].\x0a\x09self visit: anIRInlinedClosure instructions last",
-messageSends: ["do:", "allButLast", "instructions", "visit:", "ifNotNil:", "assignTo", "nextPutAll:", "stream", "alias", "variable", "nextPutAssignment", "last"],
+source: "visitIRInlinedClosure: anIRInlinedClosure\x0a\x09anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].\x0a\x09(anIRInlinedClosure assignTo notNil and: [\x0a\x09\x09anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [\x0a\x09\x09\x09self stream nextPutAll: anIRInlinedClosure assignTo variable alias.\x0a\x09\x09\x09self stream nextPutAssignment ].\x0a\x09self visit: anIRInlinedClosure instructions last",
+messageSends: ["do:", "allButLast", "instructions", "visit:", "ifTrue:", "and:", "notNil", "assignTo", "canBeAssigned", "last", "nextPutAll:", "stream", "alias", "variable", "nextPutAssignment"],
+referencedClasses: []
+}),
+smalltalk.IRInliningJSTranslator);
+
+smalltalk.addMethod(
+"_visitIRInlinedIfFalse_",
+smalltalk.method({
+selector: "visitIRInlinedIfFalse:",
+category: 'visiting',
+fn: function (anIRInlinedIfFalse){
+var self=this;
+smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutAll_", ["!"]);return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfFalse, "_instructions", []), "_last", [])]);})]);
+return self;},
+args: ["anIRInlinedIfFalse"],
+source: "visitIRInlinedIfFalse: anIRInlinedIfFalse\x0a\x09self stream \x0a\x09\x09nextPutIf: [ \x0a\x09\x09\x09self stream nextPutAll: '!'.\x0a\x09\x09\x09self visit: anIRInlinedIfFalse instructions first ]\x0a\x09\x09with: [ self visit: anIRInlinedIfFalse instructions last ]",
+messageSends: ["nextPutIf:with:", "stream", "nextPutAll:", "visit:", "first", "instructions", "last"],
 referencedClasses: []
 }),
 smalltalk.IRInliningJSTranslator);
@@ -345,7 +382,7 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitIRInlinedIfTrue:",
 category: 'visiting',
-fn: function (anIRInlinedIfTrue) {
+fn: function (anIRInlinedIfTrue){
 var self=this;
 smalltalk.send(smalltalk.send(self, "_stream", []), "_nextPutIf_with_", [(function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_first", [])]);}), (function(){return smalltalk.send(self, "_visit_", [smalltalk.send(smalltalk.send(anIRInlinedIfTrue, "_instructions", []), "_last", [])]);})]);
 return self;},
@@ -360,6 +397,30 @@ smalltalk.IRInliningJSTranslator);
 
 smalltalk.addClass('IRSendInliner', smalltalk.Object, ['send', 'translator'], 'Compiler-Inlining');
 smalltalk.IRSendInliner.comment="I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods."
+smalltalk.addMethod(
+"_ifFalse_",
+smalltalk.method({
+selector: "ifFalse:",
+category: 'inlining',
+fn: function (anIRInstruction){
+var self=this;
+var inlinedSend=nil;
+var inlinedClosure=nil;
+((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
+((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
+(inlinedClosure=smalltalk.send(self, "_inlineClosure_", [anIRInstruction]));
+(inlinedSend=smalltalk.send((smalltalk.IRInlinedIfFalse || IRInlinedIfFalse), "_new", []));
+(function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
+smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
+return inlinedSend;
+return self;},
+args: ["anIRInstruction"],
+source: "ifFalse: anIRInstruction\x0a\x09| inlinedSend inlinedClosure |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09inlinedClosure := self inlineClosure: anIRInstruction.\x0a\x0a\x09inlinedSend := IRInlinedIfFalse new.\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
+messageSends: ["ifFalse:", "isClosure", "inliningError:", "=", "size", "arguments", "inlineClosure:", "new", "add:", "first", "instructions", "send", "replaceWith:"],
+referencedClasses: ["IRInlinedIfFalse"]
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_ifTrue_",
 smalltalk.method({
@@ -371,20 +432,39 @@ var inlinedSend=nil;
 var inlinedClosure=nil;
 ((($receiver = smalltalk.send(anIRInstruction, "_isClosure", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Message argument should be a block"]);})]));
 ((($receiver = smalltalk.send(smalltalk.send(smalltalk.send(anIRInstruction, "_arguments", []), "_size", []), "__eq", [(0)])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(self, "_inliningError_", ["Inlined block should have zero argument"]);})]));
-(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
-smalltalk.send(smalltalk.send(anIRInstruction, "_instructions", []), "_do_", [(function(each){(instruction=smalltalk.send(smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each]), "_first", []));return smalltalk.send(inlinedClosure, "_add_", [(typeof instruction == 'undefined' ? nil : instruction)]);})]);
+(inlinedClosure=smalltalk.send(self, "_inlineClosure_", [anIRInstruction]));
 (inlinedSend=smalltalk.send((smalltalk.IRInlinedIfTrue || IRInlinedIfTrue), "_new", []));
 (function($rec){smalltalk.send($rec, "_add_", [smalltalk.send(smalltalk.send(smalltalk.send(self, "_send", []), "_instructions", []), "_first", [])]);return smalltalk.send($rec, "_add_", [inlinedClosure]);})(inlinedSend);
 smalltalk.send(smalltalk.send(self, "_send", []), "_replaceWith_", [inlinedSend]);
 return inlinedSend;
 return self;},
 args: ["anIRInstruction"],
-source: "ifTrue: anIRInstruction\x0a\x09| inlinedSend inlinedClosure |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09anIRInstruction instructions do: [ :each |\x0a\x09\x09instruction := (self translator visit: each) first.\x0a\x09\x09inlinedClosure add: instruction ].\x0a\x0a\x09inlinedSend := IRInlinedIfTrue new.\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
-messageSends: ["ifFalse:", "isClosure", "inliningError:", "=", "size", "arguments", "inlinedClosure", "do:", "instructions", "first", "visit:", "translator", "add:", "new", "send", "replaceWith:"],
+source: "ifTrue: anIRInstruction\x0a\x09| inlinedSend inlinedClosure |\x0a\x0a\x09anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].\x0a\x09anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].\x0a\x0a\x09inlinedClosure := self inlineClosure: anIRInstruction.\x0a\x0a\x09inlinedSend := IRInlinedIfTrue new.\x0a\x09inlinedSend\x0a\x09\x09add: self send instructions first;\x0a\x09\x09add: inlinedClosure.\x0a\x0a\x09self send replaceWith: inlinedSend.\x0a\x09^ inlinedSend",
+messageSends: ["ifFalse:", "isClosure", "inliningError:", "=", "size", "arguments", "inlineClosure:", "new", "add:", "first", "instructions", "send", "replaceWith:"],
 referencedClasses: ["IRInlinedIfTrue"]
 }),
 smalltalk.IRSendInliner);
 
+smalltalk.addMethod(
+"_inlineClosure_",
+smalltalk.method({
+selector: "inlineClosure:",
+category: 'inlining',
+fn: function (anIRClosure){
+var self=this;
+var inlinedClosure=nil;
+(inlinedClosure=smalltalk.send(self, "_inlinedClosure", []));
+smalltalk.send(inlinedClosure, "_scope_", [smalltalk.send(anIRClosure, "_scope", [])]);
+smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(anIRClosure, "_instructions", []), "_first", []), "_instructions", []), "_do_", [(function(each){return smalltalk.send(inlinedClosure, "_add_", [smalltalk.send(smalltalk.send(self, "_translator", []), "_visit_", [each])]);})]);
+return inlinedClosure;
+return self;},
+args: ["anIRClosure"],
+source: "inlineClosure: anIRClosure\x0a\x09| inlinedClosure |\x0a\x09inlinedClosure := self inlinedClosure.\x0a\x09inlinedClosure scope: anIRClosure scope.\x0a\x09anIRClosure instructions first instructions do: [ :each |\x0a\x09\x09inlinedClosure add: (self translator visit: each) ].\x0a\x09^ inlinedClosure",
+messageSends: ["inlinedClosure", "scope:", "scope", "do:", "instructions", "first", "add:", "visit:", "translator"],
+referencedClasses: []
+}),
+smalltalk.IRSendInliner);
+
 smalltalk.addMethod(
 "_inlineSend_",
 smalltalk.method({
@@ -504,12 +584,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "inlinedSelectors",
 category: 'accessing',
-fn: function () {
+fn: function (){
 var self=this;
-return ["ifTrue:"];
+return ["ifTrue:", "ifFalse:"];
 return self;},
 args: [],
-source: "inlinedSelectors\x0a\x09^ #('ifTrue:')",
+source: "inlinedSelectors\x0a\x09^ #('ifTrue:' 'ifFalse:')",
 messageSends: [],
 referencedClasses: []
 }),

+ 42 - 33
js/Compiler-Semantic.deploy.js

@@ -57,6 +57,17 @@ return self;}
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_isInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_outerScope", []), "_canInlineNonLocalReturns", []);})]);
+return self;}
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_instruction",
 smalltalk.method({
@@ -79,6 +90,17 @@ return self;}
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_instruction", []), "_isInlined", []);
+return self;}
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_isMethodScope",
 smalltalk.method({
@@ -211,9 +233,9 @@ smalltalk.addMethod(
 "_addNonLocalReturn_",
 smalltalk.method({
 selector: "addNonLocalReturn:",
-fn: function (aNode) {
+fn: function (aScope){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aScope]);
 return self;}
 }),
 smalltalk.MethodLexicalScope);
@@ -240,6 +262,17 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+fn: function (){
+var self=this;
+return true;
+return self;}
+}),
+smalltalk.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_hasLocalReturn",
 smalltalk.method({
@@ -317,28 +350,6 @@ return self;}
 }),
 smalltalk.MethodLexicalScope);
 
-smalltalk.addMethod(
-"_nonLocalReturn",
-smalltalk.method({
-selector: "nonLocalReturn",
-fn: function () {
-var self=this;
-return (($receiver = self['@nonLocalReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;}
-}),
-smalltalk.MethodLexicalScope);
-
-smalltalk.addMethod(
-"_nonLocalReturn_",
-smalltalk.method({
-selector: "nonLocalReturn:",
-fn: function (aBoolean) {
-var self=this;
-(self['@nonLocalReturn']=aBoolean);
-return self;}
-}),
-smalltalk.MethodLexicalScope);
-
 smalltalk.addMethod(
 "_nonLocalReturns",
 smalltalk.method({
@@ -366,9 +377,9 @@ smalltalk.addMethod(
 "_removeNonLocalReturn_",
 smalltalk.method({
 selector: "removeNonLocalReturn:",
-fn: function (aNode) {
+fn: function (aScope){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aScope, (function(){return nil;})]);
 return self;}
 }),
 smalltalk.MethodLexicalScope);
@@ -834,11 +845,10 @@ smalltalk.addMethod(
 "_visitAssignmentNode_",
 smalltalk.method({
 selector: "visitAssignmentNode:",
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
-smalltalk.send(smalltalk.send(aNode, "_right", []), "_assignedTo_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", [])]);
 return self;}
 }),
 smalltalk.SemanticAnalyzer);
@@ -922,9 +932,10 @@ 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", []), "_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(aNode, "_scope_", [self['@currentScope']]);
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [self['@currentScope']]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [self['@currentScope']]);})]));
 smalltalk.send(self, "_visitReturnNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 return self;}
 }),
@@ -934,12 +945,10 @@ 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 ((($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;}
 }),

+ 67 - 53
js/Compiler-Semantic.js

@@ -83,6 +83,22 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_canInlineNonLocalReturns",
+smalltalk.method({
+selector: "canInlineNonLocalReturns",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_isInlined", []), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_outerScope", []), "_canInlineNonLocalReturns", []);})]);
+return self;},
+args: [],
+source: "canInlineNonLocalReturns\x0a\x09^ self isInlined and: [ self outerScope canInlineNonLocalReturns ]",
+messageSends: ["and:", "isInlined", "canInlineNonLocalReturns", "outerScope"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_instruction",
 smalltalk.method({
@@ -115,6 +131,22 @@ referencedClasses: []
 }),
 smalltalk.LexicalScope);
 
+smalltalk.addMethod(
+"_isInlined",
+smalltalk.method({
+selector: "isInlined",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.send(smalltalk.send(self, "_instruction", []), "_isInlined", []);
+return self;},
+args: [],
+source: "isInlined\x0a\x09^ self instruction isInlined",
+messageSends: ["isInlined", "instruction"],
+referencedClasses: []
+}),
+smalltalk.LexicalScope);
+
 smalltalk.addMethod(
 "_isMethodScope",
 smalltalk.method({
@@ -304,12 +336,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "addNonLocalReturn:",
 category: 'adding',
-fn: function (aNode) {
+fn: function (aScope){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aNode]);
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_add_", [aScope]);
 return self;},
-args: ["aNode"],
-source: "addNonLocalReturn: aNode\x0a\x09self nonLocalReturns add: aNode",
+args: ["aScope"],
+source: "addNonLocalReturn: aScope\x0a\x09self nonLocalReturns add: aScope",
 messageSends: ["add:", "nonLocalReturns"],
 referencedClasses: []
 }),
@@ -347,6 +379,22 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
+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.MethodLexicalScope);
+
 smalltalk.addMethod(
 "_hasLocalReturn",
 smalltalk.method({
@@ -459,38 +507,6 @@ referencedClasses: []
 }),
 smalltalk.MethodLexicalScope);
 
-smalltalk.addMethod(
-"_nonLocalReturn",
-smalltalk.method({
-selector: "nonLocalReturn",
-category: 'accessing',
-fn: function () {
-var self=this;
-return (($receiver = self['@nonLocalReturn']) == nil || $receiver == undefined) ? (function(){return false;})() : $receiver;
-return self;},
-args: [],
-source: "nonLocalReturn\x0a\x09^ nonLocalReturn ifNil: [ false ]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-smalltalk.MethodLexicalScope);
-
-smalltalk.addMethod(
-"_nonLocalReturn_",
-smalltalk.method({
-selector: "nonLocalReturn:",
-category: 'accessing',
-fn: function (aBoolean) {
-var self=this;
-(self['@nonLocalReturn']=aBoolean);
-return self;},
-args: ["aBoolean"],
-source: "nonLocalReturn: aBoolean\x0a\x09nonLocalReturn := aBoolean",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.MethodLexicalScope);
-
 smalltalk.addMethod(
 "_nonLocalReturns",
 smalltalk.method({
@@ -529,12 +545,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "removeNonLocalReturn:",
 category: 'adding',
-fn: function (aNode) {
+fn: function (aScope){
 var self=this;
-smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aNode, (function(){return nil;})]);
+smalltalk.send(smalltalk.send(self, "_nonLocalReturns", []), "_remove_ifAbsent_", [aScope, (function(){return nil;})]);
 return self;},
-args: ["aNode"],
-source: "removeNonLocalReturn: aNode\x0a\x09self nonLocalReturns remove: aNode ifAbsent: []",
+args: ["aScope"],
+source: "removeNonLocalReturn: aScope\x0a\x09self nonLocalReturns remove: aScope ifAbsent: []",
 messageSends: ["remove:ifAbsent:", "nonLocalReturns"],
 referencedClasses: []
 }),
@@ -1206,15 +1222,14 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "visitAssignmentNode:",
 category: 'visiting',
-fn: function (aNode) {
+fn: function (aNode){
 var self=this;
 smalltalk.send(self, "_visitAssignmentNode_", [aNode], smalltalk.SemanticAnalyzer.superclass || nil);
 smalltalk.send(smalltalk.send(aNode, "_left", []), "_beAssigned", []);
-smalltalk.send(smalltalk.send(aNode, "_right", []), "_assignedTo_", [smalltalk.send(smalltalk.send(aNode, "_left", []), "_binding", [])]);
 return self;},
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned.\x0a\x09aNode right assignedTo: aNode left binding",
-messageSends: ["visitAssignmentNode:", "beAssigned", "left", "assignedTo:", "right", "binding"],
+source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned",
+messageSends: ["visitAssignmentNode:", "beAssigned", "left"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1319,14 +1334,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", []), "_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(aNode, "_scope_", [self['@currentScope']]);
+((($receiver = smalltalk.send(self['@currentScope'], "_isMethodScope", [])).klass === smalltalk.Boolean) ? (! $receiver ? (function(){return smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [self['@currentScope']]);})() : nil) : smalltalk.send($receiver, "_ifFalse_", [(function(){return smalltalk.send(smalltalk.send(self['@currentScope'], "_methodScope", []), "_addNonLocalReturn_", [self['@currentScope']]);})]));
 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 addNonLocalReturn: aNode.\x0a\x09\x09\x09aNode nonLocalReturn: true ].\x0a\x09super visitReturnNode: aNode",
-messageSends: ["ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "nonLocalReturn:", "visitReturnNode:"],
+source: "visitReturnNode: aNode\x0a\x09aNode scope: currentScope.\x0a\x09currentScope isMethodScope\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09currentScope methodScope addNonLocalReturn: currentScope ].\x0a\x09super visitReturnNode: aNode",
+messageSends: ["scope:", "ifFalse:", "isMethodScope", "addNonLocalReturn:", "methodScope", "visitReturnNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);
@@ -1336,17 +1352,15 @@ 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 ((($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 isSendNode ifTrue: [ each beUsed ]].\x0a\x0a\x09super visitSendNode: aNode",
-messageSends: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "add:", "messageSends", "selector", "ifNotNil:", "beUsed", "do:", "arguments", "isSendNode", "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\x09super visitSendNode: aNode",
+messageSends: ["ifTrue:", "=", "value", "receiver", "superSend:", "value:", "add:", "messageSends", "selector", "visitSendNode:"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzer);

+ 4 - 4
js/Compiler-Tests.deploy.js

@@ -120,14 +120,14 @@ smalltalk.addMethod(
 "_testNonLocalReturn",
 smalltalk.method({
 selector: "testNonLocalReturn",
-fn: function () {
+fn: function (){
 var self=this;
 var src=nil;
 var ast=nil;
 (src="foo | a | a + 1. ^ a");
 (ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
 smalltalk.send(self['@analyzer'], "_visit_", [ast]);
-smalltalk.send(self, "_deny_", [smalltalk.send(ast, "_hasNonLocalReturn", [])]);
+smalltalk.send(self, "_deny_", [smalltalk.send(smalltalk.send(ast, "_scope", []), "_hasNonLocalReturn", [])]);
 return self;}
 }),
 smalltalk.SemanticAnalyzerTest);
@@ -136,14 +136,14 @@ smalltalk.addMethod(
 "_testNonLocalReturn2",
 smalltalk.method({
 selector: "testNonLocalReturn2",
-fn: function () {
+fn: function (){
 var self=this;
 var src=nil;
 var ast=nil;
 (src="foo | a | a + 1. [ [ ^ a] ]");
 (ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
 smalltalk.send(self['@analyzer'], "_visit_", [ast]);
-smalltalk.send(self, "_assert_", [smalltalk.send(ast, "_hasNonLocalReturn", [])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(ast, "_scope", []), "_hasNonLocalReturn", [])]);
 return self;}
 }),
 smalltalk.SemanticAnalyzerTest);

+ 8 - 8
js/Compiler-Tests.js

@@ -161,18 +161,18 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "testNonLocalReturn",
 category: 'tests',
-fn: function () {
+fn: function (){
 var self=this;
 var src=nil;
 var ast=nil;
 (src="foo | a | a + 1. ^ a");
 (ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
 smalltalk.send(self['@analyzer'], "_visit_", [ast]);
-smalltalk.send(self, "_deny_", [smalltalk.send(ast, "_hasNonLocalReturn", [])]);
+smalltalk.send(self, "_deny_", [smalltalk.send(smalltalk.send(ast, "_scope", []), "_hasNonLocalReturn", [])]);
 return self;},
 args: [],
-source: "testNonLocalReturn\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | a + 1. ^ a'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self deny: ast hasNonLocalReturn",
-messageSends: ["parse:", "visit:", "deny:", "hasNonLocalReturn"],
+source: "testNonLocalReturn\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | a + 1. ^ a'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self deny: ast scope hasNonLocalReturn",
+messageSends: ["parse:", "visit:", "deny:", "hasNonLocalReturn", "scope"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzerTest);
@@ -182,18 +182,18 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "testNonLocalReturn2",
 category: 'tests',
-fn: function () {
+fn: function (){
 var self=this;
 var src=nil;
 var ast=nil;
 (src="foo | a | a + 1. [ [ ^ a] ]");
 (ast=smalltalk.send((typeof smalltalk == 'undefined' ? nil : smalltalk), "_parse_", [src]));
 smalltalk.send(self['@analyzer'], "_visit_", [ast]);
-smalltalk.send(self, "_assert_", [smalltalk.send(ast, "_hasNonLocalReturn", [])]);
+smalltalk.send(self, "_assert_", [smalltalk.send(smalltalk.send(ast, "_scope", []), "_hasNonLocalReturn", [])]);
 return self;},
 args: [],
-source: "testNonLocalReturn2\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | a + 1. [ [ ^ a] ]'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self assert: ast hasNonLocalReturn",
-messageSends: ["parse:", "visit:", "assert:", "hasNonLocalReturn"],
+source: "testNonLocalReturn2\x0a\x09| src ast |\x0a\x0a\x09src := 'foo | a | a + 1. [ [ ^ a] ]'.\x0a\x09ast := smalltalk parse: src.\x0a\x09analyzer visit: ast.\x0a\x0a\x09self assert: ast scope hasNonLocalReturn",
+messageSends: ["parse:", "visit:", "assert:", "hasNonLocalReturn", "scope"],
 referencedClasses: []
 }),
 smalltalk.SemanticAnalyzerTest);

+ 9 - 105
st/Compiler-AST.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-AST' properties: #{}!
 Object subclass: #Node
-	instanceVariableNames: 'nodes used assignedTo alias canBeInlined'
+	instanceVariableNames: 'nodes'
 	package: 'Compiler-AST'!
 !Node commentStamp!
 I am the abstract root class of the abstract syntax tree.!
@@ -11,44 +11,8 @@ addNode: aNode
 	self nodes add: aNode
 !
 
-alias
-	^ alias
-!
-
-alias: aString
-	alias := aString
-!
-
-assignedTo
-	^ assignedTo
-!
-
-assignedTo: aScopeVar
-	assignedTo := aScopeVar
-!
-
-beUsed
-	used := true
-!
-
-canBeInlined
-	^ canBeInlined ifNil: [ false ]
-!
-
-canBeInlined: aBoolean
-	canBeInlined := aBoolean
-!
-
 nodes
 	^nodes ifNil: [nodes := Array new]
-!
-
-used
-	^ used ifNil: [ false ]
-!
-
-used: aBoolean
-	used := aBoolean
 ! !
 
 !Node methodsFor: 'building'!
@@ -59,14 +23,6 @@ nodes: aCollection
 
 !Node methodsFor: 'testing'!
 
-canAliasChildren
-	^ true
-!
-
-isAliased
-	^ self alias notNil
-!
-
 isAssignmentNode
 	^ false
 !
@@ -83,16 +39,8 @@ isSendNode
 	^false
 !
 
-isUsed
-	^ self used
-!
-
 isValueNode
 	^false
-!
-
-shouldBeAliased
-	^ self isUsed and: [ self alias isNil ]
 ! !
 
 !Node methodsFor: 'visiting'!
@@ -112,8 +60,7 @@ left
 !
 
 left: aNode
-	left := aNode.
-	left assigned: true
+	left := aNode
 !
 
 nodes
@@ -164,11 +111,6 @@ scope: aLexicalScope
 
 !BlockNode methodsFor: 'testing'!
 
-canInlineNonLocalReturns
-	^ self canBeInlined and: [
-		self scope outerScope node canInlineNonLocalReturns]
-!
-
 isBlockNode
 	^true
 ! !
@@ -185,14 +127,6 @@ Node subclass: #CascadeNode
 
 !CascadeNode methodsFor: 'accessing'!
 
-alias
-	^self nodes last alias
-!
-
-beUsed
-	self nodes do: [ :each | each beUsed ]
-!
-
 receiver
 	^receiver
 !
@@ -301,28 +235,6 @@ source: aString
 	source := aString
 ! !
 
-!MethodNode methodsFor: 'testing'!
-
-canAliasChildren
-	^ false
-!
-
-canInlineNonLocalReturns
-	^ true
-!
-
-hasLocalReturn
-	^ self scope
-		ifNil: [ false ]
-		ifNotNil: [ self scope hasLocalReturn ]
-!
-
-hasNonLocalReturn
-	^ self scope
-		ifNil: [ false ]
-		ifNotNil: [ self scope hasNonLocalReturn ]
-! !
-
 !MethodNode methodsFor: 'visiting'!
 
 accept: aVisitor
@@ -330,23 +242,23 @@ accept: aVisitor
 ! !
 
 Node subclass: #ReturnNode
-	instanceVariableNames: 'nonLocalReturn canBeInlined'
+	instanceVariableNames: 'scope'
 	package: 'Compiler-AST'!
 
 !ReturnNode methodsFor: 'accessing'!
 
-nonLocalReturn
-	^ nonLocalReturn ifNil: [ false ]
+scope
+	^ scope
 !
 
-nonLocalReturn: aBoolean
-	nonLocalReturn := aBoolean
+scope: aLexicalScope
+	scope := aLexicalScope
 ! !
 
 !ReturnNode methodsFor: 'testing'!
 
-shouldBeAliased
-	^ false
+nonLocalReturn
+	^ self scope isMethodScope not
 ! !
 
 !ReturnNode methodsFor: 'visiting'!
@@ -462,10 +374,6 @@ asBlockSequenceNode
 	    nodes: self nodes;
 	    temps: self temps;
 	    yourself
-!
-
-canAliasChildren
-	^ false
 ! !
 
 !SequenceNode methodsFor: 'visiting'!
@@ -508,10 +416,6 @@ value: anObject
 
 isValueNode
 	^true
-!
-
-shouldBeAliased
-	^ false
 ! !
 
 !ValueNode methodsFor: 'visiting'!

+ 8 - 0
st/Compiler-Exceptions.st

@@ -29,6 +29,10 @@ I get signaled when a pseudo variable gets assigned.!
 
 !InvalidAssignmentError methodsFor: 'accessing'!
 
+messageText
+	^ ' Invalid assignment to variable: ', self variableName
+!
+
 variableName
 	^ variableName
 !
@@ -45,6 +49,10 @@ I get signaled when a variable in a block or method scope shadows a variable of
 
 !ShadowingVariableError methodsFor: 'accessing'!
 
+messageText
+	^ 'Variable shadowing error: ', self variableName, ' is already defined'
+!
+
 variableName
 	^ variableName
 !

+ 79 - 48
st/Compiler-IR.st

@@ -44,6 +44,15 @@ theClass
 
 theClass: aClass
 	theClass := aClass
+!
+
+withSequence: aSequence do: aBlock
+	| outerSequence |
+	outerSequence := self sequence.
+	self sequence: aSequence.
+	aBlock value.
+	self sequence: outerSequence.
+	^ aSequence
 ! !
 
 !IRASTTranslator methodsFor: 'visiting'!
@@ -86,6 +95,7 @@ visitBlockNode: aNode
 	| closure |
 	closure := IRClosure new
 		arguments: aNode parameters;
+		scope: aNode scope;
 		yourself.
 	aNode scope temps do: [ :each |
 		closure add: (IRTempDeclaration new 
@@ -96,19 +106,17 @@ visitBlockNode: aNode
 !
 
 visitBlockSequenceNode: aNode
-	| seq |
-	seq := IRBlockSequence new.
-	self sequence: seq.
-	aNode nodes do: [ :each | 
-		self sequence add: (self visit: each) ].
-	^ seq
+	^ self
+		withSequence: IRBlockSequence new
+		do: [ aNode nodes do: [ :each | 
+			self sequence add: (self visit: each) ]]
 !
 
 visitCascadeNode: aNode
 	| alias |
 
 	aNode receiver isValueNode ifFalse: [ 
-		alias := self sequence add: (self alias: aNode receiver).
+		alias := self alias: aNode receiver.
 		aNode nodes do: [ :each |
 			each receiver: (VariableNode new binding: alias variable) ]].
 
@@ -132,6 +140,7 @@ visitMethodNode: aNode
 		selector: aNode selector;
 		messageSends: aNode messageSends;
 		classReferences: aNode classReferences;
+		scope: aNode scope;
 		yourself).
 
 	aNode scope temps do: [ :each |
@@ -139,14 +148,9 @@ visitMethodNode: aNode
 			name: each name;
 			yourself) ].
 
-	aNode hasNonLocalReturn 
-		ifTrue: [ | handling |
-			handling := IRNonLocalReturnHandling new.
-			aNode nodes do: [ :each | handling add: (self visit: each) ].
-			self method add: handling ]
-		ifFalse: [ aNode nodes do: [ :each | self method add: (self visit: each) ]].
+	aNode nodes do: [ :each | self method add: (self visit: each) ].
 
-	aNode hasLocalReturn ifFalse: [
+	aNode scope hasLocalReturn ifFalse: [
 		(self method add: IRReturn new) add: (IRVariable new
 			variable: (aNode scope pseudoVars at: 'self');
 			yourself) ].
@@ -159,6 +163,7 @@ visitReturnNode: aNode
 	return := aNode nonLocalReturn 
 		ifTrue: [ IRNonLocalReturn new ]
 		ifFalse: [ IRReturn new ].
+	return scope: aNode scope.
 	aNode nodes do: [ :each | return add: (self visit: each) ].
 	^ return
 !
@@ -179,12 +184,13 @@ visitSendNode: aNode
 !
 
 visitSequenceNode: aNode
-	| seq |
-	seq := IRSequence new.
-	self sequence: seq.
-	aNode nodes do: [ :each | 
-		self sequence add: (self visit: each) ].
-	^ seq
+	^ self 
+		withSequence: IRSequence new 	
+		do: [
+			aNode nodes do: [ :each | | instruction |
+				instruction := self visit: each.
+				instruction isVariable ifFalse: [
+					self sequence add: instruction ]]]
 !
 
 visitValueNode: aNode
@@ -248,6 +254,10 @@ replaceWith: anIRInstruction
 
 !IRInstruction methodsFor: 'testing'!
 
+canBeAssigned
+	^ true
+!
+
 isClosure
 	^ false
 !
@@ -302,7 +312,21 @@ accept: aVisitor
 	^ aVisitor visitIRAlias: self
 ! !
 
-IRInstruction subclass: #IRClosure
+IRInstruction subclass: #IRScopedInstruction
+	instanceVariableNames: 'scope'
+	package: 'Compiler-IR'!
+
+!IRScopedInstruction methodsFor: 'accessing'!
+
+scope
+	^ scope
+!
+
+scope: aScope
+	scope := aScope
+! !
+
+IRScopedInstruction subclass: #IRClosure
 	instanceVariableNames: 'arguments'
 	package: 'Compiler-IR'!
 
@@ -314,6 +338,11 @@ arguments
 
 arguments: aCollection
 	arguments := aCollection
+!
+
+scope: aScope
+	super scope: aScope.
+	aScope instruction: self
 ! !
 
 !IRClosure methodsFor: 'testing'!
@@ -328,7 +357,7 @@ accept: aVisitor
 	^ aVisitor visitIRClosure: self
 ! !
 
-IRInstruction subclass: #IRMethod
+IRScopedInstruction subclass: #IRMethod
 	instanceVariableNames: 'source selector classReferences messageSends arguments internalVariables'
 	package: 'Compiler-IR'!
 !IRMethod commentStamp!
@@ -364,6 +393,11 @@ messageSends: aCollection
 	messageSends := aCollection
 !
 
+scope: aScope
+	super scope: aScope.
+	aScope instruction: self
+!
+
 selector
 	^ selector
 !
@@ -386,20 +420,7 @@ 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
+IRScopedInstruction subclass: #IRReturn
 	instanceVariableNames: ''
 	package: 'Compiler-IR'!
 !IRReturn commentStamp!
@@ -407,6 +428,10 @@ I am a local return instruction.!
 
 !IRReturn methodsFor: 'testing'!
 
+canBeAssigned
+	^ false
+!
+
 isReturn
 	^ true
 ! !
@@ -507,6 +532,10 @@ Statements can be used to control the PC count, among other things.!
 
 !IRStatement methodsFor: 'testing'!
 
+canBeAssigned
+	^ self instructions first canBeAssigned
+!
+
 isReturn
 	^ self instructions first isReturn
 ! !
@@ -643,12 +672,16 @@ visitIRInlinedClosure: anIRClosure
 	^ self visitIRClosure: anIRClosure
 !
 
+visitIRInlinedIfFalse: anIRInlinedIfFalse
+	^ self visitIRInlinedSend: anIRInlinedIfFalse
+!
+
 visitIRInlinedIfTrue: anIRInlinedIfTrue
 	^ self visitIRInlinedSend: anIRInlinedIfTrue
 !
 
 visitIRInlinedNonLocalReturn: anIRNonLocalReturn
-	^ self visitIRNonLocalReturn: anIRNonLocalReturn anIRNonLocalReturn
+	^ self visitIRReturn: anIRNonLocalReturn
 !
 
 visitIRInlinedSend: anIRInlinedSend
@@ -656,7 +689,8 @@ visitIRInlinedSend: anIRInlinedSend
 !
 
 visitIRInstruction: anIRInstruction
-	^ anIRInstruction instructions do: [ :each | self visit: each ]
+	anIRInstruction instructions do: [ :each | self visit: each ].
+	^ anIRInstruction
 !
 
 visitIRMethod: anIRMethod
@@ -760,7 +794,11 @@ visitIRMethod: anIRMethod
 				anIRMethod internalVariables notEmpty ifTrue: [
 					self stream nextPutVars: (anIRMethod internalVariables asArray collect: [ :each |
 						each variable alias ]) ].
-				super visitIRMethod: anIRMethod ]
+				anIRMethod scope hasNonLocalReturn 
+					ifTrue: [
+						self stream nextPutNonLocalReturnHandlingWith: [
+							super visitIRMethod: anIRMethod ]]
+					ifFalse: [ super visitIRMethod: anIRMethod ]]
 			arguments: anIRMethod arguments ]
 !
 
@@ -769,11 +807,6 @@ visitIRNonLocalReturn: anIRNonLocalReturn
 		super visitIRNonLocalReturn: anIRNonLocalReturn ]
 !
 
-visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling
-	self stream nextPutNonLocalReturnHandlingWith: [
-		super visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling ]
-!
-
 visitIRReturn: anIRReturn
 	self stream nextPutReturnWith: [
 		super visitIRReturn: anIRReturn ]
@@ -803,10 +836,8 @@ visitIRSequence: anIRSequence
 !
 
 visitIRStatement: anIRStatement
-	(anIRStatement instructions size = 1 and: [
-		anIRStatement instructions first isVariable ]) ifFalse: [
-			self stream nextPutStatementWith: [
-				super visitIRStatement: anIRStatement ]]
+	self stream nextPutStatementWith: [
+		super visitIRStatement: anIRStatement ]
 !
 
 visitIRTempDeclaration: anIRTempDeclaration

+ 66 - 17
st/Compiler-Inlining.st

@@ -41,7 +41,7 @@ accept: aVisitor
 	aVisitor visitIRInlinedClosure: self
 ! !
 
-IRNonLocalReturn subclass: #IRInlinedNonLocalReturn
+IRReturn subclass: #IRInlinedNonLocalReturn
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
 
@@ -73,6 +73,16 @@ accept: aVisitor
 	aVisitor visitInlinedSend: self
 ! !
 
+IRInlinedSend subclass: #IRInlinedIfFalse
+	instanceVariableNames: ''
+	package: 'Compiler-Inlining'!
+
+!IRInlinedIfFalse methodsFor: 'visiting'!
+
+accept: aVisitor
+	aVisitor visitIRInlinedIfFalse: self
+! !
+
 IRInlinedSend subclass: #IRInlinedIfTrue
 	instanceVariableNames: ''
 	package: 'Compiler-Inlining'!
@@ -115,21 +125,28 @@ sendInliner
 !
 
 visitIRAssignment: anIRAssignment
-	^ (self shouldInlineAssignment: anIRAssignment) 
+	(self shouldInlineAssignment: anIRAssignment) 
 		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]
 		ifFalse: [ super visitIRAssignment: anIRAssignment ]
 !
 
+visitIRNonLocalReturn: anIRNonLocalReturn
+	| localReturn |
+	anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [
+		anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.
+		localReturn := IRInlinedNonLocalReturn new
+			scope: anIRNonLocalReturn scope;
+			yourself.
+		anIRNonLocalReturn instructions do: [ :each |
+			localReturn add: each ].
+		anIRNonLocalReturn replaceWith: localReturn ].
+	super visitIRNonLocalReturn: anIRNonLocalReturn
+!
+
 visitIRSend: anIRSend
-	^ (self shouldInlineSend: anIRSend)
+	(self shouldInlineSend: anIRSend)
 		ifTrue: [ self sendInliner inlineSend: anIRSend ]
 		ifFalse: [ super visitIRSend: anIRSend ]
-!
-
-visitSendNode: aNode
-	aNode canBeInlined
-		ifTrue: [ self sendInliner inlineSend: aNode ]
-		ifFalse: [ super visitSendNode: aNode ]
 ! !
 
 IRJSTranslator subclass: #IRInliningJSTranslator
@@ -144,12 +161,21 @@ visitIRInlinedAssignment: anIRInlinedAssignment
 
 visitIRInlinedClosure: anIRInlinedClosure
 	anIRInlinedClosure instructions allButLast do: [ :each | self visit: each ].
-	anIRInlinedClosure assignTo ifNotNil: [
-		self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
-		self stream nextPutAssignment ].
+	(anIRInlinedClosure assignTo notNil and: [
+		anIRInlinedClosure instructions last canBeAssigned ]) ifTrue: [
+			self stream nextPutAll: anIRInlinedClosure assignTo variable alias.
+			self stream nextPutAssignment ].
 	self visit: anIRInlinedClosure instructions last
 !
 
+visitIRInlinedIfFalse: anIRInlinedIfFalse
+	self stream 
+		nextPutIf: [ 
+			self stream nextPutAll: '!!'.
+			self visit: anIRInlinedIfFalse instructions first ]
+		with: [ self visit: anIRInlinedIfFalse instructions last ]
+!
+
 visitIRInlinedIfTrue: anIRInlinedIfTrue
 	self stream 
 		nextPutIf: [ self visit: anIRInlinedIfTrue instructions first ]
@@ -192,16 +218,30 @@ inliningError: aString
 
 !IRSendInliner methodsFor: 'inlining'!
 
+ifFalse: anIRInstruction
+	| inlinedSend inlinedClosure |
+
+	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
+	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
+
+	inlinedClosure := self inlineClosure: anIRInstruction.
+
+	inlinedSend := IRInlinedIfFalse new.
+	inlinedSend
+		add: self send instructions first;
+		add: inlinedClosure.
+
+	self send replaceWith: inlinedSend.
+	^ inlinedSend
+!
+
 ifTrue: anIRInstruction
 	| inlinedSend inlinedClosure |
 
 	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].
 	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].
 
-	inlinedClosure := self inlinedClosure.
-	anIRInstruction instructions do: [ :each |
-		instruction := (self translator visit: each) first.
-		inlinedClosure add: instruction ].
+	inlinedClosure := self inlineClosure: anIRInstruction.
 
 	inlinedSend := IRInlinedIfTrue new.
 	inlinedSend
@@ -212,6 +252,15 @@ ifTrue: anIRInstruction
 	^ inlinedSend
 !
 
+inlineClosure: anIRClosure
+	| inlinedClosure |
+	inlinedClosure := self inlinedClosure.
+	inlinedClosure scope: anIRClosure scope.
+	anIRClosure instructions first instructions do: [ :each |
+		inlinedClosure add: (self translator visit: each) ].
+	^ inlinedClosure
+!
+
 inlineSend: anIRSend
 	self send: anIRSend.
 	self perform: self send selector withArguments: self send instructions allButFirst
@@ -220,7 +269,7 @@ inlineSend: anIRSend
 !IRSendInliner class methodsFor: 'accessing'!
 
 inlinedSelectors
-	^ #('ifTrue:')
+	^ #('ifTrue:' 'ifFalse:')
 ! !
 
 IRSendInliner subclass: #IRAssignmentInliner

+ 20 - 23
st/Compiler-Semantic.st

@@ -93,6 +93,14 @@ addTemp: aString
 
 !LexicalScope methodsFor: 'testing'!
 
+canInlineNonLocalReturns
+	^ self isInlined and: [ self outerScope canInlineNonLocalReturns ]
+!
+
+isInlined
+	^ self instruction isInlined
+!
+
 isMethodScope
 	^ false
 ! !
@@ -130,14 +138,6 @@ methodScope
 	^ self
 !
 
-nonLocalReturn
-	^ nonLocalReturn ifNil: [ false ]
-!
-
-nonLocalReturn: aBoolean
-	nonLocalReturn := aBoolean
-!
-
 nonLocalReturns
 	^ nonLocalReturns ifNil: [ nonLocalReturns := OrderedCollection new ]
 !
@@ -163,16 +163,20 @@ addIVar: aString
 	(self iVars at: aString) scope: self
 !
 
-addNonLocalReturn: aNode
-	self nonLocalReturns add: aNode
+addNonLocalReturn: aScope
+	self nonLocalReturns add: aScope
 !
 
-removeNonLocalReturn: aNode
-	self nonLocalReturns remove: aNode ifAbsent: []
+removeNonLocalReturn: aScope
+	self nonLocalReturns remove: aScope ifAbsent: []
 ! !
 
 !MethodLexicalScope methodsFor: 'testing'!
 
+canInlineNonLocalReturns
+	^ true
+!
+
 hasLocalReturn
 	^ self localReturn
 !
@@ -451,8 +455,7 @@ allowUnknownVariables
 
 visitAssignmentNode: aNode
 	super visitAssignmentNode: aNode.
-	aNode left beAssigned.
-	aNode right assignedTo: aNode left binding
+	aNode left beAssigned
 !
 
 visitBlockNode: aNode
@@ -502,11 +505,10 @@ visitMethodNode: aNode
 !
 
 visitReturnNode: aNode
-	currentScope isMethodScope 
-		ifTrue: [ currentScope localReturn: true ]
+	aNode scope: currentScope.
+	currentScope isMethodScope
 		ifFalse: [
-			currentScope methodScope addNonLocalReturn: aNode.
-			aNode nonLocalReturn: true ].
+			currentScope methodScope addNonLocalReturn: currentScope ].
 	super visitReturnNode: aNode
 !
 
@@ -517,11 +519,6 @@ visitSendNode: aNode
 		aNode receiver value: 'self'].
 
 	self messageSends add: aNode selector.
-	aNode receiver ifNotNil: [
-		aNode receiver beUsed ].
-	aNode arguments do: [ :each |
-		each isSendNode ifTrue: [ each beUsed ]].
-
 	super visitSendNode: aNode
 !
 

+ 2 - 2
st/Compiler-Tests.st

@@ -88,7 +88,7 @@ testNonLocalReturn
 	ast := smalltalk parse: src.
 	analyzer visit: ast.
 
-	self deny: ast hasNonLocalReturn
+	self deny: ast scope hasNonLocalReturn
 !
 
 testNonLocalReturn2
@@ -98,7 +98,7 @@ testNonLocalReturn2
 	ast := smalltalk parse: src.
 	analyzer visit: ast.
 
-	self assert: ast hasNonLocalReturn
+	self assert: ast scope hasNonLocalReturn
 !
 
 testScope

Some files were not shown because too many files changed in this diff