ww: loud fatal on unresolvable import, inline-package aware (#16 ENFORCE-driver)
Both driver twins: an import that neither locates as a file nor is satisfied by an inline 'package <name>' declaration in the unit is now fatal "ww: cannot find package <name>" (was a silent skip that masked dead imports and typos). The inline scan is a new every-line helper on the uncapped comment-skip core - peekpackage stops at the first decl, and single-file multi-package fixtures declare several. 949 pins both branches (miss->fatal, inline->build+run); 993 adds ww_ww parity.
This commit is contained in:
@@ -3310,6 +3310,28 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
||||
if (ipath != nil) {
|
||||
if (isdir != 0) { expanddir(c, ipath); }
|
||||
else { expand(c, ipath); };
|
||||
} else {
|
||||
// #16 ENFORCE-driver (rob A): a locate-miss is
|
||||
// legal when the package is defined INLINE in the
|
||||
// same unit (single-file multi-package). leaf = the
|
||||
// last dotted component of the import name; if an
|
||||
// inline `package <leaf>` exists -> silent skip
|
||||
// (the checker binds it), else fatal. cstage twin in
|
||||
// cmd/ww/main.c; fatal text identical.
|
||||
let lstart: u64 = 0u64;
|
||||
let lk: u64 = 0u64;
|
||||
for (lk < idn) {
|
||||
if (idp[lk] == 46u8) { lstart = lk + 1u64; }; // '.'
|
||||
lk += 1u64;
|
||||
};
|
||||
let leafp: *u8 = idp + lstart;
|
||||
let leafn: u64 = idn - lstart;
|
||||
if (!unithaspackage(bufp, blen, leafp, leafn)) {
|
||||
cerr("ww: cannot find package ");
|
||||
os.write(2, idp, idn);
|
||||
cerr("\n");
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
};
|
||||
i = j + 1u64;
|
||||
@@ -3415,6 +3437,68 @@ fn peekpackage(pathcs: *u8) *u8 = {
|
||||
return nil;
|
||||
};
|
||||
|
||||
// unithaspackage — does the unit buffer declare `package <leaf>;` ANYWHERE?
|
||||
// #16 ENFORCE-driver (rob A) cstage unit_has_package twin: distinguishes a
|
||||
// genuinely-missing import from one satisfied by an INLINE package in the
|
||||
// same single-file multi-package unit (`package aa; ... package main;
|
||||
// import aa;`). Scans EVERY line (comment-skip) — not just the first
|
||||
// package decl (peekpackage stops there). Decision byte-identical to
|
||||
// cstage so the skip/fatal choice + driver output match (rule 10).
|
||||
fn unithaspackage(buf: *u8, buflen: u64, leafp: *u8, leafn: u64) bool = {
|
||||
let p: u64 = 0u64;
|
||||
for (p < buflen) {
|
||||
let q: u64 = p;
|
||||
for (q < buflen) { if (buf[q] == 10u8) { break; }; q += 1u64; };
|
||||
let s: u64 = p;
|
||||
for (s < q) {
|
||||
if (buf[s] != 32u8) { if (buf[s] != 9u8) { break; }; };
|
||||
s += 1u64;
|
||||
};
|
||||
if (s < q) {
|
||||
let line: str;
|
||||
line.ptr = buf + s;
|
||||
line.len = (q - s): i32;
|
||||
if (strings.hasprefix(line, "//")) { p = q + 1u64; continue; };
|
||||
if (s + 8u64 <= q) {
|
||||
if (strings.hasprefix(line, "package")) {
|
||||
let sep: u8 = buf[s + 7u64];
|
||||
let oksep: bool = false;
|
||||
if (sep == 32u8) { oksep = true; }
|
||||
else { if (sep == 9u8) { oksep = true; }; };
|
||||
if (oksep) {
|
||||
let t: u64 = s + 8u64;
|
||||
for (t < q) {
|
||||
if (buf[t] != 32u8) { if (buf[t] != 9u8) { break; }; };
|
||||
t += 1u64;
|
||||
};
|
||||
let m: u64 = 0u64;
|
||||
let eq: bool = true;
|
||||
for (m < leafn) {
|
||||
if (t + m >= q) { eq = false; break; };
|
||||
if (buf[t + m] != leafp[m]) { eq = false; break; };
|
||||
m += 1u64;
|
||||
};
|
||||
if (eq) {
|
||||
let after: u64 = t + leafn;
|
||||
let term: bool = false;
|
||||
if (after >= q) { term = true; }
|
||||
else {
|
||||
let c: u8 = buf[after];
|
||||
if (c == 59u8) { term = true; } // ';'
|
||||
else { if (c == 32u8) { term = true; }
|
||||
else { if (c == 9u8) { term = true; }; }; };
|
||||
};
|
||||
if (term) { return true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
p = q + 1u64;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// Strict-same-package error helper. Bundled here per task #22
|
||||
// brief — failure mode is dir-enum's own.
|
||||
fn strictpkgmismatch(file: *u8, pkg: *u8, dirpkg: *u8, dirpath: *u8) void = {
|
||||
|
||||
@@ -524,6 +524,28 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
||||
if (ipath != nil) {
|
||||
if (isdir != 0) { expanddir(c, ipath); }
|
||||
else { expand(c, ipath); };
|
||||
} else {
|
||||
// #16 ENFORCE-driver (rob A): a locate-miss is
|
||||
// legal when the package is defined INLINE in the
|
||||
// same unit (single-file multi-package). leaf = the
|
||||
// last dotted component of the import name; if an
|
||||
// inline `package <leaf>` exists -> silent skip
|
||||
// (the checker binds it), else fatal. cstage twin in
|
||||
// cmd/ww/main.c; fatal text identical.
|
||||
let lstart: u64 = 0u64;
|
||||
let lk: u64 = 0u64;
|
||||
for (lk < idn) {
|
||||
if (idp[lk] == 46u8) { lstart = lk + 1u64; }; // '.'
|
||||
lk += 1u64;
|
||||
};
|
||||
let leafp: *u8 = idp + lstart;
|
||||
let leafn: u64 = idn - lstart;
|
||||
if (!unithaspackage(bufp, blen, leafp, leafn)) {
|
||||
cerr("ww: cannot find package ");
|
||||
os.write(2, idp, idn);
|
||||
cerr("\n");
|
||||
os.exit(1);
|
||||
};
|
||||
};
|
||||
};
|
||||
i = j + 1u64;
|
||||
@@ -629,6 +651,68 @@ fn peekpackage(pathcs: *u8) *u8 = {
|
||||
return nil;
|
||||
};
|
||||
|
||||
// unithaspackage — does the unit buffer declare `package <leaf>;` ANYWHERE?
|
||||
// #16 ENFORCE-driver (rob A) cstage unit_has_package twin: distinguishes a
|
||||
// genuinely-missing import from one satisfied by an INLINE package in the
|
||||
// same single-file multi-package unit (`package aa; ... package main;
|
||||
// import aa;`). Scans EVERY line (comment-skip) — not just the first
|
||||
// package decl (peekpackage stops there). Decision byte-identical to
|
||||
// cstage so the skip/fatal choice + driver output match (rule 10).
|
||||
fn unithaspackage(buf: *u8, buflen: u64, leafp: *u8, leafn: u64) bool = {
|
||||
let p: u64 = 0u64;
|
||||
for (p < buflen) {
|
||||
let q: u64 = p;
|
||||
for (q < buflen) { if (buf[q] == 10u8) { break; }; q += 1u64; };
|
||||
let s: u64 = p;
|
||||
for (s < q) {
|
||||
if (buf[s] != 32u8) { if (buf[s] != 9u8) { break; }; };
|
||||
s += 1u64;
|
||||
};
|
||||
if (s < q) {
|
||||
let line: str;
|
||||
line.ptr = buf + s;
|
||||
line.len = (q - s): i32;
|
||||
if (strings.hasprefix(line, "//")) { p = q + 1u64; continue; };
|
||||
if (s + 8u64 <= q) {
|
||||
if (strings.hasprefix(line, "package")) {
|
||||
let sep: u8 = buf[s + 7u64];
|
||||
let oksep: bool = false;
|
||||
if (sep == 32u8) { oksep = true; }
|
||||
else { if (sep == 9u8) { oksep = true; }; };
|
||||
if (oksep) {
|
||||
let t: u64 = s + 8u64;
|
||||
for (t < q) {
|
||||
if (buf[t] != 32u8) { if (buf[t] != 9u8) { break; }; };
|
||||
t += 1u64;
|
||||
};
|
||||
let m: u64 = 0u64;
|
||||
let eq: bool = true;
|
||||
for (m < leafn) {
|
||||
if (t + m >= q) { eq = false; break; };
|
||||
if (buf[t + m] != leafp[m]) { eq = false; break; };
|
||||
m += 1u64;
|
||||
};
|
||||
if (eq) {
|
||||
let after: u64 = t + leafn;
|
||||
let term: bool = false;
|
||||
if (after >= q) { term = true; }
|
||||
else {
|
||||
let c: u8 = buf[after];
|
||||
if (c == 59u8) { term = true; } // ';'
|
||||
else { if (c == 32u8) { term = true; }
|
||||
else { if (c == 9u8) { term = true; }; }; };
|
||||
};
|
||||
if (term) { return true; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
p = q + 1u64;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
// Strict-same-package error helper. Bundled here per task #22
|
||||
// brief — failure mode is dir-enum's own.
|
||||
fn strictpkgmismatch(file: *u8, pkg: *u8, dirpkg: *u8, dirpath: *u8) void = {
|
||||
|
||||
Reference in New Issue
Block a user