Browse Source

Merge branch 'master' into requirejs

Herbert Vojčík 10 years ago
parent
commit
38080721a3
7 changed files with 375 additions and 131 deletions
  1. 53 18
      js/Kernel-Classes.deploy.js
  2. 67 22
      js/Kernel-Classes.js
  3. 64 13
      js/Kernel-Collections.deploy.js
  4. 90 24
      js/Kernel-Collections.js
  5. 26 11
      st/Kernel-Classes.st
  6. 48 13
      st/Kernel-Collections.st
  7. 27 30
      support/boot.js

+ 53 - 18
js/Kernel-Classes.deploy.js

@@ -82,13 +82,13 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
-$1=_st(self._allSuperclasses())._inject_into_(self._selectors(),(function(soFar,aBehavior){
+$1=_st(self._allSuperclasses())._inject_into_(self._selectors(),(function(acc,each){
 return smalltalk.withContext(function($ctx2) {
-$2=soFar;
-_st($2)._addAll_(_st(aBehavior)._selectors());
+$2=acc;
+_st($2)._addAll_(_st(each)._selectors());
 $3=_st($2)._yourself();
 return $3;
-}, function($ctx2) {$ctx2.fillBlock({soFar:soFar,aBehavior:aBehavior},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({acc:acc,each:each},$ctx1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"allSelectors",{},smalltalk.Behavior)})},
 messageSends: ["inject:into:", "selectors", "addAll:", "yourself", "allSuperclasses"]}),
@@ -99,18 +99,24 @@ smalltalk.method({
 selector: "allSubclasses",
 fn: function (){
 var self=this;
-var result;
+var subclasses,index;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-result=self._subclasses();
-_st(self._subclasses())._do_((function(each){
+subclasses=self._subclasses();
+index=(1);
+_st((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(result)._addAll_(_st(each)._allSubclasses());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-$1=result;
+return _st(index).__gt(_st(subclasses)._size());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
+_st(subclasses)._addAll_(_st(_st(subclasses)._at_(index))._subclasses());
+index=_st(index).__plus((1));
+return index;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+$1=subclasses;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"allSubclasses",{result:result},smalltalk.Behavior)})},
-messageSends: ["subclasses", "do:", "addAll:", "allSubclasses"]}),
+}, function($ctx1) {$ctx1.fill(self,"allSubclasses",{subclasses:subclasses,index:index},smalltalk.Behavior)})},
+messageSends: ["subclasses", "whileFalse:", "addAll:", "at:", "+", ">", "size"]}),
 smalltalk.Behavior);
 
 smalltalk.addMethod(
@@ -119,13 +125,12 @@ selector: "allSubclassesDo:",
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._subclasses())._do_((function(each){
+_st(self._allSubclasses())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-_st(aBlock)._value_(each);
-return _st(each)._allSubclassesDo_(aBlock);
+return _st(aBlock)._value_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"allSubclassesDo:",{aBlock:aBlock},smalltalk.Behavior)})},
-messageSends: ["do:", "value:", "allSubclassesDo:", "subclasses"]}),
+messageSends: ["do:", "value:", "allSubclasses"]}),
 smalltalk.Behavior);
 
 smalltalk.addMethod(
@@ -646,9 +651,9 @@ selector: "subclasses",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.subclasses(self);
+self._subclassResponsibility();
 return self}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Behavior)})},
-messageSends: []}),
+messageSends: ["subclassResponsibility"]}),
 smalltalk.Behavior);
 
 smalltalk.addMethod(
@@ -904,6 +909,17 @@ return $1;
 messageSends: ["superclass:subclass:instanceVariableNames:package:", "asString", "new"]}),
 smalltalk.Class);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "subclasses",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.subclasses._copy();
+return self}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Class)})},
+messageSends: []}),
+smalltalk.Class);
+
 
 
 smalltalk.addClass('Metaclass', smalltalk.Behavior, [], 'Kernel-Classes');
