Browse Source

Merge branch 'master' into grunt

Nicolas Petton 12 years ago
parent
commit
0d3285b38b

+ 222 - 0
js/Canvas.deploy.js

@@ -377,6 +377,24 @@ return $1;
 }),
 smalltalk.HTMLCanvas);
 
+smalltalk.addMethod(
+"_entity_",
+smalltalk.method({
+selector: "entity:",
+fn: function (aString){
+var self=this;
+var result;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+result=_st(_st(_st("<span />")._asJQuery())._html_(_st(_st("&").__comma(aString)).__comma(";")))._text();
+$1=_st(_st(result)._size()).__eq((1));
+if(! smalltalk.assert($1)){
+_st(self)._error_(_st("Not an HTML entity: ").__comma(aString));
+};
+_st(self)._with_(result);
+return self}, function($ctx1) {$ctx1.fill(self,"entity:",{aString:aString,result:result}, smalltalk.HTMLCanvas)})}
+}),
+smalltalk.HTMLCanvas);
+
 smalltalk.addMethod(
 "_fieldset",
 smalltalk.method({
@@ -1133,6 +1151,28 @@ return $1;
 }),
 smalltalk.HTMLCanvas);
 
+smalltalk.addMethod(
+"_snippet_",
+smalltalk.method({
+selector: "snippet:",
+fn: function (anElement){
+var self=this;
+var clone,caret;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
+clone=_st(_st(anElement)._asJQuery())._clone();
+_st(self)._with_(_st((smalltalk.TagBrush || TagBrush))._fromJQuery_canvas_(clone,self));
+caret=_st(clone)._find_("[data-snippet=\x22*\x22]");
+$1=_st(_st(caret)._toArray())._isEmpty();
+if(smalltalk.assert($1)){
+caret=clone;
+caret;
+};
+$2=_st((smalltalk.TagBrush || TagBrush))._fromJQuery_canvas_(_st(caret)._removeAttr_("data-snippet"),self);
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"snippet:",{anElement:anElement,clone:clone,caret:caret}, smalltalk.HTMLCanvas)})}
+}),
+smalltalk.HTMLCanvas);
+
 smalltalk.addMethod(
 "_source",
 smalltalk.method({
@@ -1545,6 +1585,175 @@ return $1;
 smalltalk.HTMLCanvas.klass);
 
 
+smalltalk.addClass('HTMLSnippet', smalltalk.Object, ['snippets'], 'Canvas');
+smalltalk.addMethod(
+"_initializeFromJQuery_",
+smalltalk.method({
+selector: "initializeFromJQuery:",
+fn: function (aJQuery){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st(self)._snippetsFromJQuery_(aJQuery))._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._installSnippetFromJQuery_(_st(each)._asJQuery());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"initializeFromJQuery:",{aJQuery:aJQuery}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_installSnippetFromJQuery_",
+smalltalk.method({
+selector: "installSnippetFromJQuery:",
+fn: function (element){
+var self=this;
+var name;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
+name=_st(element)._attr_("data-snippet");
+$1=_st(name).__eq("*");
+if(! smalltalk.assert($1)){
+$2=_st(_st("^\x5c*")._asRegexp())._test_(name);
+if(smalltalk.assert($2)){
+name=_st(name)._allButFirst();
+name;
+_st(element)._attr_put_("data-snippet","*");
+} else {
+_st(element)._removeAttr_("data-snippet");
+};
+_st(self)._snippetAt_install_(name,_st(_st(element)._detach())._get_((0)));
+};
+return self}, function($ctx1) {$ctx1.fill(self,"installSnippetFromJQuery:",{element:element,name:name}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_",
+smalltalk.method({
+selector: "snippetAt:",
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._snippets())._at_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippetAt:",{aString:aString}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_compile_",
+smalltalk.method({
+selector: "snippetAt:compile:",
+fn: function (aString,anElement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(_st(_st((function(htmlReceiver){
+return smalltalk.withContext(function($ctx2) {
return _st(htmlReceiver)._snippet_(anElement);
+}, function($ctx2) {$ctx2.fillBlock({htmlReceiver:htmlReceiver},$ctx1)})}))._currySelf())._asCompiledMethod_(aString),(smalltalk.HTMLCanvas || HTMLCanvas),"**snippets");
+return self}, function($ctx1) {$ctx1.fill(self,"snippetAt:compile:",{aString:aString,anElement:anElement}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_install_",
+smalltalk.method({
+selector: "snippetAt:install:",
+fn: function (aString,anElement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st(self)._snippets())._at_put_(aString,anElement);
+_st(self)._snippetAt_compile_(aString,anElement);
+return self}, function($ctx1) {$ctx1.fill(self,"snippetAt:install:",{aString:aString,anElement:anElement}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippets",
+smalltalk.method({
+selector: "snippets",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@snippets"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@snippets"]=smalltalk.HashedCollection._fromPairs_([]);
+$1=self["@snippets"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippets",{}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetsFromJQuery_",
+smalltalk.method({
+selector: "snippetsFromJQuery:",
+fn: function (aJQuery){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(aJQuery)._find_("[data-snippet]"))._toArray();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippetsFromJQuery:",{aJQuery:aJQuery}, smalltalk.HTMLSnippet)})}
+}),
+smalltalk.HTMLSnippet);
+
+
+smalltalk.HTMLSnippet.klass.iVarNames = ['current'];
+smalltalk.addMethod(
+"_current",
+smalltalk.method({
+selector: "current",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@current"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"current",{}, smalltalk.HTMLSnippet.klass)})}
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_ensureCurrent",
+smalltalk.method({
+selector: "ensureCurrent",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3;
+$1=self["@current"];
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=smalltalk.Object.klass.fn.prototype._new.apply(_st(self), []);
+_st($2)._initializeFromJQuery_(_st(document)._asJQuery());
+$3=_st($2)._yourself();
+self["@current"]=$3;
+self["@current"];
+} else {
+$1;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"ensureCurrent",{}, smalltalk.HTMLSnippet.klass)})}
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
smalltalk.Object.klass.fn.prototype._initialize.apply(_st(self), []);
+_st(self)._ensureCurrent();
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.HTMLSnippet.klass)})}
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_new",
+smalltalk.method({
+selector: "new",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._shouldNotImplement();
+return self}, function($ctx1) {$ctx1.fill(self,"new",{}, smalltalk.HTMLSnippet.klass)})}
+}),
+smalltalk.HTMLSnippet.klass);
+
+
 smalltalk.addClass('TagBrush', smalltalk.Object, ['canvas', 'element'], 'Canvas');
 smalltalk.addMethod(
 "_accesskey_",
@@ -2453,6 +2662,19 @@ return self}, function($ctx1) {$ctx1.fill(self,"appendToJQuery:",{aJQuery:aJQuer
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_asSnippet",
+smalltalk.method({
+selector: "asSnippet",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st((smalltalk.HTMLSnippet || HTMLSnippet))._current())._snippetAt_(_st(self)._asString());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSnippet",{}, smalltalk.CharacterArray)})}
+}),
+smalltalk.CharacterArray);
+
 smalltalk.addMethod(
 "_appendToBrush_",
 smalltalk.method({

+ 293 - 0
js/Canvas.js

@@ -522,6 +522,29 @@ referencedClasses: []
 }),
 smalltalk.HTMLCanvas);
 
+smalltalk.addMethod(
+"_entity_",
+smalltalk.method({
+selector: "entity:",
+category: 'adding',
+fn: function (aString){
+var self=this;
+var result;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+result=_st(_st(_st("<span />")._asJQuery())._html_(_st(_st("&").__comma(aString)).__comma(";")))._text();
+$1=_st(_st(result)._size()).__eq((1));
+if(! smalltalk.assert($1)){
+_st(self)._error_(_st("Not an HTML entity: ").__comma(aString));
+};
+_st(self)._with_(result);
+return self}, function($ctx1) {$ctx1.fill(self,"entity:",{aString:aString,result:result}, smalltalk.HTMLCanvas)})},
+args: ["aString"],
+source: "entity: aString\x0a\x09\x22Adds a character representing html entity, eg.\x0a    html entity: 'copy'\x0a    adds a copyright sign.\x0a    If a name does not represent valid HTML entity, error is raised.\x22\x0a\x09| result |\x0a    result := ('<span />' asJQuery html: '&', aString, ';') text.\x0a    result size = 1 ifFalse: [ self error: 'Not an HTML entity: ', aString ].\x0a    self with: result",
+messageSends: ["text", "html:", ",", "asJQuery", "ifFalse:", "error:", "=", "size", "with:"],
+referencedClasses: []
+}),
+smalltalk.HTMLCanvas);
+
 smalltalk.addMethod(
 "_fieldset",
 smalltalk.method({
@@ -1568,6 +1591,33 @@ referencedClasses: []
 }),
 smalltalk.HTMLCanvas);
 
+smalltalk.addMethod(
+"_snippet_",
+smalltalk.method({
+selector: "snippet:",
+category: 'accessing',
+fn: function (anElement){
+var self=this;
+var clone,caret;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
+clone=_st(_st(anElement)._asJQuery())._clone();
+_st(self)._with_(_st((smalltalk.TagBrush || TagBrush))._fromJQuery_canvas_(clone,self));
+caret=_st(clone)._find_("[data-snippet=\x22*\x22]");
+$1=_st(_st(caret)._toArray())._isEmpty();
+if(smalltalk.assert($1)){
+caret=clone;
+caret;
+};
+$2=_st((smalltalk.TagBrush || TagBrush))._fromJQuery_canvas_(_st(caret)._removeAttr_("data-snippet"),self);
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"snippet:",{anElement:anElement,clone:clone,caret:caret}, smalltalk.HTMLCanvas)})},
+args: ["anElement"],
+source: "snippet: anElement\x0a\x09\x22Adds clone of anElement, finds [data-snippet=\x22\x22*\x22\x22] subelement\x0a    and returns TagBrush as if that subelement was just added.\x0a    \x0a    Rarely needed to use directly, use `html foo` dynamically installed method\x0a    for a snippet named foo.\x22\x0a    \x0a    | clone caret |\x0a    \x0a    clone := anElement asJQuery clone.\x0a    self with: (TagBrush fromJQuery: clone canvas: self).\x0a    caret := clone find: '[data-snippet=\x22*\x22]'.\x0a    caret toArray isEmpty ifTrue: [ caret := clone ].\x0a    ^TagBrush fromJQuery: (caret removeAttr: 'data-snippet') canvas: self",
+messageSends: ["clone", "asJQuery", "with:", "fromJQuery:canvas:", "find:", "ifTrue:", "isEmpty", "toArray", "removeAttr:"],
+referencedClasses: ["TagBrush"]
+}),
+smalltalk.HTMLCanvas);
+
 smalltalk.addMethod(
 "_source",
 smalltalk.method({
@@ -2135,6 +2185,231 @@ referencedClasses: []
 smalltalk.HTMLCanvas.klass);
 
 
+smalltalk.addClass('HTMLSnippet', smalltalk.Object, ['snippets'], 'Canvas');
+smalltalk.HTMLSnippet.comment="HTMLSnippet instance is the registry of html snippets.\x0aHTMLSnippet current is the public singleton instance.\x0a\x0aAt the beginning, it scans the document for any html elements\x0awith 'data-snippet=\x22foo\x22' attribute and takes them off the document,\x0aremembering them in the store under the specified name.\x0aIt also install method #foo into HTMLCanvas dynamically.\x0a\x0aEvery html snippet should mark a 'caret', a place where contents\x0acan be inserted, by 'data-snippet=\x22*\x22' (a special name for caret).\x0aFor example:\x0a\x0a<li data-snippet='menuelement' class='...'><a data-snippet='*'></a></li>\x0a\x0adefines a list element with a link inside; the link itself is marked as a caret.\x0a\x0aYou can later issue\x0a\x0ahtml menuelement href: '/foo'; with: 'A foo'\x0a\x0ato insert the whole snippet and directly manipulate the caret, so it renders:\x0a\x0a<li class='...'><a href='/foo'>A foo</a></li>\x0a\x0aFor a self-careting tags (not very useful, but you do not need to fill class etc.\x0ayou can use\x0a\x0a<div class='lots of classes' attr1='one' attr2='two' data-snippet='*bar'></div>\x0a\x0aand in code later do:\x0a\x0ahtml bar with: [ xxx ]\x0a\x0ato render\x0a\x0a<div class='lots of classes' attr1='one' attr2='two'>...added by xxx...</div>\x0a"
+smalltalk.addMethod(
+"_initializeFromJQuery_",
+smalltalk.method({
+selector: "initializeFromJQuery:",
+category: 'initialization',
+fn: function (aJQuery){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st(self)._snippetsFromJQuery_(aJQuery))._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._installSnippetFromJQuery_(_st(each)._asJQuery());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"initializeFromJQuery:",{aJQuery:aJQuery}, smalltalk.HTMLSnippet)})},
+args: ["aJQuery"],
+source: "initializeFromJQuery: aJQuery\x0a\x09\x22Finds and takes out all snippets out of aJQuery.\x0a    Installs it into self.\x22\x0a    \x0a\x09(self snippetsFromJQuery: aJQuery) do: [ :each |\x0a    \x09self installSnippetFromJQuery: each asJQuery ]",
+messageSends: ["do:", "installSnippetFromJQuery:", "asJQuery", "snippetsFromJQuery:"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_installSnippetFromJQuery_",
+smalltalk.method({
+selector: "installSnippetFromJQuery:",
+category: 'snippet installation',
+fn: function (element){
+var self=this;
+var name;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
+name=_st(element)._attr_("data-snippet");
+$1=_st(name).__eq("*");
+if(! smalltalk.assert($1)){
+$2=_st(_st("^\x5c*")._asRegexp())._test_(name);
+if(smalltalk.assert($2)){
+name=_st(name)._allButFirst();
+name;
+_st(element)._attr_put_("data-snippet","*");
+} else {
+_st(element)._removeAttr_("data-snippet");
+};
+_st(self)._snippetAt_install_(name,_st(_st(element)._detach())._get_((0)));
+};
+return self}, function($ctx1) {$ctx1.fill(self,"installSnippetFromJQuery:",{element:element,name:name}, smalltalk.HTMLSnippet)})},
+args: ["element"],
+source: "installSnippetFromJQuery: element\x0a\x09| name |\x0a    name := element attr: 'data-snippet'.\x0a    name = '*' ifFalse: [\x0a    \x09('^\x5c*' asRegexp test: name) \x0a            ifTrue: [ \x0a            \x09name := name allButFirst. \x0a                element attr: 'data-snippet' put: '*' ]\x0a          \x09ifFalse: [ \x0a            \x09element removeAttr: 'data-snippet' ].\x0a        self snippetAt: name install: (element detach get: 0) ]",
+messageSends: ["attr:", "ifFalse:", "ifTrue:ifFalse:", "allButFirst", "attr:put:", "removeAttr:", "test:", "asRegexp", "snippetAt:install:", "get:", "detach", "="],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_",
+smalltalk.method({
+selector: "snippetAt:",
+category: 'accessing',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._snippets())._at_(aString);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippetAt:",{aString:aString}, smalltalk.HTMLSnippet)})},
+args: ["aString"],
+source: "snippetAt: aString\x0a\x09^ self snippets at: aString",
+messageSends: ["at:", "snippets"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_compile_",
+smalltalk.method({
+selector: "snippetAt:compile:",
+category: 'method generation',
+fn: function (aString,anElement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(_st(_st((function(htmlReceiver){
+return smalltalk.withContext(function($ctx2) {
return _st(htmlReceiver)._snippet_(anElement);
+}, function($ctx2) {$ctx2.fillBlock({htmlReceiver:htmlReceiver},$ctx1)})}))._currySelf())._asCompiledMethod_(aString),(smalltalk.HTMLCanvas || HTMLCanvas),"**snippets");
+return self}, function($ctx1) {$ctx1.fill(self,"snippetAt:compile:",{aString:aString,anElement:anElement}, smalltalk.HTMLSnippet)})},
+args: ["aString", "anElement"],
+source: "snippetAt: aString compile: anElement\x0a\x09\x22Method generation for the snippet.\x0a    The selector is aString, the method block uses anElement\x22\x0a    \x0a    ClassBuilder new\x0a    \x09installMethod: ([ :htmlReceiver | htmlReceiver snippet: anElement ] \x0a        \x09currySelf asCompiledMethod: aString)\x0a        forClass: HTMLCanvas\x0a        category: '**snippets'",
+messageSends: ["installMethod:forClass:category:", "asCompiledMethod:", "currySelf", "snippet:", "new"],
+referencedClasses: ["HTMLCanvas", "ClassBuilder"]
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetAt_install_",
+smalltalk.method({
+selector: "snippetAt:install:",
+category: 'snippet installation',
+fn: function (aString,anElement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st(self)._snippets())._at_put_(aString,anElement);
+_st(self)._snippetAt_compile_(aString,anElement);
+return self}, function($ctx1) {$ctx1.fill(self,"snippetAt:install:",{aString:aString,anElement:anElement}, smalltalk.HTMLSnippet)})},
+args: ["aString", "anElement"],
+source: "snippetAt: aString install: anElement\x0a\x09self snippets at: aString put: anElement.\x0a    self snippetAt: aString compile: anElement",
+messageSends: ["at:put:", "snippets", "snippetAt:compile:"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippets",
+smalltalk.method({
+selector: "snippets",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@snippets"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@snippets"]=smalltalk.HashedCollection._fromPairs_([]);
+$1=self["@snippets"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippets",{}, smalltalk.HTMLSnippet)})},
+args: [],
+source: "snippets\x0a\x09^snippets ifNil: [ snippets := #{} ]\x0a",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+smalltalk.addMethod(
+"_snippetsFromJQuery_",
+smalltalk.method({
+selector: "snippetsFromJQuery:",
+category: 'private',
+fn: function (aJQuery){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(aJQuery)._find_("[data-snippet]"))._toArray();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"snippetsFromJQuery:",{aJQuery:aJQuery}, smalltalk.HTMLSnippet)})},
+args: ["aJQuery"],
+source: "snippetsFromJQuery: aJQuery\x0a\x09^ (aJQuery find: '[data-snippet]') toArray",
+messageSends: ["toArray", "find:"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet);
+
+
+smalltalk.HTMLSnippet.klass.iVarNames = ['current'];
+smalltalk.addMethod(
+"_current",
+smalltalk.method({
+selector: "current",
+category: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@current"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"current",{}, smalltalk.HTMLSnippet.klass)})},
+args: [],
+source: "current\x0a\x09^ current",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_ensureCurrent",
+smalltalk.method({
+selector: "ensureCurrent",
+category: 'initialization',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3;
+$1=self["@current"];
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=smalltalk.Object.klass.fn.prototype._new.apply(_st(self), []);
+_st($2)._initializeFromJQuery_(_st(document)._asJQuery());
+$3=_st($2)._yourself();
+self["@current"]=$3;
+self["@current"];
+} else {
+$1;
+};
+return self}, function($ctx1) {$ctx1.fill(self,"ensureCurrent",{}, smalltalk.HTMLSnippet.klass)})},
+args: [],
+source: "ensureCurrent\x0a\x09current ifNil: [ \x0a    \x09current := super new\x0a\x09\x09\x09initializeFromJQuery: document asJQuery;\x0a\x09\x09\x09yourself ]",
+messageSends: ["ifNil:", "initializeFromJQuery:", "asJQuery", "new", "yourself"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
smalltalk.Object.klass.fn.prototype._initialize.apply(_st(self), []);
+_st(self)._ensureCurrent();
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.HTMLSnippet.klass)})},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09self ensureCurrent",
+messageSends: ["initialize", "ensureCurrent"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet.klass);
+
+smalltalk.addMethod(
+"_new",
+smalltalk.method({
+selector: "new",
+category: 'instance creation',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._shouldNotImplement();
+return self}, function($ctx1) {$ctx1.fill(self,"new",{}, smalltalk.HTMLSnippet.klass)})},
+args: [],
+source: "new\x0a\x09self shouldNotImplement",
+messageSends: ["shouldNotImplement"],
+referencedClasses: []
+}),
+smalltalk.HTMLSnippet.klass);
+
+
 smalltalk.addClass('TagBrush', smalltalk.Object, ['canvas', 'element'], 'Canvas');
 smalltalk.addMethod(
 "_accesskey_",
@@ -3434,6 +3709,24 @@ referencedClasses: ["HTMLCanvas"]
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_asSnippet",
+smalltalk.method({
+selector: "asSnippet",
+category: '*Canvas',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st((smalltalk.HTMLSnippet || HTMLSnippet))._current())._snippetAt_(_st(self)._asString());
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSnippet",{}, smalltalk.CharacterArray)})},
+args: [],
+source: "asSnippet\x0a\x09^ HTMLSnippet current snippetAt: self asString",
+messageSends: ["snippetAt:", "asString", "current"],
+referencedClasses: ["HTMLSnippet"]
+}),
+smalltalk.CharacterArray);
+
 smalltalk.addMethod(
 "_appendToBrush_",
 smalltalk.method({

+ 15 - 0
js/Compiler-AST.deploy.js

@@ -420,6 +420,21 @@ return self}, function($ctx1) {$ctx1.fill(self,"scope:",{aLexicalScope:aLexicalS
 }),
 smalltalk.BlockNode);
 
+smalltalk.addMethod(
+"_subtreeNeedsAliasing",
+smalltalk.method({
+selector: "subtreeNeedsAliasing",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._shouldBeAliased())._or_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._shouldBeInlined();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"subtreeNeedsAliasing",{}, smalltalk.BlockNode)})}
+}),
+smalltalk.BlockNode);
+
 
 
 smalltalk.addClass('CascadeNode', smalltalk.Node, ['receiver'], 'Compiler-AST');

+ 20 - 0
js/Compiler-AST.js

@@ -581,6 +581,26 @@ referencedClasses: []
 }),
 smalltalk.BlockNode);
 
+smalltalk.addMethod(
+"_subtreeNeedsAliasing",
+smalltalk.method({
+selector: "subtreeNeedsAliasing",
+category: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._shouldBeAliased())._or_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._shouldBeInlined();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"subtreeNeedsAliasing",{}, smalltalk.BlockNode)})},
+args: [],
+source: "subtreeNeedsAliasing\x0a    ^ self shouldBeAliased or: [ self shouldBeInlined ]",
+messageSends: ["or:", "shouldBeInlined", "shouldBeAliased"],
+referencedClasses: []
+}),
+smalltalk.BlockNode);
+
 
 
 smalltalk.addClass('CascadeNode', smalltalk.Node, ['receiver'], 'Compiler-AST');

+ 2 - 19
js/Compiler-Core.deploy.js

@@ -150,15 +150,10 @@ smalltalk.method({
 selector: "install:forClass:category:",
 fn: function (aString,aBehavior,anotherString){
 var self=this;
-var compiled;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-compiled=_st(self)._eval_(_st(self)._compile_forClass_(aString,aBehavior));
-_st(compiled)._category_(anotherString);
-_st(aBehavior)._addCompiledMethod_(compiled);
-_st(self)._setupClass_(aBehavior);
-$1=compiled;
+$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(_st(self)._eval_(_st(self)._compile_forClass_(aString,aBehavior)),aBehavior,anotherString);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"install:forClass:category:",{aString:aString,aBehavior:aBehavior,anotherString:anotherString,compiled:compiled}, smalltalk.Compiler)})}
+}, function($ctx1) {$ctx1.fill(self,"install:forClass:category:",{aString:aString,aBehavior:aBehavior,anotherString:anotherString}, smalltalk.Compiler)})}
 }),
 smalltalk.Compiler);
 
@@ -199,7 +194,6 @@ _st(_st(aClass)._methodDictionary())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
_st(console)._log_(_st(_st(_st(aClass)._name()).__comma(" >> ")).__comma(_st(each)._selector()));
 return _st(self)._install_forClass_category_(_st(each)._source(),aClass,_st(each)._category());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(aClass);
 $1=_st(aClass)._isMetaclass();
 if(! smalltalk.assert($1)){
 _st(self)._recompile_(_st(aClass)._class());
@@ -228,17 +222,6 @@ return self}, function($ctx1) {$ctx1.fill(self,"recompileAll",{}, smalltalk.Comp
 }),
 smalltalk.Compiler);
 
-smalltalk.addMethod(
-"_setupClass_",
-smalltalk.method({
-selector: "setupClass:",
-fn: function (aClass){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
smalltalk.init(aClass);
-return self}, function($ctx1) {$ctx1.fill(self,"setupClass:",{aClass:aClass}, smalltalk.Compiler)})}
-}),
-smalltalk.Compiler);
-
 smalltalk.addMethod(
 "_source",
 smalltalk.method({

+ 7 - 29
js/Compiler-Core.js

@@ -202,19 +202,14 @@ selector: "install:forClass:category:",
 category: 'compiling',
 fn: function (aString,aBehavior,anotherString){
 var self=this;
-var compiled;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-compiled=_st(self)._eval_(_st(self)._compile_forClass_(aString,aBehavior));
-_st(compiled)._category_(anotherString);
-_st(aBehavior)._addCompiledMethod_(compiled);
-_st(self)._setupClass_(aBehavior);
-$1=compiled;
+$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(_st(self)._eval_(_st(self)._compile_forClass_(aString,aBehavior)),aBehavior,anotherString);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"install:forClass:category:",{aString:aString,aBehavior:aBehavior,anotherString:anotherString,compiled:compiled}, smalltalk.Compiler)})},
+}, function($ctx1) {$ctx1.fill(self,"install:forClass:category:",{aString:aString,aBehavior:aBehavior,anotherString:anotherString}, smalltalk.Compiler)})},
 args: ["aString", "aBehavior", "anotherString"],
-source: "install: aString forClass: aBehavior category: anotherString\x0a\x09| compiled |\x0a\x09compiled := self eval: (self compile: aString forClass: aBehavior).\x0a\x09compiled category: anotherString.\x0a\x09aBehavior addCompiledMethod: compiled.\x0a    self setupClass: aBehavior.\x0a\x09^compiled",
-messageSends: ["eval:", "compile:forClass:", "category:", "addCompiledMethod:", "setupClass:"],
-referencedClasses: []
+source: "install: aString forClass: aBehavior category: anotherString\x0a   \x09^ ClassBuilder new\x0a    \x09installMethod: (self eval: (self compile: aString forClass: aBehavior))\x0a        forClass: aBehavior\x0a        category: anotherString",
+messageSends: ["installMethod:forClass:category:", "eval:", "compile:forClass:", "new"],
+referencedClasses: ["ClassBuilder"]
 }),
 smalltalk.Compiler);
 
@@ -266,15 +261,14 @@ _st(_st(aClass)._methodDictionary())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
_st(console)._log_(_st(_st(_st(aClass)._name()).__comma(" >> ")).__comma(_st(each)._selector()));
 return _st(self)._install_forClass_category_(_st(each)._source(),aClass,_st(each)._category());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(aClass);
 $1=_st(aClass)._isMetaclass();
 if(! smalltalk.assert($1)){
 _st(self)._recompile_(_st(aClass)._class());
 };
 return self}, function($ctx1) {$ctx1.fill(self,"recompile:",{aClass:aClass}, smalltalk.Compiler)})},
 args: ["aClass"],
-source: "recompile: aClass\x0a\x09aClass methodDictionary do: [:each |\x0a\x09\x09console log: aClass name, ' >> ', each selector.\x0a\x09\x09self install: each source forClass: aClass category: each category].\x0a\x09self setupClass: aClass.\x0a\x09aClass isMetaclass ifFalse: [self recompile: aClass class]",
-messageSends: ["do:", "log:", ",", "selector", "name", "install:forClass:category:", "source", "category", "methodDictionary", "setupClass:", "ifFalse:", "recompile:", "class", "isMetaclass"],
+source: "recompile: aClass\x0a\x09aClass methodDictionary do: [:each |\x0a\x09\x09console log: aClass name, ' >> ', each selector.\x0a\x09\x09self install: each source forClass: aClass category: each category].\x0a\x09\x22self setupClass: aClass.\x22\x0a\x09aClass isMetaclass ifFalse: [self recompile: aClass class]",
+messageSends: ["do:", "log:", ",", "selector", "name", "install:forClass:category:", "source", "category", "methodDictionary", "ifFalse:", "recompile:", "class", "isMetaclass"],
 referencedClasses: []
 }),
 smalltalk.Compiler);
@@ -304,22 +298,6 @@ referencedClasses: ["Transcript", "Smalltalk"]
 }),
 smalltalk.Compiler);
 
