Browse Source

Basic streaming protocol extracted to ProtoStream

Herbert Vojčík 9 years ago
parent
commit
5d683a8f83
3 changed files with 747 additions and 349 deletions
  1. 2 0
      API-CHANGES.txt
  2. 588 268
      src/Kernel-Collections.js
  3. 157 81
      src/Kernel-Collections.st

+ 2 - 0
API-CHANGES.txt

@@ -1,5 +1,7 @@
 0.14.11:
 
+* Basic streaming protocol extracted from Stream to ProtoStream
+
 + Object >>
   + in:
 + JSObjectProxy >>

+ 588 - 268
src/Kernel-Collections.js

@@ -8679,322 +8679,474 @@ $globals.Set);
 
 
 
-$core.addClass('Queue', $globals.Object, ['read', 'readIndex', 'write'], 'Kernel-Collections');
+$core.addClass('ProtoStream', $globals.Object, [], 'Kernel-Collections');
 //>>excludeStart("ide", pragmas.excludeIdeData);
-$globals.Queue.comment="I am a one-sided queue.\x0a\x0a## Usage\x0a\x0aUse `#nextPut:` to add items to the queue.\x0aUse `#next` or `#nextIfAbsent:` to get (and remove) the next item in the queue.\x0a\x0a## Implementation notes\x0a\x0aA Queue uses two OrderedCollections inside,\x0a`read` is at the front, is not modified and only read using `readIndex`.\x0a`write` is at the back and is appended new items.\x0aWhen `read` is exhausted, `write` is promoted to `read` and new `write` is created.\x0a\x0aAs a consequence, no data moving is done by me, write appending may do data moving\x0awhen growing `write`, but this is left to engine to implement as good as it chooses to.";
+$globals.ProtoStream.comment="I am the abstract base for different accessor for a sequence of objects. This sequence is referred to as my \x22contents\x22.\x0aMy instances are read/write streams modifying the contents.";
 //>>excludeEnd("ide");
 $core.addMethod(
 $core.method({
-selector: "initialize",
-protocol: 'initialization',
-fn: function (){
+selector: "<<",
+protocol: 'writing',
+fn: function (anObject){
 var self=this;
-function $OrderedCollection(){return $globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-(
+self._write_(anObject);
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = true, 
+}, function($ctx1) {$ctx1.fill(self,"<<",{anObject:anObject},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
-$globals.Queue.superclass.fn.prototype._initialize.apply($recv(self), []));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.supercall = false;
-//>>excludeEnd("ctx");;
-self["@read"]=$recv($OrderedCollection())._new();
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "<< anObject\x0a\x09self write: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["write:"]
+}),
+$globals.ProtoStream);
+
+$core.addMethod(
+$core.method({
+selector: "atEnd",
+protocol: 'testing',
+fn: function (){
+var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["new"]=1;
+return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-self["@write"]=$recv($OrderedCollection())._new();
-self["@readIndex"]=(1);
+self._subclassResponsibility();
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"initialize",{},$globals.Queue)});
+}, function($ctx1) {$ctx1.fill(self,"atEnd",{},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "initialize\x0a\x09super initialize.\x0a\x09read := OrderedCollection new.\x0a\x09write := OrderedCollection new.\x0a\x09readIndex := 1",
-referencedClasses: ["OrderedCollection"],
+source: "atEnd\x0a\x09self subclassResponsibility",
+referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["initialize", "new"]
+messageSends: ["subclassResponsibility"]
 }),
-$globals.Queue);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "next",
-protocol: 'accessing',
+selector: "atStart",
+protocol: 'testing',
 fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=self._nextIfAbsent_((function(){
+self._subclassResponsibility();
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
+}, function($ctx1) {$ctx1.fill(self,"atStart",{},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
-return self._error_("Cannot read from empty Queue.");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "atStart\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["subclassResponsibility"]
+}),
+$globals.ProtoStream);
+
+$core.addMethod(
+$core.method({
+selector: "contents",
+protocol: 'accessing',
+fn: function (){
+var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-}));
-return $1;
+self._subclassResponsibility();
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"next",{},$globals.Queue)});
+}, function($ctx1) {$ctx1.fill(self,"contents",{},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "next\x0a\x09^ self nextIfAbsent: [ self error: 'Cannot read from empty Queue.' ]",
+source: "contents\x0a\x09self subclassResponsibility",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["nextIfAbsent:", "error:"]
+messageSends: ["subclassResponsibility"]
 }),
-$globals.Queue);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "nextIfAbsent:",
-protocol: 'accessing',
+selector: "do:",
+protocol: 'enumerating',
 fn: function (aBlock){
 var self=this;
-var result;
-function $OrderedCollection(){return $globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2,$3,$4;
-var $early={};
-try {
-result=$recv(self["@read"])._at_ifAbsent_(self["@readIndex"],(function(){
+$recv((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$1=$recv(self["@write"])._isEmpty();
-if($core.assert($1)){
-$2=$recv(self["@readIndex"]).__gt((1));
-if($core.assert($2)){
-self["@read"]=[];
-self["@read"];
-self["@readIndex"]=(1);
-self["@readIndex"];
-};
-$3=$recv(aBlock)._value();
-throw $early=[$3];
-};
-self["@read"]=self["@write"];
-self["@read"];
-self["@readIndex"]=(1);
-self["@readIndex"];
-self["@write"]=$recv($OrderedCollection())._new();
-self["@write"];
-return $recv(self["@read"])._first();
+return self._atEnd();
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
+}))._whileFalse_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(aBlock)._value_(self._next());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
+//>>excludeEnd("ctx");
 }));
-$recv(self["@read"])._at_put_(self["@readIndex"],nil);
-self["@readIndex"]=$recv(self["@readIndex"]).__plus((1));
-$4=result;
-return $4;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextIfAbsent:",{aBlock:aBlock,result:result},$globals.Queue)});
+}, function($ctx1) {$ctx1.fill(self,"do:",{aBlock:aBlock},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock"],
-source: "nextIfAbsent: aBlock\x0a\x09| result |\x0a\x09result := read at: readIndex ifAbsent: [\x0a\x09\x09write isEmpty ifTrue: [\x0a\x09\x09\x09readIndex > 1 ifTrue: [ read := #(). readIndex := 1 ].\x0a\x09\x09\x09^ aBlock value ].\x0a\x09\x09read := write.\x0a\x09\x09readIndex := 1.\x0a\x09\x09write := OrderedCollection new.\x0a\x09\x09read first ].\x0a\x09read at: readIndex put: nil.\x0a\x09readIndex := readIndex + 1.\x0a\x09^ result",
-referencedClasses: ["OrderedCollection"],
+source: "do: aBlock\x0a\x09[ self atEnd ] whileFalse: [ aBlock value: self next ]",
+referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["at:ifAbsent:", "ifTrue:", "isEmpty", ">", "value", "new", "first", "at:put:", "+"]
+messageSends: ["whileFalse:", "atEnd", "value:", "next"]
 }),
-$globals.Queue);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "nextPut:",
-protocol: 'accessing',
-fn: function (anObject){
+selector: "isEmpty",
+protocol: 'testing',
+fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$recv(self["@write"])._add_(anObject);
-return self;
+var $1;
+$1=$recv(self._atStart())._and_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextPut:",{anObject:anObject},$globals.Queue)});
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return self._atEnd();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return $1;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"isEmpty",{},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anObject"],
-source: "nextPut: anObject\x0a\x09write add: anObject",
+args: [],
+source: "isEmpty\x0a\x09^ self atStart and: [ self atEnd ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["add:"]
+messageSends: ["and:", "atStart", "atEnd"]
 }),