@@ -996,6 +1012,25 @@ return self}, function($ctx1) {$ctx1.fill(self,"printOn:",{aStream:aStream},smal
 messageSends: ["nextPutAll:", "name", "instanceClass"]}),
 smalltalk.Metaclass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "subclasses",
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(self._instanceClass())._subclasses())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(each)._isMetaclass())._not();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each)._theMetaClass();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Metaclass)})},
+messageSends: ["collect:", "theMetaClass", "select:", "not", "isMetaclass", "subclasses", "instanceClass"]}),
+smalltalk.Metaclass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "theMetaClass",

+ 67 - 22
js/Kernel-Classes.js

@@ -99,17 +99,17 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$3,$1;
-$1=_st(self._allSuperclasses())._inject_into_(self._selectors(),(function(soFar,aBehavior){
+$1=_st(self._allSuperclasses())._inject_into_(self._selectors(),(function(acc,each){
 return smalltalk.withContext(function($ctx2) {
-$2=soFar;
-_st($2)._addAll_(_st(aBehavior)._selectors());
+$2=acc;
+_st($2)._addAll_(_st(each)._selectors());
 $3=_st($2)._yourself();
 return $3;
-}, function($ctx2) {$ctx2.fillBlock({soFar:soFar,aBehavior:aBehavior},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({acc:acc,each:each},$ctx1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"allSelectors",{},smalltalk.Behavior)})},
 args: [],
-source: "allSelectors\x0a\x09^self allSuperclasses\x0a\x09\x09inject: self selectors\x0a\x09\x09into: [ :soFar :aBehavior | soFar addAll: aBehavior selectors; yourself ]",
+source: "allSelectors\x0a\x09^ self allSuperclasses\x0a\x09\x09inject: self selectors\x0a\x09\x09into: [ :acc :each | acc addAll: each selectors; yourself ]",
 messageSends: ["inject:into:", "selectors", "addAll:", "yourself", "allSuperclasses"],
 referencedClasses: []
 }),
@@ -121,20 +121,26 @@ selector: "allSubclasses",
 category: 'accessing',
 fn: function (){
 var self=this;
-var result;
+var subclasses,index;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-result=self._subclasses();
-_st(self._subclasses())._do_((function(each){
+subclasses=self._subclasses();
+index=(1);
+_st((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(result)._addAll_(_st(each)._allSubclasses());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-$1=result;
+return _st(index).__gt(_st(subclasses)._size());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx2) {
+_st(subclasses)._addAll_(_st(_st(subclasses)._at_(index))._subclasses());
+index=_st(index).__plus((1));
+return index;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+$1=subclasses;
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"allSubclasses",{result:result},smalltalk.Behavior)})},
+}, function($ctx1) {$ctx1.fill(self,"allSubclasses",{subclasses:subclasses,index:index},smalltalk.Behavior)})},
 args: [],
-source: "allSubclasses\x0a\x09| result |\x0a\x09result := self subclasses.\x0a\x09self subclasses do: [:each |\x0a\x09\x09result addAll: each allSubclasses].\x0a\x09^result",
-messageSends: ["subclasses", "do:", "addAll:", "allSubclasses"],
+source: "allSubclasses\x0a\x09\x22Answer an collection of the receiver's and the receiver's descendent's subclasses. \x22\x0a\x0a\x09| subclasses index |\x0a\x09\x0a\x09subclasses := self subclasses.\x0a\x09index := 1.\x0a\x09[ index > subclasses size ]\x0a\x09\x09whileFalse: [ subclasses addAll: (subclasses at: index) subclasses.\x0a\x09\x09\x09index := index + 1 ].\x0a\x0a\x09^ subclasses",
+messageSends: ["subclasses", "whileFalse:", "addAll:", "at:", "+", ">", "size"],
 referencedClasses: []
 }),
 smalltalk.Behavior);
