Smalltalk current createPackage: 'Kernel-Collections' properties: #{}! Object subclass: #Collection instanceVariableNames: '' category: 'Kernel-Collections'! !Collection methodsFor: 'accessing'! size self subclassResponsibility ! readStream ^self stream ! writeStream ^self stream ! stream ^self streamClass on: self ! streamClass ^self class streamClass ! ! !Collection methodsFor: 'adding/removing'! add: anObject self subclassResponsibility ! addAll: aCollection aCollection do: [:each | self add: each]. ^aCollection ! remove: anObject ^self remove: anObject ifAbsent: [self errorNotFound] ! remove: anObject ifAbsent: aBlock self subclassResponsibility ! ! !Collection methodsFor: 'converting'! asArray | array index | array := Array new. index := 0. self do: [:each | index := index + 1. array at: index put: each]. ^array ! asSet ^Set withAll: self ! ! !Collection methodsFor: 'copying'! , aCollection ^self copy addAll: aCollection; yourself ! copyWith: anObject ^self copy add: anObject; yourself ! copyWithAll: aCollection ^self copy addAll: aCollection; yourself ! copyWithoutAll: aCollection "Answer a copy of the receiver that does not contain any elements equal to those in aCollection." ^ self reject: [:each | aCollection includes: each] ! ! !Collection methodsFor: 'enumerating'! do: aBlock ! collect: aBlock | newCollection | newCollection := self class new. self do: [:each | newCollection add: (aBlock value: each)]. ^newCollection ! detect: aBlock ^self detect: aBlock ifNone: [self errorNotFound] ! detect: aBlock ifNone: anotherBlock < for(var i = 0; i < self.length; i++) if(aBlock(self[i])) return self[i]; return anotherBlock(); > ! do: aBlock separatedBy: anotherBlock | first | first := true. self do: [:each | first ifTrue: [first := false] ifFalse: [anotherBlock value]. aBlock value: each] ! inject: anObject into: aBlock | result | result := anObject. self do: [:each | result := aBlock value: result value: each]. ^result ! reject: aBlock ^self select: [:each | (aBlock value: each) = false] ! select: aBlock | stream | stream := self class new writeStream. self do: [:each | (aBlock value: each) ifTrue: [ stream nextPut: each]]. ^stream contents ! ! !Collection methodsFor: 'error handling'! errorNotFound self error: 'Object is not in the collection' ! ! !Collection methodsFor: 'testing'! includes: anObject < var i = self.length; while (i--) { if (smalltalk.send(self[i], "__eq", [anObject])) {return true;} } return false > ! notEmpty ^self isEmpty not ! isEmpty ^self size = 0 ! ifNotEmpty: aBlock self notEmpty ifTrue: aBlock. ! ifEmpty: aBlock self isEmpty ifTrue: aBlock. ! ! !Collection class methodsFor: 'accessing'! streamClass ^Stream ! ! !Collection class methodsFor: 'instance creation'! with: anObject ^self new add: anObject; yourself ! with: anObject with: anotherObject ^self new add: anObject; add: anotherObject; yourself ! with: firstObject with: secondObject with: thirdObject ^self new add: firstObject; add: secondObject; add: thirdObject; yourself ! withAll: aCollection ^self new addAll: aCollection; yourself ! ! Collection subclass: #SequenceableCollection instanceVariableNames: '' category: 'Kernel-Collections'! !SequenceableCollection methodsFor: 'accessing'! at: anIndex ^self at: anIndex ifAbsent: [ self errorNotFound] ! at: anIndex ifAbsent: aBlock self subclassResponsibility ! at: anIndex put: anObject self subclassResponsibility ! first ^self at: 1 ! fourth ^self at: 4 ! last ^self at: self size ! second ^self at: 2 ! third ^self at: 3 ! allButFirst ^self copyFrom: 2 to: self size ! allButLast ^self copyFrom: 1 to: self size - 1 ! indexOf: anObject ^self indexOf: anObject ifAbsent: [self errorNotFound] ! indexOf: anObject ifAbsent: aBlock < for(var i=0;i ! indexOf: anObject startingAt: start ifAbsent: aBlock < for(var i=start-1;i ! indexOf: anObject startingAt: start "Answer the index of the first occurence of anElement after start within the receiver. If the receiver does not contain anElement, answer 0." ^self indexOf: anObject startingAt: start ifAbsent: [0] ! atRandom ^ self at: self size atRandom ! ! !SequenceableCollection methodsFor: 'adding'! removeLast self remove: self last ! addLast: anObject self add: anObject ! ! !SequenceableCollection methodsFor: 'converting'! reversed self subclassResponsibility ! ! !SequenceableCollection methodsFor: 'copying'! copyFrom: anIndex to: anotherIndex self subclassResponsibility ! ! !SequenceableCollection methodsFor: 'enumerating'! withIndexDo: aBlock ! ! SequenceableCollection subclass: #String instanceVariableNames: '' category: 'Kernel-Collections'! !String methodsFor: 'accessing'! size ! at: anIndex ! at: anIndex put: anObject self errorReadOnly ! at: anIndex ifAbsent: aBlock (self at: anIndex) ifNil: [aBlock] ! escaped ! unescaped ! asciiValue ! ! !String methodsFor: 'adding'! add: anObject self errorReadOnly ! remove: anObject self errorReadOnly ! ! !String methodsFor: 'comparing'! = aString aString class = self class ifFalse: [^false]. ! > aString > aString> ! < aString ! >= aString >= aString> ! <= aString ! == aString aString class = self class ifFalse: [^false]. ! ! !String methodsFor: 'converting'! asSelector "If you change this method, change smalltalk.convertSelector too (see js/boot.js file)" | selector | selector := '_', self. selector := selector replace: ':' with: '_'. selector := selector replace: '[+]' with: '_plus'. selector := selector replace: '-' with: '_minus'. selector := selector replace: '[*]' with: '_star'. selector := selector replace: '[/]' with: '_slash'. selector := selector replace: '>' with: '_gt'. selector := selector replace: '<' with: '_lt'. selector := selector replace: '=' with: '_eq'. selector := selector replace: ',' with: '_comma'. selector := selector replace: '[@]' with: '_at'. ^selector ! asJavascript < if(self.search(/^[a-zA-Z0-9_:.$ ]*$/) == -1) return "unescape(\"" + escape(self) + "\")"; else return "\"" + self + "\""; > ! tokenize: aString ! asString ^self ! asNumber ! asLowercase ! asUppercase ! reversed ! asJavaScriptSelector ^(self asSelector replace: '^_' with: '') replace: '_.*' with: ''. ! ! !String methodsFor: 'copying'! , aString ! copyFrom: anIndex to: anotherIndex ! shallowCopy ^self class fromString: self ! deepCopy ^self shallowCopy ! ! !String methodsFor: 'error handling'! errorReadOnly self error: 'Object is read-only' ! ! !String methodsFor: 'printing'! printString ^'''', self, '''' ! printNl ! ! !String methodsFor: 'regular expressions'! replace: aString with: anotherString ^self replaceRegexp: (RegularExpression fromString: aString flag: 'g') with: anotherString ! replaceRegexp: aRegexp with: aString ! match: aRegexp ! trimLeft: separators ^self replaceRegexp: (RegularExpression fromString: '^[', separators, ']+' flag: 'g') with: '' ! trimRight: separators ^self replaceRegexp: (RegularExpression fromString: '[', separators, ']+$' flag: 'g') with: '' ! trimLeft ^self trimLeft: '\s' ! trimRight ^self trimRight: '\s' ! trimBoth ^self trimBoth: '\s' ! trimBoth: separators ^(self trimLeft: separators) trimRight: separators ! ! !String methodsFor: 'split join'! join: aCollection ^ String streamContents: [:stream | aCollection do: [:each | stream nextPutAll: each asString] separatedBy: [stream nextPutAll: self]] ! lineIndicesDo: aBlock "execute aBlock with 3 arguments for each line: - start index of line - end index of line without line delimiter - end index of line including line delimiter(s) CR, LF or CRLF" | cr lf start sz nextLF nextCR | start := 1. sz := self size. cr := String cr. nextCR := self indexOf: cr startingAt: 1. lf := String lf. nextLF := self indexOf: lf startingAt: 1. [ start <= sz ] whileTrue: [ (nextLF = 0 and: [ nextCR = 0 ]) ifTrue: [ "No more CR, nor LF, the string is over" aBlock value: start value: sz value: sz. ^self ]. (nextCR = 0 or: [ 0 < nextLF and: [ nextLF < nextCR ] ]) ifTrue: [ "Found a LF" aBlock value: start value: nextLF - 1 value: nextLF. start := 1 + nextLF. nextLF := self indexOf: lf startingAt: start ] ifFalse: [ 1 + nextCR = nextLF ifTrue: [ "Found a CR-LF pair" aBlock value: start value: nextCR - 1 value: nextLF. start := 1 + nextLF. nextCR := self indexOf: cr startingAt: start. nextLF := self indexOf: lf startingAt: start ] ifFalse: [ "Found a CR" aBlock value: start value: nextCR - 1 value: nextCR. start := 1 + nextCR. nextCR := self indexOf: cr startingAt: start ]]] ! linesDo: aBlock "Execute aBlock with each line in this string. The terminating line delimiters CR, LF or CRLF pairs are not included in what is passed to aBlock" self lineIndicesDo: [:start :endWithoutDelimiters :end | aBlock value: (self copyFrom: start to: endWithoutDelimiters)] ! lines "Answer an array of lines composing this receiver without the line ending delimiters." | lines | lines := Array new. self linesDo: [:aLine | lines add: aLine]. ^lines ! lineNumber: anIndex "Answer a string containing the characters in the given line number." | lineCount | lineCount := 0. self lineIndicesDo: [:start :endWithoutDelimiters :end | (lineCount := lineCount + 1) = anIndex ifTrue: [^self copyFrom: start to: endWithoutDelimiters]]. ^nil ! ! !String methodsFor: 'testing'! isString ^true ! includesSubString: subString < return self.indexOf(subString) !!= -1 > ! ! !String class methodsFor: 'accessing'! streamClass ^StringStream ! cr ! lf ! space ! tab ! crlf ! ! !String class methodsFor: 'instance creation'! fromString: aString ! streamContents: blockWithArg |stream| stream := (self streamClass on: String new). blockWithArg value: stream. ^ stream contents ! value: aUTFCharCode ! ! SequenceableCollection subclass: #Array instanceVariableNames: '' category: 'Kernel-Collections'! !Array methodsFor: 'accessing'! size ! at: anIndex put: anObject ! at: anIndex ifAbsent: aBlock < var value = self[anIndex - 1]; if(value === undefined) { return aBlock(); } else { return value; } > ! ! !Array methodsFor: 'adding/removing'! add: anObject ! remove: anObject < for(var i=0;i ! removeFrom: aNumber to: anotherNumber ! ! !Array methodsFor: 'comparing'! = aCollection (self class = aCollection class and: [ self size = aCollection size]) ifFalse: [^false]. self withIndexDo: [:each :i | (aCollection at: i) = each ifFalse: [^false]]. ^true ! ! !Array methodsFor: 'converting'! asJavascript ^'[', ((self collect: [:each | each asJavascript]) join: ', '), ']' ! reversed ! ! !Array methodsFor: 'copying'! shallowCopy | newCollection | newCollection := self class new. self do: [:each | newCollection add: each]. ^newCollection ! deepCopy | newCollection | newCollection := self class new. self do: [:each | newCollection add: each deepCopy]. ^newCollection ! copyFrom: anIndex to: anotherIndex | array | array := self class new. anIndex to: anotherIndex do: [:each | array add: (self at: each)]. ^array ! ! !Array methodsFor: 'enumerating'! join: aString ! sort ^self basicPerform: 'sort' ! sort: aBlock < return self.sort(function(a, b) { if(aBlock(a,b)) {return -1} else {return 1} }) > ! sorted ^self copy sort ! sorted: aBlock ^self copy sort: aBlock ! printString | str | str := '' writeStream. str nextPutAll: super printString, ' ('. self do: [:each | str nextPutAll: each printString] separatedBy: [str nextPutAll: ' ']. str nextPutAll: ')'. ^str contents ! ! Object subclass: #RegularExpression instanceVariableNames: '' category: 'Kernel-Collections'! !RegularExpression methodsFor: 'evaluating'! compile: aString ! exec: aString ! test: aString ! ! !RegularExpression class methodsFor: 'instance creation'! fromString: aString flag: anotherString ! fromString: aString ^self fromString: aString flag: '' ! ! 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 ! ! Collection subclass: #Dictionary instanceVariableNames: '' category: 'Kernel-Collections'! !Dictionary methodsFor: 'accessing'! size ^self keys size ! associations | associations | associations := #(). self keys do: [:each | associations add: (Association key: each value: (self at: each))]. ^associations ! keys < var keys = []; for(var i in self) { if(self.hasOwnProperty(i)) { keys.push(i); } }; return keys; > ! values ^self keys collect: [:each | self at: each] ! at: aKey put: aValue ^self basicAt: aKey put: aValue ! at: aKey ifAbsent: aBlock ^(self includesKey: aKey) ifTrue: [self basicAt: aKey] ifFalse: aBlock ! at: aKey ifAbsentPut: aBlock ^self at: aKey ifAbsent: [ self at: aKey put: aBlock value] ! at: aKey ifPresent: aBlock ^(self basicAt: aKey) ifNotNil: [aBlock value: (self at: aKey)] ! at: aKey ifPresent: aBlock ifAbsent: anotherBlock ^(self basicAt: aKey) ifNil: anotherBlock ifNotNil: [aBlock value: (self at: aKey)] ! at: aKey ^self at: aKey ifAbsent: [self errorNotFound] ! ! !Dictionary methodsFor: 'adding/removing'! add: anAssociation self at: anAssociation key put: anAssociation value ! addAll: aDictionary super addAll: aDictionary associations. ^aDictionary ! removeKey: aKey self remove: aKey ! remove: aKey ifAbsent: aBlock ^self removeKey: aKey ifAbsent: aBlock ! removeKey: aKey ifAbsent: aBlock ^(self includesKey: aKey) ifFalse: [aBlock value] ifTrue: [self basicDelete: aKey] ! ! !Dictionary methodsFor: 'comparing'! = aDictionary self class = aDictionary class ifFalse: [^false]. self size = aDictionary size ifFalse: [^false]. ^self associations = aDictionary associations ! ! !Dictionary methodsFor: 'copying'! shallowCopy | copy | copy := self class new. self associationsDo: [:each | copy at: each key put: each value]. ^copy ! , aCollection self shouldNotImplement ! copyFrom: anIndex to: anotherIndex self shouldNotImplement ! deepCopy | copy | copy := self class new. self associationsDo: [:each | copy at: each key put: each value deepCopy]. ^copy ! ! !Dictionary methodsFor: 'enumerating'! associationsDo: aBlock self associations do: aBlock ! keysAndValuesDo: aBlock self associationsDo: [:each | aBlock value: each key value: each value] ! do: aBlock self values do: aBlock ! select: aBlock | newDict | newDict := self class new. self keysAndValuesDo: [:key :value | (aBlock value: value) ifTrue: [newDict at: key put: value]]. ^newDict ! collect: aBlock | newDict | newDict := self class new. self keysAndValuesDo: [:key :value | newDict at: key put: (aBlock value: value)]. ^newDict ! detect: aBlock ifNone: anotherBlock ^self values detect: aBlock ifNone: anotherBlock ! includes: anObject ^self values includes: anObject ! ! !Dictionary methodsFor: 'printing'! printString ^String streamContents: [:aStream| aStream nextPutAll: super printString; nextPutAll: '('. self associations do: [:anAssociation| aStream nextPutAll: anAssociation key printString; nextPutAll: ' -> '; nextPutAll: anAssociation value printString] separatedBy: [aStream nextPutAll: ' , ']. aStream nextPutAll: ')'] ! storeOn: aStream aStream nextPutAll: '#{'. self associations do: [:each | each storeOn: aStream] separatedBy: [ aStream nextPutAll: '. ']. aStream nextPutAll: '}' ! ! !Dictionary methodsFor: 'testing'! includesKey: aKey ! ! !Dictionary class methodsFor: 'instance creation'! fromPairs: aCollection | dict | dict := self new. aCollection do: [:each | dict add: each]. ^dict ! ! Object subclass: #Stream instanceVariableNames: 'collection position streamSize' category: 'Kernel-Collections'! !Stream methodsFor: 'accessing'! collection ^collection ! setCollection: aCollection collection := aCollection ! position ^position ifNil: [position := 0] ! position: anInteger position := anInteger ! streamSize ^streamSize ! setStreamSize: anInteger streamSize := anInteger ! contents ^self collection copyFrom: 1 to: self streamSize ! size ^self streamSize ! ! !Stream methodsFor: 'actions'! reset self position: 0 ! close ! flush ! resetContents self reset. self setStreamSize: 0 ! ! !Stream methodsFor: 'enumerating'! do: aBlock [self atEnd] whileFalse: [aBlock value: self next] ! ! !Stream methodsFor: 'positioning'! setToEnd self position: self size ! skip: anInteger self position: ((self position + anInteger) min: self size max: 0) ! ! !Stream methodsFor: 'reading'! next self position: self position + 1. ^collection at: self position ! next: anInteger | tempCollection | tempCollection := self collection class new. anInteger timesRepeat: [ self atEnd ifFalse: [ tempCollection add: self next]]. ^tempCollection ! peek ^self atEnd ifFalse: [ self collection at: self position + 1] ! ! !Stream methodsFor: 'testing'! atEnd ^self position = self size ! atStart ^self position = 0 ! isEmpty ^self size = 0 ! ! !Stream methodsFor: 'writing'! 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] ! ! !Stream class methodsFor: 'instance creation'! on: aCollection ^self new setCollection: aCollection; setStreamSize: aCollection size; yourself ! ! Stream subclass: #StringStream instanceVariableNames: '' category: 'Kernel-Collections'! !StringStream methodsFor: 'reading'! next: anInteger | tempCollection | tempCollection := self collection class new. anInteger timesRepeat: [ self atEnd ifFalse: [ tempCollection := tempCollection, self next]]. ^tempCollection ! ! !StringStream methodsFor: 'writing'! nextPut: aString self nextPutAll: aString ! nextPutAll: aString self setCollection: (self collection copyFrom: 1 to: self position), aString, (self collection copyFrom: (self position + 1 + aString size) to: self collection size). self position: self position + aString size. self setStreamSize: (self streamSize max: self position) ! cr ^self nextPutAll: String cr ! crlf ^self nextPutAll: String crlf ! lf ^self nextPutAll: String lf ! space self nextPut: ' ' ! ! Collection subclass: #Set instanceVariableNames: 'elements' category: 'Kernel-Collections'! !Set methodsFor: 'accessing'! size ^elements size ! ! !Set methodsFor: 'adding/removing'! add: anObject < var found; for(var i in self['@elements']) { if(anObject == self['@elements'][i]) { found = true; break; } } if(!!found) {self['@elements'].push(anObject)} > ! remove: anObject elements remove: anObject ! ! !Set methodsFor: 'comparing'! = aCollection ^self class = aCollection class and: [ elements = aCollection asArray] ! ! !Set methodsFor: 'converting'! asArray ^elements copy ! ! !Set methodsFor: 'enumerating'! detect: aBlock ifNone: anotherBlock ^elements detect: aBlock ifNone: anotherBlock ! do: aBlock elements do: aBlock ! ! !Set methodsFor: 'initialization'! initialize super initialize. elements := #() ! ! !Set methodsFor: 'testing'! includes: anObject ^elements includes: anObject ! !