-$globals.Queue);
-
-
+$globals.ProtoStream);
 
-$core.addClass('RegularExpression', $globals.Object, [], 'Kernel-Collections');
-//>>excludeStart("ide", pragmas.excludeIdeData);
-$globals.RegularExpression.comment="I represent a regular expression object. My instances are JavaScript `RegExp` object.";
-//>>excludeEnd("ide");
 $core.addMethod(
 $core.method({
-selector: "compile:",
-protocol: 'evaluating',
-fn: function (aString){
+selector: "next",
+protocol: 'reading',
+fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return self.compile(aString);
-return self;
+var $2,$1;
+$2=self._atEnd();
+if($core.assert($2)){
+$1=nil;
+} else {
+$1=self._subclassResponsibility();
+};
+return $1;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"compile:",{aString:aString},$globals.RegularExpression)});
+}, function($ctx1) {$ctx1.fill(self,"next",{},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "compile: aString\x0a\x09<return self.compile(aString)>",
+args: [],
+source: "next\x0a\x09^ self atEnd\x0a\x09\x09ifTrue: [ nil ]\x0a\x09\x09ifFalse: [ self subclassResponsibility ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: []
+messageSends: ["ifTrue:ifFalse:", "atEnd", "subclassResponsibility"]
 }),
-$globals.RegularExpression);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "exec:",
-protocol: 'evaluating',
-fn: function (aString){
+selector: "nextPut:",
+protocol: 'writing',
+fn: function (anObject){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return self.exec(aString) || nil;
+self._subclassResponsibility();
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"exec:",{aString:aString},$globals.RegularExpression)});
+}, function($ctx1) {$ctx1.fill(self,"nextPut:",{anObject:anObject},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "exec: aString\x0a\x09<return self.exec(aString) || nil>",
+args: ["anObject"],
+source: "nextPut: anObject\x0a\x09self subclassResponsibility",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: []
+messageSends: ["subclassResponsibility"]
 }),
