:class var cell bytes data :m !: ( n -- ) data ! ;m :m +: ( n -- ) data +! ;m :m @: ( -- n ) data @ ;m :m p: ( data ) data @ . ;m \ print self ;class :class bool 1 bytes bdata :m set: -1 bdata c! ;m :m clear: 0 bdata c! ;m :m @: ( -- flag ) bdata c@ 255 = ;m :m p: self @: . ;m ;class 0 [IF] SEQUENCE is a generic superclass for classes which have multiple items which frequently need to be looked at in sequence. At present the main function of Sequence is to implement the EACH: method, which makes it very simple to deal with each element. The usage is BEGIN each: WHILE (do something with the element) REPEAT Sequence can be a superclass for any class which implements the FIRST?: and NEXT?: methods. The actual implementation details are quite irrelevant, as long as these methods are supported. [THEN] makeSelect next?: makeSelect first?: :class sequence bool each_started? :m each: \ ( -- T | -- F ) each_started? c@ IF \ Subsequent time in: [self] next?: \ next?: is declared as a selector but there is no method yet IF true ELSE 0 each_started? c! false THEN ELSE \ First time in: [self] first?: \ first?: is declared as a selector but there is no method yet 0= IF 0 exit THEN -1 each_started? c! true \ Yes, we've got the 1st element THEN ;m :m uneach: \ Use to terminate an EACH: loop before the end. each_started? clear: ;m \ could have used 0 each_started? c! ;class :class dicPtr :class dicArray R + self resize: \ addr-src len self @ R> + ( addr-src len dest) SWAP MOVE ;m :m @: ( -- addr len ) self @ size @ ;m :m p: self @: TYPE ;m :m +: ( char -- ) \ add char to end of string size @ 1+ self resize: self @: + 1- c! ;m ;class true value case-sensitive? \ used for searches in string+ objects :class string+ IF 2drop false exit THEN case-sensitive? IF \ do case sensitive search { addr len } self @ end @ + ( start-addr) self rem: ( len) addr len search IF \ found ( u3 ) drop ( c-addr3 ) self @ - dup len + end ! start ! true ELSE false THEN ELSE \ do case insensitive search self CIsearch: THEN ;m :m chsearch: ( char -- flag ) theChar c! theChar 1 self search: ;m :m delete: \ deletes the substring defined by START and END \ leaves START at the same place, END is set to START end @ start @ - 1 < IF exit THEN self @ end @ + \ src self @ start @ + \ src dest self rem: \ src dest cnt move size @ end @ start @ - - self resize: start @ end ! ;m \ inserts text starting at END, START and END are moved to end of inserted text :m insert: { addr len -- } size @ len + self resize: self @ end @ + dup ( src src ) len + ( dest ) self rem: ( cnt ) MOVE addr ( src ) self @ end @ + ( dest ) len MOVE end @ len + dup start ! end ! ;m \ inserts char at END, START and END are moved to just past inserted char :m chinsert: ( c -- ) theChar c! theChar 1 self insert: ;m \ replace selected text, if any, with given text :m replace: ( addr len -- ) self delete: self insert: ;m \ Search for text1 starting at END. \ If found replace with text2. \ Success flag is returned. :m sch&repl: { addr1 len1 addr2 len2 -- flag } addr1 len1 self search: dup IF addr2 len2 self replace: THEN ;m \ Reset self and replaces all occurrences of (addr1 len1) by (addr2 len2) \ in the WHOLE of self. Self is lastly reset again. :m replall: { addr1 len1 addr2 len2 -- } self reset: BEGIN addr1 len1 self search: WHILE addr2 len2 self replace: REPEAT self reset: ;m :m d: \ formatted dump of string for debugging cr ." 1 2 3 4" cr ." 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0" cr self size: 80 min 0 ?DO space i self at: emit LOOP cr start @ 42 min 2* spaces [char] S emit cr end @ 42 min 2* spaces [char] E emit cr ." start= " start p: ." end= " end p: ." rem= " self rem: . ." size= " size p: ." case-sensitive?= " case-sensitive? . ;m :m skipBlanks: BEGIN end @ size @ <> end @ self at: 32 = and WHILE 1 end +! REPEAT end @ start ! ;m \ CIword: must only be called by word: :m CIword: { c -- flag } \ handle case insensitive c lowerCase? IF c 32 - to c THEN BEGIN end @ size @ 1- > IF true exit THEN end @ self at: dup lowerCase? IF 32 - THEN c = IF true exit THEN true WHILE 1 end +! REPEAT \ should never get here ;m \ Parse the string for text ending with char c. \ Leading blanks are skipped. \ Use @sub: to retrieve the substring if true is returned. \ Subsequent use of word: will automatically advance past \ the last "hit". :m word: { c -- flag } self skipBlanks: end @ size @ = IF false exit THEN case-sensitive? 0= IF c self CIword: exit THEN BEGIN end @ size @ 1- > IF true exit THEN end @ self at: c = IF true exit THEN true WHILE 1 end +! REPEAT \ should never get here ;m ;class \ a (restricted resizeable) string that is alloted in the dictionary \ although it could still be cast as a HEAP> object :class xstring 1 abort" xstring !: not enough room" addr ( src ) idxBase ( dest ) len MOVE len current ! ;m :m add: { addr len -- } current @ len + limit > abort" xstring add: not enough room" addr ( src ) idxBase current @ + ( dest ) len MOVE len current +! ;m :m +: ( char -- ) current @ 1+ limit > abort" xstring +: not enough room" idxBase current @ + c! 1 current +! ;m :m p: ( -- ) self @: TYPE ;m :m size: ( -- u ) current @ ;m ;class :class ordered-col r CELL+ r> cnt CELL * move ;m \ Finds a value in a collection. :m search: \ { val -- indx T | -- F } locals| val | self size: 0 ?DO i self at: val = IF i unloop true exit THEN LOOP false ;m :m map: { xt -- } \ apply xt to each element in the list BEGIN self each: WHILE xt execute REPEAT ;m ;class \ ordered-col+ is modeled after the Smalltalk implementation :class ordered-col+ WHILE idx 1- dup to idx ( idx ) self at: idx 1+ self to: REPEAT ( n ) 0 self to: \ place n at the begining 1 cursize +: ;m \ finally, increase current size by one :m removeFirst: ( -- ) 0 super delete: ;m :m set: ( cnt -- ) \ adds cnt items to collection \ example usage: 3 5 7 9 12 5 set: 0 ?DO self addFirst: LOOP ;m :m sum: ( -- sum ) 0 BEGIN self each: WHILE + REPEAT ;m :m max: ( -- max ) \ return maximum number in collection 0 locals| max | BEGIN self each: WHILE dup max > IF to max ELSE drop THEN REPEAT max ;m :m min: ( -- min ) \ return maximum number in collection self size: 2 < IF 1 < IF true ABORT" empty collection" THEN 0 self at: THEN 1 self at: locals| min | \ must start with something in min BEGIN self each: WHILE dup min < IF to min ELSE drop THEN REPEAT min ;m :m removeAll: ( n -- ) \ remove all occurances of n from the list locals| n | BEGIN n self search: WHILE super delete: REPEAT ;m :m occurrencesOf: ( n -- cnt ) \ number of times n is in collection 0 locals| cnt n | BEGIN self each: WHILE n = IF cnt 1+ to cnt THEN REPEAT cnt ;m :m conform: ( xt -- flag ) \ test if all elements meet condition locals| xt | BEGIN self each: WHILE xt execute ( flag ) 0= IF self uneach: false exit THEN REPEAT true ;m \ NOTE: for accept: reject: and collect: we return a new collection. The original \ collection is unchanged. This new collection returned \ will be nameless and dynamically allocated in the heap. Thus if you use one \ of these methods, the resulting collection must eventually get a