Browse Source

new interpreter passes the tests

Nicolas Petton 11 years ago
parent
commit
5c06010269

+ 105 - 33
js/Compiler-AST.deploy.js

@@ -27,61 +27,45 @@ smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "extent",
+selector: "isAssignmentNode",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=self._nextNode();
-if(($receiver = $2) == nil || $receiver == undefined){
-$3=self._parent();
-if(($receiver = $3) == nil || $receiver == undefined){
-$1=$3;
-} else {
-var node;
-node=$receiver;
-$1=_st(node)._extent();
-};
-} else {
-var node;
-node=$receiver;
-$1=_st(node)._position();
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"extent",{},smalltalk.Node)})},
-messageSends: ["ifNil:ifNotNil:", "ifNotNil:", "extent", "parent", "position", "nextNode"]}),
+return false;
+}, function($ctx1) {$ctx1.fill(self,"isAssignmentNode",{},smalltalk.Node)})},
+messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isAssignmentNode",
+selector: "isBlockNode",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isAssignmentNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isBlockNode",{},smalltalk.Node)})},
 messageSends: []}),
 messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isBlockNode",
+selector: "isBlockSequenceNode",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isBlockNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isBlockSequenceNode",{},smalltalk.Node)})},
 messageSends: []}),
 messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isBlockSequenceNode",
+selector: "isCascadeNode",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isBlockSequenceNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isCascadeNode",{},smalltalk.Node)})},
 messageSends: []}),
 messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
@@ -107,6 +91,19 @@ return false;
 messageSends: []}),
 messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isLastChild",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(self._parent())._nodes())._last()).__eq(self);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isLastChild",{},smalltalk.Node)})},
+messageSends: ["=", "last", "nodes", "parent"]}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isNode",
 selector: "isNode",
@@ -307,6 +304,21 @@ return self}, function($ctx1) {$ctx1.fill(self,"position:",{aPosition:aPosition}
 messageSends: []}),
 messageSends: []}),
 smalltalk.Node);
 smalltalk.Node);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "postCopy",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.Object.fn.prototype._postCopy.apply(_st(self), []);
+_st(self._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each)._parent_(self);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"postCopy",{},smalltalk.Node)})},
+messageSends: ["postCopy", "do:", "nodes", "parent:"]}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "shouldBeAliased",
 selector: "shouldBeAliased",
@@ -519,6 +531,19 @@ return true;
 messageSends: []}),
 messageSends: []}),
 smalltalk.BlockNode);
 smalltalk.BlockNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "nextChild",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"nextChild",{},smalltalk.BlockNode)})},
+messageSends: []}),
+smalltalk.BlockNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "nextNode:",
 selector: "nextNode:",
@@ -619,6 +644,17 @@ return $1;
 messageSends: ["visitCascadeNode:"]}),
 messageSends: ["visitCascadeNode:"]}),
 smalltalk.CascadeNode);
 smalltalk.CascadeNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isCascadeNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return true;
+}, function($ctx1) {$ctx1.fill(self,"isCascadeNode",{},smalltalk.CascadeNode)})},
+messageSends: []}),
+smalltalk.CascadeNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "receiver",
 selector: "receiver",
@@ -1097,6 +1133,19 @@ return self}, function($ctx1) {$ctx1.fill(self,"index:",{anInteger:anInteger},sm
 messageSends: []}),
 messageSends: []}),
 smalltalk.SendNode);
 smalltalk.SendNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isCascadeSendNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._parent())._isCascadeNode();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isCascadeSendNode",{},smalltalk.SendNode)})},
+messageSends: ["isCascadeNode", "parent"]}),
+smalltalk.SendNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isSendNode",
 selector: "isSendNode",
@@ -1115,14 +1164,21 @@ fn: function (){
 var self=this;
 var self=this;
 function $Array(){return smalltalk.Array||(typeof Array=="undefined"?nil:Array)}
 function $Array(){return smalltalk.Array||(typeof Array=="undefined"?nil:Array)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=_st($Array())._withAll_(self._arguments());
-_st($2)._add_(self._receiver());
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
+var $1,$2,$4,$5,$3;
+$1=self._receiver();
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=_st(self._arguments())._copy();
+return $2;
+} else {
+$1;
+};
+$4=_st($Array())._with_(self._receiver());
+_st($4)._addAll_(self._arguments());
+$5=_st($4)._yourself();
+$3=$5;
+return $3;
 }, function($ctx1) {$ctx1.fill(self,"nodes",{},smalltalk.SendNode)})},
 }, function($ctx1) {$ctx1.fill(self,"nodes",{},smalltalk.SendNode)})},
-messageSends: ["add:", "receiver", "withAll:", "arguments", "yourself"]}),
+messageSends: ["ifNil:", "receiver", "copy", "arguments", "addAll:", "with:", "yourself"]}),
 smalltalk.SendNode);
 smalltalk.SendNode);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1424,6 +1480,22 @@ return self}, function($ctx1) {$ctx1.fill(self,"value:",{anObject:anObject},smal
 messageSends: []}),
 messageSends: []}),
 smalltalk.ValueNode);
 smalltalk.ValueNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "xxxDoIt",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._stack();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"xxxDoIt",{},smalltalk.ValueNode)})},
+messageSends: ["value", "stack"]}),
+smalltalk.ValueNode);
+
 
 
 
 
 smalltalk.addClass('VariableNode', smalltalk.ValueNode, ['assigned', 'binding'], 'Compiler-AST');
 smalltalk.addClass('VariableNode', smalltalk.ValueNode, ['assigned', 'binding'], 'Compiler-AST');

+ 141 - 39
js/Compiler-AST.js

@@ -38,47 +38,31 @@ smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "extent",
-category: 'accessing',
+selector: "isAssignmentNode",
+category: 'testing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=self._nextNode();
-if(($receiver = $2) == nil || $receiver == undefined){
-$3=self._parent();
-if(($receiver = $3) == nil || $receiver == undefined){
-$1=$3;
-} else {
-var node;
-node=$receiver;
-$1=_st(node)._extent();
-};
-} else {
-var node;
-node=$receiver;
-$1=_st(node)._position();
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"extent",{},smalltalk.Node)})},
+return false;
+}, function($ctx1) {$ctx1.fill(self,"isAssignmentNode",{},smalltalk.Node)})},
 args: [],
 args: [],
-source: "extent\x0a\x09\x22Answer the line and column of the end position of the receiver in the source code\x22\x0a\x09\x0a\x09^ self nextNode \x0a\x09\x09ifNil: [ self parent ifNotNil: [ :node | node extent ] ]\x0a\x09\x09ifNotNil: [ :node | node position ]",
-messageSends: ["ifNil:ifNotNil:", "ifNotNil:", "extent", "parent", "position", "nextNode"],
+source: "isAssignmentNode\x0a\x09^ false",
+messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Node);
 smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isAssignmentNode",
+selector: "isBlockNode",
 category: 'testing',
 category: 'testing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isAssignmentNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isBlockNode",{},smalltalk.Node)})},
 args: [],
 args: [],
-source: "isAssignmentNode\x0a\x09^ false",
+source: "isBlockNode\x0a\x09^false",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -86,15 +70,15 @@ smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isBlockNode",
+selector: "isBlockSequenceNode",
 category: 'testing',
 category: 'testing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isBlockNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isBlockSequenceNode",{},smalltalk.Node)})},
 args: [],
 args: [],
-source: "isBlockNode\x0a\x09^false",
+source: "isBlockSequenceNode\x0a\x09^false",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -102,15 +86,15 @@ smalltalk.Node);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "isBlockSequenceNode",
+selector: "isCascadeNode",
 category: 'testing',
 category: 'testing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 return false;
 return false;
-}, function($ctx1) {$ctx1.fill(self,"isBlockSequenceNode",{},smalltalk.Node)})},
+}, function($ctx1) {$ctx1.fill(self,"isCascadeNode",{},smalltalk.Node)})},
 args: [],
 args: [],
-source: "isBlockSequenceNode\x0a\x09^false",
+source: "isCascadeNode\x0a\x09^ false",
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -148,6 +132,24 @@ referencedClasses: []
 }),
 }),
 smalltalk.Node);
 smalltalk.Node);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isLastChild",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(self._parent())._nodes())._last()).__eq(self);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isLastChild",{},smalltalk.Node)})},
+args: [],
+source: "isLastChild\x0a\x09^ self parent nodes last = self",
+messageSends: ["=", "last", "nodes", "parent"],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isNode",
 selector: "isNode",
@@ -413,6 +415,26 @@ referencedClasses: []
 }),
 }),
 smalltalk.Node);
 smalltalk.Node);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "postCopy",
+category: 'copying',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+smalltalk.Object.fn.prototype._postCopy.apply(_st(self), []);
+_st(self._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each)._parent_(self);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"postCopy",{},smalltalk.Node)})},
+args: [],
+source: "postCopy\x0a\x09super postCopy.\x0a\x09self nodes do: [ :each | each parent: self ]",
+messageSends: ["postCopy", "do:", "nodes", "parent:"],
+referencedClasses: []
+}),
+smalltalk.Node);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "shouldBeAliased",
 selector: "shouldBeAliased",
@@ -702,6 +724,24 @@ referencedClasses: []
 }),
 }),
 smalltalk.BlockNode);
 smalltalk.BlockNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "nextChild",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"nextChild",{},smalltalk.BlockNode)})},
+args: [],
+source: "nextChild\x0a\x09\x22Answer the receiver as we want to avoid eager evaluation\x22\x0a\x09\x0a\x09^ self",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.BlockNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "nextNode:",
 selector: "nextNode:",
@@ -838,6 +878,22 @@ referencedClasses: []
 }),
 }),
 smalltalk.CascadeNode);
 smalltalk.CascadeNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isCascadeNode",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return true;
+}, function($ctx1) {$ctx1.fill(self,"isCascadeNode",{},smalltalk.CascadeNode)})},
+args: [],
+source: "isCascadeNode\x0a\x09^ true",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.CascadeNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "receiver",
 selector: "receiver",
@@ -1497,6 +1553,24 @@ referencedClasses: []
 }),
 }),
 smalltalk.SendNode);
 smalltalk.SendNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isCascadeSendNode",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._parent())._isCascadeNode();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isCascadeSendNode",{},smalltalk.SendNode)})},
+args: [],
+source: "isCascadeSendNode\x0a\x09^ self parent isCascadeNode",
+messageSends: ["isCascadeNode", "parent"],
+referencedClasses: []
+}),
+smalltalk.SendNode);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "isSendNode",
 selector: "isSendNode",
@@ -1521,16 +1595,23 @@ fn: function (){
 var self=this;
 var self=this;
 function $Array(){return smalltalk.Array||(typeof Array=="undefined"?nil:Array)}
 function $Array(){return smalltalk.Array||(typeof Array=="undefined"?nil:Array)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=_st($Array())._withAll_(self._arguments());
-_st($2)._add_(self._receiver());
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
+var $1,$2,$4,$5,$3;
+$1=self._receiver();
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=_st(self._arguments())._copy();
+return $2;
+} else {
+$1;
+};
+$4=_st($Array())._with_(self._receiver());
+_st($4)._addAll_(self._arguments());
+$5=_st($4)._yourself();
+$3=$5;
+return $3;
 }, function($ctx1) {$ctx1.fill(self,"nodes",{},smalltalk.SendNode)})},
 }, function($ctx1) {$ctx1.fill(self,"nodes",{},smalltalk.SendNode)})},
 args: [],
 args: [],
-source: "nodes\x0a\x09^ (Array withAll: self arguments)\x0a\x09\x09add: self receiver;\x0a\x09\x09yourself",
-messageSends: ["add:", "receiver", "withAll:", "arguments", "yourself"],
+source: "nodes\x0a\x09self receiver ifNil: [ ^ self arguments copy ].\x0a\x09\x0a\x09^ (Array with: self receiver)\x0a\x09\x09addAll: self arguments;\x0a\x09\x09yourself",
+messageSends: ["ifNil:", "receiver", "copy", "arguments", "addAll:", "with:", "yourself"],
 referencedClasses: ["Array"]
 referencedClasses: ["Array"]
 }),
 }),
 smalltalk.SendNode);
 smalltalk.SendNode);
@@ -1942,6 +2023,27 @@ referencedClasses: []
 }),
 }),
 smalltalk.ValueNode);
 smalltalk.ValueNode);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "xxxDoIt",
+category: 'xxxDoIt',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._stack();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._value();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"xxxDoIt",{},smalltalk.ValueNode)})},
+args: [],
+source: "xxxDoIt ^[self stack] value",
+messageSends: ["value", "stack"],
+referencedClasses: []
+}),
+smalltalk.ValueNode);
+
 
 
 
 
 smalltalk.addClass('VariableNode', smalltalk.ValueNode, ['assigned', 'binding'], 'Compiler-AST');
 smalltalk.addClass('VariableNode', smalltalk.ValueNode, ['assigned', 'binding'], 'Compiler-AST');

+ 139 - 29
js/Compiler-Interpreter.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Interpreter');
 smalltalk.addPackage('Compiler-Interpreter');
-smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'ast', 'interpreter'], 'Compiler-Interpreter');
+smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'ast', 'interpreter', 'methodContext'], 'Compiler-Interpreter');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "arguments",
 selector: "arguments",
@@ -13,7 +13,7 @@ return self._localAt_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"arguments",{},smalltalk.AIContext)})},
 }, function($ctx1) {$ctx1.fill(self,"arguments",{},smalltalk.AIContext)})},
-messageSends: ["collect:", "localAt:", "arguments", "ast"]}),
+messageSends: ["collect:", "arguments", "ast", "localAt:"]}),
 smalltalk.AIContext);
 smalltalk.AIContext);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -448,7 +448,7 @@ _st(_st($SemanticAnalyzer())._on_(_st(_st(self._context())._receiver())._class()
 $1=ast;
 $1=ast;
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast},smalltalk.ASTDebugger)})},
 }, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast},smalltalk.ASTDebugger)})},
-messageSends: ["parse:", "source", "method", "current", "visit:", "on:", "class", "receiver", "context"]}),
+messageSends: ["parse:", "current", "source", "method", "visit:", "on:", "class", "receiver", "context"]}),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -506,7 +506,7 @@ $2=_st($1)._currentNode();
 next=$2;
 next=$2;
 _st(self._interpreter())._interpret_(next);
 _st(self._interpreter())._interpret_(next);
 return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{ast:ast,next:next},smalltalk.ASTDebugger)})},
 return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{ast:ast,next:next},smalltalk.ASTDebugger)})},
-messageSends: ["buildAST", "context:", "context", "new", "visit:", "currentNode", "interpret:", "interpreter"]}),
+messageSends: ["buildAST", "context:", "new", "context", "visit:", "currentNode", "interpret:", "interpreter"]}),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -620,7 +620,7 @@ _st(self._interpreter())._step();
 return self._step();
 return self._step();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"step",{},smalltalk.ASTDebugger)})},
 return self}, function($ctx1) {$ctx1.fill(self,"step",{},smalltalk.ASTDebugger)})},