@@ -146,15 +152,14 @@ category: 'enumerating',
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._subclasses())._do_((function(each){
+_st(self._allSubclasses())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-_st(aBlock)._value_(each);
-return _st(each)._allSubclassesDo_(aBlock);
+return _st(aBlock)._value_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"allSubclassesDo:",{aBlock:aBlock},smalltalk.Behavior)})},
 args: ["aBlock"],
-source: "allSubclassesDo: aBlock\x0a\x09\x22Evaluate the argument, aBlock, for each of the receiver's subclasses.\x22\x0a\x0a\x09self subclasses do: [ :each |\x0a    \x09aBlock value: each.\x0a        each allSubclassesDo: aBlock ].",
-messageSends: ["do:", "value:", "allSubclassesDo:", "subclasses"],
+source: "allSubclassesDo: aBlock\x0a\x09\x22Evaluate the argument, aBlock, for each of the receiver's subclasses.\x22\x0a\x0a\x09self allSubclasses do: [ :each |\x0a    \x09aBlock value: each ]",
+messageSends: ["do:", "value:", "allSubclasses"],
 referencedClasses: []
 }),
 smalltalk.Behavior);
@@ -843,11 +848,11 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return smalltalk.subclasses(self);
+self._subclassResponsibility();
 return self}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Behavior)})},
 args: [],
-source: "subclasses\x0a\x09<return smalltalk.subclasses(self)>",
-messageSends: [],
+source: "subclasses\x0a\x09self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
 referencedClasses: []
 }),
 smalltalk.Behavior);
@@ -1186,6 +1191,22 @@ referencedClasses: ["ClassBuilder"]
 }),
 smalltalk.Class);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "subclasses",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.subclasses._copy();
+return self}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Class)})},
+args: [],
+source: "subclasses\x0a\x09<return self.subclasses._copy()>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Class);
+
 
 
 smalltalk.addClass('Metaclass', smalltalk.Behavior, [], 'Kernel-Classes');
@@ -1309,6 +1330,30 @@ referencedClasses: []
 }),
 smalltalk.Metaclass);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "subclasses",
+category: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(_st(self._instanceClass())._subclasses())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(each)._isMetaclass())._not();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})})))._collect_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each)._theMetaClass();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"subclasses",{},smalltalk.Metaclass)})},
+args: [],
+source: "subclasses\x0a\x09^ (self instanceClass subclasses \x0a\x09\x09select: [ :each | each isMetaclass not ])\x0a\x09\x09collect: [ :each | each theMetaClass ]",
+messageSends: ["collect:", "theMetaClass", "select:", "not", "isMetaclass", "subclasses", "instanceClass"],
+referencedClasses: []
+}),
+smalltalk.Metaclass);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "theMetaClass",

+ 64 - 13
js/Kernel-Collections.deploy.js

@@ -592,6 +592,28 @@ return $2;
 messageSends: ["writeStream", "new", "class", "do:", "ifTrue:", "nextPut:", "value:", "contents"]}),
 smalltalk.Collection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "select:thenCollect:",