-smalltalk.addMethod(
-"_setupClass_",
-smalltalk.method({
-selector: "setupClass:",
-category: 'compiling',
-fn: function (aClass){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
smalltalk.init(aClass);
-return self}, function($ctx1) {$ctx1.fill(self,"setupClass:",{aClass:aClass}, smalltalk.Compiler)})},
-args: ["aClass"],
-source: "setupClass: aClass\x0a\x09<smalltalk.init(aClass)>",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Compiler);
-
 smalltalk.addMethod(
 "_source",
 smalltalk.method({

+ 732 - 122
js/Compiler-Interpreter.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Interpreter', {});
-smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'pc', 'locals', 'receiver', 'selector'], 'Compiler-Interpreter');
+smalltalk.addClass('AIContext', smalltalk.NodeVisitor, ['outerContext', 'pc', 'locals', 'method'], 'Compiler-Interpreter');
 smalltalk.addMethod(
 "_initializeFromMethodContext_",
 smalltalk.method({
@@ -9,7 +9,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 _st(self)._pc_(_st(aMethodContext)._pc());
 _st(self)._receiver_(_st(aMethodContext)._receiver());
-_st(self)._selector_(_st(aMethodContext)._selector());
+_st(self)._method_(_st(aMethodContext)._method());
 $1=_st(aMethodContext)._outerContext();
 if(($receiver = $1) == nil || $receiver == undefined){
 $1;
@@ -68,6 +68,30 @@ return $1;
 }),
 smalltalk.AIContext);
 
+smalltalk.addMethod(
+"_method",
+smalltalk.method({
+selector: "method",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@method"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"method",{}, smalltalk.AIContext)})}
+}),
+smalltalk.AIContext);
+
+smalltalk.addMethod(
+"_method_",
+smalltalk.method({
+selector: "method:",
+fn: function (aCompiledMethod){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@method"]=aCompiledMethod;
+return self}, function($ctx1) {$ctx1.fill(self,"method:",{aCompiledMethod:aCompiledMethod}, smalltalk.AIContext)})}
+}),
+smalltalk.AIContext);
+
 smalltalk.addMethod(
 "_outerContext",
 smalltalk.method({
@@ -129,7 +153,7 @@ selector: "receiver",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=self["@receiver"];
+$1=_st(self)._localAt_("self");
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"receiver",{}, smalltalk.AIContext)})}
 }),
@@ -141,7 +165,7 @@ smalltalk.method({
 selector: "receiver:",
 fn: function (anObject){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@receiver"]=anObject;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._localAt_put_("self",anObject);
 return self}, function($ctx1) {$ctx1.fill(self,"receiver:",{anObject:anObject}, smalltalk.AIContext)})}
 }),
 smalltalk.AIContext);
@@ -152,24 +176,18 @@ smalltalk.method({
 selector: "selector",
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=self["@selector"];
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=_st(self)._metod();
+if(($receiver = $2) == nil || $receiver == undefined){
+$1=$2;
+} else {
+$1=_st(_st(self)._method())._selector();
+};
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"selector",{}, smalltalk.AIContext)})}
 }),
 smalltalk.AIContext);
 
-smalltalk.addMethod(
-"_selector_",
-smalltalk.method({
-selector: "selector:",
-fn: function (aString){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@selector"]=aString;
-return self}, function($ctx1) {$ctx1.fill(self,"selector:",{aString:aString}, smalltalk.AIContext)})}
-}),
-smalltalk.AIContext);
-
 
 smalltalk.addMethod(
 "_fromMethodContext_",
@@ -188,7 +206,209 @@ return $1;
 smalltalk.AIContext.klass);
 
 
-smalltalk.addClass('ASTInterpreter', smalltalk.NodeVisitor, ['currentNode', 'context', 'shouldReturn', 'currentValue'], 'Compiler-Interpreter');
+smalltalk.addClass('ASTDebugger', smalltalk.Object, ['interpreter', 'context'], 'Compiler-Interpreter');
+smalltalk.addMethod(
+"_buildAST",
+smalltalk.method({
+selector: "buildAST",
+fn: function (){
+var self=this;
+var ast;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+ast=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._parse_(_st(_st(self)._method())._source());
+_st(_st((smalltalk.SemanticAnalyzer || SemanticAnalyzer))._on_(_st(_st(_st(self)._context())._receiver())._class()))._visit_(ast);
+$1=ast;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"buildAST",{ast:ast}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_context",
+smalltalk.method({
+selector: "context",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@context"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"context",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_context_",
+smalltalk.method({
+selector: "context:",
+fn: function (aContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@context"]=_st((smalltalk.AIContext || AIContext))._new();
+return self}, function($ctx1) {$ctx1.fill(self,"context:",{aContext:aContext}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_defaultInterpreterClass",
+smalltalk.method({
+selector: "defaultInterpreterClass",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=(smalltalk.ASTSteppingInterpreter || ASTSteppingInterpreter);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"defaultInterpreterClass",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_initializeInterpreter",
+smalltalk.method({
+selector: "initializeInterpreter",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(_st(self)._interpreter())._interpret_(_st(_st(_st(self)._buildAST())._nodes())._first());
+return self}, function($ctx1) {$ctx1.fill(self,"initializeInterpreter",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_initializeWithContext_",
+smalltalk.method({
+selector: "initializeWithContext:",
+fn: function (aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._context_(_st((smalltalk.AIContext || AIContext))._fromMethodContext_(aMethodContext));
+_st(self)._initializeInterpreter();
+return self}, function($ctx1) {$ctx1.fill(self,"initializeWithContext:",{aMethodContext:aMethodContext}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_interpreter",
+smalltalk.method({
+selector: "interpreter",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@interpreter"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@interpreter"]=_st(_st(self)._defaultInterpreterClass())._new();
+$1=self["@interpreter"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_interpreter_",
+smalltalk.method({
+selector: "interpreter:",
+fn: function (anInterpreter){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@interpreter"]=anInterpreter;
+return self}, function($ctx1) {$ctx1.fill(self,"interpreter:",{anInterpreter:anInterpreter}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_method",
+smalltalk.method({
+selector: "method",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._context())._method();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"method",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_restart",
+smalltalk.method({
+selector: "restart",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._shouldBeImplemented();
+return self}, function($ctx1) {$ctx1.fill(self,"restart",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_resume",
+smalltalk.method({
+selector: "resume",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._shouldBeImplemented();
+return self}, function($ctx1) {$ctx1.fill(self,"resume",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_step",
+smalltalk.method({
+selector: "step",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(_st(_st(_st(_st(self)._interpreter())._nextNode())._notNil())._and_((function(){
+return smalltalk.withContext(function($ctx3) {
return _st(_st(_st(self)._interpreter())._nextNode())._stopOnStepping();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})})))._or_((function(){
+return smalltalk.withContext(function($ctx3) {
return _st(_st(_st(self)._interpreter())._atEnd())._not();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
_st(_st(self)._interpreter())._step();
+return _st(self)._step();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"step",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_stepInto",
+smalltalk.method({
+selector: "stepInto",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._shouldBeImplemented();
+return self}, function($ctx1) {$ctx1.fill(self,"stepInto",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+smalltalk.addMethod(
+"_stepOver",
+smalltalk.method({
+selector: "stepOver",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._step();
+return self}, function($ctx1) {$ctx1.fill(self,"stepOver",{}, smalltalk.ASTDebugger)})}
+}),
+smalltalk.ASTDebugger);
+
+
+smalltalk.addMethod(
+"_context_",
+smalltalk.method({
+selector: "context:",
+fn: function (aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$3,$1;
+$2=_st(self)._new();
+_st($2)._initializeWithContext_(aMethodContext);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"context:",{aMethodContext:aMethodContext}, smalltalk.ASTDebugger.klass)})}
+}),
+smalltalk.ASTDebugger.klass);
+
+
+smalltalk.addClass('ASTInterpreter', smalltalk.Object, ['currentNode', 'context', 'shouldReturn', 'result'], 'Compiler-Interpreter');
 smalltalk.addMethod(
 "_assign_to_",
 smalltalk.method({
@@ -238,26 +458,27 @@ return self}, function($ctx1) {$ctx1.fill(self,"context:",{anAIContext:anAIConte
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_continue_",
+"_continue_value_",
 smalltalk.method({
-selector: "continue:",
-fn: function (anObject){
+selector: "continue:value:",
+fn: function (aBlock,anObject){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@currentValue"]=anObject;
-return self}, function($ctx1) {$ctx1.fill(self,"continue:",{anObject:anObject}, smalltalk.ASTInterpreter)})}
+return smalltalk.withContext(function($ctx1) { 
self["@result"]=anObject;
+_st(aBlock)._value_(anObject);
+return self}, function($ctx1) {$ctx1.fill(self,"continue:value:",{aBlock:aBlock,anObject:anObject}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_currentValue",
+"_currentNode",
 smalltalk.method({
-selector: "currentValue",
+selector: "currentNode",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=self["@currentValue"];
+$1=self["@currentNode"];
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"currentValue",{}, smalltalk.ASTInterpreter)})}
+}, function($ctx1) {$ctx1.fill(self,"currentNode",{}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
@@ -295,7 +516,7 @@ smalltalk.method({
 selector: "initialize",
 fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
smalltalk.NodeVisitor.fn.prototype._initialize.apply(_st(self), []);
+return smalltalk.withContext(function($ctx1) { 
smalltalk.Object.fn.prototype._initialize.apply(_st(self), []);
 self["@shouldReturn"]=false;
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.ASTInterpreter)})}
 }),
@@ -309,8 +530,8 @@ fn: function (aNode){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
self["@shouldReturn"]=false;
 _st(self)._interpret_continue_(aNode,(function(value){
-return smalltalk.withContext(function($ctx2) {
self["@currentValue"]=value;
-return self["@currentValue"];
+return smalltalk.withContext(function($ctx2) {
self["@result"]=value;
+return self["@result"];
 }, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
 }),
@@ -330,12 +551,14 @@ return $2;
 };
 $3=_st(aNode)._isNode();
 if(smalltalk.assert($3)){
-_st(self)._visit_(aNode);
+self["@currentNode"]=aNode;
+self["@currentNode"];
+_st(self)._interpretNode_continue_(aNode,(function(value){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_value_(aBlock,value);
+}, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 } else {
-self["@currentValue"]=aNode;
-self["@currentValue"];
+_st(self)._continue_value_(aBlock,aNode);
 };
-_st(aBlock)._value_(_st(self)._currentValue());
 return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
@@ -360,7 +583,7 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(nodes)._isEmpty();
 if(smalltalk.assert($1)){
-_st(aBlock)._value_(aCollection);
+_st(self)._continue_value_(aBlock,aCollection);
 } else {
 _st(self)._interpret_continue_(_st(nodes)._first(),(function(value){
 return smalltalk.withContext(function($ctx2) {
return _st(self)._interpretAll_continue_result_(_st(nodes)._allButFirst(),aBlock,_st(aCollection).__comma([value]));
@@ -371,58 +594,51 @@ return self}, function($ctx1) {$ctx1.fill(self,"interpretAll:continue:result:",{
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_messageFromSendNode_do_",
-smalltalk.method({
-selector: "messageFromSendNode:do:",
-fn: function (aSendNode,aBlock){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2;
-_st(self)._interpretAll_continue_(_st(aSendNode)._arguments(),(function(args){
-return smalltalk.withContext(function($ctx2) {
$1=_st((smalltalk.Message || Message))._new();
-_st($1)._selector_(_st(aSendNode)._selector());
-_st($1)._arguments_(args);
-$2=_st($1)._yourself();
-return _st(aBlock)._value_($2);
-}, function($ctx2) {$ctx2.fillBlock({args:args},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:do:",{aSendNode:aSendNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
-}),
-smalltalk.ASTInterpreter);
-
-smalltalk.addMethod(
-"_visitAssignmentNode_",
+"_interpretAssignmentNode_continue_",
 smalltalk.method({
-selector: "visitAssignmentNode:",
-fn: function (aNode){
+selector: "interpretAssignmentNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_continue_(_st(aNode)._right(),(function(value){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_(_st(self)._assign_to_(_st(aNode)._left(),value));
+return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_value_(aBlock,_st(self)._assign_to_(_st(aNode)._left(),value));
 }, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretAssignmentNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitBlockNode_",
+"_interpretBlockNode_continue_",
 smalltalk.method({
-selector: "visitBlockNode:",
-fn: function (aNode){
+selector: "interpretBlockNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2;
-_st(self)._continue_((function(){
+_st(self)._continue_value_(aBlock,(function(){
 return smalltalk.withContext(function($ctx2) {
$1=self;
 _st($1)._interpret_(_st(_st(aNode)._nodes())._first());
-$2=_st($1)._currentValue();
+$2=_st($1)._result();
 return $2;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitBlockNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretBlockNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitCascadeNode_",
+"_interpretBlockSequenceNode_continue_",
 smalltalk.method({
-selector: "visitCascadeNode:",
-fn: function (aNode){
+selector: "interpretBlockSequenceNode:continue:",
+fn: function (aNode,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpretSequenceNode_continue_(aNode,aBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"interpretBlockSequenceNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_interpretCascadeNode_continue_",
+smalltalk.method({
+selector: "interpretCascadeNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_continue_(_st(aNode)._receiver(),(function(receiver){
 return smalltalk.withContext(function($ctx2) {
_st(_st(aNode)._nodes())._do_((function(each){
@@ -430,43 +646,43 @@ return smalltalk.withContext(function($ctx3) {
return _st(each)._receiver_(recei
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx1)})}));
 return _st(self)._interpretAll_continue_(_st(_st(aNode)._nodes())._allButLast(),(function(){
 return smalltalk.withContext(function($ctx3) {
return _st(self)._interpret_continue_(_st(_st(aNode)._nodes())._last(),(function(val){
-return smalltalk.withContext(function($ctx4) {
return _st(self)._continue_(val);
+return smalltalk.withContext(function($ctx4) {
return _st(self)._continue_value_(aBlock,val);
 }, function($ctx4) {$ctx4.fillBlock({val:val},$ctx1)})}));
 }, function($ctx3) {$ctx3.fillBlock({},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitCascadeNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretCascadeNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitClassReferenceNode_",
+"_interpretClassReferenceNode_continue_",
 smalltalk.method({
-selector: "visitClassReferenceNode:",
-fn: function (aNode){
+selector: "interpretClassReferenceNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
_st(self)._continue_(_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._at_(_st(aNode)._value()));
-return self}, function($ctx1) {$ctx1.fill(self,"visitClassReferenceNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return smalltalk.withContext(function($ctx1) { 
_st(self)._continue_value_(aBlock,_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._at_(_st(aNode)._value()));
+return self}, function($ctx1) {$ctx1.fill(self,"interpretClassReferenceNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitDynamicArrayNode_",
+"_interpretDynamicArrayNode_continue_",
 smalltalk.method({
-selector: "visitDynamicArrayNode:",
-fn: function (aNode){
+selector: "interpretDynamicArrayNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpretAll_continue_(_st(aNode)._nodes(),(function(array){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_(array);
+return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_value_(aBlock,array);
 }, function($ctx2) {$ctx2.fillBlock({array:array},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicArrayNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretDynamicArrayNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitDynamicDictionaryNode_",
+"_interpretDynamicDictionaryNode_continue_",
 smalltalk.method({
-selector: "visitDynamicDictionaryNode:",
-fn: function (aNode){
+selector: "interpretDynamicDictionaryNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpretAll_continue_(_st(aNode)._nodes(),(function(array){
 var hashedCollection;
@@ -475,82 +691,190 @@ hashedCollection;
 _st(array)._do_((function(each){
 return smalltalk.withContext(function($ctx3) {
return _st(hashedCollection)._add_(each);
 }, function($ctx3) {$ctx3.fillBlock({each:each},$ctx1)})}));
-return _st(self)._continue_(hashedCollection);
+return _st(self)._continue_value_(aBlock,hashedCollection);
 }, function($ctx2) {$ctx2.fillBlock({array:array,hashedCollection:hashedCollection},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitDynamicDictionaryNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretDynamicDictionaryNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitJSStatementNode_",
+"_interpretJSStatementNode_continue_",
 smalltalk.method({
-selector: "visitJSStatementNode:",
-fn: function (aNode){
+selector: "interpretJSStatementNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
self["@shouldReturn"]=true;
-_st(self)._continue_(_st(self)._eval_(_st(aNode)._source()));
-return self}, function($ctx1) {$ctx1.fill(self,"visitJSStatementNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+_st(self)._continue_value_(aBlock,_st(self)._eval_(_st(aNode)._source()));
+return self}, function($ctx1) {$ctx1.fill(self,"interpretJSStatementNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitReturnNode_",
+"_interpretMethodNode_continue_",
 smalltalk.method({
-selector: "visitReturnNode:",
-fn: function (aNode){
+selector: "interpretMethodNode:continue:",
+fn: function (aNode,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpretAll_continue_(_st(aNode)._nodes(),(function(array){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_value_(aBlock,_st(array)._first());
+}, function($ctx2) {$ctx2.fillBlock({array:array},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"interpretMethodNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_interpretNode_continue_",
+smalltalk.method({
+selector: "interpretNode:continue:",
+fn: function (aNode,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(aNode)._interpreter_continue_(self,aBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"interpretNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_interpretReturnNode_continue_",
+smalltalk.method({
+selector: "interpretReturnNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_continue_(_st(_st(aNode)._nodes())._first(),(function(value){
 return smalltalk.withContext(function($ctx2) {
self["@shouldReturn"]=true;
 self["@shouldReturn"];
-return _st(self)._continue_(value);
+return _st(self)._continue_value_(aBlock,value);
 }, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitReturnNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretReturnNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitSendNode_",
+"_interpretSendNode_continue_",
 smalltalk.method({
-selector: "visitSendNode:",
-fn: function (aNode){
+selector: "interpretSendNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_continue_(_st(aNode)._receiver(),(function(receiver){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._messageFromSendNode_do_(aNode,(function(message){
-return smalltalk.withContext(function($ctx3) {
_st(_st(self)._context())._pc_(_st(_st(_st(self)._context())._pc()).__plus((1)));
-return _st(self)._continue_(_st(message)._sendTo_(receiver));
-}, function($ctx3) {$ctx3.fillBlock({message:message},$ctx1)})}));
+return smalltalk.withContext(function($ctx2) {
return _st(self)._interpretAll_continue_(_st(aNode)._arguments(),(function(args){
+return smalltalk.withContext(function($ctx3) {
return _st(self)._messageFromSendNode_arguments_do_(aNode,args,(function(message){
+return smalltalk.withContext(function($ctx4) {
_st(_st(self)._context())._pc_(_st(_st(_st(self)._context())._pc()).__plus((1)));
+return _st(self)._continue_value_(aBlock,_st(message)._sendTo_(receiver));
+}, function($ctx4) {$ctx4.fillBlock({message:message},$ctx1)})}));
+}, function($ctx3) {$ctx3.fillBlock({args:args},$ctx1)})}));
 }, function($ctx2) {$ctx2.fillBlock({receiver:receiver},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitSendNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretSendNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitSequenceNode_",
+"_interpretSequenceNode_continue_",
 smalltalk.method({
-selector: "visitSequenceNode:",
-fn: function (aNode){
+selector: "interpretSequenceNode:continue:",
+fn: function (aNode,aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self)._interpretAll_continue_(_st(aNode)._nodes(),(function(array){
-return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_(_st(array)._last());
+return smalltalk.withContext(function($ctx2) {
return _st(self)._continue_value_(aBlock,_st(array)._last());
 }, function($ctx2) {$ctx2.fillBlock({array:array},$ctx1)})}));
-return self}, function($ctx1) {$ctx1.fill(self,"visitSequenceNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpretSequenceNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
 smalltalk.addMethod(
-"_visitValueNode_",
+"_interpretValueNode_continue_",
 smalltalk.method({
-selector: "visitValueNode:",
-fn: function (aNode){
+selector: "interpretValueNode:continue:",
+fn: function (aNode,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._continue_value_(aBlock,_st(aNode)._value());
+return self}, function($ctx1) {$ctx1.fill(self,"interpretValueNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_interpretVariableNode_continue_",
+smalltalk.method({
+selector: "interpretVariableNode:continue:",
+fn: function (aNode,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$3;
+$1=self;
+$2=aBlock;
+$4=_st(_st(aNode)._binding())._isInstanceVar();
+if(smalltalk.assert($4)){
+$3=_st(_st(_st(self)._context())._receiver())._instVarAt_(_st(aNode)._value());
+} else {
+$3=_st(_st(self)._context())._localAt_(_st(aNode)._value());
+};
+_st($1)._continue_value_($2,$3);
+return self}, function($ctx1) {$ctx1.fill(self,"interpretVariableNode:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_messageFromSendNode_arguments_do_",
+smalltalk.method({
+selector: "messageFromSendNode:arguments:do:",
+fn: function (aSendNode,aCollection,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
+$1=_st((smalltalk.Message || Message))._new();
+_st($1)._selector_(_st(aSendNode)._selector());
+_st($1)._arguments_(aCollection);
+$2=_st($1)._yourself();
+_st(self)._continue_value_(aBlock,$2);
+return self}, function($ctx1) {$ctx1.fill(self,"messageFromSendNode:arguments:do:",{aSendNode:aSendNode,aCollection:aCollection,aBlock:aBlock}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
+
+smalltalk.addMethod(
+"_result",
+smalltalk.method({
+selector: "result",
+fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
_st(self)._continue_(_st(aNode)._value());
-return self}, function($ctx1) {$ctx1.fill(self,"visitValueNode:",{aNode:aNode}, smalltalk.ASTInterpreter)})}
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@result"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"result",{}, smalltalk.ASTInterpreter)})}
 }),
 smalltalk.ASTInterpreter);
 
+smalltalk.addMethod(
+"_shouldReturn",
+smalltalk.method({
+selector: "shouldReturn",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@shouldReturn"];
+if(($receiver = $2) == nil || $receiver == undefined){
+$1=false;
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"shouldReturn",{}, smalltalk.ASTInterpreter)})}
+}),
+smalltalk.ASTInterpreter);
 
 
-smalltalk.addClass('ASTDebugger', smalltalk.ASTInterpreter, ['continuation'], 'Compiler-Interpreter');
+
+smalltalk.addClass('ASTSteppingInterpreter', smalltalk.ASTInterpreter, ['continuation', 'nextNode'], 'Compiler-Interpreter');
+smalltalk.addMethod(
+"_atEnd",
+smalltalk.method({
+selector: "atEnd",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(self)._shouldReturn())._or_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._nextNode()).__eq_eq(_st(self)._currentNode());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"atEnd",{}, smalltalk.ASTSteppingInterpreter)})}
+}),
+smalltalk.ASTSteppingInterpreter);
+
 smalltalk.addMethod(
 "_initialize",
 smalltalk.method({
@@ -560,9 +884,9 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
smalltalk.ASTInterpreter.fn.prototype._initialize.apply(_st(self), []);
 self["@continuation"]=(function(){
 return smalltalk.withContext(function($ctx2) {
}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})});
-return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.ASTDebugger)})}
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.ASTSteppingInterpreter)})}
 }),
-smalltalk.ASTDebugger);
+smalltalk.ASTSteppingInterpreter);
 
 smalltalk.addMethod(
 "_interpret_continue_",
@@ -570,23 +894,309 @@ smalltalk.method({
 selector: "interpret:continue:",
 fn: function (aNode,aBlock){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@continuation"]=(function(){
+return smalltalk.withContext(function($ctx1) { 
self["@nextNode"]=aNode;
+self["@continuation"]=(function(){
 return smalltalk.withContext(function($ctx2) {
return smalltalk.ASTInterpreter.fn.prototype._interpret_continue_.apply(_st(self), [aNode,aBlock]);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})});
-return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTDebugger)})}
+return self}, function($ctx1) {$ctx1.fill(self,"interpret:continue:",{aNode:aNode,aBlock:aBlock}, smalltalk.ASTSteppingInterpreter)})}
 }),
-smalltalk.ASTDebugger);
+smalltalk.ASTSteppingInterpreter);
 
 smalltalk.addMethod(
-"_stepOver",
+"_nextNode",
 smalltalk.method({
-selector: "stepOver",
+selector: "nextNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@nextNode"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"nextNode",{}, smalltalk.ASTSteppingInterpreter)})}
+}),
+smalltalk.ASTSteppingInterpreter);
+
+smalltalk.addMethod(
+"_step",
+smalltalk.method({
+selector: "step",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self["@continuation"])._value();
-return self}, function($ctx1) {$ctx1.fill(self,"stepOver",{}, smalltalk.ASTDebugger)})}
+return self}, function($ctx1) {$ctx1.fill(self,"step",{}, smalltalk.ASTSteppingInterpreter)})}
 }),
-smalltalk.ASTDebugger);
+smalltalk.ASTSteppingInterpreter);
+
+
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.Node)})}
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return false;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.Node)})}
+}),
+smalltalk.Node);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretAssignmentNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.AssignmentNode)})}
+}),
+smalltalk.AssignmentNode);
 
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.AssignmentNode)})}
+}),
+smalltalk.AssignmentNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretBlockNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.BlockNode)})}
+}),
+smalltalk.BlockNode);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.BlockNode)})}
+}),
+smalltalk.BlockNode);
 
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretCascadeNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.CascadeNode)})}
+}),
+smalltalk.CascadeNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretDynamicArrayNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.DynamicArrayNode)})}
+}),
+smalltalk.DynamicArrayNode);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.DynamicArrayNode)})}
+}),
+smalltalk.DynamicArrayNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretDynamicDictionaryNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.DynamicDictionaryNode)})}
+}),
+smalltalk.DynamicDictionaryNode);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.DynamicDictionaryNode)})}
+}),
+smalltalk.DynamicDictionaryNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretJSStatementNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.JSStatementNode)})}
+}),
+smalltalk.JSStatementNode);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.JSStatementNode)})}
+}),
+smalltalk.JSStatementNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretMethodNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.MethodNode)})}
+}),
+smalltalk.MethodNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretReturnNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.ReturnNode)})}
+}),
+smalltalk.ReturnNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretSendNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.SendNode)})}
+}),
+smalltalk.SendNode);
+
+smalltalk.addMethod(
+"_isSteppingNode",
+smalltalk.method({
+selector: "isSteppingNode",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return true;
+}, function($ctx1) {$ctx1.fill(self,"isSteppingNode",{}, smalltalk.SendNode)})}
+}),
+smalltalk.SendNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretSequenceNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.SequenceNode)})}
+}),
+smalltalk.SequenceNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretBlockSequenceNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.BlockSequenceNode)})}
+}),
+smalltalk.BlockSequenceNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretValueNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.ValueNode)})}
+}),
+smalltalk.ValueNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretVariableNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.VariableNode)})}
+}),
+smalltalk.VariableNode);
+
+smalltalk.addMethod(
+"_interpreter_continue_",
+smalltalk.method({
+selector: "interpreter:continue:",
+fn: function (anInterpreter,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(anInterpreter)._interpretClassReferenceNode_continue_(self,aBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter:continue:",{anInterpreter:anInterpreter,aBlock:aBlock}, smalltalk.ClassReferenceNode)})}
+}),
+smalltalk.ClassReferenceNode);
 

File diff suppressed because it is too large
+ 638 - 195
js/Compiler-Interpreter.js


+ 130 - 16
js/Compiler-Tests.deploy.js

@@ -1,5 +1,5 @@
 smalltalk.addPackage('Compiler-Tests', {});
-smalltalk.addClass('ASTInterpreterTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addClass('AbstractASTInterpreterTest', smalltalk.TestCase, [], 'Compiler-Tests');
 smalltalk.addMethod(
 "_analyze_forClass_",
 smalltalk.method({
@@ -10,9 +10,9 @@ return smalltalk.withContext(function($ctx1) { 
var $1;
 _st(_st((smalltalk.SemanticAnalyzer || SemanticAnalyzer))._on_(aClass))._visit_(aNode);
 $1=aNode;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"analyze:forClass:",{aNode:aNode,aClass:aClass}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"analyze:forClass:",{aNode:aNode,aClass:aClass}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_",
@@ -23,9 +23,9 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._interpret_withArguments_(aString,_st((smalltalk.Dictionary || Dictionary))._new());
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpret:",{aString:aString}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"interpret:",{aString:aString}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_receiver_withArguments_",
@@ -43,12 +43,12 @@ return smalltalk.withContext(function($ctx2) {
return _st(ctx)._localAt_put_(key
 $2=_st(self)._interpreter();
 _st($2)._context_(ctx);
 _st($2)._interpret_(_st(_st(_st(self)._parse_forClass_(aString,_st(anObject)._class()))._nodes())._first());
-$3=_st($2)._currentValue();
+$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.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"interpret:receiver:withArguments:",{aString:aString,anObject:anObject,aDictionary:aDictionary,ctx:ctx}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_withArguments_",
@@ -59,9 +59,9 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._interpret_receiver_withArguments_(aString,_st((smalltalk.Object || Object))._new(),aDictionary);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpret:withArguments:",{aString:aString,aDictionary:aDictionary}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"interpret:withArguments:",{aString:aString,aDictionary:aDictionary}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpreter",
@@ -70,11 +70,11 @@ selector: "interpreter",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st((smalltalk.ASTInterpreter || ASTInterpreter))._new();
+$1=_st(self)._subclassResponsibility();
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_parse_",
@@ -85,9 +85,9 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._parse_(aString);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString}, smalltalk.AbstractASTInterpreterTest)})}
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_parse_forClass_",
@@ -98,7 +98,23 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._analyze_forClass_(_st(self)._parse_(aString),aClass);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"parse:forClass:",{aString:aString,aClass:aClass}, smalltalk.ASTInterpreterTest)})}
+}, function($ctx1) {$ctx1.fill(self,"parse:forClass:",{aString:aString,aClass:aClass}, smalltalk.AbstractASTInterpreterTest)})}
+}),
+smalltalk.AbstractASTInterpreterTest);
+
+
+
+smalltalk.addClass('ASTInterpreterTest', smalltalk.AbstractASTInterpreterTest, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_interpreter",
+smalltalk.method({
+selector: "interpreter",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st((smalltalk.ASTInterpreter || ASTInterpreter))._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTInterpreterTest)})}
 }),
 smalltalk.ASTInterpreterTest);
 