-messageSends: ["whileFalse:", "step", "interpreter", "or:", "not", "atEnd", "and:", "stopOnStepping", "nextNode", "notNil"]}),
+messageSends: ["whileFalse:", "or:", "and:", "notNil", "nextNode", "interpreter", "stopOnStepping", "not", "atEnd", "step"]}),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -679,7 +679,7 @@ $1=_st(self._context())._localAt_put_(_st(aNode)._value(),anObject);
 };
 };
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"assign:to:",{aNode:aNode,anObject:anObject},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"assign:to:",{aNode:aNode,anObject:anObject},smalltalk.ASTInterpreter)})},
-messageSends: ["ifTrue:ifFalse:", "instVarAt:put:", "value", "receiver", "context", "localAt:put:", "isInstanceVar", "binding"]}),
+messageSends: ["ifTrue:ifFalse:", "isInstanceVar", "binding", "instVarAt:put:", "receiver", "context", "value", "localAt:put:"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -823,7 +823,7 @@ return self._continue_value_(aBlock,value);
 self._continue_value_(aBlock,aNode);
 self._continue_value_(aBlock,aNode);
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["ifTrue:", "ifTrue:ifFalse:", "interpretNode:continue:", "continue:value:", "isNode"]}),
+messageSends: ["ifTrue:", "ifTrue:ifFalse:", "isNode", "interpretNode:continue:", "continue:value:"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -855,7 +855,7 @@ return self._interpretAll_continue_result_(_st(nodes)._allButFirst(),aBlock,_st(
 }, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"interpretAll:continue:result:",{nodes:nodes,aBlock:aBlock,aCollection:aCollection},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretAll:continue:result:",{nodes:nodes,aBlock:aBlock,aCollection:aCollection},smalltalk.ASTInterpreter)})},
-messageSends: ["ifTrue:ifFalse:", "continue:value:", "interpret:continue:", "first", "interpretAll:continue:result:", "allButFirst", ",", "isEmpty"]}),
+messageSends: ["ifTrue:ifFalse:", "isEmpty", "continue:value:", "interpret:continue:", "first", "interpretAll:continue:result:", "allButFirst", ","]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -925,7 +925,7 @@ return self._continue_value_(aBlock,val);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2)})}));
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"interpretCascadeNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretCascadeNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["interpret:continue:", "receiver", "do:", "receiver:", "nodes", "interpretAll:continue:", "allButLast", "last", "continue:value:"]}),
+messageSends: ["interpret:continue:", "receiver", "do:", "nodes", "receiver:", "interpretAll:continue:", "allButLast", "last", "continue:value:"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -937,7 +937,7 @@ function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 self._continue_value_(aBlock,_st(_st($Smalltalk())._current())._at_(_st(aNode)._value()));
 self._continue_value_(aBlock,_st(_st($Smalltalk())._current())._at_(_st(aNode)._value()));
 return self}, function($ctx1) {$ctx1.fill(self,"interpretClassReferenceNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretClassReferenceNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["continue:value:", "at:", "value", "current"]}),
+messageSends: ["continue:value:", "at:", "current", "value"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1047,7 +1047,7 @@ return self._continue_value_(aBlock,self._sendMessage_to_superSend_(message,rece
 }, function($ctx3) {$ctx3.fillBlock({args:args},$ctx2)})}));
 }, function($ctx3) {$ctx3.fillBlock({args:args},$ctx2)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"interpretSendNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretSendNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["interpret:continue:", "receiver", "interpretAll:continue:", "arguments", "messageFromSendNode:arguments:do:", "pc:", "+", "pc", "context", "continue:value:", "sendMessage:to:superSend:", "superSend"]}),
+messageSends: ["interpret:continue:", "receiver", "interpretAll:continue:", "arguments", "messageFromSendNode:arguments:do:", "pc:", "context", "+", "pc", "continue:value:", "sendMessage:to:superSend:", "superSend"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1092,7 +1092,7 @@ $3=_st(self._context())._localAt_(_st(aNode)._value());
 };
 };
 _st($1)._continue_value_($2,$3);
 _st($1)._continue_value_($2,$3);
 return self}, function($ctx1) {$ctx1.fill(self,"interpretVariableNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretVariableNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["continue:value:", "ifTrue:ifFalse:", "instVarAt:", "value", "receiver", "context", "localAt:", "isInstanceVar", "binding"]}),
+messageSends: ["continue:value:", "ifTrue:ifFalse:", "isInstanceVar", "binding", "instVarAt:", "receiver", "context", "value", "localAt:"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1109,7 +1109,7 @@ _st($1)._arguments_(aCollection);
 $2=_st($1)._yourself();
 $2=_st($1)._yourself();
 self._continue_value_(aBlock,$2);
 self._continue_value_(aBlock,$2);
 return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:arguments:do:",{aSendNode:aSendNode,aCollection:aCollection,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:arguments:do:",{aSendNode:aSendNode,aCollection:aCollection,aBlock:aBlock},smalltalk.ASTInterpreter)})},
-messageSends: ["continue:value:", "selector:", "selector", "new", "arguments:", "yourself"]}),
+messageSends: ["continue:value:", "selector:", "new", "selector", "arguments:", "yourself"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1186,7 +1186,7 @@ return $6;
 }
 }
 catch(e) {if(e===$early)return e[0]; throw e}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"sendMessage:to:superSend:",{aMessage:aMessage,anObject:anObject,aBoolean:aBoolean,method:method},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"sendMessage:to:superSend:",{aMessage:aMessage,anObject:anObject,aBoolean:aBoolean,method:method},smalltalk.ASTInterpreter)})},
-messageSends: ["ifFalse:", "sendTo:", "ifNil:", "messageNotUnderstood:receiver:", "superclass", "class", "at:ifAbsent:", "selector", "methodDictionary", "applyTo:arguments:", "arguments", "fn"]}),
+messageSends: ["ifFalse:", "sendTo:", "ifNil:", "superclass", "class", "messageNotUnderstood:receiver:", "at:ifAbsent:", "methodDictionary", "selector", "applyTo:arguments:", "fn", "arguments"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1225,7 +1225,7 @@ self._context_(_st(self._context())._outerContext());
 $3=blockResult;
 $3=blockResult;
 return $3;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"withBlockContext:",{aBlock:aBlock,blockResult:blockResult},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"withBlockContext:",{aBlock:aBlock,blockResult:blockResult},smalltalk.ASTInterpreter)})},
-messageSends: ["context:", "outerContext:", "context", "new", "yourself", "value", "outerContext"]}),
+messageSends: ["context:", "outerContext:", "new", "context", "yourself", "value", "outerContext"]}),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
 
 
 
 
@@ -1244,7 +1244,7 @@ return _st(self._nextNode()).__eq_eq(self._currentNode());
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"atEnd",{},smalltalk.ASTSteppingInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"atEnd",{},smalltalk.ASTSteppingInterpreter)})},
-messageSends: ["or:", "==", "currentNode", "nextNode", "shouldReturn"]}),
+messageSends: ["or:", "shouldReturn", "==", "nextNode", "currentNode"]}),
 smalltalk.ASTSteppingInterpreter);
 smalltalk.ASTSteppingInterpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1534,6 +1534,18 @@ return self}, function($ctx1) {$ctx1.fill(self,"interpret",{},smalltalk.Interpre
 messageSends: ["visit:", "node"]}),
 messageSends: ["visit:", "node"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpret:",
+fn: function (aNode){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._node_(aNode);
+self._interpret();
+return self}, function($ctx1) {$ctx1.fill(self,"interpret:",{aNode:aNode},smalltalk.Interpreter)})},
+messageSends: ["node:", "interpret"]}),
+smalltalk.Interpreter);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "messageFromSendNode:arguments:",
 selector: "messageFromSendNode:arguments:",
@@ -1640,13 +1652,13 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 _st((function(){
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
-return _st(self._node())._notNil();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileTrue_((function(){
+return self._atEnd();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
 return self._step();
 return self._step();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},smalltalk.Interpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},smalltalk.Interpreter)})},
-messageSends: ["whileTrue:", "step", "notNil", "node"]}),
+messageSends: ["whileFalse:", "atEnd", "step"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1664,20 +1676,33 @@ smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "returnValue",
+selector: "result",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
-$2=self["@returnValue"];
+$2=self._returnValue();
 if(($receiver = $2) == nil || $receiver == undefined){
 if(($receiver = $2) == nil || $receiver == undefined){
 $1=_st(self._context())._receiver();
 $1=_st(self._context())._receiver();
 } else {
 } else {
 $1=$2;
 $1=$2;
 };
 };
 return $1;
 return $1;
+}, function($ctx1) {$ctx1.fill(self,"result",{},smalltalk.Interpreter)})},
+messageSends: ["ifNil:", "returnValue", "receiver", "context"]}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "returnValue",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@returnValue"];
+return $1;
 }, function($ctx1) {$ctx1.fill(self,"returnValue",{},smalltalk.Interpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"returnValue",{},smalltalk.Interpreter)})},
-messageSends: ["ifNil:", "receiver", "context"]}),
+messageSends: []}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1733,10 +1758,10 @@ fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-$1=_st(self["@returnValue"])._notNil();
+$1=_st(self._returnValue())._notNil();
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"shouldReturn",{},smalltalk.Interpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"shouldReturn",{},smalltalk.Interpreter)})},
-messageSends: ["notNil"]}),
+messageSends: ["notNil", "returnValue"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1804,10 +1829,50 @@ smalltalk.method({
 selector: "visitAssignmentNode:",
 selector: "visitAssignmentNode:",
 fn: function (aNode){
 fn: function (aNode){
 var self=this;
 var self=this;
+var value;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-self._assign_to_(_st(aNode)._left(),self._peek());
-return self}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode},smalltalk.Interpreter)})},
-messageSends: ["assign:to:", "left", "peek"]}),
+value=self._pop();
+self._pop();
+self._push_(value);
+self._assign_to_(_st(aNode)._left(),value);
+return self}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode,value:value},smalltalk.Interpreter)})},
+messageSends: ["pop", "push:", "assign:to:", "left"]}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitBlockNode:",
+fn: function (aNode){
+var self=this;
+var blockNode,blockContext,block,interpreter;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4,$5;
+blockNode=_st(_st(_st(aNode)._nodes())._first())._copy();
+_st(blockNode)._parent_(nil);
+$1=_st(_st(self._context())._class())._new();
+_st($1)._outerContext_(self._context());
+$2=_st($1)._yourself();
+blockContext=$2;
+block=(function(){
+return smalltalk.withContext(function($ctx2) {
+interpreter=_st(self._class())._new();
+interpreter;
+$3=interpreter;
+_st($3)._context_(blockContext);
+_st($3)._node_(_st(blockNode)._nextChild());
+$4=_st($3)._proceed();
+$4;
+self._returnValue_(_st(interpreter)._returnValue());
+$5=_st(_st(interpreter)._stack())._isEmpty();
+if(smalltalk.assert($5)){
+return nil;
+} else {
+return _st(interpreter)._pop();
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})});
+self._push_(block);
+return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode,blockNode:blockNode,blockContext:blockContext,block:block,interpreter:interpreter},smalltalk.Interpreter)})},
+messageSends: ["copy", "first", "nodes", "parent:", "outerContext:", "new", "class", "context", "yourself", "context:", "node:", "nextChild", "proceed", "returnValue:", "returnValue", "ifTrue:ifFalse:", "isEmpty", "stack", "pop", "push:"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1822,6 +1887,41 @@ return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode
 messageSends: ["push:", "at:", "value", "current"]}),
 messageSends: ["push:", "at:", "value", "current"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitDynamicArrayNode:",
+fn: function (aNode){
+var self=this;
+var array;
+return smalltalk.withContext(function($ctx1) { 
+array=[];
+_st(_st(aNode)._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(array)._addFirst_(self._pop());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+self._push_(array);
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicArrayNode:",{aNode:aNode,array:array},smalltalk.Interpreter)})},
+messageSends: ["do:", "nodes", "addFirst:", "pop", "push:"]}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitDynamicDictionaryNode:",
+fn: function (aNode){
+var self=this;
+var hashedCollection;
+function $HashedCollection(){return smalltalk.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+hashedCollection=_st($HashedCollection())._new();
+_st(_st(aNode)._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(hashedCollection)._add_(self._pop());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+self._push_(hashedCollection);
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,hashedCollection:hashedCollection},smalltalk.Interpreter)})},
+messageSends: ["new", "do:", "nodes", "add:", "pop", "push:"]}),
+smalltalk.Interpreter);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "visitJSStatementNode:",
 selector: "visitJSStatementNode:",
@@ -1861,16 +1961,26 @@ fn: function (aNode){
 var self=this;
 var self=this;
 var receiver,args,message,result;
 var receiver,args,message,result;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
+var $1;
 args=_st(_st(aNode)._arguments())._collect_((function(each){
 args=_st(_st(aNode)._arguments())._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
 return self._pop();
 return self._pop();
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 receiver=self._pop();
 receiver=self._pop();
-message=self._messageFromSendNode_arguments_(aNode,args);
+message=self._messageFromSendNode_arguments_(aNode,_st(args)._reversed());
 result=self._sendMessage_to_superSend_(message,receiver,_st(aNode)._superSend());
 result=self._sendMessage_to_superSend_(message,receiver,_st(aNode)._superSend());
+_st(self._context())._pc_(_st(_st(self._context())._pc()).__plus((1)));
+$1=_st(_st(aNode)._isCascadeSendNode())._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(aNode)._isLastChild())._not();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+if(smalltalk.assert($1)){
+self._push_(receiver);
+} else {
 self._push_(result);
 self._push_(result);
+};
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode,receiver:receiver,args:args,message:message,result:result},smalltalk.Interpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode,receiver:receiver,args:args,message:message,result:result},smalltalk.Interpreter)})},
-messageSends: ["collect:", "pop", "arguments", "messageFromSendNode:arguments:", "sendMessage:to:superSend:", "superSend", "push:"]}),
+messageSends: ["collect:", "arguments", "pop", "messageFromSendNode:arguments:", "reversed", "sendMessage:to:superSend:", "superSend", "pc:", "context", "+", "pc", "ifTrue:ifFalse:", "and:", "isCascadeSendNode", "not", "isLastChild", "push:"]}),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(

+ 169 - 34
js/Compiler-Interpreter.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Interpreter');
 smalltalk.addPackage('Compiler-Interpreter');
-smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'ast', 'interpreter'], 'Compiler-Interpreter');
+smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'innerContext', 'pc', 'locals', 'method', 'ast', 'interpreter', 'methodContext'], 'Compiler-Interpreter');
 smalltalk.AIContext.comment="I am like a `MethodContext`, used by the `ASTInterpreter`.\x0aUnlike a `MethodContext`, my instances are not read-only.\x0a\x0aWhen debugging, my instances are created by copying the current `MethodContext` (thisContext)";
 smalltalk.AIContext.comment="I am like a `MethodContext`, used by the `ASTInterpreter`.\x0aUnlike a `MethodContext`, my instances are not read-only.\x0a\x0aWhen debugging, my instances are created by copying the current `MethodContext` (thisContext)";
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
@@ -17,7 +17,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"arguments",{},smalltalk.AIContext)})},
 }, function($ctx1) {$ctx1.fill(self,"arguments",{},smalltalk.AIContext)})},
 args: [],
 args: [],
 source: "arguments\x0a\x09^ self ast arguments collect: [ :each |\x0a\x09\x09self localAt: each ]",
 source: "arguments\x0a\x09^ self ast arguments collect: [ :each |\x0a\x09\x09self localAt: each ]",
-messageSends: ["collect:", "localAt:", "arguments", "ast"],
+messageSends: ["collect:", "arguments", "ast", "localAt:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.AIContext);
 smalltalk.AIContext);
@@ -593,7 +593,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast},smalltalk.ASTDebugger)})},
 }, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast},smalltalk.ASTDebugger)})},
 args: [],
 args: [],
 source: "buildAST\x0a\x09\x22Build the AST tree from the method source code.\x0a\x09The AST is annotated with a SemanticAnalyzer,\x0a\x09to know the semantics and bindings of each node needed for later debugging\x22\x0a\x09\x0a\x09| ast |\x0a\x09\x0a\x09ast := Smalltalk current parse: self method source.\x0a\x09(SemanticAnalyzer on: self context receiver class)\x0a\x09\x09visit: ast.\x0a\x09\x0a\x09^ ast",
 source: "buildAST\x0a\x09\x22Build the AST tree from the method source code.\x0a\x09The AST is annotated with a SemanticAnalyzer,\x0a\x09to know the semantics and bindings of each node needed for later debugging\x22\x0a\x09\x0a\x09| ast |\x0a\x09\x0a\x09ast := Smalltalk current parse: self method source.\x0a\x09(SemanticAnalyzer on: self context receiver class)\x0a\x09\x09visit: ast.\x0a\x09\x0a\x09^ ast",
-messageSends: ["parse:", "source", "method", "current", "visit:", "on:", "class", "receiver", "context"],
+messageSends: ["parse:", "current", "source", "method", "visit:", "on:", "class", "receiver", "context"],
 referencedClasses: ["Smalltalk", "SemanticAnalyzer"]
 referencedClasses: ["Smalltalk", "SemanticAnalyzer"]
 }),
 }),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
@@ -671,7 +671,7 @@ _st(self._interpreter())._interpret_(next);
 return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{ast:ast,next:next},smalltalk.ASTDebugger)})},
 return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{ast:ast,next:next},smalltalk.ASTDebugger)})},
 args: [],
 args: [],
 source: "initializeInterpreter\x0a\x09| ast next |\x0a\x09ast := self buildAST.\x0a\x09next := ASTPCNodeVisitor new\x0a\x09\x09context: self context;\x0a\x09\x09visit: ast;\x0a\x09\x09currentNode.\x0a\x09self interpreter interpret: next",
 source: "initializeInterpreter\x0a\x09| ast next |\x0a\x09ast := self buildAST.\x0a\x09next := ASTPCNodeVisitor new\x0a\x09\x09context: self context;\x0a\x09\x09visit: ast;\x0a\x09\x09currentNode.\x0a\x09self interpreter interpret: next",
-messageSends: ["buildAST", "context:", "context", "new", "visit:", "currentNode", "interpret:", "interpreter"],
+messageSends: ["buildAST", "context:", "new", "context", "visit:", "currentNode", "interpret:", "interpreter"],
 referencedClasses: ["ASTPCNodeVisitor"]
 referencedClasses: ["ASTPCNodeVisitor"]
 }),
 }),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