+fn: function (selectBlock,collectBlock){
+var self=this;
+var stream;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+stream=_st(_st(self._class())._new())._writeStream();
+self._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(selectBlock)._value_(each);
+if(smalltalk.assert($1)){
+return _st(stream)._nextPut_(_st(collectBlock)._value_(each));
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+$2=_st(stream)._contents();
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"select:thenCollect:",{selectBlock:selectBlock,collectBlock:collectBlock,stream:stream},smalltalk.Collection)})},
+messageSends: ["writeStream", "new", "class", "do:", "ifTrue:", "nextPut:", "value:", "contents"]}),
+smalltalk.Collection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "size",
@@ -1304,14 +1326,13 @@ selector: "values",
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(self._keys())._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return self._at_(each);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.HashedCollection)})},
-messageSends: ["collect:", "at:", "keys"]}),
+
+		return self._keys().map(function(key){
+			return self._at_(key);
+		});
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.HashedCollection)})},
+messageSends: []}),
 smalltalk.HashedCollection);
 
 smalltalk.addMethod(
@@ -1320,12 +1341,12 @@ selector: "valuesDo:",
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-self._keysAndValuesDo_((function(key,value){
+_st(self._values())._do_((function(value){
 return smalltalk.withContext(function($ctx2) {
 return _st(aBlock)._value_(value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"valuesDo:",{aBlock:aBlock},smalltalk.HashedCollection)})},
-messageSends: ["keysAndValuesDo:", "value:"]}),
+messageSends: ["do:", "value:", "values"]}),
 smalltalk.HashedCollection);
 
 smalltalk.addMethod(
@@ -1595,10 +1616,10 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self["@values"])._copy();
+$1=self["@values"];
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.Dictionary)})},
-messageSends: ["copy"]}),
+messageSends: []}),
 smalltalk.Dictionary);
 
 smalltalk.addMethod(
@@ -2141,6 +2162,17 @@ return self}, function($ctx1) {$ctx1.fill(self,"at:put:",{anIndex:anIndex,anObje
 messageSends: []}),
 smalltalk.Array);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collect:",
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.map(function(each) {return aBlock._value_(each)});
+return self}, function($ctx1) {$ctx1.fill(self,"collect:",{aBlock:aBlock},smalltalk.Array)})},
+messageSends: []}),
+smalltalk.Array);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "join:",
@@ -2224,6 +2256,25 @@ return self}, function($ctx1) {$ctx1.fill(self,"reversed",{},smalltalk.Array)})}
 messageSends: []}),
 smalltalk.Array);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "select:",
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+
+		var result = self.klass._new();
+		for(var i=0; i<self.length; i++) {
+			if(aBlock._value_(self[i])) {
+				result.push(self[i]);
+			}
+		}
+		return result;
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"select:",{aBlock:aBlock},smalltalk.Array)})},
+messageSends: []}),
+smalltalk.Array);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "size",

+ 90 - 24
js/Kernel-Collections.js

@@ -709,7 +709,7 @@ return _st(_st(aBlock)._value_(each)).__eq(false);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"reject:",{aBlock:aBlock},smalltalk.Collection)})},
 args: ["aBlock"],
-source: "reject: aBlock\x0a\x09^self select: [:each | (aBlock value: each) = false]",
+source: "reject: aBlock\x0a\x09^ self select: [ :each | (aBlock value: each) = false ]",
 messageSends: ["select:", "=", "value:"],
 referencedClasses: []
 }),
@@ -779,6 +779,33 @@ referencedClasses: []
 }),
 smalltalk.Collection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "select:thenCollect:",
+category: 'enumerating',
+fn: function (selectBlock,collectBlock){
+var self=this;
+var stream;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+stream=_st(_st(self._class())._new())._writeStream();
+self._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(selectBlock)._value_(each);
+if(smalltalk.assert($1)){
+return _st(stream)._nextPut_(_st(collectBlock)._value_(each));
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
+$2=_st(stream)._contents();
+return $2;
+}, function($ctx1) {$ctx1.fill(self,"select:thenCollect:",{selectBlock:selectBlock,collectBlock:collectBlock,stream:stream},smalltalk.Collection)})},
+args: ["selectBlock", "collectBlock"],
+source: "select: selectBlock thenCollect: collectBlock\x0a\x09| stream |\x0a\x09stream := self class new writeStream.\x0a\x09self do: [:each |\x0a\x09\x09(selectBlock value: each) ifTrue: [\x0a\x09\x09stream nextPut: (collectBlock value: each)]].\x0a\x09^stream contents",
+messageSends: ["writeStream", "new", "class", "do:", "ifTrue:", "nextPut:", "value:", "contents"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "size",
@@ -1729,16 +1756,15 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(self._keys())._collect_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return self._at_(each);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1)})}));
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.HashedCollection)})},
+
+		return self._keys().map(function(key){
+			return self._at_(key);
+		});
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.HashedCollection)})},
 args: [],
