Browse Source

Merge branch 'up' into branching-sends

# Conflicts:
#	support/parser.js
Herbert Vojčík 8 years ago
parent
commit
7e65ecbd8e

+ 1 - 0
.travis.yml

@@ -1,4 +1,5 @@
 language: node_js
+sudo: false
 node_js:
   - "0.10"
   - "0.12"

+ 2 - 2
package.json

@@ -30,11 +30,11 @@
   },
   "devDependencies": {
     "grunt": "^0.4.0",
-    "grunt-contrib-clean": "^0.6.0",
+    "grunt-contrib-clean": "^0.7.0",
     "grunt-contrib-jshint": "^0.11.0",
     "grunt-contrib-requirejs": "^0.4.4",
     "grunt-execute": "^0.2.1",
-    "pegjs": "^0.8.0",
+    "pegjs": "^0.9.0",
     "requirejs": "^2.1.15"
   }
 }

+ 31 - 0
src/Compiler-AST.js

@@ -421,6 +421,37 @@ messageSends: []
 }),
 $globals.Node);
 
+$core.addMethod(
+$core.method({
+selector: "location:",
+protocol: 'accessing',
+fn: function (aLocation){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $3,$2,$1;
+$3=$recv(aLocation)._start();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["start"]=1;
+//>>excludeEnd("ctx");
+$2=$recv($3)._line();
+$1=$recv($2).__at($recv($recv(aLocation)._start())._column());
+self._position_($1);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"location:",{aLocation:aLocation},$globals.Node)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aLocation"],
+source: "location: aLocation\x0a\x09self position: aLocation start line @ aLocation start column",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["position:", "@", "line", "start", "column"]
+}),
+$globals.Node);
+
 $core.addMethod(
 $core.method({
 selector: "method",

+ 4 - 0
src/Compiler-AST.st

@@ -26,6 +26,10 @@ allNodes
 	^ allNodes
 !
 
+location: aLocation
+	self position: aLocation start line @ aLocation start column
+!
+
 method
 	^ self parent ifNotNil: [ :node | node method ]
 !

+ 193 - 132
src/Compiler-Interpreter.js

@@ -278,7 +278,8 @@ $2=$recv(context)._interpreter();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["interpreter"]=1;
 //>>excludeEnd("ctx");
-$recv($2)._node_($recv(sequenceNode)._nextChild());
+$recv($2)._node_(sequenceNode);
+$recv($2)._enterNode();
 $recv($2)._proceed();
 $3=$recv(self["@outerContext"])._interpreter();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -292,10 +293,10 @@ return $recv($recv(context)._interpreter())._pop();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aCollection"],
-source: "valueWithPossibleArguments: aCollection\x0a\x09| context sequenceNode |\x0a\x09context := outerContext newInnerContext.\x0a\x0a\x09\x22Interpret a copy of the sequence node to avoid creating a new AIBlockClosure\x22\x0a\x09sequenceNode := node nodes first copy\x0a\x09\x09parent: nil;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09\x22Define locals in the context\x22\x0a\x09sequenceNode temps do: [ :each |\x0a\x09\x09context defineLocal: each ].\x0a\x09\x09\x0a\x09\x22Populate the arguments into the context locals\x22\x09\x0a\x09node parameters withIndexDo: [ :each :index |\x0a\x09\x09context defineLocal: each.\x0a\x09\x09context localAt: each put: (aCollection at: index ifAbsent: [ nil ]) ].\x0a\x0a\x09\x22Interpret the first node of the BlockSequenceNode\x22\x0a\x09context interpreter\x0a\x09\x09node: sequenceNode nextChild;\x0a\x09\x09proceed.\x0a\x09\x09\x0a\x09outerContext interpreter\x0a\x09\x09setNonLocalReturnFromContext: context.\x0a\x09\x09\x0a\x09^ context interpreter pop",
+source: "valueWithPossibleArguments: aCollection\x0a\x09| context sequenceNode |\x0a\x09context := outerContext newInnerContext.\x0a\x0a\x09\x22Interpret a copy of the sequence node to avoid creating a new AIBlockClosure\x22\x0a\x09sequenceNode := node nodes first copy\x0a\x09\x09parent: nil;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09\x22Define locals in the context\x22\x0a\x09sequenceNode temps do: [ :each |\x0a\x09\x09context defineLocal: each ].\x0a\x09\x09\x0a\x09\x22Populate the arguments into the context locals\x22\x09\x0a\x09node parameters withIndexDo: [ :each :index |\x0a\x09\x09context defineLocal: each.\x0a\x09\x09context localAt: each put: (aCollection at: index ifAbsent: [ nil ]) ].\x0a\x0a\x09\x22Interpret the first node of the BlockSequenceNode\x22\x0a\x09context interpreter\x0a\x09\x09node: sequenceNode;\x0a\x09\x09enterNode;\x0a\x09\x09proceed.\x0a\x09\x09\x0a\x09outerContext interpreter\x0a\x09\x09setNonLocalReturnFromContext: context.\x0a\x09\x09\x0a\x09^ context interpreter pop",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["newInnerContext", "parent:", "copy", "first", "nodes", "yourself", "do:", "temps", "defineLocal:", "withIndexDo:", "parameters", "localAt:put:", "at:ifAbsent:", "node:", "interpreter", "nextChild", "proceed", "setNonLocalReturnFromContext:", "pop"]
+messageSends: ["newInnerContext", "parent:", "copy", "first", "nodes", "yourself", "do:", "temps", "defineLocal:", "withIndexDo:", "parameters", "localAt:put:", "at:ifAbsent:", "node:", "interpreter", "enterNode", "proceed", "setNonLocalReturnFromContext:", "pop"]
 }),
 $globals.AIBlockClosure);
 
@@ -543,7 +544,8 @@ return $core.withContext(function($ctx1) {
 var $1;
 $1=$recv($ASTInterpreter())._new();
 $recv($1)._context_(self);
-$recv($1)._node_($recv(aNode)._nextChild());
+$recv($1)._node_(aNode);
+$recv($1)._enterNode();
 $recv($1)._proceed();
 return $recv($1)._result();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -552,10 +554,10 @@ return $recv($1)._result();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "evaluateNode: aNode\x0a\x09^ ASTInterpreter new\x0a\x09\x09context: self;\x0a\x09\x09node: aNode nextChild;\x0a\x09\x09proceed;\x0a\x09\x09result",
+source: "evaluateNode: aNode\x0a\x09^ ASTInterpreter new\x0a\x09\x09context: self;\x0a\x09\x09node: aNode;\x0a\x09\x09enterNode;\x0a\x09\x09proceed;\x0a\x09\x09result",
 referencedClasses: ["ASTInterpreter"],
 //>>excludeEnd("ide");
-messageSends: ["context:", "new", "node:", "nextChild", "proceed", "result"]
+messageSends: ["context:", "new", "node:", "enterNode", "proceed", "result"]
 }),
 $globals.AIContext);
 
@@ -2042,6 +2044,129 @@ messageSends: ["context:", "new", "yourself"]
 $globals.ASTDebugger.klass);
 
 