@@ -825,7 +825,7 @@ return self._step();
 return self}, function($ctx1) {$ctx1.fill(self,"step",{},smalltalk.ASTDebugger)})},
 return self}, function($ctx1) {$ctx1.fill(self,"step",{},smalltalk.ASTDebugger)})},
 args: [],
 args: [],
 source: "step\x0a\x09\x22The ASTSteppingInterpreter stops at each node interpretation.\x0a\x09One step will interpret nodes until:\x0a\x09- we get at the end\x0a\x09- the next node is a stepping node (send, assignment, etc.)\x22\x0a\x09\x0a\x09[ (self interpreter nextNode notNil and: [ self interpreter nextNode stopOnStepping ])\x0a\x09\x09or: [ self interpreter atEnd not ] ]\x0a\x09\x09\x09whileFalse: [\x0a\x09\x09\x09\x09self interpreter step.\x0a\x09\x09\x09\x09self step ]",
 source: "step\x0a\x09\x22The ASTSteppingInterpreter stops at each node interpretation.\x0a\x09One step will interpret nodes until:\x0a\x09- we get at the end\x0a\x09- the next node is a stepping node (send, assignment, etc.)\x22\x0a\x09\x0a\x09[ (self interpreter nextNode notNil and: [ self interpreter nextNode stopOnStepping ])\x0a\x09\x09or: [ self interpreter atEnd not ] ]\x0a\x09\x09\x09whileFalse: [\x0a\x09\x09\x09\x09self interpreter step.\x0a\x09\x09\x09\x09self step ]",
-messageSends: ["whileFalse:", "step", "interpreter", "or:", "not", "atEnd", "and:", "stopOnStepping", "nextNode", "notNil"],
+messageSends: ["whileFalse:", "or:", "and:", "notNil", "nextNode", "interpreter", "stopOnStepping", "not", "atEnd", "step"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTDebugger);
 smalltalk.ASTDebugger);
@@ -905,7 +905,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"assign:to:",{aNode:aNode,anObject:anObject},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"assign:to:",{aNode:aNode,anObject:anObject},smalltalk.ASTInterpreter)})},
 args: ["aNode", "anObject"],
 args: ["aNode", "anObject"],
 source: "assign: aNode to: anObject\x0a\x09^ aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value put: anObject ]",
 source: "assign: aNode to: anObject\x0a\x09^ aNode binding isInstanceVar\x0a\x09\x09ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]\x0a\x09\x09ifFalse: [ self context localAt: aNode value put: anObject ]",
-messageSends: ["ifTrue:ifFalse:", "instVarAt:put:", "value", "receiver", "context", "localAt:put:", "isInstanceVar", "binding"],
+messageSends: ["ifTrue:ifFalse:", "isInstanceVar", "binding", "instVarAt:put:", "receiver", "context", "value", "localAt:put:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1089,7 +1089,7 @@ self._continue_value_(aBlock,aNode);
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aNode", "aBlock"],
 args: ["aNode", "aBlock"],
 source: "interpret: aNode continue: aBlock\x0a\x09shouldReturn ifTrue: [ ^ self ].\x0a\x0a\x09aNode isNode\x0a\x09\x09ifTrue: [\x0a\x09\x09\x09currentNode := aNode.\x0a\x09\x09\x09self interpretNode: aNode continue: [ :value |\x0a\x09\x09\x09\x09self continue: aBlock value: value ] ]\x0a\x09\x09ifFalse: [ self continue: aBlock value: aNode ]",
 source: "interpret: aNode continue: aBlock\x0a\x09shouldReturn ifTrue: [ ^ self ].\x0a\x0a\x09aNode isNode\x0a\x09\x09ifTrue: [\x0a\x09\x09\x09currentNode := aNode.\x0a\x09\x09\x09self interpretNode: aNode continue: [ :value |\x0a\x09\x09\x09\x09self continue: aBlock value: value ] ]\x0a\x09\x09ifFalse: [ self continue: aBlock value: aNode ]",
-messageSends: ["ifTrue:", "ifTrue:ifFalse:", "interpretNode:continue:", "continue:value:", "isNode"],
+messageSends: ["ifTrue:", "ifTrue:ifFalse:", "isNode", "interpretNode:continue:", "continue:value:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1131,7 +1131,7 @@ return self._interpretAll_continue_result_(_st(nodes)._allButFirst(),aBlock,_st(
 return self}, function($ctx1) {$ctx1.fill(self,"interpretAll:continue:result:",{nodes:nodes,aBlock:aBlock,aCollection:aCollection},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretAll:continue:result:",{nodes:nodes,aBlock:aBlock,aCollection:aCollection},smalltalk.ASTInterpreter)})},
 args: ["nodes", "aBlock", "aCollection"],
 args: ["nodes", "aBlock", "aCollection"],
 source: "interpretAll: nodes continue: aBlock result: aCollection\x0a\x09nodes isEmpty\x0a\x09\x09ifTrue: [ self continue: aBlock value: aCollection ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09self interpret: nodes first continue: [:value |\x0a\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09interpretAll: nodes allButFirst\x0a\x09\x09\x09\x09\x09continue: aBlock\x0a\x09\x09\x09\x09\x09result: aCollection, { value } ] ]",
 source: "interpretAll: nodes continue: aBlock result: aCollection\x0a\x09nodes isEmpty\x0a\x09\x09ifTrue: [ self continue: aBlock value: aCollection ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09self interpret: nodes first continue: [:value |\x0a\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09interpretAll: nodes allButFirst\x0a\x09\x09\x09\x09\x09continue: aBlock\x0a\x09\x09\x09\x09\x09result: aCollection, { value } ] ]",
-messageSends: ["ifTrue:ifFalse:", "continue:value:", "interpret:continue:", "first", "interpretAll:continue:result:", "allButFirst", ",", "isEmpty"],
+messageSends: ["ifTrue:ifFalse:", "isEmpty", "continue:value:", "interpret:continue:", "first", "interpretAll:continue:result:", "allButFirst", ","],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1221,7 +1221,7 @@ return self._continue_value_(aBlock,val);
 return self}, function($ctx1) {$ctx1.fill(self,"interpretCascadeNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretCascadeNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aNode", "aBlock"],
 args: ["aNode", "aBlock"],
 source: "interpretCascadeNode: aNode continue: aBlock\x0a\x09\x22TODO: Handle super sends\x22\x0a\x09\x0a\x09self interpret: aNode receiver continue: [ :receiver |\x0a\x09\x09\x22Only interpret the receiver once\x22\x0a\x09\x09aNode nodes do: [ :each | each receiver: receiver ].\x0a\x0a\x09\x09self\x0a\x09\x09\x09interpretAll: aNode nodes allButLast\x0a\x09\x09\x09continue: [\x0a\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09interpret: aNode nodes last\x0a\x09\x09\x09\x09\x09continue: [ :val | self continue: aBlock value: val ] ] ]",
 source: "interpretCascadeNode: aNode continue: aBlock\x0a\x09\x22TODO: Handle super sends\x22\x0a\x09\x0a\x09self interpret: aNode receiver continue: [ :receiver |\x0a\x09\x09\x22Only interpret the receiver once\x22\x0a\x09\x09aNode nodes do: [ :each | each receiver: receiver ].\x0a\x0a\x09\x09self\x0a\x09\x09\x09interpretAll: aNode nodes allButLast\x0a\x09\x09\x09continue: [\x0a\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09interpret: aNode nodes last\x0a\x09\x09\x09\x09\x09continue: [ :val | self continue: aBlock value: val ] ] ]",
-messageSends: ["interpret:continue:", "receiver", "do:", "receiver:", "nodes", "interpretAll:continue:", "allButLast", "last", "continue:value:"],
+messageSends: ["interpret:continue:", "receiver", "do:", "nodes", "receiver:", "interpretAll:continue:", "allButLast", "last", "continue:value:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1238,7 +1238,7 @@ self._continue_value_(aBlock,_st(_st($Smalltalk())._current())._at_(_st(aNode)._
 return self}, function($ctx1) {$ctx1.fill(self,"interpretClassReferenceNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretClassReferenceNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aNode", "aBlock"],
 args: ["aNode", "aBlock"],
 source: "interpretClassReferenceNode: aNode continue: aBlock\x0a\x09self continue: aBlock value: (Smalltalk current at: aNode value)",
 source: "interpretClassReferenceNode: aNode continue: aBlock\x0a\x09self continue: aBlock value: (Smalltalk current at: aNode value)",
-messageSends: ["continue:value:", "at:", "value", "current"],
+messageSends: ["continue:value:", "at:", "current", "value"],
 referencedClasses: ["Smalltalk"]
 referencedClasses: ["Smalltalk"]
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1383,7 +1383,7 @@ return self._continue_value_(aBlock,self._sendMessage_to_superSend_(message,rece
 return self}, function($ctx1) {$ctx1.fill(self,"interpretSendNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretSendNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aNode", "aBlock"],
 args: ["aNode", "aBlock"],
 source: "interpretSendNode: aNode continue: aBlock\x0a\x09self interpret: aNode receiver continue: [ :receiver |\x0a\x09\x09self interpretAll: aNode arguments continue: [ :args |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09messageFromSendNode: aNode\x0a\x09\x09\x09\x09arguments: args\x0a\x09\x09\x09\x09do: [ :message |\x0a\x09\x09\x09\x09\x09self context pc: self context pc + 1.\x0a\x09\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09\x09continue: aBlock\x0a\x09\x09\x09\x09\x09\x09value: (self sendMessage: message to: receiver superSend: aNode superSend) ] ] ]",
 source: "interpretSendNode: aNode continue: aBlock\x0a\x09self interpret: aNode receiver continue: [ :receiver |\x0a\x09\x09self interpretAll: aNode arguments continue: [ :args |\x0a\x09\x09\x09self\x0a\x09\x09\x09\x09messageFromSendNode: aNode\x0a\x09\x09\x09\x09arguments: args\x0a\x09\x09\x09\x09do: [ :message |\x0a\x09\x09\x09\x09\x09self context pc: self context pc + 1.\x0a\x09\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09\x09continue: aBlock\x0a\x09\x09\x09\x09\x09\x09value: (self sendMessage: message to: receiver superSend: aNode superSend) ] ] ]",
-messageSends: ["interpret:continue:", "receiver", "interpretAll:continue:", "arguments", "messageFromSendNode:arguments:do:", "pc:", "+", "pc", "context", "continue:value:", "sendMessage:to:superSend:", "superSend"],
+messageSends: ["interpret:continue:", "receiver", "interpretAll:continue:", "arguments", "messageFromSendNode:arguments:do:", "pc:", "context", "+", "pc", "continue:value:", "sendMessage:to:superSend:", "superSend"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1443,7 +1443,7 @@ _st($1)._continue_value_($2,$3);
 return self}, function($ctx1) {$ctx1.fill(self,"interpretVariableNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"interpretVariableNode:continue:",{aNode:aNode,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aNode", "aBlock"],
 args: ["aNode", "aBlock"],
 source: "interpretVariableNode: aNode continue: aBlock\x0a\x09self\x0a\x09\x09continue: aBlock\x0a\x09\x09value: (aNode binding isInstanceVar\x0a\x09\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09\x09ifFalse: [ self context localAt: aNode value ])",
 source: "interpretVariableNode: aNode continue: aBlock\x0a\x09self\x0a\x09\x09continue: aBlock\x0a\x09\x09value: (aNode binding isInstanceVar\x0a\x09\x09\x09ifTrue: [ self context receiver instVarAt: aNode value ]\x0a\x09\x09\x09ifFalse: [ self context localAt: aNode value ])",
-messageSends: ["continue:value:", "ifTrue:ifFalse:", "instVarAt:", "value", "receiver", "context", "localAt:", "isInstanceVar", "binding"],
+messageSends: ["continue:value:", "ifTrue:ifFalse:", "isInstanceVar", "binding", "instVarAt:", "receiver", "context", "value", "localAt:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1465,7 +1465,7 @@ self._continue_value_(aBlock,$2);
 return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:arguments:do:",{aSendNode:aSendNode,aCollection:aCollection,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:arguments:do:",{aSendNode:aSendNode,aCollection:aCollection,aBlock:aBlock},smalltalk.ASTInterpreter)})},
 args: ["aSendNode", "aCollection", "aBlock"],
 args: ["aSendNode", "aCollection", "aBlock"],
 source: "messageFromSendNode: aSendNode arguments: aCollection do: aBlock\x0a\x09self\x0a\x09\x09continue: aBlock\x0a\x09\x09value: (Message new\x0a\x09\x09\x09selector: aSendNode selector;\x0a\x09\x09\x09arguments: aCollection;\x0a\x09\x09\x09yourself)",
 source: "messageFromSendNode: aSendNode arguments: aCollection do: aBlock\x0a\x09self\x0a\x09\x09continue: aBlock\x0a\x09\x09value: (Message new\x0a\x09\x09\x09selector: aSendNode selector;\x0a\x09\x09\x09arguments: aCollection;\x0a\x09\x09\x09yourself)",
-messageSends: ["continue:value:", "selector:", "selector", "new", "arguments:", "yourself"],
+messageSends: ["continue:value:", "selector:", "new", "selector", "arguments:", "yourself"],
 referencedClasses: ["Message"]
 referencedClasses: ["Message"]
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1562,7 +1562,7 @@ catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"sendMessage:to:superSend:",{aMessage:aMessage,anObject:anObject,aBoolean:aBoolean,method:method},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"sendMessage:to:superSend:",{aMessage:aMessage,anObject:anObject,aBoolean:aBoolean,method:method},smalltalk.ASTInterpreter)})},
 args: ["aMessage", "anObject", "aBoolean"],
 args: ["aMessage", "anObject", "aBoolean"],
 source: "sendMessage: aMessage to: anObject superSend: aBoolean\x0a\x09| method |\x0a\x09\x0a\x09aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].\x0a\x09anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x0a\x09method := anObject class superclass methodDictionary\x0a\x09\x09at: aMessage selector\x0a\x09\x09ifAbsent: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x09\x0a\x09^ method fn applyTo: anObject arguments: aMessage arguments\x0a\x09\x09\x0a\x09\x0a\x09",
 source: "sendMessage: aMessage to: anObject superSend: aBoolean\x0a\x09| method |\x0a\x09\x0a\x09aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].\x0a\x09anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x0a\x09method := anObject class superclass methodDictionary\x0a\x09\x09at: aMessage selector\x0a\x09\x09ifAbsent: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x09\x0a\x09^ method fn applyTo: anObject arguments: aMessage arguments\x0a\x09\x09\x0a\x09\x0a\x09",
-messageSends: ["ifFalse:", "sendTo:", "ifNil:", "messageNotUnderstood:receiver:", "superclass", "class", "at:ifAbsent:", "selector", "methodDictionary", "applyTo:arguments:", "arguments", "fn"],
+messageSends: ["ifFalse:", "sendTo:", "ifNil:", "superclass", "class", "messageNotUnderstood:receiver:", "at:ifAbsent:", "methodDictionary", "selector", "applyTo:arguments:", "fn", "arguments"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1611,7 +1611,7 @@ return $3;
 }, function($ctx1) {$ctx1.fill(self,"withBlockContext:",{aBlock:aBlock,blockResult:blockResult},smalltalk.ASTInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"withBlockContext:",{aBlock:aBlock,blockResult:blockResult},smalltalk.ASTInterpreter)})},
 args: ["aBlock"],
 args: ["aBlock"],
 source: "withBlockContext: aBlock\x0a\x09\x22Evaluate aBlock with a BlockContext:\x0a\x09- a context is pushed before aBlock evaluation.\x0a\x09- the context is poped after aBlock evaluation\x0a\x09- the result of aBlock evaluation is answered\x22\x0a\x09\x0a\x09| blockResult |\x0a\x09\x09\x09\x0a\x09self context: (AIContext new\x0a\x09\x09outerContext: self context;\x0a\x09\x09yourself).\x0a\x09\x0a\x09blockResult := aBlock value.\x0a\x09\x0a\x09self context: self context outerContext.\x0a\x09^ blockResult",
 source: "withBlockContext: aBlock\x0a\x09\x22Evaluate aBlock with a BlockContext:\x0a\x09- a context is pushed before aBlock evaluation.\x0a\x09- the context is poped after aBlock evaluation\x0a\x09- the result of aBlock evaluation is answered\x22\x0a\x09\x0a\x09| blockResult |\x0a\x09\x09\x09\x0a\x09self context: (AIContext new\x0a\x09\x09outerContext: self context;\x0a\x09\x09yourself).\x0a\x09\x0a\x09blockResult := aBlock value.\x0a\x09\x0a\x09self context: self context outerContext.\x0a\x09^ blockResult",
