From 8d0d4912d0e3cb39fa8747f6eab69bdc92df5c2d Mon Sep 17 00:00:00 2001 From: Dmitrii Vasilev Date: Sun, 18 Oct 2026 00:58:04 +0700 Subject: [PATCH] t27b: emit_kit -- one home for the writers' shared helpers (Refs #9994) #10047 merged at its head before this fix reached the branch, and master's duplicate-bodies gate went red: ts_emit.t27 repeats 18 helper bodies of verilog_emit.t27 word for word (byte writers, to_front, line_near, the scope and name resolver, the symbol encoding, the test-tree builders). They now live once, in specs/tri/t27b/emit_kit.t27, with tests of their own, and both writers `use` it by name. A whole-module `use` of verilog_emit from ts_emit does not work: the splice counts words inside string literals as references, so ts_emit's "export function" pulls verilog_emit's fn `function`, and the generated Rust typecheck refuses it against ts_emit's own param_type and stmts. The ledger also loses its ternary_matmul row: that group is gone on master and the gate refuses a ceiling left above the real count. Measured on the Railway lab, on top of master 896d87b45: test-report emit_kit 4/4, ts_emit 4/4, verilog_emit 7/7, 0 vacuous; dupe_scan ok after the bless; t27b ts and t27b verilog print byte-identical output and exit codes before and after on all 2095 specs (4190 of 4190). Generated writers and the three records regenerated there. Co-Authored-By: Claude Opus 5.5 --- .trinity/seals/t27b_T27bEmitKit.json | 33 ++ .trinity/seals/t27b_T27bTsEmit.json | 18 +- .trinity/seals/t27b_T27bVerilogEmit.json | 18 +- cli/t27b/README.md | 4 +- docs/reports/t27b_expectations.json | 1 + gen/rust/tri/t27b/ts_emit.rs | 444 +++++++++++------------ gen/rust/tri/t27b/verilog_emit.rs | 444 +++++++++++------------ specs/tri/t27b/emit_kit.t27 | 325 +++++++++++++++++ specs/tri/t27b/ts_emit.t27 | 221 +---------- specs/tri/t27b/verilog_emit.t27 | 221 +---------- tools/duplicate_bodies_baseline.txt | 1 - 11 files changed, 830 insertions(+), 900 deletions(-) create mode 100644 .trinity/seals/t27b_T27bEmitKit.json create mode 100644 specs/tri/t27b/emit_kit.t27 diff --git a/.trinity/seals/t27b_T27bEmitKit.json b/.trinity/seals/t27b_T27bEmitKit.json new file mode 100644 index 0000000000..368aacdc08 --- /dev/null +++ b/.trinity/seals/t27b_T27bEmitKit.json @@ -0,0 +1,33 @@ +{ + "built_by": "t27c-bootstrap@0.5.2+9b160b143", + "closure": [ + { + "spec": "specs/tri/t27b/verilog_plan.t27", + "spec_hash": "sha256:a52dbb4524173c54e19d205ee72b8a1544da978df82cc15a92341c7cad9ba428" + } + ], + "config": "gen=c,rust,verilog,zig;tests=zig", + "gen_hash_c": "sha256:3eeea85101c9dff7f3899dab14da7177aece63cb40504ad0f2cf655b73d92a33", + "gen_hash_rust": "sha256:5b6aa47e15d247a39085a75ce6771e40bd305a1fa7c78afd66471297d5ab9497", + "gen_hash_verilog": "sha256:f44541bb247251be1dfdd84155738a64a2e414d8a5b3ddb8b45fcba5659e465a", + "gen_hash_zig": "sha256:29b2b4afd4bbb22e09013427d12b157f90a813d5686af24e345c2fad57984d21", + "module": "T27bEmitKit", + "ring": 12, + "seal_schema": 2, + "sealed_at": "2026-10-17T17:54:26Z", + "sealed_by": "t27c-bootstrap@0.5.2", + "spec_hash": "sha256:7a31a1e4383104b0b59b2a339ccbe6d87eb69f56f28e5bff95befa18b0dba795", + "spec_path": "specs/tri/t27b/emit_kit.t27", + "tests": { + "failed": 0, + "failing": [], + "forced": false, + "passed": 4, + "total": 4, + "vacuous": 0 + }, + "toolchain": { + "test_runner": "sha256:1982ae948e24d00c5d221ccec12dfce1eb01204b53e37b0f857f93b16d64629d", + "zig": "0.16.0" + } +} \ No newline at end of file diff --git a/.trinity/seals/t27b_T27bTsEmit.json b/.trinity/seals/t27b_T27bTsEmit.json index 08c6cb24eb..55119bc106 100644 --- a/.trinity/seals/t27b_T27bTsEmit.json +++ b/.trinity/seals/t27b_T27bTsEmit.json @@ -1,6 +1,10 @@ { - "built_by": "t27c-bootstrap@0.5.2+a1b584b29", + "built_by": "t27c-bootstrap@0.5.2+9b160b143", "closure": [ + { + "spec": "specs/tri/t27b/emit_kit; // byte writers, to_front, line_near, resolve and symbols, test trees.t27", + "spec_hash": "missing" + }, { "spec": "specs/tri/t27b/text_escape.t27", "spec_hash": "sha256:c88981799b2e3f97cd0815471d288e48550f5a785c504412546ca58c0b19656a" @@ -11,16 +15,16 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:91d80cba62f45cc2dd2e052287b1336b88a00fec91e65f98653f7ae2f90bebc1", - "gen_hash_rust": "sha256:a902659f2f30c887876e487094668138d7fcd90f266c7ca4a56e859cc94bff34", - "gen_hash_verilog": "sha256:204115c5a4cbcac65f725db2cc393b9b909ce9faedf4132ad05feb2f5c0aa736", - "gen_hash_zig": "sha256:1eaa2c4f003d1912304766da67ddd8679b0dbc86edf6101344fbdb4f5dd68971", + "gen_hash_c": "sha256:ae5ac364c812f2f979e0f3beb6647a4bcd675ef6f0e67e7cf7b1d0c812d7abcc", + "gen_hash_rust": "sha256:b90304cef833b4b0753bb405dd9e14e53e8385b1981f55b217d2ae2847839fff", + "gen_hash_verilog": "sha256:c64da405cca1d76d46ff4cac8e9e991cfb840fa1e8bc8d155f196752adfbd179", + "gen_hash_zig": "sha256:22ee38ad0e7f11e71cfd6eb3517e91494d96d114fe8db98ce5576a23f593e8aa", "module": "T27bTsEmit", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-17T17:23:04Z", + "sealed_at": "2026-10-17T17:54:27Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:bc52c75db0f5923f9b3bdd4f9373e0d2b45ae62c7119eb135519c25d3d419ecb", + "spec_hash": "sha256:8e93f798666f4030ff62f124e1531e63a7d94dfc1ddbb934b747914f1c36b176", "spec_path": "specs/tri/t27b/ts_emit.t27", "tests": { "failed": 0, diff --git a/.trinity/seals/t27b_T27bVerilogEmit.json b/.trinity/seals/t27b_T27bVerilogEmit.json index b53fe770c2..9a9149b323 100644 --- a/.trinity/seals/t27b_T27bVerilogEmit.json +++ b/.trinity/seals/t27b_T27bVerilogEmit.json @@ -1,6 +1,10 @@ { - "built_by": "t27c-bootstrap@0.5.2+f787afb", + "built_by": "t27c-bootstrap@0.5.2+9b160b143", "closure": [ + { + "spec": "specs/tri/t27b/emit_kit; // byte writers, to_front, line_near, resolve and symbols, test trees.t27", + "spec_hash": "missing" + }, { "spec": "specs/tri/t27b/text_escape.t27", "spec_hash": "sha256:c88981799b2e3f97cd0815471d288e48550f5a785c504412546ca58c0b19656a" @@ -11,16 +15,16 @@ } ], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:e898398e1e6f1541b034d7f93b45eca4341c961f5b37ba1e154c02b3272ece5b", - "gen_hash_rust": "sha256:b218d53be59a034da8a84565c204e96647bcb1b7af9bd400d448149a9904ae31", - "gen_hash_verilog": "sha256:17511cc822f43fc37f070e9d2178ffa1ff1f6ef1300134a38cb9bdcab4e03d49", - "gen_hash_zig": "sha256:a654b907033a49164f3eb19c4592c1cf58ce7d7b29230819258712cdb7a00e41", + "gen_hash_c": "sha256:24f73f039c0ba7fa8a523d428bb49d715d43cbbb784f12d9ff08cde73b3035e1", + "gen_hash_rust": "sha256:827184630e8660cf8a16957f96bffd91a136365061ce2b7ad32287a0380421fc", + "gen_hash_verilog": "sha256:cc260a30a0d7d86562173ec7e5037d4e12b388faaf267a083783b72f24356760", + "gen_hash_zig": "sha256:5970a4a3ef8dfa8c720bee5f09573e5914ce023f6c7d86caecc080dd81a23d1a", "module": "T27bVerilogEmit", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-17T17:33:08Z", + "sealed_at": "2026-10-17T17:54:27Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:62dfd9b10d4cbcb90a55ca2c76c712c9b94ffd8a416020ac1f8ff980b930ca60", + "spec_hash": "sha256:e34f866a304927d4ff6b2eca2485c74551490d6dd79aae40001249debc14cc76", "spec_path": "specs/tri/t27b/verilog_emit.t27", "tests": { "failed": 0, diff --git a/cli/t27b/README.md b/cli/t27b/README.md index 948a0b587f..61c998a950 100644 --- a/cli/t27b/README.md +++ b/cli/t27b/README.md @@ -346,7 +346,9 @@ test-report. Anything outside that subset is refused, exit 2, with The decisions are in `specs/tri/t27b/ts_plan.t27`: the types, the operator forms, folding, reserved names, and the prelude and coda. The writer is -`specs/tri/t27b/ts_emit.t27`. Node 24 runs the output as `.mts`: +`specs/tri/t27b/ts_emit.t27`. It shares its byte writers, name resolver and +test trees with the Verilog writer through `specs/tri/t27b/emit_kit.t27`. +Node 24 runs the output as `.mts`: ``` t27b ts specs/queen/key_failover.t27 > /tmp/kf.mts diff --git a/docs/reports/t27b_expectations.json b/docs/reports/t27b_expectations.json index f2c4ed54f8..143113021d 100644 --- a/docs/reports/t27b_expectations.json +++ b/docs/reports/t27b_expectations.json @@ -1308,6 +1308,7 @@ {"path": "specs/tri/t27b/discard_plan.t27", "t27b": "pass"}, {"path": "specs/tri/t27b/dogfood.t27", "t27b": "pass"}, {"path": "specs/tri/t27b/elf.t27", "t27b": "pass"}, + {"path": "specs/tri/t27b/emit_kit.t27", "t27b": "pass"}, {"path": "specs/tri/t27b/empty_lit_plan.t27", "t27b": "pass"}, {"path": "specs/tri/t27b/eval_arith.t27", "t27b": "pass"}, {"path": "specs/tri/t27b/float_as_plan.t27", "t27b": "pass"}, diff --git a/gen/rust/tri/t27b/ts_emit.rs b/gen/rust/tri/t27b/ts_emit.rs index dd867e023c..492e396069 100644 --- a/gen/rust/tri/t27b/ts_emit.rs +++ b/gen/rust/tri/t27b/ts_emit.rs @@ -4,65 +4,6 @@ // This backend emits declarations only. The spec's checks live in // the Zig and Verilog outputs; do not read this file as verified. -pub const MSG_ROOM: usize = 400; - -pub const NAME_CAP: usize = 120; - -pub const SYM_UNIT: i64 = 1099511627776; - -pub const SYM_LOCAL: i64 = 1; - -pub const SYM_PARAM: i64 = 2; - -pub const SYM_TOP: i64 = 3; - -pub const SYM_FN: i64 = 4; - -pub const NO_SYM: i64 = -1; - -pub fn put_bytes(out: &mut [u8], at: usize, s: &[u8], a: usize, b: usize) -> usize { - let mut k: usize = a; - let mut q: usize = at; - while (k < b) { - out[(q) as usize] = s[(k) as usize]; - q = (q + 1); - k = (k + 1); - } - return q; -} - -pub fn dec_len(v: u64) -> usize { - let mut n: usize = 1; - let mut x: u64 = v; - while (x >= 10) { - x = (x / 10); - n = (n + 1); - } - return n; -} - -pub fn put_dec(out: &mut [u8], at: usize, v: u64) -> usize { - let n: usize = dec_len(v); - let mut x: u64 = v; - let mut k: usize = n; - while (k > 0) { - let db: u8 = (((x % 10) + 48) as _); - out[(((at + k) - 1)) as usize] = db; - x = (x / 10); - k = (k - 1); - } - return (at + n); -} - -pub fn put_ind(out: &mut [u8], at: usize, n: usize) -> usize { - let mut k: usize = 0; - while (k < n) { - out[((at + k)) as usize] = 32; - k = (k + 1); - } - return (at + n); -} - pub fn put_i64(out: &mut [u8], at: usize, v: i64) -> usize { if (v < 0) { let mut q: usize = put_text(out, at, "(-"); @@ -91,24 +32,6 @@ pub fn put_sign(out: &mut [u8], at: usize, t: i64) -> usize { return put_text(out, at, ", false)"); } -pub fn line_near(nodes: &[u8], meta: &[u8], i: usize) -> usize { - let mut j: usize = i; - while (j < end(nodes, i)) { - if (line_of(meta, j) != 0) { - return line_of(meta, j); - } - j = (j + 1); - } - let mut k: usize = i; - while (k > 0) { - k = (k - 1); - if (line_of(meta, k) != 0) { - return line_of(meta, k); - } - } - return 0; -} - pub fn fail(out: &mut [u8], nodes: &[u8], meta: &[u8], text: &[u8], i: usize, what: &'static str, a: usize, b: usize) -> i64 { let base: usize = (out.len() - MSG_ROOM); let mut q: usize = put_text(out, base, "t27b: ts: unsupported construct "); @@ -128,17 +51,6 @@ pub fn fail(out: &mut [u8], nodes: &[u8], meta: &[u8], text: &[u8], i: usize, wh return (0 - len); } -pub fn to_front(out: &mut [u8], n: usize) -> i64 { - let base: usize = (out.len() - MSG_ROOM); - let mut k: usize = 0; - while (k < n) { - out[(k) as usize] = out[((base + k)) as usize]; - k = (k + 1); - } - let ni: i64 = (n as _); - return (0 - ni); -} - pub fn fail_front(out: &mut [u8], what: &'static str) -> i64 { let mut q: usize = put_text(out, 0, "t27b: ts: unsupported construct "); q = put_text(out, q, what); @@ -180,64 +92,6 @@ pub fn bad_name(s: &[u8], a: usize, b: usize) -> bool { return ts_reserved(&s[(a) as usize..(b) as usize]); } -pub fn child_holding(nodes: &[u8], c: usize, d: usize) -> usize { - let mut x: usize = (c + 1); - while (x < end(nodes, c)) { - if (d < end(nodes, x)) { - return x; - } - x = end(nodes, x); - } - return c; -} - -pub fn parent_of(nodes: &[u8], root: usize, d: usize) -> usize { - let mut cur: usize = root; - while true { - let nx: usize = child_holding(nodes, cur, d); - if ((nx == d) || (nx == cur)) { - return cur; - } - cur = nx; - } - return cur; -} - -pub fn in_scope(nodes: &[u8], item: usize, d: usize, u: usize) -> bool { - if ((d >= u) || (u < end(nodes, d))) { - return false; - } - let pb: usize = parent_of(nodes, item, d); - return (u < end(nodes, pb)); -} - -pub fn param_index(text: &[u8], meta: &[u8], ptext: &[u8], item: usize, a: usize, b: usize) -> i64 { - let pa: usize = params_lo(meta, item); - let pb: usize = params_hi(meta, item); - let mut k: usize = 0; - let mut s: usize = pa; - while (s < pb) { - let e: usize = line_stop(ptext, s, pb); - let c: usize = colon_at(ptext, s, e); - if (((c - s) == (b - a)) && has_at(ptext, s, c, &text[(a) as usize..(b) as usize])) { - let ki: i64 = (k as _); - return ki; - } - k = (k + 1); - s = (e + 1); - } - return -(1); -} - -pub fn param_name_lo(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { - return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); -} - -pub fn param_name_hi(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { - let s: usize = param_name_lo(meta, ptext, item, k); - return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); -} - pub fn param_type(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> i64 { let s: usize = param_name_lo(meta, ptext, item, k); let e: usize = line_stop(ptext, s, params_hi(meta, item)); @@ -248,52 +102,11 @@ pub fn param_type(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> i64 { return ts_type(ptext, (c + 1), e); } -pub fn resolve(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, u: usize, a: usize, b: usize) -> i64 { - if (item > 0) { - let mut j: usize = u; - while (j > (item + 1)) { - j = (j - 1); - if ((kind(nodes, j) == K_STMT_LOCAL) && field_is(nodes, text, j, F_NAME, &text[(a) as usize..(b) as usize])) { - if in_scope(nodes, item, j, u) { - let ji: i64 = (j as _); - return ((SYM_LOCAL * SYM_UNIT) + ji); - } - } - } - if (kind(nodes, item) == K_FN_DECL) { - let pk: i64 = param_index(text, meta, ptext, item, a, b); - if (pk >= 0) { - return ((SYM_PARAM * SYM_UNIT) + pk); - } - } - } - let d: i64 = find_decl(nodes, text, a, b); - if (d != NO_NODE) { - return ((SYM_TOP * SYM_UNIT) + d); - } - let f: i64 = find_fn(nodes, text, a, b); - if (f != NO_NODE) { - return ((SYM_FN * SYM_UNIT) + f); - } - return NO_SYM; -} - -pub fn sym_of(tag: i64, at: usize) -> i64 { - let ai: i64 = (at as _); - return ((tag * SYM_UNIT) + ai); -} - pub fn sym_tag(s: i64) -> i64 { let t: i64 = (s / SYM_UNIT); return t; } -pub fn sym_at(s: i64) -> usize { - let r: i64 = (s % SYM_UNIT); - let ru: usize = (r as _); - return ru; -} - pub fn sym_type(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, s: i64, depth: usize) -> i64 { let tg: i64 = sym_tag(s); let at: usize = sym_at(s); @@ -1500,41 +1313,6 @@ pub fn emit(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], work: impl AsR return rq; } -pub fn tnode(buf: &mut [u8], i: usize, k: u8, e: usize, a: usize, b: usize) -> () { - buf[((i * REC)) as usize] = k; - vput32(buf, ((i * REC) + 4), e); - let mut f: usize = 0; - while (f < FIELDS) { - vput32(buf, (((i * REC) + 8) + (f * 8)), 0); - vput32(buf, (((i * REC) + 12) + (f * 8)), 0); - f = (f + 1); - } - vput32(buf, ((i * REC) + 8), a); - vput32(buf, ((i * REC) + 12), b); -} - -pub fn tmeta(m: &mut [u8], i: usize, flags: usize, line: usize) -> () { - vput32(m, (i * META), flags); - vput32(m, ((i * META) + 4), line); - vput32(m, ((i * META) + 8), 0); - vput32(m, ((i * META) + 12), 0); -} - -pub fn holds(out: &[u8], n: usize, w: &'static str) -> bool { - let mut i: usize = 0; - while ((i + w.len()) <= n) { - let mut k: usize = 0; - while ((k < w.len()) && (out[((i + k)) as usize] == w.as_bytes()[(k) as usize])) { - k = (k + 1); - } - if (k == w.len()) { - return true; - } - i = (i + 1); - } - return false; -} - pub fn ttree(nb: &mut [u8], mb: &mut [u8], ca: usize, cb: usize) -> () { tnode(nb, 0, K_MODULE, 13, 0, 1); tnode(nb, 1, K_FN_DECL, 6, 1, 2); @@ -1726,6 +1504,228 @@ pub fn u32_at(nodes: &[u8], at: usize) -> usize { return (((b0 + (b1 * 256)) + (b2 * 65536)) + (b3 * 16777216)); } +pub const MSG_ROOM: usize = 400; + +pub const NAME_CAP: usize = 120; + +pub const NO_SYM: i64 = -1; + +pub const SYM_FN: i64 = 4; + +pub const SYM_LOCAL: i64 = 1; + +pub const SYM_PARAM: i64 = 2; + +pub const SYM_TOP: i64 = 3; + +pub const SYM_UNIT: i64 = 1099511627776; + +pub fn child_holding(nodes: &[u8], c: usize, d: usize) -> usize { + let mut x: usize = (c + 1); + while (x < end(nodes, c)) { + if (d < end(nodes, x)) { + return x; + } + x = end(nodes, x); + } + return c; +} + +pub fn dec_len(v: u64) -> usize { + let mut n: usize = 1; + let mut x: u64 = v; + while (x >= 10) { + x = (x / 10); + n = (n + 1); + } + return n; +} + +pub fn holds(out: &[u8], n: usize, w: &'static str) -> bool { + let mut i: usize = 0; + while ((i + w.len()) <= n) { + let mut k: usize = 0; + while ((k < w.len()) && (out[((i + k)) as usize] == w.as_bytes()[(k) as usize])) { + k = (k + 1); + } + if (k == w.len()) { + return true; + } + i = (i + 1); + } + return false; +} + +pub fn in_scope(nodes: &[u8], item: usize, d: usize, u: usize) -> bool { + if ((d >= u) || (u < end(nodes, d))) { + return false; + } + let pb: usize = parent_of(nodes, item, d); + return (u < end(nodes, pb)); +} + +pub fn line_near(nodes: &[u8], meta: &[u8], i: usize) -> usize { + let mut j: usize = i; + while (j < end(nodes, i)) { + if (line_of(meta, j) != 0) { + return line_of(meta, j); + } + j = (j + 1); + } + let mut k: usize = i; + while (k > 0) { + k = (k - 1); + if (line_of(meta, k) != 0) { + return line_of(meta, k); + } + } + return 0; +} + +pub fn param_index(text: &[u8], meta: &[u8], ptext: &[u8], item: usize, a: usize, b: usize) -> i64 { + let pa: usize = params_lo(meta, item); + let pb: usize = params_hi(meta, item); + let mut k: usize = 0; + let mut s: usize = pa; + while (s < pb) { + let e: usize = line_stop(ptext, s, pb); + let c: usize = colon_at(ptext, s, e); + if (((c - s) == (b - a)) && has_at(ptext, s, c, &text[(a) as usize..(b) as usize])) { + let ki: i64 = (k as _); + return ki; + } + k = (k + 1); + s = (e + 1); + } + return -(1); +} + +pub fn param_name_hi(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { + let s: usize = param_name_lo(meta, ptext, item, k); + return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); +} + +pub fn param_name_lo(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { + return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); +} + +pub fn parent_of(nodes: &[u8], root: usize, d: usize) -> usize { + let mut cur: usize = root; + while true { + let nx: usize = child_holding(nodes, cur, d); + if ((nx == d) || (nx == cur)) { + return cur; + } + cur = nx; + } + return cur; +} + +pub fn put_bytes(out: &mut [u8], at: usize, s: &[u8], a: usize, b: usize) -> usize { + let mut k: usize = a; + let mut q: usize = at; + while (k < b) { + out[(q) as usize] = s[(k) as usize]; + q = (q + 1); + k = (k + 1); + } + return q; +} + +pub fn put_dec(out: &mut [u8], at: usize, v: u64) -> usize { + let n: usize = dec_len(v); + let mut x: u64 = v; + let mut k: usize = n; + while (k > 0) { + let db: u8 = (((x % 10) + 48) as _); + out[(((at + k) - 1)) as usize] = db; + x = (x / 10); + k = (k - 1); + } + return (at + n); +} + +pub fn put_ind(out: &mut [u8], at: usize, n: usize) -> usize { + let mut k: usize = 0; + while (k < n) { + out[((at + k)) as usize] = 32; + k = (k + 1); + } + return (at + n); +} + +pub fn resolve(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, u: usize, a: usize, b: usize) -> i64 { + if (item > 0) { + let mut j: usize = u; + while (j > (item + 1)) { + j = (j - 1); + if ((kind(nodes, j) == K_STMT_LOCAL) && field_is(nodes, text, j, F_NAME, &text[(a) as usize..(b) as usize])) { + if in_scope(nodes, item, j, u) { + let ji: i64 = (j as _); + return ((SYM_LOCAL * SYM_UNIT) + ji); + } + } + } + if (kind(nodes, item) == K_FN_DECL) { + let pk: i64 = param_index(text, meta, ptext, item, a, b); + if (pk >= 0) { + return ((SYM_PARAM * SYM_UNIT) + pk); + } + } + } + let d: i64 = find_decl(nodes, text, a, b); + if (d != NO_NODE) { + return ((SYM_TOP * SYM_UNIT) + d); + } + let f: i64 = find_fn(nodes, text, a, b); + if (f != NO_NODE) { + return ((SYM_FN * SYM_UNIT) + f); + } + return NO_SYM; +} + +pub fn sym_at(s: i64) -> usize { + let r: i64 = (s % SYM_UNIT); + let ru: usize = (r as _); + return ru; +} + +pub fn sym_of(tag: i64, at: usize) -> i64 { + let ai: i64 = (at as _); + return ((tag * SYM_UNIT) + ai); +} + +pub fn tmeta(m: &mut [u8], i: usize, flags: usize, line: usize) -> () { + vput32(m, (i * META), flags); + vput32(m, ((i * META) + 4), line); + vput32(m, ((i * META) + 8), 0); + vput32(m, ((i * META) + 12), 0); +} + +pub fn tnode(buf: &mut [u8], i: usize, k: u8, e: usize, a: usize, b: usize) -> () { + buf[((i * REC)) as usize] = k; + vput32(buf, ((i * REC) + 4), e); + let mut f: usize = 0; + while (f < FIELDS) { + vput32(buf, (((i * REC) + 8) + (f * 8)), 0); + vput32(buf, (((i * REC) + 12) + (f * 8)), 0); + f = (f + 1); + } + vput32(buf, ((i * REC) + 8), a); + vput32(buf, ((i * REC) + 12), b); +} + +pub fn to_front(out: &mut [u8], n: usize) -> i64 { + let base: usize = (out.len() - MSG_ROOM); + let mut k: usize = 0; + while (k < n) { + out[(k) as usize] = out[((base + k)) as usize]; + k = (k + 1); + } + let ni: i64 = (n as _); + return (0 - ni); +} + pub fn put_text(out: &mut [u8], at: usize, w: &'static str) -> usize { let mut k: usize = 0; while (k < w.len()) { diff --git a/gen/rust/tri/t27b/verilog_emit.rs b/gen/rust/tri/t27b/verilog_emit.rs index 8992e27097..516efcca8f 100644 --- a/gen/rust/tri/t27b/verilog_emit.rs +++ b/gen/rust/tri/t27b/verilog_emit.rs @@ -14,65 +14,6 @@ pub const M_TEST: u8 = 3; pub const M_TBFUNC: u8 = 4; -pub const MSG_ROOM: usize = 400; - -pub const NAME_CAP: usize = 120; - -pub const SYM_UNIT: i64 = 1099511627776; - -pub const SYM_LOCAL: i64 = 1; - -pub const SYM_PARAM: i64 = 2; - -pub const SYM_TOP: i64 = 3; - -pub const SYM_FN: i64 = 4; - -pub const NO_SYM: i64 = -1; - -pub fn put_bytes(out: &mut [u8], at: usize, s: &[u8], a: usize, b: usize) -> usize { - let mut k: usize = a; - let mut q: usize = at; - while (k < b) { - out[(q) as usize] = s[(k) as usize]; - q = (q + 1); - k = (k + 1); - } - return q; -} - -pub fn dec_len(v: u64) -> usize { - let mut n: usize = 1; - let mut x: u64 = v; - while (x >= 10) { - x = (x / 10); - n = (n + 1); - } - return n; -} - -pub fn put_dec(out: &mut [u8], at: usize, v: u64) -> usize { - let n: usize = dec_len(v); - let mut x: u64 = v; - let mut k: usize = n; - while (k > 0) { - let db: u8 = (((x % 10) + 48) as _); - out[(((at + k) - 1)) as usize] = db; - x = (x / 10); - k = (k - 1); - } - return (at + n); -} - -pub fn put_ind(out: &mut [u8], at: usize, n: usize) -> usize { - let mut k: usize = 0; - while (k < n) { - out[((at + k)) as usize] = 32; - k = (k + 1); - } - return (at + n); -} - pub fn put_name(out: &mut [u8], at: usize, text: &[u8], a: usize, b: usize) -> usize { if verilog_keyword(&text[(a) as usize..(b) as usize]) { let mut q: usize = put_text(out, at, "\\"); @@ -106,24 +47,6 @@ pub fn put_lit(out: &mut [u8], at: usize, v: u64, t: i64) -> usize { return put_dec(out, q, v); } -pub fn line_near(nodes: &[u8], meta: &[u8], i: usize) -> usize { - let mut j: usize = i; - while (j < end(nodes, i)) { - if (line_of(meta, j) != 0) { - return line_of(meta, j); - } - j = (j + 1); - } - let mut k: usize = i; - while (k > 0) { - k = (k - 1); - if (line_of(meta, k) != 0) { - return line_of(meta, k); - } - } - return 0; -} - pub fn fail(out: &mut [u8], nodes: &[u8], meta: &[u8], text: &[u8], i: usize, what: &'static str, a: usize, b: usize) -> i64 { let base: usize = (out.len() - MSG_ROOM); let mut q: usize = put_text(out, base, "t27b: verilog: unsupported construct "); @@ -153,75 +76,6 @@ pub fn copy_msg(out: &mut [u8], at: usize, n: usize) -> usize { return (at + n); } -pub fn to_front(out: &mut [u8], n: usize) -> i64 { - let base: usize = (out.len() - MSG_ROOM); - let mut k: usize = 0; - while (k < n) { - out[(k) as usize] = out[((base + k)) as usize]; - k = (k + 1); - } - let ni: i64 = (n as _); - return (0 - ni); -} - -pub fn child_holding(nodes: &[u8], c: usize, d: usize) -> usize { - let mut x: usize = (c + 1); - while (x < end(nodes, c)) { - if (d < end(nodes, x)) { - return x; - } - x = end(nodes, x); - } - return c; -} - -pub fn parent_of(nodes: &[u8], root: usize, d: usize) -> usize { - let mut cur: usize = root; - while true { - let nx: usize = child_holding(nodes, cur, d); - if ((nx == d) || (nx == cur)) { - return cur; - } - cur = nx; - } - return cur; -} - -pub fn in_scope(nodes: &[u8], item: usize, d: usize, u: usize) -> bool { - if ((d >= u) || (u < end(nodes, d))) { - return false; - } - let pb: usize = parent_of(nodes, item, d); - return (u < end(nodes, pb)); -} - -pub fn param_index(text: &[u8], meta: &[u8], ptext: &[u8], item: usize, a: usize, b: usize) -> i64 { - let pa: usize = params_lo(meta, item); - let pb: usize = params_hi(meta, item); - let mut k: usize = 0; - let mut s: usize = pa; - while (s < pb) { - let e: usize = line_stop(ptext, s, pb); - let c: usize = colon_at(ptext, s, e); - if (((c - s) == (b - a)) && has_at(ptext, s, c, &text[(a) as usize..(b) as usize])) { - let ki: i64 = (k as _); - return ki; - } - k = (k + 1); - s = (e + 1); - } - return -(1); -} - -pub fn param_name_lo(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { - return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); -} - -pub fn param_name_hi(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { - let s: usize = param_name_lo(meta, ptext, item, k); - return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); -} - pub fn param_type(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, k: usize) -> i64 { let s: usize = param_name_lo(meta, ptext, item, k); let e: usize = line_stop(ptext, s, params_hi(meta, item)); @@ -232,51 +86,10 @@ pub fn param_type(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: us return type_code(ptext, (c + 1), e); } -pub fn resolve(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, u: usize, a: usize, b: usize) -> i64 { - if (item > 0) { - let mut j: usize = u; - while (j > (item + 1)) { - j = (j - 1); - if ((kind(nodes, j) == K_STMT_LOCAL) && field_is(nodes, text, j, F_NAME, &text[(a) as usize..(b) as usize])) { - if in_scope(nodes, item, j, u) { - let ji: i64 = (j as _); - return ((SYM_LOCAL * SYM_UNIT) + ji); - } - } - } - if (kind(nodes, item) == K_FN_DECL) { - let pk: i64 = param_index(text, meta, ptext, item, a, b); - if (pk >= 0) { - return ((SYM_PARAM * SYM_UNIT) + pk); - } - } - } - let d: i64 = find_decl(nodes, text, a, b); - if (d != NO_NODE) { - return ((SYM_TOP * SYM_UNIT) + d); - } - let f: i64 = find_fn(nodes, text, a, b); - if (f != NO_NODE) { - return ((SYM_FN * SYM_UNIT) + f); - } - return NO_SYM; -} - -pub fn sym_of(tag: i64, at: usize) -> i64 { - let ai: i64 = (at as _); - return ((tag * SYM_UNIT) + ai); -} - pub fn sym_tag(s: i64) -> i64 { return (s / SYM_UNIT); } -pub fn sym_at(s: i64) -> usize { - let r: i64 = (s % SYM_UNIT); - let ru: usize = (r as _); - return ru; -} - pub fn named_type(nodes: &[u8], text: &[u8], a: usize, b: usize) -> i64 { let t: i64 = type_code(text, a, b); if (t != TY_BAD) { @@ -2528,41 +2341,6 @@ pub fn fail_front(out: &mut [u8], what: &'static str) -> i64 { return (0 - l); } -pub fn tnode(buf: &mut [u8], i: usize, k: u8, e: usize, a: usize, b: usize) -> () { - buf[((i * REC)) as usize] = k; - vput32(buf, ((i * REC) + 4), e); - let mut f: usize = 0; - while (f < FIELDS) { - vput32(buf, (((i * REC) + 8) + (f * 8)), 0); - vput32(buf, (((i * REC) + 12) + (f * 8)), 0); - f = (f + 1); - } - vput32(buf, ((i * REC) + 8), a); - vput32(buf, ((i * REC) + 12), b); -} - -pub fn tmeta(m: &mut [u8], i: usize, flags: usize, line: usize) -> () { - vput32(m, (i * META), flags); - vput32(m, ((i * META) + 4), line); - vput32(m, ((i * META) + 8), 0); - vput32(m, ((i * META) + 12), 0); -} - -pub fn holds(out: &[u8], n: usize, w: &'static str) -> bool { - let mut i: usize = 0; - while ((i + w.len()) <= n) { - let mut k: usize = 0; - while ((k < w.len()) && (out[((i + k)) as usize] == w.as_bytes()[(k) as usize])) { - k = (k + 1); - } - if (k == w.len()) { - return true; - } - i = (i + 1); - } - return false; -} - pub fn tied_counter(nb: &mut [u8], mb: &mut [u8], rv_in: bool, rv_lo: usize, rv_hi: usize, ev_lo: usize, ev_hi: usize) -> () { tnode(nb, 0, K_MODULE, 13, 0, 1); tnode(nb, 1, K_CONST_DECL, 3, 1, 2); @@ -2761,6 +2539,228 @@ pub fn u32_at(nodes: &[u8], at: usize) -> usize { return (((b0 + (b1 * 256)) + (b2 * 65536)) + (b3 * 16777216)); } +pub const MSG_ROOM: usize = 400; + +pub const NAME_CAP: usize = 120; + +pub const NO_SYM: i64 = -1; + +pub const SYM_FN: i64 = 4; + +pub const SYM_LOCAL: i64 = 1; + +pub const SYM_PARAM: i64 = 2; + +pub const SYM_TOP: i64 = 3; + +pub const SYM_UNIT: i64 = 1099511627776; + +pub fn child_holding(nodes: &[u8], c: usize, d: usize) -> usize { + let mut x: usize = (c + 1); + while (x < end(nodes, c)) { + if (d < end(nodes, x)) { + return x; + } + x = end(nodes, x); + } + return c; +} + +pub fn dec_len(v: u64) -> usize { + let mut n: usize = 1; + let mut x: u64 = v; + while (x >= 10) { + x = (x / 10); + n = (n + 1); + } + return n; +} + +pub fn holds(out: &[u8], n: usize, w: &'static str) -> bool { + let mut i: usize = 0; + while ((i + w.len()) <= n) { + let mut k: usize = 0; + while ((k < w.len()) && (out[((i + k)) as usize] == w.as_bytes()[(k) as usize])) { + k = (k + 1); + } + if (k == w.len()) { + return true; + } + i = (i + 1); + } + return false; +} + +pub fn in_scope(nodes: &[u8], item: usize, d: usize, u: usize) -> bool { + if ((d >= u) || (u < end(nodes, d))) { + return false; + } + let pb: usize = parent_of(nodes, item, d); + return (u < end(nodes, pb)); +} + +pub fn line_near(nodes: &[u8], meta: &[u8], i: usize) -> usize { + let mut j: usize = i; + while (j < end(nodes, i)) { + if (line_of(meta, j) != 0) { + return line_of(meta, j); + } + j = (j + 1); + } + let mut k: usize = i; + while (k > 0) { + k = (k - 1); + if (line_of(meta, k) != 0) { + return line_of(meta, k); + } + } + return 0; +} + +pub fn param_index(text: &[u8], meta: &[u8], ptext: &[u8], item: usize, a: usize, b: usize) -> i64 { + let pa: usize = params_lo(meta, item); + let pb: usize = params_hi(meta, item); + let mut k: usize = 0; + let mut s: usize = pa; + while (s < pb) { + let e: usize = line_stop(ptext, s, pb); + let c: usize = colon_at(ptext, s, e); + if (((c - s) == (b - a)) && has_at(ptext, s, c, &text[(a) as usize..(b) as usize])) { + let ki: i64 = (k as _); + return ki; + } + k = (k + 1); + s = (e + 1); + } + return -(1); +} + +pub fn param_name_hi(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { + let s: usize = param_name_lo(meta, ptext, item, k); + return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); +} + +pub fn param_name_lo(meta: &[u8], ptext: &[u8], item: usize, k: usize) -> usize { + return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); +} + +pub fn parent_of(nodes: &[u8], root: usize, d: usize) -> usize { + let mut cur: usize = root; + while true { + let nx: usize = child_holding(nodes, cur, d); + if ((nx == d) || (nx == cur)) { + return cur; + } + cur = nx; + } + return cur; +} + +pub fn put_bytes(out: &mut [u8], at: usize, s: &[u8], a: usize, b: usize) -> usize { + let mut k: usize = a; + let mut q: usize = at; + while (k < b) { + out[(q) as usize] = s[(k) as usize]; + q = (q + 1); + k = (k + 1); + } + return q; +} + +pub fn put_dec(out: &mut [u8], at: usize, v: u64) -> usize { + let n: usize = dec_len(v); + let mut x: u64 = v; + let mut k: usize = n; + while (k > 0) { + let db: u8 = (((x % 10) + 48) as _); + out[(((at + k) - 1)) as usize] = db; + x = (x / 10); + k = (k - 1); + } + return (at + n); +} + +pub fn put_ind(out: &mut [u8], at: usize, n: usize) -> usize { + let mut k: usize = 0; + while (k < n) { + out[((at + k)) as usize] = 32; + k = (k + 1); + } + return (at + n); +} + +pub fn resolve(nodes: &[u8], text: &[u8], meta: &[u8], ptext: &[u8], item: usize, u: usize, a: usize, b: usize) -> i64 { + if (item > 0) { + let mut j: usize = u; + while (j > (item + 1)) { + j = (j - 1); + if ((kind(nodes, j) == K_STMT_LOCAL) && field_is(nodes, text, j, F_NAME, &text[(a) as usize..(b) as usize])) { + if in_scope(nodes, item, j, u) { + let ji: i64 = (j as _); + return ((SYM_LOCAL * SYM_UNIT) + ji); + } + } + } + if (kind(nodes, item) == K_FN_DECL) { + let pk: i64 = param_index(text, meta, ptext, item, a, b); + if (pk >= 0) { + return ((SYM_PARAM * SYM_UNIT) + pk); + } + } + } + let d: i64 = find_decl(nodes, text, a, b); + if (d != NO_NODE) { + return ((SYM_TOP * SYM_UNIT) + d); + } + let f: i64 = find_fn(nodes, text, a, b); + if (f != NO_NODE) { + return ((SYM_FN * SYM_UNIT) + f); + } + return NO_SYM; +} + +pub fn sym_at(s: i64) -> usize { + let r: i64 = (s % SYM_UNIT); + let ru: usize = (r as _); + return ru; +} + +pub fn sym_of(tag: i64, at: usize) -> i64 { + let ai: i64 = (at as _); + return ((tag * SYM_UNIT) + ai); +} + +pub fn tmeta(m: &mut [u8], i: usize, flags: usize, line: usize) -> () { + vput32(m, (i * META), flags); + vput32(m, ((i * META) + 4), line); + vput32(m, ((i * META) + 8), 0); + vput32(m, ((i * META) + 12), 0); +} + +pub fn tnode(buf: &mut [u8], i: usize, k: u8, e: usize, a: usize, b: usize) -> () { + buf[((i * REC)) as usize] = k; + vput32(buf, ((i * REC) + 4), e); + let mut f: usize = 0; + while (f < FIELDS) { + vput32(buf, (((i * REC) + 8) + (f * 8)), 0); + vput32(buf, (((i * REC) + 12) + (f * 8)), 0); + f = (f + 1); + } + vput32(buf, ((i * REC) + 8), a); + vput32(buf, ((i * REC) + 12), b); +} + +pub fn to_front(out: &mut [u8], n: usize) -> i64 { + let base: usize = (out.len() - MSG_ROOM); + let mut k: usize = 0; + while (k < n) { + out[(k) as usize] = out[((base + k)) as usize]; + k = (k + 1); + } + let ni: i64 = (n as _); + return (0 - ni); +} + pub fn put_text(out: &mut [u8], at: usize, w: &'static str) -> usize { let mut k: usize = 0; while (k < w.len()) { diff --git a/specs/tri/t27b/emit_kit.t27 b/specs/tri/t27b/emit_kit.t27 new file mode 100644 index 0000000000..d370f19de7 --- /dev/null +++ b/specs/tri/t27b/emit_kit.t27 @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: Apache-2.0 +; specs/tri/t27b/emit_kit.t27 -- what the source writers of t27b share: verilog_emit.t27 (`t27b verilog`) +; and ts_emit.t27 (`t27b ts`, issue #9994). Both walk the t27c AST of one spec, as `flat` in +; cli/t27b/src/lower.rs writes it (specs/tri/t27b/ast_walk.t27), and both wrote these helpers out word for +; word until tools/dupe_scan.py refused the second copy. A body written twice is a bug fixed twice. +; -- +; Here: the byte writers (put_bytes, put_dec, put_ind), the line a refusal quotes (line_near), moving a +; refusal written at the end of the output to its front (to_front), the scope and name resolver (resolve: +; a local in scope, a parameter, a top-level declaration, a fn) with its symbol encoding, and the builders +; of the hand-made trees their tests run on (tnode, tmeta, holds). Each writer keeps its own `fail`, since +; the backend's name is in its message. +; -- +; A writer must `use` this module by name: the splice pulls a name only when the writer does not declare it +; itself, and gen-rust type-checks every declaration it pulls, so a whole-module `use` of the other writer +; pulls that writer's fns too (any word in a string literal counts as a reference). +; ASCII only (L3) +; phi^2 + 1/phi^2 = 3 | TRINITY + +module T27bEmitKit; + +use tri::t27b::verilog_plan; + +/// The room at the end of `out` a refusal is first written to, so the text before it survives. +pub const MSG_ROOM : usize = 400; +/// The longest name a refusal quotes. +pub const NAME_CAP : usize = 120; + +/// Symbols: a resolved name is a tag times SYM_UNIT plus a node index (a parameter: its position). +pub const SYM_UNIT : i64 = 1099511627776; +pub const SYM_LOCAL : i64 = 1; +pub const SYM_PARAM : i64 = 2; +pub const SYM_TOP : i64 = 3; +pub const SYM_FN : i64 = 4; +pub const NO_SYM : i64 = -1; + +// ---------------------------------------------------------------------------------------------------------- +// Writing bytes and placing a refusal. +// ---------------------------------------------------------------------------------------------------------- + +/// Writes s[a .. b] at out[at ..]. +pub fn put_bytes(out: []u8, at: usize, s: []const u8, a: usize, b: usize) -> usize { + var k : usize = a; + var q : usize = at; + while (k < b) { + out[q] = s[k]; + q = q + 1; + k = k + 1; + } + return q; +} + +/// How many decimal digits v has. +pub fn dec_len(v: u64) -> usize { + var n : usize = 1; + var x : u64 = v; + while (x >= 10) { + x = x / 10; + n = n + 1; + } + return n; +} + +/// Writes v in decimal. +pub fn put_dec(out: []u8, at: usize, v: u64) -> usize { + const n : usize = dec_len(v); + var x : u64 = v; + var k : usize = n; + while (k > 0) { + const db : u8 = @intCast(x % 10 + 48); + out[at + k - 1] = db; + x = x / 10; + k = k - 1; + } + return at + n; +} + +/// Writes n spaces. +pub fn put_ind(out: []u8, at: usize, n: usize) -> usize { + var k : usize = 0; + while (k < n) { + out[at + k] = 32; + k = k + 1; + } + return at + n; +} + +/// The first non-zero source line at or after node i within its subtree, else the nearest one before it. +pub fn line_near(nodes: []const u8, meta: []const u8, i: usize) -> usize { + var j : usize = i; + while (j < end(nodes, i)) { + if (line_of(meta, j) != 0) { return line_of(meta, j); } + j = j + 1; + } + var k : usize = i; + while (k > 0) { + k = k - 1; + if (line_of(meta, k) != 0) { return line_of(meta, k); } + } + return 0; +} + +/// Copies the refusal of length n from the end of out to its start; returns minus n. +pub fn to_front(out: []u8, n: usize) -> i64 { + const base : usize = out.len - MSG_ROOM; + var k : usize = 0; + while (k < n) { + out[k] = out[base + k]; + k = k + 1; + } + const ni : i64 = @intCast(n); + return 0 - ni; +} + +// ---------------------------------------------------------------------------------------------------------- +// Scopes and names. +// ---------------------------------------------------------------------------------------------------------- + +/// The child of node c that holds node d in its subtree (c < d < end(c)). +pub fn child_holding(nodes: []const u8, c: usize, d: usize) -> usize { + var x : usize = c + 1; + while (x < end(nodes, c)) { + if (d < end(nodes, x)) { return x; } + x = end(nodes, x); + } + return c; +} + +/// The node whose direct child d is, searching down from `root` (root < d). +pub fn parent_of(nodes: []const u8, root: usize, d: usize) -> usize { + var cur : usize = root; + while (true) { + const nx : usize = child_holding(nodes, cur, d); + if (nx == d or nx == cur) { return cur; } + cur = nx; + } + return cur; +} + +/// Is the local declared at node d (under item) in scope at node u: d comes before u, u is not in d's own +/// initializer, and d's enclosing block holds u? +pub fn in_scope(nodes: []const u8, item: usize, d: usize, u: usize) -> bool { + if (d >= u or u < end(nodes, d)) { return false; } + const pb : usize = parent_of(nodes, item, d); + return u < end(nodes, pb); +} + +/// The position of the parameter named text[a .. b] in fn `item`'s parameter lines, or -1. +pub fn param_index(text: []const u8, meta: []const u8, ptext: []const u8, item: usize, a: usize, b: usize) -> i64 { + const pa : usize = params_lo(meta, item); + const pb : usize = params_hi(meta, item); + var k : usize = 0; + var s : usize = pa; + while (s < pb) { + const e : usize = line_stop(ptext, s, pb); + const c : usize = colon_at(ptext, s, e); + if (c - s == b - a and has_at(ptext, s, c, text[a .. b])) { + const ki : i64 = @intCast(k); + return ki; + } + k = k + 1; + s = e + 1; + } + return -1; +} + +/// Where parameter k's name starts in the params text of `item`. +pub fn param_name_lo(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { + return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); +} + +/// Where parameter k's name ends. +pub fn param_name_hi(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { + const s : usize = param_name_lo(meta, ptext, item, k); + return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); +} + +/// Resolves the name text[a .. b] used at node u inside `item` (a fn, a test or an invariant; 0 for the +/// module scope): a local in scope, a parameter of item, a top-level declaration, or a top-level fn. NO_SYM +/// when there is none. +pub fn resolve(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []const u8, item: usize, u: usize, a: usize, b: usize) -> i64 { + if (item > 0) { + var j : usize = u; + while (j > item + 1) { + j = j - 1; + if (kind(nodes, j) == K_STMT_LOCAL and field_is(nodes, text, j, F_NAME, text[a .. b])) { + if (in_scope(nodes, item, j, u)) { + const ji : i64 = @intCast(j); + return SYM_LOCAL * SYM_UNIT + ji; + } + } + } + if (kind(nodes, item) == K_FN_DECL) { + const pk : i64 = param_index(text, meta, ptext, item, a, b); + if (pk >= 0) { return SYM_PARAM * SYM_UNIT + pk; } + } + } + const d : i64 = find_decl(nodes, text, a, b); + if (d != NO_NODE) { return SYM_TOP * SYM_UNIT + d; } + const f : i64 = find_fn(nodes, text, a, b); + if (f != NO_NODE) { return SYM_FN * SYM_UNIT + f; } + return NO_SYM; +} + +/// The symbol of tag `tag` at node (or parameter position) `at`. +pub fn sym_of(tag: i64, at: usize) -> i64 { + const ai : i64 = @intCast(at); + return tag * SYM_UNIT + ai; +} + +/// The node index (or parameter position) of a symbol. +pub fn sym_at(s: i64) -> usize { + const r : i64 = @rem(s, SYM_UNIT); + const ru : usize = @intCast(r); + return ru; +} + +// ---------------------------------------------------------------------------------------------------------- +// Hand-made trees for the writers' tests: ast_walk.t27's node records and verilog_plan.t27's meta records. +// ---------------------------------------------------------------------------------------------------------- + +/// Node i: kind k, subtree end e, name text[a .. b], every other field empty. +pub fn tnode(buf: []u8, i: usize, k: u8, e: usize, a: usize, b: usize) -> void { + buf[i * REC] = k; + vput32(buf, i * REC + 4, e); + var f : usize = 0; + while (f < FIELDS) { + vput32(buf, i * REC + 8 + f * 8, 0); + vput32(buf, i * REC + 12 + f * 8, 0); + f = f + 1; + } + vput32(buf, i * REC + 8, a); + vput32(buf, i * REC + 12, b); +} + +/// Node i's meta record: flags, line, no parameters. +pub fn tmeta(m: []u8, i: usize, flags: usize, line: usize) -> void { + vput32(m, i * META, flags); + vput32(m, i * META + 4, line); + vput32(m, i * META + 8, 0); + vput32(m, i * META + 12, 0); +} + +/// Does out[0 .. n] hold w? +pub fn holds(out: []const u8, n: usize, w: str) -> bool { + var i : usize = 0; + while (i + w.len <= n) { + var k : usize = 0; + while (k < w.len and out[i + k] == w[k]) { k = k + 1; } + if (k == w.len) { return true; } + i = i + 1; + } + return false; +} + +// ---------------------------------------------------------------------------------------------------------- +// Tests. +// ---------------------------------------------------------------------------------------------------------- + +test bytes_and_numbers_are_written_where_asked { + var out : [64]u8 = undefined; + const n0 : usize = put_dec(out[0 .. 64], 0, 0); + assert n0 == 1 and out[0] == 48; + const n1 : usize = put_dec(out[0 .. 64], 3, 4294967295); + assert n1 == 13 and holds(out[0 .. 64], n1, "4294967295"); + const n2 : usize = put_ind(out[0 .. 64], 0, 4); + assert n2 == 4 and out[0] == 32 and out[3] == 32; + const n3 : usize = put_bytes(out[0 .. 64], n2, "xabcx", 1, 4); + assert n3 == 7 and holds(out[0 .. 64], n3, " abc"); + assert !holds(out[0 .. 64], n3, "abcx"); +} + +test a_refusal_written_at_the_end_moves_to_the_front { + var out : [512]u8 = undefined; + const base : usize = 512 - MSG_ROOM; + const n : usize = put_bytes(out[0 .. 512], base, "no", 0, 2); + const r : i64 = to_front(out[0 .. 512], n - base); + assert r == -2 and out[0] == 110 and out[1] == 111; +} + +test symbols_keep_their_tag_and_position { + const s : i64 = sym_of(SYM_PARAM, 5); + assert sym_at(s) == 5 and s == SYM_PARAM * SYM_UNIT + 5; + assert sym_at(sym_of(SYM_FN, 0)) == 0; +} + +/// The tree of `module M; fn f(x: u8) -> u8 { const y : u8 = 2; return y; }`. +/// text: M 0..1, f 1..2, y 2..3, x 3..4 +fn ktree(nb: []u8, mb: []u8) -> void { + tnode(nb, 0, K_MODULE, 6, 0, 1); + tnode(nb, 1, K_FN_DECL, 6, 1, 2); + tnode(nb, 2, K_STMT_LOCAL, 4, 2, 3); + tnode(nb, 3, K_EXPR_LITERAL, 4, 0, 0); + tnode(nb, 4, K_EXPR_RETURN, 6, 0, 0); + tnode(nb, 5, K_EXPR_IDENTIFIER, 6, 2, 3); + var i : usize = 0; + while (i < 6) { + tmeta(mb, i, 0, 0); + i = i + 1; + } + // fn f, at line 2, with the one parameter line `x:u8` of the params text + tmeta(mb, 1, 0, 2); + vput32(mb, 1 * META + 12, 5); +} + +test names_resolve_to_a_local_in_scope_a_parameter_or_a_fn { + const tx : str = "Mfyx"; + const pt : str = "x:u8\n"; + var nb : [432]u8 = undefined; + var mb : [96]u8 = undefined; + ktree(nb[0 .. 432], mb[0 .. 96]); + // y read by the return is the local at node 2 + assert resolve(nb[0 .. 432], tx, mb[0 .. 96], pt, 1, 5, 2, 3) == SYM_LOCAL * SYM_UNIT + 2; + // y inside its own initializer is not yet in scope + assert resolve(nb[0 .. 432], tx, mb[0 .. 96], pt, 1, 3, 2, 3) == NO_SYM; + assert in_scope(nb[0 .. 432], 1, 2, 5) and !in_scope(nb[0 .. 432], 1, 2, 3); + assert parent_of(nb[0 .. 432], 1, 2) == 1 and child_holding(nb[0 .. 432], 1, 5) == 4; + // x is parameter 0, its name at ptext[0 .. 1] + assert resolve(nb[0 .. 432], tx, mb[0 .. 96], pt, 1, 5, 3, 4) == SYM_PARAM * SYM_UNIT; + assert param_index(tx, mb[0 .. 96], pt, 1, 3, 4) == 0 and param_index(tx, mb[0 .. 96], pt, 1, 2, 3) == -1; + assert param_name_lo(mb[0 .. 96], pt, 1, 0) == 0 and param_name_hi(mb[0 .. 96], pt, 1, 0) == 1; + // f is the fn at node 1 + assert resolve(nb[0 .. 432], tx, mb[0 .. 96], pt, 1, 5, 1, 2) == SYM_FN * SYM_UNIT + 1; + // the line a refusal quotes is the nearest one recorded + assert line_near(nb[0 .. 432], mb[0 .. 96], 1) == 2 and line_near(nb[0 .. 432], mb[0 .. 96], 4) == 2; +} diff --git a/specs/tri/t27b/ts_emit.t27 b/specs/tri/t27b/ts_emit.t27 index e8501d6991..c594304905 100644 --- a/specs/tri/t27b/ts_emit.t27 +++ b/specs/tri/t27b/ts_emit.t27 @@ -29,71 +29,12 @@ module T27bTsEmit; use tri::t27b::ts_plan; use tri::t27b::text_escape; - -/// The room at the end of `out` a refusal is first written to, so the text before it survives. -pub const MSG_ROOM : usize = 400; -/// The longest name a refusal quotes. -pub const NAME_CAP : usize = 120; - -/// Symbols: a resolved name is a tag times SYM_UNIT plus a node index (a parameter: its position). -pub const SYM_UNIT : i64 = 1099511627776; -pub const SYM_LOCAL : i64 = 1; -pub const SYM_PARAM : i64 = 2; -pub const SYM_TOP : i64 = 3; -pub const SYM_FN : i64 = 4; -pub const NO_SYM : i64 = -1; +use tri::t27b::emit_kit; // byte writers, to_front, line_near, resolve and symbols, test trees // ---------------------------------------------------------------------------------------------------------- // Writing bytes. // ---------------------------------------------------------------------------------------------------------- -/// Writes s[a .. b] at out[at ..]. -pub fn put_bytes(out: []u8, at: usize, s: []const u8, a: usize, b: usize) -> usize { - var k : usize = a; - var q : usize = at; - while (k < b) { - out[q] = s[k]; - q = q + 1; - k = k + 1; - } - return q; -} - -/// How many decimal digits v has. -pub fn dec_len(v: u64) -> usize { - var n : usize = 1; - var x : u64 = v; - while (x >= 10) { - x = x / 10; - n = n + 1; - } - return n; -} - -/// Writes v in decimal. -pub fn put_dec(out: []u8, at: usize, v: u64) -> usize { - const n : usize = dec_len(v); - var x : u64 = v; - var k : usize = n; - while (k > 0) { - const db : u8 = @intCast(x % 10 + 48); - out[at + k - 1] = db; - x = x / 10; - k = k - 1; - } - return at + n; -} - -/// Writes n spaces. -pub fn put_ind(out: []u8, at: usize, n: usize) -> usize { - var k : usize = 0; - while (k < n) { - out[at + k] = 32; - k = k + 1; - } - return at + n; -} - /// Writes v in decimal; a negative value in parentheses, `(-5)`, so no operator before it reads it /// otherwise. pub fn put_i64(out: []u8, at: usize, v: i64) -> usize { @@ -122,21 +63,6 @@ pub fn put_sign(out: []u8, at: usize, t: i64) -> usize { return put_text(out, at, ", false)"); } -/// The first non-zero source line at or after node i within its subtree, else the nearest one before it. -pub fn line_near(nodes: []const u8, meta: []const u8, i: usize) -> usize { - var j : usize = i; - while (j < end(nodes, i)) { - if (line_of(meta, j) != 0) { return line_of(meta, j); } - j = j + 1; - } - var k : usize = i; - while (k > 0) { - k = k - 1; - if (line_of(meta, k) != 0) { return line_of(meta, k); } - } - return 0; -} - /// Writes a refusal at the end of out: "t27b: ts: unsupported construct `` at line ", the /// name being text[a .. b] (none when a == b). Returns minus its length. pub fn fail(out: []u8, nodes: []const u8, meta: []const u8, text: []const u8, i: usize, what: str, a: usize, b: usize) -> i64 { @@ -156,18 +82,6 @@ pub fn fail(out: []u8, nodes: []const u8, meta: []const u8, text: []const u8, i: return 0 - len; } -/// Copies the refusal of length n from the end of out to its start; returns minus n. -pub fn to_front(out: []u8, n: usize) -> i64 { - const base : usize = out.len - MSG_ROOM; - var k : usize = 0; - while (k < n) { - out[k] = out[base + k]; - k = k + 1; - } - const ni : i64 = @intCast(n); - return 0 - ni; -} - /// A refusal with no node, written at the front. pub fn fail_front(out: []u8, what: str) -> i64 { var q : usize = put_text(out, 0, "t27b: ts: unsupported construct "); @@ -205,65 +119,6 @@ pub fn bad_name(s: []const u8, a: usize, b: usize) -> bool { return ts_reserved(s[a .. b]); } -/// The child of node c that holds node d in its subtree (c < d < end(c)). -pub fn child_holding(nodes: []const u8, c: usize, d: usize) -> usize { - var x : usize = c + 1; - while (x < end(nodes, c)) { - if (d < end(nodes, x)) { return x; } - x = end(nodes, x); - } - return c; -} - -/// The node whose direct child d is, searching down from `root` (root < d). -pub fn parent_of(nodes: []const u8, root: usize, d: usize) -> usize { - var cur : usize = root; - while (true) { - const nx : usize = child_holding(nodes, cur, d); - if (nx == d or nx == cur) { return cur; } - cur = nx; - } - return cur; -} - -/// Is the local declared at node d (under item) in scope at node u: d comes before u, u is not in d's own -/// initializer, and d's enclosing block holds u? -pub fn in_scope(nodes: []const u8, item: usize, d: usize, u: usize) -> bool { - if (d >= u or u < end(nodes, d)) { return false; } - const pb : usize = parent_of(nodes, item, d); - return u < end(nodes, pb); -} - -/// The position of the parameter named text[a .. b] in fn `item`'s parameter lines, or -1. -pub fn param_index(text: []const u8, meta: []const u8, ptext: []const u8, item: usize, a: usize, b: usize) -> i64 { - const pa : usize = params_lo(meta, item); - const pb : usize = params_hi(meta, item); - var k : usize = 0; - var s : usize = pa; - while (s < pb) { - const e : usize = line_stop(ptext, s, pb); - const c : usize = colon_at(ptext, s, e); - if (c - s == b - a and has_at(ptext, s, c, text[a .. b])) { - const ki : i64 = @intCast(k); - return ki; - } - k = k + 1; - s = e + 1; - } - return -1; -} - -/// Where parameter k's name starts in the params text of `item`. -pub fn param_name_lo(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { - return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); -} - -/// Where parameter k's name ends. -pub fn param_name_hi(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { - const s : usize = param_name_lo(meta, ptext, item, k); - return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); -} - /// The type code of parameter k of `item`. pub fn param_type(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> i64 { const s : usize = param_name_lo(meta, ptext, item, k); @@ -273,52 +128,12 @@ pub fn param_type(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> return ts_type(ptext, c + 1, e); } -/// Resolves the name text[a .. b] used at node u inside `item` (a fn, a test or an invariant; 0 for the -/// module scope): a local in scope, a parameter of item, a top-level declaration, or a top-level fn. NO_SYM -/// when there is none. -pub fn resolve(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []const u8, item: usize, u: usize, a: usize, b: usize) -> i64 { - if (item > 0) { - var j : usize = u; - while (j > item + 1) { - j = j - 1; - if (kind(nodes, j) == K_STMT_LOCAL and field_is(nodes, text, j, F_NAME, text[a .. b])) { - if (in_scope(nodes, item, j, u)) { - const ji : i64 = @intCast(j); - return SYM_LOCAL * SYM_UNIT + ji; - } - } - } - if (kind(nodes, item) == K_FN_DECL) { - const pk : i64 = param_index(text, meta, ptext, item, a, b); - if (pk >= 0) { return SYM_PARAM * SYM_UNIT + pk; } - } - } - const d : i64 = find_decl(nodes, text, a, b); - if (d != NO_NODE) { return SYM_TOP * SYM_UNIT + d; } - const f : i64 = find_fn(nodes, text, a, b); - if (f != NO_NODE) { return SYM_FN * SYM_UNIT + f; } - return NO_SYM; -} - -/// The symbol of tag `tag` at node (or parameter position) `at`. -pub fn sym_of(tag: i64, at: usize) -> i64 { - const ai : i64 = @intCast(at); - return tag * SYM_UNIT + ai; -} - /// The tag of a symbol. pub fn sym_tag(s: i64) -> i64 { const t : i64 = @divTrunc(s, SYM_UNIT); return t; } -/// The node index (or parameter position) of a symbol. -pub fn sym_at(s: i64) -> usize { - const r : i64 = @rem(s, SYM_UNIT); - const ru : usize = @intCast(r); - return ru; -} - /// The type of a symbol (a local, a parameter, a top-level const). pub fn sym_type(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []const u8, item: usize, s: i64, depth: usize) -> i64 { const tg : i64 = sym_tag(s); @@ -1269,40 +1084,6 @@ pub fn emit(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []cons // constant. The expected TypeScript is what ts_plan.t27 decides for it. // ---------------------------------------------------------------------------------------------------------- -/// Node i: kind k, subtree end e, name text[a .. b], every other field empty. -fn tnode(buf: []u8, i: usize, k: u8, e: usize, a: usize, b: usize) -> void { - buf[i * REC] = k; - vput32(buf, i * REC + 4, e); - var f : usize = 0; - while (f < FIELDS) { - vput32(buf, i * REC + 8 + f * 8, 0); - vput32(buf, i * REC + 12 + f * 8, 0); - f = f + 1; - } - vput32(buf, i * REC + 8, a); - vput32(buf, i * REC + 12, b); -} - -/// Node i's meta record: flags, line, no parameters. -fn tmeta(m: []u8, i: usize, flags: usize, line: usize) -> void { - vput32(m, i * META, flags); - vput32(m, i * META + 4, line); - vput32(m, i * META + 8, 0); - vput32(m, i * META + 12, 0); -} - -/// Does out[0 .. n] hold w? -fn holds(out: []const u8, n: usize, w: str) -> bool { - var i : usize = 0; - while (i + w.len <= n) { - var k : usize = 0; - while (k < w.len and out[i + k] == w[k]) { k = k + 1; } - if (k == w.len) { return true; } - i = i + 1; - } - return false; -} - /// The tree of `module M; pub fn f(x: u8) -> u8 { return x + 1; } test t { assert f(1) == 2; }`, with the /// called fn's name at text[ca .. cb] (`f`, or an undeclared one). /// text: M 0..1, f 1..2, x 2..3, u8 3..5, + 5..6, 1 6..7, 2 7..8, t 8..9, assert 9..15, == 15..17, g 17..18 diff --git a/specs/tri/t27b/verilog_emit.t27 b/specs/tri/t27b/verilog_emit.t27 index 9dffb29de0..9a069a1aa4 100644 --- a/specs/tri/t27b/verilog_emit.t27 +++ b/specs/tri/t27b/verilog_emit.t27 @@ -25,6 +25,7 @@ module T27bVerilogEmit; use tri::t27b::verilog_plan; use tri::t27b::text_escape; +use tri::t27b::emit_kit; // byte writers, to_front, line_near, resolve and symbols, test trees pub const M_TOP : u8 = 0; pub const M_FUNC : u8 = 1; @@ -32,70 +33,10 @@ pub const M_CLOCK : u8 = 2; pub const M_TEST : u8 = 3; pub const M_TBFUNC : u8 = 4; -/// The room at the end of `out` a refusal is first written to, so the text before it survives. -pub const MSG_ROOM : usize = 400; -/// The longest name a refusal quotes. -pub const NAME_CAP : usize = 120; - -/// Symbols: a resolved name is a tag times SYM_UNIT plus a node index (a parameter: its position). -pub const SYM_UNIT : i64 = 1099511627776; -pub const SYM_LOCAL : i64 = 1; -pub const SYM_PARAM : i64 = 2; -pub const SYM_TOP : i64 = 3; -pub const SYM_FN : i64 = 4; -pub const NO_SYM : i64 = -1; - // ---------------------------------------------------------------------------------------------------------- // Writing bytes. // ---------------------------------------------------------------------------------------------------------- -/// Writes s[a .. b] at out[at ..]. -pub fn put_bytes(out: []u8, at: usize, s: []const u8, a: usize, b: usize) -> usize { - var k : usize = a; - var q : usize = at; - while (k < b) { - out[q] = s[k]; - q = q + 1; - k = k + 1; - } - return q; -} - -/// How many decimal digits v has. -pub fn dec_len(v: u64) -> usize { - var n : usize = 1; - var x : u64 = v; - while (x >= 10) { - x = x / 10; - n = n + 1; - } - return n; -} - -/// Writes v in decimal. -pub fn put_dec(out: []u8, at: usize, v: u64) -> usize { - const n : usize = dec_len(v); - var x : u64 = v; - var k : usize = n; - while (k > 0) { - const db : u8 = @intCast(x % 10 + 48); - out[at + k - 1] = db; - x = x / 10; - k = k - 1; - } - return at + n; -} - -/// Writes n spaces. -pub fn put_ind(out: []u8, at: usize, n: usize) -> usize { - var k : usize = 0; - while (k < n) { - out[at + k] = 32; - k = k + 1; - } - return at + n; -} - /// Writes the name text[a .. b], as an escaped identifier (`\wait `) when it is a Verilog keyword. pub fn put_name(out: []u8, at: usize, text: []const u8, a: usize, b: usize) -> usize { if (verilog_keyword(text[a .. b])) { @@ -128,21 +69,6 @@ pub fn put_lit(out: []u8, at: usize, v: u64, t: i64) -> usize { return put_dec(out, q, v); } -/// The first non-zero source line at or after node i within its subtree, else the nearest one before it. -pub fn line_near(nodes: []const u8, meta: []const u8, i: usize) -> usize { - var j : usize = i; - while (j < end(nodes, i)) { - if (line_of(meta, j) != 0) { return line_of(meta, j); } - j = j + 1; - } - var k : usize = i; - while (k > 0) { - k = k - 1; - if (line_of(meta, k) != 0) { return line_of(meta, k); } - } - return 0; -} - /// Writes a refusal at the end of out: "t27b: verilog: unsupported construct `` at line ", /// the name being text[a .. b] (none when a == b). Returns minus its length. pub fn fail(out: []u8, nodes: []const u8, meta: []const u8, text: []const u8, i: usize, what: str, a: usize, b: usize) -> i64 { @@ -173,81 +99,10 @@ pub fn copy_msg(out: []u8, at: usize, n: usize) -> usize { return at + n; } -/// Copies the refusal of length n from the end of out to its start; returns minus n. -pub fn to_front(out: []u8, n: usize) -> i64 { - const base : usize = out.len - MSG_ROOM; - var k : usize = 0; - while (k < n) { - out[k] = out[base + k]; - k = k + 1; - } - const ni : i64 = @intCast(n); - return 0 - ni; -} - // ---------------------------------------------------------------------------------------------------------- // Names, scopes and types. // ---------------------------------------------------------------------------------------------------------- -/// The child of node c that holds node d in its subtree (c < d < end(c)). -pub fn child_holding(nodes: []const u8, c: usize, d: usize) -> usize { - var x : usize = c + 1; - while (x < end(nodes, c)) { - if (d < end(nodes, x)) { return x; } - x = end(nodes, x); - } - return c; -} - -/// The node whose direct child d is, searching down from `root` (root < d). -pub fn parent_of(nodes: []const u8, root: usize, d: usize) -> usize { - var cur : usize = root; - while (true) { - const nx : usize = child_holding(nodes, cur, d); - if (nx == d or nx == cur) { return cur; } - cur = nx; - } - return cur; -} - -/// Is the local declared at node d (under item) in scope at node u: d comes before u, u is not in d's own -/// initializer, and d's enclosing block holds u? -pub fn in_scope(nodes: []const u8, item: usize, d: usize, u: usize) -> bool { - if (d >= u or u < end(nodes, d)) { return false; } - const pb : usize = parent_of(nodes, item, d); - return u < end(nodes, pb); -} - -/// The position of the parameter named text[a .. b] in fn `item`'s parameter lines, or -1. -pub fn param_index(text: []const u8, meta: []const u8, ptext: []const u8, item: usize, a: usize, b: usize) -> i64 { - const pa : usize = params_lo(meta, item); - const pb : usize = params_hi(meta, item); - var k : usize = 0; - var s : usize = pa; - while (s < pb) { - const e : usize = line_stop(ptext, s, pb); - const c : usize = colon_at(ptext, s, e); - if (c - s == b - a and has_at(ptext, s, c, text[a .. b])) { - const ki : i64 = @intCast(k); - return ki; - } - k = k + 1; - s = e + 1; - } - return -1; -} - -/// Where parameter k's name starts in the params text of `item`. -pub fn param_name_lo(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { - return param_at(ptext, params_lo(meta, item), params_hi(meta, item), k); -} - -/// Where parameter k's name ends. -pub fn param_name_hi(meta: []const u8, ptext: []const u8, item: usize, k: usize) -> usize { - const s : usize = param_name_lo(meta, ptext, item, k); - return colon_at(ptext, s, line_stop(ptext, s, params_hi(meta, item))); -} - /// The type code of parameter k of `item`. pub fn param_type(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []const u8, item: usize, k: usize) -> i64 { const s : usize = param_name_lo(meta, ptext, item, k); @@ -257,51 +112,11 @@ pub fn param_type(nodes: []const u8, text: []const u8, meta: []const u8, ptext: return type_code(ptext, c + 1, e); } -/// Resolves the name text[a .. b] used at node u inside `item` (a fn or a test; 0 for the module scope): a -/// local in scope, a parameter of item, a top-level declaration, or a top-level fn. NO_SYM when there is -/// none. -pub fn resolve(nodes: []const u8, text: []const u8, meta: []const u8, ptext: []const u8, item: usize, u: usize, a: usize, b: usize) -> i64 { - if (item > 0) { - var j : usize = u; - while (j > item + 1) { - j = j - 1; - if (kind(nodes, j) == K_STMT_LOCAL and field_is(nodes, text, j, F_NAME, text[a .. b])) { - if (in_scope(nodes, item, j, u)) { - const ji : i64 = @intCast(j); - return SYM_LOCAL * SYM_UNIT + ji; - } - } - } - if (kind(nodes, item) == K_FN_DECL) { - const pk : i64 = param_index(text, meta, ptext, item, a, b); - if (pk >= 0) { return SYM_PARAM * SYM_UNIT + pk; } - } - } - const d : i64 = find_decl(nodes, text, a, b); - if (d != NO_NODE) { return SYM_TOP * SYM_UNIT + d; } - const f : i64 = find_fn(nodes, text, a, b); - if (f != NO_NODE) { return SYM_FN * SYM_UNIT + f; } - return NO_SYM; -} - -/// The symbol of tag `tag` at node (or parameter position) `at`. -pub fn sym_of(tag: i64, at: usize) -> i64 { - const ai : i64 = @intCast(at); - return tag * SYM_UNIT + ai; -} - /// The tag of a symbol. pub fn sym_tag(s: i64) -> i64 { return @divTrunc(s, SYM_UNIT); } -/// The node index (or parameter position) of a symbol. -pub fn sym_at(s: i64) -> usize { - const r : i64 = @rem(s, SYM_UNIT); - const ru : usize = @intCast(r); - return ru; -} - /// The type a type text names: a scalar code, or TY_STRUCT plus the struct declared under that name. pub fn named_type(nodes: []const u8, text: []const u8, a: usize, b: usize) -> i64 { const t : i64 = type_code(text, a, b); @@ -2265,40 +2080,6 @@ pub fn fail_front(out: []u8, what: str) -> i64 { // constant. The expected Verilog is what verilog_plan.t27 decides for it. // ---------------------------------------------------------------------------------------------------------- -/// Node i: kind k, subtree end e, name text[a .. b], every other field empty. -fn tnode(buf: []u8, i: usize, k: u8, e: usize, a: usize, b: usize) -> void { - buf[i * REC] = k; - vput32(buf, i * REC + 4, e); - var f : usize = 0; - while (f < FIELDS) { - vput32(buf, i * REC + 8 + f * 8, 0); - vput32(buf, i * REC + 12 + f * 8, 0); - f = f + 1; - } - vput32(buf, i * REC + 8, a); - vput32(buf, i * REC + 12, b); -} - -/// Node i's meta record: flags, line, no parameters. -fn tmeta(m: []u8, i: usize, flags: usize, line: usize) -> void { - vput32(m, i * META, flags); - vput32(m, i * META + 4, line); - vput32(m, i * META + 8, 0); - vput32(m, i * META + 12, 0); -} - -/// Does out[0 .. n] hold w? -fn holds(out: []const u8, n: usize, w: str) -> bool { - var i : usize = 0; - while (i + w.len <= n) { - var k : usize = 0; - while (k < w.len and out[i + k] == w[k]) { k = k + 1; } - if (k == w.len) { return true; } - i = i + 1; - } - return false; -} - test numbers_ranges_literals_and_names_are_spelled { var out : [64]u8 = undefined; assert put_dec(out[0 .. 64], 0, 0) == 1 and out[0] == 48; diff --git a/tools/duplicate_bodies_baseline.txt b/tools/duplicate_bodies_baseline.txt index bd22fecd73..4366b3fdb5 100644 --- a/tools/duplicate_bodies_baseline.txt +++ b/tools/duplicate_bodies_baseline.txt @@ -186,7 +186,6 @@ slices_equal 2 starts_with 2 startup_config 2 temporal_trace_check 2 -ternary_matmul 2 tokenize_prompt_inner 2 trit_add 2 trit_compare 2