+$core.addClass('ASTEnterNode', $globals.NodeVisitor, ['interpreter'], 'Compiler-Interpreter');
+$core.addMethod(
+$core.method({
+selector: "interpreter",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return self["@interpreter"];
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "interpreter\x0a\x09^ interpreter",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.ASTEnterNode);
+
+$core.addMethod(
+$core.method({
+selector: "interpreter:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@interpreter"]=anObject;
+return self;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "interpreter: anObject\x0a\x09interpreter := anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.ASTEnterNode);
+
+$core.addMethod(
+$core.method({
+selector: "visitBlockNode:",
+protocol: 'visiting',
+fn: function (aNode){
+var self=this;
+return aNode;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aNode"],
+source: "visitBlockNode: aNode\x0a\x09\x22Answer the node as we want to avoid eager evaluation\x22\x0a\x09\x0a\x09^ aNode",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.ASTEnterNode);
+
+$core.addMethod(
+$core.method({
+selector: "visitNode:",
+protocol: 'visiting',
+fn: function (aNode){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $early={};
+try {
+$recv($recv(aNode)._nodes())._ifEmpty_ifNotEmpty_((function(){
+throw $early=[aNode];
+
+}),(function(nodes){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+throw $early=[self._visit_($recv(nodes)._first())];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({nodes:nodes},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+return self;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"visitNode:",{aNode:aNode},$globals.ASTEnterNode)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aNode"],
+source: "visitNode: aNode\x0a\x09aNode nodes\x0a\x09\x09ifEmpty: [ ^ aNode ]\x0a\x09\x09ifNotEmpty: [ :nodes | ^ self visit: nodes first ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["ifEmpty:ifNotEmpty:", "nodes", "visit:", "first"]
+}),
+$globals.ASTEnterNode);
+
+
+$core.addMethod(
+$core.method({
+selector: "on:",
+protocol: 'instance creation',
+fn: function (anInterpreter){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=self._new();
+$recv($1)._interpreter_(anInterpreter);
+return $recv($1)._yourself();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"on:",{anInterpreter:anInterpreter},$globals.ASTEnterNode.klass)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anInterpreter"],
+source: "on: anInterpreter\x0a\x09^ self new\x0a\x09\x09interpreter: anInterpreter;\x0a\x09\x09yourself",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["interpreter:", "new", "yourself"]
+}),
+$globals.ASTEnterNode.klass);
+
+
 $core.addClass('ASTInterpreter', $globals.NodeVisitor, ['node', 'context', 'stack', 'returnValue', 'returned', 'forceAtEnd'], 'Compiler-Interpreter');
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.ASTInterpreter.comment="I visit an AST, interpreting (evaluating) nodes one after the other, using a small stack machine.\x0a\x0a## API\x0a\x0aWhile my instances should be used from within an `ASTDebugger`, which provides a more high level interface,\x0ayou can use methods from the `interpreting` protocol:\x0a\x0a- `#step` evaluates the current `node` only\x0a- `#stepOver` evaluates the AST from the current `node` up to the next stepping node (most likely the next send node)\x0a- `#proceed` evaluates eagerly the AST\x0a- `#restart` select the first node of the AST\x0a- `#skip` skips the current node, moving to the next one if any";
@@ -2158,6 +2283,31 @@ messageSends: []
 }),
 $globals.ASTInterpreter);
 
+$core.addMethod(
+$core.method({
+selector: "enterNode",
+protocol: 'interpreting',
+fn: function (){
+var self=this;
+function $ASTEnterNode(){return $globals.ASTEnterNode||(typeof ASTEnterNode=="undefined"?nil:ASTEnterNode)}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._node_($recv($recv($ASTEnterNode())._on_(self))._visit_(self._node()));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"enterNode",{},$globals.ASTInterpreter)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "enterNode\x0a\x09self node: ((ASTEnterNode on: self) visit: self node)",
+referencedClasses: ["ASTEnterNode"],
+//>>excludeEnd("ide");
+messageSends: ["node:", "visit:", "on:", "node"]
+}),
+$globals.ASTInterpreter);
+
 $core.addMethod(
 $core.method({
 selector: "eval:",
@@ -2324,31 +2474,6 @@ messageSends: ["visit:", "node"]
 }),
 $globals.ASTInterpreter);
 
-$core.addMethod(
-$core.method({
-selector: "interpret:",
-protocol: 'interpreting',
-fn: function (aNode){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-self._node_(aNode);
-self._interpret();
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"interpret:",{aNode:aNode},$globals.ASTInterpreter)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aNode"],
-source: "interpret: aNode\x0a\x09self node: aNode.\x0a\x09self interpret",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["node:", "interpret"]
-}),
-$globals.ASTInterpreter);
-
 $core.addMethod(
 $core.method({
 selector: "messageFromSendNode:arguments:",
@@ -2412,21 +2537,40 @@ selector: "next",
 protocol: 'interpreting',
 fn: function (){
 var self=this;
+var nd,nextNode;
+function $ASTEnterNode(){return $globals.ASTEnterNode||(typeof ASTEnterNode=="undefined"?nil:ASTEnterNode)}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-self._node_($recv(self._node())._nextNode());
+var $1,$2,$receiver;
+nd=self._node();
+$1=$recv(nd)._parent();
+if(($receiver = $1) == null || $receiver.isNil){
+nextNode=$1;
+} else {
+var parent;
+parent=$receiver;
+$2=$recv(parent)._nextSiblingNode_(nd);
+if(($receiver = $2) == null || $receiver.isNil){
+nextNode=parent;
+} else {
+var sibling;
+sibling=$receiver;
+nextNode=$recv($recv($ASTEnterNode())._on_(self))._visit_(sibling);
+};
+};
+self._node_(nextNode);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"next",{},$globals.ASTInterpreter)});
+}, function($ctx1) {$ctx1.fill(self,"next",{nd:nd,nextNode:nextNode},$globals.ASTInterpreter)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "next\x0a\x09self node: self node nextNode",
-referencedClasses: [],
+source: "next\x0a\x09| nd nextNode |\x0a\x09nd := self node.\x0a\x09nextNode := nd parent ifNotNil: [ :parent |\x0a\x09\x09(parent nextSiblingNode: nd)\x0a\x09\x09\x09ifNil: [ parent ]\x0a\x09\x09\x09ifNotNil: [ :sibling | (ASTEnterNode on: self) visit: sibling ] ].\x0a\x09self node: nextNode",
+referencedClasses: ["ASTEnterNode"],
 //>>excludeEnd("ide");
-messageSends: ["node:", "nextNode", "node"]
+messageSends: ["node", "ifNotNil:", "parent", "ifNil:ifNotNil:", "nextSiblingNode:", "visit:", "on:", "node:"]
 }),
 $globals.ASTInterpreter);
 
@@ -2601,7 +2745,8 @@ var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-self._node_($recv($recv(self._context())._ast())._nextChild());
+self._node_($recv(self._context())._ast());
+self._enterNode();
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"restart",{},$globals.ASTInterpreter)});
@@ -2609,10 +2754,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "restart\x0a\x09self node: self context ast nextChild",
+source: "restart\x0a\x09self node: self context ast; enterNode",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["node:", "nextChild", "ast", "context"]
+messageSends: ["node:", "ast", "context", "enterNode"]
 }),
 $globals.ASTInterpreter);
 
@@ -3667,34 +3812,16 @@ $globals.BlockNode);
 
 $core.addMethod(
 $core.method({
-selector: "nextChild",
-protocol: '*Compiler-Interpreter',
-fn: function (){
-var self=this;
-return self;
-
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "nextChild\x0a\x09\x22Answer the receiver as we want to avoid eager evaluation\x22\x0a\x09\x0a\x09^ self",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: []
-}),
-$globals.BlockNode);
-
-$core.addMethod(
-$core.method({
-selector: "nextNode:",
+selector: "nextSiblingNode:",
 protocol: '*Compiler-Interpreter',
 fn: function (aNode){
 var self=this;
-return self;
+return nil;
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "nextNode: aNode\x0a\x09\x22Answer the receiver as we want to avoid eager evaluation\x22\x0a\x09\x0a\x09^ self",
+source: "nextSiblingNode: aNode\x0a\x09\x22Answer nil as we want to avoid eager evaluation\x22\x0a\x09\x0a\x09\x22In fact, this should not have been called, ever. IMO. -- herby\x22\x0a\x09\x0a\x09^ nil",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -3775,75 +3902,10 @@ $globals.Node);
 
 $core.addMethod(
 $core.method({
-selector: "nextChild",
-protocol: '*Compiler-Interpreter',
-fn: function (){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $2,$1;
-$2=self._nodes();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["nodes"]=1;
-//>>excludeEnd("ctx");
-$1=$recv($2)._isEmpty();
-if($core.assert($1)){
-return self;
-} else {
-return $recv($recv(self._nodes())._first())._nextChild();
-};
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextChild",{},$globals.Node)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "nextChild\x0a\x09\x22Answer the next node after aNode.\x0a\x09Recurse into the possible children of the receiver to answer the next node to be evaluated\x22\x0a\x09\x0a\x09^ self nodes isEmpty\x0a\x09\x09ifTrue: [ self ]\x0a\x09\x09ifFalse: [ self nodes first nextChild ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["ifTrue:ifFalse:", "isEmpty", "nodes", "nextChild", "first"]
-}),
-$globals.Node);
-
-$core.addMethod(
-$core.method({
-selector: "nextNode",
-protocol: '*Compiler-Interpreter',
-fn: function (){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$receiver;
-$1=self._parent();
-if(($receiver = $1) == null || $receiver.isNil){
-return $1;
-} else {
-var node;
-node=$receiver;
-return $recv(node)._nextNode_(self);
-};
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextNode",{},$globals.Node)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "nextNode\x0a\x09^ self parent ifNotNil: [ :node |\x0a\x09\x09node nextNode: self ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["ifNotNil:", "parent", "nextNode:"]
-}),
-$globals.Node);
-
-$core.addMethod(
-$core.method({
-selector: "nextNode:",
+selector: "nextSiblingNode:",
 protocol: '*Compiler-Interpreter',
 fn: function (aNode){
 var self=this;
-var next;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
@@ -3854,23 +3916,22 @@ $1=self._nodes();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["nodes"]=1;
 //>>excludeEnd("ctx");
-next=$recv($1)._at_ifAbsent_($recv($recv(self._nodes())._indexOf_(aNode)).__plus((1)),(function(){
-throw $early=[self];
+return $recv($1)._at_ifAbsent_($recv($recv(self._nodes())._indexOf_(aNode)).__plus((1)),(function(){
+throw $early=[nil];
 
 }));
-return $recv(next)._nextChild();
 }
 catch(e) {if(e===$early)return e[0]; throw e}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextNode:",{aNode:aNode,next:next},$globals.Node)});
+}, function($ctx1) {$ctx1.fill(self,"nextSiblingNode:",{aNode:aNode},$globals.Node)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "nextNode: aNode\x0a\x09\x22Answer the next node after aNode.\x0a\x09Recurse into the possible children of the next node to answer the next node to be evaluated\x22\x0a\x09\x0a\x09| next |\x0a\x09\x0a\x09next := self nodes \x0a\x09\x09at: (self nodes indexOf: aNode) + 1\x0a\x09\x09ifAbsent: [ ^ self ].\x0a\x09\x0a\x09^ next nextChild",
+source: "nextSiblingNode: aNode\x0a\x09\x22Answer the next node after aNode or nil\x22\x0a\x09\x0a\x09^ self nodes \x0a\x09\x09at: (self nodes indexOf: aNode) + 1\x0a\x09\x09ifAbsent: [ ^ nil ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["at:ifAbsent:", "nodes", "+", "indexOf:", "nextChild"]
+messageSends: ["at:ifAbsent:", "nodes", "+", "indexOf:"]
 }),
 $globals.Node);
 

+ 60 - 40
src/Compiler-Interpreter.st

@@ -75,7 +75,8 @@ valueWithPossibleArguments: aCollection
 
 	"Interpret the first node of the BlockSequenceNode"
 	context interpreter
-		node: sequenceNode nextChild;
+		node: sequenceNode;
+		enterNode;
 		proceed.
 		
 	outerContext interpreter
@@ -219,7 +220,8 @@ evaluate: aString on: anEvaluator
 evaluateNode: aNode
 	^ ASTInterpreter new
 		context: self;
-		node: aNode nextChild;
+		node: aNode;
+		enterNode;
 		proceed;
 		result
 ! !
@@ -536,6 +538,42 @@ context: aContext
 		yourself
 ! !
 
+NodeVisitor subclass: #ASTEnterNode
+	instanceVariableNames: 'interpreter'
+	package: 'Compiler-Interpreter'!
+
+!ASTEnterNode methodsFor: 'accessing'!
+
+interpreter
+	^ interpreter
+!
+
+interpreter: anObject
+	interpreter := anObject
+! !
+
+!ASTEnterNode methodsFor: 'visiting'!
+
+visitBlockNode: aNode
+	"Answer the node as we want to avoid eager evaluation"
+	
+	^ aNode
+!
+
+visitNode: aNode
+	aNode nodes
+		ifEmpty: [ ^ aNode ]
+		ifNotEmpty: [ :nodes | ^ self visit: nodes first ]
+! !
+
+!ASTEnterNode class methodsFor: 'instance creation'!
+
+on: anInterpreter
+	^ self new
+		interpreter: anInterpreter;
+		yourself
+! !
+
 NodeVisitor subclass: #ASTInterpreter
 	instanceVariableNames: 'node context stack returnValue returned forceAtEnd'
 	package: 'Compiler-Interpreter'!
@@ -601,19 +639,24 @@ initialize
 
 !ASTInterpreter methodsFor: 'interpreting'!
 
+enterNode
+	self node: ((ASTEnterNode on: self) visit: self node)
+!
+
 interpret
 	"Interpret the next node to be evaluated"
 	
 	self visit: self node
 !
 
-interpret: aNode
-	self node: aNode.
-	self interpret
-!
-
 next
-	self node: self node nextNode
+	| nd nextNode |
+	nd := self node.
+	nextNode := nd parent ifNotNil: [ :parent |
+		(parent nextSiblingNode: nd)
+			ifNil: [ parent ]
+			ifNotNil: [ :sibling | (ASTEnterNode on: self) visit: sibling ] ].
+	self node: nextNode
 !
 
 proceed
@@ -624,7 +667,7 @@ proceed
 !
 
 restart
-	self node: self context ast nextChild
+	self node: self context ast; enterNode
 !
 
 setNonLocalReturnFromContext: aContext
@@ -942,16 +985,12 @@ isSteppingNode
 	^ true
 !
 
-nextChild
-	"Answer the receiver as we want to avoid eager evaluation"
+nextSiblingNode: aNode
+	"Answer nil as we want to avoid eager evaluation"
 	
-	^ self
-!
-
-nextNode: aNode
-	"Answer the receiver as we want to avoid eager evaluation"
+	"In fact, this should not have been called, ever. IMO. -- herby"
 	
-	^ self
+	^ nil
 ! !
 
 !DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
@@ -978,31 +1017,12 @@ isSteppingNode
 	^ false
 !
 
-nextChild
-	"Answer the next node after aNode.
-	Recurse into the possible children of the receiver to answer the next node to be evaluated"
-	
-	^ self nodes isEmpty
-		ifTrue: [ self ]
-		ifFalse: [ self nodes first nextChild ]
-!
-
-nextNode
-	^ self parent ifNotNil: [ :node |
-		node nextNode: self ]
-!
-
-nextNode: aNode
-	"Answer the next node after aNode.
-	Recurse into the possible children of the next node to answer the next node to be evaluated"
+nextSiblingNode: aNode
+	"Answer the next node after aNode or nil"
 	
-	| next |
-	
-	next := self nodes 
+	^ self nodes 
 		at: (self nodes indexOf: aNode) + 1
-		ifAbsent: [ ^ self ].
-	
-	^ next nextChild
+		ifAbsent: [ ^ nil ]
 ! !
 
 !SendNode methodsFor: '*Compiler-Interpreter'!

+ 13 - 10
src/Compiler-Tests.js

@@ -1899,7 +1899,8 @@ return $recv(ctx)._localAt_put_(key,value);
 }));
 $3=interpreter;
 $recv($3)._context_(ctx);
-$recv($3)._interpret_($recv(ast)._nextChild());
+$recv($3)._node_(ast);
+$recv($3)._enterNode();
 $recv($3)._proceed();
 return $recv($3)._result();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -1908,10 +1909,10 @@ return $recv($3)._result();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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 ast interpreter |\x0a\x09\x0a\x09interpreter := ASTInterpreter new.\x0a\x09ast := self parse: aString forClass: anObject class.\x0a\x09\x0a\x09ctx := AIContext new\x0a\x09\x09receiver: anObject;\x0a\x09\x09interpreter: interpreter;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09\x22Define locals for the context\x22\x0a\x09ast sequenceNode ifNotNil: [ :sequence |\x0a\x09\x09sequence temps do: [ :each |\x0a\x09\x09\x09ctx defineLocal: each ] ].\x0a\x09\x09\x0a\x09aDictionary keysAndValuesDo: [ :key :value |\x0a\x09\x09ctx localAt: key put: value ].\x0a\x09\x0a\x09^ interpreter\x0a\x09\x09context: ctx;\x0a\x09\x09interpret: ast nextChild;\x0a\x09\x09proceed;\x0a\x09\x09result",
+source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09\x22The food is a methodNode. Interpret the sequenceNode only\x22\x0a\x09\x0a\x09| ctx ast interpreter |\x0a\x09\x0a\x09interpreter := ASTInterpreter new.\x0a\x09ast := self parse: aString forClass: anObject class.\x0a\x09\x0a\x09ctx := AIContext new\x0a\x09\x09receiver: anObject;\x0a\x09\x09interpreter: interpreter;\x0a\x09\x09yourself.\x0a\x09\x09\x0a\x09\x22Define locals for the context\x22\x0a\x09ast sequenceNode ifNotNil: [ :sequence |\x0a\x09\x09sequence temps do: [ :each |\x0a\x09\x09\x09ctx defineLocal: each ] ].\x0a\x09\x09\x0a\x09aDictionary keysAndValuesDo: [ :key :value |\x0a\x09\x09ctx localAt: key put: value ].\x0a\x09\x0a\x09^ interpreter\x0a\x09\x09context: ctx;\x0a\x09\x09node: ast;\x0a\x09\x09enterNode;\x0a\x09\x09proceed;\x0a\x09\x09result",
 referencedClasses: ["ASTInterpreter", "AIContext"],
 //>>excludeEnd("ide");
-messageSends: ["new", "parse:forClass:", "class", "receiver:", "interpreter:", "yourself", "ifNotNil:", "sequenceNode", "do:", "temps", "defineLocal:", "keysAndValuesDo:", "localAt:put:", "context:", "interpret:", "nextChild", "proceed", "result"]
+messageSends: ["new", "parse:forClass:", "class", "receiver:", "interpreter:", "yourself", "ifNotNil:", "sequenceNode", "do:", "temps", "defineLocal:", "keysAndValuesDo:", "localAt:put:", "context:", "node:", "enterNode", "proceed", "result"]
 }),
 $globals.ASTInterpreterTest);
 
@@ -2002,7 +2003,7 @@ function $ASTDebugger(){return $globals.ASTDebugger||(typeof ASTDebugger=="undef
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4,$receiver;
+var $1,$2,$3,$4,$5,$receiver;
 $1=$recv($AIContext())._new();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["new"]=1;
@@ -2044,21 +2045,23 @@ $recv($3)._context_(ctx);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["context:"]=1;
 //>>excludeEnd("ctx");
-$recv($recv(ctx)._interpreter())._node_($recv(ast)._nextChild());
+$4=$recv(ctx)._interpreter();
+$recv($4)._node_(ast);
+$recv($4)._enterNode();
 debugger_=$recv($ASTDebugger())._context_(ctx);
-$4=debugger_;
-$recv($4)._proceed();
-return $recv($4)._result();
+$5=debugger_;
+$recv($5)._proceed();
+return $recv($5)._result();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"interpret:receiver:withArguments:",{aString:aString,anObject:anObject,aDictionary:aDictionary,ctx:ctx,ast:ast,debugger_:debugger_},$globals.ASTDebuggerTest)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "anObject", "aDictionary"],
-source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09| ctx ast debugger |\x0a\x09\x0a\x09ctx := AIContext new\x0a\x09\x09receiver: anObject;\x0a\x09\x09interpreter: ASTInterpreter new;\x0a\x09\x09yourself.\x0a\x09ast := self parse: aString forClass: anObject class.\x0a\x09\x09\x0a\x09\x22Define locals for the context\x22\x0a\x09ast sequenceNode ifNotNil: [ :sequence |\x0a\x09\x09sequence temps do: [ :each |\x0a\x09\x09\x09ctx defineLocal: each ] ].\x0a\x09\x0a\x09aDictionary keysAndValuesDo: [ :key :value |\x0a\x09\x09ctx localAt: key put: value ].\x0a\x09ctx interpreter context: ctx.\x0a\x09\x0a\x09ctx interpreter node: ast nextChild.\x0a\x09\x0a\x09debugger := ASTDebugger context: ctx.\x0a\x09\x0a\x09^ debugger \x0a\x09\x09proceed; \x0a\x09\x09result",
+source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09| ctx ast debugger |\x0a\x09\x0a\x09ctx := AIContext new\x0a\x09\x09receiver: anObject;\x0a\x09\x09interpreter: ASTInterpreter new;\x0a\x09\x09yourself.\x0a\x09ast := self parse: aString forClass: anObject class.\x0a\x09\x09\x0a\x09\x22Define locals for the context\x22\x0a\x09ast sequenceNode ifNotNil: [ :sequence |\x0a\x09\x09sequence temps do: [ :each |\x0a\x09\x09\x09ctx defineLocal: each ] ].\x0a\x09\x0a\x09aDictionary keysAndValuesDo: [ :key :value |\x0a\x09\x09ctx localAt: key put: value ].\x0a\x09ctx interpreter context: ctx.\x0a\x09\x0a\x09ctx interpreter node: ast; enterNode.\x0a\x09\x0a\x09debugger := ASTDebugger context: ctx.\x0a\x09\x0a\x09^ debugger \x0a\x09\x09proceed; \x0a\x09\x09result",
 referencedClasses: ["AIContext", "ASTInterpreter", "ASTDebugger"],
 //>>excludeEnd("ide");
-messageSends: ["receiver:", "new", "interpreter:", "yourself", "parse:forClass:", "class", "ifNotNil:", "sequenceNode", "do:", "temps", "defineLocal:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "node:", "nextChild", "proceed", "result"]
+messageSends: ["receiver:", "new", "interpreter:", "yourself", "parse:forClass:", "class", "ifNotNil:", "sequenceNode", "do:", "temps", "defineLocal:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "node:", "enterNode", "proceed", "result"]
 }),
 $globals.ASTDebuggerTest);
 

+ 3 - 2
src/Compiler-Tests.st

@@ -517,7 +517,8 @@ interpret: aString receiver: anObject withArguments: aDictionary
 	
 	^ interpreter
 		context: ctx;
-		interpret: ast nextChild;
+		node: ast;
+		enterNode;
 		proceed;
 		result
 ! !
@@ -556,7 +557,7 @@ interpret: aString receiver: anObject withArguments: aDictionary
 		ctx localAt: key put: value ].
 	ctx interpreter context: ctx.
 	
-	ctx interpreter node: ast nextChild.
+	ctx interpreter node: ast; enterNode.
 	
 	debugger := ASTDebugger context: ctx.
 	

+ 17 - 17
src/Kernel-Collections.js

@@ -5896,7 +5896,10 @@ var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return aString != null && String(self) === (typeof aString === "string" ? aString : aString.valueOf());
+
+	if (typeof aString === "string") return String(self) === aString;
+	else if (aString != null && typeof aString === "object") return String(self) === aString.valueOf();
+	else return false;;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"==",{aString:aString},$globals.String)});
@@ -5904,7 +5907,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
-source: "== aString\x0a<return aString != null && String(self) === (typeof aString === \x22string\x22 ? aString : aString.valueOf())>",
+source: "== aString\x0a<\x0a\x09if (typeof aString === \x22string\x22) return String(self) === aString;\x0a\x09else if (aString != null && typeof aString === \x22object\x22) return String(self) === aString.valueOf();\x0a\x09else return false;\x0a>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -7880,21 +7883,18 @@ var self=this;
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 
-		var type, bucket, prim = anObject == null ? (anObject = nil) : anObject.valueOf();
-		if ((type = typeof prim) === "object") {
-			if (anObject !== nil) {
-				bucket = null;
-				self['@slowBucketStores'].some(function (store) {
-					return bucket = store._bucketOfElement_(anObject);
-				});
-				return [ anObject, null, bucket || self['@defaultBucket'] ];
-			}
-			
-			// include nil to well-known objects under 'boolean' fastBucket
-			prim = null;
-			type = 'boolean';
+		// include nil to well-known objects under 'boolean' fastBucket
+		if (anObject == null || anObject.isNil) return [ null, self['@fastBuckets'].boolean ];
+		
+		var prim = anObject.valueOf();
+		if (typeof prim === "object" || typeof prim === "function" || !self['@fastBuckets'][typeof prim]) {
+			var bucket = null;
+			self['@slowBucketStores'].some(function (store) {
+				return bucket = store._bucketOfElement_(anObject);
+			});
+			return [ anObject, null, bucket || self['@defaultBucket'] ];
 		}
-		return [ prim, self['@fastBuckets'][type] ];
+		return [ prim, self['@fastBuckets'][typeof prim] ];
 	;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -7903,7 +7903,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anObject"],
-source: "bucketsOfElement: anObject\x0a\x09\x22Find the appropriate bucket for `anObject`.\x0a\x09For optimization purposes, directly answer an array with: \x0a\x09- the object to be store\x0a\x09- the primitive bucket\x0a\x09- the slow bucket\x22\x0a\x09\x0a\x09<\x0a\x09\x09var type, bucket, prim = anObject == null ? (anObject = nil) : anObject.valueOf();\x0a\x09\x09if ((type = typeof prim) === \x22object\x22) {\x0a\x09\x09\x09if (anObject !== nil) {\x0a\x09\x09\x09\x09bucket = null;\x0a\x09\x09\x09\x09self['@slowBucketStores'].some(function (store) {\x0a\x09\x09\x09\x09\x09return bucket = store._bucketOfElement_(anObject);\x0a\x09\x09\x09\x09});\x0a\x09\x09\x09\x09return [ anObject, null, bucket || self['@defaultBucket'] ];\x0a\x09\x09\x09}\x0a\x09\x09\x09\x0a\x09\x09\x09// include nil to well-known objects under 'boolean' fastBucket\x0a\x09\x09\x09prim = null;\x0a\x09\x09\x09type = 'boolean';\x0a\x09\x09}\x0a\x09\x09return [ prim, self['@fastBuckets'][type] ];\x0a\x09>",
+source: "bucketsOfElement: anObject\x0a\x09\x22Find the appropriate bucket for `anObject`.\x0a\x09For optimization purposes, directly answer an array with: \x0a\x09- the object to be store\x0a\x09- the primitive bucket\x0a\x09- the slow bucket\x22\x0a\x09\x0a\x09<\x0a\x09\x09// include nil to well-known objects under 'boolean' fastBucket\x0a\x09\x09if (anObject == null || anObject.isNil) return [ null, self['@fastBuckets'].boolean ];\x0a\x09\x09\x0a\x09\x09var prim = anObject.valueOf();\x0a\x09\x09if (typeof prim === \x22object\x22 || typeof prim === \x22function\x22 || !self['@fastBuckets'][typeof prim]) {\x0a\x09\x09\x09var bucket = null;\x0a\x09\x09\x09self['@slowBucketStores'].some(function (store) {\x0a\x09\x09\x09\x09return bucket = store._bucketOfElement_(anObject);\x0a\x09\x09\x09});\x0a\x09\x09\x09return [ anObject, null, bucket || self['@defaultBucket'] ];\x0a\x09\x09}\x0a\x09\x09return [ prim, self['@fastBuckets'][typeof prim] ];\x0a\x09>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []

+ 16 - 15
src/Kernel-Collections.st

@@ -1473,7 +1473,11 @@ size
 !
 
 == aString
-<return aString !!= null && String(self) === (typeof aString === "string" ? aString : aString.valueOf())>
+<
+	if (typeof aString === "string") return String(self) === aString;
+	else if (aString !!= null && typeof aString === "object") return String(self) === aString.valueOf();
+	else return false;
+>
 !
 
 > aString
@@ -1986,21 +1990,18 @@ bucketsOfElement: anObject
 	- the slow bucket"
 	
 	<
-		var type, bucket, prim = anObject == null ? (anObject = nil) : anObject.valueOf();
-		if ((type = typeof prim) === "object") {
-			if (anObject !!== nil) {
-				bucket = null;
-				self['@slowBucketStores'].some(function (store) {
-					return bucket = store._bucketOfElement_(anObject);
-				});
-				return [ anObject, null, bucket || self['@defaultBucket'] ];
-			}
-			
-			// include nil to well-known objects under 'boolean' fastBucket
-			prim = null;
-			type = 'boolean';
+		// include nil to well-known objects under 'boolean' fastBucket
+		if (anObject == null || anObject.isNil) return [ null, self['@fastBuckets'].boolean ];
+		
+		var prim = anObject.valueOf();
+		if (typeof prim === "object" || typeof prim === "function" || !!self['@fastBuckets'][typeof prim]) {
+			var bucket = null;
+			self['@slowBucketStores'].some(function (store) {
+				return bucket = store._bucketOfElement_(anObject);
+			});
+			return [ anObject, null, bucket || self['@defaultBucket'] ];
 		}
-		return [ prim, self['@fastBuckets'][type] ];
+		return [ prim, self['@fastBuckets'][typeof prim] ];
 	>
 !
 

+ 10 - 4
src/Kernel-Objects.js

@@ -1769,7 +1769,10 @@ var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return aBoolean != null && self.valueOf() === (typeof aBoolean === "boolean" ? aBoolean : aBoolean.valueOf());
+
+	if (typeof aBoolean === "boolean") return self.valueOf() === aBoolean;
+	else if (aBoolean != null && typeof aBoolean === "object") return self.valueOf() === aBoolean.valueOf();
+	else return false;;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"==",{aBoolean:aBoolean},$globals.Boolean)});
@@ -1777,7 +1780,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBoolean"],
-source: "== aBoolean\x0a<return aBoolean != null && self.valueOf() === (typeof aBoolean === \x22boolean\x22 ? aBoolean : aBoolean.valueOf())>",
+source: "== aBoolean\x0a<\x0a\x09if (typeof aBoolean === \x22boolean\x22) return self.valueOf() === aBoolean;\x0a\x09else if (aBoolean != null && typeof aBoolean === \x22object\x22) return self.valueOf() === aBoolean.valueOf();\x0a\x09else return false;\x0a>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -3416,7 +3419,10 @@ var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return aNumber != null && Number(self) === (typeof aNumber === "number" ? aNumber : aNumber.valueOf());
+
+	if (typeof aNumber === "number") return Number(self) === aNumber;
+	else if (aNumber != null && typeof aNumber === "object") return Number(self) === aNumber.valueOf();
+	else return false;;
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"==",{aNumber:aNumber},$globals.Number)});
@@ -3424,7 +3430,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNumber"],
-source: "== aNumber\x0a<return aNumber != null && Number(self) === (typeof aNumber === \x22number\x22 ? aNumber : aNumber.valueOf())>",
+source: "== aNumber\x0a<\x0a\x09if (typeof aNumber === \x22number\x22) return Number(self) === aNumber;\x0a\x09else if (aNumber != null && typeof aNumber === \x22object\x22) return Number(self) === aNumber.valueOf();\x0a\x09else return false;\x0a>",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []

+ 10 - 2
src/Kernel-Objects.st

@@ -434,7 +434,11 @@ I am directly mapped to JavaScript Boolean. The `true` and `false` objects are t
 !Boolean methodsFor: 'comparing'!
 
 == aBoolean
-<return aBoolean !!= null && self.valueOf() === (typeof aBoolean === "boolean" ? aBoolean : aBoolean.valueOf())>
+<
+	if (typeof aBoolean === "boolean") return self.valueOf() === aBoolean;
+	else if (aBoolean !!= null && typeof aBoolean === "object") return self.valueOf() === aBoolean.valueOf();
+	else return false;
+>
 ! !
 
 !Boolean methodsFor: 'controlling'!
@@ -826,7 +830,11 @@ negated
 !
 
 == aNumber
-<return aNumber !!= null && Number(self) === (typeof aNumber === "number" ? aNumber : aNumber.valueOf())>
+<
+	if (typeof aNumber === "number") return Number(self) === aNumber;
+	else if (aNumber !!= null && typeof aNumber === "object") return Number(self) === aNumber.valueOf();
+	else return false;
+>
 !
 
 > aNumber

+ 107 - 30
src/Kernel-Tests.js

@@ -2459,7 +2459,7 @@ $globals.ClassTest);
 
 
 
-$core.addClass('CollectionTest', $globals.TestCase, [], 'Kernel-Tests');
+$core.addClass('CollectionTest', $globals.TestCase, ['sampleBlock'], 'Kernel-Tests');
 $core.addMethod(
 $core.method({
 selector: "assertSameContents:as:",
@@ -2653,6 +2653,40 @@ messageSends: ["subclassResponsibility"]
 }),
 $globals.CollectionTest);
 