-messageSends: ["context:", "outerContext:", "context", "new", "yourself", "value", "outerContext"],
+messageSends: ["context:", "outerContext:", "new", "context", "yourself", "value", "outerContext"],
 referencedClasses: ["AIContext"]
 referencedClasses: ["AIContext"]
 }),
 }),
 smalltalk.ASTInterpreter);
 smalltalk.ASTInterpreter);
@@ -1636,7 +1636,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"atEnd",{},smalltalk.ASTSteppingInterpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"atEnd",{},smalltalk.ASTSteppingInterpreter)})},
 args: [],
 args: [],
 source: "atEnd\x0a\x09^ self shouldReturn or: [ self nextNode == self currentNode ]",
 source: "atEnd\x0a\x09^ self shouldReturn or: [ self nextNode == self currentNode ]",
-messageSends: ["or:", "==", "currentNode", "nextNode", "shouldReturn"],
+messageSends: ["or:", "shouldReturn", "==", "nextNode", "currentNode"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.ASTSteppingInterpreter);
 smalltalk.ASTSteppingInterpreter);
@@ -2024,6 +2024,23 @@ referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpret:",
+category: 'interpreting',
+fn: function (aNode){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._node_(aNode);
+self._interpret();
+return self}, function($ctx1) {$ctx1.fill(self,"interpret:",{aNode:aNode},smalltalk.Interpreter)})},
+args: ["aNode"],
+source: "interpret: aNode\x0a\x09self node: aNode.\x0a\x09self interpret",
+messageSends: ["node:", "interpret"],
+referencedClasses: []
+}),
+smalltalk.Interpreter);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "messageFromSendNode:arguments:",
 selector: "messageFromSendNode:arguments:",
@@ -2166,15 +2183,15 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 _st((function(){
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
-return _st(self._node())._notNil();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileTrue_((function(){
+return self._atEnd();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
 return self._step();
 return self._step();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},smalltalk.Interpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"proceed",{},smalltalk.Interpreter)})},
 args: [],
 args: [],
-source: "proceed\x0a\x09\x22Eagerly evaluate the ast\x22\x0a\x09\x0a\x09[ self node notNil ] whileTrue: [ \x0a\x09\x09self step ]",
-messageSends: ["whileTrue:", "step", "notNil", "node"],
+source: "proceed\x0a\x09\x22Eagerly evaluate the ast\x22\x0a\x09\x0a\x09[ self atEnd ] whileFalse: [ \x0a\x09\x09self step ]",
+messageSends: ["whileFalse:", "atEnd", "step"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
@@ -2199,23 +2216,41 @@ smalltalk.Interpreter);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
-selector: "returnValue",
+selector: "result",
 category: 'accessing',
 category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 var $2,$1;
-$2=self["@returnValue"];
+$2=self._returnValue();
 if(($receiver = $2) == nil || $receiver == undefined){
 if(($receiver = $2) == nil || $receiver == undefined){
 $1=_st(self._context())._receiver();
 $1=_st(self._context())._receiver();
 } else {
 } else {
 $1=$2;
 $1=$2;
 };
 };
 return $1;
 return $1;
+}, function($ctx1) {$ctx1.fill(self,"result",{},smalltalk.Interpreter)})},
+args: [],
+source: "result\x0a\x09^ self returnValue ifNil: [ self context receiver ]",
+messageSends: ["ifNil:", "returnValue", "receiver", "context"],
+referencedClasses: []
+}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "returnValue",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@returnValue"];
+return $1;
 }, function($ctx1) {$ctx1.fill(self,"returnValue",{},smalltalk.Interpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"returnValue",{},smalltalk.Interpreter)})},
 args: [],
 args: [],
-source: "returnValue\x0a\x09^ returnValue ifNil: [ self context receiver ]",
-messageSends: ["ifNil:", "receiver", "context"],
+source: "returnValue\x0a\x09^ returnValue",
+messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
@@ -2284,12 +2319,12 @@ fn: function (){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-$1=_st(self["@returnValue"])._notNil();
+$1=_st(self._returnValue())._notNil();
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"shouldReturn",{},smalltalk.Interpreter)})},
 }, function($ctx1) {$ctx1.fill(self,"shouldReturn",{},smalltalk.Interpreter)})},
 args: [],
 args: [],
-source: "shouldReturn\x0a\x09^ returnValue notNil",
-messageSends: ["notNil"],
+source: "shouldReturn\x0a\x09^ self returnValue notNil",
+messageSends: ["notNil", "returnValue"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
@@ -2380,12 +2415,57 @@ selector: "visitAssignmentNode:",
 category: 'visiting',
 category: 'visiting',
 fn: function (aNode){
 fn: function (aNode){
 var self=this;
 var self=this;
+var value;
+return smalltalk.withContext(function($ctx1) { 
+value=self._pop();
+self._pop();
+self._push_(value);
+self._assign_to_(_st(aNode)._left(),value);
+return self}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode,value:value},smalltalk.Interpreter)})},
+args: ["aNode"],
+source: "visitAssignmentNode: aNode\x0a\x09| value |\x0a\x09\x0a\x09value := self pop.\x0a\x09\x0a\x09\x22Pop the left side of the assignment.\x0a\x09It already has been visited, and we don't need its value.\x22\x0a\x09self pop.\x0a\x09\x0a\x09self push: value.\x0a\x09self assign: aNode left to: value",
+messageSends: ["pop", "push:", "assign:to:", "left"],
+referencedClasses: []
+}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitBlockNode:",
+category: 'visiting',
+fn: function (aNode){
+var self=this;
+var blockNode,blockContext,block,interpreter;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
-self._assign_to_(_st(aNode)._left(),self._peek());
-return self}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode},smalltalk.Interpreter)})},
+var $1,$2,$3,$4,$5;
+blockNode=_st(_st(_st(aNode)._nodes())._first())._copy();
+_st(blockNode)._parent_(nil);
+$1=_st(_st(self._context())._class())._new();
+_st($1)._outerContext_(self._context());
+$2=_st($1)._yourself();
+blockContext=$2;
+block=(function(){
+return smalltalk.withContext(function($ctx2) {
+interpreter=_st(self._class())._new();
+interpreter;
+$3=interpreter;
+_st($3)._context_(blockContext);
+_st($3)._node_(_st(blockNode)._nextChild());
+$4=_st($3)._proceed();
+$4;
+self._returnValue_(_st(interpreter)._returnValue());
+$5=_st(_st(interpreter)._stack())._isEmpty();
+if(smalltalk.assert($5)){
+return nil;
+} else {
+return _st(interpreter)._pop();
+};
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})});
+self._push_(block);
+return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode,blockNode:blockNode,blockContext:blockContext,block:block,interpreter:interpreter},smalltalk.Interpreter)})},
 args: ["aNode"],
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09\x22Do not pop as the pushed value would be the right node\x22\x0a\x09\x0a\x09self assign: aNode left to: self peek",
-messageSends: ["assign:to:", "left", "peek"],
+source: "visitBlockNode: aNode\x0a\x09\x22Do not evaluate the block node.\x0a\x09Instead, put all instructions into a block that we push to the stack for later evaluation\x22\x0a\x09\x0a\x09| blockNode blockContext block interpreter |\x0a\x09\x0a\x09\x22Copy the sequence node without the parent to avoid evaluating nodes up the block. \x0a\x09#nextNode should not go anymore up than the block itself\x22\x0a\x09blockNode := aNode nodes first copy.\x0a\x09blockNode parent: nil.\x0a\x09\x09\x0a\x09blockContext := self context class new\x0a\x09\x09outerContext: self context;\x0a\x09\x09yourself.\x0a\x09\x0a\x09block := [\x0a\x09\x09interpreter := self class new.\x0a\x09\x09interpreter\x0a\x09\x09\x09context: blockContext;\x0a\x09\x09\x09node: blockNode nextChild;\x0a\x09\x09\x09proceed.\x0a\x09\x09\x0a\x09\x09\x22Non local returns hanlding\x22\x0a\x09\x09self returnValue: interpreter returnValue.\x0a\x09\x09\x0a\x09\x09\x22Answer the last evaluation of the block or nil\x22\x0a\x09\x09interpreter stack isEmpty\x0a\x09\x09\x09ifTrue: [ nil ]\x0a\x09\x09\x09ifFalse: [ interpreter pop ] ].\x0a\x09\x0a\x09self push: block",
+messageSends: ["copy", "first", "nodes", "parent:", "outerContext:", "new", "class", "context", "yourself", "context:", "node:", "nextChild", "proceed", "returnValue:", "returnValue", "ifTrue:ifFalse:", "isEmpty", "stack", "pop", "push:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
@@ -2407,6 +2487,51 @@ referencedClasses: ["Smalltalk"]
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);
 
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitDynamicArrayNode:",
+category: 'visiting',
+fn: function (aNode){
+var self=this;
+var array;
+return smalltalk.withContext(function($ctx1) { 
+array=[];
+_st(_st(aNode)._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(array)._addFirst_(self._pop());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+self._push_(array);
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicArrayNode:",{aNode:aNode,array:array},smalltalk.Interpreter)})},
+args: ["aNode"],
+source: "visitDynamicArrayNode: aNode\x0a\x09| array |\x0a\x09\x0a\x09array := #().\x0a\x09aNode nodes do: [ :each |\x0a\x09\x09array addFirst: self pop ].\x0a\x09\x0a\x09self push: array",
+messageSends: ["do:", "nodes", "addFirst:", "pop", "push:"],
+referencedClasses: []
+}),
+smalltalk.Interpreter);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "visitDynamicDictionaryNode:",
+category: 'visiting',
+fn: function (aNode){
+var self=this;
+var hashedCollection;
+function $HashedCollection(){return smalltalk.HashedCollection||(typeof HashedCollection=="undefined"?nil:HashedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+hashedCollection=_st($HashedCollection())._new();
+_st(_st(aNode)._nodes())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(hashedCollection)._add_(self._pop());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+self._push_(hashedCollection);
+return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode,hashedCollection:hashedCollection},smalltalk.Interpreter)})},
+args: ["aNode"],
+source: "visitDynamicDictionaryNode: aNode\x0a\x09| hashedCollection |\x0a\x09\x0a\x09hashedCollection := HashedCollection new.\x0a\x09aNode nodes do: [ :each | \x0a\x09\x09hashedCollection add: self pop ].\x0a\x09\x0a\x09self push: hashedCollection",
+messageSends: ["new", "do:", "nodes", "add:", "pop", "push:"],
+referencedClasses: ["HashedCollection"]
+}),
+smalltalk.Interpreter);
+
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({
 selector: "visitJSStatementNode:",
 selector: "visitJSStatementNode:",
@@ -2462,18 +2587,28 @@ fn: function (aNode){
 var self=this;
 var self=this;
 var receiver,args,message,result;
 var receiver,args,message,result;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
+var $1;
 args=_st(_st(aNode)._arguments())._collect_((function(each){
 args=_st(_st(aNode)._arguments())._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return smalltalk.withContext(function($ctx2) {
 return self._pop();
 return self._pop();
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 receiver=self._pop();
 receiver=self._pop();
-message=self._messageFromSendNode_arguments_(aNode,args);
+message=self._messageFromSendNode_arguments_(aNode,_st(args)._reversed());
 result=self._sendMessage_to_superSend_(message,receiver,_st(aNode)._superSend());
 result=self._sendMessage_to_superSend_(message,receiver,_st(aNode)._superSend());
+_st(self._context())._pc_(_st(_st(self._context())._pc()).__plus((1)));
+$1=_st(_st(aNode)._isCascadeSendNode())._and_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(aNode)._isLastChild())._not();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+if(smalltalk.assert($1)){
+self._push_(receiver);
+} else {
 self._push_(result);
 self._push_(result);
+};
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode,receiver:receiver,args:args,message:message,result:result},smalltalk.Interpreter)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode,receiver:receiver,args:args,message:message,result:result},smalltalk.Interpreter)})},
 args: ["aNode"],
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| receiver args message result |\x0a\x09\x0a\x09args := aNode arguments collect: [ :each |\x0a\x09\x09self pop ].\x0a\x09receiver := self pop.\x0a\x09\x0a\x09message := self\x0a\x09\x09messageFromSendNode: aNode\x0a\x09\x09arguments: args.\x0a\x09\x0a\x09result := self sendMessage: message to: receiver superSend: aNode superSend.\x0a\x09\x0a\x09self push: result",
-messageSends: ["collect:", "pop", "arguments", "messageFromSendNode:arguments:", "sendMessage:to:superSend:", "superSend", "push:"],
+source: "visitSendNode: aNode\x0a\x09| receiver args message result |\x0a\x09\x0a\x09args := aNode arguments collect: [ :each | self pop ].\x0a\x09receiver := self pop.\x0a\x09\x0a\x09message := self\x0a\x09\x09messageFromSendNode: aNode\x0a\x09\x09arguments: args reversed.\x0a\x09\x0a\x09result := self sendMessage: message to: receiver superSend: aNode superSend.\x0a\x09\x0a\x09self context pc: self context pc + 1.\x0a\x09\x0a\x09\x22For cascade sends, push the reciever if the send is not the last one\x22\x0a\x09(aNode isCascadeSendNode and: [ aNode isLastChild not ])\x0a\x09\x09ifTrue: [ self push: receiver ]\x0a\x09\x09ifFalse: [ self push: result ]",
+messageSends: ["collect:", "arguments", "pop", "messageFromSendNode:arguments:", "reversed", "sendMessage:to:superSend:", "superSend", "pc:", "context", "+", "pc", "ifTrue:ifFalse:", "and:", "isCascadeSendNode", "not", "isLastChild", "push:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.Interpreter);
 smalltalk.Interpreter);

+ 25 - 29
js/Compiler-Semantic.deploy.js

@@ -10,7 +10,7 @@ return smalltalk.withContext(function($ctx1) {
 _st(self._args())._at_put_(aString,_st($ArgVar())._on_(aString));
 _st(self._args())._at_put_(aString,_st($ArgVar())._on_(aString));
 _st(_st(self._args())._at_(aString))._scope_(self);
 _st(_st(self._args())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addArg:",{aString:aString},smalltalk.LexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addArg:",{aString:aString},smalltalk.LexicalScope)})},
-messageSends: ["at:put:", "on:", "args", "scope:", "at:"]}),
+messageSends: ["at:put:", "args", "on:", "scope:", "at:"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -23,7 +23,7 @@ return smalltalk.withContext(function($ctx1) {
 _st(self._temps())._at_put_(aString,_st($TempVar())._on_(aString));
 _st(self._temps())._at_put_(aString,_st($TempVar())._on_(aString));
 _st(_st(self._temps())._at_(aString))._scope_(self);
 _st(_st(self._temps())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addTemp:",{aString:aString},smalltalk.LexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addTemp:",{aString:aString},smalltalk.LexicalScope)})},
-messageSends: ["at:put:", "on:", "temps", "scope:", "at:"]}),
+messageSends: ["at:put:", "temps", "on:", "scope:", "at:"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -49,7 +49,7 @@ var $1;
 $1=_st(_st(self._args())._keys()).__comma(_st(self._temps())._keys());
 $1=_st(_st(self._args())._keys()).__comma(_st(self._temps())._keys());
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.LexicalScope)})},
-messageSends: [",", "keys", "temps", "args"]}),
+messageSends: [",", "keys", "args", "temps"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -91,7 +91,7 @@ return nil;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aStringOrNode:aStringOrNode},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aStringOrNode:aStringOrNode},smalltalk.LexicalScope)})},
-messageSends: ["at:ifAbsent:", "value", "temps", "args", "pseudoVars"]}),
+messageSends: ["at:ifAbsent:", "pseudoVars", "value", "args", "temps"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -107,7 +107,7 @@ return _st(self._outerScope())._canInlineNonLocalReturns();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"canInlineNonLocalReturns",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"canInlineNonLocalReturns",{},smalltalk.LexicalScope)})},
-messageSends: ["and:", "canInlineNonLocalReturns", "outerScope", "isInlined"]}),
+messageSends: ["and:", "isInlined", "canInlineNonLocalReturns", "outerScope"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -160,7 +160,7 @@ return _st(self._instruction())._isInlined();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.LexicalScope)})},
-messageSends: ["and:", "isInlined", "instruction", "notNil"]}),
+messageSends: ["and:", "notNil", "instruction", "isInlined"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -198,7 +198,7 @@ $1;
 $3=lookup;
 $3=lookup;
 return $3;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"lookupVariable:",{aNode:aNode,lookup:lookup},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"lookupVariable:",{aNode:aNode,lookup:lookup},smalltalk.LexicalScope)})},