-source: "values\x0a\x09^self keys collect: [:each | self at: each]",
-messageSends: ["collect:", "at:", "keys"],
+source: "values\x0a\x09<\x0a\x09\x09return self._keys().map(function(key){\x0a\x09\x09\x09return self._at_(key);\x0a\x09\x09});\x0a\x09>",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.HashedCollection);
@@ -1750,14 +1776,14 @@ category: 'enumerating',
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-self._keysAndValuesDo_((function(key,value){
+_st(self._values())._do_((function(value){
 return smalltalk.withContext(function($ctx2) {
 return _st(aBlock)._value_(value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1)})}));
+}, function($ctx2) {$ctx2.fillBlock({value:value},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"valuesDo:",{aBlock:aBlock},smalltalk.HashedCollection)})},
 args: ["aBlock"],
-source: "valuesDo: aBlock\x0a\x09self keysAndValuesDo: [ :key :value | aBlock value: value ]",
-messageSends: ["keysAndValuesDo:", "value:"],
+source: "valuesDo: aBlock\x0a\x09self values do: [ :value | aBlock value: value ]",
+messageSends: ["do:", "value:", "values"],
 referencedClasses: []
 }),
 smalltalk.HashedCollection);
@@ -1868,7 +1894,7 @@ $1=_st($HashedCollection())._from_(self._associations());
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"asHashedCollection",{},smalltalk.Dictionary)})},
 args: [],
-source: "asHashedCollection\x0a\x09^HashedCollection from: self associations",
+source: "asHashedCollection\x0a\x09^ HashedCollection from: self associations",
 messageSends: ["from:", "associations"],
 referencedClasses: ["HashedCollection"]
 }),
@@ -1886,7 +1912,7 @@ $1=_st(self._asHashedCollection())._asJSON();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"asJSON",{},smalltalk.Dictionary)})},
 args: [],
-source: "asJSON\x0a\x09^self asHashedCollection asJSON",
+source: "asJSON\x0a\x09^ self asHashedCollection asJSON",
 messageSends: ["asJSON", "asHashedCollection"],
 referencedClasses: []
 }),
@@ -1974,7 +2000,7 @@ $1=_st(self["@keys"])._at_(index);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"indexOf:ifAbsent:",{anObject:anObject,aBlock:aBlock,index:index},smalltalk.Dictionary)})},
 args: ["anObject", "aBlock"],
-source: "indexOf: anObject ifAbsent: aBlock\x0a\x0a\x09| index |\x0a\x09index := values indexOf: anObject ifAbsent: [0].\x0a\x09^ index = 0 ifTrue: [ aBlock value ] ifFalse: [ keys at: index ]",
+source: "indexOf: anObject ifAbsent: aBlock\x0a\x09| index |\x0a\x09index := values \x0a\x09\x09indexOf: anObject \x0a\x09\x09ifAbsent: [ 0 ].\x0a\x09^ index = 0 \x0a\x09\x09ifTrue: [ aBlock value ] \x0a\x09\x09ifFalse: [ keys at: index ]",
 messageSends: ["indexOf:ifAbsent:", "ifTrue:ifFalse:", "value", "at:", "="],
 referencedClasses: []
 }),
@@ -2010,7 +2036,7 @@ $1=_st(self["@keys"])._copy();
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"keys",{},smalltalk.Dictionary)})},
 args: [],
-source: "keys\x0a\x09^keys copy",
+source: "keys\x0a\x09^ keys copy",
 messageSends: ["copy"],
 referencedClasses: []
 }),
@@ -2028,7 +2054,7 @@ $1=_st(self["@keys"])._with_do_(self["@values"],aBlock);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"keysAndValuesDo:",{aBlock:aBlock},smalltalk.Dictionary)})},
 args: ["aBlock"],
-source: "keysAndValuesDo: aBlock\x0a\x09^keys with: values do: aBlock",
+source: "keysAndValuesDo: aBlock\x0a\x09^ keys with: values do: aBlock",
 messageSends: ["with:do:"],
 referencedClasses: []
 }),
