code wiki / (root) / nx_lex_kinds.nx

nx_lex_kinds.nx source

↩ module page · 168 lines · 5724 B

1// lex_kinds.nx -- Tok record + named TokenKind constants. 2// 3// Shared by lex.nx (producer) and parse.nx (consumer). Both used 4// to carry their own copy of the `Tok` struct and compare 5// `t.kind == 67` with a comment saying "LPAREN"; with this module 6// imported they use `t.kind == TK_LPAREN` directly. 7// 8// Numbers below must match the comment table in lex.nx and the 9// emission sites in lex.nx's lexer -- do not renumber without 10// auditing both callers and the existing test fixtures. 11 12// ---- Tok record --------------------------------------------------- 13// 14// text[] (64 bytes) lives inline as 8 i64 words starting at offset 15// 32. Access via tok_text_ptr() defined by lex.nx. 16 17struct Tok { 18 kind: i64, 19 line: i64, 20 col: i64, 21 int_val: i64, 22 text0: i64, 23 text1: i64, 24 text2: i64, 25 text3: i64, 26 text4: i64, 27 text5: i64, 28 text6: i64, 29 text7: i64, 30 // Overflow buffer for TK_STRING longer than 63 bytes; mirrors 31 // the str_data/str_len fields added to nxc2/lex.h. 32 str_data: i64, 33 str_len: i64, 34} 35 36const TOK_BYTES: i64 = 112 37 38// ---- literals ----------------------------------------------------- 39 40const TK_EOF: i64 = 0 41const TK_INT: i64 = 1 42const TK_IDENT: i64 = 2 43const TK_STRING: i64 = 3 44// Floating-point literal. Lexer splits the number into whole / 45// fractional parts and stores both in the Tok: 46// t.int_val = whole part 47// t.text0 = fractional digits as i64 (e.g. "14" in "3.14" -> 14) 48// t.text1 = number of fractional digits (2 in the example) 49// Parser converts to IEEE 754 via quant.nx when building the IR. 50// Keeping whole/frac as two ints in the token avoids pulling fp 51// conversion into the lexer and lets parse.nx decide f32 vs f64 52// based on the declared variable type. 53const TK_FLOAT: i64 = 4 54 55// Explicit-f32 float literal -- written `1.5f32` (or `1.5F32`) in 56// source. Same int_val / text0 / text1 packing as TK_FLOAT (whole / 57// frac_num / frac_digits); the kind tells parse.nx to use 58// fp32_from_parts + TY_F32 instead of the default fp64 path. 59// `1.5f64` is allowed as an explicit-default and emits TK_FLOAT. 60const TK_FLOAT_F32: i64 = 5 61 62// ---- keywords ----------------------------------------------------- 63 64const TK_FUNC: i64 = 10 65const TK_LET: i64 = 11 66const TK_VAR: i64 = 12 67const TK_CONST: i64 = 13 68const TK_STATIC: i64 = 14 69const TK_IF: i64 = 15 70const TK_ELSE: i64 = 16 71const TK_WHILE: i64 = 17 72const TK_LOOP: i64 = 18 73const TK_FOR: i64 = 19 74const TK_IN: i64 = 20 75const TK_BREAK: i64 = 21 76const TK_CONTINUE: i64 = 22 77const TK_RETURN: i64 = 23 78const TK_TRUE: i64 = 24 79const TK_FALSE: i64 = 25 80const TK_STRUCT: i64 = 26 81const TK_ENUM: i64 = 27 82// @priv VISIBILITY ATTRIBUTE. Ported from the laptop SSOT 2026-07-31 -- buildroot had NO const at slot 33 83// (verified free before claiming it), so the trees can converge without renumbering anything. 84const TK_PRIV: i64 = 33 85const TK_MATCH: i64 = 28 86const TK_COMPTIME: i64 = 29 87const TK_EXTERN: i64 = 30 88const TK_AS: i64 = 31 89// V-LANGEXT M2: if-then-else as expression keyword. Distinct from 90// statement-form `if c { ... } else { ... }` (which uses braces); the 91// expression form `if c then a else b` matches Haskell/OCaml/Elm 92// convention. Required to disambiguate at parse_primary. 93const TK_THEN: i64 = 32 94 95// ---- arithmetic / assign ----------------------------------------- 96 97const TK_PLUS: i64 = 40 98const TK_MINUS: i64 = 41 99const TK_STAR: i64 = 42 100const TK_SLASH: i64 = 43 101const TK_PERCENT: i64 = 44 102const TK_ASSIGN: i64 = 45 103 104// ---- comparisons -------------------------------------------------- 105 106const TK_EQ: i64 = 46 107const TK_NE: i64 = 47 108const TK_LT: i64 = 48 109const TK_GT: i64 = 49 110const TK_LE: i64 = 50 111const TK_GE: i64 = 51 112 113// ---- logical / bitwise -------------------------------------------- 114 115const TK_AND_AND: i64 = 52 116const TK_OR_OR: i64 = 53 117const TK_BANG: i64 = 54 118const TK_AMP: i64 = 55 119const TK_PIPE: i64 = 56 120const TK_CARET: i64 = 57 121const TK_TILDE: i64 = 58 122const TK_SHL: i64 = 59 123const TK_SHR: i64 = 60 124 125// ---- structural punctuation --------------------------------------- 126 127const TK_ARROW: i64 = 61 // -> 128const TK_DOT_DOT: i64 = 62 // .. 129const TK_DOT: i64 = 63 130const TK_COLON: i64 = 64 131const TK_SEMI: i64 = 65 132const TK_COMMA: i64 = 66 133const TK_LPAREN: i64 = 67 134const TK_RPAREN: i64 = 68 135const TK_LBRACE: i64 = 69 136const TK_RBRACE: i64 = 70 137const TK_LBRACKET: i64 = 71 138const TK_RBRACKET: i64 = 72 139const TK_AT: i64 = 73 140const TK_HASH: i64 = 74 141const TK_COLON_COLON: i64 = 75 // :: 142const TK_FAT_ARROW: i64 = 76 // => (used by `match` arms) 143const TK_QUESTION: i64 = 77 // ? (C-style ternary cond ? a : b) 144 145// ---- shared Tok helpers ---- 146// 147// Kept here because they depend only on the Tok layout. Both lex.nx 148// (token producer) and parse.nx (token consumer) used to carry local 149// copies -- now they share one. 150 151func tok_text_ptr(t: *Tok) -> *u8 { 152 let base: i64 = t as i64 153 return (base + 32) as *u8 154} 155 156// Compare `n` bytes between `a` and `b`. If the shorter side (`b`) 157// isn't null-terminated at position n the match fails -- matches the 158// C strncmp-style "prefix of a equals exactly b" semantics used by 159// keyword lookup. 160func streq_n(a: *u8, b: *u8, n: i64) -> i64 { 161 var i: i64 = 0 162 while i < n { 163 if a[i] != b[i] { return 0 } 164 i = i + 1 165 } 166 if b[n] != 0 { return 0 } 167 return 1 168}