-messageSends: ["bindingFor:", "ifNil:", "ifNotNil:", "lookupVariable:", "outerScope"]}),
+messageSends: ["bindingFor:", "ifNil:", "ifNotNil:", "outerScope", "lookupVariable:"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -216,7 +216,7 @@ $1=_st(self._outerScope())._methodScope();
 };
 };
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"methodScope",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"methodScope",{},smalltalk.LexicalScope)})},
-messageSends: ["ifNotNil:", "methodScope", "outerScope"]}),
+messageSends: ["ifNotNil:", "outerScope", "methodScope"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -301,7 +301,7 @@ return $3;
 $4=_st(_st(self._outerScope())._scopeLevel()).__plus((1));
 $4=_st(_st(self._outerScope())._scopeLevel()).__plus((1));
 return $4;
 return $4;
 }, function($ctx1) {$ctx1.fill(self,"scopeLevel",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"scopeLevel",{},smalltalk.LexicalScope)})},
-messageSends: ["ifNil:", "outerScope", "ifTrue:", "scopeLevel", "isInlined", "+"]}),
+messageSends: ["ifNil:", "outerScope", "ifTrue:", "isInlined", "scopeLevel", "+"]}),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -337,7 +337,7 @@ return smalltalk.withContext(function($ctx1) {
 _st(self._iVars())._at_put_(aString,_st($InstanceVar())._on_(aString));
 _st(self._iVars())._at_put_(aString,_st($InstanceVar())._on_(aString));
 _st(_st(self._iVars())._at_(aString))._scope_(self);
 _st(_st(self._iVars())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addIVar:",{aString:aString},smalltalk.MethodLexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addIVar:",{aString:aString},smalltalk.MethodLexicalScope)})},
-messageSends: ["at:put:", "on:", "iVars", "scope:", "at:"]}),
+messageSends: ["at:put:", "iVars", "on:", "scope:", "at:"]}),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -361,7 +361,7 @@ var $1;
 $1=_st(smalltalk.LexicalScope.fn.prototype._allVariableNames.apply(_st(self), [])).__comma(_st(self._iVars())._keys());
 $1=_st(smalltalk.LexicalScope.fn.prototype._allVariableNames.apply(_st(self), [])).__comma(_st(self._iVars())._keys());
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.MethodLexicalScope)})},
-messageSends: [",", "keys", "iVars", "allVariableNames"]}),
+messageSends: [",", "allVariableNames", "keys", "iVars"]}),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -382,7 +382,7 @@ $1=$2;
 };
 };
 return $1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aNode:aNode},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aNode:aNode},smalltalk.MethodLexicalScope)})},
-messageSends: ["ifNil:", "at:ifAbsent:", "value", "iVars", "bindingFor:"]}),
+messageSends: ["ifNil:", "bindingFor:", "at:ifAbsent:", "iVars", "value"]}),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -521,8 +521,8 @@ selector: "pseudoVars",
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
 function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
-function $PseudoVar(){return smalltalk.PseudoVar||(typeof PseudoVar=="undefined"?nil:PseudoVar)}
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+function $PseudoVar(){return smalltalk.PseudoVar||(typeof PseudoVar=="undefined"?nil:PseudoVar)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3,$4;
 var $1,$2,$3,$4;
 $1=self["@pseudoVars"];
 $1=self["@pseudoVars"];
@@ -542,7 +542,7 @@ $1;
 $4=self["@pseudoVars"];
 $4=self["@pseudoVars"];
 return $4;
 return $4;
 }, function($ctx1) {$ctx1.fill(self,"pseudoVars",{},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"pseudoVars",{},smalltalk.MethodLexicalScope)})},
-messageSends: ["ifNil:", "new", "do:", "at:put:", "scope:", "methodScope", "on:", "yourself", "pseudoVariableNames", "current"]}),
+messageSends: ["ifNil:", "new", "do:", "pseudoVariableNames", "current", "at:put:", "scope:", "on:", "methodScope", "yourself"]}),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -727,7 +727,7 @@ $3=_st($2)._signal();
 $3;
 $3;
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"validateAssignment",{},smalltalk.ScopeVar)})},
 return self}, function($ctx1) {$ctx1.fill(self,"validateAssignment",{},smalltalk.ScopeVar)})},
-messageSends: ["ifTrue:", "variableName:", "name", "new", "signal", "or:", "isPseudoVar", "isArgVar"]}),
+messageSends: ["ifTrue:", "or:", "isArgVar", "isPseudoVar", "variableName:", "new", "name", "signal"]}),
 smalltalk.ScopeVar);
 smalltalk.ScopeVar);
 
 
 
 
@@ -957,7 +957,7 @@ $3;
 _st(_st(_st(self["@currentScope"])._methodScope())._unknownVariables())._add_(_st(aNode)._value());
 _st(_st(_st(self["@currentScope"])._methodScope())._unknownVariables())._add_(_st(aNode)._value());
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"errorUnknownVariable:",{aNode:aNode,identifier:identifier},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"errorUnknownVariable:",{aNode:aNode,identifier:identifier},smalltalk.SemanticAnalyzer)})},
-messageSends: ["value", "ifTrue:ifFalse:", "variableName:", "new", "signal", "add:", "unknownVariables", "methodScope", "and:", "isVariableGloballyUndefined:", "not", "includes:"]}),
+messageSends: ["value", "ifTrue:ifFalse:", "and:", "not", "includes:", "isVariableGloballyUndefined:", "variableName:", "new", "signal", "add:", "unknownVariables", "methodScope"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1123,7 +1123,7 @@ $1;
 self._errorShadowingVariable_(aString);
 self._errorShadowingVariable_(aString);
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"validateVariableScope:",{aString:aString},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"validateVariableScope:",{aString:aString},smalltalk.SemanticAnalyzer)})},
-messageSends: ["ifNotNil:", "errorShadowingVariable:", "lookupVariable:"]}),
+messageSends: ["ifNotNil:", "lookupVariable:", "errorShadowingVariable:"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1155,7 +1155,7 @@ return _st(self["@currentScope"])._addArg_(each);
 smalltalk.NodeVisitor.fn.prototype._visitBlockNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitBlockNode_.apply(_st(self), [aNode]);
 self._popScope();
 self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "validateVariableScope:", "addArg:", "parameters", "visitBlockNode:", "popScope"]}),
+messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1165,10 +1165,6 @@ fn: function (aNode){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-_st(_st(aNode)._nodes())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(each)._receiver_(_st(aNode)._receiver());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 smalltalk.NodeVisitor.fn.prototype._visitCascadeNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitCascadeNode_.apply(_st(self), [aNode]);
 $1=_st(_st(_st(aNode)._nodes())._first())._superSend();
 $1=_st(_st(_st(aNode)._nodes())._first())._superSend();
 if(smalltalk.assert($1)){
 if(smalltalk.assert($1)){
@@ -1178,7 +1174,7 @@ return _st(each)._superSend_(true);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"visitCascadeNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitCascadeNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["do:", "receiver:", "receiver", "nodes", "visitCascadeNode:", "ifTrue:", "superSend:", "superSend", "first"]}),
+messageSends: ["visitCascadeNode:", "ifTrue:", "superSend", "first", "nodes", "do:", "superSend:"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1195,7 +1191,7 @@ _st($1)._name_(_st(aNode)._value());
 $2=_st($1)._yourself();
 $2=_st($1)._yourself();
 _st(aNode)._binding_($2);
 _st(aNode)._binding_($2);
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["add:", "value", "classReferences", "binding:", "name:", "new", "yourself"]}),
+messageSends: ["add:", "classReferences", "value", "binding:", "name:", "new", "yourself"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1224,7 +1220,7 @@ _st($1)._messageSends_(_st(self._messageSends())._keys());
 $2=_st($1)._superSends_(_st(self._superSends())._keys());
 $2=_st($1)._superSends_(_st(self._superSends())._keys());
 self._popScope();
 self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitMethodNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitMethodNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["pushScope:", "newMethodScope", "scope:", "node:", "do:", "addIVar:", "allInstanceVariableNames", "theClass", "validateVariableScope:", "addArg:", "arguments", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "keys", "messageSends", "superSends:", "superSends", "popScope"]}),
+messageSends: ["pushScope:", "newMethodScope", "scope:", "node:", "do:", "allInstanceVariableNames", "theClass", "addIVar:", "arguments", "validateVariableScope:", "addArg:", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "keys", "messageSends", "superSends:", "superSends", "popScope"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1243,7 +1239,7 @@ _st(_st(self["@currentScope"])._methodScope())._addNonLocalReturn_(self["@curren
 };
 };
 smalltalk.NodeVisitor.fn.prototype._visitReturnNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitReturnNode_.apply(_st(self), [aNode]);
 return self}, function($ctx1) {$ctx1.fill(self,"visitReturnNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitReturnNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["scope:", "ifTrue:ifFalse:", "localReturn:", "addNonLocalReturn:", "methodScope", "isMethodScope", "visitReturnNode:"]}),
+messageSends: ["scope:", "ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "visitReturnNode:"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1279,7 +1275,7 @@ _st(_st(self._messageSends())._at_(_st(aNode)._selector()))._add_(aNode);
 _st(aNode)._index_(_st(_st(self._messageSends())._at_(_st(aNode)._selector()))._size());
 _st(aNode)._index_(_st(_st(self._messageSends())._at_(_st(aNode)._selector()))._size());
 smalltalk.NodeVisitor.fn.prototype._visitSendNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitSendNode_.apply(_st(self), [aNode]);
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["ifTrue:ifFalse:", "superSend:", "value:", "receiver", "at:ifAbsentPut:", "selector", "new", "superSends", "add:", "at:", "ifTrue:", "shouldBeInlined:", "shouldBeAliased:", "includes:", "inlinedSelectors", "=", "value", "messageSends", "index:", "size", "visitSendNode:"]}),
+messageSends: ["ifTrue:ifFalse:", "=", "value", "receiver", "superSend:", "value:", "at:ifAbsentPut:", "superSends", "selector", "new", "add:", "at:", "ifTrue:", "includes:", "inlinedSelectors", "shouldBeInlined:", "shouldBeAliased:", "messageSends", "index:", "size", "visitSendNode:"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1295,7 +1291,7 @@ return _st(self["@currentScope"])._addTemp_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 smalltalk.NodeVisitor.fn.prototype._visitSequenceNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitSequenceNode_.apply(_st(self), [aNode]);
 return self}, function($ctx1) {$ctx1.fill(self,"visitSequenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSequenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["do:", "validateVariableScope:", "addTemp:", "temps", "visitSequenceNode:"]}),
+messageSends: ["do:", "temps", "validateVariableScope:", "addTemp:", "visitSequenceNode:"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -1319,7 +1315,7 @@ $2=$3;
 };
 };
 _st($1)._binding_($2);
 _st($1)._binding_($2);
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
-messageSends: ["binding:", "ifNil:", "errorUnknownVariable:", "name:", "value", "new", "yourself", "lookupVariable:"]}),
+messageSends: ["binding:", "ifNil:", "lookupVariable:", "errorUnknownVariable:", "name:", "new", "value", "yourself"]}),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
 
 
 
 

+ 27 - 31
js/Compiler-Semantic.js

@@ -14,7 +14,7 @@ _st(_st(self._args())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addArg:",{aString:aString},smalltalk.LexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addArg:",{aString:aString},smalltalk.LexicalScope)})},
 args: ["aString"],
 args: ["aString"],
 source: "addArg: aString\x0a\x09self args at: aString put: (ArgVar on: aString).\x0a\x09(self args at: aString) scope: self",
 source: "addArg: aString\x0a\x09self args at: aString put: (ArgVar on: aString).\x0a\x09(self args at: aString) scope: self",
-messageSends: ["at:put:", "on:", "args", "scope:", "at:"],
+messageSends: ["at:put:", "args", "on:", "scope:", "at:"],
 referencedClasses: ["ArgVar"]
 referencedClasses: ["ArgVar"]
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -32,7 +32,7 @@ _st(_st(self._temps())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addTemp:",{aString:aString},smalltalk.LexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addTemp:",{aString:aString},smalltalk.LexicalScope)})},
 args: ["aString"],
 args: ["aString"],
 source: "addTemp: aString\x0a\x09self temps at: aString put: (TempVar on: aString).\x0a\x09(self temps at: aString) scope: self",
 source: "addTemp: aString\x0a\x09self temps at: aString put: (TempVar on: aString).\x0a\x09(self temps at: aString) scope: self",
-messageSends: ["at:put:", "on:", "temps", "scope:", "at:"],
+messageSends: ["at:put:", "temps", "on:", "scope:", "at:"],
 referencedClasses: ["TempVar"]
 referencedClasses: ["TempVar"]
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -68,7 +68,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.LexicalScope)})},
 args: [],
 args: [],
 source: "allVariableNames\x0a\x09^ self args keys, self temps keys",
 source: "allVariableNames\x0a\x09^ self args keys, self temps keys",
-messageSends: [",", "keys", "temps", "args"],
+messageSends: [",", "keys", "args", "temps"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -120,7 +120,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aStringOrNode:aStringOrNode},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aStringOrNode:aStringOrNode},smalltalk.LexicalScope)})},
 args: ["aStringOrNode"],
 args: ["aStringOrNode"],
 source: "bindingFor: aStringOrNode\x0a\x09^ self pseudoVars at: aStringOrNode value ifAbsent: [\x0a\x09\x09self args at: aStringOrNode value ifAbsent: [\x0a\x09\x09\x09self temps at: aStringOrNode value ifAbsent: [ nil ]]]",
 source: "bindingFor: aStringOrNode\x0a\x09^ self pseudoVars at: aStringOrNode value ifAbsent: [\x0a\x09\x09self args at: aStringOrNode value ifAbsent: [\x0a\x09\x09\x09self temps at: aStringOrNode value ifAbsent: [ nil ]]]",
-messageSends: ["at:ifAbsent:", "value", "temps", "args", "pseudoVars"],
+messageSends: ["at:ifAbsent:", "pseudoVars", "value", "args", "temps"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -141,7 +141,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"canInlineNonLocalReturns",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"canInlineNonLocalReturns",{},smalltalk.LexicalScope)})},
 args: [],
 args: [],
 source: "canInlineNonLocalReturns\x0a\x09^ self isInlined and: [ self outerScope canInlineNonLocalReturns ]",
 source: "canInlineNonLocalReturns\x0a\x09^ self isInlined and: [ self outerScope canInlineNonLocalReturns ]",
-messageSends: ["and:", "canInlineNonLocalReturns", "outerScope", "isInlined"],
+messageSends: ["and:", "isInlined", "canInlineNonLocalReturns", "outerScope"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -214,7 +214,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"isInlined",{},smalltalk.LexicalScope)})},
 args: [],
 args: [],
 source: "isInlined\x0a\x09^ self instruction notNil and: [\x0a\x09\x09self instruction isInlined ]",
 source: "isInlined\x0a\x09^ self instruction notNil and: [\x0a\x09\x09self instruction isInlined ]",
-messageSends: ["and:", "isInlined", "instruction", "notNil"],
+messageSends: ["and:", "notNil", "instruction", "isInlined"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -262,7 +262,7 @@ return $3;
 }, function($ctx1) {$ctx1.fill(self,"lookupVariable:",{aNode:aNode,lookup:lookup},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"lookupVariable:",{aNode:aNode,lookup:lookup},smalltalk.LexicalScope)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "lookupVariable: aNode\x0a\x09| lookup |\x0a\x09lookup := (self bindingFor: aNode).\x0a\x09lookup ifNil: [\x0a\x09\x09lookup := self outerScope ifNotNil: [\x0a\x09\x09\x09(self outerScope lookupVariable: aNode) ]].\x0a\x09^ lookup",
 source: "lookupVariable: aNode\x0a\x09| lookup |\x0a\x09lookup := (self bindingFor: aNode).\x0a\x09lookup ifNil: [\x0a\x09\x09lookup := self outerScope ifNotNil: [\x0a\x09\x09\x09(self outerScope lookupVariable: aNode) ]].\x0a\x09^ lookup",
-messageSends: ["bindingFor:", "ifNil:", "ifNotNil:", "lookupVariable:", "outerScope"],
+messageSends: ["bindingFor:", "ifNil:", "ifNotNil:", "outerScope", "lookupVariable:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -285,7 +285,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"methodScope",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"methodScope",{},smalltalk.LexicalScope)})},
 args: [],
 args: [],
 source: "methodScope\x0a\x09^ self outerScope ifNotNil: [\x0a\x09\x09self outerScope methodScope ]",
 source: "methodScope\x0a\x09^ self outerScope ifNotNil: [\x0a\x09\x09self outerScope methodScope ]",
-messageSends: ["ifNotNil:", "methodScope", "outerScope"],
+messageSends: ["ifNotNil:", "outerScope", "methodScope"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -400,7 +400,7 @@ return $4;
 }, function($ctx1) {$ctx1.fill(self,"scopeLevel",{},smalltalk.LexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"scopeLevel",{},smalltalk.LexicalScope)})},
 args: [],
 args: [],
 source: "scopeLevel\x0a\x09self outerScope ifNil: [ ^ 1 ].\x0a\x09self isInlined ifTrue: [ ^ self outerScope scopeLevel ].\x0a\x09\x0a\x09^ self outerScope scopeLevel + 1",
 source: "scopeLevel\x0a\x09self outerScope ifNil: [ ^ 1 ].\x0a\x09self isInlined ifTrue: [ ^ self outerScope scopeLevel ].\x0a\x09\x0a\x09^ self outerScope scopeLevel + 1",