+$core.addMethod(
+$core.method({
+selector: "initialize",
+protocol: 'initialization',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true, 
+//>>excludeEnd("ctx");
+($globals.CollectionTest.superclass||$boot.dnu).fn.prototype._initialize.apply($recv(self), []));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = false;
+//>>excludeEnd("ctx");;
+self["@sampleBlock"]=(function(){
+
+});
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"initialize",{},$globals.CollectionTest)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x0a\x09sampleBlock := []",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["initialize"]
+}),
+$globals.CollectionTest);
+
 $core.addMethod(
 $core.method({
 selector: "isCollectionReadOnly",
@@ -3070,7 +3104,7 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 c=self._collectionWithDuplicates();
 set=$recv(c)._asSet();
-self._assert_equals_($recv(set)._size(),(5));
+self._assert_equals_($recv(set)._size(),(6));
 $recv(c)._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -3087,7 +3121,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "testAsSet\x0a\x09| c set |\x0a\x09c := self collectionWithDuplicates.\x0a\x09set := c asSet.\x0a\x09self assert: set size equals: 5.\x0a\x09c do: [ :each |\x0a\x09\x09self assert: (set includes: each) ]",
+source: "testAsSet\x0a\x09| c set |\x0a\x09c := self collectionWithDuplicates.\x0a\x09set := c asSet.\x0a\x09self assert: set size equals: 6.\x0a\x09c do: [ :each |\x0a\x09\x09self assert: (set includes: each) ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: ["collectionWithDuplicates", "asSet", "assert:equals:", "size", "do:", "assert:", "includes:"]
@@ -5183,6 +5217,7 @@ selector: "nonIndexesDo:",
 protocol: 'fixture',
 fn: function (aBlock){
 var self=this;
+function $Object(){return $globals.Object||(typeof Object=="undefined"?nil:Object)}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
@@ -5190,6 +5225,16 @@ $recv(aBlock)._value_((5));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["value:"]=1;
 //>>excludeEnd("ctx");
+$recv(aBlock)._value_((function(){
+
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["value:"]=2;
+//>>excludeEnd("ctx");
+$recv(aBlock)._value_($recv($Object())._new());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["value:"]=3;
+//>>excludeEnd("ctx");
 $recv(aBlock)._value_("z");
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -5198,10 +5243,10 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
-source: "nonIndexesDo: aBlock\x0a\x09aBlock value: 5.\x0a\x09aBlock value: 'z'",
-referencedClasses: [],
+source: "nonIndexesDo: aBlock\x0a\x09aBlock value: 5.\x0a\x09aBlock value: [].\x0a\x09aBlock value: Object new.\x0a\x09aBlock value: 'z'",
+referencedClasses: ["Object"],
 //>>excludeEnd("ide");
-messageSends: ["value:"]
+messageSends: ["value:", "new"]
 }),
 $globals.AssociativeCollectionTest);
 
@@ -5885,6 +5930,10 @@ $recv($1)._at_put_(true,(3));
 $ctx1.sendIdx["at:put:"]=3;
 //>>excludeEnd("ctx");
 $recv($1)._at_put_((1).__at((3)),(-4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["at:put:"]=4;
+//>>excludeEnd("ctx");
+$recv($1)._at_put_(self["@sampleBlock"],(9));
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collection",{},$globals.DictionaryTest)});
@@ -5892,7 +5941,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collection\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 1@3 put: -4;\x0a\x09\x09yourself",
+source: "collection\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 1@3 put: -4;\x0a\x09\x09at: sampleBlock put: 9;\x0a\x09\x09yourself",
 referencedClasses: ["Dictionary"],
 //>>excludeEnd("ide");
 messageSends: ["at:put:", "new", "@", "yourself"]
@@ -5908,14 +5957,14 @@ var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return [(1),"a",true,(1).__at((3))];
+return [(1),"a",true,(1).__at((3)),self["@sampleBlock"]];
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collectionKeys",{},$globals.DictionaryTest)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionKeys\x0a\x09^ {1. 'a'. true. 1@3}",
+source: "collectionKeys\x0a\x09^ {1. 'a'. true. 1@3. sampleBlock}",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: ["@"]
@@ -5947,6 +5996,10 @@ $recv($1)._at_put_(true,"3");
 $ctx1.sendIdx["at:put:"]=3;
 //>>excludeEnd("ctx");
 $recv($1)._at_put_((1).__at((3)),"-4");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["at:put:"]=4;
+//>>excludeEnd("ctx");
+$recv($1)._at_put_(self["@sampleBlock"],"9");
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collectionOfPrintStrings",{},$globals.DictionaryTest)});
@@ -5954,7 +6007,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionOfPrintStrings\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: '1';\x0a\x09\x09at: 'a' put: '2';\x0a\x09\x09at: true put: '3';\x0a\x09\x09at: 1@3 put: '-4';\x0a\x09\x09yourself",
+source: "collectionOfPrintStrings\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: '1';\x0a\x09\x09at: 'a' put: '2';\x0a\x09\x09at: true put: '3';\x0a\x09\x09at: 1@3 put: '-4';\x0a\x09\x09at: sampleBlock put: '9';\x0a\x09\x09yourself",
 referencedClasses: ["Dictionary"],
 //>>excludeEnd("ide");
 messageSends: ["at:put:", "new", "@", "yourself"]
@@ -5967,12 +6020,12 @@ selector: "collectionSize",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return (4);
+return (5);
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionSize\x0a\x09^ 4",
+source: "collectionSize\x0a\x09^ 5",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -5985,12 +6038,12 @@ selector: "collectionValues",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return [(1),(2),(3),(-4)];
+return [(1),(2),(3),(-4),(9)];
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionValues\x0a\x09^ {1. 2. 3. -4}",
+source: "collectionValues\x0a\x09^ {1. 2. 3. -4. 9}",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -6025,14 +6078,18 @@ $recv($1)._at_put_((4),(-4));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=4;
 //>>excludeEnd("ctx");
-$recv($1)._at_put_("b",(1));
+$recv($1)._at_put_(self["@sampleBlock"],(9));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=5;
 //>>excludeEnd("ctx");
-$recv($1)._at_put_((3),(3));
+$recv($1)._at_put_("b",(1));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=6;
 //>>excludeEnd("ctx");
+$recv($1)._at_put_((3),(3));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["at:put:"]=7;
+//>>excludeEnd("ctx");
 $recv($1)._at_put_(false,(12));
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -6041,7 +6098,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithDuplicates\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 4 put: -4;\x0a\x09\x09at: 'b' put: 1;\x0a\x09\x09at: 3 put: 3;\x0a\x09\x09at: false put: 12;\x0a\x09\x09yourself",
+source: "collectionWithDuplicates\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 4 put: -4;\x0a\x09\x09at: sampleBlock put: 9;\x0a\x09\x09at: 'b' put: 1;\x0a\x09\x09at: 3 put: 3;\x0a\x09\x09at: false put: 12;\x0a\x09\x09yourself",
 referencedClasses: ["Dictionary"],
 //>>excludeEnd("ide");
 messageSends: ["at:put:", "new", "yourself"]
@@ -6076,6 +6133,10 @@ $recv($1)._at_put_((1).__at((3)),(-4));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.sendIdx["at:put:"]=4;
 //>>excludeEnd("ctx");
+$recv($1)._at_put_(self["@sampleBlock"],(9));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["at:put:"]=5;
+//>>excludeEnd("ctx");
 $recv($1)._at_put_("new","N");
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -6084,7 +6145,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithNewValue\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 1@3 put: -4;\x0a\x09\x09at: 'new' put: 'N';\x0a\x09\x09yourself",
+source: "collectionWithNewValue\x0a\x09^ Dictionary new\x0a\x09\x09at: 1 put: 1;\x0a\x09\x09at: 'a' put: 2;\x0a\x09\x09at: true put: 3;\x0a\x09\x09at: 1@3 put: -4;\x0a\x09\x09at: sampleBlock put: 9;\x0a\x09\x09at: 'new' put: 'N';\x0a\x09\x09yourself",
 referencedClasses: ["Dictionary"],
 //>>excludeEnd("ide");
 messageSends: ["at:put:", "new", "@", "yourself"]
@@ -6140,6 +6201,10 @@ $recv(aBlock)._value_value_(true,(3));
 $ctx1.sendIdx["value:value:"]=1;
 //>>excludeEnd("ctx");
 $recv(aBlock)._value_value_((1).__at((3)),(-4));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["value:value:"]=2;
+//>>excludeEnd("ctx");
+$recv(aBlock)._value_value_(self["@sampleBlock"],(9));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"samplesDo:",{aBlock:aBlock},$globals.DictionaryTest)});
@@ -6147,7 +6212,7 @@ return self;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
-source: "samplesDo: aBlock\x0a\x09super samplesDo: aBlock.\x0a\x09aBlock value: true value: 3.\x0a\x09aBlock value: 1@3 value: -4",
+source: "samplesDo: aBlock\x0a\x09super samplesDo: aBlock.\x0a\x09aBlock value: true value: 3.\x0a\x09aBlock value: 1@3 value: -4.\x0a\x09aBlock value: sampleBlock value: 9",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: ["samplesDo:", "value:value:", "@"]
@@ -6406,12 +6471,12 @@ selector: "collectionWithDuplicates",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return $globals.HashedCollection._newFromPairs_(["b",(1),"a",(2),"c",(3),"d",(-4),"e",(1),"f",(2),"g",(10)]);
+return $globals.HashedCollection._newFromPairs_(["b",(1),"a",(2),"c",(3),"d",(-4),"e",(1),"f",(2),"g",(10),"h",(0)]);
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithDuplicates\x0a\x09^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'e' -> 1. 'f' -> 2. 'g' -> 10 }",
+source: "collectionWithDuplicates\x0a\x09^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'e' -> 1. 'f' -> 2. 'g' -> 10. 'h' -> 0 }",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -7312,12 +7377,12 @@ selector: "collectionWithDuplicates",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return ["a", "b", "c", (1), (2), (1), "a"];
+return ["a", "b", "c", (1), (2), (1), "a", []];
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithDuplicates\x0a\x09^ #('a' 'b' 'c' 1 2 1 'a')",
+source: "collectionWithDuplicates\x0a\x09^ #('a' 'b' 'c' 1 2 1 'a' ())",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -7891,12 +7956,12 @@ selector: "collectionWithDuplicates",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return "abbaerte";
+return "abbaerten";
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithDuplicates\x0a\x09^ 'abbaerte'",
+source: "collectionWithDuplicates\x0a\x09^ 'abbaerten'",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -8941,6 +9006,10 @@ $recv($1)._add_((3).__at((3)));
 $ctx1.sendIdx["add:"]=3;
 //>>excludeEnd("ctx");
 $recv($1)._add_(false);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["add:"]=4;
+//>>excludeEnd("ctx");
+$recv($1)._add_(self["@sampleBlock"]);
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collection",{},$globals.SetTest)});
@@ -8948,7 +9017,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collection\x0a\x09^ Set new\x0a\x09\x09add: Smalltalk;\x0a\x09\x09add: nil;\x0a\x09\x09add: 3@3;\x0a\x09\x09add: false;\x0a\x09\x09yourself",
+source: "collection\x0a\x09^ Set new\x0a\x09\x09add: Smalltalk;\x0a\x09\x09add: nil;\x0a\x09\x09add: 3@3;\x0a\x09\x09add: false;\x0a\x09\x09add: sampleBlock;\x0a\x09\x09yourself",
 referencedClasses: ["Set", "Smalltalk"],
 //>>excludeEnd("ide");
 messageSends: ["add:", "new", "@", "yourself"]
@@ -8980,6 +9049,10 @@ $recv($1)._add_("3@3");
 $ctx1.sendIdx["add:"]=3;
 //>>excludeEnd("ctx");
 $recv($1)._add_("false");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["add:"]=4;
+//>>excludeEnd("ctx");
+$recv($1)._add_("a BlockClosure");
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collectionOfPrintStrings",{},$globals.SetTest)});
@@ -8987,7 +9060,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionOfPrintStrings\x0a\x09^ Set new\x0a\x09\x09add: 'a SmalltalkImage';\x0a\x09\x09add: 'nil';\x0a\x09\x09add: '3@3';\x0a\x09\x09add: 'false';\x0a\x09\x09yourself",
+source: "collectionOfPrintStrings\x0a\x09^ Set new\x0a\x09\x09add: 'a SmalltalkImage';\x0a\x09\x09add: 'nil';\x0a\x09\x09add: '3@3';\x0a\x09\x09add: 'false';\x0a\x09\x09add: 'a BlockClosure';\x0a\x09\x09yourself",
 referencedClasses: ["Set"],
 //>>excludeEnd("ide");
 messageSends: ["add:", "new", "yourself"]
@@ -9000,12 +9073,12 @@ selector: "collectionSize",
 protocol: 'fixture',
 fn: function (){
 var self=this;
-return (4);
+return (5);
 
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionSize\x0a\x09^ 4",
+source: "collectionSize\x0a\x09^ 5",
 referencedClasses: [],
 //>>excludeEnd("ide");
 messageSends: []
@@ -9068,6 +9141,10 @@ $recv($1)._add_("N");
 $ctx1.sendIdx["add:"]=4;
 //>>excludeEnd("ctx");
 $recv($1)._add_(false);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["add:"]=5;
+//>>excludeEnd("ctx");
+$recv($1)._add_(self["@sampleBlock"]);
 return $recv($1)._yourself();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"collectionWithNewValue",{},$globals.SetTest)});