@@ -2046,7 +2072,7 @@ $1=_st(self["@keys"])._do_(aBlock);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"keysDo:",{aBlock:aBlock},smalltalk.Dictionary)})},
 args: ["aBlock"],
-source: "keysDo: aBlock\x0a\x09^keys do: aBlock",
+source: "keysDo: aBlock\x0a\x09^ keys do: aBlock",
 messageSends: ["do:"],
 referencedClasses: []
 }),
@@ -2111,12 +2137,12 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self["@values"])._copy();
+$1=self["@values"];
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"values",{},smalltalk.Dictionary)})},
 args: [],
-source: "values\x0a\x09^values copy",
-messageSends: ["copy"],
+source: "values\x0a\x09^ values",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.Dictionary);
@@ -2133,7 +2159,7 @@ $1=_st(self["@values"])._do_(aBlock);
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"valuesDo:",{aBlock:aBlock},smalltalk.Dictionary)})},
 args: ["aBlock"],
-source: "valuesDo: aBlock\x0a\x09^values do: aBlock",
+source: "valuesDo: aBlock\x0a\x09^ values do: aBlock",
 messageSends: ["do:"],
 referencedClasses: []
 }),
@@ -2853,6 +2879,22 @@ referencedClasses: []
 }),
 smalltalk.Array);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "collect:",
+category: 'enumerating',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self.map(function(each) {return aBlock._value_(each)});
+return self}, function($ctx1) {$ctx1.fill(self,"collect:",{aBlock:aBlock},smalltalk.Array)})},
+args: ["aBlock"],
+source: "collect: aBlock\x0a\x09\x22Optimized version\x22\x0a\x09<return self.map(function(each) {return aBlock._value_(each)})>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Array);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "join:",
@@ -2966,6 +3008,30 @@ referencedClasses: []
 }),
 smalltalk.Array);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "select:",
+category: 'enumerating',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+
+		var result = self.klass._new();
+		for(var i=0; i<self.length; i++) {
+			if(aBlock._value_(self[i])) {
+				result.push(self[i]);
+			}
+		}
+		return result;
+	;
+return self}, function($ctx1) {$ctx1.fill(self,"select:",{aBlock:aBlock},smalltalk.Array)})},
+args: ["aBlock"],
+source: "select: aBlock\x0a\x09\x22Optimized version\x22\x0a\x09\x0a\x09<\x0a\x09\x09var result = self.klass._new();\x0a\x09\x09for(var i=0; i<self.length; i++) {\x0a\x09\x09\x09if(aBlock._value_(self[i])) {\x0a\x09\x09\x09\x09result.push(self[i]);\x0a\x09\x09\x09}\x0a\x09\x09}\x0a\x09\x09return result;\x0a\x09>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Array);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "size",

+ 26 - 11
st/Kernel-Classes.st

@@ -27,17 +27,23 @@ allInstanceVariableNames
 !
 
 allSelectors
-	^self allSuperclasses
+	^ self allSuperclasses
 		inject: self selectors
-		into: [ :soFar :aBehavior | soFar addAll: aBehavior selectors; yourself ]
+		into: [ :acc :each | acc addAll: each selectors; yourself ]
 !
 
 allSubclasses
-	| result |
-	result := self subclasses.
-	self subclasses do: [:each |
-		result addAll: each allSubclasses].
-	^result
+	"Answer an collection of the receiver's and the receiver's descendent's subclasses. "
+
+	| subclasses index |
+	
+	subclasses := self subclasses.
+	index := 1.
+	[ index > subclasses size ]
+		whileFalse: [ subclasses addAll: (subclasses at: index) subclasses.
+			index := index + 1 ].
+
+	^ subclasses
 !
 
 allSuperclasses
@@ -150,7 +156,7 @@ selectors
 !
 
 subclasses
-	<return smalltalk.subclasses(self)>
+	self subclassResponsibility
 !
 
 superclass
@@ -232,9 +238,8 @@ removeCompiledMethod: aMethod
 allSubclassesDo: aBlock
 	"Evaluate the argument, aBlock, for each of the receiver's subclasses."
 