-messageSends: ["ifNil:", "outerScope", "ifTrue:", "scopeLevel", "isInlined", "+"],
+messageSends: ["ifNil:", "outerScope", "ifTrue:", "isInlined", "scopeLevel", "+"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.LexicalScope);
 smalltalk.LexicalScope);
@@ -447,7 +447,7 @@ _st(_st(self._iVars())._at_(aString))._scope_(self);
 return self}, function($ctx1) {$ctx1.fill(self,"addIVar:",{aString:aString},smalltalk.MethodLexicalScope)})},
 return self}, function($ctx1) {$ctx1.fill(self,"addIVar:",{aString:aString},smalltalk.MethodLexicalScope)})},
 args: ["aString"],
 args: ["aString"],
 source: "addIVar: aString\x0a\x09self iVars at: aString put: (InstanceVar on: aString).\x0a\x09(self iVars at: aString) scope: self",
 source: "addIVar: aString\x0a\x09self iVars at: aString put: (InstanceVar on: aString).\x0a\x09(self iVars at: aString) scope: self",
-messageSends: ["at:put:", "on:", "iVars", "scope:", "at:"],
+messageSends: ["at:put:", "iVars", "on:", "scope:", "at:"],
 referencedClasses: ["InstanceVar"]
 referencedClasses: ["InstanceVar"]
 }),
 }),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
@@ -481,7 +481,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"allVariableNames",{},smalltalk.MethodLexicalScope)})},
 args: [],
 args: [],
 source: "allVariableNames\x0a\x09^ super allVariableNames, self iVars keys",
 source: "allVariableNames\x0a\x09^ super allVariableNames, self iVars keys",
-messageSends: [",", "keys", "iVars", "allVariableNames"],
+messageSends: [",", "allVariableNames", "keys", "iVars"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
@@ -507,7 +507,7 @@ return $1;
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aNode:aNode},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"bindingFor:",{aNode:aNode},smalltalk.MethodLexicalScope)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "bindingFor: aNode\x0a\x09^ (super bindingFor: aNode) ifNil: [\x0a\x09\x09self iVars at: aNode value ifAbsent: [ nil ]]",
 source: "bindingFor: aNode\x0a\x09^ (super bindingFor: aNode) ifNil: [\x0a\x09\x09self iVars at: aNode value ifAbsent: [ nil ]]",
-messageSends: ["ifNil:", "at:ifAbsent:", "value", "iVars", "bindingFor:"],
+messageSends: ["ifNil:", "bindingFor:", "at:ifAbsent:", "iVars", "value"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
@@ -694,8 +694,8 @@ category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
 function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
-function $PseudoVar(){return smalltalk.PseudoVar||(typeof PseudoVar=="undefined"?nil:PseudoVar)}
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
 function $Smalltalk(){return smalltalk.Smalltalk||(typeof Smalltalk=="undefined"?nil:Smalltalk)}
+function $PseudoVar(){return smalltalk.PseudoVar||(typeof PseudoVar=="undefined"?nil:PseudoVar)}
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3,$4;
 var $1,$2,$3,$4;
 $1=self["@pseudoVars"];
 $1=self["@pseudoVars"];
@@ -717,8 +717,8 @@ return $4;
 }, function($ctx1) {$ctx1.fill(self,"pseudoVars",{},smalltalk.MethodLexicalScope)})},
 }, function($ctx1) {$ctx1.fill(self,"pseudoVars",{},smalltalk.MethodLexicalScope)})},
 args: [],
 args: [],
 source: "pseudoVars\x0a\x09pseudoVars ifNil: [\x0a\x09\x09pseudoVars := Dictionary new.\x0a\x09\x09Smalltalk current pseudoVariableNames do: [ :each |\x0a\x09\x09\x09pseudoVars at: each put: ((PseudoVar on: each)\x0a\x09\x09\x09\x09scope: self methodScope;\x0a\x09\x09\x09\x09yourself) ]].\x0a\x09^ pseudoVars",
 source: "pseudoVars\x0a\x09pseudoVars ifNil: [\x0a\x09\x09pseudoVars := Dictionary new.\x0a\x09\x09Smalltalk current pseudoVariableNames do: [ :each |\x0a\x09\x09\x09pseudoVars at: each put: ((PseudoVar on: each)\x0a\x09\x09\x09\x09scope: self methodScope;\x0a\x09\x09\x09\x09yourself) ]].\x0a\x09^ pseudoVars",
-messageSends: ["ifNil:", "new", "do:", "at:put:", "scope:", "methodScope", "on:", "yourself", "pseudoVariableNames", "current"],
-referencedClasses: ["Dictionary", "PseudoVar", "Smalltalk"]
+messageSends: ["ifNil:", "new", "do:", "pseudoVariableNames", "current", "at:put:", "scope:", "on:", "methodScope", "yourself"],
+referencedClasses: ["Dictionary", "Smalltalk", "PseudoVar"]
 }),
 }),
 smalltalk.MethodLexicalScope);
 smalltalk.MethodLexicalScope);
 
 
@@ -973,7 +973,7 @@ $3;
 return self}, function($ctx1) {$ctx1.fill(self,"validateAssignment",{},smalltalk.ScopeVar)})},
 return self}, function($ctx1) {$ctx1.fill(self,"validateAssignment",{},smalltalk.ScopeVar)})},
 args: [],
 args: [],
 source: "validateAssignment\x0a\x09(self isArgVar or: [ self isPseudoVar ]) ifTrue: [\x0a\x09\x09InvalidAssignmentError new\x0a\x09\x09\x09variableName: self name;\x0a\x09\x09\x09signal]",
 source: "validateAssignment\x0a\x09(self isArgVar or: [ self isPseudoVar ]) ifTrue: [\x0a\x09\x09InvalidAssignmentError new\x0a\x09\x09\x09variableName: self name;\x0a\x09\x09\x09signal]",
-messageSends: ["ifTrue:", "variableName:", "name", "new", "signal", "or:", "isPseudoVar", "isArgVar"],
+messageSends: ["ifTrue:", "or:", "isArgVar", "isPseudoVar", "variableName:", "new", "name", "signal"],
 referencedClasses: ["InvalidAssignmentError"]
 referencedClasses: ["InvalidAssignmentError"]
 }),
 }),
 smalltalk.ScopeVar);
 smalltalk.ScopeVar);
@@ -1286,7 +1286,7 @@ _st(_st(_st(self["@currentScope"])._methodScope())._unknownVariables())._add_(_s
 return self}, function($ctx1) {$ctx1.fill(self,"errorUnknownVariable:",{aNode:aNode,identifier:identifier},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"errorUnknownVariable:",{aNode:aNode,identifier:identifier},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "errorUnknownVariable: aNode\x0a\x09\x22Throw an error if the variable is undeclared in the global JS scope (i.e. window).\x0a\x09We allow four variable names in addition: `jQuery`, `window`, `process` and `global`\x0a\x09for nodejs and browser environments.\x0a\x09\x0a\x09This is only to make sure compilation works on both browser-based and nodejs environments.\x0a\x09The ideal solution would be to use a pragma instead\x22\x0a\x0a\x09| identifier |\x0a\x09identifier := aNode value.\x0a\x09\x0a\x09((#('jQuery' 'window' 'document' 'process' 'global') includes: identifier) not\x0a\x09\x09and: [ self isVariableGloballyUndefined: identifier ])\x0a\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09UnknownVariableError new\x0a\x09\x09\x09\x09\x09variableName: aNode value;\x0a\x09\x09\x09\x09\x09signal ]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09currentScope methodScope unknownVariables add: aNode value ]",
 source: "errorUnknownVariable: aNode\x0a\x09\x22Throw an error if the variable is undeclared in the global JS scope (i.e. window).\x0a\x09We allow four variable names in addition: `jQuery`, `window`, `process` and `global`\x0a\x09for nodejs and browser environments.\x0a\x09\x0a\x09This is only to make sure compilation works on both browser-based and nodejs environments.\x0a\x09The ideal solution would be to use a pragma instead\x22\x0a\x0a\x09| identifier |\x0a\x09identifier := aNode value.\x0a\x09\x0a\x09((#('jQuery' 'window' 'document' 'process' 'global') includes: identifier) not\x0a\x09\x09and: [ self isVariableGloballyUndefined: identifier ])\x0a\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09UnknownVariableError new\x0a\x09\x09\x09\x09\x09variableName: aNode value;\x0a\x09\x09\x09\x09\x09signal ]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09currentScope methodScope unknownVariables add: aNode value ]",
-messageSends: ["value", "ifTrue:ifFalse:", "variableName:", "new", "signal", "add:", "unknownVariables", "methodScope", "and:", "isVariableGloballyUndefined:", "not", "includes:"],
+messageSends: ["value", "ifTrue:ifFalse:", "and:", "not", "includes:", "isVariableGloballyUndefined:", "variableName:", "new", "signal", "add:", "unknownVariables", "methodScope"],
 referencedClasses: ["UnknownVariableError"]
 referencedClasses: ["UnknownVariableError"]
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1507,7 +1507,7 @@ self._errorShadowingVariable_(aString);
 return self}, function($ctx1) {$ctx1.fill(self,"validateVariableScope:",{aString:aString},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"validateVariableScope:",{aString:aString},smalltalk.SemanticAnalyzer)})},
 args: ["aString"],
 args: ["aString"],
 source: "validateVariableScope: aString\x0a\x09\x22Validate the variable scope in by doing a recursive lookup, up to the method scope\x22\x0a\x0a\x09(currentScope lookupVariable: aString) ifNotNil: [\x0a\x09\x09self errorShadowingVariable: aString ]",
 source: "validateVariableScope: aString\x0a\x09\x22Validate the variable scope in by doing a recursive lookup, up to the method scope\x22\x0a\x0a\x09(currentScope lookupVariable: aString) ifNotNil: [\x0a\x09\x09self errorShadowingVariable: aString ]",