@@ -9075,7 +9152,7 @@ return $recv($1)._yourself();
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "collectionWithNewValue\x0a\x09^ Set new\x0a\x09\x09add: Smalltalk;\x0a\x09\x09add: nil;\x0a\x09\x09add: 3@3;\x0a\x09\x09add: 'N';\x0a\x09\x09add: false;\x0a\x09\x09yourself",
+source: "collectionWithNewValue\x0a\x09^ Set new\x0a\x09\x09add: Smalltalk;\x0a\x09\x09add: nil;\x0a\x09\x09add: 3@3;\x0a\x09\x09add: 'N';\x0a\x09\x09add: false;\x0a\x09\x09add: sampleBlock;\x0a\x09\x09yourself",
 referencedClasses: ["Set", "Smalltalk"],
 //>>excludeEnd("ide");
 messageSends: ["add:", "new", "@", "yourself"]

+ 28 - 10
src/Kernel-Tests.st

@@ -470,7 +470,7 @@ testSetJavaScriptConstructor
 ! !
 
 TestCase subclass: #CollectionTest
-	instanceVariableNames: ''
+	instanceVariableNames: 'sampleBlock'
 	package: 'Kernel-Tests'!
 
 !CollectionTest methodsFor: 'convenience'!
@@ -539,6 +539,14 @@ sampleNewValueAsCollection
 	^ self collectionClass with: self sampleNewValue
 ! !
 