-$globals.RegularExpression);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "test:",
-protocol: 'evaluating',
-fn: function (aString){
+selector: "nextPutAll:",
+protocol: 'writing',
+fn: function (aCollection){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return self.test(aString);
+$recv(aCollection)._do_((function(each){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return self._nextPut_(each);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"test:",{aString:aString},$globals.RegularExpression)});
+}, function($ctx1) {$ctx1.fill(self,"nextPutAll:",{aCollection:aCollection},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "test: aString\x0a\x09<return self.test(aString)>",
+args: ["aCollection"],
+source: "nextPutAll: aCollection\x0a\x09aCollection do: [ :each |\x0a\x09\x09self nextPut: each ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: []
+messageSends: ["do:", "nextPut:"]
 }),
-$globals.RegularExpression);
-
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "fromString:",
-protocol: 'instance creation',
+selector: "nextPutString:",
+protocol: 'writing',
 fn: function (aString){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=self._fromString_flag_(aString,"");
-return $1;
+self._nextPut_(aString);
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"fromString:",{aString:aString},$globals.RegularExpression.klass)});
+}, function($ctx1) {$ctx1.fill(self,"nextPutString:",{aString:aString},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString"],
-source: "fromString: aString\x0a\x09\x09^ self fromString: aString flag: ''",
+source: "nextPutString: aString\x0a\x09self nextPut: aString",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["fromString:flag:"]
+messageSends: ["nextPut:"]
 }),
-$globals.RegularExpression.klass);
+$globals.ProtoStream);
 
 $core.addMethod(
 $core.method({
-selector: "fromString:flag:",
-protocol: 'instance creation',
-fn: function (aString,anotherString){
+selector: "peek",
+protocol: 'reading',
+fn: function (){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return new RegExp(aString, anotherString);
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"fromString:flag:",{aString:aString,anotherString:anotherString},$globals.RegularExpression.klass)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString", "anotherString"],
-source: "fromString: aString flag: anotherString\x0a\x09<return new RegExp(aString, anotherString)>",
+var $2,$1;
+$2=self._atEnd();
+if($core.assert($2)){
+$1=nil;
+} else {
+$1=self._subclassResponsibility();
+};
+return $1;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"peek",{},$globals.ProtoStream)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "peek\x0a\x09^ self atEnd\x0a\x09\x09ifTrue: [ nil ]\x0a\x09\x09ifFalse: [ self subclassResponsibility ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: []
+messageSends: ["ifTrue:ifFalse:", "atEnd", "subclassResponsibility"]
 }),
-$globals.RegularExpression.klass);
+$globals.ProtoStream);
 
+$core.addMethod(
+$core.method({
+selector: "reset",
+protocol: 'actions',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"reset",{},$globals.ProtoStream)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "reset\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["subclassResponsibility"]
+}),
+$globals.ProtoStream);
 