-	self subclasses do: [ :each |
-    	aBlock value: each.
-        each allSubclassesDo: aBlock ].
+	self allSubclasses do: [ :each |
+    	aBlock value: each ]
 !
 
 protocolsDo: aBlock
@@ -353,6 +358,10 @@ package: aPackage
 
 rename: aString
 	ClassBuilder new renameClass: self to: aString
+!
+
+subclasses
+	<return self.subclasses._copy()>
 ! !
 
 !Class methodsFor: 'class creation'!
@@ -426,6 +435,12 @@ instanceVariableNames: aCollection
 		class: self instanceVariableNames: aCollection
 !
 
+subclasses
+	^ (self instanceClass subclasses 
+		select: [ :each | each isMetaclass not ])
+		collect: [ :each | each theMetaClass ]
+!
+
 theMetaClass
 	^ self
 !

+ 48 - 13
st/Kernel-Collections.st

@@ -189,7 +189,7 @@ intersection: aCollection
 !
 
 reject: aBlock
-	^self select: [:each | (aBlock value: each) = false]
+	^ self select: [ :each | (aBlock value: each) = false ]
 !
 
 select: aBlock
@@ -199,6 +199,15 @@ select: aBlock
 		(aBlock value: each) ifTrue: [
 		stream nextPut: each]].
 	^stream contents
+!
+
+select: selectBlock thenCollect: collectBlock
+	| stream |
+	stream := self class new writeStream.
+	self do: [:each |
+		(selectBlock value: each) ifTrue: [
+		stream nextPut: (collectBlock value: each)]].
+	^stream contents
 ! !
 
 !Collection methodsFor: 'error handling'!
@@ -442,7 +451,11 @@ size
 !
 
 values
-	^self keys collect: [:each | self at: each]
+	<
+		return self._keys().map(function(key){
+			return self._at_(key);
+		});
+	>
 ! !
 
 !HashedCollection methodsFor: 'adding/removing'!
@@ -559,7 +572,7 @@ select: aBlock
 !
 
 valuesDo: aBlock
-	self keysAndValuesDo: [ :key :value | aBlock value: value ]
+	self values do: [ :value | aBlock value: value ]
 !
 
 withIndexDo: aBlock
@@ -646,18 +659,21 @@ at: aKey put: aValue
 !
 
 indexOf: anObject ifAbsent: aBlock
-
 	| index |
-	index := values indexOf: anObject ifAbsent: [0].
-	^ index = 0 ifTrue: [ aBlock value ] ifFalse: [ keys at: index ]
+	index := values 
+		indexOf: anObject 
+		ifAbsent: [ 0 ].
+	^ index = 0 
+		ifTrue: [ aBlock value ] 
+		ifFalse: [ keys at: index ]
 !
 
 keys
-	^keys copy
+	^ keys copy
 !
 
 values
-	^values copy
+	^ values
 ! !
 
 !Dictionary methodsFor: 'adding/removing'!
@@ -682,25 +698,25 @@ removeKey: aKey ifAbsent: aBlock
 !Dictionary methodsFor: 'converting'!
 
 asHashedCollection
-	^HashedCollection from: self associations
+	^ HashedCollection from: self associations
 !
 
 asJSON
-	^self asHashedCollection asJSON
+	^ self asHashedCollection asJSON
 ! !
 
 !Dictionary methodsFor: 'enumerating'!
 
 keysAndValuesDo: aBlock
-	^keys with: values do: aBlock
+	^ keys with: values do: aBlock
 !
 
 keysDo: aBlock
-	^keys do: aBlock
+	^ keys do: aBlock
 !
 
 valuesDo: aBlock
-	^values do: aBlock
+	^ values do: aBlock
 ! !
 
 !Dictionary methodsFor: 'initialization'!
@@ -999,10 +1015,29 @@ reversed
 
 !Array methodsFor: 'enumerating'!
 