-messageSends: ["ifNotNil:", "errorShadowingVariable:", "lookupVariable:"],
+messageSends: ["ifNotNil:", "lookupVariable:", "errorShadowingVariable:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1549,7 +1549,7 @@ self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x09\x0a\x09aNode parameters do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
 source: "visitBlockNode: aNode\x0a\x09self pushScope: self newBlockScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x09\x0a\x09aNode parameters do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitBlockNode: aNode.\x0a\x09self popScope",
-messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "validateVariableScope:", "addArg:", "parameters", "visitBlockNode:", "popScope"],
+messageSends: ["pushScope:", "newBlockScope", "scope:", "node:", "do:", "parameters", "validateVariableScope:", "addArg:", "visitBlockNode:", "popScope"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1562,10 +1562,6 @@ fn: function (aNode){
 var self=this;
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 return smalltalk.withContext(function($ctx1) { 
 var $1;
 var $1;
-_st(_st(aNode)._nodes())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(each)._receiver_(_st(aNode)._receiver());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 smalltalk.NodeVisitor.fn.prototype._visitCascadeNode_.apply(_st(self), [aNode]);
 smalltalk.NodeVisitor.fn.prototype._visitCascadeNode_.apply(_st(self), [aNode]);
 $1=_st(_st(_st(aNode)._nodes())._first())._superSend();
 $1=_st(_st(_st(aNode)._nodes())._first())._superSend();
 if(smalltalk.assert($1)){
 if(smalltalk.assert($1)){
@@ -1576,8 +1572,8 @@ return _st(each)._superSend_(true);
 };
 };
 return self}, function($ctx1) {$ctx1.fill(self,"visitCascadeNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitCascadeNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
-source: "visitCascadeNode: aNode\x0a\x09\x22Populate the receiver into all children\x22\x0a\x09aNode nodes do: [ :each |\x0a\x09\x09each receiver: aNode receiver ].\x0a\x09super visitCascadeNode: aNode.\x0a\x09aNode nodes first superSend ifTrue: [\x0a\x09\x09aNode nodes do: [ :each | each superSend: true ]]",
-messageSends: ["do:", "receiver:", "receiver", "nodes", "visitCascadeNode:", "ifTrue:", "superSend:", "superSend", "first"],
+source: "visitCascadeNode: aNode\x0a\x09super visitCascadeNode: aNode.\x0a\x09aNode nodes first superSend ifTrue: [\x0a\x09\x09aNode nodes do: [ :each | each superSend: true ]]",
+messageSends: ["visitCascadeNode:", "ifTrue:", "superSend", "first", "nodes", "do:", "superSend:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1599,7 +1595,7 @@ _st(aNode)._binding_($2);
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitClassReferenceNode: aNode\x0a\x09self classReferences add: aNode value.\x0a\x09aNode binding: (ClassRefVar new name: aNode value; yourself)",
 source: "visitClassReferenceNode: aNode\x0a\x09self classReferences add: aNode value.\x0a\x09aNode binding: (ClassRefVar new name: aNode value; yourself)",
-messageSends: ["add:", "value", "classReferences", "binding:", "name:", "new", "yourself"],
+messageSends: ["add:", "classReferences", "value", "binding:", "name:", "new", "yourself"],
 referencedClasses: ["ClassRefVar"]
 referencedClasses: ["ClassRefVar"]
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1633,7 +1629,7 @@ self._popScope();
 return self}, function($ctx1) {$ctx1.fill(self,"visitMethodNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitMethodNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitMethodNode: aNode\x0a\x09self pushScope: self newMethodScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x0a\x09self theClass allInstanceVariableNames do: [:each |\x0a\x09\x09currentScope addIVar: each ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitMethodNode: aNode.\x0a\x0a\x09aNode\x0a\x09\x09classReferences: self classReferences;\x0a\x09\x09messageSends: self messageSends keys;\x0a\x09\x09superSends: self superSends keys.\x0a\x09self popScope",
 source: "visitMethodNode: aNode\x0a\x09self pushScope: self newMethodScope.\x0a\x09aNode scope: currentScope.\x0a\x09currentScope node: aNode.\x0a\x0a\x09self theClass allInstanceVariableNames do: [:each |\x0a\x09\x09currentScope addIVar: each ].\x0a\x09aNode arguments do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addArg: each ].\x0a\x0a\x09super visitMethodNode: aNode.\x0a\x0a\x09aNode\x0a\x09\x09classReferences: self classReferences;\x0a\x09\x09messageSends: self messageSends keys;\x0a\x09\x09superSends: self superSends keys.\x0a\x09self popScope",
-messageSends: ["pushScope:", "newMethodScope", "scope:", "node:", "do:", "addIVar:", "allInstanceVariableNames", "theClass", "validateVariableScope:", "addArg:", "arguments", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "keys", "messageSends", "superSends:", "superSends", "popScope"],
+messageSends: ["pushScope:", "newMethodScope", "scope:", "node:", "do:", "allInstanceVariableNames", "theClass", "addIVar:", "arguments", "validateVariableScope:", "addArg:", "visitMethodNode:", "classReferences:", "classReferences", "messageSends:", "keys", "messageSends", "superSends:", "superSends", "popScope"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1657,7 +1653,7 @@ smalltalk.NodeVisitor.fn.prototype._visitReturnNode_.apply(_st(self), [aNode]);
 return self}, function($ctx1) {$ctx1.fill(self,"visitReturnNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitReturnNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitReturnNode: aNode\x0a\x09aNode scope: currentScope.\x0a\x09currentScope isMethodScope\x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [ currentScope methodScope addNonLocalReturn: currentScope ].\x0a\x09super visitReturnNode: aNode",
 source: "visitReturnNode: aNode\x0a\x09aNode scope: currentScope.\x0a\x09currentScope isMethodScope\x0a\x09\x09ifTrue: [ currentScope localReturn: true ]\x0a\x09\x09ifFalse: [ currentScope methodScope addNonLocalReturn: currentScope ].\x0a\x09super visitReturnNode: aNode",
-messageSends: ["scope:", "ifTrue:ifFalse:", "localReturn:", "addNonLocalReturn:", "methodScope", "isMethodScope", "visitReturnNode:"],
+messageSends: ["scope:", "ifTrue:ifFalse:", "isMethodScope", "localReturn:", "addNonLocalReturn:", "methodScope", "visitReturnNode:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1698,7 +1694,7 @@ smalltalk.NodeVisitor.fn.prototype._visitSendNode_.apply(_st(self), [aNode]);
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super'\x0a\x09\x09ifTrue: [\x0a\x09\x09\x09aNode superSend: true.\x0a\x09\x09\x09aNode receiver value: 'self'.\x0a\x09\x09\x09self superSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09\x09\x09(self superSends at: aNode selector) add: aNode ]\x0a\x09\x09\x0a\x09\x09ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [\x0a\x09\x09\x09aNode shouldBeInlined: true.\x0a\x09\x09\x09aNode receiver shouldBeAliased: true ] ].\x0a\x0a\x09self messageSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09(self messageSends at: aNode selector) add: aNode.\x0a\x0a\x09aNode index: (self messageSends at: aNode selector) size.\x0a\x0a\x09super visitSendNode: aNode",
 source: "visitSendNode: aNode\x0a\x0a\x09aNode receiver value = 'super'\x0a\x09\x09ifTrue: [\x0a\x09\x09\x09aNode superSend: true.\x0a\x09\x09\x09aNode receiver value: 'self'.\x0a\x09\x09\x09self superSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09\x09\x09(self superSends at: aNode selector) add: aNode ]\x0a\x09\x09\x0a\x09\x09ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [\x0a\x09\x09\x09aNode shouldBeInlined: true.\x0a\x09\x09\x09aNode receiver shouldBeAliased: true ] ].\x0a\x0a\x09self messageSends at: aNode selector ifAbsentPut: [ Set new ].\x0a\x09(self messageSends at: aNode selector) add: aNode.\x0a\x0a\x09aNode index: (self messageSends at: aNode selector) size.\x0a\x0a\x09super visitSendNode: aNode",
-messageSends: ["ifTrue:ifFalse:", "superSend:", "value:", "receiver", "at:ifAbsentPut:", "selector", "new", "superSends", "add:", "at:", "ifTrue:", "shouldBeInlined:", "shouldBeAliased:", "includes:", "inlinedSelectors", "=", "value", "messageSends", "index:", "size", "visitSendNode:"],
+messageSends: ["ifTrue:ifFalse:", "=", "value", "receiver", "superSend:", "value:", "at:ifAbsentPut:", "superSends", "selector", "new", "add:", "at:", "ifTrue:", "includes:", "inlinedSelectors", "shouldBeInlined:", "shouldBeAliased:", "messageSends", "index:", "size", "visitSendNode:"],
 referencedClasses: ["Set", "IRSendInliner"]
 referencedClasses: ["Set", "IRSendInliner"]
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1719,7 +1715,7 @@ smalltalk.NodeVisitor.fn.prototype._visitSequenceNode_.apply(_st(self), [aNode])
 return self}, function($ctx1) {$ctx1.fill(self,"visitSequenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitSequenceNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitSequenceNode: aNode\x0a\x09aNode temps do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addTemp: each ].\x0a\x0a\x09super visitSequenceNode: aNode",
 source: "visitSequenceNode: aNode\x0a\x09aNode temps do: [ :each |\x0a\x09\x09self validateVariableScope: each.\x0a\x09\x09currentScope addTemp: each ].\x0a\x0a\x09super visitSequenceNode: aNode",
-messageSends: ["do:", "validateVariableScope:", "addTemp:", "temps", "visitSequenceNode:"],
+messageSends: ["do:", "temps", "validateVariableScope:", "addTemp:", "visitSequenceNode:"],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);
@@ -1748,7 +1744,7 @@ _st($1)._binding_($2);
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 return self}, function($ctx1) {$ctx1.fill(self,"visitVariableNode:",{aNode:aNode},smalltalk.SemanticAnalyzer)})},
 args: ["aNode"],
 args: ["aNode"],
 source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error\x22\x0a\x0a\x09aNode binding: ((currentScope lookupVariable: aNode) ifNil: [\x0a\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09UnknownVar new name: aNode value; yourself ])",
 source: "visitVariableNode: aNode\x0a\x09\x22Bind a ScopeVar to aNode by doing a lookup in the current scope.\x0a\x09If no ScopeVar is found, bind a UnknowVar and throw an error\x22\x0a\x0a\x09aNode binding: ((currentScope lookupVariable: aNode) ifNil: [\x0a\x09\x09self errorUnknownVariable: aNode.\x0a\x09\x09UnknownVar new name: aNode value; yourself ])",
-messageSends: ["binding:", "ifNil:", "errorUnknownVariable:", "name:", "value", "new", "yourself", "lookupVariable:"],
+messageSends: ["binding:", "ifNil:", "lookupVariable:", "errorUnknownVariable:", "name:", "new", "value", "yourself"],
 referencedClasses: ["UnknownVar"]
 referencedClasses: ["UnknownVar"]
 }),
 }),
 smalltalk.SemanticAnalyzer);
 smalltalk.SemanticAnalyzer);

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

@@ -491,6 +491,222 @@ smalltalk.ASTSteppingInterpreterTest);
 
 
 
 
 
 
+smalltalk.addClass('InterpreterTest', smalltalk.AbstractASTInterpreterTest, [], 'Compiler-Tests');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpret:receiver:withArguments:",
+fn: function (aString,anObject,aDictionary){
+var self=this;
+var ctx;
+function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+ctx=_st($AIContext())._new();
+_st(ctx)._receiver_(anObject);
+_st(aDictionary)._keysAndValuesDo_((function(key,value){
+return smalltalk.withContext(function($ctx2) {
+return _st(ctx)._localAt_put_(key,value);
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+$2=self._interpreter();
+_st($2)._context_(ctx);
+_st($2)._interpret_(_st(self._parse_forClass_(aString,_st(anObject)._class()))._nextChild());
+_st($2)._proceed();
+$3=_st($2)._result();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpret:receiver:withArguments:",{aString:aString,anObject:anObject,aDictionary:aDictionary,ctx:ctx},smalltalk.InterpreterTest)})},
+messageSends: ["new", "receiver:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "interpret:", "nextChild", "parse:forClass:", "class", "proceed", "result"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpreter",
+fn: function (){
+var self=this;
+function $Interpreter(){return smalltalk.Interpreter||(typeof Interpreter=="undefined"?nil:Interpreter)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($Interpreter())._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{},smalltalk.InterpreterTest)})},
+messageSends: ["new"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testBinarySend",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ 2+3+4"),(9));
+return self}, function($ctx1) {$ctx1.fill(self,"testBinarySend",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testBlockLiteral",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ true ifTrue: [ 1 ] ifFalse: [ 2 ]"),(1));
+self._assert_equals_(self._interpret_("foo true ifTrue: [ ^ 1 ] ifFalse: [ 2 ]"),(1));
+self._assert_equals_(self._interpret_("foo ^ false ifTrue: [ 1 ] ifFalse: [ 2 ]"),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testBlockLiteral",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testCascade",
+fn: function (){
+var self=this;
+function $OrderedCollection(){return smalltalk.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ OrderedCollection new add: 2; add: 3; yourself"),_st($OrderedCollection())._with_with_((2),(3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testCascade",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:", "with:with:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDynamicArray",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ {1+1. 2+2}"),[(2), (4)]);
+return self}, function($ctx1) {$ctx1.fill(self,"testDynamicArray",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDynamicDictionary",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ #{1->1. 2->3}"),smalltalk.HashedCollection._fromPairs_([(1).__minus_gt((1)),(2).__minus_gt((3))]));
+return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionary",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:", "->"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInlinedJSStatement",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo <return 2+3>"),(5));
+self._assert_equals_(self._interpret_withArguments_("foo: anInteger <return 2 + anInteger>",smalltalk.HashedCollection._fromPairs_(["anInteger".__minus_gt((3))])),(5));
+return self}, function($ctx1) {$ctx1.fill(self,"testInlinedJSStatement",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:", "interpret:withArguments:", "->"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInstVarAccess",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ x",(2).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAccess",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInstVarAssignment",
+fn: function (){
+var self=this;
+function $Point(){return smalltalk.Point||(typeof Point=="undefined"?nil:Point)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo: anInteger x := anInteger. ^ x",_st($Point())._new(),smalltalk.HashedCollection._fromPairs_(["anInteger".__minus_gt((2))])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAssignment",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "new", "->"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testKeywordSend",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ Point x: 1 y: 2"),(1).__at((2)));
+return self}, function($ctx1) {$ctx1.fill(self,"testKeywordSend",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:", "@"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testNonlocalReturn",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo true ifTrue: [ ^ 1 ]. ^2"),(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testNonlocalReturn",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testReceiver",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ self",(2).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2).__at((3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testReceiver",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testSuper",
+fn: function (){
+var self=this;
+function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ super isBoolean",true,_st($Dictionary())._new()),false);
+return self}, function($ctx1) {$ctx1.fill(self,"testSuper",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "new"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testTempAssignment",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo | a | a := 2. ^ a"),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testTempAssignment",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testThisContext",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_(_st(_st(self._interpret_("foo ^ thisContext"))._outerContext())._isNil());
+self._assert_(_st(_st(self._interpret_("foo ^ [ thisContext ] value"))._outerContext())._notNil());
+self._assert_(self._interpret_("foo ^ [ thisContext ] value outerContext == thisContext"));
+return self}, function($ctx1) {$ctx1.fill(self,"testThisContext",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:", "isNil", "outerContext", "interpret:", "notNil"]}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testUnarySend",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ 1 asString"),"1");
+return self}, function($ctx1) {$ctx1.fill(self,"testUnarySend",{},smalltalk.InterpreterTest)})},
+messageSends: ["assert:equals:", "interpret:"]}),
+smalltalk.InterpreterTest);
+
+
+
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({

+ 301 - 0
js/Compiler-Tests.js

@@ -651,6 +651,307 @@ smalltalk.ASTSteppingInterpreterTest);
 
 
 
 
 
 
+smalltalk.addClass('InterpreterTest', smalltalk.AbstractASTInterpreterTest, [], 'Compiler-Tests');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpret:receiver:withArguments:",
+category: 'as yet unclassified',
+fn: function (aString,anObject,aDictionary){
+var self=this;
+var ctx;
+function $AIContext(){return smalltalk.AIContext||(typeof AIContext=="undefined"?nil:AIContext)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+ctx=_st($AIContext())._new();
+_st(ctx)._receiver_(anObject);
+_st(aDictionary)._keysAndValuesDo_((function(key,value){
+return smalltalk.withContext(function($ctx2) {
+return _st(ctx)._localAt_put_(key,value);
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+$2=self._interpreter();
+_st($2)._context_(ctx);
+_st($2)._interpret_(_st(self._parse_forClass_(aString,_st(anObject)._class()))._nextChild());
+_st($2)._proceed();
+$3=_st($2)._result();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpret:receiver:withArguments:",{aString:aString,anObject:anObject,aDictionary:aDictionary,ctx:ctx},smalltalk.InterpreterTest)})},
+args: ["aString", "anObject", "aDictionary"],
+source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09\x22The food is a methodNode. Interpret the sequenceNode only\x22\x0a\x09\x0a\x09| ctx |\x0a\x09\x0a\x09ctx := AIContext new.\x0a\x09ctx receiver: anObject.\x0a\x09aDictionary keysAndValuesDo: [ :key :value |\x0a\x09\x09ctx localAt: key put: value ].\x0a\x09\x0a\x09^ self interpreter\x0a\x09\x09context: ctx;\x0a\x09\x09interpret: (self parse: aString forClass: anObject class) nextChild;\x0a\x09\x09proceed;\x0a\x09\x09result",
+messageSends: ["new", "receiver:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "interpret:", "nextChild", "parse:forClass:", "class", "proceed", "result"],
+referencedClasses: ["AIContext"]
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "interpreter",
+category: 'accessing',
+fn: function (){
+var self=this;
+function $Interpreter(){return smalltalk.Interpreter||(typeof Interpreter=="undefined"?nil:Interpreter)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($Interpreter())._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "interpreter\x0a\x09^ Interpreter new",
+messageSends: ["new"],
+referencedClasses: ["Interpreter"]
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testBinarySend",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ 2+3+4"),(9));
+return self}, function($ctx1) {$ctx1.fill(self,"testBinarySend",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testBinarySend\x0a\x09self assert: (self interpret: 'foo ^ 2+3+4') equals: 9",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testBlockLiteral",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ true ifTrue: [ 1 ] ifFalse: [ 2 ]"),(1));
+self._assert_equals_(self._interpret_("foo true ifTrue: [ ^ 1 ] ifFalse: [ 2 ]"),(1));
+self._assert_equals_(self._interpret_("foo ^ false ifTrue: [ 1 ] ifFalse: [ 2 ]"),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testBlockLiteral",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testBlockLiteral\x0a\x09self assert: (self interpret: 'foo ^ true ifTrue: [ 1 ] ifFalse: [ 2 ]') equals: 1.\x0a\x09self assert: (self interpret: 'foo true ifTrue: [ ^ 1 ] ifFalse: [ 2 ]') equals: 1.\x0a\x09self assert: (self interpret: 'foo ^ false ifTrue: [ 1 ] ifFalse: [ 2 ]') equals: 2",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testCascade",
+category: 'tests',
+fn: function (){
+var self=this;
+function $OrderedCollection(){return smalltalk.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ OrderedCollection new add: 2; add: 3; yourself"),_st($OrderedCollection())._with_with_((2),(3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testCascade",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testCascade\x0a\x09self assert: (self interpret: 'foo ^ OrderedCollection new add: 2; add: 3; yourself') equals: (OrderedCollection with: 2 with: 3)",
+messageSends: ["assert:equals:", "interpret:", "with:with:"],
+referencedClasses: ["OrderedCollection"]
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDynamicArray",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ {1+1. 2+2}"),[(2), (4)]);
+return self}, function($ctx1) {$ctx1.fill(self,"testDynamicArray",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testDynamicArray\x0a\x09self assert: (self interpret: 'foo ^ {1+1. 2+2}') equals: #(2 4)",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testDynamicDictionary",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ #{1->1. 2->3}"),smalltalk.HashedCollection._fromPairs_([(1).__minus_gt((1)),(2).__minus_gt((3))]));
+return self}, function($ctx1) {$ctx1.fill(self,"testDynamicDictionary",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testDynamicDictionary\x0a\x09self assert: (self interpret: 'foo ^ #{1->1. 2->3}') equals: #{1->1. 2->3}",
+messageSends: ["assert:equals:", "interpret:", "->"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInlinedJSStatement",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo <return 2+3>"),(5));
+self._assert_equals_(self._interpret_withArguments_("foo: anInteger <return 2 + anInteger>",smalltalk.HashedCollection._fromPairs_(["anInteger".__minus_gt((3))])),(5));
+return self}, function($ctx1) {$ctx1.fill(self,"testInlinedJSStatement",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testInlinedJSStatement\x0a\x09self assert: (self interpret: 'foo <return 2+3>') equals: 5.\x0a\x09\x0a\x09self\x0a\x09\x09assert: (self\x0a\x09\x09\x09interpret: 'foo: anInteger <return 2 + anInteger>'\x0a\x09\x09\x09withArguments: #{ 'anInteger' -> 3})\x0a\x09\x09equals: 5",
+messageSends: ["assert:equals:", "interpret:", "interpret:withArguments:", "->"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInstVarAccess",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ x",(2).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAccess",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testInstVarAccess\x0a\x09self\x0a\x09\x09assert: (self\x0a\x09\x09\x09interpret: 'foo ^ x'\x0a\x09\x09\x09receiver: 2@3\x0a\x09\x09\x09withArguments: #{})\x0a\x09\x09equals: 2",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInstVarAssignment",
+category: 'tests',
+fn: function (){
+var self=this;
+function $Point(){return smalltalk.Point||(typeof Point=="undefined"?nil:Point)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo: anInteger x := anInteger. ^ x",_st($Point())._new(),smalltalk.HashedCollection._fromPairs_(["anInteger".__minus_gt((2))])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAssignment",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testInstVarAssignment\x0a\x09self\x0a\x09\x09assert: (self\x0a\x09\x09\x09interpret: 'foo: anInteger x := anInteger. ^ x'\x0a\x09\x09\x09receiver: Point new\x0a\x09\x09\x09withArguments: #{'anInteger' -> 2})\x0a\x09\x09equals: 2",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "new", "->"],
+referencedClasses: ["Point"]
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testKeywordSend",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ Point x: 1 y: 2"),(1).__at((2)));
+return self}, function($ctx1) {$ctx1.fill(self,"testKeywordSend",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testKeywordSend\x0a\x09self assert: (self interpret: 'foo ^ Point x: 1 y: 2') equals: 1@2",
+messageSends: ["assert:equals:", "interpret:", "@"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testNonlocalReturn",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo true ifTrue: [ ^ 1 ]. ^2"),(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testNonlocalReturn",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testNonlocalReturn\x0a\x09self assert: (self interpret: 'foo true ifTrue: [ ^ 1 ]. ^2') equals: 1",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testReceiver",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ self",(2).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2).__at((3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testReceiver",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testReceiver\x0a\x09self\x0a\x09\x09assert: (self\x0a\x09\x09\x09interpret: 'foo ^ self'\x0a\x09\x09\x09receiver: 2@3\x0a\x09\x09\x09withArguments: #{})\x0a\x09\x09equals: 2@3",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testSuper",
+category: 'tests',
+fn: function (){
+var self=this;
+function $Dictionary(){return smalltalk.Dictionary||(typeof Dictionary=="undefined"?nil:Dictionary)}
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_receiver_withArguments_("foo ^ super isBoolean",true,_st($Dictionary())._new()),false);
+return self}, function($ctx1) {$ctx1.fill(self,"testSuper",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testSuper\x0a\x09self \x0a\x09\x09assert: (self \x0a\x09\x09\x09interpret: 'foo ^ super isBoolean' \x0a\x09\x09\x09receiver: true \x0a\x09\x09\x09withArguments: Dictionary new) \x0a\x09\x09equals: false",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "new"],
+referencedClasses: ["Dictionary"]
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testTempAssignment",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo | a | a := 2. ^ a"),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testTempAssignment",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testTempAssignment\x0a\x09self assert: (self interpret: 'foo | a | a := 2. ^ a') equals: 2",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testThisContext",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_(_st(_st(self._interpret_("foo ^ thisContext"))._outerContext())._isNil());
+self._assert_(_st(_st(self._interpret_("foo ^ [ thisContext ] value"))._outerContext())._notNil());
+self._assert_(self._interpret_("foo ^ [ thisContext ] value outerContext == thisContext"));
+return self}, function($ctx1) {$ctx1.fill(self,"testThisContext",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testThisContext\x0a\x09self assert: (self interpret: 'foo ^ thisContext') outerContext isNil.\x0a\x09self assert: (self interpret: 'foo ^ [ thisContext ] value') outerContext notNil.\x0a\x09self assert: (self interpret: 'foo ^ [ thisContext ] value outerContext == thisContext')",
+messageSends: ["assert:", "isNil", "outerContext", "interpret:", "notNil"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testUnarySend",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._assert_equals_(self._interpret_("foo ^ 1 asString"),"1");
+return self}, function($ctx1) {$ctx1.fill(self,"testUnarySend",{},smalltalk.InterpreterTest)})},
+args: [],
+source: "testUnarySend\x0a\x09self assert: (self interpret: 'foo ^ 1 asString') equals: '1'",
+messageSends: ["assert:equals:", "interpret:"],
+referencedClasses: []
+}),
+smalltalk.InterpreterTest);
+
+
+
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 smalltalk.addMethod(
 smalltalk.method({
 smalltalk.method({

+ 40 - 10
st/Compiler-AST.st

@@ -16,14 +16,6 @@ addNode: aNode
 	aNode parent: self
 	aNode parent: self
 !
 !
 
 
-extent
-	"Answer the line and column of the end position of the receiver in the source code"
-	
-	^ self nextNode 
-		ifNil: [ self parent ifNotNil: [ :node | node extent ] ]
-		ifNotNil: [ :node | node position ]
-!
-
 nextChild
 nextChild
 	"Answer the next node after aNode.
 	"Answer the next node after aNode.
 	Recurse into the possible children of the receiver to answer the next node to be evaluated"
 	Recurse into the possible children of the receiver to answer the next node to be evaluated"
@@ -97,6 +89,13 @@ position: aPosition
 	position := aPosition
 	position := aPosition
 ! !
 ! !
 
 
+!Node methodsFor: 'copying'!
+
+postCopy
+	super postCopy.
+	self nodes do: [ :each | each parent: self ]
+! !
+
 !Node methodsFor: 'testing'!
 !Node methodsFor: 'testing'!
 
 
 isAssignmentNode
 isAssignmentNode
@@ -111,6 +110,10 @@ isBlockSequenceNode
 	^false
 	^false
 !
 !
 
 
+isCascadeNode
+	^ false
+!
+
 isImmutable
 isImmutable
 	^false
 	^false
 !
 !
@@ -119,6 +122,10 @@ isJSStatementNode
 	^ false
 	^ false
 !
 !
 
 
+isLastChild
+	^ self parent nodes last = self
+!
+
 isNode
 isNode
 	^ true
 	^ true
 !
 !
@@ -200,6 +207,12 @@ I represent an block closure node.!
 
 
 !BlockNode methodsFor: 'accessing'!
 !BlockNode methodsFor: 'accessing'!
 
 
+nextChild
+	"Answer the receiver as we want to avoid eager evaluation"
+	
+	^ self
+!
+
 nextNode: aNode
 nextNode: aNode
 	"Answer the receiver as we want to avoid eager evaluation"
 	"Answer the receiver as we want to avoid eager evaluation"
 	
 	
@@ -254,6 +267,12 @@ receiver: aNode
 	receiver := aNode
 	receiver := aNode
 ! !
 ! !
 
 
+!CascadeNode methodsFor: 'testing'!
+
+isCascadeNode
+	^ true
+! !
+
 !CascadeNode methodsFor: 'visiting'!
 !CascadeNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
@@ -458,8 +477,10 @@ index: anInteger
 !
 !
 
 
 nodes
 nodes
-	^ (Array withAll: self arguments)
-		add: self receiver;
+	self receiver ifNil: [ ^ self arguments copy ].
+	
+	^ (Array with: self receiver)
+		addAll: self arguments;
 		yourself
 		yourself
 !
 !
 
 
@@ -502,6 +523,10 @@ valueForReceiver: anObject
 
 
 !SendNode methodsFor: 'testing'!
 !SendNode methodsFor: 'testing'!
 
 
+isCascadeSendNode
+	^ self parent isCascadeNode
+!
+
 isSendNode
 isSendNode
 	^ true
 	^ true
 !
 !
@@ -606,6 +631,11 @@ accept: aVisitor
 	^ aVisitor visitValueNode: self
 	^ aVisitor visitValueNode: self
 ! !
 ! !
 
 
+!ValueNode methodsFor: 'xxxDoIt'!
+
+xxxDoIt ^[self stack] value
+! !
+
 ValueNode subclass: #VariableNode
 ValueNode subclass: #VariableNode
 	instanceVariableNames: 'assigned binding'
 	instanceVariableNames: 'assigned binding'
 	package: 'Compiler-AST'!
 	package: 'Compiler-AST'!

+ 83 - 10
st/Compiler-Interpreter.st

@@ -1,6 +1,6 @@
 Smalltalk current createPackage: 'Compiler-Interpreter'!
 Smalltalk current createPackage: 'Compiler-Interpreter'!
 NodeVisitor subclass: #AIContext
 NodeVisitor subclass: #AIContext
-	instanceVariableNames: 'outerContext innerContext pc locals method ast interpreter'
+	instanceVariableNames: 'outerContext innerContext pc locals method ast interpreter methodContext'
 	package: 'Compiler-Interpreter'!
 	package: 'Compiler-Interpreter'!
 !AIContext commentStamp!
 !AIContext commentStamp!
 I am like a `MethodContext`, used by the `ASTInterpreter`.
 I am like a `MethodContext`, used by the `ASTInterpreter`.
@@ -703,8 +703,12 @@ node: aNode
 	node := aNode
 	node := aNode
 !
 !
 
 
+result
+	^ self returnValue ifNil: [ self context receiver ]
+!
+
 returnValue
 returnValue
-	^ returnValue ifNil: [ self context receiver ]
+	^ returnValue
 !
 !
 
 
 returnValue: anObject
 returnValue: anObject
@@ -723,6 +727,11 @@ interpret
 	self visit: self node
 	self visit: self node
 !
 !
 
 
+interpret: aNode
+	self node: aNode.
+	self interpret
+!
+
 next
 next
 	self node: self node nextNode
 	self node: self node nextNode
 !
 !
@@ -730,7 +739,7 @@ next
 proceed
 proceed
 	"Eagerly evaluate the ast"
 	"Eagerly evaluate the ast"
 	
 	
-	[ self node notNil ] whileTrue: [ 
+	[ self atEnd ] whileFalse: [ 
 		self step ]
 		self step ]
 !
 !
 
 
@@ -831,7 +840,7 @@ atEnd
 !
 !
 
 
 shouldReturn
 shouldReturn
-	^ returnValue notNil
+	^ self returnValue notNil
 ! !
 ! !
 
 
 !Interpreter methodsFor: 'visiting'!
 !Interpreter methodsFor: 'visiting'!
@@ -841,15 +850,75 @@ visit: aNode
 !
 !
 
 
 visitAssignmentNode: aNode
 visitAssignmentNode: aNode
-	"Do not pop as the pushed value would be the right node"
+	| value |
+	
+	value := self pop.
 	
 	
-	self assign: aNode left to: self peek
+	"Pop the left side of the assignment.
+	It already has been visited, and we don't need its value."
+	self pop.
+	
+	self push: value.
+	self assign: aNode left to: value
+!
+
+visitBlockNode: aNode
+	"Do not evaluate the block node.
+	Instead, put all instructions into a block that we push to the stack for later evaluation"
+	
+	| blockNode blockContext block interpreter |
+	
+	"Copy the sequence node without the parent to avoid evaluating nodes up the block. 
+	#nextNode should not go anymore up than the block itself"
+	blockNode := aNode nodes first copy.
+	blockNode parent: nil.
+		
+	blockContext := self context class new
+		outerContext: self context;
+		yourself.
+	
+	block := [
+		interpreter := self class new.
+		interpreter
+			context: blockContext;
+			node: blockNode nextChild;
+			proceed.
+		
+		"Non local returns hanlding"
+		self returnValue: interpreter returnValue.
+		
+		"Answer the last evaluation of the block or nil"
+		interpreter stack isEmpty
+			ifTrue: [ nil ]
+			ifFalse: [ interpreter pop ] ].
+	
+	self push: block
 !
 !
 
 
 visitClassReferenceNode: aNode
 visitClassReferenceNode: aNode
 	self push: (Smalltalk current at: aNode value)
 	self push: (Smalltalk current at: aNode value)
 !
 !
 
 
+visitDynamicArrayNode: aNode
+	| array |
+	
+	array := #().
+	aNode nodes do: [ :each |
+		array addFirst: self pop ].
+	
+	self push: array
+!
+
+visitDynamicDictionaryNode: aNode
+	| hashedCollection |
+	
+	hashedCollection := HashedCollection new.
+	aNode nodes do: [ :each | 
+		hashedCollection add: self pop ].
+	
+	self push: hashedCollection
+!
+
 visitJSStatementNode: aNode
 visitJSStatementNode: aNode
 	self returnValue: (self eval: aNode source)
 	self returnValue: (self eval: aNode source)
 !
 !
@@ -865,17 +934,21 @@ visitReturnNode: aNode
 visitSendNode: aNode
 visitSendNode: aNode
 	| receiver args message result |
 	| receiver args message result |
 	
 	
-	args := aNode arguments collect: [ :each |
-		self pop ].
+	args := aNode arguments collect: [ :each | self pop ].
 	receiver := self pop.
 	receiver := self pop.
 	
 	
 	message := self
 	message := self
 		messageFromSendNode: aNode
 		messageFromSendNode: aNode
-		arguments: args.
+		arguments: args reversed.
 	
 	
 	result := self sendMessage: message to: receiver superSend: aNode superSend.
 	result := self sendMessage: message to: receiver superSend: aNode superSend.
 	
 	
-	self push: result
+	self context pc: self context pc + 1.
+	
+	"For cascade sends, push the reciever if the send is not the last one"
+	(aNode isCascadeSendNode and: [ aNode isLastChild not ])
+		ifTrue: [ self push: receiver ]
+		ifFalse: [ self push: result ]
 !
 !
 
 
 visitValueNode: aNode
 visitValueNode: aNode

+ 0 - 3
st/Compiler-Semantic.st

@@ -498,9 +498,6 @@ visitBlockNode: aNode
 !
 !
 
 
 visitCascadeNode: aNode
 visitCascadeNode: aNode
-	"Populate the receiver into all children"
-	aNode nodes do: [ :each |
-		each receiver: aNode receiver ].
 	super visitCascadeNode: aNode.
 	super visitCascadeNode: aNode.
 	aNode nodes first superSend ifTrue: [
 	aNode nodes first superSend ifTrue: [
 		aNode nodes do: [ :each | each superSend: true ]]
 		aNode nodes do: [ :each | each superSend: true ]]

+ 121 - 0
st/Compiler-Tests.st

@@ -292,6 +292,127 @@ testSimpleStepping
 	self assert: self interpreter result equals: 1
 	self assert: self interpreter result equals: 1
 ! !
 ! !
 
 
+AbstractASTInterpreterTest subclass: #InterpreterTest
+	instanceVariableNames: ''
+	package: 'Compiler-Tests'!
+
+!InterpreterTest methodsFor: 'accessing'!
+
+interpreter
+	^ Interpreter new
+! !
+
+!InterpreterTest methodsFor: 'as yet unclassified'!
+
+interpret: aString receiver: anObject withArguments: aDictionary
+	"The food is a methodNode. Interpret the sequenceNode only"
+	
+	| ctx |
+	
+	ctx := AIContext new.
+	ctx receiver: anObject.
+	aDictionary keysAndValuesDo: [ :key :value |
+		ctx localAt: key put: value ].
+	
+	^ self interpreter
+		context: ctx;
+		interpret: (self parse: aString forClass: anObject class) nextChild;
+		proceed;
+		result
+! !
+
+!InterpreterTest methodsFor: 'tests'!
+
+testBinarySend
+	self assert: (self interpret: 'foo ^ 2+3+4') equals: 9
+!
+
+testBlockLiteral
+	self assert: (self interpret: 'foo ^ true ifTrue: [ 1 ] ifFalse: [ 2 ]') equals: 1.
+	self assert: (self interpret: 'foo true ifTrue: [ ^ 1 ] ifFalse: [ 2 ]') equals: 1.
+	self assert: (self interpret: 'foo ^ false ifTrue: [ 1 ] ifFalse: [ 2 ]') equals: 2
+!
+
+testCascade
+	self assert: (self interpret: 'foo ^ OrderedCollection new add: 2; add: 3; yourself') equals: (OrderedCollection with: 2 with: 3)
+!
+
+testDynamicArray
+	self assert: (self interpret: 'foo ^ {1+1. 2+2}') equals: #(2 4)
+!
+
+testDynamicDictionary
+	self assert: (self interpret: 'foo ^ #{1->1. 2->3}') equals: #{1->1. 2->3}
+!
+
+testInlinedJSStatement
+	self assert: (self interpret: 'foo <return 2+3>') equals: 5.
+	
+	self
+		assert: (self
+			interpret: 'foo: anInteger <return 2 + anInteger>'
+			withArguments: #{ 'anInteger' -> 3})
+		equals: 5
+!
+
+testInstVarAccess
+	self
+		assert: (self
+			interpret: 'foo ^ x'
+			receiver: 2@3
+			withArguments: #{})
+		equals: 2
+!
+
+testInstVarAssignment
+	self
+		assert: (self
+			interpret: 'foo: anInteger x := anInteger. ^ x'
+			receiver: Point new
+			withArguments: #{'anInteger' -> 2})
+		equals: 2
+!
+
+testKeywordSend
+	self assert: (self interpret: 'foo ^ Point x: 1 y: 2') equals: 1@2
+!
+
+testNonlocalReturn
+	self assert: (self interpret: 'foo true ifTrue: [ ^ 1 ]. ^2') equals: 1
+!
+
+testReceiver
+	self
+		assert: (self
+			interpret: 'foo ^ self'
+			receiver: 2@3
+			withArguments: #{})
+		equals: 2@3
+!
+
+testSuper
+	self 
+		assert: (self 
+			interpret: 'foo ^ super isBoolean' 
+			receiver: true 
+			withArguments: Dictionary new) 
+		equals: false
+!
+
+testTempAssignment
+	self assert: (self interpret: 'foo | a | a := 2. ^ a') equals: 2
+!
+
+testThisContext
+	self assert: (self interpret: 'foo ^ thisContext') outerContext isNil.
+	self assert: (self interpret: 'foo ^ [ thisContext ] value') outerContext notNil.
+	self assert: (self interpret: 'foo ^ [ thisContext ] value outerContext == thisContext')
+!
+
+testUnarySend
+	self assert: (self interpret: 'foo ^ 1 asString') equals: '1'
+! !
+
 TestCase subclass: #CodeGeneratorTest
 TestCase subclass: #CodeGeneratorTest
 	instanceVariableNames: 'receiver'
 	instanceVariableNames: 'receiver'
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!