nx_js_lex.nx
buildroot/runtime/nx_js_lex.nx
about
nx_js_lex.nx -- R-JS-LEX (WB-JS-001 rung 0): the ECMAScript TOKENIZER, the
hardware-up floor of the sovereign JS engine (browser-engine-exceed roadmap ยง2).
Founds R-JS-PARSE above it (no-floating law: the lexer is built+gated before any
parser rides it). Shape = STATE_MACHINE/STRUCT_WALK over source bytes -- an
EXISTING emitter shape, so team-authorable now (NOT blocked on X-AUT-006c).
Scans ECMAScript source into a flat token stream (3 i64 slots per token:
kind, start-offset, byte-length). Covers the lexical core real JS uses:
- whitespace + line-terminators (skipped; ASI is a PARSER concern, rung 1)
- // line comments and /* block */ comments (skipped)
- identifiers + keywords ($ and _ legal; keyword set classified)
- numeric literals: decimal int/float, exponent, 0x/0o/0b prefixes
- string literals ' and " with backslash-escape handling (\" \' \\ \n ...)
- punctuators incl. multi-char operators (=== !== >>>= => ?. ?? ** etc.)
- unterminated string -> ERROR token (honest, never silently swallowed)
HONEST RUNG-0 SCOPE (named OPEN, NOT faked): template literals (`...${}`) and
regex-literal disambiguation need PARSER context (is `/` a divide or a regex?),
so they are R-JS-LEX-0b, built once the parser can feed back context. BigInt `n`
suffix + full Unicode IdentifierStart are also 0b. Rung 0 tokenizes ASCII JS.
GATE (main): 7 KATs assert the exact token stream (kind + lexeme) on real JS
snippets + TAMPER (unterminated string must be ERROR, never a fabricated STRING).
Self-validating; exit 0 iff all pass; appends knowledge/status/js_engine.log.
license_tier: ORIGINAL (tutor-bootstrap scaffold; team re-authors from the
R-JS-LEX data spec via author=organ -- (B)-debt, mirror the h2 capstone note.)
dependencies 2 imports · 1 importers
imports: nx_syscalls.nxnx_itoa_lib.nx
imported by: nx_js_parse.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 31 | const JS_TOK_EOF: i64 = 0 |
| 32 | const JS_TOK_IDENT: i64 = 1 |
| 33 | const JS_TOK_KEYWORD: i64 = 2 |
| 34 | const JS_TOK_NUMBER: i64 = 3 |
| 35 | const JS_TOK_STRING: i64 = 4 |
| 36 | const JS_TOK_PUNCT: i64 = 5 |
| 37 | const JS_TOK_ERROR: i64 = 8 |
| 38 | const JS_TOK_TEMPLATE: i64 = 9 // template literal: whole span incl both backticks; interior re-lexed at eval |
| 39 | const JS_TOK_REGEX: i64 = 10 // regex literal /pattern/flags: whole span; pattern+flags extracted at eval |
functions
| 42 | func js_is_digit(c: i64) -> i64 { if c >= 48 { if c <= 57 { return 1 } } return 0 } |
| 43 | func js_is_alpha(c: i64) -> i64 called by 1: js_is_idstart |
| 62 | func js_is_idstart(c: i64) -> i64 |
| 69 | func js_is_idpart(c: i64) -> i64 |
| 74 | func js_is_hex(c: i64) -> i64 |
| 80 | func js_is_space(c: i64) -> i64 called by 1: js_skip_trivia |
| 91 | func js_lexeme_eq(src: *u8, start: i64, len: i64, lit: *u8) -> i64 |
| 103 | func js_is_keyword(src: *u8, start: i64, len: i64) -> i64 |
| 146 | func js_scan_ident(src: *u8, srclen: i64, pos: i64) -> i64 |
| 155 | func js_scan_while_digit(src: *u8, srclen: i64, pos: i64) -> i64 |
| 164 | func js_scan_while_hex(src: *u8, srclen: i64, pos: i64) -> i64 |
| 173 | func js_scan_exp(src: *u8, srclen: i64, pos: i64) -> i64 |
| 183 | func js_scan_number(src: *u8, srclen: i64, pos: i64) -> i64 |
| 208 | func js_scan_string(src: *u8, srclen: i64, pos: i64) -> i64 called by 1: js_lex_string |
| 229 | func js_punct_len(src: *u8, srclen: i64, pos: i64) -> i64 |
| 307 | func js_skip_trivia(src: *u8, srclen: i64, pos: i64) -> i64 |
| 341 | func js_emit(toks: *i64, ntok_box: *i64, kind: i64, start: i64, len: i64) -> i64 |
| 350 | func js_num_starts(src: *u8, srclen: i64, pos: i64) -> i64 |
| 357 | func js_lex_string(src: *u8, srclen: i64, pos: i64, toks: *i64, ntok_box: *i64) -> i64 |
| 369 | func js_lex_template(src: *u8, srclen: i64, pos: i64, toks: *i64, ntok_box: *i64) -> i64 |
| 406 | func js_regex_context(toks: *i64, ntok: i64, src: *u8) -> i64 |
| 434 | func js_lex_regex(src: *u8, srclen: i64, pos: i64, toks: *i64, ntok_box: *i64) -> i64 |
| 457 | func js_lex_one(src: *u8, srclen: i64, pos: i64, toks: *i64, ntok_box: *i64) -> i64 called by 1: js_lex calls 11: js_is_idstartjs_scan_identjs_is_keywordjs_emitjs_num_startsjs_scan_number+5 |
| 482 | func js_lex(src: *u8, srclen: i64, toks: *i64, maxtoks: i64, ntok_box: *i64) -> i64 |
| 496 | func jl_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } |
| 501 | func jl_putn(v: i64) -> i64 { nxi_out(v); return 0 } |
| 502 | func jl_strlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } called by 1: main |
| 504 | func js_expect(toks: *i64, ntok: i64, idx: i64, kind: i64, src: *u8, lit: *u8) -> i64 |
| 510 | func main() -> i64 |
| 653 | func jl_fdn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } |