export Scalar, CharDestructured(*), MaxCharBuf destructure, unscalarize, regularize, printf-char, scan-from-mem next-char, char-from-u8 * # i'll explicitly import all used modules to quickly check for cycles. # this module should be imported by Str. use Mem (uninit-buf) use Cnile (FILE) use Prim destructure, unscalarize, regularize, printf-char, next-char, scan-from-mem, char-from-u8, between, assert Scalar, CharDestructured(Ref, Scalar), MaxCharBuf # assumes we are somewhere in the middle of a character. fn sync-char (p Ptr U8) -> Size # BACKWARDS movement! i = 0 while True pb = @offset-ptr(p, - Mem.size-i64(i))& # BTW the intrinsic itself is not really needed, I just left it here cuz why not. if not (pb >= 128 and pb < 128 + 64) return i i <= i + 1 # moves the character back from the previous correct character. fn previous-char (p Ptr U8) -> Size # BACKWARDS movement! return p Mem.offset-ptr(-1) sync-char() + 1 # (+1, because imagine: lands on a correct char. then sync-char() returns 0. so we must add 1) # it will fail for grapheme clusters. use only when you know what chars you're going to get. fn try-scalarize (c Char) -> Maybe Scalar @panic('(scalarize) todo') return None # bad. remove later. it's only for quick stuff. fn char-u8(c Char) -> U8 case c destructure() Ref(c) return c.ptr& Scalar(scalar) return Mem.u32-u8(scalar.value) inst Eq Scalar eq (l _, r _): l.value == r.value inst Eq Char eq (l Char, r Char) if l.num-bytes /= r.num-bytes return False # NOTE(05.06.26): this complex function slowed down Interpret types by 40ms for reminda GEEEEG lc = l regularize(&uninit-buf()) rc = r regularize(&uninit-buf()) # TODO(utf8): normalize?????? i = 0 while @cast(i) < lc.num-bytes if @offset-ptr(lc.ptr, i)& /= @offset-ptr(rc.ptr, i)& return False i <= i + 1 return True inst Ord Char cmp (l _, r _) if l.num-bytes /= 1 or r.num-bytes /= 1 @panic('(TODO) comparison of non-ascii characters not implemented') # I think it's specified in the unicode spec? return cmp(char-u8(l), char-u8(r)) #### fn nullchar() -> Char: '\0' #### fn as-u8-slice (c Char, buf Ptr MaxCharBuf) -> Slice U8 cc = c regularize(buf) return Slice { ptr: cc.ptr, count: cc.num-bytes } fn to-c-wchar (c Char) -> Cnile.WChar case c destructure() Ref(c) wcp =& Mem.zeroed() num-chars = Cnile.mbstowcs(wcp, c.ptr Mem.cast-ptr(), 1) if num-chars == (Mem.cast(-1 as I64) as Size) @panic('could NOT convert char to wchar_t :c') # maybe later return None if cannot convert. return wcp& Scalar(sc) if not sc.value Mem.size-of() == (Mem.get-typesize() as Mem.TypeSize Cnile.WChar).size @panic('Scalar size should be the same as Cnile.WChar') return sc.value Mem.cast() fn fprintf-char (file Ptr FILE, c Char) -> I32 c = c regularize(&@undefined) return Cnile.fprintf2(file, '%.*s', c.num-bytes Mem.size-i32(), c.ptr) #### # another name for scalarize() - maybe better? # (also, it should be in another module, which can use the Error module (so we can display which chars failed.)) # fn own (c Char) -> Char # case c try-scalarize() # Just(sc) # return sc # None # @panic('(Char.own) could not turn char into scalar.') fn from-u8 (b U8) -> Char: char-from-u8(b) # Should this even be here? It's related to the AsciiChar. fn ascii-u8(c Cnile.AsciiChar): @cast(c) as U8 fn u8-ascii(b U8): @cast(b) as Cnile.AsciiChar fn ascii-char(c Cnile.AsciiChar): c ascii-u8() from-u8() ####### # TEMP: consider utf8 characters as alpha fn is-alpha (c Char): c.num-bytes > 1 or c between('a', 'z') or c between ('A', 'Z') fn is-whitespace (c Char): c == ' ' or c == '\n' or c == '\t' fn is-not-whitespace (c): not is-whitespace(c) # TEMP: consider num-bytes in the comparison. fn is-digit (c Char): c.num-bytes == 1 and c between('0', '9') fn is-hex (c Char): c.num-bytes == 1 and (c is-digit() or c between('a', 'f') or c between('A', 'F')) fn is-binary (c Char): c.num-bytes == 1 and (c == '0' or c == '1') fn is-octal (c Char): c.num-bytes == 1 and c between('0', '7') fn is-alphanumeric(c Char): c is-alpha() or c is-digit() # TEMP: only for ascii for now. fn is-upper (c Char): c.num-bytes == 1 and c between('A', 'Z') fn is-lower (c Char): not c is-upper() fn char-case-diff (): 'a' char-u8() - 'A' char-u8() fn to-lower (c Char) if is-upper(c) assert(c.num-bytes == 1, '(to-lower) utf8 not yet supported.') return from-u8(c char-u8() + char-case-diff()) return c fn parse-digit (c) if is-digit(c) return Just(Mem.u8-i32(char-u8(c) - char-u8('0'))) else return None