-$core.addClass('Stream', $globals.Object, ['collection', 'position', 'streamSize'], 'Kernel-Collections');
+$core.addMethod(
+$core.method({
+selector: "resetContents",
+protocol: 'actions',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"resetContents",{},$globals.ProtoStream)});
+//>>excludeEnd("ctx");
+},
 //>>excludeStart("ide", pragmas.excludeIdeData);
-$globals.Stream.comment="I represent an accessor for a sequence of objects. This sequence is referred to as my \x22contents\x22.\x0aMy instances are read/write streams to the contents sequence collection.";
+args: [],
+source: "resetContents\x0a\x09self subclassResponsibility",
+referencedClasses: [],
 //>>excludeEnd("ide");
+messageSends: ["subclassResponsibility"]
+}),
+$globals.ProtoStream);
+
 $core.addMethod(
 $core.method({
-selector: "<<",
+selector: "setToEnd",
+protocol: 'positioning',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._subclassResponsibility();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"setToEnd",{},$globals.ProtoStream)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "setToEnd\x0a\x09self subclassResponsibility",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["subclassResponsibility"]
+}),
+$globals.ProtoStream);
+
+$core.addMethod(
+$core.method({
+selector: "setToStart",
+protocol: 'positioning',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._reset();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"setToStart",{},$globals.ProtoStream)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "setToStart\x0a\x09self reset",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["reset"]
+}),
+$globals.ProtoStream);
+
+$core.addMethod(
+$core.method({
+selector: "write:",
 protocol: 'writing',
 fn: function (anObject){
 var self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-self._write_(anObject);
+$recv(anObject)._putOn_(self);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"<<",{anObject:anObject},$globals.Stream)});
+}, function($ctx1) {$ctx1.fill(self,"write:",{anObject:anObject},$globals.ProtoStream)});
 //>>excludeEnd("ctx");
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anObject"],
-source: "<< anObject\x0a\x09self write: anObject",
+source: "write: anObject\x0a\x09anObject putOn: self",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["write:"]
+messageSends: ["putOn:"]
 }),
-$globals.Stream);
+$globals.ProtoStream);
+
+
+$core.addMethod(
+$core.method({
+selector: "on:",
+protocol: 'instance creation',
+fn: function (aCollection){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $2,$3,$1;
+$2=self._new();
+$recv($2)._setCollection_(aCollection);
+$recv($2)._setStreamSize_($recv(aCollection)._size());
+$3=$recv($2)._yourself();
+$1=$3;
+return $1;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"on:",{aCollection:aCollection},$globals.ProtoStream.klass)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection"],
+source: "on: aCollection\x0a\x09\x09^ self new\x0a\x09\x09setCollection: aCollection;\x0a\x09\x09setStreamSize: aCollection size;\x0a\x09\x09yourself",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["setCollection:", "new", "setStreamSize:", "size", "yourself"]
+}),
+$globals.ProtoStream.klass);
 
+
+$core.addClass('Stream', $globals.ProtoStream, ['collection', 'position', 'streamSize'], 'Kernel-Collections');
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.Stream.comment="I represent an accessor for a sequence of objects. This sequence is referred to as my \x22contents\x22.\x0aMy instances are read/write streams to the contents sequence collection.";
+//>>excludeEnd("ide");
 $core.addMethod(
 $core.method({
 selector: "atEnd",
@@ -9108,46 +9260,6 @@ messageSends: ["copyFrom:to:", "collection", "streamSize"]
 }),
 $globals.Stream);
 