+collect: aBlock
+	"Optimized version"
+	<return self.map(function(each) {return aBlock._value_(each)})>
+!
+
 join: aString
 	<return self.join(aString)>
 !
 
+select: aBlock
+	"Optimized version"
+	
+	<
+		var result = self.klass._new();
+		for(var i=0; i<self.length; i++) {
+			if(aBlock._value_(self[i])) {
+				result.push(self[i]);
+			}
+		}
+		return result;
+	>
+!
+
 sort
 	^self basicPerform: 'sort'
 !

+ 27 - 30
support/boot.js

@@ -308,6 +308,7 @@ function ClassesBrik(brikz, st) {
 		st.wrapClassName("Class", "Kernel-Classes", SmalltalkClass, st.Behavior, false);
 
 		st.Object.klass.superclass = st.Class;
+		addSubclass(st.Object.klass);
 
 		st.wrapClassName("Package", "Kernel-Infrastructure", SmalltalkPackage, st.Object, false);
 	};
@@ -340,7 +341,10 @@ function ClassesBrik(brikz, st) {
 		spec = spec || {};
 		var meta = metaclass(spec);
 		var that = meta.instanceClass;
+
 		that.fn = spec.fn || inherits(function () {}, spec.superclass.fn);
+		that.subclasses = [];
+
 		setupClass(that, spec);
 
 		that.className = spec.className;
@@ -411,7 +415,11 @@ function ClassesBrik(brikz, st) {
 
 	function rawAddClass(pkgName, className, superclass, iVarNames, wrapped, fn) {
 		var pkg = st.packages[pkgName];
-		if (!pkg) { throw new Error("Missing package "+pkgName); }
+
+		if (!pkg) { 
+			throw new Error("Missing package "+pkgName); 
+		}
+
 		if(st[className] && st[className].superclass == superclass) {
 //            st[className].superclass = superclass;
 			st[className].iVarNames = iVarNames || [];
@@ -433,6 +441,8 @@ function ClassesBrik(brikz, st) {
 				fn: fn,
 				wrapped: wrapped
 			});
+
+			addSubclass(st[className]);
 		}
 
 		classes.addElement(st[className]);
@@ -442,9 +452,22 @@ function ClassesBrik(brikz, st) {
 	st.removeClass = function(klass) {
 		org.removeOrganizationElement(klass.pkg, klass);
 		classes.removeElement(klass);
+		removeSubclass(klass);
 		delete st[klass.className];
 	};
 
+	function addSubclass(klass) {
+		if(klass.superclass) {
+			klass.superclass.subclasses.addElement(klass);
+		}
+	}
+
+	function removeSubclass(klass) {
+		if(klass.superclass) {
+			klass.superclass.subclasses.removeElement(klass);
+		}
+	}
+
 	/* Create a new class wrapping a JavaScript constructor, and add it to the
 	 global smalltalk object. Package is lazily created if it does not exist with given name. */
 
@@ -485,36 +508,10 @@ function ClassesBrik(brikz, st) {
 		return packages;
 	};
 
-	/* Answer the direct subclasses of klass. */
-
-	st.subclasses = function(klass) {
-		var subclasses = [];
-		var classes = st.classes();
-		for(var i=0; i < classes.length; i++) {
-			var c = classes[i];
-			if(c.fn) {
-				//Classes
-				if(c.superclass === klass) {
-					subclasses.push(c);
-				}
-				c = c.klass;
-				//Metaclasses
-				if(c && c.superclass === klass) {
-					subclasses.push(c);
-				}
-			}
-		}
-		return subclasses;
-	};
-
+	// Still used, but could go away now that subclasses are stored
+	// into classes directly.
 	st.allSubclasses = function(klass) {
-		var result, subclasses;
-		result = subclasses = st.subclasses(klass);
-		subclasses.forEach(function(subclass) {
-			result.push.apply(result, st.allSubclasses(subclass));
-		});
-
-		return result;
+		return klass._allSubclasses();
 	};
 
 }