use CharType char-type # for kc :) HighlightType Number String Comment Ident1 # lowercase Ident2 # uppercase Ident3 # for intrinsics (maybe classify as special?) Ident4 # members Keyword1 Keyword2 Special1 # more important symbols like '=', '<=', '<&=' (the last two may be parsed dynamically!), '&', '->' Special2 # more normal symbols like '==', '/=', etc Special3 # annotations???? Invalid # special? inst Eq HighlightType eq (l _, r _): (Mem.cast-on-zeroed(l) as U32) == (Mem.cast-on-zeroed(r)) Highlight type HighlightType from I32 to I32 # Highlighters fn kc (hls Ptr (List al Highlight), line-sv StrView) <= Allocator al sc =& Scan.mk-from-str(line-sv) while not sc null() from-off = sc&.byte-offset Mem.size-i32() first-char = sc Scan.peek() # comment if sc Scan.try-char('#') # optionally a tag! if sc Scan.try-char('[') sc Scan.skip-while(fn c: c /= ']') sc drop'(1) to-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: line-sv StrView.num-bytes() Mem.size-i32(), type: Special3 }) else hls List.add({ from: from-off, to: line-sv StrView.num-bytes() Mem.size-i32(), type: Comment }) break # string elif sc Scan.try-char('\'') while True sc Scan.skip-while(fn c: c /= '\'' and c /= '\\') if sc Scan.peek() == Just('\\') sc drop'(1) if sc Scan.peek() == Just('\'') sc drop'(1) else # todo for highlighting special sequences and interpolation pass else sc drop'(1) # drop the ending quote also break cur-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: cur-off, type: String }) # intrinsics elif sc Scan.try-char('@') if sc Scan.char-satisfies(is-alpha) sc Scan.skip-while(fn c: c char-type() == CharType.CharWord or c == '\'') cur-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: cur-off, type: Ident3 }) else # none for now. maybe later when single @ gets a meaning? pass # members (i dont like it, currently cant distinguish between `Module.member` and `struct.member`) # elif sc Scan.try-char('.') # if sc Scan.char-satisfies(is-alpha) # sc Scan.skip-while(fn c: c char-type() == CharType.CharWord) # cur-off = sc&.byte-offset Mem.size-i32() # hls List.add({ from: from-off, to: cur-off, type: Ident4 }) # else # # none for now. maybe later when single @ gets a meaning? # pass elif ['==', '/='] any(fn sym: sc Scan.matches-str(sym)) cur-off = sc&.byte-offset Mem.size-i32() type = Special2 hls List.add({ from: from-off, to: cur-off, type }) elif ['<&', '=' as StrView, '&', '->', ':', '(', ')', '{', '}', '[', ']', ','] any(fn sym: sc Scan.matches-str(sym)) cur-off = sc&.byte-offset Mem.size-i32() type = Special1 hls List.add({ from: from-off, to: cur-off, type }) # lowercase and uppercase identifier and word keywords elif sc Scan.char-satisfies(is-alpha) sc Scan.skip-while(fn c: c char-type() == CharType.CharWord or c == '\'') cur-off = sc&.byte-offset Mem.size-i32() first-char-uppercase = first-char Misc.maybe(is-upper, False) type = if first-char-uppercase: Ident2 else Ident1 ident = line-sv StrView.byte-substr(from-off Mem.i32-size(), cur-off Mem.i32-size()) as StrView # more important keywords keywords1 = # leave it here or put it in Highlight module? [ 'fn' , 'class' , 'inst' , 'external' , 'use' , 'export' , 'let' ] keywords2 = [ 'if' , 'elif' , 'else' , 'case' , 'for' , 'in' , 'while' , 'pass' , 'break' , 'continue' , 'as' , 'or' , 'and' , 'not' , 'return' ] if keywords1 any(fn kw: kw == ident) type <= Keyword1 elif keywords2 any(fn kw: kw == ident) type <= Keyword2 elif not first-char-uppercase and sc Scan.peek() == Just('(') # check if it's a function call? accept space or not? but then it depends if functions declarations have a space between em. type <= Ident4 hls List.add({ from: from-off, to: cur-off, type }) else case sc Scan.int() Just(i) cur-off = sc&.byte-offset Mem.size-i32() type = Number if i == 0 if sc Scan.try-char('x') sc Scan.skip-while(is-hex) cur-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: cur-off, type }) sc Scan.skip-while(is-alpha) invalid-off = sc&.byte-offset Mem.size-i32() if cur-off /= invalid-off hls List.add({ from: cur-off, to: invalid-off, type: Invalid }) elif sc Scan.try-char('o') sc Scan.skip-while(is-octal) cur-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: cur-off, type }) sc Scan.skip-while(is-digit) # skip the invalid numbers (or create an invalid highlight :O) invalid-off = sc&.byte-offset Mem.size-i32() if cur-off /= invalid-off hls List.add({ from: cur-off, to: invalid-off, type: Invalid }) elif sc Scan.try-char('b') sc Scan.skip-while(is-binary) cur-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: cur-off, type }) sc Scan.skip-while(is-digit) # skip the invalid numbers (or create an invalid highlight :O) invalid-off = sc&.byte-offset Mem.size-i32() if cur-off /= invalid-off hls List.add({ from: cur-off, to: invalid-off, type: Invalid }) else hls List.add({ from: from-off, to: cur-off, type }) else hls List.add({ from: from-off, to: cur-off, type }) None # if nothing matched at all, just drop the character. sc drop'(1) fn markdown (hls Ptr (List al Highlight), line-sv StrView) <= Allocator al sc =& Scan.mk-from-str(line-sv) if sc Scan.try-char('#') hls List.add({ from: 0, to: line-sv StrView.num-bytes() Mem.size-i32(), type: Keyword1 }) else sc Scan.skip-while(is-whitespace) from-off = sc&.byte-offset Mem.size-i32() if sc Scan.try-char('-') to-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: to-off, type: Special1 }) sc Scan.skip-while(is-whitespace) from-off = sc&.byte-offset Mem.size-i32() if sc Scan.matches-str('[ ]') to-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: to-off, type: Keyword1 }) elif sc Scan.matches-str('[x]') or sc Scan.matches-str('[X]') to-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: to-off, type: Keyword2 }) # todo more pass # TEMP: there's a compiler bug, which forbids me from defining it inside. fn gcode-keyword-char(c Char): c is-not-whitespace() and c /= ';' fn gcode (hls Ptr (List al Highlight), line-sv StrView) <= Allocator al sc =& Scan.mk-from-str(line-sv) sc Scan.skip-while(is-whitespace) # syntax: instr [arg...] ;? # the gcode-keyword-char function should be defined here, but it breaks in the monomorphiser # fn gcode-keyword-char(c Char): c is-not-whitespace() and c /= ';' first-from-off = sc&.byte-offset Mem.size-i32() if sc Scan.char-satisfies(is-alphanumeric) sc Scan.skip-while(gcode-keyword-char) first-to-off = sc&.byte-offset Mem.size-i32() type = Invalid first-char = line-sv StrView.char-at-offset(first-from-off Mem.i32-size()) Char.to-lower() if first-char == 'm' type <= Keyword1 elif first-char == 'g' type <= Ident1 hls List.add({ from: first-from-off, to: first-to-off, type }) sc Scan.skip-while(is-whitespace) from-off = sc&.byte-offset Mem.size-i32() while sc Scan.char-satisfies(is-alphanumeric) sc Scan.skip-while(gcode-keyword-char) to-off = sc&.byte-offset Mem.size-i32() sc Scan.skip-while(is-whitespace) hls List.add({ from: from-off, to: to-off, type: Ident4 }) # skip non-comment chars. while sc Scan.char-satisfies(fn c: c /= ';') pass from-off = sc&.byte-offset Mem.size-i32() if sc Scan.try-char(';') hls List.add({ from: from-off, to: line-sv StrView.num-bytes() Mem.size-i32(), type: Comment }) fn brainfuck (hls Ptr (List al Highlight), line-sv StrView) <= Allocator al sc =& Scan.mk-from-str(line-sv) sc Scan.skip-while(is-whitespace) bf-chars = [ ('[', Special1) , (']', Special1) , ('+', Special2) , ('-', Special2) , ('<', Special3) , ('>', Special3) , (',', Keyword1) , ('.', Keyword2) ] as Slice (Char, HighlightType) is-bf-char = fn c: bf-chars map(fst) any(fn eq: eq == c) while not sc null() while True from-off = sc&.byte-offset Mem.size-i32() case sc Scan.char-satisfies'(fn c: bf-chars map(fst) any(fn ec: ec == c)) Just(cc) hl = bf-chars filter(fn ((c, _)): c == cc) head() or-fail('could not find matched char (it should not happen)') snd() to-off = sc&.byte-offset Mem.size-i32() hls List.add({ from: from-off, to: to-off, type: hl }) None break from-off = sc&.byte-offset Mem.size-i32() sc Scan.skip-while(fn c: not c is-bf-char()) to-off = sc&.byte-offset Mem.size-i32() if to-off > from-off hls List.add({ from: from-off, to: to-off, type: Comment })