@@ -171,6 +187,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"testInlinedJSStatement",{}, smal
 }),
 smalltalk.ASTInterpreterTest);
 
+smalltalk.addMethod(
+"_testInstVarAccess",
+smalltalk.method({
+selector: "testInstVarAccess",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._assert_equals_(_st(self)._interpret_receiver_withArguments_("foo ^ x",_st((2)).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAccess",{}, smalltalk.ASTInterpreterTest)})}
+}),
+smalltalk.ASTInterpreterTest);
+
 smalltalk.addMethod(
 "_testInstVarAssignment",
 smalltalk.method({
@@ -193,6 +220,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"testNonlocalReturn",{}, smalltal
 }),
 smalltalk.ASTInterpreterTest);
 
+smalltalk.addMethod(
+"_testReceiver",
+smalltalk.method({
+selector: "testReceiver",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._assert_equals_(_st(self)._interpret_receiver_withArguments_("foo ^ self",_st((2)).__at((3)),smalltalk.HashedCollection._fromPairs_([])),_st((2)).__at((3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testReceiver",{}, smalltalk.ASTInterpreterTest)})}
+}),
+smalltalk.ASTInterpreterTest);
+
 smalltalk.addMethod(
 "_testTempAssignment",
 smalltalk.method({
@@ -206,6 +244,82 @@ smalltalk.ASTInterpreterTest);
 
 
 
+smalltalk.addClass('ASTSteppingInterpreterTest', smalltalk.AbstractASTInterpreterTest, ['interpreter'], 'Compiler-Tests');
+smalltalk.addMethod(
+"_interpreter",
+smalltalk.method({
+selector: "interpreter",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@interpreter"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@interpreter"]=_st((smalltalk.ASTSteppingInterpreter || ASTSteppingInterpreter))._new();
+$1=self["@interpreter"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTSteppingInterpreterTest)})}
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testAtEnd",
+smalltalk.method({
+selector: "testAtEnd",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1 + 2");
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_(_st(_st(self)._interpreter())._atEnd());
+return self}, function($ctx1) {$ctx1.fill(self,"testAtEnd",{}, smalltalk.ASTSteppingInterpreterTest)})}
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testMessageSend",
+smalltalk.method({
+selector: "testMessageSend",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1 + 2");
+_st(_st(self)._interpreter())._step();
+_st(_st(self)._interpreter())._step();
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(_st(self)._interpreter())._currentNode())._value(),(1));
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(_st(self)._interpreter())._currentNode())._value(),(2));
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(self)._interpreter())._result(),(3));
+return self}, function($ctx1) {$ctx1.fill(self,"testMessageSend",{}, smalltalk.ASTSteppingInterpreterTest)})}
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testSimpleStepping",
+smalltalk.method({
+selector: "testSimpleStepping",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1");
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_(_st(_st(_st(self)._interpreter())._result())._isNil());
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(self)._interpreter())._result(),(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testSimpleStepping",{}, smalltalk.ASTSteppingInterpreterTest)})}
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+
+
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 "_codeGeneratorClass",

+ 176 - 27
js/Compiler-Tests.js

@@ -1,47 +1,47 @@
 smalltalk.addPackage('Compiler-Tests', {});
-smalltalk.addClass('ASTInterpreterTest', smalltalk.TestCase, [], 'Compiler-Tests');
+smalltalk.addClass('AbstractASTInterpreterTest', smalltalk.TestCase, [], 'Compiler-Tests');
 smalltalk.addMethod(
 "_analyze_forClass_",
 smalltalk.method({
 selector: "analyze:forClass:",
-category: 'accessing',
+category: 'interpreting',
 fn: function (aNode,aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 _st(_st((smalltalk.SemanticAnalyzer || SemanticAnalyzer))._on_(aClass))._visit_(aNode);
 $1=aNode;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"analyze:forClass:",{aNode:aNode,aClass:aClass}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"analyze:forClass:",{aNode:aNode,aClass:aClass}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aNode", "aClass"],
 source: "analyze: aNode forClass: aClass\x0a\x09(SemanticAnalyzer on: aClass) visit: aNode.\x0a    ^ aNode",
 messageSends: ["visit:", "on:"],
 referencedClasses: ["SemanticAnalyzer"]
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_",
 smalltalk.method({
 selector: "interpret:",
-category: 'accessing',
+category: 'interpreting',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._interpret_withArguments_(aString,_st((smalltalk.Dictionary || Dictionary))._new());
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpret:",{aString:aString}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"interpret:",{aString:aString}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aString"],
 source: "interpret: aString\x0a\x09^ self \x0a    \x09interpret: aString \x0a        withArguments: Dictionary new",
 messageSends: ["interpret:withArguments:", "new"],
 referencedClasses: ["Dictionary"]
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_receiver_withArguments_",
 smalltalk.method({
 selector: "interpret:receiver:withArguments:",
-category: 'accessing',
+category: 'interpreting',
 fn: function (aString,anObject,aDictionary){
 var self=this;
 var ctx;
@@ -54,34 +54,34 @@ return smalltalk.withContext(function($ctx2) {
return _st(ctx)._localAt_put_(key
 $2=_st(self)._interpreter();
 _st($2)._context_(ctx);
 _st($2)._interpret_(_st(_st(_st(self)._parse_forClass_(aString,_st(anObject)._class()))._nodes())._first());
-$3=_st($2)._currentValue();
+$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.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"interpret:receiver:withArguments:",{aString:aString,anObject:anObject,aDictionary:aDictionary,ctx:ctx}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aString", "anObject", "aDictionary"],
-source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09\x22The food is a methodNode. Interpret the sequenceNode only\x22\x0a    \x0a    | ctx |\x0a    \x0a    ctx := AIContext new.\x0a    ctx receiver: anObject.\x0a    aDictionary keysAndValuesDo: [ :key :value |\x0a    \x09ctx localAt: key put: value ].\x0a    \x0a    ^ self interpreter\x0a    \x09context: ctx;\x0a    \x09interpret: (self parse: aString forClass: anObject class) \x0a        \x09nodes first;\x0a        currentValue",
-messageSends: ["new", "receiver:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "interpret:", "first", "nodes", "parse:forClass:", "class", "currentValue"],
+source: "interpret: aString receiver: anObject withArguments: aDictionary\x0a\x09\x22The food is a methodNode. Interpret the sequenceNode only\x22\x0a    \x0a    | ctx |\x0a    \x0a    ctx := AIContext new.\x0a    ctx receiver: anObject.\x0a    aDictionary keysAndValuesDo: [ :key :value |\x0a    \x09ctx localAt: key put: value ].\x0a    \x0a    ^ self interpreter\x0a    \x09context: ctx;\x0a    \x09interpret: (self parse: aString forClass: anObject class) \x0a        \x09nodes first;\x0a        result",
+messageSends: ["new", "receiver:", "keysAndValuesDo:", "localAt:put:", "context:", "interpreter", "interpret:", "first", "nodes", "parse:forClass:", "class", "result"],
 referencedClasses: ["AIContext"]
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpret_withArguments_",
 smalltalk.method({
 selector: "interpret:withArguments:",
-category: 'accessing',
+category: 'interpreting',
 fn: function (aString,aDictionary){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._interpret_receiver_withArguments_(aString,_st((smalltalk.Object || Object))._new(),aDictionary);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpret:withArguments:",{aString:aString,aDictionary:aDictionary}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"interpret:withArguments:",{aString:aString,aDictionary:aDictionary}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aString", "aDictionary"],
 source: "interpret: aString withArguments: aDictionary\x0a\x09^ self \x0a    \x09interpret: aString \x0a        receiver: Object new\x0a        withArguments: aDictionary",
 messageSends: ["interpret:receiver:withArguments:", "new"],
 referencedClasses: ["Object"]
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_interpreter",
@@ -91,50 +91,71 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st((smalltalk.ASTInterpreter || ASTInterpreter))._new();
+$1=_st(self)._subclassResponsibility();
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.AbstractASTInterpreterTest)})},
 args: [],
-source: "interpreter\x0a\x09^ ASTInterpreter new",
-messageSends: ["new"],
-referencedClasses: ["ASTInterpreter"]
+source: "interpreter\x0a\x09^ self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
+referencedClasses: []
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_parse_",
 smalltalk.method({
 selector: "parse:",
-category: 'accessing',
+category: 'parsing',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._parse_(aString);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"parse:",{aString:aString}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aString"],
 source: "parse: aString\x0a\x09^ Smalltalk current parse: aString",
 messageSends: ["parse:", "current"],
 referencedClasses: ["Smalltalk"]
 }),
-smalltalk.ASTInterpreterTest);
+smalltalk.AbstractASTInterpreterTest);
 
 smalltalk.addMethod(
 "_parse_forClass_",
 smalltalk.method({
 selector: "parse:forClass:",
-category: 'accessing',
+category: 'parsing',
 fn: function (aString,aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(self)._analyze_forClass_(_st(self)._parse_(aString),aClass);
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"parse:forClass:",{aString:aString,aClass:aClass}, smalltalk.ASTInterpreterTest)})},
+}, function($ctx1) {$ctx1.fill(self,"parse:forClass:",{aString:aString,aClass:aClass}, smalltalk.AbstractASTInterpreterTest)})},
 args: ["aString", "aClass"],
 source: "parse: aString forClass: aClass\x0a\x09^ self analyze: (self parse: aString) forClass: aClass",
 messageSends: ["analyze:forClass:", "parse:"],
 referencedClasses: []
 }),
+smalltalk.AbstractASTInterpreterTest);
+
+
+
+smalltalk.addClass('ASTInterpreterTest', smalltalk.AbstractASTInterpreterTest, [], 'Compiler-Tests');
+smalltalk.addMethod(
+"_interpreter",
+smalltalk.method({
+selector: "interpreter",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st((smalltalk.ASTInterpreter || ASTInterpreter))._new();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTInterpreterTest)})},
+args: [],
+source: "interpreter\x0a\x09^ ASTInterpreter new",
+messageSends: ["new"],
+referencedClasses: ["ASTInterpreter"]
+}),
 smalltalk.ASTInterpreterTest);
 
 smalltalk.addMethod(
@@ -236,6 +257,22 @@ referencedClasses: []
 }),
 smalltalk.ASTInterpreterTest);
 
+smalltalk.addMethod(
+"_testInstVarAccess",
+smalltalk.method({
+selector: "testInstVarAccess",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._assert_equals_(_st(self)._interpret_receiver_withArguments_("foo ^ x",_st((2)).__at((3)),smalltalk.HashedCollection._fromPairs_([])),(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testInstVarAccess",{}, smalltalk.ASTInterpreterTest)})},
+args: [],
+source: "testInstVarAccess\x0a\x09self \x0a    \x09assert: (self \x0a    \x09\x09interpret: 'foo ^ x'\x0a        \x09receiver: 2@3\x0a        \x09withArguments: #{})\x0a        equals: 2",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"],
+referencedClasses: []
+}),
+smalltalk.ASTInterpreterTest);
+
 smalltalk.addMethod(
 "_testInstVarAssignment",
 smalltalk.method({
@@ -268,6 +305,22 @@ referencedClasses: []
 }),
 smalltalk.ASTInterpreterTest);
 
+smalltalk.addMethod(
+"_testReceiver",
+smalltalk.method({
+selector: "testReceiver",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._assert_equals_(_st(self)._interpret_receiver_withArguments_("foo ^ self",_st((2)).__at((3)),smalltalk.HashedCollection._fromPairs_([])),_st((2)).__at((3)));
+return self}, function($ctx1) {$ctx1.fill(self,"testReceiver",{}, smalltalk.ASTInterpreterTest)})},
+args: [],
+source: "testReceiver\x0a\x09self \x0a    \x09assert: (self \x0a    \x09\x09interpret: 'foo ^ self'\x0a        \x09receiver: 2@3\x0a        \x09withArguments: #{})\x0a        equals: 2@3",
+messageSends: ["assert:equals:", "interpret:receiver:withArguments:", "@"],
+referencedClasses: []
+}),
+smalltalk.ASTInterpreterTest);
+
 smalltalk.addMethod(
 "_testTempAssignment",
 smalltalk.method({
@@ -286,6 +339,102 @@ smalltalk.ASTInterpreterTest);
 
 
 
+smalltalk.addClass('ASTSteppingInterpreterTest', smalltalk.AbstractASTInterpreterTest, ['interpreter'], 'Compiler-Tests');
+smalltalk.addMethod(
+"_interpreter",
+smalltalk.method({
+selector: "interpreter",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=self["@interpreter"];
+if(($receiver = $2) == nil || $receiver == undefined){
+self["@interpreter"]=_st((smalltalk.ASTSteppingInterpreter || ASTSteppingInterpreter))._new();
+$1=self["@interpreter"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"interpreter",{}, smalltalk.ASTSteppingInterpreterTest)})},
+args: [],
+source: "interpreter\x0a\x09^ interpreter ifNil: [ interpreter := ASTSteppingInterpreter new ]",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["ASTSteppingInterpreter"]
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testAtEnd",
+smalltalk.method({
+selector: "testAtEnd",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1 + 2");
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._deny_(_st(_st(self)._interpreter())._atEnd());
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_(_st(_st(self)._interpreter())._atEnd());
+return self}, function($ctx1) {$ctx1.fill(self,"testAtEnd",{}, smalltalk.ASTSteppingInterpreterTest)})},
+args: [],
+source: "testAtEnd\x0a\x09self interpret: 'foo 1 + 2'.\x0a    self deny: self interpreter atEnd.\x0a\x0a    self interpreter step.\x0a    self deny: self interpreter atEnd.\x0a    \x0a    self interpreter step.\x0a    self deny: self interpreter atEnd.\x0a    \x0a    self interpreter step.\x0a    self deny: self interpreter atEnd.\x0a    \x0a    self interpreter step.\x0a    self assert: self interpreter atEnd",
+messageSends: ["interpret:", "deny:", "atEnd", "interpreter", "step", "assert:"],
+referencedClasses: []
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testMessageSend",
+smalltalk.method({
+selector: "testMessageSend",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1 + 2");
+_st(_st(self)._interpreter())._step();
+_st(_st(self)._interpreter())._step();
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(_st(self)._interpreter())._currentNode())._value(),(1));
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(_st(self)._interpreter())._currentNode())._value(),(2));
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(self)._interpreter())._result(),(3));
+return self}, function($ctx1) {$ctx1.fill(self,"testMessageSend",{}, smalltalk.ASTSteppingInterpreterTest)})},
+args: [],
+source: "testMessageSend\x0a\x09self interpret: 'foo 1 + 2'.\x0a    \x0a    \x22SequenceNode\x22\x0a    self interpreter step.\x0a    \x0a    \x22SendNode\x22\x0a    self interpreter step.\x0a    \x0a     \x22ValueNode\x22\x0a    self interpreter step.\x0a    self assert: self interpreter currentNode value equals: 1.\x0a    \x0a    \x22ValueNode\x22\x0a    self interpreter step.\x0a    self assert: self interpreter currentNode value equals: 2.\x0a    \x0a    \x22Result\x22\x0a    self interpreter step.\x0a    self assert: self interpreter result equals: 3\x0a\x09",
+messageSends: ["interpret:", "step", "interpreter", "assert:equals:", "value", "currentNode", "result"],
+referencedClasses: []
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+smalltalk.addMethod(
+"_testSimpleStepping",
+smalltalk.method({
+selector: "testSimpleStepping",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._interpret_("foo 1");
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_(_st(_st(_st(self)._interpreter())._result())._isNil());
+_st(_st(self)._interpreter())._step();
+_st(self)._assert_equals_(_st(_st(self)._interpreter())._result(),(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testSimpleStepping",{}, smalltalk.ASTSteppingInterpreterTest)})},
+args: [],
+source: "testSimpleStepping\x0a\x09self interpret: 'foo 1'.\x0a    \x0a    \x22SequenceNode\x22\x0a    self interpreter step.\x0a    \x0a    self assert: self interpreter result isNil.\x0a    \x0a    \x22ValueNode\x22\x0a    self interpreter step.\x0a    \x0a    self assert: self interpreter result equals: 1\x0a    \x0a\x09",
+messageSends: ["interpret:", "step", "interpreter", "assert:", "isNil", "result", "assert:equals:"],
+referencedClasses: []
+}),
+smalltalk.ASTSteppingInterpreterTest);
+
+
+
 smalltalk.addClass('CodeGeneratorTest', smalltalk.TestCase, ['receiver'], 'Compiler-Tests');
 smalltalk.addMethod(
 "_codeGeneratorClass",

+ 34 - 83
js/IDE.deploy.js

@@ -457,7 +457,7 @@ return smalltalk.withContext(function($ctx2) {
return _st(compiler)._parseExpres
 return smalltalk.withContext(function($ctx2) {
$1=_st(window)._alert_(_st(ex)._messageText());
 throw $early=[$1];
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
-$2=_st(_st(_st(compiler)._eval_(_st(compiler)._compile_forClass_(_st(_st("doIt ^[").__comma(aString)).__comma("] value"),(smalltalk.DoIt || DoIt))))._fn())._applyTo_arguments_(_st(self)._receiver(),[]);
+$2=_st(compiler)._evaluateExpression_(aString);
 return $2;
 }
 catch(e) {if(e===$early)return e[0]; throw e}
@@ -670,65 +670,20 @@ return $1;
 }),
 smalltalk.SourceArea);
 
-smalltalk.addMethod(
-"_selectionEnd",
-smalltalk.method({
-selector: "selectionEnd",
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionEnd", []);
-    return $1;
-}
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionEnd_",
-smalltalk.method({
-selector: "selectionEnd:",
-fn: function (anInteger) {
-    var self = this;
-    smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionEnd_", [anInteger]);
-    return self;
-}
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionStart",
-smalltalk.method({
-selector: "selectionStart",
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionStart", []);
-    return $1;
-}
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionStart_",
-smalltalk.method({
-selector: "selectionStart:",
-fn: function (anInteger) {
-    var self = this;
-    smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionStart_", [anInteger]);
-    return self;
-}
-}),
-smalltalk.SourceArea);
-
 smalltalk.addMethod(
 "_setEditorOn_",
 smalltalk.method({
 selector: "setEditorOn:",
-fn: function (aTextarea) {
-    var self = this;
-    self['@editor'] = CodeMirror.fromTextArea(aTextarea, {theme: "amber", lineNumbers: true, enterMode: "flat", matchBrackets: true, electricChars: false});
-    return self;
-}
+fn: function (aTextarea){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
+		theme: 'amber',
+                lineNumbers: true,
+                enterMode: 'flat',
+                matchBrackets: true,
+                electricChars: false
+	});
+return self}, function($ctx1) {$ctx1.fill(self,"setEditorOn:",{aTextarea:aTextarea}, smalltalk.SourceArea)})}
 }),
 smalltalk.SourceArea);
 
@@ -736,12 +691,12 @@ smalltalk.addMethod(
 "_val",
 smalltalk.method({
 selector: "val",
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(self['@editor'], "_getValue", []);
-    return $1;
-}
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(self["@editor"])._getValue();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"val",{}, smalltalk.SourceArea)})}
 }),
 smalltalk.SourceArea);
 
@@ -749,11 +704,10 @@ smalltalk.addMethod(
 "_val_",
 smalltalk.method({
 selector: "val:",
-fn: function (aString) {
-    var self = this;
-    smalltalk.send(self['@editor'], "_setValue_", [aString]);
-    return self;
-}
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self["@editor"])._setValue_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"val:",{aString:aString}, smalltalk.SourceArea)})}
 }),
 smalltalk.SourceArea);
 
@@ -1665,7 +1619,7 @@ selector: "compileMethodDefinitionFor:",
 fn: function (aClass){
 var self=this;
 var compiler,method,source,node;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3,$4,$6,$8,$9,$7,$5;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3,$4,$5,$6;
 var $early={};
 try {
 source=_st(self["@sourceArea"])._val();
@@ -1686,23 +1640,20 @@ return $3;
 };
 _st(compiler)._currentClass_(aClass);
 method=_st(compiler)._eval_(_st(compiler)._compileNode_(node));
-_st(method)._category_(self["@selectedProtocol"]);
-$4=_st(compiler)._unknownVariables();
-$5=(function(each){
-return smalltalk.withContext(function($ctx2) {
$6=_st(window)._at_(each);
-$7=(function(){
-return smalltalk.withContext(function($ctx3) {
$8=_st(window)._confirm_(_st(_st("Declare '").__comma(each)).__comma("' as instance variable?"));
-if(smalltalk.assert($8)){
+_st(_st(compiler)._unknownVariables())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
$4=_st(window)._at_(each);
+if(($receiver = $4) == nil || $receiver == undefined){
+$5=_st(window)._confirm_(_st(_st("Declare '").__comma(each)).__comma("' as instance variable?"));
+if(smalltalk.assert($5)){
 _st(self)._addInstanceVariableNamed_toClass_(each,aClass);
-$9=_st(self)._compileMethodDefinitionFor_(aClass);
-throw $early=[$9];
+$6=_st(self)._compileMethodDefinitionFor_(aClass);
+throw $early=[$6];
 };
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($6)._ifNil_($7);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})});
-_st($4)._do_($5);
-_st(aClass)._addCompiledMethod_(method);
-_st(compiler)._setupClass_(aClass);
+} else {
+return $4;
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(method,aClass,self["@selectedProtocol"]);
 _st(self)._updateMethodsList();
 _st(self)._selectMethod_(method);
 return self}

+ 40 - 109
js/IDE.js

@@ -593,15 +593,15 @@ return smalltalk.withContext(function($ctx2) {
return _st(compiler)._parseExpres
 return smalltalk.withContext(function($ctx2) {
$1=_st(window)._alert_(_st(ex)._messageText());
 throw $early=[$1];
 }, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
-$2=_st(_st(_st(compiler)._eval_(_st(compiler)._compile_forClass_(_st(_st("doIt ^[").__comma(aString)).__comma("] value"),(smalltalk.DoIt || DoIt))))._fn())._applyTo_arguments_(_st(self)._receiver(),[]);
+$2=_st(compiler)._evaluateExpression_(aString);
 return $2;
 }
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"eval:",{aString:aString,compiler:compiler}, smalltalk.SourceArea)})},
 args: ["aString"],
-source: "eval: aString\x0a\x09| compiler  |\x0a\x09compiler := Compiler new.\x0a\x09[compiler parseExpression: aString] on: Error do: [:ex |\x0a\x09\x09^window alert: ex messageText].\x0a\x09^(compiler eval: (compiler compile: 'doIt ^[', aString, '] value' forClass: DoIt)) fn applyTo: self receiver arguments: #()",
-messageSends: ["new", "on:do:", "alert:", "messageText", "parseExpression:", "applyTo:arguments:", "receiver", "fn", "eval:", "compile:forClass:", ","],
-referencedClasses: ["Compiler", "Error", "DoIt"]
+source: "eval: aString\x0a\x09| compiler  |\x0a\x09compiler := Compiler new.\x0a\x09[compiler parseExpression: aString] on: Error do: [:ex |\x0a\x09\x09^window alert: ex messageText].\x0a\x09^compiler evaluateExpression: aString",
+messageSends: ["new", "on:do:", "alert:", "messageText", "parseExpression:", "evaluateExpression:"],
+referencedClasses: ["Compiler", "Error"]
 }),
 smalltalk.SourceArea);
 
@@ -880,86 +880,21 @@ referencedClasses: []
 }),
 smalltalk.SourceArea);
 
-smalltalk.addMethod(
-"_selectionEnd",
-smalltalk.method({
-selector: "selectionEnd",
-category: 'accessing',
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionEnd", []);
-    return $1;
-},
-args: [],
-source: "selectionEnd\x0a   ^textarea element selectionEnd",
-messageSends: ["selectionEnd", "element"],
-referencedClasses: []
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionEnd_",
-smalltalk.method({
-selector: "selectionEnd:",
-category: 'accessing',
-fn: function (anInteger) {
-    var self = this;
-    smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionEnd_", [anInteger]);
-    return self;
-},
-args: ["anInteger"],
-source: "selectionEnd: anInteger\x0a   textarea element selectionEnd: anInteger",
-messageSends: ["selectionEnd:", "element"],
-referencedClasses: []
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionStart",
-smalltalk.method({
-selector: "selectionStart",
-category: 'accessing',
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionStart", []);
-    return $1;
-},
-args: [],
-source: "selectionStart\x0a   ^textarea element selectionStart",
-messageSends: ["selectionStart", "element"],
-referencedClasses: []
-}),
-smalltalk.SourceArea);
-
-smalltalk.addMethod(
-"_selectionStart_",
-smalltalk.method({
-selector: "selectionStart:",
-category: 'accessing',
-fn: function (anInteger) {
-    var self = this;
-    smalltalk.send(smalltalk.send(textarea, "_element", []), "_selectionStart_", [anInteger]);
-    return self;
-},
-args: ["anInteger"],
-source: "selectionStart: anInteger\x0a   textarea element selectionStart: anInteger",
-messageSends: ["selectionStart:", "element"],
-referencedClasses: []
-}),
-smalltalk.SourceArea);
-
 smalltalk.addMethod(
 "_setEditorOn_",
 smalltalk.method({
 selector: "setEditorOn:",
 category: 'accessing',
-fn: function (aTextarea) {
-    var self = this;
-    self['@editor'] = CodeMirror.fromTextArea(aTextarea, {theme: "amber", lineNumbers: true, enterMode: "flat", matchBrackets: true, electricChars: false});
-    return self;
-},
+fn: function (aTextarea){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
+		theme: 'amber',
+                lineNumbers: true,
+                enterMode: 'flat',
+                matchBrackets: true,
+                electricChars: false
+	});
+return self}, function($ctx1) {$ctx1.fill(self,"setEditorOn:",{aTextarea:aTextarea}, smalltalk.SourceArea)})},
 args: ["aTextarea"],
 source: "setEditorOn: aTextarea\x0a\x09<self['@editor'] = CodeMirror.fromTextArea(aTextarea, {\x0a\x09\x09theme: 'amber',\x0a                lineNumbers: true,\x0a                enterMode: 'flat',\x0a                matchBrackets: true,\x0a                electricChars: false\x0a\x09})>",
 messageSends: [],
@@ -972,12 +907,12 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "val",
 category: 'accessing',
-fn: function () {
-    var self = this;
-    var $1;
-    $1 = smalltalk.send(self['@editor'], "_getValue", []);
-    return $1;
-},
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(self["@editor"])._getValue();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"val",{}, smalltalk.SourceArea)})},
 args: [],
 source: "val\x0a    ^editor getValue",
 messageSends: ["getValue"],
@@ -990,11 +925,10 @@ smalltalk.addMethod(
 smalltalk.method({
 selector: "val:",
 category: 'accessing',
-fn: function (aString) {
-    var self = this;
-    smalltalk.send(self['@editor'], "_setValue_", [aString]);
-    return self;
-},
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self["@editor"])._setValue_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"val:",{aString:aString}, smalltalk.SourceArea)})},
 args: ["aString"],
 source: "val: aString\x0a    editor setValue: aString",
 messageSends: ["setValue:"],
