Browse Source

Merge pull request #133 from lolgzs/master

Add some kernel methods + tests. Partially fix method protocols combo that was broken
Nicolas Petton 13 years ago
parent
commit
b5bf057750
12 changed files with 1747 additions and 1340 deletions
  1. 438 438
      js/IDE.deploy.js
  2. 550 295
      js/IDE.js
  3. 93 82
      js/Kernel-Collections.deploy.js
  4. 133 117
      js/Kernel-Collections.js
  5. 11 0
      js/Kernel-Objects.deploy.js
  6. 16 0
      js/Kernel-Objects.js
  7. 28 0
      js/Kernel-Tests.deploy.js
  8. 38 0
      js/Kernel-Tests.js
  9. 360 359
      st/IDE.st
  10. 56 49
      st/Kernel-Collections.st
  11. 7 0
      st/Kernel-Objects.st
  12. 17 0
      st/Kernel-Tests.st

File diff suppressed because it is too large
+ 438 - 438
js/IDE.deploy.js


File diff suppressed because it is too large
+ 550 - 295
js/IDE.js


+ 93 - 82
js/Kernel-Collections.deploy.js

@@ -1,86 +1,4 @@
 smalltalk.addPackage('Kernel-Collections', {});
-smalltalk.addClass('Association', smalltalk.Object, ['key', 'value'], 'Kernel-Collections');
-smalltalk.addMethod(
-unescape('__eq'),
-smalltalk.method({
-selector: unescape('%3D'),
-fn: function (anAssociation) {
-var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "__eq", [smalltalk.send(anAssociation, "_class", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_key", []), "__eq", [smalltalk.send(anAssociation, "_key", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_value", []), "__eq", [smalltalk.send(anAssociation, "_value", [])]);})]);})]);
-return self;}
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_key_'),
-smalltalk.method({
-selector: unescape('key%3A'),
-fn: function (aKey) {
-var self=this;
-(self['@key']=aKey);
-return self;}
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_key'),
-smalltalk.method({
-selector: unescape('key'),
-fn: function () {
-var self=this;
-return self['@key'];
-return self;}
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_value_'),
-smalltalk.method({
-selector: unescape('value%3A'),
-fn: function (aValue) {
-var self=this;
-(self['@value']=aValue);
-return self;}
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_value'),
-smalltalk.method({
-selector: unescape('value'),
-fn: function () {
-var self=this;
-return self['@value'];
-return self;}
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_storeOn_'),
-smalltalk.method({
-selector: unescape('storeOn%3A'),
-fn: function (aStream) {
-var self=this;
-smalltalk.send(self['@key'], "_storeOn_", [aStream]);
-smalltalk.send(aStream, "_nextPutAll_", [unescape("-%3E")]);
-smalltalk.send(self['@value'], "_storeOn_", [aStream]);
-return self;}
-}),
-smalltalk.Association);
-
-
-smalltalk.addMethod(
-unescape('_key_value_'),
-smalltalk.method({
-selector: unescape('key%3Avalue%3A'),
-fn: function (aKey, aValue) {
-var self=this;
-return (function($rec){smalltalk.send($rec, "_key_", [aKey]);smalltalk.send($rec, "_value_", [aValue]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_new", []));
-return self;}
-}),
-smalltalk.Association.klass);
-
-
 smalltalk.addClass('Stream', smalltalk.Object, ['collection', 'position', 'streamSize'], 'Kernel-Collections');
 smalltalk.addMethod(
 unescape('_collection'),
@@ -354,6 +272,88 @@ return self;}
 smalltalk.Stream.klass);
 
 
+smalltalk.addClass('Association', smalltalk.Object, ['key', 'value'], 'Kernel-Collections');
+smalltalk.addMethod(
+unescape('__eq'),
+smalltalk.method({
+selector: unescape('%3D'),
+fn: function (anAssociation) {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "__eq", [smalltalk.send(anAssociation, "_class", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_key", []), "__eq", [smalltalk.send(anAssociation, "_key", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_value", []), "__eq", [smalltalk.send(anAssociation, "_value", [])]);})]);})]);
+return self;}
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_key_'),
+smalltalk.method({
+selector: unescape('key%3A'),
+fn: function (aKey) {
+var self=this;
+(self['@key']=aKey);
+return self;}
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_key'),
+smalltalk.method({
+selector: unescape('key'),
+fn: function () {
+var self=this;
+return self['@key'];
+return self;}
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_value_'),
+smalltalk.method({
+selector: unescape('value%3A'),
+fn: function (aValue) {
+var self=this;
+(self['@value']=aValue);
+return self;}
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_value'),
+smalltalk.method({
+selector: unescape('value'),
+fn: function () {
+var self=this;
+return self['@value'];
+return self;}
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_storeOn_'),
+smalltalk.method({
+selector: unescape('storeOn%3A'),
+fn: function (aStream) {
+var self=this;
+smalltalk.send(self['@key'], "_storeOn_", [aStream]);
+smalltalk.send(aStream, "_nextPutAll_", [unescape("-%3E")]);
+smalltalk.send(self['@value'], "_storeOn_", [aStream]);
+return self;}
+}),
+smalltalk.Association);
+
+
+smalltalk.addMethod(
+unescape('_key_value_'),
+smalltalk.method({
+selector: unescape('key%3Avalue%3A'),
+fn: function (aKey, aValue) {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_key_", [aKey]);smalltalk.send($rec, "_value_", [aValue]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_new", []));
+return self;}
+}),
+smalltalk.Association.klass);
+
+
 smalltalk.addClass('RegularExpression', smalltalk.Object, [], 'Kernel-Collections');
 smalltalk.addMethod(
 unescape('_compile_'),
@@ -1139,6 +1139,17 @@ return self;}
 }),
 smalltalk.SequenceableCollection);
 
+smalltalk.addMethod(
+unescape('_first_'),
+smalltalk.method({
+selector: unescape('first%3A'),
+fn: function (n){
+var self=this;
+return smalltalk.send(self, "_copyFrom_to_", [(1), n]);
+return self;}
+}),
+smalltalk.SequenceableCollection);
+
 
 
 smalltalk.addClass('CharacterArray', smalltalk.SequenceableCollection, [], 'Kernel-Collections');

+ 133 - 117
js/Kernel-Collections.js

@@ -1,121 +1,4 @@
 smalltalk.addPackage('Kernel-Collections', {});
-smalltalk.addClass('Association', smalltalk.Object, ['key', 'value'], 'Kernel-Collections');
-smalltalk.addMethod(
-unescape('__eq'),
-smalltalk.method({
-selector: unescape('%3D'),
-category: 'comparing',
-fn: function (anAssociation) {
-var self=this;
-return smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "__eq", [smalltalk.send(anAssociation, "_class", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_key", []), "__eq", [smalltalk.send(anAssociation, "_key", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_value", []), "__eq", [smalltalk.send(anAssociation, "_value", [])]);})]);})]);
-return self;},
-args: ["anAssociation"],
-source: unescape('%3D%20anAssociation%0A%09%5Eself%20class%20%3D%20anAssociation%20class%20and%3A%20%5B%0A%09%20%20%20%20self%20key%20%3D%20anAssociation%20key%20and%3A%20%5B%0A%09%09self%20value%20%3D%20anAssociation%20value%5D%5D'),
-messageSends: ["and:", unescape("%3D"), "class", "key", "value"],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_key_'),
-smalltalk.method({
-selector: unescape('key%3A'),
-category: 'accessing',
-fn: function (aKey) {
-var self=this;
-(self['@key']=aKey);
-return self;},
-args: ["aKey"],
-source: unescape('key%3A%20aKey%0A%09key%20%3A%3D%20aKey'),
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_key'),
-smalltalk.method({
-selector: unescape('key'),
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@key'];
-return self;},
-args: [],
-source: unescape('key%0A%09%5Ekey'),
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_value_'),
-smalltalk.method({
-selector: unescape('value%3A'),
-category: 'accessing',
-fn: function (aValue) {
-var self=this;
-(self['@value']=aValue);
-return self;},
-args: ["aValue"],
-source: unescape('value%3A%20aValue%0A%09value%20%3A%3D%20aValue'),
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_value'),
-smalltalk.method({
-selector: unescape('value'),
-category: 'accessing',
-fn: function () {
-var self=this;
-return self['@value'];
-return self;},
-args: [],
-source: unescape('value%0A%09%5Evalue'),
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-smalltalk.addMethod(
-unescape('_storeOn_'),
-smalltalk.method({
-selector: unescape('storeOn%3A'),
-category: 'comparing',
-fn: function (aStream) {
-var self=this;
-smalltalk.send(self['@key'], "_storeOn_", [aStream]);
-smalltalk.send(aStream, "_nextPutAll_", [unescape("-%3E")]);
-smalltalk.send(self['@value'], "_storeOn_", [aStream]);
-return self;},
-args: ["aStream"],
-source: unescape('storeOn%3A%20aStream%0A%09%22Store%20in%20the%20format%20%28key-%3Evalue%29%22%0A%0A%09%22aStream%20nextPutAll%3A%20%27%28%27.%22%0A%09key%20storeOn%3A%20aStream.%0A%09aStream%20nextPutAll%3A%20%27-%3E%27.%0A%09value%20storeOn%3A%20aStream.%0A%09%22aStream%20nextPutAll%3A%20%27%29%27%22'),
-messageSends: ["storeOn:", "nextPutAll:"],
-referencedClasses: []
-}),
-smalltalk.Association);
-
-
-smalltalk.addMethod(
-unescape('_key_value_'),
-smalltalk.method({
-selector: unescape('key%3Avalue%3A'),
-category: 'instance creation',
-fn: function (aKey, aValue) {
-var self=this;
-return (function($rec){smalltalk.send($rec, "_key_", [aKey]);smalltalk.send($rec, "_value_", [aValue]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_new", []));
-return self;},
-args: ["aKey", "aValue"],
-source: unescape('key%3A%20aKey%20value%3A%20aValue%0A%09%20%20%20%20%5Eself%20new%0A%09%09key%3A%20aKey%3B%0A%09%09value%3A%20aValue%3B%0A%09%09yourself'),
-messageSends: ["key:", "value:", "yourself", "new"],
-referencedClasses: []
-}),
-smalltalk.Association.klass);
-
-
 smalltalk.addClass('Stream', smalltalk.Object, ['collection', 'position', 'streamSize'], 'Kernel-Collections');
 smalltalk.addMethod(
 unescape('_collection'),
@@ -509,6 +392,123 @@ referencedClasses: []
 smalltalk.Stream.klass);
 
 
+smalltalk.addClass('Association', smalltalk.Object, ['key', 'value'], 'Kernel-Collections');
+smalltalk.addMethod(
+unescape('__eq'),
+smalltalk.method({
+selector: unescape('%3D'),
+category: 'comparing',
+fn: function (anAssociation) {
+var self=this;
+return smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "__eq", [smalltalk.send(anAssociation, "_class", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(smalltalk.send(self, "_key", []), "__eq", [smalltalk.send(anAssociation, "_key", [])]), "_and_", [(function(){return smalltalk.send(smalltalk.send(self, "_value", []), "__eq", [smalltalk.send(anAssociation, "_value", [])]);})]);})]);
+return self;},
+args: ["anAssociation"],
+source: unescape('%3D%20anAssociation%0A%09%5Eself%20class%20%3D%20anAssociation%20class%20and%3A%20%5B%0A%09%20%20%20%20self%20key%20%3D%20anAssociation%20key%20and%3A%20%5B%0A%09%09self%20value%20%3D%20anAssociation%20value%5D%5D'),
+messageSends: ["and:", unescape("%3D"), "class", "key", "value"],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_key_'),
+smalltalk.method({
+selector: unescape('key%3A'),
+category: 'accessing',
+fn: function (aKey) {
+var self=this;
+(self['@key']=aKey);
+return self;},
+args: ["aKey"],
+source: unescape('key%3A%20aKey%0A%09key%20%3A%3D%20aKey'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_key'),
+smalltalk.method({
+selector: unescape('key'),
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@key'];
+return self;},
+args: [],
+source: unescape('key%0A%09%5Ekey'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_value_'),
+smalltalk.method({
+selector: unescape('value%3A'),
+category: 'accessing',
+fn: function (aValue) {
+var self=this;
+(self['@value']=aValue);
+return self;},
+args: ["aValue"],
+source: unescape('value%3A%20aValue%0A%09value%20%3A%3D%20aValue'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_value'),
+smalltalk.method({
+selector: unescape('value'),
+category: 'accessing',
+fn: function () {
+var self=this;
+return self['@value'];
+return self;},
+args: [],
+source: unescape('value%0A%09%5Evalue'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+smalltalk.addMethod(
+unescape('_storeOn_'),
+smalltalk.method({
+selector: unescape('storeOn%3A'),
+category: 'comparing',
+fn: function (aStream) {
+var self=this;
+smalltalk.send(self['@key'], "_storeOn_", [aStream]);
+smalltalk.send(aStream, "_nextPutAll_", [unescape("-%3E")]);
+smalltalk.send(self['@value'], "_storeOn_", [aStream]);
+return self;},
+args: ["aStream"],
+source: unescape('storeOn%3A%20aStream%0A%09%22Store%20in%20the%20format%20%28key-%3Evalue%29%22%0A%0A%09%22aStream%20nextPutAll%3A%20%27%28%27.%22%0A%09key%20storeOn%3A%20aStream.%0A%09aStream%20nextPutAll%3A%20%27-%3E%27.%0A%09value%20storeOn%3A%20aStream.%0A%09%22aStream%20nextPutAll%3A%20%27%29%27%22'),
+messageSends: ["storeOn:", "nextPutAll:"],
+referencedClasses: []
+}),
+smalltalk.Association);
+
+
+smalltalk.addMethod(
+unescape('_key_value_'),
+smalltalk.method({
+selector: unescape('key%3Avalue%3A'),
+category: 'instance creation',
+fn: function (aKey, aValue) {
+var self=this;
+return (function($rec){smalltalk.send($rec, "_key_", [aKey]);smalltalk.send($rec, "_value_", [aValue]);return smalltalk.send($rec, "_yourself", []);})(smalltalk.send(self, "_new", []));
+return self;},
+args: ["aKey", "aValue"],
+source: unescape('key%3A%20aKey%20value%3A%20aValue%0A%09%20%20%20%20%5Eself%20new%0A%09%09key%3A%20aKey%3B%0A%09%09value%3A%20aValue%3B%0A%09%09yourself'),
+messageSends: ["key:", "value:", "yourself", "new"],
+referencedClasses: []
+}),
+smalltalk.Association.klass);
+
+
 smalltalk.addClass('RegularExpression', smalltalk.Object, [], 'Kernel-Collections');
 smalltalk.addMethod(
 unescape('_compile_'),
@@ -1624,6 +1624,22 @@ referencedClasses: []
 }),
 smalltalk.SequenceableCollection);
 
+smalltalk.addMethod(
+unescape('_first_'),
+smalltalk.method({
+selector: unescape('first%3A'),
+category: 'accessing',
+fn: function (n){
+var self=this;
+return smalltalk.send(self, "_copyFrom_to_", [(1), n]);
+return self;},
+args: ["n"],
+source: unescape('first%3A%20n%0A%09%22Answer%20the%20first%20n%20elements%20of%20the%20receiver.%0A%09Raise%20an%20error%20if%20there%20are%20not%20enough%20elements.%22%0A%0A%09%5E%20self%20copyFrom%3A%201%20to%3A%20n'),
+messageSends: ["copyFrom:to:"],
+referencedClasses: []
+}),
+smalltalk.SequenceableCollection);
+
 
 
 smalltalk.addClass('CharacterArray', smalltalk.SequenceableCollection, [], 'Kernel-Collections');

+ 11 - 0
js/Kernel-Objects.deploy.js

@@ -3397,6 +3397,17 @@ fn: function () {
 }),
 smalltalk.Point);
 
+smalltalk.addMethod(
+unescape('_translateBy_'),
+smalltalk.method({
+selector: unescape('translateBy%3A'),
+fn: function (delta){
+var self=this;
+return smalltalk.send(((($receiver = smalltalk.send(delta, "_x", [])).klass === smalltalk.Number) ? $receiver +self['@x'] : smalltalk.send($receiver, "__plus", [self['@x']])), "__at", [((($receiver = smalltalk.send(delta, "_y", [])).klass === smalltalk.Number) ? $receiver +self['@y'] : smalltalk.send($receiver, "__plus", [self['@y']]))]);
+return self;}
+}),
+smalltalk.Point);
+
 
 smalltalk.addMethod(
 unescape('_x_y_'),

+ 16 - 0
js/Kernel-Objects.js

@@ -4747,6 +4747,22 @@ referencedClasses: ["String"]
 }),
 smalltalk.Point);
 
+smalltalk.addMethod(
+unescape('_translateBy_'),
+smalltalk.method({
+selector: unescape('translateBy%3A'),
+category: 'transforming',
+fn: function (delta){
+var self=this;
+return smalltalk.send(((($receiver = smalltalk.send(delta, "_x", [])).klass === smalltalk.Number) ? $receiver +self['@x'] : smalltalk.send($receiver, "__plus", [self['@x']])), "__at", [((($receiver = smalltalk.send(delta, "_y", [])).klass === smalltalk.Number) ? $receiver +self['@y'] : smalltalk.send($receiver, "__plus", [self['@y']]))]);
+return self;},
+args: ["delta"],
+source: unescape('translateBy%3A%20delta%20%0A%09%22Answer%20a%20Point%20translated%20by%20delta%20%28an%20instance%20of%20Point%29.%22%0A%09%5E%28delta%20x%20+%20x%29%20@%20%28delta%20y%20+%20y%29'),
+messageSends: [unescape("@"), unescape("+"), "x", "y"],
+referencedClasses: []
+}),
+smalltalk.Point);
+
 
 smalltalk.addMethod(
 unescape('_x_y_'),

+ 28 - 0
js/Kernel-Tests.deploy.js

@@ -184,6 +184,20 @@ return self;}
 }),
 smalltalk.PointTest);
 
+smalltalk.addMethod(
+unescape('_testTranslateBy'),
+smalltalk.method({
+selector: unescape('testTranslateBy'),
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((3), "__at", [(4)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((0), "__at", [(1)])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((3), "__at", [(2)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((0), "__at", [smalltalk.send((1), "_negated", [])])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((5), "__at", [(6)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((2), "__at", [(3)])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((0), "__at", [(3)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send(smalltalk.send((3), "_negated", []), "__at", [(0)])])]);
+return self;}
+}),
+smalltalk.PointTest);
+
 
 
 smalltalk.addClass('UndefinedTest', smalltalk.TestCase, [], 'Kernel-Tests');
@@ -1358,6 +1372,20 @@ smalltalk.StringTest);
 
 
 
+smalltalk.addClass('ArrayTest', smalltalk.TestCase, [], 'Kernel-Tests');
+smalltalk.addMethod(
+unescape('_testFirstN'),
+smalltalk.method({
+selector: unescape('testFirstN'),
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_equals_", [[(1),(2),(3)], smalltalk.send([(1),(2),(3),(4),(5)], "_first_", [(3)])]);
+return self;}
+}),
+smalltalk.ArrayTest);
+
+
+
 smalltalk.addClass('PackageWithDefaultCommitPathChangedTest', smalltalk.PackageTest, [], 'Kernel-Tests');
 smalltalk.addMethod(
 unescape('_setUp'),

+ 38 - 0
js/Kernel-Tests.js

@@ -249,6 +249,25 @@ referencedClasses: ["Point"]
 }),
 smalltalk.PointTest);
 
+smalltalk.addMethod(
+unescape('_testTranslateBy'),
+smalltalk.method({
+selector: unescape('testTranslateBy'),
+category: 'tests',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((3), "__at", [(4)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((0), "__at", [(1)])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((3), "__at", [(2)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((0), "__at", [smalltalk.send((1), "_negated", [])])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((5), "__at", [(6)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send((2), "__at", [(3)])])]);
+smalltalk.send(self, "_assert_equals_", [smalltalk.send((0), "__at", [(3)]), smalltalk.send(smalltalk.send((3), "__at", [(3)]), "_translateBy_", [smalltalk.send(smalltalk.send((3), "_negated", []), "__at", [(0)])])]);
+return self;},
+args: [],
+source: unescape('testTranslateBy%0A%09self%20assert%3A%203@4%20equals%3A%20%283@3%20translateBy%3A%200@1%29.%0A%09self%20assert%3A%203@2%20equals%3A%20%283@3%20translateBy%3A%200@1%20negated%29.%0A%09self%20assert%3A%205@6%20equals%3A%20%283@3%20translateBy%3A%202@3%29.%0A%09self%20assert%3A%200@3%20equals%3A%20%283@3%20translateBy%3A%203%20negated%20@0%29.'),
+messageSends: ["assert:equals:", unescape("@"), "translateBy:", "negated"],
+referencedClasses: []
+}),
+smalltalk.PointTest);
+
 
 
 smalltalk.addClass('UndefinedTest', smalltalk.TestCase, [], 'Kernel-Tests');
@@ -1843,6 +1862,25 @@ smalltalk.StringTest);
 
 
 
+smalltalk.addClass('ArrayTest', smalltalk.TestCase, [], 'Kernel-Tests');
+smalltalk.addMethod(
+unescape('_testFirstN'),
+smalltalk.method({
+selector: unescape('testFirstN'),
+category: 'testing',
+fn: function (){
+var self=this;
+smalltalk.send(self, "_assert_equals_", [[(1),(2),(3)], smalltalk.send([(1),(2),(3),(4),(5)], "_first_", [(3)])]);
+return self;},
+args: [],
+source: unescape('testFirstN%0A%09self%20assert%3A%20%7B1.%202.%203%7D%20equals%3A%20%28%7B1.%202.%A03.%204.%205%7D%20first%3A%203%29.'),
+messageSends: ["assert:equals:", "first:"],
+referencedClasses: []
+}),
+smalltalk.ArrayTest);
+
+
+
 smalltalk.addClass('PackageWithDefaultCommitPathChangedTest', smalltalk.PackageTest, [], 'Kernel-Tests');
 smalltalk.addMethod(
 unescape('_setUp'),

+ 360 - 359
st/IDE.st

@@ -1,185 +1,295 @@
 Smalltalk current createPackage: 'IDE' properties: #{}!
-ErrorHandler subclass: #DebugErrorHandler
-	instanceVariableNames: ''
-	category: 'IDE'!
-
-!DebugErrorHandler methodsFor: 'error handling'!
-
-handleError: anError
-	[Debugger new
-		error: anError;
-		open] on: Error do: [:error |
-			ErrorHandler new handleError: error]
-! !
-
-!DebugErrorHandler class methodsFor: 'initialization'!
-
-initialize
-	self register
-! !
-
-Widget subclass: #ClassesListNode
-	instanceVariableNames: 'browser theClass level nodes'
+Widget subclass: #TabManager
+	instanceVariableNames: 'selectedTab tabs opened ul input'
 	category: 'IDE'!
 
-!ClassesListNode methodsFor: ''!
-
-renderOn: html
-	| li cssClass |
-	cssClass := ''.
-	li := html li 
-		onClick: [self browser selectClass: self theClass]. 
-	li asJQuery html: self label.
-
-	self browser selectedClass = self theClass ifTrue:  [
-		cssClass := cssClass, ' selected'].
-
-	self theClass comment isEmpty ifFalse: [
-		cssClass := cssClass, ' commented'].
+!TabManager methodsFor: 'accessing'!
 
-	li class: cssClass.
+tabs
+    ^tabs ifNil: [tabs := Array new]
+!
 
-	self nodes do: [:each |
-		each renderOn: html]
+labelFor: aWidget
+	| label maxSize |
+	maxSize := 15.
+	label := aWidget label copyFrom: 0 to: (aWidget label size min: maxSize).
+	aWidget label size > maxSize ifTrue: [
+		label := label, '...'].
+	^label
 ! !
 
-!ClassesListNode methodsFor: 'accessing'!
-
-nodes
-	^nodes
-!
-
-theClass
-	^theClass
-!
+!TabManager methodsFor: 'actions'!
 
-theClass: aClass
-	theClass := aClass
+updateBodyMargin
+    self setBodyMargin: '#jtalk' asJQuery height
 !
 
-browser
-	^browser
+updatePosition
+    <jQuery('#jtalk').css('top', '').css('bottom', '0px')>
 !
 
-browser: aBrowser
-	browser := aBrowser
+removeBodyMargin
+    self setBodyMargin: 0
 !
 
-level
-	^level
+setBodyMargin: anInteger
+    '.jtalkBody' asJQuery css: 'margin-bottom' put: anInteger asString, 'px'
 !
 
-level: anInteger
-	level := anInteger
+onResize: aBlock
+    <jQuery('#jtalk').resizable({
+	handles: 'n', 
+	resize: aBlock,
+	minHeight: 230
+})>
 !
 
-label
-	| str |
-	str := String new writeStream.
-	self level timesRepeat: [
-		str nextPutAll: '&nbsp;&nbsp;&nbsp;&nbsp;'].
-	str nextPutAll: self theClass name.
-	^str contents
+onWindowResize: aBlock
+    <jQuery(window).resize(aBlock)>
 !
 
-getNodesFrom: aCollection
-	| children others |
-	children := #().
-	others := #().
-	aCollection do: [:each |
-		(each superclass = self theClass)
-			ifTrue: [children add: each]
-			ifFalse: [others add: each]].
-	nodes:= children collect: [:each |
-		ClassesListNode on: each browser: self browser classes: others level: self level + 1]
-! !
-
-!ClassesListNode class methodsFor: 'instance creation'!
-
-on: aClass browser: aBrowser classes: aCollection level: anInteger
-	^self new
-		theClass: aClass;
-		browser: aBrowser;
-		level: anInteger;
-		getNodesFrom: aCollection;
-		yourself
-! !
-
-Widget subclass: #ClassesList
-	instanceVariableNames: 'browser ul nodes'
-	category: 'IDE'!
-
-!ClassesList methodsFor: 'accessing'!
-
-category
-	^self browser selectedPackage
+open
+    opened ifFalse: [
+	'body' asJQuery addClass: 'jtalkBody'.
+	'#jtalk' asJQuery show.
+	ul asJQuery show.
+	self updateBodyMargin.
+	selectedTab show.
+	opened := true]
 !
 
-nodes
-	nodes ifNil: [nodes := self getNodes].
-	^nodes
+close
+    opened ifTrue: [
+	'#jtalk' asJQuery hide.
+	ul asJQuery hide.
+	selectedTab hide.
+	self removeBodyMargin.
+	'body' asJQuery removeClass: 'jtalkBody'.
+	opened := false]
 !
 
-browser
-	^browser
+newBrowserTab
+    Browser open
 !
 
-browser: aBrowser
-	browser := aBrowser
+selectTab: aWidget
+    self open.
+    selectedTab := aWidget.
+    self tabs do: [:each |
+	each hide].
+    aWidget show.
+	
+    self update
 !
 
-getNodes
-	| classes children others |
-	classes := self browser classes.
-	children := #().
-	others := #().
-	classes do: [:each |
-		(classes includes: each superclass)
-			ifFalse: [children add: each]
-			ifTrue: [others add: each]].
-	^children collect: [:each |
-		ClassesListNode on: each browser: self browser classes: others level: 0]
+closeTab: aWidget
+    self removeTab: aWidget.
+    self selectTab: self tabs last.
+    aWidget remove.
+    self update
 !
 
-resetNodes
-	nodes := nil
+search: aString
+	| searchedClass |
+	searchedClass := Smalltalk current at: aString.
+		searchedClass isClass
+			ifTrue: [Browser openOn: searchedClass]
+			ifFalse: [ReferencesBrowser search: aString]
 ! !
 
-!ClassesList methodsFor: 'rendering'!
+!TabManager methodsFor: 'adding/Removing'!
 
-renderOn: html
-	ul := html ul
-		class: 'jt_column browser classes';
-		yourself.
-	self updateNodes
+addTab: aWidget
+    self tabs add: aWidget.
+    aWidget appendToJQuery: '#jtalk' asJQuery.
+    aWidget hide
 !
 
-updateNodes
-	ul contents: [:html |
-		self nodes do: [:each |
-			each renderOn: html]]
+removeTab: aWidget
+    self tabs remove: aWidget.
+    self update
 ! !
 
-!ClassesList class methodsFor: 'instance creation'!
+!TabManager methodsFor: 'initialization'!
 
-on: aBrowser
-	^self new 
-		browser: aBrowser; 
-		yourself
+initialize
+    super initialize.
+    opened := true.
+    [:html | html div id: 'jtalk'] appendToJQuery: 'body' asJQuery.
+    'body' asJQuery 
+	addClass: 'jtalkBody'.
+    self appendToJQuery: '#jtalk' asJQuery.
+    self 
+	addTab: IDETranscript current;
+	addTab: Workspace new;
+	addTab: TestRunner new.
+    self selectTab: self tabs last.
+    self 
+	onResize: [self updateBodyMargin; updatePosition];
+	onWindowResize: [self updatePosition]
 ! !
 
-Widget subclass: #SourceArea
-	instanceVariableNames: 'editor div receiver onDoIt'
-	category: 'IDE'!
-
-!SourceArea methodsFor: 'accessing'!
+!TabManager methodsFor: 'rendering'!
 
-val
-    ^editor getValue
+renderOn: html
+	html div id: 'logo'.
+	self renderToolbarOn: html.
+	ul := html ul
+		id: 'jtalkTabs';
+		yourself.
+	self renderTabs
 !
 
-val: aString
-    editor setValue: aString
+renderTabFor: aWidget on: html
+	| li |
+	li := html li.
+	selectedTab = aWidget ifTrue: [
+	li class: 'selected'].
+	li with: [
+		html span class: 'ltab'.
+		html span
+			class: 'mtab';
+			with: [
+				aWidget canBeClosed ifTrue: [
+					html span 
+						class: 'close';
+						with: 'x';
+					onClick: [self closeTab: aWidget]].
+			html span with: (self labelFor: aWidget)].
+		html span class: 'rtab'];
+	onClick: [self selectTab: aWidget]
+!
+
+renderTabs
+	ul contents: [:html |
+	    self tabs do: [:each |
+		self renderTabFor: each on: html].
+	    html li
+		class: 'newtab';
+		with: [
+			html span class: 'ltab'.
+			html span class: 'mtab'; with: ' + '.
+			html span class: 'rtab'];
+		onClick: [self newBrowserTab]]
+!
+
+renderToolbarOn: html
+	html div 
+		id: 'jt_toolbar';
+		with: [
+			input := html input 
+				class: 'implementors';
+				yourself.
+			input onKeyPress: [:event |
+				event keyCode = 13 ifTrue: [
+				self search: input asJQuery val]].
+			html div id: 'jt_close'; onClick: [self close]]
+! !
+
+!TabManager methodsFor: 'updating'!
+
+update
+	self renderTabs
+! !
+
+TabManager class instanceVariableNames: 'current'!
+
+!TabManager class methodsFor: 'instance creation'!
+
+current
+    ^current ifNil: [current := super new]
+!
+
+new
+    self shouldNotImplement
+! !
+
+Widget subclass: #TabWidget
+	instanceVariableNames: 'div'
+	category: 'IDE'!
+
+!TabWidget methodsFor: 'accessing'!
+
+label
+    self subclassResponsibility
+! !
+
+!TabWidget methodsFor: 'actions'!
+
+open
+    TabManager current addTab: self.
+    TabManager current selectTab: self
+!
+
+show
+	div asJQuery show
+!
+
+hide
+	div asJQuery hide
+!
+
+remove
+	div asJQuery remove
+!
+
+close
+    TabManager current closeTab: self
+! !
+
+!TabWidget methodsFor: 'rendering'!
+
+renderOn: html
+	div := html div
+		class: 'jtalkTool';
+		yourself.
+	self renderTab
+!
+
+renderBoxOn: html
+!
+
+renderButtonsOn: html
+!
+
+update
+	self renderTab
+!
+
+renderTab
+	div contents: [:html |
+	    html div
+		class: 'jt_box';
+		with: [self renderBoxOn: html].
+	    html div
+		class: 'jt_buttons';
+		with: [self renderButtonsOn: html]]
+! !
+
+!TabWidget methodsFor: 'testing'!
+
+canBeClosed
+    ^false
+! !
+
+!TabWidget class methodsFor: 'instance creation'!
+
+open
+    ^self new open
+! !
+
+Widget subclass: #SourceArea
+	instanceVariableNames: 'editor div receiver onDoIt'
+	category: 'IDE'!
+
+!SourceArea methodsFor: 'accessing'!
+
+val
+    ^editor getValue
+!
+
+val: aString
+    editor setValue: aString
 !
 
 currentLine
@@ -328,283 +438,173 @@ renderOn: html
     div onKeyDown: [:e | self handleKeyDown: e]
 ! !
 
-Widget subclass: #TabWidget
-	instanceVariableNames: 'div'
+Widget subclass: #ClassesList
+	instanceVariableNames: 'browser ul nodes'
 	category: 'IDE'!
 
-!TabWidget methodsFor: 'accessing'!
-
-label
-    self subclassResponsibility
-! !
+!ClassesList methodsFor: 'accessing'!
 
-!TabWidget methodsFor: 'actions'!
+category
+	^self browser selectedPackage
+!
 
-open
-    TabManager current addTab: self.
-    TabManager current selectTab: self
+nodes
+	nodes ifNil: [nodes := self getNodes].
+	^nodes
 !
 
-show
-	div asJQuery show
+browser
+	^browser
 !
 
-hide
-	div asJQuery hide
+browser: aBrowser
+	browser := aBrowser
 !
 
-remove
-	div asJQuery remove
+getNodes
+	| classes children others |
+	classes := self browser classes.
+	children := #().
+	others := #().
+	classes do: [:each |
+		(classes includes: each superclass)
+			ifFalse: [children add: each]
+			ifTrue: [others add: each]].
+	^children collect: [:each |
+		ClassesListNode on: each browser: self browser classes: others level: 0]
 !
 
-close
-    TabManager current closeTab: self
+resetNodes
+	nodes := nil
 ! !
 
-!TabWidget methodsFor: 'rendering'!
+!ClassesList methodsFor: 'rendering'!
 
 renderOn: html
-	div := html div
-		class: 'jtalkTool';
+	ul := html ul
+		class: 'jt_column browser classes';
 		yourself.
-	self renderTab
-!
-
-renderBoxOn: html
-!
-
-renderButtonsOn: html
-!
-
-update
-	self renderTab
+	self updateNodes
 !
 
-renderTab
-	div contents: [:html |
-	    html div
-		class: 'jt_box';
-		with: [self renderBoxOn: html].
-	    html div
-		class: 'jt_buttons';
-		with: [self renderButtonsOn: html]]
-! !
-
-!TabWidget methodsFor: 'testing'!
-
-canBeClosed
-    ^false
+updateNodes
+	ul contents: [:html |
+		self nodes do: [:each |
+			each renderOn: html]]
 ! !
 
-!TabWidget class methodsFor: 'instance creation'!
+!ClassesList class methodsFor: 'instance creation'!
 
-open
-    ^self new open
+on: aBrowser
+	^self new 
+		browser: aBrowser; 
+		yourself
 ! !
 
-Widget subclass: #TabManager
-	instanceVariableNames: 'selectedTab tabs opened ul input'
+Widget subclass: #ClassesListNode
+	instanceVariableNames: 'browser theClass level nodes'
 	category: 'IDE'!
 
-!TabManager methodsFor: 'accessing'!
-
-tabs
-    ^tabs ifNil: [tabs := Array new]
-!
+!ClassesListNode methodsFor: ''!
 
-labelFor: aWidget
-	| label maxSize |
-	maxSize := 15.
-	label := aWidget label copyFrom: 0 to: (aWidget label size min: maxSize).
-	aWidget label size > maxSize ifTrue: [
-		label := label, '...'].
-	^label
-! !
+renderOn: html
+	| li cssClass |
+	cssClass := ''.
+	li := html li 
+		onClick: [self browser selectClass: self theClass]. 
+	li asJQuery html: self label.
 
-!TabManager methodsFor: 'actions'!
+	self browser selectedClass = self theClass ifTrue:  [
+		cssClass := cssClass, ' selected'].
 
-updateBodyMargin
-    self setBodyMargin: '#jtalk' asJQuery height
-!
+	self theClass comment isEmpty ifFalse: [
+		cssClass := cssClass, ' commented'].
 
-updatePosition
-    <jQuery('#jtalk').css('top', '').css('bottom', '0px')>
-!
+	li class: cssClass.
 
-removeBodyMargin
-    self setBodyMargin: 0
-!
+	self nodes do: [:each |
+		each renderOn: html]
+! !
 
-setBodyMargin: anInteger
-    '.jtalkBody' asJQuery css: 'margin-bottom' put: anInteger asString, 'px'
-!
+!ClassesListNode methodsFor: 'accessing'!
 
-onResize: aBlock
-    <jQuery('#jtalk').resizable({
-	handles: 'n', 
-	resize: aBlock,
-	minHeight: 230
-})>
+nodes
+	^nodes
 !
 
-onWindowResize: aBlock
-    <jQuery(window).resize(aBlock)>
+theClass
+	^theClass
 !
 
-open
-    opened ifFalse: [
-	'body' asJQuery addClass: 'jtalkBody'.
-	'#jtalk' asJQuery show.
-	ul asJQuery show.
-	self updateBodyMargin.
-	selectedTab show.
-	opened := true]
+theClass: aClass
+	theClass := aClass
 !
 
-close
-    opened ifTrue: [
-	'#jtalk' asJQuery hide.
-	ul asJQuery hide.
-	selectedTab hide.
-	self removeBodyMargin.
-	'body' asJQuery removeClass: 'jtalkBody'.
-	opened := false]
+browser
+	^browser
 !
 
-newBrowserTab
-    Browser open
+browser: aBrowser
+	browser := aBrowser
 !
 
-selectTab: aWidget
-    self open.
-    selectedTab := aWidget.
-    self tabs do: [:each |
-	each hide].
-    aWidget show.
-	
-    self update
+level
+	^level
 !
 
-closeTab: aWidget
-    self removeTab: aWidget.
-    self selectTab: self tabs last.
-    aWidget remove.
-    self update
+level: anInteger
+	level := anInteger
 !
 
-search: aString
-	| searchedClass |
-	searchedClass := Smalltalk current at: aString.
-		searchedClass isClass
-			ifTrue: [Browser openOn: searchedClass]
-			ifFalse: [ReferencesBrowser search: aString]
-! !
-
-!TabManager methodsFor: 'adding/Removing'!
-
-addTab: aWidget
-    self tabs add: aWidget.
-    aWidget appendToJQuery: '#jtalk' asJQuery.
-    aWidget hide
+label
+	| str |
+	str := String new writeStream.
+	self level timesRepeat: [
+		str nextPutAll: '&nbsp;&nbsp;&nbsp;&nbsp;'].
+	str nextPutAll: self theClass name.
+	^str contents
 !
 
-removeTab: aWidget
-    self tabs remove: aWidget.
-    self update
+getNodesFrom: aCollection
+	| children others |
+	children := #().
+	others := #().
+	aCollection do: [:each |
+		(each superclass = self theClass)
+			ifTrue: [children add: each]
+			ifFalse: [others add: each]].
+	nodes:= children collect: [:each |
+		ClassesListNode on: each browser: self browser classes: others level: self level + 1]
 ! !
 
-!TabManager methodsFor: 'initialization'!
+!ClassesListNode class methodsFor: 'instance creation'!
 
-initialize
-    super initialize.
-    opened := true.
-    [:html | html div id: 'jtalk'] appendToJQuery: 'body' asJQuery.
-    'body' asJQuery 
-	addClass: 'jtalkBody'.
-    self appendToJQuery: '#jtalk' asJQuery.
-    self 
-	addTab: IDETranscript current;
-	addTab: Workspace new;
-	addTab: TestRunner new.
-    self selectTab: self tabs last.
-    self 
-	onResize: [self updateBodyMargin; updatePosition];
-	onWindowResize: [self updatePosition]
+on: aClass browser: aBrowser classes: aCollection level: anInteger
+	^self new
+		theClass: aClass;
+		browser: aBrowser;
+		level: anInteger;
+		getNodesFrom: aCollection;
+		yourself
 ! !
 
-!TabManager methodsFor: 'rendering'!
-
-renderOn: html
-	html div id: 'logo'.
-	self renderToolbarOn: html.
-	ul := html ul
-		id: 'jtalkTabs';
-		yourself.
-	self renderTabs
-!
-
-renderTabFor: aWidget on: html
-	| li |
-	li := html li.
-	selectedTab = aWidget ifTrue: [
-	li class: 'selected'].
-	li with: [
-		html span class: 'ltab'.
-		html span
-			class: 'mtab';
-			with: [
-				aWidget canBeClosed ifTrue: [
-					html span 
-						class: 'close';
-						with: 'x';
-					onClick: [self closeTab: aWidget]].
-			html span with: (self labelFor: aWidget)].
-		html span class: 'rtab'];
-	onClick: [self selectTab: aWidget]
-!
-
-renderTabs
-	ul contents: [:html |
-	    self tabs do: [:each |
-		self renderTabFor: each on: html].
-	    html li
-		class: 'newtab';
-		with: [
-			html span class: 'ltab'.
-			html span class: 'mtab'; with: ' + '.
-			html span class: 'rtab'];
-		onClick: [self newBrowserTab]]
-!
-
-renderToolbarOn: html
-	html div 
-		id: 'jt_toolbar';
-		with: [
-			input := html input 
-				class: 'implementors';
-				yourself.
-			input onKeyPress: [:event |
-				event keyCode = 13 ifTrue: [
-				self search: input asJQuery val]].
-			html div id: 'jt_close'; onClick: [self close]]
-! !
+ErrorHandler subclass: #DebugErrorHandler
+	instanceVariableNames: ''
+	category: 'IDE'!
 
-!TabManager methodsFor: 'updating'!
+!DebugErrorHandler methodsFor: 'error handling'!
 
-update
-	self renderTabs
+handleError: anError
+	[Debugger new
+		error: anError;
+		open] on: Error do: [:error |
+			ErrorHandler new handleError: error]
 ! !
 
-TabManager class instanceVariableNames: 'current'!
-
-!TabManager class methodsFor: 'instance creation'!
-
-current
-    ^current ifNil: [current := super new]
-!
+!DebugErrorHandler class methodsFor: 'initialization'!
 
-new
-    self shouldNotImplement
+initialize
+	self register
 ! !
 
 TabWidget subclass: #Workspace
@@ -1289,12 +1289,13 @@ updateSourceAndButtons
 					class: 'important';
 					with: 'New...'.
 				self protocols do: [:each |
-					html option with: each]].
+					option := html option with: each.
+					selectedProtocol = each ifTrue: [ option at: 'selected' put: 'selected' ] ]].
 		selectedMethod isNil ifFalse: [
 			referencesSelect := html select.
                         referencesSelect
 				onChange: [self searchReferencesOf: referencesSelect asJQuery val];
-				with: [
+				with: [ |option|
 					html option
 						with: 'References';
 						at: 'disabled' put: 'disabled'.

+ 56 - 49
st/Kernel-Collections.st

@@ -1,53 +1,4 @@
 Smalltalk current createPackage: 'Kernel-Collections' properties: #{}!
-Object subclass: #Association
-	instanceVariableNames: 'key value'
-	category: 'Kernel-Collections'!
-
-!Association methodsFor: 'accessing'!
-
-key: aKey
-	key := aKey
-!
-
-key
-	^key
-!
-
-value: aValue
-	value := aValue
-!
-
-value
-	^value
-! !
-
-!Association methodsFor: 'comparing'!
-
-= anAssociation
-	^self class = anAssociation class and: [
-	    self key = anAssociation key and: [
-		self value = anAssociation value]]
-!
-
-storeOn: aStream
-	"Store in the format (key->value)"
-
-	"aStream nextPutAll: '('."
-	key storeOn: aStream.
-	aStream nextPutAll: '->'.
-	value storeOn: aStream.
-	"aStream nextPutAll: ')'"
-! !
-
-!Association class methodsFor: 'instance creation'!
-
-key: aKey value: aValue
-	    ^self new
-		key: aKey;
-		value: aValue;
-		yourself
-! !
-
 Object subclass: #Stream
 	instanceVariableNames: 'collection position streamSize'
 	category: 'Kernel-Collections'!
@@ -181,6 +132,55 @@ on: aCollection
 		yourself
 ! !
 
+Object subclass: #Association
+	instanceVariableNames: 'key value'
+	category: 'Kernel-Collections'!
+
+!Association methodsFor: 'accessing'!
+
+key: aKey
+	key := aKey
+!
+
+key
+	^key
+!
+
+value: aValue
+	value := aValue
+!
+
+value
+	^value
+! !
+
+!Association methodsFor: 'comparing'!
+
+= anAssociation
+	^self class = anAssociation class and: [
+	    self key = anAssociation key and: [
+		self value = anAssociation value]]
+!
+
+storeOn: aStream
+	"Store in the format (key->value)"
+
+	"aStream nextPutAll: '('."
+	key storeOn: aStream.
+	aStream nextPutAll: '->'.
+	value storeOn: aStream.
+	"aStream nextPutAll: ')'"
+! !
+
+!Association class methodsFor: 'instance creation'!
+
+key: aKey value: aValue
+	    ^self new
+		key: aKey;
+		value: aValue;
+		yourself
+! !
+
 Object subclass: #RegularExpression
 	instanceVariableNames: ''
 	category: 'Kernel-Collections'!
@@ -505,6 +505,13 @@ indexOf: anObject startingAt: start
 
 atRandom
 	^ self at: self size atRandom
+!
+
+first: n
+	"Answer the first n elements of the receiver.
+	Raise an error if there are not enough elements."
+
+	^ self copyFrom: 1 to: n
 ! !
 
 !SequenceableCollection methodsFor: 'adding'!

+ 7 - 0
st/Kernel-Objects.st

@@ -1635,6 +1635,13 @@ printString
 		stream nextPutAll: y printString]
 ! !
 
+!Point methodsFor: 'transforming'!
+
+translateBy: delta 
+	"Answer a Point translated by delta (an instance of Point)."
+	^(delta x + x) @ (delta y + y)
+! !
+
 !Point class methodsFor: 'instance creation'!
 
 x: aNumber y: anotherNumber

+ 17 - 0
st/Kernel-Tests.st

@@ -117,6 +117,13 @@ testArithmetic
 	self assert: 3@4 + (3@4 ) equals: (Point x: 6 y: 8).
 	self assert: 3@4 - (3@4 ) equals: (Point x: 0 y: 0).
 	self assert: 6@8 / (3@4 ) equals: (Point x: 2 y: 2)
+!
+
+testTranslateBy
+	self assert: 3@4 equals: (3@3 translateBy: 0@1).
+	self assert: 3@2 equals: (3@3 translateBy: 0@1 negated).
+	self assert: 5@6 equals: (3@3 translateBy: 2@3).
+	self assert: 0@3 equals: (3@3 translateBy: 3 negated @0).
 ! !
 
 TestCase subclass: #UndefinedTest
@@ -856,6 +863,16 @@ testAsArray
 	self assert: 'hello' asArray = #('h' 'e' 'l' 'l' 'o').
 ! !
 
+TestCase subclass: #ArrayTest
+	instanceVariableNames: ''
+	category: 'Kernel-Tests'!
+
+!ArrayTest methodsFor: 'testing'!
+
+testFirstN
+	self assert: {1. 2. 3} equals: ({1. 2. 3. 4. 5} first: 3).
+! !
+
 PackageTest subclass: #PackageWithDefaultCommitPathChangedTest
 	instanceVariableNames: ''
 	category: 'Kernel-Tests'!

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