code wiki / (root) / nx_jsscope.nx

nx_jsscope.nx

buildroot/runtime/nx_jsscope.nx

19095 B445 linesdepth 5pulls 5 transitivereach 38 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_jsscope.nx -- STATIC SCOPE RESOLUTION over nx_js_parse's AST: does every identifier a script REFERENCES have a declaration in a scope that ENCLOSES the reference? WHY THIS EXISTS. 2026-08-25 every /world page with a cast went black on the WebGL tier and reverted to the CPU renderer, and the reason -- once the reload was made to carry it -- was `ReferenceError: nxHairTick is not defined`: a function DECLARED inside loadNPC, CALLED from drawNPCs at script scope. The page LEXED (nx_jsbalance passed it), the wasm PAINTED, every gate was green. Nothing in the estate asks the one question a browser asks first: can this name be seen from here? This organ asks it, statically, over the incumbent parser -- one AST, no second front-end. THE RULE, STATED ONCE. A reference resolves if its name is declared in the SAME function scope or any ENCLOSING one (function declarations and `var` hoist to their function; params, class names, catch params and for-targets bind where they appear). A name declared ONLY in a function that does NOT enclose the reference is the exact defect above and is reported as OUT-OF-SCOPE, with the declaring scope named -- because "undefined" sends a reader to grep for a typo, while "declared in loadNPC" sends them to the real fix. A name declared nowhere is UNRESOLVED and is checked against a globals CONF (knowledge/js_globals.conf, one name per line): browser and language globals are DATA the page may lean on, never a list compiled into this organ. ⚠ DECLARED IMPRECISION, because a checker whose blind spots are unstated gets trusted as exact. 1. `let`/`const` are BLOCK-scoped in JS; this pass binds them to their FUNCTION. A let in one block referenced from a sibling block would be a real ReferenceError this organ does NOT see. That is the conservative direction -- it misses an error class, it never invents one. 2. Template-literal interiors (`${expr}`) are not parsed by nx_js_parse (the token is opaque), so references inside them are invisible here. 3. `with` statements and `eval` are not modelled; a page that used them could not be judged. 4. Property names (a.b), object keys, labels and destructuring keys are NOT references and are never counted, by construction of the walk. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 3 imports · 17 importers

nx_syscalls.nx nx_js_lex.nx nx_js_parse.nx nx_jsscope.nx nx_craft_body_driver_t138.nx nx_craft_combined_emit_t28.nx nx_craft_combined_emit_t29.nx nx_craft_emit.nx nx_craft_feedback_emit_t28.nx nx_craft_garment_emit_t132.nx nx_craft_integrated_emit_t73.nx nx_craft_knight_emit_t25.nx nx_craft_material_body_emit_t61.nx nx_craft_material_emit_t55.nx

diagram shows first 10 each side; +0 more imports, +7 more importers in the complete lists below.

imports: nx_syscalls.nxnx_js_lex.nxnx_js_parse.nx

imported by: nx_craft_body_driver_t138.nxnx_craft_combined_emit_t28.nxnx_craft_combined_emit_t29.nxnx_craft_emit.nxnx_craft_feedback_emit_t28.nxnx_craft_garment_emit_t132.nxnx_craft_integrated_emit_t73.nxnx_craft_knight_emit_t25.nxnx_craft_material_body_emit_t61.nxnx_craft_material_emit_t55.nxnx_craft_move_emit_t72.nxnx_craft_pipeline_emit_t64.nxnx_craft_recovery_emit_t23.nxnx_craft_search_emit_t53.nxnx_craft_support_emit_t31.nxnx_craft_workspace_emit_t48.nxnx_jsscope_gate.nx

structs

none

consts

38const SC_MAX: i64 = 4096 // function scopes a page may hold -- a REFUSAL at the cap, never a silent stop
39const DC_MAX: i64 = 65536 // declarations across all scopes
40const SC_ROW: i64 = 4 // node, parent, decl_start, decl_count
41const SC_NODE: i64 = 0
42const SC_PARENT: i64 = 1
43const SC_DSTART: i64 = 2
44const SC_DCOUNT: i64 = 3
47const RP_MAX: i64 = 4096
48const RP_ROW: i64 = 4
49const RP_UNRESOLVED: i64 = 1
50const RP_OUTOFSCOPE: i64 = 2
53const RP_REDECL: i64 = 3
56const JS_ST_CTX: i64 = 0
57const JS_ST_SC: i64 = 1 // scope rows
58const JS_ST_NSC: i64 = 2
59const JS_ST_DC: i64 = 3 // decl pairs
60const JS_ST_NDC: i64 = 4
61const JS_ST_RP: i64 = 5 // report rows
62const JS_ST_NRP: i64 = 6
63const JS_ST_NREF: i64 = 7 // references examined -- the coverage figure
64const JS_ST_OVER: i64 = 8 // 1 if any table hit its cap (the verdict is then a BOUND)
65const JS_ST_GLOB: i64 = 9 // globals conf bytes
66const JS_ST_GLOBN: i64 = 10
67const JS_ST_N: i64 = 12

functions

69func jss_tokidx(ctx: *i64, idx: i64) -> i64 { let n: *i64 = jp_nodes(ctx); return n[idx * NODE_SLOTS + 4] }
70func jss_src(ctx: *i64) -> *u8 { return (ctx[CTX_SRC]) as *u8 }
71func jss_tok_start(ctx: *i64, tokidx: i64) -> i64 { let t: *i64 = jp_toks(ctx); return t[tokidx*3 + 1] }
72func jss_tok_len(ctx: *i64, tokidx: i64) -> i64 { let t: *i64 = jp_toks(ctx); return t[tokidx*3 + 2] }
75func jss_tok_eq(ctx: *i64, ta: i64, tb: i64) -> i64
90func jss_declared_in(st: *i64, s: i64, tokidx: i64) -> i64
102func jss_report(st: *i64, kind: i64, tokidx: i64, scope: i64, declscope: i64) -> i64
called by 2: jss_declarejss_ref
115func jss_declare(st: *i64, scope: i64, tokidx: i64) -> i64
136func jss_new_scope(st: *i64, node: i64, parent: i64) -> i64
called by 2: jss_walkjss_check
151func jss_resolve(st: *i64, s: i64, tokidx: i64) -> i64
called by 1: jss_ref calls 1: jss_declared_in
162func jss_declared_anywhere(st: *i64, tokidx: i64) -> i64
called by 1: jss_ref calls 1: jss_declared_in
173func jss_is_global(st: *i64, tokidx: i64) -> i64
202func jss_is_list(k: i64) -> i64
called by 2: jss_collectjss_walk
217func jss_collect(st: *i64, scope: i64, idx: i64) -> i64
305func jss_ref(st: *i64, scope: i64, tokidx: i64) -> i64
314func jss_walk(st: *i64, scope: i64, idx: i64) -> i64
405func jss_check(src: *u8, srclen: i64, globals: *u8, globlen: i64) -> *i64
427func jss_error_pos(src: *u8, srclen: i64) -> i64
436func jss_scope_name_tok(st: *i64, s: i64) -> i64
called by 1: jg_print calls 2: jp_najss_tokidx