+!CollectionTest methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+
+	sampleBlock := []
+! !
+
 !CollectionTest methodsFor: 'testing'!
 
 isCollectionReadOnly
@@ -591,7 +599,7 @@ testAsSet
 	| c set |
 	c := self collectionWithDuplicates.
 	set := c asSet.
-	self assert: set size equals: 5.
+	self assert: set size equals: 6.
 	c do: [ :each |
 		self assert: (set includes: each) ]
 !
@@ -878,6 +886,8 @@ collectionValues
 
 nonIndexesDo: aBlock
 	aBlock value: 5.
+	aBlock value: [].
+	aBlock value: Object new.
 	aBlock value: 'z'
 !
 
@@ -992,11 +1002,12 @@ collection
 		at: 'a' put: 2;
 		at: true put: 3;
 		at: 1@3 put: -4;
+		at: sampleBlock put: 9;
 		yourself
 !
 
 collectionKeys
-	^ {1. 'a'. true. 1@3}
+	^ {1. 'a'. true. 1@3. sampleBlock}
 !
 
 collectionOfPrintStrings
@@ -1005,15 +1016,16 @@ collectionOfPrintStrings
 		at: 'a' put: '2';
 		at: true put: '3';
 		at: 1@3 put: '-4';
+		at: sampleBlock put: '9';
 		yourself
 !
 
 collectionSize
