1 # src/rules/tokens: helpers the token rules share (put, escape, nat, strings, 2 # twice, arms): significant tokens, literal kinds, Nat literals, case 3 # patterns, and a name's uses under a node. 4 import Base 5 import ../lazy/lazy.bend as Lazy 6 import ../syntax/lex.bend as Lex 7 import ../syntax/tree.bend as Tree 8 9 # the tokens without space, newlines and comments 10 def sig(toks: List<&2, Lex.Tok>) -> List<&2, Lex.Tok>: 11 match toks: 12 case Nil{}: 13 Nil{} 14 case Con{Lex.Tok{+k, t, l, c}, rest}: 15 +more = sig(rest) 16 Bool.pick(List<&2, Lex.Tok>, Lex.significant(k), Lex.Tok{k, t, l, c} <> more, more) 17 18 # a text cut to its first char 19 def code.cut(tt: String) -> String: 20 match tt: 21 case SNil{}: 22 SNil{} 23 case SCon{h, _t}: 24 SCon{h, SNil{}} 25 26 # a string literal cut to its opening quote; any other token as it is 27 def code.tok(tk: Lex.Tok) -> Lex.Tok: 28 match tk: 29 case Lex.Tok{+k, +t, l, c}: 30 Lex.Tok{k, Bool.pick(String, Lex.is_str(k), code.cut(t), t), l, c} 31 32 # the tokens, each string literal cut to its opening quote 33 def code.toks(ts: List<&2, Lex.Tok>) -> List<&2, Lex.Tok>: 34 match ts: 35 case Nil{}: 36 Nil{} 37 case Con{h, t}: 38 code.tok(h) <> code.toks(t) 39 40 # a text with each string literal cut to its opening quote: what of it is 41 # code, as the lexer reads it 42 def code(+tt: String) -> String: 43 Lex.text(code.toks(Lex.tokens(tt))) 44 45 # a number, a char or a string literal? 46 def is_lit(kk: Lex.TokKind) -> Bool: 47 match kk: 48 case Lex.TNum{}: 49 True{} 50 case Lex.TChar{}: 51 True{} 52 case Lex.TStr{}: 53 True{} 54 case other: 55 False{} 56 57 # digits, then one final `n`: a Nat literal's chars 58 def nat_ok(cs: List<&2, Char>) -> Bool: 59 match cs: 60 case Con{'n', Nil{}}: 61 True{} 62 case Con{+c, t}: 63 Lazy.and_then(Char.is_digit(c), _u => nat_ok(t)) 64 case Nil{}: 65 False{} 66 67 # the text without its last char (a Nat literal's digits) 68 def stem(+tt: String) -> String: 69 String.take(tt, Nat.sub(String.length(tt), 1n)) 70 71 # a Nat literal's value (`12n` is 12); none for anything else or past U32 72 def nat_value(+tt: String) -> Maybe<&2, U32>: 73 Bool.pick(Maybe<&2, U32>, nat_ok(String.to_list(tt)), U32.read(stem(tt)), None{}) 74 75 # a text's width in chars 76 def width(tt: String) -> U32: 77 U32.from_nat(String.length(tt)) 78 79 # is the first node the keyword? 80 def keyword(nn: Tree.Node, +word: String) -> Bool: 81 match nn: 82 case Tree.NCons{Tree.Leaf{Lex.Tok{Lex.TKey{}, +t, l, c}}, rest}: 83 String.eq(t, word) 84 case other: 85 False{} 86 87 # a case statement's pattern (its tokens after `case`, the colon and an 88 # inline body included) 89 def pattern(kids: Tree.Node) -> Tree.Node: 90 match kids: 91 case Tree.NCons{h, rest}: 92 rest 93 case other: 94 other