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:
@@ -230,6 +230,40 @@ peek_package(const char *path, char *out, size_t outsz)
|
||||
return found;
|
||||
}
|
||||
|
||||
/* unit_has_package — does `path` declare `package <leaf>;` ANYWHERE?
|
||||
* #16 ENFORCE-driver (rob A): distinguishes a genuinely-missing import
|
||||
* from one satisfied by an INLINE package in the same unit. Unlike
|
||||
* peek_package (stops at the FIRST package decl), this scans every line
|
||||
* — single-file multi-package fixtures carry several `package` decls. The
|
||||
* comment-skip line scan + name match mirror peek_package, uncapped. The
|
||||
* wwstage twin unithaspackage must stay byte-identical (rule 10). */
|
||||
static int
|
||||
unit_has_package(const char *path, const char *leaf)
|
||||
{
|
||||
FILE *in = fopen(path, "rb");
|
||||
if (in == NULL) return 0;
|
||||
char line[2048];
|
||||
int found = 0;
|
||||
while (fgets(line, sizeof line, in)) {
|
||||
const char *p = line;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
if (p[0] == '/' && p[1] == '/') continue;
|
||||
if (strncmp(p, "package ", 8) != 0
|
||||
&& strncmp(p, "package\t", 8) != 0) continue;
|
||||
p += 8;
|
||||
while (*p == ' ' || *p == '\t') p++;
|
||||
size_t i = 0;
|
||||
while (leaf[i] != '\0' && leaf[i] == p[i]) i++;
|
||||
if (leaf[i] == '\0') {
|
||||
char c = p[i];
|
||||
if (c == ';' || c == ' ' || c == '\t'
|
||||
|| c == '\n' || c == '\0') { found = 1; break; }
|
||||
}
|
||||
}
|
||||
fclose(in);
|
||||
return found;
|
||||
}
|
||||
|
||||
/* expand_dir — enumerate <dirpath>/*.ww (skip *test.ww), byte-sort,
|
||||
* recurse into each. Mirrors ref/hare/hare/module/srcs.ha:183
|
||||
* `_findsrcs` minus tag handling. The visited set still keys on
|
||||
@@ -299,9 +333,24 @@ expand(FILE *out, const char *path, struct ImportSet *visited,
|
||||
import_path_form(name, path_form, sizeof path_form);
|
||||
char ipath[1024];
|
||||
int is_dir = 0;
|
||||
/* #16 ENFORCE-driver (rob A): an unresolvable import is a hard
|
||||
* error, not a silent skip — the old `continue` let a typo'd/
|
||||
* missing package drop its symbols and surface later as a
|
||||
* confusing downstream failure. BUT a locate-miss is legal when
|
||||
* the package is defined INLINE in the same unit (single-file
|
||||
* multi-package: `package aa; ... package main; import aa;`) —
|
||||
* the bundler can't pull it as a file but the checker binds it.
|
||||
* So: miss + inline `package <leaf>` present -> silent skip;
|
||||
* miss + not inline -> fatal. */
|
||||
if (!locate_import(libdir, path_form, ipath, sizeof ipath,
|
||||
&is_dir))
|
||||
continue; /* silently skip if not found */
|
||||
&is_dir)) {
|
||||
const char *dot = strrchr(name, '.');
|
||||
const char *leaf = dot ? dot + 1 : name;
|
||||
if (unit_has_package(path, leaf))
|
||||
continue; /* inline-satisfied */
|
||||
fprintf(stderr, "ww: cannot find package %s\n", name);
|
||||
exit(1);
|
||||
}
|
||||
if (is_dir) expand_dir(out, ipath, visited, libdir);
|
||||
else expand(out, ipath, visited, libdir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user