export Str(*), StrConcatIter(*), count-digits, int-iter, uint-iter, * use Cnile use Iter Iter(*), IntoIter(*) head, zip, all, for-each, drop, count, to Drop, Take, TakeWhile, AppendIter drop-while', drop' use Mem (TypeSize) use Char (is-whitespace) use Math use Misc (fst, snd) use Prim Str(*), StrConcatIter count-digits, int-iter, uint-iter ############# Str instances ################ ####### ASCII ###### inst Str Cnile.AsciiChar print-str (self _) Cnile.printf1('%c', self) chars (self _): Iter.single(self Char.ascii-char()) ##### ConstStr ###### ConstStrIter ogstr ConstStr i Size inst IntoIter ConstStr into-iter (self): ConstStrIter { ogstr: self, i: 0 } inst IntoIter ConstStrIter into-iter (self): self inst Iter ConstStrIter next (self) char-ptr = Mem.cast(self&.ogstr) as Ptr U8 optr = (char-ptr Mem.offset-ptr(Mem.size-i64(self&.i))) if optr& == Mem.cast(0) # later this will be good, when the default string will also have a length. return None char = optr Char.scan-from-mem() self <&.i= self&.i + char.num-bytes return Just(char) inst Str ConstStr print-str (self _) -> Unit Cnile.printf1('%s', self) chars (self _) -> ConstStrIter: self into-iter() inst Indexable ConstStr elem-get (self _, sz Size) -> Char return Mem.offset-ptr(self Mem.cast() as Ptr Char, sz Mem.size-i64())& # DEFAULT INSTANCE FUNCTION (uses Char's print-str) fn default-print-str (s Str): s chars() for-each(print-str) ####### Int ####### inst Str U32 print-str (self U32) -> Unit Cnile.printf1('%u', self) chars (self U32): uint-iter(self) inst Str U8 print-str (self U8) -> Unit Cnile.printf1('%d', Mem.u8-i32(self)) chars (self U8): uint-iter(self) inst Str I64 print-str (self I64) -> Unit Cnile.printf1('%ld', self) chars (self I64): int-iter(self) ####### Others, non-polymorphic ####### inst Str Bool print-str (self Bool) -> Unit if self print-str('True') else print-str('False') chars (self) if self return 'True' chars() else return 'False' chars() inst Str Unit print-str (self Unit) -> Unit print-str('()') chars (self): '()' chars() inst Str Ordering print-str (self) case self LT print-str('LT') EQ print-str('EQ') GT print-str('GT') chars (self) case self LT return 'LT' chars() EQ return 'EQ' chars() GT return 'GT' chars() ####### StrCase ####### StrCaseIter c1 c2 StrCaseIter1 c1 StrCaseIter2 c2 inst IntoIter StrCaseIter into-iter(self): self inst Iter StrCaseIter next(self) case self Ptr(StrCaseIter1(c)) return next(&c) Ptr(StrCaseIter2(c)) return next(&c) # before it was this, but it acted differently on different backends. # TODO: I SHOULD CODIFY THESE SEMANTICS FINALLY # case self& # StrCaseIter1(c) # return next(&c) # StrCaseIter2(c) # return next(&c) inst IntoIter StrCase into-iter (self) case self StrCase1(c1) return StrCaseIter1(c1 chars()) StrCase2(c2) return StrCaseIter2(c2 chars()) inst Str StrCase print-str (self) case self StrCase1(c) c print-str() StrCase2(c) c print-str() chars (self): self into-iter() inst Str Ptr print-str (self _) _ = print-str(self&) chars (self): self& chars() inst Str Maybe print-str (self _) case self None print-str('None') Just(x) print-str('Just(\(x))') chars (self) c = @undefined case self None c <= 'None' StrCase1() Just(x) c <= 'Just(\(x))' StrCase2() return c chars() inst Str Tuple2 print-str (tup) case tup Tuple2(l, r) print-str('(\(l), \(r))') chars ((l, r)): '(\(l), \(r))' chars() inst Str Tuple3 print-str (tup) case tup Tuple3(a, b, c) print-str('(\(a), \(b), \(c))') inst Str Tuple4 print-str (tup) case tup Tuple4(a, b, c, d) print-str('(\(a), \(b), \(c), \(d))') inst Str U32 print-str (self U32) -> Unit Cnile.printf1('%u', self) chars (self U32): uint-iter(self) inst Str U8 print-str (self U8) -> Unit Cnile.printf1('%d', Mem.u8-i32(self)) chars (self U8): uint-iter(self) inst Str I64 print-str (self I64) -> Unit Cnile.printf1('%ld', self) chars (self I64): int-iter(self) inst Str U64 print-str (self _) -> Unit Cnile.printf1('%lu', self) chars (self _): uint-iter(self) ### StrSepBy WhichStrSepIter StrSepElem StrSepSep StrSepByIter se si sepe sepi cur-elem-it Maybe se elem-it si cur-sep-it sepe sep-it sepi which-iter WhichStrSepIter inst Iter StrSepByIter next (self Ptr _) -> Maybe Char while True case self&.which-iter StrSepSep case self&.cur-elem-it None return None Just(_) pass case next(&self&.cur-sep-it) Just(se) return Just(se) None self <&.cur-sep-it= self&.sep-it chars() self <&.which-iter= StrSepElem StrSepElem case &self&.cur-elem-it Ptr(None) return None Ptr(Just(elem-it)) case next(&elem-it) Just(se) return Just(se) None self <&.cur-elem-it= next(&self&.elem-it) Misc.fmap-maybe(chars) self <&.which-iter= StrSepSep inst IntoIter StrSepByIter into-iter (self _): self StrSepBy s sep s s sep sep inst Str StrSepBy print-str (self _) @panic('StrSepBy: print-str') chars (self StrSepBy s sep) <= IntoIter s, Str sep elem-it = self.s into-iter() cur-elem-it = next(&elem-it) Misc.fmap-maybe(chars) sep-it = self.sep cur-sep-it = sep-it chars() return StrSepByIter { elem-it, cur-elem-it, sep-it, cur-sep-it, which-iter: StrSepElem } # should be something like 'join'? fn sep-by (s, sep): StrSepBy { s, sep } ### PadZeroes PadZeroes x I32 len U8 inst IntoIter PadZeroes into-iter(self): self inst Iter PadZeroes next (self Ptr _) -> Maybe Char if self&.len <= 0 return None trim-down = 10 Math.pow (self&.len Mem.u8-i32() - 1) upper = self&.x / trim-down upper-mask = (upper / 10) * 10 digit = Mem.i32-u8(upper - upper-mask) self <&.len= self&.len - 1 digit-char = Char.from-u8(digit + 48) return Just(digit-char) inst Str PadZeroes print-str (pz) @panic('todo') chars (self PadZeroes): self fn pad-zeroes(x I32, num-zeroes U8, trim-larger Bool): PadZeroes { x, len: if not trim-larger: num-zeroes else Math.max(num-zeroes, x count-digits() Mem.i32-u8()) } ##### Iterators (rn I've decided that treating strings as iterators should *just work* for strings(TM)) (this MIGHT CHANGE IN THE FUTURE) inst Str Take print-str (self) self for-each(print-str) chars (self): self inst Str Drop # this is barely typed. Assumes Item = Char print-str (self) self for-each(print-str) chars (self): self inst Str TakeWhile print-str (self) self for-each(print-str) chars (self): self inst Str AppendIter print-str (self): self for-each(print-str) chars (self): self ###### Functions ###### fn eq(l, r) l =& l chars() r =& r chars() while True mlc = l next() mrc = r next() case (mlc, mrc) (None, None) return True (Just(lc), Just(rc)) if lc /= rc return False _ return False fn streq(l, r): eq(l, r) fn print-as-list(it) print-str('[') case it head() None pass Just(x) print-str(x) it drop(1) for-each(fn x: ', \(x)' print-str()) print-str(']') fn list-chars (it) seps = it sep-by(', ') return '[\(seps)]' chars() fn const-str-len (s ConstStr): s chars() count() # SIKE. Im using iterators. fn is-blank (s): s chars() all(is-whitespace) fn parse-int(s) fn sequence-maybe (e, b) case b None return None Just(x) case Char.parse-digit(e) None return None Just(xe) return Just(x * 10 + Mem.i32-i64(xe)) cs = s chars() case cs head() Just(x) return cs Iter.reduce(Just(0), sequence-maybe) None return None fn begins-with (s Str, beg Str) -> Bool scs =& s chars() begcs =& beg chars() while True case (scs next(), begcs next()) ((Just(lc), Just(rc))) if lc /= rc return False ((None, Just(_))) return False _ return True fn ends-with (s Str, end Str) -> Bool scs =& s chars() while True cscs =& (scs& Misc.own()) endcs =& end chars() while True case (cscs next(), endcs next()) ((Just(lc), Just(rc))) if lc /= rc break ((None, Just(_))) return False ((None, None)) return True _ break next(scs) #### split by multiple at a time. SplitWhitespaceIter it a it it # TODO: in the future, add custom separator function. fun a -> Bool fn split-by(it, fun) it = it into-iter() it = it drop-while'(fun) return SplitWhitespaceIter { it, fun } fn split(it): split-by(it, is-whitespace) inst IntoIter SplitWhitespaceIter into-iter (self): self inst Iter SplitWhitespaceIter next (self Ptr (SplitWhitespaceIter it a)) <= Iter it, IntoIter it if self&.it Iter.null() return None itAndTaken = self&.it Iter.take-while'(fn x: not self&.fun(x)) case itAndTaken Tuple2(it, taken) self <&.it= it drop-while'(self&.fun) return Just(taken) #### split by each character (does not trim in the beginninig) SplitEachWhitespaceIter it a it it # TODO: in the future, add custom separator function. fun a -> Bool fn split-by-each(it, fun) it = it into-iter() return SplitWhitespaceIter { it, fun } inst IntoIter SplitEachWhitespaceIter into-iter (self): self inst Iter SplitEachWhitespaceIter next (self Ptr (SplitEachWhitespaceIter it a)) <= Iter it, IntoIter it if self&.it Iter.null() return None itAndTaken = self&.it Iter.take-while'(fn x: not self&.fun(x)) case itAndTaken Tuple2(it, taken) (&self&.it) drop'(1) return Just(taken) # F64 yooo FloatStrIter buf Array 32 Cnile.AsciiChar # seems to be max possible? i I32 inst IntoIter F64 into-iter (f _) buf =& @undefined as Array 32 Cnile.AsciiChar Cnile.snprintf1(buf Mem.cast-ptr(), 32, '%f', f) return FloatStrIter { buf: buf&, i: 0 } inst IntoIter F32 into-iter (f _) buf =& @undefined as Array 32 Cnile.AsciiChar Cnile.snprintf1(buf Mem.cast-ptr(), 32, '%f', @f32-f64(f)) return FloatStrIter { buf: buf&, i: 0 } inst IntoIter FloatStrIter into-iter (self): self inst Iter FloatStrIter next (self) -> Maybe Char buf = &self&.buf c = buf Array.get(self&.i Mem.i32-size()) if c == '\0' return None self <&.i= self&.i + 1 return c Char.ascii-char() Just() inst Str F64 print-str (self) Cnile.printf1('%f', self) chars (self): self into-iter() inst Str F32 print-str (self) Cnile.printf1('%f', @f32-f64(self)) chars (self): self into-iter() ###### Other Instances ##### inst Eq ConstStr eq (l, r): Cnile.strcmp(l, r) == 0 # NOTE(24.06.26): i'll leave it as a demonstration for what can happen when instances are left over (the arguments defaulted to ConstStr due to strcmp) # inst Eq StrView # eq (l, r): Cnile.strcmp(l, r) == 0