-	^ 4
+	^ 5
 !
 
 collectionValues
-	^ {1. 2. 3. -4}
+	^ {1. 2. 3. -4. 9}
 !
 
 collectionWithDuplicates
@@ -1022,6 +1034,7 @@ collectionWithDuplicates
 		at: 'a' put: 2;
 		at: true put: 3;
 		at: 4 put: -4;
+		at: sampleBlock put: 9;
 		at: 'b' put: 1;
 		at: 3 put: 3;
 		at: false put: 12;
@@ -1034,6 +1047,7 @@ collectionWithNewValue
 		at: 'a' put: 2;
 		at: true put: 3;
 		at: 1@3 put: -4;
+		at: sampleBlock put: 9;
 		at: 'new' put: 'N';
 		yourself
 !
@@ -1047,7 +1061,8 @@ sampleNewValueAsCollection
 samplesDo: aBlock
 	super samplesDo: aBlock.
 	aBlock value: true value: 3.
-	aBlock value: 1@3 value: -4
+	aBlock value: 1@3 value: -4.
+	aBlock value: sampleBlock value: 9
 ! !
 
 !DictionaryTest methodsFor: 'tests'!
@@ -1112,7 +1127,7 @@ collectionValues
 !
 
 collectionWithDuplicates
-	^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'e' -> 1. 'f' -> 2. 'g' -> 10 }
+	^ #{ 'b' -> 1. 'a' -> 2. 'c' -> 3. 'd' -> -4. 'e' -> 1. 'f' -> 2. 'g' -> 10. 'h' -> 0 }
 !
 
 collectionWithNewValue
