nx_langspec.nx
buildroot/runtime/nx_langspec.nx
about
nx_langspec.nx -- THE CONFORMANCE RUNNER for the written NishiLang specification.
lang.plan rung LR5, watch symbol spec_conformance_run, board /compare/lang.
THE FERROCENE LESSON, TAKEN EARLY. Rust reached safety-critical qualification only by retrofitting
a written specification years after 1.0, and the qualification artifact was never the prose -- it
was REQUIREMENTS-TO-TESTS TRACEABILITY. So the load-bearing half of this rung is this runner, not
the document: every clause in knowledge/specs/nishilang.spec carries an ID, every case in
knowledge/specs/nishilang.suite cites the clause IDs it exercises, and this organ resolves those
citations MECHANICALLY, drives the SHIPPED compiler over every case, and reports which clauses no
case exercises. That unexercised list is the real deliverable: a spec nothing checks is a comment,
and a clause nothing exercises is UNVERIFIED however confidently it is written.
WHAT IT IS NOT. It is not a second compiler-gate driver: it COMPOSES nx_ccgate_lib, the one organ
in the estate that spawns the compiler, and nx_lineconf_lib for its thresholds. It does not
replace nx_langdiag_gate -- that gate proved 11 hand-written rows refuse for the RIGHT reason and
is where this suite's discipline comes from. What it adds is the three things a hard-coded row
list structurally cannot have: the cases are DATA (adding one is a data row, not a rebuild), each
case is TRACED to a normative clause, and the run reports COVERAGE over the whole clause set.
THREE STATES, NEVER TWO. A case is PASS, FAIL or UNOBSERVABLE. UNOBSERVABLE is a case the runner
could not judge through no fault of the language -- its source is missing, the assembler failed,
the artifact could not be renamed. It is NOT folded into pass and NOT folded into fail: an axis
that cannot see must abstain, never acquit. Every count is printed beside its denominator and the
partition is reconciled in the output, because an abstention nobody reads is a lie nobody told.
NO SILENT CAPS. Budgets come from the conf. A spec or suite that exceeds one is not truncated in
silence: the surplus is counted, named OVER-BUDGET, and coverage_complete is forced to 0.
EXITS: 0 CONFORMANT - 1 DEVIATION - 2 usage - 3 UNOBSERVABLE - 4 EMPTY-SUITE.
EMPTY-SUITE is its own exit on purpose: a conformance runner that certifies the empty set is the
vacuous-test defect wearing a certification costume, and 0 must be unreachable that way.
DECLARED LIMITATION, MEASURED NOT ASSUMED: an INLINE case is materialised into a scratch directory
outside the tree and the compiler resolves an import relative to the importing file, so an INLINE
case CANNOT import. A case that needs the standard library is written as a fixture in the tree and
cited by path. Found by this organ's own first run, which reported the offending case FAIL in the
compiler's own words (expand_imports failed, exit 12) rather than passing it for the wrong reason.
Usage: nx_langspec [run|coverage|clauses|cases] [spec] [suite] [compiler] [conf]
The conf argument exists so a gate can supply its OWN thresholds against its OWN fixture spec
dependencies 4 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nxnx_ccgate_lib.nxnx_lineconf_lib.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 49 | const LS_CONF: *u8 = "knowledge/specs/nishilang_conformance.conf\x00" |
| 50 | const LS_SPEC_DEF: *u8 = "knowledge/specs/nishilang.spec\x00" |
| 51 | const LS_SUITE_DEF: *u8 = "knowledge/specs/nishilang.suite\x00" |
| 52 | const LS_SCRATCH: *u8 = "/tmp/nx_langspec\x00" |
| 54 | const LS_EXIT_CONFORMANT: i64 = 0 |
| 55 | const LS_EXIT_DEVIATION: i64 = 1 |
| 56 | const LS_EXIT_USAGE: i64 = 2 |
| 57 | const LS_EXIT_UNOBSERVABLE: i64 = 3 |
| 58 | const LS_EXIT_EMPTY: i64 = 4 |
| 60 | const LS_KIND_ACCEPT: i64 = 1 |
| 61 | const LS_KIND_REFUSE: i64 = 2 |
| 62 | const LS_KIND_RUN: i64 = 3 |
| 64 | const LS_V_PASS: i64 = 1 |
| 65 | const LS_V_FAIL: i64 = 2 |
| 66 | const LS_V_UNOBS: i64 = 3 |
| 68 | const LS_R_NONE: i64 = 0 |
| 69 | const LS_R_SRC_ABSENT: i64 = 1 |
| 70 | const LS_R_REFUSED_LEGAL: i64 = 2 |
| 71 | const LS_R_ASM_MARKER: i64 = 3 |
| 72 | const LS_R_ACCEPTED_ILLEGAL: i64 = 4 |
| 73 | const LS_R_WRONG_REASON: i64 = 5 |
| 74 | const LS_R_WRONG_CC_EXIT: i64 = 6 |
| 75 | const LS_R_ASSEMBLER: i64 = 7 |
| 76 | const LS_R_RENAME: i64 = 8 |
| 77 | const LS_R_WRONG_RUN_EXIT: i64 = 9 |
| 78 | const LS_R_INLINE_WRITE: i64 = 10 |
| 79 | const LS_R_BAD_KIND: i64 = 11 |
| 82 | const LS_LF: i64 = 9 |
| 83 | const LS_L_IDOFF: i64 = 0 |
| 84 | const LS_L_IDLEN: i64 = 1 |
| 85 | const LS_L_SECOFF: i64 = 2 |
| 86 | const LS_L_SECLEN: i64 = 3 |
| 87 | const LS_L_TTLOFF: i64 = 4 |
| 88 | const LS_L_TTLLEN: i64 = 5 |
| 89 | const LS_L_TXTOFF: i64 = 6 |
| 90 | const LS_L_TXTLEN: i64 = 7 |
| 91 | const LS_L_EX: i64 = 8 |
| 94 | const LS_CF: i64 = 18 |
| 95 | const LS_C_IDOFF: i64 = 0 |
| 96 | const LS_C_IDLEN: i64 = 1 |
| 97 | const LS_C_CLOFF: i64 = 2 |
| 98 | const LS_C_CLLEN: i64 = 3 |
| 99 | const LS_C_KIND: i64 = 4 |
| 100 | const LS_C_FLGOFF: i64 = 5 |
| 101 | const LS_C_FLGLEN: i64 = 6 |
| 102 | const LS_C_EXPOFF: i64 = 7 |
| 103 | const LS_C_EXPLEN: i64 = 8 |
| 104 | const LS_C_SRCOFF: i64 = 9 |
| 105 | const LS_C_SRCLEN: i64 = 10 |
| 106 | const LS_C_INLINE: i64 = 11 |
| 107 | const LS_C_VERD: i64 = 12 |
| 108 | const LS_C_WANT: i64 = 13 |
| 109 | const LS_C_GOT: i64 = 14 |
| 110 | const LS_C_PAROFF: i64 = 15 |
| 111 | const LS_C_PARLEN: i64 = 16 |
| 112 | const LS_C_REASON: i64 = 17 |
| 114 | const LS_PIPE: i64 = 124 |
| 115 | const LS_SEMI: i64 = 59 |
| 116 | const LS_SPEC_FIELDS: i64 = 5 |
| 117 | const LS_CASE_FIELDS: i64 = 8 |
| 118 | const LS_PERMIL: i64 = 1000 |
| 119 | const LS_MODE_RW: i64 = 0x1a4 |
| 120 | const LS_SCRATCH_MODE: i64 = 0x1ed |
| 121 | const LS_FBUF: i64 = 32 |
functions
| 126 | func ls_p(s: *u8) -> i64 { gv_puts(s); return 0 } |
| 127 | func ls_n(v: i64) -> i64 { gv_num(v); return 0 } |
| 128 | func ls_kv(k: *u8, v: i64) -> i64 { gv_puts(k); gv_puts("=" as *u8); gv_num(v); gv_puts("\n" as *u8); return 0 } |
| 130 | func ls_wr(b: *u8, off: i64, len: i64) -> i64 |
| 136 | func ls_eol(b: *u8, n: i64, i: i64) -> i64 |
| 147 | func ls_starts(b: *u8, off: i64, end: i64, lit: *u8) -> i64 |
| 161 | func ls_litlen(lit: *u8) -> i64 { var j: i64 = 0; while lit[j] != (0 as u8) { j = j + 1 } return j } called by 1: ls_slice_is |
| 163 | func ls_slice_is(b: *u8, off: i64, len: i64, lit: *u8) -> i64 |
| 168 | func ls_streq(a: *u8, b: *u8) -> i64 called by 1: main |
| 182 | func ls_nfields(b: *u8, off: i64, end: i64) -> i64 called by 1: spec_conformance_run |
| 190 | func ls_field(b: *u8, off: i64, end: i64, k: i64, out: *i64) -> i64 called by 1: spec_conformance_run |
| 208 | func ls_dup(b: *u8, off: i64, len: i64) -> *u8 |
| 217 | func ls_int_after_eq(b: *u8, off: i64, len: i64) -> i64 called by 1: spec_conformance_run |
| 241 | func ls_readable(p: *u8) -> i64 |
| 248 | func ls_write_slice(path: *u8, b: *u8, off: i64, len: i64) -> i64 |
| 258 | func ls_head(path: *u8, cap: i64) -> i64 |
| 273 | func ls_verd_name(v: i64) -> *u8 called by 1: spec_conformance_run |
| 280 | func ls_reason_name(r: i64) -> *u8 called by 1: spec_conformance_run |
| 295 | func ls_kind_name(k: i64) -> *u8 called by 1: spec_conformance_run |
| 303 | func ls_find_clause(L: *i64, nl: i64, sb: *u8, ub: *u8, off: i64, len: i64) -> i64 called by 1: spec_conformance_run |
| 332 | func spec_conformance_run(specp: *u8, suitep: *u8, cc: *u8, do_run: i64, confp: *u8) -> i64 |
| 702 | func ls_usage() -> i64 |
| 713 | func ls_list(specp: *u8, suitep: *u8, want_cases: i64) -> i64 |
| 737 | func main(argc: i64, argv: *i64) -> i64 |