@@ -2171,7 +2105,7 @@ category: 'actions',
 fn: function (aClass){
 var self=this;
 var compiler,method,source,node;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3,$4,$6,$8,$9,$7,$5;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3,$4,$5,$6;
 var $early={};
 try {
 source=_st(self["@sourceArea"])._val();
@@ -2192,32 +2126,29 @@ return $3;
 };
 _st(compiler)._currentClass_(aClass);
 method=_st(compiler)._eval_(_st(compiler)._compileNode_(node));
-_st(method)._category_(self["@selectedProtocol"]);
-$4=_st(compiler)._unknownVariables();
-$5=(function(each){
-return smalltalk.withContext(function($ctx2) {
$6=_st(window)._at_(each);
-$7=(function(){
-return smalltalk.withContext(function($ctx3) {
$8=_st(window)._confirm_(_st(_st("Declare '").__comma(each)).__comma("' as instance variable?"));
-if(smalltalk.assert($8)){
+_st(_st(compiler)._unknownVariables())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
$4=_st(window)._at_(each);
+if(($receiver = $4) == nil || $receiver == undefined){
+$5=_st(window)._confirm_(_st(_st("Declare '").__comma(each)).__comma("' as instance variable?"));
+if(smalltalk.assert($5)){
 _st(self)._addInstanceVariableNamed_toClass_(each,aClass);
-$9=_st(self)._compileMethodDefinitionFor_(aClass);
-throw $early=[$9];
+$6=_st(self)._compileMethodDefinitionFor_(aClass);
+throw $early=[$6];
 };
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($6)._ifNil_($7);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})});
-_st($4)._do_($5);
-_st(aClass)._addCompiledMethod_(method);
-_st(compiler)._setupClass_(aClass);
+} else {
+return $4;
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._installMethod_forClass_category_(method,aClass,self["@selectedProtocol"]);
 _st(self)._updateMethodsList();
 _st(self)._selectMethod_(method);
 return self}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"compileMethodDefinitionFor:",{aClass:aClass,compiler:compiler,method:method,source:source,node:node}, smalltalk.Browser)})},
 args: ["aClass"],
-source: "compileMethodDefinitionFor: aClass\x0a    | compiler method source node | \x0a    source := sourceArea val.\x0a    selectedProtocol ifNil: [selectedProtocol := selectedMethod category].\x0a    compiler := Compiler new.\x0a    compiler source: source.\x0a    node := compiler parse: source.\x0a    node isParseFailure ifTrue: [\x0a\x09^window alert: 'PARSE ERROR: ', node reason, ', position: ', node position asString].\x0a    compiler currentClass: aClass.\x0a    method := compiler eval: (compiler compileNode: node).\x0a    method category: selectedProtocol.\x0a    compiler unknownVariables do: [:each |\x0a         \x22Do not try to redeclare javascript's objects\x22\x0a         (window at: each) ifNil: [\x0a\x09 \x09(window confirm: 'Declare ''', each, ''' as instance variable?') ifTrue: [\x0a\x09\x09\x09self addInstanceVariableNamed: each toClass: aClass.\x0a\x09\x09\x09^self compileMethodDefinitionFor: aClass]]].\x0a    aClass addCompiledMethod: method.\x0a    compiler setupClass: aClass.\x0a    self updateMethodsList.\x0a    self selectMethod: method",
-messageSends: ["val", "ifNil:", "category", "new", "source:", "parse:", "ifTrue:", "alert:", ",", "asString", "position", "reason", "isParseFailure", "currentClass:", "eval:", "compileNode:", "category:", "do:", "addInstanceVariableNamed:toClass:", "compileMethodDefinitionFor:", "confirm:", "at:", "unknownVariables", "addCompiledMethod:", "setupClass:", "updateMethodsList", "selectMethod:"],
-referencedClasses: ["Compiler"]
+source: "compileMethodDefinitionFor: aClass\x0a    | compiler method source node | \x0a    source := sourceArea val.\x0a    selectedProtocol ifNil: [ selectedProtocol := selectedMethod category ].\x0a    compiler := Compiler new.\x0a    compiler source: source.\x0a    node := compiler parse: source.\x0a    node isParseFailure ifTrue: [\x0a\x09^window alert: 'PARSE ERROR: ', node reason, ', position: ', node position asString].\x0a    compiler currentClass: aClass.\x0a    method := compiler eval: (compiler compileNode: node).\x0a    compiler unknownVariables do: [:each |\x0a         \x22Do not try to redeclare javascript's objects\x22\x0a         (window at: each) ifNil: [\x0a\x09 \x09(window confirm: 'Declare ''', each, ''' as instance variable?') ifTrue: [\x0a\x09\x09\x09self addInstanceVariableNamed: each toClass: aClass.\x0a\x09\x09\x09^self compileMethodDefinitionFor: aClass]]].\x0a    ClassBuilder new installMethod: method forClass: aClass category: selectedProtocol.\x0a    self updateMethodsList.\x0a    self selectMethod: method",
+messageSends: ["val", "ifNil:", "category", "new", "source:", "parse:", "ifTrue:", "alert:", ",", "asString", "position", "reason", "isParseFailure", "currentClass:", "eval:", "compileNode:", "do:", "addInstanceVariableNamed:toClass:", "compileMethodDefinitionFor:", "confirm:", "at:", "unknownVariables", "installMethod:forClass:category:", "updateMethodsList", "selectMethod:"],
+referencedClasses: ["Compiler", "ClassBuilder"]
 }),
 smalltalk.Browser);
 

+ 2 - 0
js/Kernel-Announcements.js

@@ -1,5 +1,6 @@
 smalltalk.addPackage('Kernel-Announcements', {});
 smalltalk.addClass('AnnouncementSubscription', smalltalk.Object, ['block', 'announcementClass'], 'Kernel-Announcements');
+smalltalk.AnnouncementSubscription.comment="The subscription is a single entry in a subscription registry of an `Announcer`.\x0aSeveral subscriptions by the same object is possible."
 smalltalk.addMethod(
 "_announcementClass",
 smalltalk.method({
@@ -109,6 +110,7 @@ smalltalk.AnnouncementSubscription);
 
 
 smalltalk.addClass('Announcer', smalltalk.Object, ['registry', 'subscriptions'], 'Kernel-Announcements');
+smalltalk.Announcer.comment="The code is based on the announcements as [described by Vassili Bykov](http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?searchCategory=Announcements%20Framework).\x0aThe Announcer holds annoncement subscriptions (`AnnouncementSubscription`) in a private registry.\x0a\x0aUse `#on:do:` to register subscriptions."
 smalltalk.addMethod(
 "_announce_",
 smalltalk.method({

+ 73 - 21
js/Kernel-Classes.deploy.js

@@ -890,14 +890,24 @@ smalltalk.method({
 selector: "basicClass:instanceVariableNames:",
 fn: function (aClass,aString){
 var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._basicClass_instanceVariables_(aClass,_st(self)._instanceVariableNamesFor_(aString));
+return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariableNames:",{aClass:aClass,aString:aString}, smalltalk.ClassBuilder)})}
+}),
+smalltalk.ClassBuilder);
+
+smalltalk.addMethod(
+"_basicClass_instanceVariables_",
+smalltalk.method({
+selector: "basicClass:instanceVariables:",
+fn: function (aClass,aCollection){
+var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(aClass)._isMetaclass();
 if(! smalltalk.assert($1)){
 _st(self)._error_(_st(_st(aClass)._name()).__comma(" is not a metaclass"));
 };
-_st(aClass)._basicAt_put_("iVarNames",_st(self)._instanceVariableNamesFor_(aString));
-_st(self)._setupClass_(aClass);
-return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariableNames:",{aClass:aClass,aString:aString}, smalltalk.ClassBuilder)})}
+_st(aClass)._basicAt_put_("iVarNames",aCollection);
+return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariables:",{aClass:aClass,aCollection:aCollection}, smalltalk.ClassBuilder)})}
 }),
 smalltalk.ClassBuilder);
 
@@ -935,6 +945,7 @@ fn: function (aClass,aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 _st(self)._basicClass_instanceVariableNames_(aClass,aString);
+_st(self)._setupClass_(aClass);
 $1=_st((smalltalk.ClassDefinitionChanged || ClassDefinitionChanged))._new();
 _st($1)._theClass_(aClass);
 $2=_st($1)._yourself();
@@ -952,17 +963,45 @@ var self=this;
 var newClass;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 newClass=_st(self)._addSubclassOf_named_instanceVariableNames_package_(_st(aClass)._superclass(),aString,_st(aClass)._instanceVariableNames(),_st(_st(aClass)._package())._name());
-_st(self)._setupClass_(newClass);
+_st(self)._copyClass_to_(aClass,newClass);
+$1=newClass;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"copyClass:named:",{aClass:aClass,aString:aString,newClass:newClass}, smalltalk.ClassBuilder)})}
+}),
+smalltalk.ClassBuilder);
+
+smalltalk.addMethod(
+"_copyClass_to_",
+smalltalk.method({
+selector: "copyClass:to:",
+fn: function (aClass,anotherClass){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(anotherClass)._comment_(_st(aClass)._comment());
 _st(_st(_st(aClass)._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),newClass,_st(each)._category());
+return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),anotherClass,_st(each)._category());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+_st(self)._basicClass_instanceVariables_(_st(anotherClass)._class(),_st(_st(aClass)._class())._instanceVariableNames());
 _st(_st(_st(_st(aClass)._class())._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(newClass)._class(),_st(each)._category());
+return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(anotherClass)._class(),_st(each)._category());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(newClass);
-$1=newClass;
+_st(self)._setupClass_(anotherClass);
+return self}, function($ctx1) {$ctx1.fill(self,"copyClass:to:",{aClass:aClass,anotherClass:anotherClass}, smalltalk.ClassBuilder)})}
+}),
+smalltalk.ClassBuilder);
+
+smalltalk.addMethod(
+"_installMethod_forClass_category_",
+smalltalk.method({
+selector: "installMethod:forClass:category:",
+fn: function (aCompiledMethod,aBehavior,aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+_st(aCompiledMethod)._category_(aString);
+_st(aBehavior)._addCompiledMethod_(aCompiledMethod);
+_st(self)._setupClass_(aBehavior);
+$1=aCompiledMethod;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"copyClass:named:",{aClass:aClass,aString:aString,newClass:newClass}, smalltalk.ClassBuilder)})}
+}, function($ctx1) {$ctx1.fill(self,"installMethod:forClass:category:",{aCompiledMethod:aCompiledMethod,aBehavior:aBehavior,aString:aString}, smalltalk.ClassBuilder)})}
 }),
 smalltalk.ClassBuilder);
 
@@ -981,6 +1020,17 @@ return $1;
 }),
 smalltalk.ClassBuilder);
 
+smalltalk.addMethod(
+"_migrateClass_superclass_",
+smalltalk.method({
+selector: "migrateClass:superclass:",
+fn: function (aClass,anotherClass){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._migrateClassNamed_superclass_instanceVariableNames_package_(_st(aClass)._name(),anotherClass,_st(aClass)._instanceVariableNames(),_st(_st(aClass)._package())._name());
+return self}, function($ctx1) {$ctx1.fill(self,"migrateClass:superclass:",{aClass:aClass,anotherClass:anotherClass}, smalltalk.ClassBuilder)})}
+}),
+smalltalk.ClassBuilder);
+
 smalltalk.addMethod(
 "_migrateClassNamed_superclass_instanceVariableNames_package_",
 smalltalk.method({
@@ -990,19 +1040,21 @@ var self=this;
 var oldClass,newClass;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3;
 oldClass=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._at_(aString);
-$1=self;
-_st($1)._basicRenameClass_to_(oldClass,_st("Old").__comma(aString));
-$2=_st($1)._basicRemoveClass_(oldClass);
+_st(self)._basicRenameClass_to_(oldClass,_st("Old").__comma(aString));
 newClass=_st(self)._addSubclassOf_named_instanceVariableNames_package_(aClass,aString,aCollection,packageName);
-_st(self)._setupClass_(newClass);
-_st(newClass)._comment_(_st(oldClass)._comment());
-_st(_st(_st(oldClass)._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),newClass,_st(each)._category());
+_st(_st(oldClass)._subclasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._migrateClass_superclass_(each,newClass);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(_st(_st(_st(oldClass)._class())._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(newClass)._class(),_st(each)._category());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(newClass);
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._copyClass_to_(oldClass,newClass);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_((smalltalk.Error || Error),(function(exception){
+return smalltalk.withContext(function($ctx2) {
$1=self;
+_st($1)._basicRemoveClass_(newClass);
+$2=_st($1)._basicRenameClass_to_(oldClass,aString);
+$2;
+return _st(exception)._signal();
+}, function($ctx2) {$ctx2.fillBlock({exception:exception},$ctx1)})}));
+_st(self)._basicRemoveClass_(oldClass);
 $3=newClass;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"migrateClassNamed:superclass:instanceVariableNames:package:",{aString:aString,aClass:aClass,aCollection:aCollection,packageName:packageName,oldClass:oldClass,newClass:newClass}, smalltalk.ClassBuilder)})}
@@ -1130,7 +1182,7 @@ return _st(chunk)._isEmpty();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
 return smalltalk.withContext(function($ctx2) {
return _st(self)._compileMethod_(chunk);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-_st(_st((smalltalk.Compiler || Compiler))._new())._setupClass_(self["@class"]);
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._setupClass_(self["@class"]);
 return self}, function($ctx1) {$ctx1.fill(self,"scanFrom:",{aChunkParser:aChunkParser,chunk:chunk}, smalltalk.ClassCategoryReader)})}
 }),
 smalltalk.ClassCategoryReader);

+ 112 - 40
js/Kernel-Classes.js

@@ -1195,17 +1195,32 @@ selector: "basicClass:instanceVariableNames:",
 category: 'private',
 fn: function (aClass,aString){
 var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._basicClass_instanceVariables_(aClass,_st(self)._instanceVariableNamesFor_(aString));
+return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariableNames:",{aClass:aClass,aString:aString}, smalltalk.ClassBuilder)})},
+args: ["aClass", "aString"],
+source: "basicClass: aClass instanceVariableNames: aString\x0a\x09self basicClass: aClass instanceVariables: (self instanceVariableNamesFor: aString)",
+messageSends: ["basicClass:instanceVariables:", "instanceVariableNamesFor:"],
+referencedClasses: []
+}),
+smalltalk.ClassBuilder);
+
+smalltalk.addMethod(
+"_basicClass_instanceVariables_",
+smalltalk.method({
+selector: "basicClass:instanceVariables:",
+category: 'private',
+fn: function (aClass,aCollection){
+var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 $1=_st(aClass)._isMetaclass();
 if(! smalltalk.assert($1)){
 _st(self)._error_(_st(_st(aClass)._name()).__comma(" is not a metaclass"));
 };
-_st(aClass)._basicAt_put_("iVarNames",_st(self)._instanceVariableNamesFor_(aString));
-_st(self)._setupClass_(aClass);
-return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariableNames:",{aClass:aClass,aString:aString}, smalltalk.ClassBuilder)})},
-args: ["aClass", "aString"],
-source: "basicClass: aClass instanceVariableNames: aString\x0a\x0a\x09aClass isMetaclass ifFalse: [self error: aClass name, ' is not a metaclass'].\x0a\x09aClass basicAt: 'iVarNames' put: (self instanceVariableNamesFor: aString).\x0a    \x0a\x09self setupClass: aClass",
-messageSends: ["ifFalse:", "error:", ",", "name", "isMetaclass", "basicAt:put:", "instanceVariableNamesFor:", "setupClass:"],
+_st(aClass)._basicAt_put_("iVarNames",aCollection);
+return self}, function($ctx1) {$ctx1.fill(self,"basicClass:instanceVariables:",{aClass:aClass,aCollection:aCollection}, smalltalk.ClassBuilder)})},
+args: ["aClass", "aCollection"],
+source: "basicClass: aClass instanceVariables: aCollection\x0a\x0a\x09aClass isMetaclass ifFalse: [self error: aClass name, ' is not a metaclass'].\x0a\x09aClass basicAt: 'iVarNames' put: aCollection",
+messageSends: ["ifFalse:", "error:", ",", "name", "isMetaclass", "basicAt:put:"],
 referencedClasses: []
 }),
 smalltalk.ClassBuilder);
@@ -1250,19 +1265,20 @@ smalltalk.addMethod(
 "_class_instanceVariableNames_",
 smalltalk.method({
 selector: "class:instanceVariableNames:",
-category: 'class creation',
+category: 'api',
 fn: function (aClass,aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 _st(self)._basicClass_instanceVariableNames_(aClass,aString);
+_st(self)._setupClass_(aClass);
 $1=_st((smalltalk.ClassDefinitionChanged || ClassDefinitionChanged))._new();
 _st($1)._theClass_(aClass);
 $2=_st($1)._yourself();
 _st(_st((smalltalk.SystemAnnouncer || SystemAnnouncer))._current())._announce_($2);
 return self}, function($ctx1) {$ctx1.fill(self,"class:instanceVariableNames:",{aClass:aClass,aString:aString}, smalltalk.ClassBuilder)})},
 args: ["aClass", "aString"],
-source: "class: aClass instanceVariableNames: aString\x0a\x09self basicClass: aClass instanceVariableNames: aString.\x0a    \x0a    SystemAnnouncer current\x0a    \x09announce: (ClassDefinitionChanged new\x0a        \x09theClass: aClass;\x0a            yourself)",
-messageSends: ["basicClass:instanceVariableNames:", "announce:", "theClass:", "new", "yourself", "current"],
+source: "class: aClass instanceVariableNames: aString\x0a\x09self basicClass: aClass instanceVariableNames: aString.\x0a    self setupClass: aClass.\x0a    \x0a    SystemAnnouncer current\x0a    \x09announce: (ClassDefinitionChanged new\x0a        \x09theClass: aClass;\x0a            yourself)",
+messageSends: ["basicClass:instanceVariableNames:", "setupClass:", "announce:", "theClass:", "new", "yourself", "current"],
 referencedClasses: ["ClassDefinitionChanged", "SystemAnnouncer"]
 }),
 smalltalk.ClassBuilder);
@@ -1277,24 +1293,62 @@ var self=this;
 var newClass;
 return smalltalk.withContext(function($ctx1) { 
var $1;
 newClass=_st(self)._addSubclassOf_named_instanceVariableNames_package_(_st(aClass)._superclass(),aString,_st(aClass)._instanceVariableNames(),_st(_st(aClass)._package())._name());
-_st(self)._setupClass_(newClass);
-_st(_st(_st(aClass)._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),newClass,_st(each)._category());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(_st(_st(_st(aClass)._class())._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(newClass)._class(),_st(each)._category());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(newClass);
+_st(self)._copyClass_to_(aClass,newClass);
 $1=newClass;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"copyClass:named:",{aClass:aClass,aString:aString,newClass:newClass}, smalltalk.ClassBuilder)})},
 args: ["aClass", "aString"],
-source: "copyClass: aClass named: aString\x0a\x09| newClass |\x0a\x0a\x09newClass := self \x0a\x09\x09addSubclassOf: aClass superclass\x0a\x09\x09named: aString \x0a\x09\x09instanceVariableNames: aClass instanceVariableNames \x0a\x09\x09package: aClass package name.\x0a\x0a\x09self setupClass: newClass.\x0a\x0a\x09aClass methodDictionary values do: [:each |\x0a\x09\x09Compiler new install: each source forClass: newClass category: each category].\x0a\x0a\x09aClass class methodDictionary values do: [:each |\x0a\x09\x09Compiler new install: each source forClass: newClass class category: each category].\x0a\x0a\x09self setupClass: newClass.\x0a\x09^newClass",
-messageSends: ["addSubclassOf:named:instanceVariableNames:package:", "superclass", "instanceVariableNames", "name", "package", "setupClass:", "do:", "install:forClass:category:", "source", "category", "new", "values", "methodDictionary", "class"],
+source: "copyClass: aClass named: aString\x0a\x09| newClass |\x0a\x0a\x09newClass := self \x0a\x09\x09addSubclassOf: aClass superclass\x0a\x09\x09named: aString \x0a\x09\x09instanceVariableNames: aClass instanceVariableNames \x0a\x09\x09package: aClass package name.\x0a\x0a\x09self copyClass: aClass to: newClass.\x0a    \x0a\x09^newClass",
+messageSends: ["addSubclassOf:named:instanceVariableNames:package:", "superclass", "instanceVariableNames", "name", "package", "copyClass:to:"],
+referencedClasses: []
+}),
+smalltalk.ClassBuilder);
+
+smalltalk.addMethod(
+"_copyClass_to_",
+smalltalk.method({
+selector: "copyClass:to:",
+category: 'private',
+fn: function (aClass,anotherClass){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(anotherClass)._comment_(_st(aClass)._comment());
+_st(_st(_st(aClass)._methodDictionary())._values())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),anotherClass,_st(each)._category());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+_st(self)._basicClass_instanceVariables_(_st(anotherClass)._class(),_st(_st(aClass)._class())._instanceVariableNames());
+_st(_st(_st(_st(aClass)._class())._methodDictionary())._values())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(anotherClass)._class(),_st(each)._category());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+_st(self)._setupClass_(anotherClass);
+return self}, function($ctx1) {$ctx1.fill(self,"copyClass:to:",{aClass:aClass,anotherClass:anotherClass}, smalltalk.ClassBuilder)})},
+args: ["aClass", "anotherClass"],
+source: "copyClass: aClass to: anotherClass\x0a\x0a\x09anotherClass comment: aClass comment.\x0a\x0a\x09aClass methodDictionary values do: [ :each |\x0a\x09\x09Compiler new install: each source forClass: anotherClass category: each category ].\x0a\x0a\x09self basicClass: anotherClass class instanceVariables: aClass class instanceVariableNames.\x0a\x0a\x09aClass class methodDictionary values do: [ :each |\x0a\x09\x09Compiler new install: each source forClass: anotherClass class category: each category ].\x0a\x0a\x09self setupClass: anotherClass",
+messageSends: ["comment:", "comment", "do:", "install:forClass:category:", "source", "category", "new", "values", "methodDictionary", "basicClass:instanceVariables:", "class", "instanceVariableNames", "setupClass:"],
 referencedClasses: ["Compiler"]
 }),
 smalltalk.ClassBuilder);
 
+smalltalk.addMethod(
+"_installMethod_forClass_category_",
+smalltalk.method({
+selector: "installMethod:forClass:category:",
+category: 'api',
+fn: function (aCompiledMethod,aBehavior,aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+_st(aCompiledMethod)._category_(aString);
+_st(aBehavior)._addCompiledMethod_(aCompiledMethod);
+_st(self)._setupClass_(aBehavior);
+$1=aCompiledMethod;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"installMethod:forClass:category:",{aCompiledMethod:aCompiledMethod,aBehavior:aBehavior,aString:aString}, smalltalk.ClassBuilder)})},
+args: ["aCompiledMethod", "aBehavior", "aString"],
+source: "installMethod: aCompiledMethod forClass: aBehavior category: aString\x0a\x09aCompiledMethod category: aString.\x0a\x09aBehavior addCompiledMethod: aCompiledMethod.\x0a    self setupClass: aBehavior.\x0a\x09^aCompiledMethod",
+messageSends: ["category:", "addCompiledMethod:", "setupClass:"],
+referencedClasses: []
+}),
+smalltalk.ClassBuilder);
+
 smalltalk.addMethod(
 "_instanceVariableNamesFor_",
 smalltalk.method({
@@ -1315,6 +1369,22 @@ referencedClasses: []
 }),
 smalltalk.ClassBuilder);
 
+smalltalk.addMethod(
+"_migrateClass_superclass_",
+smalltalk.method({
+selector: "migrateClass:superclass:",
+category: 'private',
+fn: function (aClass,anotherClass){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
_st(self)._migrateClassNamed_superclass_instanceVariableNames_package_(_st(aClass)._name(),anotherClass,_st(aClass)._instanceVariableNames(),_st(_st(aClass)._package())._name());
+return self}, function($ctx1) {$ctx1.fill(self,"migrateClass:superclass:",{aClass:aClass,anotherClass:anotherClass}, smalltalk.ClassBuilder)})},
+args: ["aClass", "anotherClass"],
+source: "migrateClass: aClass superclass: anotherClass\x0a\x09self \x0a    \x09migrateClassNamed: aClass name\x0a        superclass: anotherClass\x0a        instanceVariableNames: aClass instanceVariableNames\x0a        package: aClass package name",
+messageSends: ["migrateClassNamed:superclass:instanceVariableNames:package:", "name", "instanceVariableNames", "package"],
+referencedClasses: []
+}),
+smalltalk.ClassBuilder);
+
 smalltalk.addMethod(
 "_migrateClassNamed_superclass_instanceVariableNames_package_",
 smalltalk.method({
@@ -1325,26 +1395,28 @@ var self=this;
 var oldClass,newClass;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2,$3;
 oldClass=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._at_(aString);
-$1=self;
-_st($1)._basicRenameClass_to_(oldClass,_st("Old").__comma(aString));
-$2=_st($1)._basicRemoveClass_(oldClass);
+_st(self)._basicRenameClass_to_(oldClass,_st("Old").__comma(aString));
 newClass=_st(self)._addSubclassOf_named_instanceVariableNames_package_(aClass,aString,aCollection,packageName);
-_st(self)._setupClass_(newClass);
-_st(newClass)._comment_(_st(oldClass)._comment());
-_st(_st(_st(oldClass)._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),newClass,_st(each)._category());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(_st(_st(_st(oldClass)._class())._methodDictionary())._values())._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(_st((smalltalk.Compiler || Compiler))._new())._install_forClass_category_(_st(each)._source(),_st(newClass)._class(),_st(each)._category());
+_st(_st(oldClass)._subclasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._migrateClass_superclass_(each,newClass);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-_st(self)._setupClass_(newClass);
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(self)._copyClass_to_(oldClass,newClass);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_((smalltalk.Error || Error),(function(exception){
+return smalltalk.withContext(function($ctx2) {
$1=self;
+_st($1)._basicRemoveClass_(newClass);
+$2=_st($1)._basicRenameClass_to_(oldClass,aString);
+$2;
+return _st(exception)._signal();
+}, function($ctx2) {$ctx2.fillBlock({exception:exception},$ctx1)})}));
+_st(self)._basicRemoveClass_(oldClass);
 $3=newClass;
 return $3;
 }, function($ctx1) {$ctx1.fill(self,"migrateClassNamed:superclass:instanceVariableNames:package:",{aString:aString,aClass:aClass,aCollection:aCollection,packageName:packageName,oldClass:oldClass,newClass:newClass}, smalltalk.ClassBuilder)})},
 args: ["aString", "aClass", "aCollection", "packageName"],
-source: "migrateClassNamed: aString superclass: aClass instanceVariableNames: aCollection package: packageName\x0a\x09| oldClass newClass |\x0a    \x0a    oldClass := Smalltalk current at: aString.\x0a    \x0a    \x22Rename the class for existing instances\x22\x0a\x09self \x0a    \x09basicRenameClass: oldClass to: 'Old', aString;\x0a        basicRemoveClass: oldClass.\x0a        \x0a    newClass := self \x0a\x09\x09addSubclassOf: aClass\x0a\x09\x09named: aString \x0a\x09\x09instanceVariableNames: aCollection\x0a\x09\x09package: packageName.\x0a\x0a\x09self setupClass: newClass.\x0a\x0a\x09newClass comment: oldClass comment.\x0a\x0a\x09oldClass methodDictionary values do: [:each |\x0a\x09\x09Compiler new install: each source forClass: newClass category: each category].\x0a\x0a\x09oldClass class methodDictionary values do: [:each |\x0a\x09\x09Compiler new install: each source forClass: newClass class category: each category].\x0a\x0a\x09self setupClass: newClass.\x0a    \x0a\x09^newClass",
-messageSends: ["at:", "current", "basicRenameClass:to:", ",", "basicRemoveClass:", "addSubclassOf:named:instanceVariableNames:package:", "setupClass:", "comment:", "comment", "do:", "install:forClass:category:", "source", "category", "new", "values", "methodDictionary", "class"],
-referencedClasses: ["Smalltalk", "Compiler"]
+source: "migrateClassNamed: aString superclass: aClass instanceVariableNames: aCollection package: packageName\x0a\x09| oldClass newClass |\x0a    \x0a    oldClass := Smalltalk current at: aString.\x0a    \x0a    \x22Rename the old class for existing instances\x22\x0a\x09self basicRenameClass: oldClass to: 'Old', aString.\x0a    \x0a    newClass := self \x0a\x09\x09addSubclassOf: aClass\x0a\x09\x09named: aString \x0a\x09\x09instanceVariableNames: aCollection\x0a\x09\x09package: packageName.\x0a\x0a\x09oldClass subclasses do: [ :each |\x0a    \x09self migrateClass: each superclass: newClass ].\x0a\x0a    [ self copyClass: oldClass to: newClass ] \x0a    \x09on: Error\x0a        do: [ :exception |\x0a        \x09self \x0a            \x09basicRemoveClass: newClass;\x0a            \x09basicRenameClass: oldClass to: aString.\x0a            exception signal ].\x0a            \x0a    self basicRemoveClass: oldClass.\x0a\x09^newClass",
+messageSends: ["at:", "current", "basicRenameClass:to:", ",", "addSubclassOf:named:instanceVariableNames:package:", "do:", "migrateClass:superclass:", "subclasses", "on:do:", "basicRemoveClass:", "signal", "copyClass:to:"],
+referencedClasses: ["Smalltalk", "Error"]
 }),
 smalltalk.ClassBuilder);
 
@@ -1352,7 +1424,7 @@ smalltalk.addMethod(
 "_renameClass_to_",
 smalltalk.method({
 selector: "renameClass:to:",
-category: 'class creation',
+category: 'api',
 fn: function (aClass,aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1,$2;
@@ -1373,7 +1445,7 @@ smalltalk.addMethod(
 "_setupClass_",
 smalltalk.method({
 selector: "setupClass:",
-category: 'class creation',
+category: 'api',
 fn: function (aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
smalltalk.init(aClass);;
@@ -1389,7 +1461,7 @@ smalltalk.addMethod(
 "_superclass_subclass_",
 smalltalk.method({
 selector: "superclass:subclass:",
-category: 'class creation',
+category: 'api',
 fn: function (aClass,aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
@@ -1407,7 +1479,7 @@ smalltalk.addMethod(
 "_superclass_subclass_instanceVariableNames_package_",
 smalltalk.method({
 selector: "superclass:subclass:instanceVariableNames:package:",
-category: 'class creation',
+category: 'api',
 fn: function (aClass,aString,aString2,aString3){
 var self=this;
 var newClass;
@@ -1506,12 +1578,12 @@ return _st(chunk)._isEmpty();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
 return smalltalk.withContext(function($ctx2) {
return _st(self)._compileMethod_(chunk);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-_st(_st((smalltalk.Compiler || Compiler))._new())._setupClass_(self["@class"]);
+_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._setupClass_(self["@class"]);
 return self}, function($ctx1) {$ctx1.fill(self,"scanFrom:",{aChunkParser:aChunkParser,chunk:chunk}, smalltalk.ClassCategoryReader)})},
 args: ["aChunkParser"],
-source: "scanFrom: aChunkParser\x0a\x09| chunk |\x0a\x09[chunk := aChunkParser nextChunk.\x0a\x09chunk isEmpty] whileFalse: [\x0a\x09    self compileMethod: chunk].\x0a\x09Compiler new setupClass: class",
+source: "scanFrom: aChunkParser\x0a\x09| chunk |\x0a\x09[chunk := aChunkParser nextChunk.\x0a\x09chunk isEmpty] whileFalse: [\x0a\x09    self compileMethod: chunk].\x0a\x09ClassBuilder new setupClass: class",
 messageSends: ["whileFalse:", "compileMethod:", "nextChunk", "isEmpty", "setupClass:", "new"],
-referencedClasses: ["Compiler"]
+referencedClasses: ["ClassBuilder"]
 }),
 smalltalk.ClassCategoryReader);
 

File diff suppressed because it is too large
+ 133 - 131
js/Kernel-Collections.deploy.js


File diff suppressed because it is too large
+ 134 - 132
js/Kernel-Collections.js


+ 82 - 0
js/Kernel-Exceptions.deploy.js

@@ -119,6 +119,88 @@ return $1;
 smalltalk.Error.klass);
 
 
+smalltalk.addClass('JavaScriptException', smalltalk.Error, ['exception'], 'Kernel-Exceptions');
+smalltalk.addMethod(
+"_context_",
+smalltalk.method({
+selector: "context:",
+fn: function (aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self.context = aMethodContext;
+return self}, function($ctx1) {$ctx1.fill(self,"context:",{aMethodContext:aMethodContext}, smalltalk.JavaScriptException)})}
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_exception",
+smalltalk.method({
+selector: "exception",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@exception"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"exception",{}, smalltalk.JavaScriptException)})}
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_exception_",
+smalltalk.method({
+selector: "exception:",
+fn: function (anException){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@exception"]=anException;
+return self}, function($ctx1) {$ctx1.fill(self,"exception:",{anException:anException}, smalltalk.JavaScriptException)})}
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return 'JavaScript exception: ' + self["@exception"].toString();
+return self}, function($ctx1) {$ctx1.fill(self,"messageText",{}, smalltalk.JavaScriptException)})}
+}),
+smalltalk.JavaScriptException);
+
+
+smalltalk.addMethod(
+"_on_",
+smalltalk.method({
+selector: "on:",
+fn: function (anException){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$3,$1;
+$2=_st(self)._new();
+_st($2)._exception_(anException);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:",{anException:anException}, smalltalk.JavaScriptException.klass)})}
+}),
+smalltalk.JavaScriptException.klass);
+
+smalltalk.addMethod(
+"_on_context_",
+smalltalk.method({
+selector: "on:context:",
+fn: function (anException,aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$3,$1;
+$2=_st(self)._new();
+_st($2)._exception_(anException);
+_st($2)._context_(aMethodContext);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:context:",{anException:anException,aMethodContext:aMethodContext}, smalltalk.JavaScriptException.klass)})}
+}),
+smalltalk.JavaScriptException.klass);
+
+
 smalltalk.addClass('MessageNotUnderstood', smalltalk.Error, ['message', 'receiver'], 'Kernel-Exceptions');
 smalltalk.addMethod(
 "_message",

+ 117 - 0
js/Kernel-Exceptions.js

@@ -1,5 +1,6 @@
 smalltalk.addPackage('Kernel-Exceptions', {});
 smalltalk.addClass('Error', smalltalk.Object, ['messageText'], 'Kernel-Exceptions');
+smalltalk.Error.comment="From the ANSI standard:\x0a\x0aThis protocol describes the behavior of instances of class `Error`. \x0aThese are used to represent error conditions that prevent the normal continuation of processing. \x0aActual error exceptions used by an application may be subclasses of this class.\x0aAs `Error` is explicitly specified  to be subclassable, conforming implementations must implement its behavior in a non-fragile manner."
 smalltalk.addMethod(
 "_context",
 smalltalk.method({
@@ -169,7 +170,121 @@ referencedClasses: []
 smalltalk.Error.klass);
 
 
+smalltalk.addClass('JavaScriptException', smalltalk.Error, ['exception'], 'Kernel-Exceptions');
+smalltalk.JavaScriptException.comment="A JavaScriptException is thrown when a non-Smalltalk exception occurs while in the Smalltalk stack.\x0aSee `boot.js` `inContext()` and `BlockClosure >> on:do:`"
+smalltalk.addMethod(
+"_context_",
+smalltalk.method({
+selector: "context:",
+category: 'accessing',
+fn: function (aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self.context = aMethodContext;
+return self}, function($ctx1) {$ctx1.fill(self,"context:",{aMethodContext:aMethodContext}, smalltalk.JavaScriptException)})},
+args: ["aMethodContext"],
+source: "context: aMethodContext\x0a\x09\x22Set the context from the outside.\x0a    See boot.js `inContext()` exception handling\x22\x0a    \x0a    <self.context = aMethodContext>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_exception",
+smalltalk.method({
+selector: "exception",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=self["@exception"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"exception",{}, smalltalk.JavaScriptException)})},
+args: [],
+source: "exception\x0a\x09^ exception",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_exception_",
+smalltalk.method({
+selector: "exception:",
+category: 'accessing',
+fn: function (anException){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
self["@exception"]=anException;
+return self}, function($ctx1) {$ctx1.fill(self,"exception:",{anException:anException}, smalltalk.JavaScriptException)})},
+args: ["anException"],
+source: "exception: anException\x0a\x09exception := anException",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException);
+
+smalltalk.addMethod(
+"_messageText",
+smalltalk.method({
+selector: "messageText",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return 'JavaScript exception: ' + self["@exception"].toString();
+return self}, function($ctx1) {$ctx1.fill(self,"messageText",{}, smalltalk.JavaScriptException)})},
+args: [],
+source: "messageText\x0a\x09<return 'JavaScript exception: ' + self[\x22@exception\x22].toString()>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException);
+
+
+smalltalk.addMethod(
+"_on_",
+smalltalk.method({
+selector: "on:",
+category: 'instance creation',
+fn: function (anException){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$3,$1;
+$2=_st(self)._new();
+_st($2)._exception_(anException);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:",{anException:anException}, smalltalk.JavaScriptException.klass)})},
+args: ["anException"],
+source: "on: anException\x0a\x09^ self new\x0a    \x09exception: anException;\x0a        yourself",
+messageSends: ["exception:", "new", "yourself"],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException.klass);
+
+smalltalk.addMethod(
+"_on_context_",
+smalltalk.method({
+selector: "on:context:",
+category: 'instance creation',
+fn: function (anException,aMethodContext){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$3,$1;
+$2=_st(self)._new();
+_st($2)._exception_(anException);
+_st($2)._context_(aMethodContext);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:context:",{anException:anException,aMethodContext:aMethodContext}, smalltalk.JavaScriptException.klass)})},
+args: ["anException", "aMethodContext"],
+source: "on: anException context: aMethodContext\x0a\x09^ self new\x0a    \x09exception: anException;\x0a        context: aMethodContext;\x0a        yourself",
+messageSends: ["exception:", "new", "context:", "yourself"],
+referencedClasses: []
+}),
+smalltalk.JavaScriptException.klass);
+
+
 smalltalk.addClass('MessageNotUnderstood', smalltalk.Error, ['message', 'receiver'], 'Kernel-Exceptions');
+smalltalk.MessageNotUnderstood.comment="This exception is provided to support `Object>>doesNotUnderstand:`."
 smalltalk.addMethod(
 "_message",
 smalltalk.method({
@@ -259,6 +374,7 @@ smalltalk.MessageNotUnderstood);
 
 
 smalltalk.addClass('NonBooleanReceiver', smalltalk.Error, ['object'], 'Kernel-Exceptions');
+smalltalk.NonBooleanReceiver.comment="NonBooleanReceiver exceptions may be thrown when executing inlined methods such as `#ifTrue:` with a non boolean receiver."
 smalltalk.addMethod(
 "_object",
 smalltalk.method({
@@ -296,6 +412,7 @@ smalltalk.NonBooleanReceiver);
 
 
 smalltalk.addClass('ErrorHandler', smalltalk.Object, [], 'Kernel-Exceptions');
+smalltalk.ErrorHandler.comment="ErrorHandler is used to manage Smalltalk errors. \x0aSee `boot.js` `handleError()` function.\x0a\x0aSubclasses of `ErrorHandler` can register themselves as the current handler with\x0a`ErrorHandler class >> register`.\x0a\x0aSubclasses may override `#handleError:` to perform an action on the thrown exception.\x0aThe default behavior is to log the error and the context stack to the JavaScript console."
 smalltalk.addMethod(
 "_handleError_",
 smalltalk.method({

+ 115 - 11
js/Kernel-Methods.deploy.js

@@ -11,6 +11,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"applyTo:arguments:",{anObject:an
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_asCompiledMethod_",
+smalltalk.method({
+selector: "asCompiledMethod:",
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return smalltalk.method({selector:aString, fn:self});;
+return self}, function($ctx1) {$ctx1.fill(self,"asCompiledMethod:",{aString:aString}, smalltalk.BlockClosure)})}
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_compiledSource",
 smalltalk.method({
@@ -22,6 +33,23 @@ return self}, function($ctx1) {$ctx1.fill(self,"compiledSource",{}, smalltalk.Bl
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_currySelf",
+smalltalk.method({
+selector: "currySelf",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	return function () {
+    		var args = [ this ];
+        	args.push.apply(args, arguments);
+        	return self.apply(null, args);
+    	}
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"currySelf",{}, smalltalk.BlockClosure)})}
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_ensure_",
 smalltalk.method({
@@ -83,7 +111,7 @@ smalltalk.method({
 selector: "newValue:value:value:",
 fn: function (anObject,anObject2,anObject3){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
return new self(anObject, anObject2);
+return smalltalk.withContext(function($ctx1) { 
return new self(anObject, anObject2,anObject3);
 return self}, function($ctx1) {$ctx1.fill(self,"newValue:value:value:",{anObject:anObject,anObject2:anObject2,anObject3:anObject3}, smalltalk.BlockClosure)})}
 }),
 smalltalk.BlockClosure);
@@ -105,18 +133,18 @@ smalltalk.method({
 selector: "on:do:",
 fn: function (anErrorClass,aBlock){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $2,$3,$5,$4,$1;
-$2=self;
-$3=self;
-$4=(function(error){
-return smalltalk.withContext(function($ctx2) {
$5=_st(error)._isKindOf_(anErrorClass);
-if(smalltalk.assert($5)){
-return _st(aBlock)._value_(error);
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$1=_st(self)._try_catch_(self,(function(error){
+var smalltalkError;
+return smalltalk.withContext(function($ctx2) {
smalltalkError=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._asSmalltalkException_(error);
+smalltalkError;
+$2=_st(smalltalkError)._isKindOf_(anErrorClass);
+if(smalltalk.assert($2)){
+return _st(aBlock)._value_(smalltalkError);
 } else {
-return _st(error)._signal();
+return _st(smalltalkError)._signal();
 };
-}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1)})});
-$1=_st($2)._try_catch_($3,$4);
+}, function($ctx2) {$ctx2.fillBlock({error:error,smalltalkError:smalltalkError},$ctx1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock}, smalltalk.BlockClosure)})}
 }),
@@ -877,3 +905,79 @@ smalltalk.MethodContext);
 
 
 
+smalltalk.addClass('NativeFunction', smalltalk.Object, [], 'Kernel-Methods');
+
+smalltalk.addMethod(
+"_constructor_",
+smalltalk.method({
+selector: "constructor:",
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native();
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:",{aString:aString}, smalltalk.NativeFunction.klass)})}
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_",
+smalltalk.method({
+selector: "constructor:value:",
+fn: function (aString,anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:",{aString:aString,anObject:anObject}, smalltalk.NativeFunction.klass)})}
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_value_",
+smalltalk.method({
+selector: "constructor:value:value:",
+fn: function (aString,anObject,anObject2){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject,anObject2);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2}, smalltalk.NativeFunction.klass)})}
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_value_value_",
+smalltalk.method({
+selector: "constructor:value:value:value:",
+fn: function (aString,anObject,anObject2,anObject3){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject,anObject2, anObject3);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2,anObject3:anObject3}, smalltalk.NativeFunction.klass)})}
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_exists_",
+smalltalk.method({
+selector: "exists:",
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	if(aString in window) {
+        	return true
+        } else {
+        	return false
+        }
+    ;
+return self}, function($ctx1) {$ctx1.fill(self,"exists:",{aString:aString}, smalltalk.NativeFunction.klass)})}
+}),
+smalltalk.NativeFunction.klass);
+
+

+ 157 - 17
js/Kernel-Methods.js

@@ -17,6 +17,22 @@ referencedClasses: []
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_asCompiledMethod_",
+smalltalk.method({
+selector: "asCompiledMethod:",
+category: 'converting',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return smalltalk.method({selector:aString, fn:self});;
+return self}, function($ctx1) {$ctx1.fill(self,"asCompiledMethod:",{aString:aString}, smalltalk.BlockClosure)})},
+args: ["aString"],
+source: "asCompiledMethod: aString\x0a\x09<return smalltalk.method({selector:aString, fn:self});>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_compiledSource",
 smalltalk.method({
@@ -33,6 +49,28 @@ referencedClasses: []
 }),
 smalltalk.BlockClosure);
 
+smalltalk.addMethod(
+"_currySelf",
+smalltalk.method({
+selector: "currySelf",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	return function () {
+    		var args = [ this ];
+        	args.push.apply(args, arguments);
+        	return self.apply(null, args);
+    	}
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"currySelf",{}, smalltalk.BlockClosure)})},
+args: [],
+source: "currySelf\x0a\x09\x22Transforms [ :selfarg :x :y | stcode ] block\x0a    which represents JS function (selfarg, x, y, ...) {jscode}\x0a    into function (x, y, ...) {jscode} that takes selfarg from 'this'.\x0a    IOW, it is usable as JS method and first arg takes the receiver.\x22\x0a    \x0a    <\x0a    \x09return function () {\x0a    \x09\x09var args = [ this ];\x0a        \x09args.push.apply(args, arguments);\x0a        \x09return self.apply(null, args);\x0a    \x09}\x0a\x09>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.BlockClosure);
+
 smalltalk.addMethod(
 "_ensure_",
 smalltalk.method({
@@ -120,10 +158,10 @@ selector: "newValue:value:value:",
 category: 'evaluating',
 fn: function (anObject,anObject2,anObject3){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
return new self(anObject, anObject2);
+return smalltalk.withContext(function($ctx1) { 
return new self(anObject, anObject2,anObject3);
 return self}, function($ctx1) {$ctx1.fill(self,"newValue:value:value:",{anObject:anObject,anObject2:anObject2,anObject3:anObject3}, smalltalk.BlockClosure)})},
 args: ["anObject", "anObject2", "anObject3"],
-source: "newValue:  anObject value: anObject2 value: anObject3\x0a\x09\x22Use the receiver as a JS constructor. \x0a\x09*Do not* use this method to instanciate Smalltalk objects!\x22\x0a\x09<return new self(anObject, anObject2)>",
+source: "newValue:  anObject value: anObject2 value: anObject3\x0a\x09\x22Use the receiver as a JS constructor. \x0a\x09*Do not* use this method to instanciate Smalltalk objects!\x22\x0a\x09<return new self(anObject, anObject2,anObject3)>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -152,24 +190,24 @@ selector: "on:do:",
 category: 'error handling',
 fn: function (anErrorClass,aBlock){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $2,$3,$5,$4,$1;
-$2=self;
-$3=self;
-$4=(function(error){
-return smalltalk.withContext(function($ctx2) {
$5=_st(error)._isKindOf_(anErrorClass);
-if(smalltalk.assert($5)){
-return _st(aBlock)._value_(error);
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$1=_st(self)._try_catch_(self,(function(error){
+var smalltalkError;
+return smalltalk.withContext(function($ctx2) {
smalltalkError=_st(_st((smalltalk.Smalltalk || Smalltalk))._current())._asSmalltalkException_(error);
+smalltalkError;
+$2=_st(smalltalkError)._isKindOf_(anErrorClass);
+if(smalltalk.assert($2)){
+return _st(aBlock)._value_(smalltalkError);
 } else {
-return _st(error)._signal();
+return _st(smalltalkError)._signal();
 };
-}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1)})});
-$1=_st($2)._try_catch_($3,$4);
+}, function($ctx2) {$ctx2.fillBlock({error:error,smalltalkError:smalltalkError},$ctx1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock}, smalltalk.BlockClosure)})},
 args: ["anErrorClass", "aBlock"],
-source: "on: anErrorClass do: aBlock\x0a\x09^self try: self catch: [:error |\x0a\x09    (error isKindOf: anErrorClass) \x0a\x09     ifTrue: [aBlock value: error]\x0a\x09     ifFalse: [error signal]]",
-messageSends: ["try:catch:", "ifTrue:ifFalse:", "value:", "signal", "isKindOf:"],
-referencedClasses: []
+source: "on: anErrorClass do: aBlock\x0a\x09\x22All exceptions thrown in the Smalltalk stack are cought.\x0a    Convert all JS exceptions to JavaScriptException instances.\x22\x0a    \x0a\x09^self try: self catch: [ :error | | smalltalkError |\x0a    \x09smalltalkError := Smalltalk current asSmalltalkException: error.\x0a\x09    (smalltalkError isKindOf: anErrorClass) \x0a\x09     ifTrue: [ aBlock value: smalltalkError ]\x0a\x09     ifFalse: [ smalltalkError signal ] ]",
+messageSends: ["try:catch:", "asSmalltalkException:", "current", "ifTrue:ifFalse:", "value:", "signal", "isKindOf:"],
+referencedClasses: ["Smalltalk"]
 }),
 smalltalk.BlockClosure);
 
@@ -635,7 +673,7 @@ smalltalk.addMethod(
 "_addWorker",
 smalltalk.method({
 selector: "addWorker",
-category: 'action',
+category: 'private',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
_st(self["@worker"])._valueWithTimeout_((0));
@@ -670,7 +708,7 @@ smalltalk.addMethod(
 "_fork_",
 smalltalk.method({
 selector: "fork:",
-category: 'action',
+category: 'actions',
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
@@ -1202,3 +1240,105 @@ smalltalk.MethodContext);
 
 
 
+smalltalk.addClass('NativeFunction', smalltalk.Object, [], 'Kernel-Methods');
+smalltalk.NativeFunction.comment="NativeFunction is a wrapper around native functions, such as `WebSocket`.\x0aFor 'normal' functions (whose constructor is the JavaScript `Function` object), use `BlockClosure`.\x0a\x0aSee the class-side `instance creation` methods.\x0a\x0aCreated instances will most probably be instance of `JSObjectProxy`.\x0a\x0aUsage example:\x0a\x0a    | ws |\x0a    ws := NativeFunction constructor: 'WebSocket' value: 'ws://localhost'.\x0a    ws at: 'onopen' put: [ ws send: 'hey there from Amber' ]"
+
+smalltalk.addMethod(
+"_constructor_",
+smalltalk.method({
+selector: "constructor:",
+category: 'instance creation',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native();
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:",{aString:aString}, smalltalk.NativeFunction.klass)})},
+args: ["aString"],
+source: "constructor: aString\x0a\x09<\x0a    \x09var native=eval(aString); \x0a        return new native();\x0a\x09>\x0a",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_",
+smalltalk.method({
+selector: "constructor:value:",
+category: 'instance creation',
+fn: function (aString,anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:",{aString:aString,anObject:anObject}, smalltalk.NativeFunction.klass)})},
+args: ["aString", "anObject"],
+source: "constructor: aString value:anObject\x0a\x09<\x0a    \x09var native=eval(aString); \x0a        return new native(anObject);\x0a\x09>\x0a",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_value_",
+smalltalk.method({
+selector: "constructor:value:value:",
+category: 'instance creation',
+fn: function (aString,anObject,anObject2){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject,anObject2);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2}, smalltalk.NativeFunction.klass)})},
+args: ["aString", "anObject", "anObject2"],
+source: "constructor: aString value:anObject value: anObject2\x0a\x09<\x0a    \x09var native=eval(aString); \x0a        return new native(anObject,anObject2);\x0a\x09>\x0a",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_constructor_value_value_value_",
+smalltalk.method({
+selector: "constructor:value:value:value:",
+category: 'instance creation',
+fn: function (aString,anObject,anObject2,anObject3){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var native=eval(aString); 
+        return new native(anObject,anObject2, anObject3);
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"constructor:value:value:value:",{aString:aString,anObject:anObject,anObject2:anObject2,anObject3:anObject3}, smalltalk.NativeFunction.klass)})},
+args: ["aString", "anObject", "anObject2", "anObject3"],
+source: "constructor: aString value:anObject value: anObject2 value:anObject3\x0a\x09<\x0a    \x09var native=eval(aString); \x0a        return new native(anObject,anObject2, anObject3);\x0a\x09>\x0a",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.NativeFunction.klass);
+
+smalltalk.addMethod(
+"_exists_",
+smalltalk.method({
+selector: "exists:",
+category: 'testing',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	if(aString in window) {
+        	return true
+        } else {
+        	return false
+        }
+    ;
+return self}, function($ctx1) {$ctx1.fill(self,"exists:",{aString:aString}, smalltalk.NativeFunction.klass)})},
+args: ["aString"],
+source: "exists: aString\x0a\x09<\x0a    \x09if(aString in window) {\x0a        \x09return true\x0a        } else {\x0a        \x09return false\x0a        }\x0a    >",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.NativeFunction.klass);
+
+

+ 90 - 4
js/Kernel-Objects.deploy.js

@@ -1467,6 +1467,21 @@ return self}, function($ctx1) {$ctx1.fill(self,"at:",{aSymbol:aSymbol}, smalltal
 }),
 smalltalk.JSObjectProxy);
 
+smalltalk.addMethod(
+"_at_ifAbsent_",
+smalltalk.method({
+selector: "at:ifAbsent:",
+fn: function (aSymbol,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var obj = self['@jsObject'],
+        	symbol = aSymbol._asString();
+		return symbol in obj ? obj[symbol] : aBlock();
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aSymbol:aSymbol,aBlock:aBlock}, smalltalk.JSObjectProxy)})}
+}),
+smalltalk.JSObjectProxy);
+
 smalltalk.addMethod(
 "_at_put_",
 smalltalk.method({
@@ -1597,6 +1612,21 @@ return $1;
 }),
 smalltalk.JSObjectProxy);
 
+smalltalk.addMethod(
+"_value",
+smalltalk.method({
+selector: "value",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(self)._at_ifAbsent_("value",(function(){
+return smalltalk.withContext(function($ctx2) {
return smalltalk.Object.fn.prototype._value.apply(_st(self), []);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{}, smalltalk.JSObjectProxy)})}
+}),
+smalltalk.JSObjectProxy);
+
 
 smalltalk.addMethod(
 "_on_",
@@ -2537,6 +2567,22 @@ smalltalk.Package);
 
 
 smalltalk.Package.klass.iVarNames = ['defaultCommitPathJs','defaultCommitPathSt'];
+smalltalk.addMethod(
+"_commitPathsFromLoader",
+smalltalk.method({
+selector: "commitPathsFromLoader",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    var cp = smalltalk['@@commitPath'];
+    if (!cp) return;
+    if (cp.js) self._defaultCommitPathJs_(cp.js);
+    if (cp.st) self._defaultCommitPathSt_(cp.st);
+    ;
+return self}, function($ctx1) {$ctx1.fill(self,"commitPathsFromLoader",{}, smalltalk.Package.klass)})}
+}),
+smalltalk.Package.klass);
+
 smalltalk.addMethod(
 "_defaultCommitPathJs",
 smalltalk.method({
@@ -2621,6 +2667,18 @@ return self}, function($ctx1) {$ctx1.fill(self,"fetch:prefix:",{aPackageName:aPa
 }),
 smalltalk.Package.klass);
 
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
smalltalk.Object.klass.fn.prototype._initialize.apply(_st(self), []);
+_st(self)._commitPathsFromLoader();
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.Package.klass)})}
+}),
+smalltalk.Package.klass);
+
 smalltalk.addMethod(
 "_named_",
 smalltalk.method({
@@ -2911,6 +2969,26 @@ smalltalk.Random);
 
 
 smalltalk.addClass('Smalltalk', smalltalk.Object, [], 'Kernel-Objects');
+smalltalk.addMethod(
+"_asSmalltalkException_",
+smalltalk.method({
+selector: "asSmalltalkException:",
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=_st(_st(self)._isSmalltalkObject_(anObject))._and_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(anObject)._isKindOf_((smalltalk.Error || Error));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+if(smalltalk.assert($2)){
+$1=anObject;
+} else {
+$1=_st((smalltalk.JavaScriptException || JavaScriptException))._on_(anObject);
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSmalltalkException:",{anObject:anObject}, smalltalk.Smalltalk)})}
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_at_",
 smalltalk.method({
@@ -2995,6 +3073,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"deletePackage:",{packageName:pac
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+"_isSmalltalkObject_",
+smalltalk.method({
+selector: "isSmalltalkObject:",
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return typeof anObject.klass !== 'undefined';
+return self}, function($ctx1) {$ctx1.fill(self,"isSmalltalkObject:",{anObject:anObject}, smalltalk.Smalltalk)})}
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_packageAt_",
 smalltalk.method({
@@ -3398,7 +3487,7 @@ selector: "subclass:instanceVariableNames:package:",
 fn: function (aString,aString2,aString3){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._superclass_subclass_instanceVariableNames_package_(self,aString,aString2,aString3);
+$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._superclass_subclass_instanceVariableNames_package_(self,_st(aString)._asString(),aString2,aString3);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"subclass:instanceVariableNames:package:",{aString:aString,aString2:aString2,aString3:aString3}, smalltalk.UndefinedObject)})}
 }),
@@ -3417,6 +3506,3 @@ return self}, function($ctx1) {$ctx1.fill(self,"new",{}, smalltalk.UndefinedObje
 smalltalk.UndefinedObject.klass);
 
 
-smalltalk.addClass('[object Object]', smalltalk.nil, [], 'Kernel-Objects');
-
-

+ 122 - 6
js/Kernel-Objects.js

@@ -2056,6 +2056,26 @@ referencedClasses: []
 }),
 smalltalk.JSObjectProxy);
 
+smalltalk.addMethod(
+"_at_ifAbsent_",
+smalltalk.method({
+selector: "at:ifAbsent:",
+category: 'accessing',
+fn: function (aSymbol,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    	var obj = self['@jsObject'],
+        	symbol = aSymbol._asString();
+		return symbol in obj ? obj[symbol] : aBlock();
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aSymbol:aSymbol,aBlock:aBlock}, smalltalk.JSObjectProxy)})},
+args: ["aSymbol", "aBlock"],
+source: "at: aSymbol ifAbsent: aBlock\x0a\x09\x22return the aSymbol property or evaluate aBlock if the property is not defined on the object\x22\x0a\x09<\x0a    \x09var obj = self['@jsObject'],\x0a        \x09symbol = aSymbol._asString();\x0a\x09\x09return symbol in obj ? obj[symbol] : aBlock();\x0a\x09>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.JSObjectProxy);
+
 smalltalk.addMethod(
 "_at_put_",
 smalltalk.method({
@@ -2231,6 +2251,26 @@ referencedClasses: []
 }),
 smalltalk.JSObjectProxy);
 
+smalltalk.addMethod(
+"_value",
+smalltalk.method({
+selector: "value",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(self)._at_ifAbsent_("value",(function(){
+return smalltalk.withContext(function($ctx2) {
return smalltalk.Object.fn.prototype._value.apply(_st(self), []);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"value",{}, smalltalk.JSObjectProxy)})},
+args: [],
+source: "value\x0a\x09\x22if attribute 'value' exists on the JS object return it,\x0a    otherwise return the result of Object>>value.\x22\x0a\x09^ self at: 'value' ifAbsent: [super value]",
+messageSends: ["at:ifAbsent:", "value"],
+referencedClasses: []
+}),
+smalltalk.JSObjectProxy);
+
 
 smalltalk.addMethod(
 "_on_",
@@ -3513,6 +3553,27 @@ smalltalk.Package);
 
 
 smalltalk.Package.klass.iVarNames = ['defaultCommitPathJs','defaultCommitPathSt'];
+smalltalk.addMethod(
+"_commitPathsFromLoader",
+smalltalk.method({
+selector: "commitPathsFromLoader",
+category: 'commit paths',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+    var cp = smalltalk['@@commitPath'];
+    if (!cp) return;
+    if (cp.js) self._defaultCommitPathJs_(cp.js);
+    if (cp.st) self._defaultCommitPathSt_(cp.st);
+    ;
+return self}, function($ctx1) {$ctx1.fill(self,"commitPathsFromLoader",{}, smalltalk.Package.klass)})},
+args: [],
+source: "commitPathsFromLoader\x0a    <\x0a    var cp = smalltalk['@@commitPath'];\x0a    if (!cp) return;\x0a    if (cp.js) self._defaultCommitPathJs_(cp.js);\x0a    if (cp.st) self._defaultCommitPathSt_(cp.st);\x0a    >",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Package.klass);
+
 smalltalk.addMethod(
 "_defaultCommitPathJs",
 smalltalk.method({
@@ -3627,6 +3688,23 @@ referencedClasses: ["Package"]
 }),
 smalltalk.Package.klass);
 
+smalltalk.addMethod(
+"_initialize",
+smalltalk.method({
+selector: "initialize",
+category: 'initialization',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
smalltalk.Object.klass.fn.prototype._initialize.apply(_st(self), []);
+_st(self)._commitPathsFromLoader();
+return self}, function($ctx1) {$ctx1.fill(self,"initialize",{}, smalltalk.Package.klass)})},
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a    self commitPathsFromLoader",
+messageSends: ["initialize", "commitPathsFromLoader"],
+referencedClasses: []
+}),
+smalltalk.Package.klass);
+
 smalltalk.addMethod(
 "_named_",
 smalltalk.method({
@@ -4015,6 +4093,31 @@ smalltalk.Random);
 
 smalltalk.addClass('Smalltalk', smalltalk.Object, [], 'Kernel-Objects');
 smalltalk.Smalltalk.comment="Smalltalk has only one instance, accessed with `Smalltalk current`. \x0aIt represents the global JavaScript variable `smalltalk` declared in `js/boot.js`.\x0a\x0aThe `smalltalk` object holds all class and packages defined in the system.\x0a\x0a## Classes\x0a\x0aClasses can be accessed using the following methods:\x0a\x0a- `#classes` answers the full list of Smalltalk classes in the system\x0a- `#at:` answers a specific class of `nil`\x0a\x0a## Packages\x0a\x0aPackages can be accessed using the following methods:\x0a\x0a- `#packages` answers the full list of packages\x0a- `#packageAt:` answers a specific class of `nil`\x0a\x0a__note:__ classes and packages are accessed using strings, not symbols\x0a\x0a## Parsing\x0a\x0aThe `#parse:` method is used to parse Smalltalk source code. \x0aIt requires the `Compiler` package and the `js/parser.js` parser file in order to work"
+smalltalk.addMethod(
+"_asSmalltalkException_",
+smalltalk.method({
+selector: "asSmalltalkException:",
+category: 'error handling',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $2,$1;
+$2=_st(_st(self)._isSmalltalkObject_(anObject))._and_((function(){
+return smalltalk.withContext(function($ctx2) {
return _st(anObject)._isKindOf_((smalltalk.Error || Error));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+if(smalltalk.assert($2)){
+$1=anObject;
+} else {
+$1=_st((smalltalk.JavaScriptException || JavaScriptException))._on_(anObject);
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"asSmalltalkException:",{anObject:anObject}, smalltalk.Smalltalk)})},
+args: ["anObject"],
+source: "asSmalltalkException: anObject\x0a\x09\x22A JavaScript exception may be thrown.\x0a    We then need to convert it back to a Smalltalk object\x22\x0a    \x0a    ^ ((self isSmalltalkObject: anObject) and: [ anObject isKindOf: Error ])\x0a    \x09ifTrue: [ anObject ]\x0a      \x09ifFalse: [ JavaScriptException on: anObject ]",
+messageSends: ["ifTrue:ifFalse:", "on:", "and:", "isKindOf:", "isSmalltalkObject:"],
+referencedClasses: ["JavaScriptException", "Error"]
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_at_",
 smalltalk.method({
@@ -4134,6 +4237,22 @@ referencedClasses: []
 }),
 smalltalk.Smalltalk);
 
+smalltalk.addMethod(
+"_isSmalltalkObject_",
+smalltalk.method({
+selector: "isSmalltalkObject:",
+category: 'testing',
+fn: function (anObject){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
return typeof anObject.klass !== 'undefined';
+return self}, function($ctx1) {$ctx1.fill(self,"isSmalltalkObject:",{anObject:anObject}, smalltalk.Smalltalk)})},
+args: ["anObject"],
+source: "isSmalltalkObject: anObject\x0a\x09\x22Consider anObject a Smalltalk object if it has a 'klass' property.\x0a    Note that this may be unaccurate\x22\x0a    \x0a    <return typeof anObject.klass !== 'undefined'>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Smalltalk);
+
 smalltalk.addMethod(
 "_packageAt_",
 smalltalk.method({
@@ -4680,12 +4799,12 @@ category: 'class creation',
 fn: function (aString,aString2,aString3){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._superclass_subclass_instanceVariableNames_package_(self,aString,aString2,aString3);
+$1=_st(_st((smalltalk.ClassBuilder || ClassBuilder))._new())._superclass_subclass_instanceVariableNames_package_(self,_st(aString)._asString(),aString2,aString3);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"subclass:instanceVariableNames:package:",{aString:aString,aString2:aString2,aString3:aString3}, smalltalk.UndefinedObject)})},
 args: ["aString", "aString2", "aString3"],
-source: "subclass: aString instanceVariableNames: aString2 package: aString3\x0a\x09^ClassBuilder new\x0a\x09    superclass: self subclass: aString instanceVariableNames: aString2 package: aString3",
-messageSends: ["superclass:subclass:instanceVariableNames:package:", "new"],
+source: "subclass: aString instanceVariableNames: aString2 package: aString3\x0a\x09^ClassBuilder new\x0a\x09    superclass: self subclass: aString asString instanceVariableNames: aString2 package: aString3",
+messageSends: ["superclass:subclass:instanceVariableNames:package:", "asString", "new"],
 referencedClasses: ["ClassBuilder"]
 }),
 smalltalk.UndefinedObject);
@@ -4708,6 +4827,3 @@ referencedClasses: []
 smalltalk.UndefinedObject.klass);
 
 
-smalltalk.addClass('[object Object]', smalltalk.nil, [], 'Kernel-Objects');
-
-

File diff suppressed because it is too large
+ 189 - 112
js/Kernel-Tests.deploy.js


File diff suppressed because it is too large
+ 205 - 108
js/Kernel-Tests.js


+ 34 - 42
js/SUnit-Tests.deploy.js

@@ -192,28 +192,28 @@ return self}, function($ctx1) {$ctx1.fill(self,"fakeTimeout",{}, smalltalk.SUnit
 smalltalk.SUnitAsyncTest);
 
 smalltalk.addMethod(
-"_setUp",
+"_selectorSetOf_",
 smalltalk.method({
-selector: "setUp",
-fn: function (){
+selector: "selectorSetOf:",
+fn: function (aCollection){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
self["@flag"]="ok";
-return self}, function($ctx1) {$ctx1.fill(self,"setUp",{}, smalltalk.SUnitAsyncTest)})}
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(aCollection)._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(each)._selector();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._asSet();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectorSetOf:",{aCollection:aCollection}, smalltalk.SUnitAsyncTest)})}
 }),
 smalltalk.SUnitAsyncTest);
 
 smalltalk.addMethod(
-"_sortedSelectors_",
+"_setUp",
 smalltalk.method({
-selector: "sortedSelectors:",
-fn: function (aCollection){
+selector: "setUp",
+fn: function (){
 var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st(_st(aCollection)._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(each)._selector();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._sorted();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"sortedSelectors:",{aCollection:aCollection}, smalltalk.SUnitAsyncTest)})}
+return smalltalk.withContext(function($ctx1) { 
self["@flag"]="ok";
+return self}, function($ctx1) {$ctx1.fill(self,"setUp",{}, smalltalk.SUnitAsyncTest)})}
 }),
 smalltalk.SUnitAsyncTest);
 
@@ -235,7 +235,7 @@ selector: "testAsyncErrorsAndFailures",
 fn: function (){
 var self=this;
 var suite,runner,result,assertBlock;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$6,$5,$3;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 suite=_st(["fakeError", "fakeErrorFailingInTearDown", "fakeFailure", "testPass"])._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._class())._selector_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
@@ -243,21 +243,17 @@ runner=_st((smalltalk.TestSuiteRunner || TestSuiteRunner))._on_(suite);
 _st(self)._timeout_((200));
 result=_st(runner)._result();
 assertBlock=_st(self)._async_((function(){
-return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(["fakeError"],_st(self)._sortedSelectors_(_st(result)._errors()));
-_st(self)._assert_equals_(["fakeErrorFailingInTearDown", "fakeFailure"],_st(self)._sortedSelectors_(_st(result)._failures()));
+return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(_st(["fakeError"])._asSet(),_st(self)._selectorSetOf_(_st(result)._errors()));
+_st(self)._assert_equals_(_st(["fakeErrorFailingInTearDown", "fakeFailure"])._asSet(),_st(self)._selectorSetOf_(_st(result)._failures()));
 return _st(self)._finished();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$1=_st(runner)._announcer();
-$2=(smalltalk.ResultAnnouncement || ResultAnnouncement);
-$3=(function(ann){
-return smalltalk.withContext(function($ctx2) {
$4=_st(_st(ann)._result()).__eq_eq(result);
-$5=(function(){
-return smalltalk.withContext(function($ctx3) {
$6=_st(_st(result)._runs()).__eq(_st(result)._total());
-return _st($6)._ifTrue_(assertBlock);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($4)._ifTrue_($5);
-}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})});
-_st($1)._on_do_($2,$3);
+_st(_st(runner)._announcer())._on_do_((smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+return smalltalk.withContext(function($ctx2) {
$1=_st(_st(ann)._result()).__eq_eq(result);
+if(smalltalk.assert($1)){
+$2=_st(_st(result)._runs()).__eq(_st(result)._total());
+return _st($2)._ifTrue_(assertBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})}));
 _st(runner)._run();
 return self}, function($ctx1) {$ctx1.fill(self,"testAsyncErrorsAndFailures",{suite:suite,runner:runner,result:result,assertBlock:assertBlock}, smalltalk.SUnitAsyncTest)})}
 }),
@@ -340,7 +336,7 @@ selector: "testTimeouts",
 fn: function (){
 var self=this;
 var suite,runner,result,assertBlock;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$6,$5,$3;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 suite=_st(["fakeTimeout", "fakeMultipleTimeoutFailing", "fakeMultipleTimeoutPassing", "testPass"])._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._class())._selector_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
@@ -348,21 +344,17 @@ runner=_st((smalltalk.TestSuiteRunner || TestSuiteRunner))._on_(suite);
 _st(self)._timeout_((200));
 result=_st(runner)._result();
 assertBlock=_st(self)._async_((function(){
-return smalltalk.withContext(function($ctx2) {
_st(self)._assert_(_st(_st(result)._errors())._isEmpty());
-_st(self)._assert_equals_(["fakeMultipleTimeoutFailing", "fakeTimeout"],_st(self)._sortedSelectors_(_st(result)._failures()));
+return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(_st((smalltalk.Set || Set))._new(),_st(self)._selectorSetOf_(_st(result)._errors()));
+_st(self)._assert_equals_(_st(["fakeMultipleTimeoutFailing", "fakeTimeout"])._asSet(),_st(self)._selectorSetOf_(_st(result)._failures()));
 return _st(self)._finished();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$1=_st(runner)._announcer();
-$2=(smalltalk.ResultAnnouncement || ResultAnnouncement);
-$3=(function(ann){
-return smalltalk.withContext(function($ctx2) {
$4=_st(_st(ann)._result()).__eq_eq(result);
-$5=(function(){
-return smalltalk.withContext(function($ctx3) {
$6=_st(_st(result)._runs()).__eq(_st(result)._total());
-return _st($6)._ifTrue_(assertBlock);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($4)._ifTrue_($5);
-}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})});
-_st($1)._on_do_($2,$3);
+_st(_st(runner)._announcer())._on_do_((smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+return smalltalk.withContext(function($ctx2) {
$1=_st(_st(ann)._result()).__eq_eq(result);
+if(smalltalk.assert($1)){
+$2=_st(_st(result)._runs()).__eq(_st(result)._total());
+return _st($2)._ifTrue_(assertBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})}));
 _st(runner)._run();
 return self}, function($ctx1) {$ctx1.fill(self,"testTimeouts",{suite:suite,runner:runner,result:result,assertBlock:assertBlock}, smalltalk.SUnitAsyncTest)})}
 }),

+ 45 - 53
js/SUnit-Tests.js

@@ -257,6 +257,26 @@ referencedClasses: []
 }),
 smalltalk.SUnitAsyncTest);
 
+smalltalk.addMethod(
+"_selectorSetOf_",
+smalltalk.method({
+selector: "selectorSetOf:",
+category: 'private',
+fn: function (aCollection){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
var $1;
+$1=_st(_st(aCollection)._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
return _st(each)._selector();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._asSet();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"selectorSetOf:",{aCollection:aCollection}, smalltalk.SUnitAsyncTest)})},
+args: ["aCollection"],
+source: "selectorSetOf: aCollection\x0a\x09^(aCollection collect: [:each | each selector]) asSet",
+messageSends: ["asSet", "collect:", "selector"],
+referencedClasses: []
+}),
+smalltalk.SUnitAsyncTest);
+
 smalltalk.addMethod(
 "_setUp",
 smalltalk.method({
@@ -273,26 +293,6 @@ referencedClasses: []
 }),
 smalltalk.SUnitAsyncTest);
 
-smalltalk.addMethod(
-"_sortedSelectors_",
-smalltalk.method({
-selector: "sortedSelectors:",
-category: 'private',
-fn: function (aCollection){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
var $1;
-$1=_st(_st(aCollection)._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
return _st(each)._selector();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._sorted();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"sortedSelectors:",{aCollection:aCollection}, smalltalk.SUnitAsyncTest)})},
-args: ["aCollection"],
-source: "sortedSelectors: aCollection\x0a\x09^(aCollection collect: [:each | each selector]) sorted",
-messageSends: ["sorted", "collect:", "selector"],
-referencedClasses: []
-}),
-smalltalk.SUnitAsyncTest);
-
 smalltalk.addMethod(
 "_tearDown",
 smalltalk.method({
@@ -317,7 +317,7 @@ category: 'tests',
 fn: function (){
 var self=this;
 var suite,runner,result,assertBlock;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$6,$5,$3;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 suite=_st(["fakeError", "fakeErrorFailingInTearDown", "fakeFailure", "testPass"])._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._class())._selector_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
@@ -325,26 +325,22 @@ runner=_st((smalltalk.TestSuiteRunner || TestSuiteRunner))._on_(suite);
 _st(self)._timeout_((200));
 result=_st(runner)._result();
 assertBlock=_st(self)._async_((function(){
-return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(["fakeError"],_st(self)._sortedSelectors_(_st(result)._errors()));
-_st(self)._assert_equals_(["fakeErrorFailingInTearDown", "fakeFailure"],_st(self)._sortedSelectors_(_st(result)._failures()));
+return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(_st(["fakeError"])._asSet(),_st(self)._selectorSetOf_(_st(result)._errors()));
+_st(self)._assert_equals_(_st(["fakeErrorFailingInTearDown", "fakeFailure"])._asSet(),_st(self)._selectorSetOf_(_st(result)._failures()));
 return _st(self)._finished();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$1=_st(runner)._announcer();
-$2=(smalltalk.ResultAnnouncement || ResultAnnouncement);
-$3=(function(ann){
-return smalltalk.withContext(function($ctx2) {
$4=_st(_st(ann)._result()).__eq_eq(result);
-$5=(function(){
-return smalltalk.withContext(function($ctx3) {
$6=_st(_st(result)._runs()).__eq(_st(result)._total());
-return _st($6)._ifTrue_(assertBlock);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($4)._ifTrue_($5);
-}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})});
-_st($1)._on_do_($2,$3);
+_st(_st(runner)._announcer())._on_do_((smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+return smalltalk.withContext(function($ctx2) {
$1=_st(_st(ann)._result()).__eq_eq(result);
+if(smalltalk.assert($1)){
+$2=_st(_st(result)._runs()).__eq(_st(result)._total());
+return _st($2)._ifTrue_(assertBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})}));
 _st(runner)._run();
 return self}, function($ctx1) {$ctx1.fill(self,"testAsyncErrorsAndFailures",{suite:suite,runner:runner,result:result,assertBlock:assertBlock}, smalltalk.SUnitAsyncTest)})},
 args: [],
-source: "testAsyncErrorsAndFailures\x0a\x09| suite runner result assertBlock |\x0a\x09suite := #('fakeError' 'fakeErrorFailingInTearDown' 'fakeFailure' 'testPass') collect: [ :each | self class selector: each ].\x0a    runner := TestSuiteRunner on: suite.\x0a    self timeout: 200.\x0a\x09result := runner result.\x0a    assertBlock := self async: [\x0a\x09\x09self assert: #('fakeError') equals: (self sortedSelectors: result errors).\x0a\x09\x09self assert: #('fakeErrorFailingInTearDown' 'fakeFailure') equals: (self sortedSelectors: result failures).\x0a\x09\x09self finished\x0a  \x09].\x0a    runner announcer on: ResultAnnouncement do: [:ann |\x0a    \x09ann result == result  ifTrue: [ result runs = result total ifTrue: assertBlock ]].\x0a\x09runner run",
-messageSends: ["collect:", "selector:", "class", "on:", "timeout:", "result", "async:", "assert:equals:", "sortedSelectors:", "errors", "failures", "finished", "on:do:", "ifTrue:", "=", "total", "runs", "==", "announcer", "run"],
+source: "testAsyncErrorsAndFailures\x0a\x09| suite runner result assertBlock |\x0a\x09suite := #('fakeError' 'fakeErrorFailingInTearDown' 'fakeFailure' 'testPass') collect: [ :each | self class selector: each ].\x0a    runner := TestSuiteRunner on: suite.\x0a    self timeout: 200.\x0a\x09result := runner result.\x0a    assertBlock := self async: [\x0a\x09\x09self assert: #('fakeError') asSet equals: (self selectorSetOf: result errors).\x0a\x09\x09self assert: #('fakeErrorFailingInTearDown' 'fakeFailure') asSet equals: (self selectorSetOf: result failures).\x0a\x09\x09self finished\x0a  \x09].\x0a    runner announcer on: ResultAnnouncement do: [:ann |\x0a    \x09ann result == result  ifTrue: [ result runs = result total ifTrue: assertBlock ]].\x0a\x09runner run",
+messageSends: ["collect:", "selector:", "class", "on:", "timeout:", "result", "async:", "assert:equals:", "asSet", "selectorSetOf:", "errors", "failures", "finished", "on:do:", "ifTrue:", "=", "total", "runs", "==", "announcer", "run"],
 referencedClasses: ["TestSuiteRunner", "ResultAnnouncement"]
 }),
 smalltalk.SUnitAsyncTest);
@@ -447,7 +443,7 @@ category: 'tests',
 fn: function (){
 var self=this;
 var suite,runner,result,assertBlock;
-return smalltalk.withContext(function($ctx1) { 
var $1,$2,$4,$6,$5,$3;
+return smalltalk.withContext(function($ctx1) { 
var $1,$2;
 suite=_st(["fakeTimeout", "fakeMultipleTimeoutFailing", "fakeMultipleTimeoutPassing", "testPass"])._collect_((function(each){
 return smalltalk.withContext(function($ctx2) {
return _st(_st(self)._class())._selector_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
@@ -455,27 +451,23 @@ runner=_st((smalltalk.TestSuiteRunner || TestSuiteRunner))._on_(suite);
 _st(self)._timeout_((200));
 result=_st(runner)._result();
 assertBlock=_st(self)._async_((function(){
-return smalltalk.withContext(function($ctx2) {
_st(self)._assert_(_st(_st(result)._errors())._isEmpty());
-_st(self)._assert_equals_(["fakeMultipleTimeoutFailing", "fakeTimeout"],_st(self)._sortedSelectors_(_st(result)._failures()));
+return smalltalk.withContext(function($ctx2) {
_st(self)._assert_equals_(_st((smalltalk.Set || Set))._new(),_st(self)._selectorSetOf_(_st(result)._errors()));
+_st(self)._assert_equals_(_st(["fakeMultipleTimeoutFailing", "fakeTimeout"])._asSet(),_st(self)._selectorSetOf_(_st(result)._failures()));
 return _st(self)._finished();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
-$1=_st(runner)._announcer();
-$2=(smalltalk.ResultAnnouncement || ResultAnnouncement);
-$3=(function(ann){
-return smalltalk.withContext(function($ctx2) {
$4=_st(_st(ann)._result()).__eq_eq(result);
-$5=(function(){
-return smalltalk.withContext(function($ctx3) {
$6=_st(_st(result)._runs()).__eq(_st(result)._total());
-return _st($6)._ifTrue_(assertBlock);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx1)})});
-return _st($4)._ifTrue_($5);
-}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})});
-_st($1)._on_do_($2,$3);
+_st(_st(runner)._announcer())._on_do_((smalltalk.ResultAnnouncement || ResultAnnouncement),(function(ann){
+return smalltalk.withContext(function($ctx2) {
$1=_st(_st(ann)._result()).__eq_eq(result);
+if(smalltalk.assert($1)){
+$2=_st(_st(result)._runs()).__eq(_st(result)._total());
+return _st($2)._ifTrue_(assertBlock);
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1)})}));
 _st(runner)._run();
 return self}, function($ctx1) {$ctx1.fill(self,"testTimeouts",{suite:suite,runner:runner,result:result,assertBlock:assertBlock}, smalltalk.SUnitAsyncTest)})},
 args: [],
-source: "testTimeouts\x0a\x09| suite runner result assertBlock |\x0a\x09suite := #('fakeTimeout' 'fakeMultipleTimeoutFailing' 'fakeMultipleTimeoutPassing' 'testPass') collect: [ :each | self class selector: each ].\x0a    runner := TestSuiteRunner on: suite.\x0a    self timeout: 200.\x0a\x09result := runner result.\x0a    assertBlock := self async: [\x0a\x09\x09self assert: result errors isEmpty.\x0a\x09\x09self assert: #('fakeMultipleTimeoutFailing' 'fakeTimeout') equals: (self sortedSelectors: result failures).\x0a\x09\x09self finished\x0a  \x09].\x0a    runner announcer on: ResultAnnouncement do: [:ann |\x0a    \x09ann result == result  ifTrue: [ result runs = result total ifTrue: assertBlock ]].\x0a\x09runner run",
-messageSends: ["collect:", "selector:", "class", "on:", "timeout:", "result", "async:", "assert:", "isEmpty", "errors", "assert:equals:", "sortedSelectors:", "failures", "finished", "on:do:", "ifTrue:", "=", "total", "runs", "==", "announcer", "run"],
-referencedClasses: ["TestSuiteRunner", "ResultAnnouncement"]
+source: "testTimeouts\x0a\x09| suite runner result assertBlock |\x0a\x09suite := #('fakeTimeout' 'fakeMultipleTimeoutFailing' 'fakeMultipleTimeoutPassing' 'testPass') collect: [ :each | self class selector: each ].\x0a    runner := TestSuiteRunner on: suite.\x0a    self timeout: 200.\x0a\x09result := runner result.\x0a    assertBlock := self async: [\x0a\x09\x09self assert: Set new equals: (self selectorSetOf: result errors).\x0a\x09\x09self assert: #('fakeMultipleTimeoutFailing' 'fakeTimeout') asSet equals: (self selectorSetOf: result failures).\x0a\x09\x09self finished\x0a  \x09].\x0a    runner announcer on: ResultAnnouncement do: [:ann |\x0a    \x09ann result == result  ifTrue: [ result runs = result total ifTrue: assertBlock ]].\x0a\x09runner run",
+messageSends: ["collect:", "selector:", "class", "on:", "timeout:", "result", "async:", "assert:equals:", "new", "selectorSetOf:", "errors", "asSet", "failures", "finished", "on:do:", "ifTrue:", "=", "total", "runs", "==", "announcer", "run"],
+referencedClasses: ["TestSuiteRunner", "Set", "ResultAnnouncement"]
 }),
 smalltalk.SUnitAsyncTest);
 

+ 2 - 5
js/amber.js

@@ -267,10 +267,7 @@ amber = (function() {
 	function evaluateSmalltalkScripts() {
 		jQuery(document).ready(function() {
 			jQuery('script[type="text/smalltalk"]').each(function(i, elt) {
-				smalltalk.send(
-					smalltalk.send(smalltalk.Compiler, '_new'),
-					'_evaluateExpression_',
-					[jQuery(elt).html()])
+				smalltalk.Compiler._new()._evaluateExpression_(jQuery(elt).html());
 			});
 		})
 	}
@@ -279,7 +276,7 @@ amber = (function() {
 
 	function populateLocalPackages(){
 		var localStorageRE = /^smalltalk\.packages\.(.*)$/;
-		var localPackages = {};
+		localPackages = {};
 
 		var match, key;
 

+ 15 - 10
js/boot.js

@@ -526,14 +526,19 @@ function Smalltalk() {
 		} else {
 			try {return inContext(worker, setup)}
 			catch(error) {
-				// Reset the context stack in any case
-				st.thisContext = undefined;
 				if(error.smalltalkError) {
 					handleError(error);
-					return nil;
-				} else {
-					throw(error);
-				}
+                } else {
+                    var errorWrapper = st.JavaScriptException._on_(error);
+                    try {errorWrapper._signal()} catch(ex) {}
+                    errorWrapper._context_(st.getThisContext());
+                    handleError(errorWrapper);
+                }
+				// Reset the context stack in any case
+				st.thisContext = undefined;
+                // Throw the exception anyway, as we want to stop
+                // the execution to avoid infinite loops
+				throw error;
 			}
 		}
 	};
@@ -816,13 +821,13 @@ smalltalk.wrapClassName("Boolean", "Kernel", Boolean, smalltalk.Object);
 smalltalk.wrapClassName("Date", "Kernel", Date, smalltalk.Object);
 smalltalk.wrapClassName("UndefinedObject", "Kernel", SmalltalkNil, smalltalk.Object, false);
 
-smalltalk.wrapClassName("Collection", "Kernel", null, smalltalk.Object, false);
-smalltalk.wrapClassName("SequenceableCollection", "Kernel", null, smalltalk.Collection, false);
-smalltalk.wrapClassName("CharacterArray", "Kernel", null, smalltalk.SequenceableCollection, false);
+smalltalk.addClass("Collection", smalltalk.Object, null, "Kernel");
+smalltalk.addClass("SequenceableCollection", smalltalk.Collection, null, "Kernel");
+smalltalk.addClass("CharacterArray", smalltalk.SequenceableCollection, null, "Kernel");
 smalltalk.wrapClassName("String", "Kernel", String, smalltalk.CharacterArray);
 smalltalk.wrapClassName("Symbol", "Kernel", SmalltalkSymbol, smalltalk.CharacterArray, false);
 smalltalk.wrapClassName("Array", "Kernel", Array, smalltalk.SequenceableCollection);
-smalltalk.wrapClassName("RegularExpression", "Kernel", RegExp, smalltalk.String);
+smalltalk.wrapClassName("RegularExpression", "Kernel", RegExp, smalltalk.Object);
 
 smalltalk.wrapClassName("Error", "Kernel", Error, smalltalk.Object);
 smalltalk.wrapClassName("MethodContext", "Kernel", SmalltalkMethodContext, smalltalk.Object, false);

+ 159 - 0
st/Canvas.st

@@ -11,10 +11,37 @@ root
 
 root: aTagBrush
     root := aTagBrush
+!
+
+snippet: anElement
+	"Adds clone of anElement, finds [data-snippet=""*""] subelement
+    and returns TagBrush as if that subelement was just added.
+    
+    Rarely needed to use directly, use `html foo` dynamically installed method
+    for a snippet named foo."
+    
+    | clone caret |
+    
+    clone := anElement asJQuery clone.
+    self with: (TagBrush fromJQuery: clone canvas: self).
+    caret := clone find: '[data-snippet="*"]'.
+    caret toArray isEmpty ifTrue: [ caret := clone ].
+    ^TagBrush fromJQuery: (caret removeAttr: 'data-snippet') canvas: self
 ! !
 
 !HTMLCanvas methodsFor: 'adding'!
 
+entity: aString
+	"Adds a character representing html entity, eg.
+    html entity: 'copy'
+    adds a copyright sign.
+    If a name does not represent valid HTML entity, error is raised."
+	| result |
+    result := ('<span />' asJQuery html: '&', aString, ';') text.
+    result size = 1 ifFalse: [ self error: 'Not an HTML entity: ', aString ].
+    self with: result
+!
+
 with: anObject
     ^self root with: anObject
 ! !
@@ -489,6 +516,132 @@ onJQuery: aJQuery
 		yourself
 ! !
 
+Object subclass: #HTMLSnippet
+	instanceVariableNames: 'snippets'
+	package: 'Canvas'!
+!HTMLSnippet commentStamp!
+HTMLSnippet instance is the registry of html snippets.
+HTMLSnippet current is the public singleton instance.
+
+At the beginning, it scans the document for any html elements
+with 'data-snippet="foo"' attribute and takes them off the document,
+remembering them in the store under the specified name.
+It also install method #foo into HTMLCanvas dynamically.
+
+Every html snippet should mark a 'caret', a place where contents
+can be inserted, by 'data-snippet="*"' (a special name for caret).
+For example:
+
+<li data-snippet='menuelement' class='...'><a data-snippet='*'></a></li>
+
+defines a list element with a link inside; the link itself is marked as a caret.
+
+You can later issue
+
+html menuelement href: '/foo'; with: 'A foo'
+
+to insert the whole snippet and directly manipulate the caret, so it renders:
+
+<li class='...'><a href='/foo'>A foo</a></li>
+
+For a self-careting tags (not very useful, but you do not need to fill class etc.
+you can use
+
+<div class='lots of classes' attr1='one' attr2='two' data-snippet='*bar'></div>
+
+and in code later do:
+
+html bar with: [ xxx ]
+
+to render
+
+<div class='lots of classes' attr1='one' attr2='two'>...added by xxx...</div>!
+
+!HTMLSnippet methodsFor: 'accessing'!
+
+snippetAt: aString
+	^ self snippets at: aString
+!
+
+snippets
+	^snippets ifNil: [ snippets := #{} ]
+! !
+
+!HTMLSnippet methodsFor: 'initialization'!
+
+initializeFromJQuery: aJQuery
+	"Finds and takes out all snippets out of aJQuery.
+    Installs it into self."
+    
+	(self snippetsFromJQuery: aJQuery) do: [ :each |
+    	self installSnippetFromJQuery: each asJQuery ]
+! !
+
+!HTMLSnippet methodsFor: 'method generation'!
+
+snippetAt: aString compile: anElement
+	"Method generation for the snippet.
+    The selector is aString, the method block uses anElement"
+    
+    ClassBuilder new
+    	installMethod: ([ :htmlReceiver | htmlReceiver snippet: anElement ] 
+        	currySelf asCompiledMethod: aString)
+        forClass: HTMLCanvas
+        category: '**snippets'
+! !
+
+!HTMLSnippet methodsFor: 'private'!
+
+snippetsFromJQuery: aJQuery
+	^ (aJQuery find: '[data-snippet]') toArray
+! !
+
+!HTMLSnippet methodsFor: 'snippet installation'!
+
+installSnippetFromJQuery: element
+	| name |
+    name := element attr: 'data-snippet'.
+    name = '*' ifFalse: [
+    	('^\*' asRegexp test: name) 
+            ifTrue: [ 
+            	name := name allButFirst. 
+                element attr: 'data-snippet' put: '*' ]
+          	ifFalse: [ 
+            	element removeAttr: 'data-snippet' ].
+        self snippetAt: name install: (element detach get: 0) ]
+!
+
+snippetAt: aString install: anElement
+	self snippets at: aString put: anElement.
+    self snippetAt: aString compile: anElement
+! !
+
+HTMLSnippet class instanceVariableNames: 'current'!
+
+!HTMLSnippet class methodsFor: 'initialization'!
+
+ensureCurrent
+	current ifNil: [ 
+    	current := super new
+			initializeFromJQuery: document asJQuery;
+			yourself ]
+!
+
+initialize
+	super initialize.
+	self ensureCurrent
+! !
+
+!HTMLSnippet class methodsFor: 'instance creation'!
+
+current
+	^ current
+!
+
+new
+	self shouldNotImplement
+! !
+
 Object subclass: #TagBrush
 	instanceVariableNames: 'canvas element'
 	package: 'Canvas'!
@@ -868,6 +1021,12 @@ appendToJQuery: aJQuery
     self value: (HTMLCanvas onJQuery: aJQuery)
 ! !
 
+!CharacterArray methodsFor: '*Canvas'!
+
+asSnippet
+	^ HTMLSnippet current snippetAt: self asString
+! !
+
 !String methodsFor: '*Canvas'!
 
 appendToBrush: aTagBrush

+ 4 - 0
st/Compiler-AST.st

@@ -156,6 +156,10 @@ scope: aLexicalScope
 
 isBlockNode
 	^true
+!
+
+subtreeNeedsAliasing
+    ^ self shouldBeAliased or: [ self shouldBeInlined ]
 ! !
 
 !BlockNode methodsFor: 'visiting'!

+ 5 - 11
st/Compiler-Core.st

@@ -85,12 +85,10 @@ evaluateExpression: aString
 !
 
 install: aString forClass: aBehavior category: anotherString
-	| compiled |
-	compiled := self eval: (self compile: aString forClass: aBehavior).
-	compiled category: anotherString.
-	aBehavior addCompiledMethod: compiled.
-    self setupClass: aBehavior.
-	^compiled
+   	^ ClassBuilder new
+    	installMethod: (self eval: (self compile: aString forClass: aBehavior))
+        forClass: aBehavior
+        category: anotherString
 !
 
 parse: aString
@@ -105,7 +103,7 @@ recompile: aClass
 	aClass methodDictionary do: [:each |
 		console log: aClass name, ' >> ', each selector.
 		self install: each source forClass: aClass category: each category].
-	self setupClass: aClass.
+	"self setupClass: aClass."
 	aClass isMetaclass ifFalse: [self recompile: aClass class]
 !
 
@@ -113,10 +111,6 @@ recompileAll
 	Smalltalk current classes do: [:each |
 		Transcript show: each; cr.
 		[self recompile: each] valueWithTimeout: 100]
-!
-
-setupClass: aClass
-	<smalltalk.init(aClass)>
 ! !
 
 !Compiler class methodsFor: 'compiling'!

+ 443 - 112
st/Compiler-Interpreter.st

@@ -1,19 +1,14 @@
 Smalltalk current createPackage: 'Compiler-Interpreter' properties: #{}!
 NodeVisitor subclass: #AIContext
-	instanceVariableNames: 'outerContext pc locals receiver selector'
+	instanceVariableNames: 'outerContext pc locals method'
 	package: 'Compiler-Interpreter'!
+!AIContext commentStamp!
+AIContext is like a `MethodContext`, used by the `ASTInterpreter`.
+Unlike a `MethodContext`, it is not read-only.
 
-!AIContext methodsFor: 'accessing'!
+When debugging, `AIContext` instances are created by copying the current `MethodContext` (thisContext)!
 
-initializeFromMethodContext: aMethodContext
-	self pc: aMethodContext pc.
-    self receiver: aMethodContext receiver.
-    self selector: aMethodContext selector.
-    aMethodContext outerContext ifNotNil: [
-		self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
-    aMethodContext locals keysAndValuesDo: [ :key :value |
-    	self locals at: key put: value ]
-!
+!AIContext methodsFor: 'accessing'!
 
 localAt: aString
 	^ self locals at: aString ifAbsent: [ nil ]
@@ -27,6 +22,14 @@ locals
 	^ locals ifNil: [ locals := Dictionary new ]
 !
 
+method
+	^ method
+!
+
+method: aCompiledMethod
+	method := aCompiledMethod
+!
+
 outerContext
 	^ outerContext
 !
@@ -44,32 +47,160 @@ pc: anInteger
 !
 
 receiver
-	^ receiver
+	^ self localAt: 'self'
 !
 
 receiver: anObject
-	receiver := anObject
+	self localAt: 'self' put: anObject
 !
 
 selector
-	^ selector
-!
+	^ self metod
+    	ifNotNil: [ self method selector ]
+! !
 
-selector: aString
-	selector := aString
+!AIContext methodsFor: 'initialization'!
+
+initializeFromMethodContext: aMethodContext
+	self pc: aMethodContext pc.
+    self receiver: aMethodContext receiver.
+    self method: aMethodContext method.
+    aMethodContext outerContext ifNotNil: [
+		self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].
+    aMethodContext locals keysAndValuesDo: [ :key :value |
+    	self locals at: key put: value ]
 ! !
 
 !AIContext class methodsFor: 'instance creation'!
 
 fromMethodContext: aMethodContext
-	^ self new 
+	^ self new
     	initializeFromMethodContext: aMethodContext;
         yourself
 ! !
 
-NodeVisitor subclass: #ASTInterpreter
-	instanceVariableNames: 'currentNode context shouldReturn currentValue'
+Object subclass: #ASTDebugger
+	instanceVariableNames: 'interpreter context'
+	package: 'Compiler-Interpreter'!
+!ASTDebugger commentStamp!
+ASTDebugger is a debugger to Amber.
+It uses an AST interpreter to step through the code.
+
+ASTDebugger instances are created from a `MethodContext` with `ASTDebugger class >> context:`.
+They hold an `AIContext` instance internally, recursive copy of the `MethodContext`.
+
+Use the methods of the 'stepping' protocol to do stepping.!
+
+!ASTDebugger methodsFor: 'accessing'!
+
+context
+	^ context
+!
+
+context: aContext
+	context := AIContext new.
+!
+
+interpreter
+	^ interpreter ifNil: [ interpreter := self defaultInterpreterClass new ]
+!
+
+interpreter: anInterpreter
+	interpreter := anInterpreter
+!
+
+method
+	^ self context method
+! !
+
+!ASTDebugger methodsFor: 'defaults'!
+
+defaultInterpreterClass
+	^ ASTSteppingInterpreter
+! !
+
+!ASTDebugger methodsFor: 'initialization'!
+
+buildAST
+	"Build the AST tree from the method source code.
+    The AST is annotated with a SemanticAnalyzer, 
+    to know the semantics and bindings of each node needed for later debugging"
+    
+    | ast |
+    
+    ast := Smalltalk current parse: self method source.
+    (SemanticAnalyzer on: self context receiver class)
+    	visit: ast.    
+    
+    ^ ast
+!
+
+initializeInterpreter
+	self interpreter interpret: self buildAST nodes first
+!
+
+initializeWithContext: aMethodContext
+	"TODO: do we need to handle block contexts?"
+    
+    self context: (AIContext fromMethodContext: aMethodContext).
+    self initializeInterpreter
+! !
+
+!ASTDebugger methodsFor: 'stepping'!
+
+restart
+	self shouldBeImplemented
+!
+
+resume
+	self shouldBeImplemented
+!
+
+step
+	"The ASTSteppingInterpreter stops at each node interpretation. 
+    One step will interpret nodes until:
+    - we get at the end
+    - the next node is a stepping node (send, assignment, etc.)"
+    
+	[ (self interpreter nextNode notNil and: [ self interpreter nextNode stopOnStepping ])
+		or: [ self interpreter atEnd not ] ] 
+ 			whileFalse: [
+				self interpreter step. 
+                self step ]
+!
+
+stepInto
+	self shouldBeImplemented
+!
+
+stepOver
+	self step
+! !
+
+!ASTDebugger class methodsFor: 'instance creation'!
+
+context: aMethodContext
+	^ self new
+    	initializeWithContext: aMethodContext;
+        yourself
+! !
+
+Object subclass: #ASTInterpreter
+	instanceVariableNames: 'currentNode context shouldReturn result'
 	package: 'Compiler-Interpreter'!
+!ASTInterpreter commentStamp!
+ASTIntepreter is like a `NodeVisitor`, interpreting nodes one after each other.
+It is built using Continuation Passing Style for stepping purposes.
+
+Usage example:
+
+    | ast interpreter |
+    ast := Smalltalk current parse: 'foo 1+2+4'.
+    (SemanticAnalyzer on: Object) visit: ast.
+
+    ASTInterpreter new
+        interpret: ast nodes first;
+        result "Answers 7"!
 
 !ASTInterpreter methodsFor: 'accessing'!
 
@@ -81,8 +212,12 @@ context: anAIContext
 	context := anAIContext
 !
 
-currentValue
-	^ currentValue
+currentNode
+	^ currentNode
+!
+
+result
+	^ result
 ! !
 
 !ASTInterpreter methodsFor: 'initialization'!
@@ -94,14 +229,140 @@ initialize
 
 !ASTInterpreter methodsFor: 'interpreting'!
 
+interpret: aNode
+	shouldReturn := false.
+    self interpret: aNode continue: [ :value |
+    	result := value ]
+!
+
+interpret: aNode continue: aBlock
+	shouldReturn ifTrue: [ ^ self ].
+
+	aNode isNode 
+    	ifTrue: [ 	
+        	currentNode := aNode.
+            self interpretNode: aNode continue: [ :value |
+  				self continue: aBlock value: value ] ]
+        ifFalse: [ self continue: aBlock value: aNode ]
+!
+
+interpretAssignmentNode: aNode continue: aBlock
+	self interpret: aNode right continue: [ :value |
+    	self 
+        	continue: aBlock
+            value: (self assign: aNode left to: value) ]
+!
+
+interpretBlockNode: aNode continue: aBlock
+	"TODO: Context should be set"
+    
+    self 
+    	continue: aBlock 
+        value: [ self interpret: aNode nodes first; result ]
+!
+
+interpretBlockSequenceNode: aNode continue: aBlock
+	self interpretSequenceNode: aNode continue: aBlock
+!
+
+interpretCascadeNode: aNode continue: aBlock
+	"TODO: Handle super sends"
+	
+    self interpret: aNode receiver continue: [ :receiver |
+		"Only interpret the receiver once"
+        aNode nodes do: [ :each | each receiver: receiver ].
+  
+    	self 
+        	interpretAll: aNode nodes allButLast
+    		continue: [
+              	self 
+                	interpret: aNode nodes last
+                	continue: [ :val | self continue: aBlock value: val ] ] ]
+!
+
+interpretClassReferenceNode: aNode continue: aBlock
+	self continue: aBlock value: (Smalltalk current at: aNode value)
+!
+
+interpretDynamicArrayNode: aNode continue: aBlock
+	self interpretAll: aNode nodes continue: [ :array |
+    	self 
+        	continue: aBlock
+			value: array ]
+!
+
+interpretDynamicDictionaryNode: aNode continue: aBlock
+    self interpretAll: aNode nodes continue: [ :array | | hashedCollection |
+    	hashedCollection := HashedCollection new.
+        array do: [ :each | hashedCollection add: each ].
+        self 	
+        	continue: aBlock
+            value: hashedCollection ]
+!
+
+interpretJSStatementNode: aNode continue: aBlock
+	shouldReturn := true.
+	self continue: aBlock value: (self eval: aNode source)
+!
+
+interpretMethodNode: aNode continue: aBlock
+	self interpretAll: aNode nodes continue: [ :array |
+    	self continue: aBlock value: array first ]
+!
+
+interpretNode: aNode continue: aBlock
+    aNode interpreter: self continue: aBlock
+!
+
+interpretReturnNode: aNode continue: aBlock
+    self interpret: aNode nodes first continue: [ :value |
+    	shouldReturn := true.
+		self continue: aBlock value: value ]
+!
+
+interpretSendNode: aNode continue: aBlock
+	"TODO: Handle super sends"
+    
+    self interpret: aNode receiver continue: [ :receiver |
+    	self interpretAll: aNode arguments continue: [ :args |
+    		self 
+            	messageFromSendNode: aNode 
+                arguments: args
+                do: [ :message |
+        			self context pc: self context pc + 1.
+        			self 
+            			continue: aBlock 
+                		value: (message sendTo: receiver) ] ] ]
+!
+
+interpretSequenceNode: aNode continue: aBlock
+	self interpretAll: aNode nodes continue: [ :array |
+    	self continue: aBlock value: array last ]
+!
+
+interpretValueNode: aNode continue: aBlock
+	self continue: aBlock value: aNode value
+!
+
+interpretVariableNode: aNode continue: aBlock
+    self 
+    	continue: aBlock
+        value: (aNode binding isInstanceVar
+			ifTrue: [ self context receiver instVarAt: aNode value ]
+			ifFalse: [ self context localAt: aNode value ])
+! !
+
+!ASTInterpreter methodsFor: 'private'!
+
 assign: aNode to: anObject
 	^ aNode binding isInstanceVar 
     	ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]
       	ifFalse: [ self context localAt: aNode value put: anObject ]
 !
 
-continue: anObject
-	currentValue := anObject
+continue: aBlock value: anObject
+	result := anObject.
+    aBlock value: anObject
 !
 
 eval: aString
@@ -125,22 +386,6 @@ eval: aString
 	^ function valueWithPossibleArguments: self context locals values
 !
 
-interpret: aNode
-	shouldReturn := false.
-    self interpret: aNode continue: [ :value |
-    	currentValue := value ]
-!
-
-interpret: aNode continue: aBlock
-
-	shouldReturn ifTrue: [ ^ self ].
-
-	aNode isNode 
-    	ifTrue: [ self visit: aNode ]
-        ifFalse: [ currentValue := aNode ].
-	aBlock value: self currentValue
-!
-
 interpretAll: aCollection continue: aBlock
 	self 
     	interpretAll: aCollection 
@@ -150,7 +395,7 @@ interpretAll: aCollection continue: aBlock
 
 interpretAll: nodes continue: aBlock result: aCollection
 	nodes isEmpty 
-    	ifTrue: [ aBlock value: aCollection ]
+    	ifTrue: [ self continue: aBlock value: aCollection ]
     	ifFalse: [
     		self interpret: nodes first continue: [:value |
     			self 
@@ -159,108 +404,194 @@ interpretAll: nodes continue: aBlock result: aCollection
   					result: aCollection, { value } ] ]
 !
 
-messageFromSendNode: aSendNode do: aBlock
-	self interpretAll: aSendNode arguments continue: [ :args |
-    	aBlock value: (Message new
+messageFromSendNode: aSendNode arguments: aCollection do: aBlock
+    self 
+        continue: aBlock
+        value: (Message new
     		selector: aSendNode selector;
-        	arguments: args;
-        	yourself) ]
+        	arguments: aCollection;
+        	yourself)
 ! !
 
-!ASTInterpreter methodsFor: 'visiting'!
+!ASTInterpreter methodsFor: 'testing'!
 
-visitAssignmentNode: aNode
-	self interpret: aNode right continue: [ :value |
-    	self continue: (self assign: aNode left to: value) ]
-!
+shouldReturn
+	^ shouldReturn ifNil: [ false ]
+! !
 
-visitBlockNode: aNode
-	"TODO: Context should be set"
-    self continue: [ self interpret: aNode nodes first; currentValue ]
-!
+ASTInterpreter subclass: #ASTSteppingInterpreter
+	instanceVariableNames: 'continuation nextNode'
+	package: 'Compiler-Interpreter'!
+!ASTSteppingInterpreter commentStamp!
+ASTSteppingInterpreter is an interpreter with stepping capabilities.
+Use `#step` to actually interpret the next node.
+
+Usage example:
+
+    | ast interpreter |
+    ast := Smalltalk current parse: 'foo 1+2+4'.
+    (SemanticAnalyzer on: Object) visit: ast.
+
+    interpreter := ASTSteppingInterpreter new
+        interpret: ast nodes first;
+        yourself.
+        
+    debugger step; step.
+    debugger step; step.
+    debugger result."Answers 1"
+    debugger step.
+    debugger result. "Answers 3"
+    debugger step.
+    debugger result. "Answers 7"!
+
+!ASTSteppingInterpreter methodsFor: 'accessing'!
+
+nextNode
+	^ nextNode
+! !
 
-visitCascadeNode: aNode
-	"TODO: Handle super sends"
-	
-    self interpret: aNode receiver continue: [ :receiver |
-		"Only interpret the receiver once"
-        aNode nodes do: [ :each | each receiver: receiver ].
-  
-    	self 
-        	interpretAll: aNode nodes allButLast
-    		continue: [
-              	self 
-                	interpret: aNode nodes last
-                	continue: [ :val | self continue: val ] ] ]
-!
+!ASTSteppingInterpreter methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+    continuation := [  ]
+! !
+
+!ASTSteppingInterpreter methodsFor: 'interpreting'!
+
+interpret: aNode continue: aBlock
+	nextNode := aNode.
+	continuation := [ 
+    	super interpret: aNode continue: aBlock ]
+! !
+
+!ASTSteppingInterpreter methodsFor: 'stepping'!
+
+step
+	continuation value
+! !
+
+!ASTSteppingInterpreter methodsFor: 'testing'!
+
+atEnd
+	^ self shouldReturn or: [ self nextNode == self currentNode ]
+! !
+
+!Node methodsFor: '*Compiler-Interpreter'!
 
-visitClassReferenceNode: aNode
-	self continue: (Smalltalk current at: aNode value)
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretNode: self continue: aBlock
 !
 
-visitDynamicArrayNode: aNode
+isSteppingNode
+	^ false
+! !
 
-	self interpretAll: aNode nodes continue: [ :array |
-    	self continue: array ]
+!AssignmentNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretAssignmentNode: self continue: aBlock
 !
 
-visitDynamicDictionaryNode: aNode
-	
-    self interpretAll: aNode nodes continue: [ :array | | hashedCollection |
-    	hashedCollection := HashedCollection new.
-        array do: [ :each | hashedCollection add: each ].
-        self continue: hashedCollection ]
+isSteppingNode
+	^ true
+! !
+
+!BlockNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretBlockNode: self continue: aBlock
 !
 
-visitJSStatementNode: aNode
-	shouldReturn := true.
-	self continue: (self eval: aNode source)
+isSteppingNode
+	^ true
+! !
+
+!CascadeNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretCascadeNode: self continue: aBlock
+! !
+
+!DynamicArrayNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretDynamicArrayNode: self continue: aBlock
 !
 
-visitReturnNode: aNode
-    self interpret: aNode nodes first continue: [ :value |
-    	shouldReturn := true.
-		self continue: value ]
+isSteppingNode
+	^ true
+! !
+
+!DynamicDictionaryNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretDynamicDictionaryNode: self continue: aBlock
 !
 
-visitSendNode: aNode
-	"TODO: Handle super sends"
-    
-    self interpret: aNode receiver continue: [ :receiver |
-    	self messageFromSendNode: aNode do: [ :message |
-        	self context pc: self context pc + 1.
-        	self continue: (message sendTo: receiver) ] ]
+isSteppingNode
+	^ true
+! !
+
+!JSStatementNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretJSStatementNode: self continue: aBlock
 !
 
-visitSequenceNode: aNode
-	self interpretAll: aNode nodes continue: [ :array |
-    	self continue: array last ]
+isSteppingNode
+	^ true
+! !
+
+!MethodNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretMethodNode: self continue: aBlock
+! !
+
+!ReturnNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretReturnNode: self continue: aBlock
+! !
+
+!SendNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretSendNode: self continue: aBlock
 !
 
-visitValueNode: aNode
-	self continue: aNode value
+isSteppingNode
+	^ true
 ! !
 
-ASTInterpreter subclass: #ASTDebugger
-	instanceVariableNames: 'continuation'
-	package: 'Compiler-Interpreter'!
+!SequenceNode methodsFor: '*Compiler-Interpreter'!
 
-!ASTDebugger methodsFor: 'initialization'!
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretSequenceNode: self continue: aBlock
+! !
 
-initialize
-	super initialize.
-    continuation := [  ]
+!BlockSequenceNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretBlockSequenceNode: self continue: aBlock
 ! !
 
-!ASTDebugger methodsFor: 'interpreting'!
+!ValueNode methodsFor: '*Compiler-Interpreter'!
 
-interpret: aNode continue: aBlock
-	continuation := [ super interpret: aNode continue: aBlock ]
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretValueNode: self continue: aBlock
 ! !
 
-!ASTDebugger methodsFor: 'stepping'!
+!VariableNode methodsFor: '*Compiler-Interpreter'!
 
-stepOver
-	continuation value
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretVariableNode: self continue: aBlock
+! !
+
+!ClassReferenceNode methodsFor: '*Compiler-Interpreter'!
+
+interpreter: anInterpreter continue: aBlock
+	^ anInterpreter interpretClassReferenceNode: self continue: aBlock
 ! !
 

+ 104 - 7
st/Compiler-Tests.st

@@ -1,9 +1,15 @@
 Smalltalk current createPackage: 'Compiler-Tests' properties: #{}!
-TestCase subclass: #ASTInterpreterTest
+TestCase subclass: #AbstractASTInterpreterTest
 	instanceVariableNames: ''
 	package: 'Compiler-Tests'!
 
-!ASTInterpreterTest methodsFor: 'accessing'!
+!AbstractASTInterpreterTest methodsFor: 'accessing'!
+
+interpreter
+	^ self subclassResponsibility
+! !
+
+!AbstractASTInterpreterTest methodsFor: 'interpreting'!
 
 analyze: aNode forClass: aClass
 	(SemanticAnalyzer on: aClass) visit: aNode.
@@ -30,7 +36,7 @@ interpret: aString receiver: anObject withArguments: aDictionary
     	context: ctx;
     	interpret: (self parse: aString forClass: anObject class) 
         	nodes first;
-        currentValue
+        result
 !
 
 interpret: aString withArguments: aDictionary
@@ -38,11 +44,9 @@ interpret: aString withArguments: aDictionary
     	interpret: aString 
         receiver: Object new
         withArguments: aDictionary
-!
+! !
 
-interpreter
-	^ ASTInterpreter new
-!
+!AbstractASTInterpreterTest methodsFor: 'parsing'!
 
 parse: aString
 	^ Smalltalk current parse: aString
@@ -52,6 +56,16 @@ parse: aString forClass: aClass
 	^ self analyze: (self parse: aString) forClass: aClass
 ! !
 
+AbstractASTInterpreterTest subclass: #ASTInterpreterTest
+	instanceVariableNames: ''
+	package: 'Compiler-Tests'!
+
+!ASTInterpreterTest methodsFor: 'accessing'!
+
+interpreter
+	^ ASTInterpreter new
+! !
+
 !ASTInterpreterTest methodsFor: 'tests'!
 
 testBinarySend
@@ -86,6 +100,15 @@ testInlinedJSStatement
 		equals: 5
 !
 
+testInstVarAccess
+	self 
+    	assert: (self 
+    		interpret: 'foo ^ x'
+        	receiver: 2@3
+        	withArguments: #{})
+        equals: 2
+!
+
 testInstVarAssignment
 	self 
     	assert: (self 
@@ -99,10 +122,84 @@ 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
+!
+
 testTempAssignment
 	self assert: (self interpret: 'foo | a | a := 2. ^ a') equals: 2
 ! !
 
+AbstractASTInterpreterTest subclass: #ASTSteppingInterpreterTest
+	instanceVariableNames: 'interpreter'
+	package: 'Compiler-Tests'!
+
+!ASTSteppingInterpreterTest methodsFor: 'accessing'!
+
+interpreter
+	^ interpreter ifNil: [ interpreter := ASTSteppingInterpreter new ]
+! !
+
+!ASTSteppingInterpreterTest methodsFor: 'tests'!
+
+testAtEnd
+	self interpret: 'foo 1 + 2'.
+    self deny: self interpreter atEnd.
+
+    self interpreter step.
+    self deny: self interpreter atEnd.
+    
+    self interpreter step.
+    self deny: self interpreter atEnd.
+    
+    self interpreter step.
+    self deny: self interpreter atEnd.
+    
+    self interpreter step.
+    self assert: self interpreter atEnd
+!
+
+testMessageSend
+	self interpret: 'foo 1 + 2'.
+    
+    "SequenceNode"
+    self interpreter step.
+    
+    "SendNode"
+    self interpreter step.
+    
+     "ValueNode"
+    self interpreter step.
+    self assert: self interpreter currentNode value equals: 1.
+    
+    "ValueNode"
+    self interpreter step.
+    self assert: self interpreter currentNode value equals: 2.
+    
+    "Result"
+    self interpreter step.
+    self assert: self interpreter result equals: 3
+!
+
+testSimpleStepping
+	self interpret: 'foo 1'.
+    
+    "SequenceNode"
+    self interpreter step.
+    
+    self assert: self interpreter result isNil.
+    
+    "ValueNode"
+    self interpreter step.
+    
+    self assert: self interpreter result equals: 1
+! !
+
 TestCase subclass: #CodeGeneratorTest
 	instanceVariableNames: 'receiver'
 	package: 'Compiler-Tests'!

+ 3 - 21
st/IDE.st

@@ -208,22 +208,6 @@ selection
 	^editor getSelection
 !
 
-selectionEnd
-   ^textarea element selectionEnd
-!
-
-selectionEnd: anInteger
-   textarea element selectionEnd: anInteger
-!
-
-selectionStart
-   ^textarea element selectionStart
-!
-
-selectionStart: anInteger
-   textarea element selectionStart: anInteger
-!
-
 setEditorOn: aTextarea
 	<self['@editor'] = CodeMirror.fromTextArea(aTextarea, {
 		theme: 'amber',
@@ -260,7 +244,7 @@ eval: aString
 	compiler := Compiler new.
 	[compiler parseExpression: aString] on: Error do: [:ex |
 		^window alert: ex messageText].
-	^(compiler eval: (compiler compile: 'doIt ^[', aString, '] value' forClass: DoIt)) fn applyTo: self receiver arguments: #()
+	^compiler evaluateExpression: aString
 !
 
 fileIn
@@ -846,7 +830,7 @@ compileMethodDefinition
 compileMethodDefinitionFor: aClass
     | compiler method source node | 
     source := sourceArea val.
-    selectedProtocol ifNil: [selectedProtocol := selectedMethod category].
+    selectedProtocol ifNil: [ selectedProtocol := selectedMethod category ].
     compiler := Compiler new.
     compiler source: source.
     node := compiler parse: source.
@@ -854,15 +838,13 @@ compileMethodDefinitionFor: aClass
 	^window alert: 'PARSE ERROR: ', node reason, ', position: ', node position asString].
     compiler currentClass: aClass.
     method := compiler eval: (compiler compileNode: node).
-    method category: selectedProtocol.
     compiler unknownVariables do: [:each |
          "Do not try to redeclare javascript's objects"
          (window at: each) ifNil: [
 	 	(window confirm: 'Declare ''', each, ''' as instance variable?') ifTrue: [
 			self addInstanceVariableNamed: each toClass: aClass.
 			^self compileMethodDefinitionFor: aClass]]].
-    aClass addCompiledMethod: method.
-    compiler setupClass: aClass.
+    ClassBuilder new installMethod: method forClass: aClass category: selectedProtocol.
     self updateMethodsList.
     self selectMethod: method
 !

+ 8 - 0
st/Kernel-Announcements.st

@@ -2,6 +2,9 @@ Smalltalk current createPackage: 'Kernel-Announcements' properties: #{}!
 Object subclass: #AnnouncementSubscription
 	instanceVariableNames: 'block announcementClass'
 	package: 'Kernel-Announcements'!
+!AnnouncementSubscription commentStamp!
+The subscription is a single entry in a subscription registry of an `Announcer`.
+Several subscriptions by the same object is possible.!
 
 !AnnouncementSubscription methodsFor: 'accessing'!
 
@@ -35,6 +38,11 @@ handlesAnnouncement: anAnnouncement
 Object subclass: #Announcer
 	instanceVariableNames: 'registry subscriptions'
 	package: 'Kernel-Announcements'!
+!Announcer commentStamp!
+The code is based on the announcements as [described by Vassili Bykov](http://www.cincomsmalltalk.com/userblogs/vbykov/blogView?searchCategory=Announcements%20Framework).
+The Announcer holds annoncement subscriptions (`AnnouncementSubscription`) in a private registry.
+
+Use `#on:do:` to register subscriptions.!
 
 !Announcer methodsFor: 'announcing'!
 

+ 53 - 29
st/Kernel-Classes.st

@@ -394,10 +394,11 @@ ClassBuilder is responsible for compiling new classes or modifying existing clas
 
 Rather than using ClassBuilder directly to compile a class, use `Class >> subclass:instanceVariableNames:package:`.!
 
-!ClassBuilder methodsFor: 'class creation'!
+!ClassBuilder methodsFor: 'api'!
 
 class: aClass instanceVariableNames: aString
 	self basicClass: aClass instanceVariableNames: aString.
+    self setupClass: aClass.
     
     SystemAnnouncer current
     	announce: (ClassDefinitionChanged new
@@ -405,6 +406,13 @@ class: aClass instanceVariableNames: aString
             yourself)
 !
 
+installMethod: aCompiledMethod forClass: aBehavior category: aString
+	aCompiledMethod category: aString.
+	aBehavior addCompiledMethod: aCompiledMethod.
+    self setupClass: aBehavior.
+	^aCompiledMethod
+!
+
 renameClass: aClass to: aString
 	self basicRenameClass: aClass to: aString.
     
@@ -464,11 +472,13 @@ basicAddSubclassOf: aClass named: aString instanceVariableNames: aCollection pac
 !
 
 basicClass: aClass instanceVariableNames: aString
+	self basicClass: aClass instanceVariables: (self instanceVariableNamesFor: aString)
+!
+
+basicClass: aClass instanceVariables: aCollection
 
 	aClass isMetaclass ifFalse: [self error: aClass name, ' is not a metaclass'].
-	aClass basicAt: 'iVarNames' put: (self instanceVariableNamesFor: aString).
-    
-	self setupClass: aClass
+	aClass basicAt: 'iVarNames' put: aCollection
 !
 
 basicRemoveClass: aClass
@@ -492,50 +502,64 @@ copyClass: aClass named: aString
 		instanceVariableNames: aClass instanceVariableNames 
 		package: aClass package name.
 
-	self setupClass: newClass.
+	self copyClass: aClass to: newClass.
+    
+	^newClass
+!
 
-	aClass methodDictionary values do: [:each |
-		Compiler new install: each source forClass: newClass category: each category].
+copyClass: aClass to: anotherClass
 
-	aClass class methodDictionary values do: [:each |
-		Compiler new install: each source forClass: newClass class category: each category].
+	anotherClass comment: aClass comment.
 
-	self setupClass: newClass.
-	^newClass
+	aClass methodDictionary values do: [ :each |
+		Compiler new install: each source forClass: anotherClass category: each category ].
+
+	self basicClass: anotherClass class instanceVariables: aClass class instanceVariableNames.
+
+	aClass class methodDictionary values do: [ :each |
+		Compiler new install: each source forClass: anotherClass class category: each category ].
+
+	self setupClass: anotherClass
 !
 
 instanceVariableNamesFor: aString
 	^(aString tokenize: ' ') reject: [ :each | each isEmpty ]
 !
 
+migrateClass: aClass superclass: anotherClass
+	self 
+    	migrateClassNamed: aClass name
+        superclass: anotherClass
+        instanceVariableNames: aClass instanceVariableNames
+        package: aClass package name
+!
+
 migrateClassNamed: aString superclass: aClass instanceVariableNames: aCollection package: packageName
 	| oldClass newClass |
     
     oldClass := Smalltalk current at: aString.
     
-    "Rename the class for existing instances"
-	self 
-    	basicRenameClass: oldClass to: 'Old', aString;
-        basicRemoveClass: oldClass.
-        
+    "Rename the old class for existing instances"
+	self basicRenameClass: oldClass to: 'Old', aString.
+    
     newClass := self 
 		addSubclassOf: aClass
 		named: aString 
 		instanceVariableNames: aCollection
 		package: packageName.
 
-	self setupClass: newClass.
-
-	newClass comment: oldClass comment.
-
-	oldClass methodDictionary values do: [:each |
-		Compiler new install: each source forClass: newClass category: each category].
-
-	oldClass class methodDictionary values do: [:each |
-		Compiler new install: each source forClass: newClass class category: each category].
-
-	self setupClass: newClass.
-    
+	oldClass subclasses do: [ :each |
+    	self migrateClass: each superclass: newClass ].
+
+    [ self copyClass: oldClass to: newClass ] 
+    	on: Error
+        do: [ :exception |
+        	self 
+            	basicRemoveClass: newClass;
+            	basicRenameClass: oldClass to: aString.
+            exception signal ].
+            
+    self basicRemoveClass: oldClass.
 	^newClass
 ! !
 
@@ -559,7 +583,7 @@ scanFrom: aChunkParser
 	[chunk := aChunkParser nextChunk.
 	chunk isEmpty] whileFalse: [
 	    self compileMethod: chunk].
-	Compiler new setupClass: class
+	ClassBuilder new setupClass: class
 ! !
 
 !ClassCategoryReader methodsFor: 'initialization'!

+ 23 - 11
st/Kernel-Collections.st

@@ -257,13 +257,9 @@ ifNotEmpty: aBlock
 !
 
 includes: anObject
-	<
-		var i = self.length;
-		while (i--) {
-			if (smalltalk.send(self[i], "__eq", [anObject])) {return true;}	
-		}
-		return false
-	>
+	| sentinel |
+    sentinel := Object new.
+    ^(self detect: [ :each | each = anObject] ifNone: [ sentinel ]) ~= sentinel
 !
 
 isEmpty
@@ -683,7 +679,7 @@ indexOf: anObject
 indexOf: anObject ifAbsent: aBlock
 	<
 		for(var i=0;i<self.length;i++) {
-			if(smalltalk.send(self[i], '__eq', [anObject])) {return i+1}
+			if(self[i].__eq(anObject)) {return i+1}
 		};
 		return aBlock();
 	>
@@ -776,6 +772,12 @@ withIndexDo: aBlock
 	<for(var i=0;i<self.length;i++){aBlock(self[i], i+1);}>
 ! !
 
+!SequenceableCollection methodsFor: 'testing'!
+
+includes: anObject
+	^(self indexOf: anObject ifAbsent: [nil]) notNil
+! !
+
 SequenceableCollection subclass: #Array
 	instanceVariableNames: ''
 	package: 'Kernel-Collections'!
@@ -1042,6 +1044,10 @@ asNumber
 	<return Number(self)>
 !
 
+asRegexp
+	^ RegularExpression fromString: self
+!
+
 asSelector
 	<return smalltalk.selector(self)>
 !
@@ -1322,7 +1328,7 @@ asJSON
 !
 
 asJavascript
-	^'smalltalk.symbolFor("', self asString, '")'
+	^'smalltalk.symbolFor(', self asString asJavascript, ')'
 !
 
 asSelector
@@ -1439,8 +1445,10 @@ remove: anObject
 !Set methodsFor: 'comparing'!
 
 = aCollection
-	^self class = aCollection class and: [
-		elements = aCollection asArray]
+	self class = aCollection class ifFalse: [ ^ false ].
+    self size = aCollection size ifFalse: [ ^ false ].
+	self do: [:each | (aCollection includes: each) ifFalse: [ ^ false ] ].
+	^ true
 ! !
 
 !Set methodsFor: 'converting'!
@@ -1451,6 +1459,10 @@ asArray
 
 !Set methodsFor: 'enumerating'!
 
+collect: aBlock
+	^self class withAll: (elements collect: aBlock)
+!
+
 detect: aBlock ifNone: anotherBlock
 	^elements detect: aBlock ifNone: anotherBlock
 !

+ 63 - 0
st/Kernel-Exceptions.st

@@ -2,6 +2,13 @@ Smalltalk current createPackage: 'Kernel-Exceptions' properties: #{}!
 Object subclass: #Error
 	instanceVariableNames: 'messageText'
 	package: 'Kernel-Exceptions'!
+!Error commentStamp!
+From the ANSI standard:
+
+This protocol describes the behavior of instances of class `Error`. 
+These are used to represent error conditions that prevent the normal continuation of processing. 
+Actual error exceptions used by an application may be subclasses of this class.
+As `Error` is explicitly specified  to be subclassable, conforming implementations must implement its behavior in a non-fragile manner.!
 
 !Error methodsFor: 'accessing'!
 
@@ -55,9 +62,54 @@ signal: aString
 		signal: aString
 ! !
 
+Error subclass: #JavaScriptException
+	instanceVariableNames: 'exception'
+	package: 'Kernel-Exceptions'!
+!JavaScriptException commentStamp!
+A JavaScriptException is thrown when a non-Smalltalk exception occurs while in the Smalltalk stack.
+See `boot.js` `inContext()` and `BlockClosure >> on:do:`!
+
+!JavaScriptException methodsFor: 'accessing'!
+
+context: aMethodContext
+	"Set the context from the outside.
+    See boot.js `inContext()` exception handling"
+    
+    <self.context = aMethodContext>
+!
+
+exception
+	^ exception
+!
+
+exception: anException
+	exception := anException
+!
+
+messageText
+	<return 'JavaScript exception: ' + self["@exception"].toString()>
+! !
+
+!JavaScriptException class methodsFor: 'instance creation'!
+
+on: anException
+	^ self new
+    	exception: anException;
+        yourself
+!
+
+on: anException context: aMethodContext
+	^ self new
+    	exception: anException;
+        context: aMethodContext;
+        yourself
+! !
+
 Error subclass: #MessageNotUnderstood
 	instanceVariableNames: 'message receiver'
 	package: 'Kernel-Exceptions'!
+!MessageNotUnderstood commentStamp!
+This exception is provided to support `Object>>doesNotUnderstand:`.!
 
 !MessageNotUnderstood methodsFor: 'accessing'!
 
@@ -84,6 +136,8 @@ receiver: anObject
 Error subclass: #NonBooleanReceiver
 	instanceVariableNames: 'object'
 	package: 'Kernel-Exceptions'!
+!NonBooleanReceiver commentStamp!
+NonBooleanReceiver exceptions may be thrown when executing inlined methods such as `#ifTrue:` with a non boolean receiver.!
 
 !NonBooleanReceiver methodsFor: 'accessing'!
 
@@ -98,6 +152,15 @@ object: anObject
 Object subclass: #ErrorHandler
 	instanceVariableNames: ''
 	package: 'Kernel-Exceptions'!
+!ErrorHandler commentStamp!
+ErrorHandler is used to manage Smalltalk errors. 
+See `boot.js` `handleError()` function.
+
+Subclasses of `ErrorHandler` can register themselves as the current handler with
+`ErrorHandler class >> register`.
+
+Subclasses may override `#handleError:` to perform an action on the thrown exception.
+The default behavior is to log the error and the context stack to the JavaScript console.!
 
 !ErrorHandler methodsFor: 'error handling'!
 

+ 97 - 11
st/Kernel-Methods.st

@@ -40,13 +40,38 @@ whileTrue: aBlock
 	<while(self()) {aBlock()}>
 ! !
 
+!BlockClosure methodsFor: 'converting'!
+
+asCompiledMethod: aString
+	<return smalltalk.method({selector:aString, fn:self});>
+!
+
+currySelf
+	"Transforms [ :selfarg :x :y | stcode ] block
+    which represents JS function (selfarg, x, y, ...) {jscode}
+    into function (x, y, ...) {jscode} that takes selfarg from 'this'.
+    IOW, it is usable as JS method and first arg takes the receiver."
+    
+    <
+    	return function () {
+    		var args = [ this ];
+        	args.push.apply(args, arguments);
+        	return self.apply(null, args);
+    	}
+	>
+! !
+
 !BlockClosure methodsFor: 'error handling'!
 
 on: anErrorClass do: aBlock
-	^self try: self catch: [:error |
-	    (error isKindOf: anErrorClass) 
-	     ifTrue: [aBlock value: error]
-	     ifFalse: [error signal]]
+	"All exceptions thrown in the Smalltalk stack are cought.
+    Convert all JS exceptions to JavaScriptException instances."
+    
+	^self try: self catch: [ :error | | smalltalkError |
+    	smalltalkError := Smalltalk current asSmalltalkException: error.
+	    (smalltalkError isKindOf: anErrorClass) 
+	     ifTrue: [ aBlock value: smalltalkError ]
+	     ifFalse: [ smalltalkError signal ] ]
 ! !
 
 !BlockClosure methodsFor: 'evaluating'!
@@ -80,7 +105,7 @@ newValue:  anObject value: anObject2
 newValue:  anObject value: anObject2 value: anObject3
 	"Use the receiver as a JS constructor. 
 	*Do not* use this method to instanciate Smalltalk objects!!"
-	<return new self(anObject, anObject2)>
+	<return new self(anObject, anObject2,anObject3)>
 !
 
 timeToRun
@@ -237,12 +262,7 @@ maxPoolSize: anInteger
 	maxPoolSize := anInteger
 ! !
 
-!ForkPool methodsFor: 'action'!
-
-addWorker
-	worker valueWithTimeout: 0.
-    poolSize := poolSize + 1
-!
+!ForkPool methodsFor: 'actions'!
 
 fork: aBlock
 	poolSize < self maxPoolSize ifTrue: [ self addWorker ].
@@ -275,6 +295,13 @@ makeWorker
         	[ block value ] ensure: [ self addWorker ]]]
 ! !
 
+!ForkPool methodsFor: 'private'!
+
+addWorker
+	worker valueWithTimeout: 0.
+    poolSize := poolSize + 1
+! !
+
 ForkPool class instanceVariableNames: 'default'!
 
 !ForkPool class methodsFor: 'accessing'!
@@ -419,3 +446,62 @@ isBlockContext
 	^ self selector isNil
 ! !
 
+Object subclass: #NativeFunction
+	instanceVariableNames: ''
+	package: 'Kernel-Methods'!
+!NativeFunction commentStamp!
+NativeFunction is a wrapper around native functions, such as `WebSocket`.
+For 'normal' functions (whose constructor is the JavaScript `Function` object), use `BlockClosure`.
+
+See the class-side `instance creation` methods.
+
+Created instances will most probably be instance of `JSObjectProxy`.
+
+Usage example:
+
+    | ws |
+    ws := NativeFunction constructor: 'WebSocket' value: 'ws://localhost'.
+    ws at: 'onopen' put: [ ws send: 'hey there from Amber' ]!
+
+!NativeFunction class methodsFor: 'instance creation'!
+
+constructor: aString
+	<
+    	var native=eval(aString); 
+        return new native();
+	>
+!
+
+constructor: aString value:anObject
+	<
+    	var native=eval(aString); 
+        return new native(anObject);
+	>
+!
+
+constructor: aString value:anObject value: anObject2
+	<
+    	var native=eval(aString); 
+        return new native(anObject,anObject2);
+	>
+!
+
+constructor: aString value:anObject value: anObject2 value:anObject3
+	<
+    	var native=eval(aString); 
+        return new native(anObject,anObject2, anObject3);
+	>
+! !
+
+!NativeFunction class methodsFor: 'testing'!
+
+exists: aString
+	<
+    	if(aString in window) {
+        	return true
+        } else {
+        	return false
+        }
+    >
+! !
+

+ 49 - 4
st/Kernel-Objects.st

@@ -672,6 +672,15 @@ at: aSymbol
 	<return self['@jsObject'][aSymbol._asString()]>
 !
 
+at: aSymbol ifAbsent: aBlock
+	"return the aSymbol property or evaluate aBlock if the property is not defined on the object"
+	<
+    	var obj = self['@jsObject'],
+        	symbol = aSymbol._asString();
+		return symbol in obj ? obj[symbol] : aBlock();
+	>
+!
+
 at: aSymbol put: anObject
 	<self['@jsObject'][aSymbol._asString()] = anObject>
 !
@@ -682,6 +691,12 @@ jsObject
 
 jsObject: aJSObject
 	jsObject := aJSObject
+!
+
+value
+	"if attribute 'value' exists on the JS object return it,
+    otherwise return the result of Object>>value."
+	^ self at: 'value' ifAbsent: [super value]
 ! !
 
 !JSObjectProxy methodsFor: 'enumerating'!
@@ -1183,6 +1198,15 @@ named: aPackageName ifAbsent: aBlock
 
 !Package class methodsFor: 'commit paths'!
 
+commitPathsFromLoader
+    <
+    var cp = smalltalk['@@commitPath'];
+    if (!!cp) return;
+    if (cp.js) self._defaultCommitPathJs_(cp.js);
+    if (cp.st) self._defaultCommitPathSt_(cp.st);
+    >
+!
+
 defaultCommitPathJs
 	^ defaultCommitPathJs ifNil: [ defaultCommitPathJs := 'js']
 !
@@ -1204,6 +1228,13 @@ resetCommitPaths
         defaultCommitPathSt := nil.
 ! !
 
+!Package class methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+    self commitPathsFromLoader
+! !
+
 !Package class methodsFor: 'loading-storing'!
 
 fetch: aPackageName
@@ -1460,6 +1491,15 @@ removeClass: aClass
 
 !Smalltalk methodsFor: 'error handling'!
 
+asSmalltalkException: anObject
+	"A JavaScript exception may be thrown.
+    We then need to convert it back to a Smalltalk object"
+    
+    ^ ((self isSmalltalkObject: anObject) and: [ anObject isKindOf: Error ])
+    	ifTrue: [ anObject ]
+      	ifFalse: [ JavaScriptException on: anObject ]
+!
+
 parseError: anException parsing: aString
 	^ ParseError new messageText: 'Parse error on line ', (anException basicAt: 'line') ,' column ' , (anException basicAt: 'column') ,' : Unexpected character ', (anException basicAt: 'found')
 ! !
@@ -1531,6 +1571,15 @@ createPackage: packageName properties: aDict
     ^ self createPackage: packageName
 ! !
 
+!Smalltalk methodsFor: 'testing'!
+
+isSmalltalkObject: anObject
+	"Consider anObject a Smalltalk object if it has a 'klass' property.
+    Note that this may be unaccurate"
+    
+    <return typeof anObject.klass !!== 'undefined'>
+! !
+
 Smalltalk class instanceVariableNames: 'current'!
 
 !Smalltalk class methodsFor: 'accessing'!
@@ -1658,7 +1707,3 @@ new
 	    self error: 'You cannot create new instances of UndefinedObject. Use nil'
 ! !
 
-nil subclass: #[object Object]
-	instanceVariableNames: ''
-	package: 'Kernel-Objects'!
-

+ 109 - 1
st/Kernel-Tests.st

@@ -17,6 +17,15 @@ testCompiledSource
 	self assert: ([1+1] compiledSource includesSubString: 'function')
 !
 
+testCurrySelf
+	| curriedMethod array |
+    curriedMethod := [ :selfarg :x | selfarg at: x ] currySelf asCompiledMethod: 'foo:'.
+    array := #(3 1 4).
+    ClassBuilder new installMethod: curriedMethod forClass: Array category: '**test helper'.
+    [ self assert: 1 equals: (array foo: 2) ]
+    ensure: [ Array removeCompiledMethod: curriedMethod ]
+!
+
 testEnsure
 	self assert: 3 equals: ([3] ensure: [4])
 !
@@ -25,6 +34,21 @@ testEnsureRaises
 	self should: [[Error new signal] ensure: [true]] raise: Error
 !
 
+testExceptionSemantics
+	"See https://github.com/NicolasPetton/amber/issues/314"
+    self timeout: 100.
+    
+    (self async:  [ 
+    	[ 
+        	self assert: true. 
+            Error signal. 
+            "The following should *not* be run"
+            self deny: true.
+            self finished.
+  		] on: Error do: [ :ex | self finished ] 
+	]) valueWithTimeout: 0
+!
+
 testNumArgs
 	self assert: [] numArgs equals: 0.
 	self assert: [:a :b | ] numArgs equals: 2
@@ -233,6 +257,39 @@ testClassMigration
     Smalltalk current removeClass: ObjectMock2
 !
 
+testClassMigrationWithClassInstanceVariables
+    
+    builder copyClass: ObjectMock named: 'ObjectMock2'.
+    ObjectMock2 class instanceVariableNames: 'foo bar'.
+    
+    "Change the superclass of ObjectMock2"
+    ObjectMock subclass: (Smalltalk current at: 'ObjectMock2')
+    	instanceVariableNames: ''
+        package: 'Kernel-Tests'.
+    
+    self assert: ObjectMock2 class instanceVariableNames equals: #('foo' 'bar').
+    
+    Smalltalk current removeClass: ObjectMock2
+!
+
+testClassMigrationWithSubclasses
+    
+    builder copyClass: ObjectMock named: 'ObjectMock2'.
+    ObjectMock2 subclass: 'ObjectMock3' instanceVariableNames: '' package: 'Kernel-Tests'.
+    ObjectMock3 subclass: 'ObjectMock4' instanceVariableNames: '' package: 'Kernel-Tests'.
+    
+    "Change the superclass of ObjectMock2"
+    ObjectMock subclass: (Smalltalk current at: 'ObjectMock2')
+    	instanceVariableNames: ''
+        package: 'Kernel-Tests'.
+    
+    self assert: (ObjectMock subclasses includes: ObjectMock2).
+    self assert: (ObjectMock2 subclasses includes: ObjectMock3).
+    self assert: (ObjectMock3 subclasses includes: ObjectMock4).
+    
+    ObjectMock allSubclasses do: [ :each | Smalltalk current removeClass: each ]
+!
+
 testInstanceVariableNames
 	self assert: (builder instanceVariableNamesFor: '  hello   world   ') equals: #('hello' 'world')
 ! !
@@ -874,11 +931,20 @@ TestCase subclass: #JSObjectProxyTest
 !JSObjectProxyTest methodsFor: 'accessing'!
 
 jsObject
-	<return jsObject = {a: 1, b: function() {return 2;}, c: function(object) {return object;}, d: '', 'e': null}>
+	<return jsObject = {a: 1, b: function() {return 2;}, c: function(object) {return object;}, d: '', 'e': null, 'f': undefined}>
 ! !
 
 !JSObjectProxyTest methodsFor: 'tests'!
 
+testAtIfAbsent
+	| testObject |
+    testObject := self jsObject.
+	self assert: 'Property does not exist' equals: (testObject at: 'abc' ifAbsent: ['Property does not exist']).
+	self assert: nil equals: (testObject at: 'e' ifAbsent: ['Property does not exist']).
+    self assert: 1 equals: (testObject at: 'a' ifAbsent: ['Property does not exist']).
+    self assert: nil equals: (testObject at: 'f' ifAbsent: ['Property does not exist']).
+!
+
 testDNU
 	self should: [self jsObject foo] raise: MessageNotUnderstood
 !
@@ -916,6 +982,14 @@ testPropertyThatReturnsUndefined
     self assert: object e isNil
 !
 
+testValue
+	| testObject |
+    testObject := self jsObject.
+	self assert: '[object Object]' equals: testObject value printString.
+    testObject at: 'value' put: 'aValue'.
+	self assert: 'aValue' equals: testObject value
+!
+
 testYourself
 	| object |
 	object := self jsObject
@@ -925,6 +999,29 @@ testYourself
 	self assert: object d equals: 'test'
 ! !
 
+TestCase subclass: #JavaScriptExceptionTest
+	instanceVariableNames: ''
+	package: 'Kernel-Tests'!
+
+!JavaScriptExceptionTest methodsFor: 'helpers'!
+
+throwException
+	<throw 'test'>
+! !
+
+!JavaScriptExceptionTest methodsFor: 'testing'!
+
+testCatchingException
+	[ self throwException ]
+  		on: Error
+        do: [ :error | 
+			self assert: error exception = 'test' ]
+!
+
+testRaisingException
+	self should: [ self throwException ] raise: JavaScriptException
+! !
+
 TestCase subclass: #NumberTest
 	instanceVariableNames: ''
 	package: 'Kernel-Tests'!
@@ -1400,6 +1497,17 @@ testAt
 	self should: [Set new at: 1 put: 2] raise: Error
 !
 
+testCollect
+	self assert: #(0 2) asSet equals: (#(5 6 8) asSet collect: [ :x | x \\ 3 ])
+!
+
+testComparing
+	self assert: #(0 2) asSet equals: #(0 2) asSet.
+    self assert: #(2 0) asSet equals: #(0 2) asSet.
+    self deny: #(0 2 3) asSet = #(0 2) asSet.
+    self deny: #(1 2) asSet = #(0 2) asSet
+!
+
 testPrintString
 	| set |
 	set := Set new.

+ 6 - 6
st/SUnit-Tests.st

@@ -100,8 +100,8 @@ fakeTimeout
 
 !SUnitAsyncTest methodsFor: 'private'!
 
-sortedSelectors: aCollection
-	^(aCollection collect: [:each | each selector]) sorted
+selectorSetOf: aCollection
+	^(aCollection collect: [:each | each selector]) asSet
 ! !
 
 !SUnitAsyncTest methodsFor: 'running'!
@@ -123,8 +123,8 @@ testAsyncErrorsAndFailures
     self timeout: 200.
 	result := runner result.
     assertBlock := self async: [
-		self assert: #('fakeError') equals: (self sortedSelectors: result errors).
-		self assert: #('fakeErrorFailingInTearDown' 'fakeFailure') equals: (self sortedSelectors: result failures).
+		self assert: #('fakeError') asSet equals: (self selectorSetOf: result errors).
+		self assert: #('fakeErrorFailingInTearDown' 'fakeFailure') asSet equals: (self selectorSetOf: result failures).
 		self finished
   	].
     runner announcer on: ResultAnnouncement do: [:ann |
@@ -166,8 +166,8 @@ testTimeouts
     self timeout: 200.
 	result := runner result.
     assertBlock := self async: [
-		self assert: result errors isEmpty.
-		self assert: #('fakeMultipleTimeoutFailing' 'fakeTimeout') equals: (self sortedSelectors: result failures).
+		self assert: Set new equals: (self selectorSetOf: result errors).
+		self assert: #('fakeMultipleTimeoutFailing' 'fakeTimeout') asSet equals: (self selectorSetOf: result failures).
 		self finished
   	].
     runner announcer on: ResultAnnouncement do: [:ann |

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