@@ -1291,7 +1306,7 @@ collectionSize
 !
 
 collectionWithDuplicates
-	^ #('a' 'b' 'c' 1 2 1 'a')
+	^ #('a' 'b' 'c' 1 2 1 'a' ())
 !
 
 collectionWithNewValue
@@ -1422,7 +1437,7 @@ collectionSize
 !
 
 collectionWithDuplicates
-	^ 'abbaerte'
+	^ 'abbaerten'
 !
 
 collectionWithNewValue
@@ -1621,6 +1636,7 @@ collection
 		add: nil;
 		add: 3@3;
 		add: false;
+		add: sampleBlock;
 		yourself
 !
 
@@ -1630,11 +1646,12 @@ collectionOfPrintStrings
 		add: 'nil';
 		add: '3@3';
 		add: 'false';
+		add: 'a BlockClosure';
 		yourself
 !
 
 collectionSize
-	^ 4
+	^ 5
 !
 
 collectionWithDuplicates
@@ -1649,6 +1666,7 @@ collectionWithNewValue
 		add: 3@3;
 		add: 'N';
 		add: false;
+		add: sampleBlock;
 		yourself
 ! !
 

File diff suppressed because it is too large
+ 291 - 265
support/parser.js


+ 22 - 22
support/parser.pegjs

@@ -10,14 +10,14 @@ selector      = first:[a-zA-Z] others:[a-zA-Z0-9\:]* {return first + others.join
 className      = first:[A-Z] others:[a-zA-Z0-9]* {return first + others.join("");}
 string         = "'" val:(("''" {return "'";} / [^'])*) "'" {
                      return $globals.ValueNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._value_(val.join(""));
                  }
 character      = "$" char:. 
                   {
                       return $globals.ValueNode._new()
-                             ._position_((line()).__at(column()))
+                             ._location_(location())
                              ._source_(text())
                              ._value_(char);
                   }
@@ -25,13 +25,13 @@ symbol         = "#" rest:bareSymbol {return rest;}
 bareSymbol         = val:(selector / binarySelector / node:string {return node._value();})
                   {
                       return $globals.ValueNode._new()
-                             ._position_((line()).__at(column()))
+                             ._location_(location())
                              ._source_(text())
                              ._value_(val);
                   }
 number         = n:(numberExp / hex / float / integer) {
                      return $globals.ValueNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._value_(n);
                  }
@@ -42,12 +42,12 @@ integer        = neg:"-"? digits:[0-9]+ {return (parseInt((neg || '') + digits.j
 
 literalArray   = "#(" rest:wsLiteralArrayContents ws ")" {
     return rest
-        ._position_((line()).__at(column()))
+        ._location_(location())
         ._source_(text());
 }
 bareLiteralArray   = "(" rest:wsLiteralArrayContents ws ")" {
     return rest
-        ._position_((line()).__at(column()))
+        ._location_(location())
         ._source_(text());
 }
 
@@ -58,13 +58,13 @@ wsLiteralArrayContents   = lits:(ws lit:literalArrayElement {return lit._value()
                  }
 dynamicArray   = "{" ws expressions:expressions? maybeDotsWs "}" {
                      return $globals.DynamicArrayNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._nodes_(expressions || []);
                  }
 dynamicDictionary = "#{" ws expressions:associations? maybeDotsWs  "}" {
                         return $globals.DynamicDictionaryNode._new()
-                               ._position_((line()).__at(column()))
+                               ._location_(location())
                                ._source_(text())
                                ._nodes_(expressions || []);
                     }
@@ -73,7 +73,7 @@ pseudoVariable = val:(
                  / 'false' {return false;}
                  / 'nil' {return nil;}) {
                        return $globals.ValueNode._new()
-                              ._position_((line()).__at(column()))
+                              ._location_(location())
                               ._source_(text())
                               ._value_(val);
                    }
@@ -84,7 +84,7 @@ literal        = runtimeLiteral / parseTimeLiteral
 
 variable       = identifier:identifier {
                      return $globals.VariableNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._value_(identifier);
                  }
@@ -113,7 +113,7 @@ expressions    = first:expression others:wsExpressionsRest* { return [first].con
 
 assignment     = variable:variable ws ':=' ws expression:expression {
                      return $globals.AssignmentNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._left_(variable)
                             ._right_(expression);
@@ -121,7 +121,7 @@ assignment     = variable:variable ws ':=' ws expression:expression {
 
 ret            = '^' ws expression:expression {
                      return $globals.ReturnNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._nodes_([expression]);
                  }
@@ -146,7 +146,7 @@ wsSequenceWs       = (ws js:jsSequence ws { return js; }) / wsStSequenceWs
 
 wsStSequenceWs    = ws temps:temps? maybeDotsWs statements:statementsWs? {
                      return $globals.SequenceNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._temps_(temps || [])
                             ._nodes_(statements || []);
@@ -156,7 +156,7 @@ jsSequence     = jsStatement
 
 block          = '[' params:wsBlockParamList? sequence:wsSequenceWs? ']' {
                      return $globals.BlockNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._parameters_(params || [])
                             ._nodes_([sequence._asBlockSequenceNode()]);
@@ -168,12 +168,12 @@ augment = "(" send:(wsBinaryTail / wsKeywordMessage / wsUnaryTail) messages:(ws
                      if (messages.length) {
                          messages.unshift(send);
                          send = $globals.CascadeNode._new()
-                                ._position_((line()).__at(column()))
+                                ._location_(location())
                                 ._source_(text())
                                 ._nodes_(messages);
 					 }
 					 return $globals.BranchSendNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._nodes_([send]);
                  }
@@ -198,7 +198,7 @@ augmentedOperand = operand:operand tail:wsAugmentTail? {
 
 wsUnaryMessage   = ws selector:unarySelector !":" {
                      return $globals.SendNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._selector_(selector);
                  }
@@ -223,7 +223,7 @@ unarySend      = receiver:augmentedOperand tail:wsUnaryTail? {
 
 wsBinaryMessage  = ws selector:binarySelector ws arg:unarySend {
                      return $globals.SendNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._selector_(selector)
                             ._arguments_([arg]);
@@ -256,7 +256,7 @@ wsKeywordMessage = pairs:(ws key:keyword ws arg:binarySend {return {key:key, arg
                           args.push(pairs[i].arg);
                       }
                       return $globals.SendNode._new()
-                             ._position_((line()).__at(column()))
+                             ._location_(location())
                              ._source_(text())
                              ._selector_(selector)
                              ._arguments_(args);
@@ -276,21 +276,21 @@ wsMessage        = wsBinaryMessage / wsUnaryMessage / wsKeywordMessage
 cascade        = send:keywordSend & { return send._isSendNode(); } messages:(ws ";" mess:wsMessage {return mess;})+ {
                      messages.unshift(send);
                      return $globals.CascadeNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(text())
                             ._nodes_(messages);
                  }
 
 jsStatement    = "<" val:((">>" {return ">";} / [^>])*) ">" {
                      return $globals.JSStatementNode._new()
-                            ._position_((line()).__at(column()))
+                            ._location_(location())
                             ._source_(val.join(""))
                  }
 
 
 method         = pattern:(wsKeywordPattern / wsBinaryPattern / wsUnaryPattern) sequence:wsSequenceWs? {
                       return $globals.MethodNode._new()
-                             ._position_((line()).__at(column()))
+                             ._location_(location())
                              ._source_(text())
                              ._selector_(pattern[0])
                              ._arguments_(pattern[1])

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