-$core.addMethod(
-$core.method({
-selector: "do:",
-protocol: 'enumerating',
-fn: function (aBlock){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return self._atEnd();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}))._whileFalse_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(aBlock)._value_(self._next());
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"do:",{aBlock:aBlock},$globals.Stream)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aBlock"],
-source: "do: aBlock\x0a\x09[ self atEnd ] whileFalse: [ aBlock value: self next ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["whileFalse:", "atEnd", "value:", "next"]
-}),
-$globals.Stream);
-
 $core.addMethod(
 $core.method({
 selector: "flush",
@@ -9303,62 +9415,6 @@ messageSends: ["position:", "+", "position", "at:put:", "collection", "setStream
 }),
 $globals.Stream);
 
-$core.addMethod(
-$core.method({
-selector: "nextPutAll:",
-protocol: 'writing',
-fn: function (aCollection){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv(aCollection)._do_((function(each){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return self._nextPut_(each);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextPutAll:",{aCollection:aCollection},$globals.Stream)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aCollection"],
-source: "nextPutAll: aCollection\x0a\x09aCollection do: [ :each |\x0a\x09\x09self nextPut: each ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["do:", "nextPut:"]
-}),
-$globals.Stream);
-
-$core.addMethod(
-$core.method({
-selector: "nextPutString:",
-protocol: 'writing',
-fn: function (aString){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-self._nextPut_(aString);
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"nextPutString:",{aString:aString},$globals.Stream)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aString"],
-source: "nextPutString: aString\x0a\x09self nextPut: aString",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["nextPut:"]
-}),
-$globals.Stream);
-
 $core.addMethod(
 $core.method({
 selector: "peek",
@@ -9617,30 +9673,6 @@ messageSends: []
 }),
 $globals.Stream);
 
-$core.addMethod(
-$core.method({
-selector: "write:",
-protocol: 'writing',
-fn: function (anObject){
-var self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv(anObject)._putOn_(self);
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"write:",{anObject:anObject},$globals.Stream)});
-//>>excludeEnd("ctx");
-},
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anObject"],
-source: "write: anObject\x0a\x09anObject putOn: self",
-referencedClasses: [],
-//>>excludeEnd("ide");
-messageSends: ["putOn:"]
-}),
-$globals.Stream);
-
 
 $core.addMethod(
 $core.method({
@@ -9985,4 +10017,292 @@ messageSends: ["nextPutAll:", "tab"]
 $globals.StringStream);
 
 
+
+$core.addClass('Queue', $globals.Object, ['read', 'readIndex', 'write'], 'Kernel-Collections');
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.Queue.comment="I am a one-sided queue.\x0a\x0a## Usage\x0a\x0aUse `#nextPut:` to add items to the queue.\x0aUse `#next` or `#nextIfAbsent:` to get (and remove) the next item in the queue.\x0a\x0a## Implementation notes\x0a\x0aA Queue uses two OrderedCollections inside,\x0a`read` is at the front, is not modified and only read using `readIndex`.\x0a`write` is at the back and is appended new items.\x0aWhen `read` is exhausted, `write` is promoted to `read` and new `write` is created.\x0a\x0aAs a consequence, no data moving is done by me, write appending may do data moving\x0awhen growing `write`, but this is left to engine to implement as good as it chooses to.";
+//>>excludeEnd("ide");
+$core.addMethod(
+$core.method({
+selector: "initialize",
+protocol: 'initialization',
+fn: function (){
+var self=this;
+function $OrderedCollection(){return $globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+(
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = true, 
+//>>excludeEnd("ctx");
+$globals.Queue.superclass.fn.prototype._initialize.apply($recv(self), []));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.supercall = false;
+//>>excludeEnd("ctx");;
+self["@read"]=$recv($OrderedCollection())._new();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["new"]=1;
+//>>excludeEnd("ctx");
+self["@write"]=$recv($OrderedCollection())._new();
+self["@readIndex"]=(1);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"initialize",{},$globals.Queue)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "initialize\x0a\x09super initialize.\x0a\x09read := OrderedCollection new.\x0a\x09write := OrderedCollection new.\x0a\x09readIndex := 1",
+referencedClasses: ["OrderedCollection"],
+//>>excludeEnd("ide");
+messageSends: ["initialize", "new"]
+}),
+$globals.Queue);
+
+$core.addMethod(
+$core.method({
+selector: "next",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=self._nextIfAbsent_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return self._error_("Cannot read from empty Queue.");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return $1;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"next",{},$globals.Queue)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "next\x0a\x09^ self nextIfAbsent: [ self error: 'Cannot read from empty Queue.' ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["nextIfAbsent:", "error:"]
+}),
+$globals.Queue);
+
+$core.addMethod(
+$core.method({
+selector: "nextIfAbsent:",
+protocol: 'accessing',
+fn: function (aBlock){
+var self=this;
+var result;
+function $OrderedCollection(){return $globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$2,$3,$4;
+var $early={};
+try {
+result=$recv(self["@read"])._at_ifAbsent_(self["@readIndex"],(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$1=$recv(self["@write"])._isEmpty();
+if($core.assert($1)){
+$2=$recv(self["@readIndex"]).__gt((1));
+if($core.assert($2)){
+self["@read"]=[];
+self["@read"];
+self["@readIndex"]=(1);
+self["@readIndex"];
+};
+$3=$recv(aBlock)._value();
+throw $early=[$3];
+};
+self["@read"]=self["@write"];
+self["@read"];
+self["@readIndex"]=(1);
+self["@readIndex"];
+self["@write"]=$recv($OrderedCollection())._new();
+self["@write"];
+return $recv(self["@read"])._first();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$recv(self["@read"])._at_put_(self["@readIndex"],nil);
+self["@readIndex"]=$recv(self["@readIndex"]).__plus((1));
+$4=result;
+return $4;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"nextIfAbsent:",{aBlock:aBlock,result:result},$globals.Queue)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aBlock"],
+source: "nextIfAbsent: aBlock\x0a\x09| result |\x0a\x09result := read at: readIndex ifAbsent: [\x0a\x09\x09write isEmpty ifTrue: [\x0a\x09\x09\x09readIndex > 1 ifTrue: [ read := #(). readIndex := 1 ].\x0a\x09\x09\x09^ aBlock value ].\x0a\x09\x09read := write.\x0a\x09\x09readIndex := 1.\x0a\x09\x09write := OrderedCollection new.\x0a\x09\x09read first ].\x0a\x09read at: readIndex put: nil.\x0a\x09readIndex := readIndex + 1.\x0a\x09^ result",
+referencedClasses: ["OrderedCollection"],
+//>>excludeEnd("ide");
+messageSends: ["at:ifAbsent:", "ifTrue:", "isEmpty", ">", "value", "new", "first", "at:put:", "+"]
+}),
+$globals.Queue);
+
+$core.addMethod(
+$core.method({
+selector: "nextPut:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(self["@write"])._add_(anObject);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"nextPut:",{anObject:anObject},$globals.Queue)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "nextPut: anObject\x0a\x09write add: anObject",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["add:"]
+}),
+$globals.Queue);
+
+
+
+$core.addClass('RegularExpression', $globals.Object, [], 'Kernel-Collections');
+//>>excludeStart("ide", pragmas.excludeIdeData);
+$globals.RegularExpression.comment="I represent a regular expression object. My instances are JavaScript `RegExp` object.";
+//>>excludeEnd("ide");
+$core.addMethod(
+$core.method({
+selector: "compile:",
+protocol: 'evaluating',
+fn: function (aString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self.compile(aString);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"compile:",{aString:aString},$globals.RegularExpression)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "compile: aString\x0a\x09<return self.compile(aString)>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.RegularExpression);
+
+$core.addMethod(
+$core.method({
+selector: "exec:",
+protocol: 'evaluating',
+fn: function (aString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self.exec(aString) || nil;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"exec:",{aString:aString},$globals.RegularExpression)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "exec: aString\x0a\x09<return self.exec(aString) || nil>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.RegularExpression);
+
+$core.addMethod(
+$core.method({
+selector: "test:",
+protocol: 'evaluating',
+fn: function (aString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self.test(aString);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"test:",{aString:aString},$globals.RegularExpression)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "test: aString\x0a\x09<return self.test(aString)>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.RegularExpression);
+
+
+$core.addMethod(
+$core.method({
+selector: "fromString:",
+protocol: 'instance creation',
+fn: function (aString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=self._fromString_flag_(aString,"");
+return $1;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"fromString:",{aString:aString},$globals.RegularExpression.klass)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "fromString: aString\x0a\x09\x09^ self fromString: aString flag: ''",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["fromString:flag:"]
+}),
+$globals.RegularExpression.klass);
+
+$core.addMethod(
+$core.method({
+selector: "fromString:flag:",
+protocol: 'instance creation',
+fn: function (aString,anotherString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return new RegExp(aString, anotherString);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"fromString:flag:",{aString:aString,anotherString:anotherString},$globals.RegularExpression.klass)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString", "anotherString"],
+source: "fromString: aString flag: anotherString\x0a\x09<return new RegExp(aString, anotherString)>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.RegularExpression.klass);
+
 });

+ 157 - 81
src/Kernel-Collections.st

@@ -2037,92 +2037,106 @@ includes: anObject
 		ifNotNil: [ :primitiveBucket | self includes: bucket first in: primitiveBucket ]
 ! !
 
-Object subclass: #Queue
-	instanceVariableNames: 'read readIndex write'
+Object subclass: #ProtoStream
+	instanceVariableNames: ''
 	package: 'Kernel-Collections'!
-!Queue commentStamp!
-I am a one-sided queue.
+!ProtoStream commentStamp!
+I am the abstract base for different accessor for a sequence of objects. This sequence is referred to as my "contents".
+My instances are read/write streams modifying the contents.!
 
-## Usage
+!ProtoStream methodsFor: 'accessing'!
 
-Use `#nextPut:` to add items to the queue.
-Use `#next` or `#nextIfAbsent:` to get (and remove) the next item in the queue.
+contents
+	self subclassResponsibility
+! !
 
-## Implementation notes
+!ProtoStream methodsFor: 'actions'!
 
-A Queue uses two OrderedCollections inside,
-`read` is at the front, is not modified and only read using `readIndex`.
-`write` is at the back and is appended new items.
-When `read` is exhausted, `write` is promoted to `read` and new `write` is created.
+reset
+	self subclassResponsibility
+!
 
-As a consequence, no data moving is done by me, write appending may do data moving
-when growing `write`, but this is left to engine to implement as good as it chooses to.!
+resetContents
+	self subclassResponsibility
+! !
 
-!Queue methodsFor: 'accessing'!
+!ProtoStream methodsFor: 'enumerating'!
 
-next
-	^ self nextIfAbsent: [ self error: 'Cannot read from empty Queue.' ]
-!
+do: aBlock
+	[ self atEnd ] whileFalse: [ aBlock value: self next ]
+! !
 
-nextIfAbsent: aBlock
-	| result |
-	result := read at: readIndex ifAbsent: [
-		write isEmpty ifTrue: [
-			readIndex > 1 ifTrue: [ read := #(). readIndex := 1 ].
-			^ aBlock value ].
-		read := write.
-		readIndex := 1.
-		write := OrderedCollection new.
-		read first ].
-	read at: readIndex put: nil.
-	readIndex := readIndex + 1.
-	^ result
+!ProtoStream methodsFor: 'positioning'!
+
+setToEnd
+	self subclassResponsibility
 !
 
-nextPut: anObject
-	write add: anObject
+setToStart
+	self reset
 ! !
 
-!Queue methodsFor: 'initialization'!
+!ProtoStream methodsFor: 'reading'!
 
-initialize
-	super initialize.
-	read := OrderedCollection new.
-	write := OrderedCollection new.
-	readIndex := 1
+next
+	^ self atEnd
+		ifTrue: [ nil ]
+		ifFalse: [ self subclassResponsibility ]
+!
+
+peek
+	^ self atEnd
+		ifTrue: [ nil ]
+		ifFalse: [ self subclassResponsibility ]
 ! !
 
-Object subclass: #RegularExpression
-	instanceVariableNames: ''
-	package: 'Kernel-Collections'!
-!RegularExpression commentStamp!
-I represent a regular expression object. My instances are JavaScript `RegExp` object.!
+!ProtoStream methodsFor: 'testing'!
 
-!RegularExpression methodsFor: 'evaluating'!
-
-compile: aString
-	<return self.compile(aString)>
+atEnd
+	self subclassResponsibility
 !
 
-exec: aString
-	<return self.exec(aString) || nil>
+atStart
+	self subclassResponsibility
 !
 
-test: aString
-	<return self.test(aString)>
+isEmpty
+	^ self atStart and: [ self atEnd ]
 ! !
 
-!RegularExpression class methodsFor: 'instance creation'!
+!ProtoStream methodsFor: 'writing'!
 
-fromString: aString
-		^ self fromString: aString flag: ''
+<< anObject
+	self write: anObject
 !
 
-fromString: aString flag: anotherString
-	<return new RegExp(aString, anotherString)>
+nextPut: anObject
+	self subclassResponsibility
+!
+
+nextPutAll: aCollection
+	aCollection do: [ :each |
+		self nextPut: each ]
+!
+
+nextPutString: aString
+	self nextPut: aString
+!
+
+write: anObject
+	anObject putOn: self
+! !
+
+!ProtoStream class methodsFor: 'instance creation'!
+
+on: aCollection
+		^ self new
+		setCollection: aCollection;
+		setStreamSize: aCollection size;
+		yourself
 ! !
 
-Object subclass: #Stream
+ProtoStream subclass: #Stream
 	instanceVariableNames: 'collection position streamSize'
 	package: 'Kernel-Collections'!
 !Stream commentStamp!
@@ -2182,12 +2196,6 @@ resetContents
 	self setStreamSize: 0
 ! !
 
-!Stream methodsFor: 'enumerating'!
-
-do: aBlock
-	[ self atEnd ] whileFalse: [ aBlock value: self next ]
-! !
-
 !Stream methodsFor: 'positioning'!
 
 setToEnd
@@ -2238,27 +2246,10 @@ isEmpty
 
 !Stream methodsFor: 'writing'!
 
-<< anObject
-	self write: anObject
-!
-
 nextPut: anObject
 	self position: self position + 1.
 	self collection at: self position put: anObject.
 	self setStreamSize: (self streamSize max: self position)
-!
-
-nextPutAll: aCollection
-	aCollection do: [ :each |
-		self nextPut: each ]
-!
-
-nextPutString: aString
-	self nextPut: aString
-!
-
-write: anObject
-	anObject putOn: self
 ! !
 
 !Stream class methodsFor: 'instance creation'!
@@ -2328,3 +2319,88 @@ tab
 	^ self nextPutAll: String tab
 ! !
 
+Object subclass: #Queue
+	instanceVariableNames: 'read readIndex write'
+	package: 'Kernel-Collections'!
+!Queue commentStamp!
+I am a one-sided queue.
+
+## Usage
+
+Use `#nextPut:` to add items to the queue.
+Use `#next` or `#nextIfAbsent:` to get (and remove) the next item in the queue.
+
+## Implementation notes
+
+A Queue uses two OrderedCollections inside,
+`read` is at the front, is not modified and only read using `readIndex`.
+`write` is at the back and is appended new items.
+When `read` is exhausted, `write` is promoted to `read` and new `write` is created.
+
+As a consequence, no data moving is done by me, write appending may do data moving
+when growing `write`, but this is left to engine to implement as good as it chooses to.!
+
+!Queue methodsFor: 'accessing'!
+
+next
+	^ self nextIfAbsent: [ self error: 'Cannot read from empty Queue.' ]
+!
+
+nextIfAbsent: aBlock
+	| result |
+	result := read at: readIndex ifAbsent: [
+		write isEmpty ifTrue: [
+			readIndex > 1 ifTrue: [ read := #(). readIndex := 1 ].
+			^ aBlock value ].
+		read := write.
+		readIndex := 1.
+		write := OrderedCollection new.
+		read first ].
+	read at: readIndex put: nil.
+	readIndex := readIndex + 1.
+	^ result
+!
+
+nextPut: anObject
+	write add: anObject
+! !
+
+!Queue methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	read := OrderedCollection new.
+	write := OrderedCollection new.
+	readIndex := 1
+! !
+
+Object subclass: #RegularExpression
+	instanceVariableNames: ''
+	package: 'Kernel-Collections'!
+!RegularExpression commentStamp!
+I represent a regular expression object. My instances are JavaScript `RegExp` object.!
+
+!RegularExpression methodsFor: 'evaluating'!
+
+compile: aString
+	<return self.compile(aString)>
+!
+
+exec: aString
+	<return self.exec(aString) || nil>
+!
+
+test: aString
+	<return self.test(aString)>
+! !
+
+!RegularExpression class methodsFor: 'instance creation'!
+
+fromString: aString
+		^ self fromString: aString flag: ''
+!
+
+fromString: aString flag: anotherString
+	<return new RegExp(aString, anotherString)>
+! !
+