parse: enforce strict-package — reject package-less files (#24a)
Flip the soft-default to a hard "missing package clause" error symmetrically in both stages (cmd/wcc/parse.c + lib/ww/syntax/parse.ww): the first real decl of a primary section with empty pathmod/resetmod and no seen clause is now rejected. Closes the documented soft-default divergence (the 63-wrapper carve-out). The gate flip can't be split from the migration it breaks, so this is one atomic commit: ~80 test/wcc wrappers gain `package main;` via a shared wwtestpkg.h helper, 6 data fixtures plus 17 asm-grep assertions update for the bare->main.<leaf> root-helper mangle shift, and rt/ declares `package rt;` with @symbol pinning the bare rt_ensure/rt_malloc linker names. Root mangling narrows: the executable entry `main` stays bare (existing carve-out), but root helper symbols become main.X. The #84 cluster is rewritten to assert main.run distinct from aa.run/test.run; its cgen fix and bare machinery are retained — still load-bearing for package-less module-reset deps. New table-driven test 782_strict_package.c (6 rows, both stages). Retiring //ww:module-reset is deferred to #24b: it is load-bearing (clears the .wwi pathmod so the body's package clause asserts), not a vestige; fusing its removal here would be a silent mismatch. All byte-id gates green; full make test reports "all 335 tests passed".
This commit is contained in:
@@ -416,17 +416,16 @@ export fn parsefile(p: *parser) *node = {
|
||||
let f = newnode(nkind.N_FILE, p.curfile, p.curline, p.curcol);
|
||||
let head: *node = nil;
|
||||
let tail: *node = nil;
|
||||
let sawpackage: i32 = 0;
|
||||
for (p.curkind != tkind.TK_EOF) {
|
||||
// `package foo;` — each contributing source's section in a
|
||||
// concatenated stream begins with one. Single-file inputs
|
||||
// may omit it (curmod stays empty; decls treated as primary).
|
||||
//
|
||||
// Retained divergence from brief: strict missing-`package`
|
||||
// error softened to silent-default — 63 inline-source test
|
||||
// wrappers depend on the soft behavior. See task #23 for
|
||||
// the wrapper migration that unblocks the strict check.
|
||||
// Rule 7 + rule 8 documentation.
|
||||
// `package foo;` — directory-as-module declaration. Every
|
||||
// primary section opens with one (`package main;` for an
|
||||
// executable); a missing clause on the first real decl is a
|
||||
// hard error (strict-package, #24a). Imported (pathmod) and
|
||||
// sep primary-reset (resetmod) regions carry identity
|
||||
// out-of-band and are exempt.
|
||||
if (p.curkind == tkind.TK_MODULE) {
|
||||
sawpackage = 1;
|
||||
advance(p);
|
||||
let name: str;
|
||||
expectident(p, &name);
|
||||
@@ -462,6 +461,7 @@ export fn parsefile(p: *parser) *node = {
|
||||
// leaf `package` clause, and are flagged imported (gates the
|
||||
// root-only bare-`main` rule, #32).
|
||||
if (p.curkind == tkind.TK_MODPATH) {
|
||||
sawpackage = 0;
|
||||
p.pathmod = p.curtext;
|
||||
p.curmod = p.curtext;
|
||||
p.resetmod = "";
|
||||
@@ -477,6 +477,7 @@ export fn parsefile(p: *parser) *node = {
|
||||
// directive after a mid-file `package` would strip subsequent
|
||||
// decls to bare — that usage is deliberate-only.
|
||||
if (p.curkind == tkind.TK_MODRESET) {
|
||||
sawpackage = 0;
|
||||
// #57: a path-carrying reset (sep primary body) mangles decls
|
||||
// on the dotted path so definer == importer, but leaves
|
||||
// imported==0 (curmod set, pathmod "") so -c primary-ness and
|
||||
@@ -503,6 +504,15 @@ export fn parsefile(p: *parser) *node = {
|
||||
};
|
||||
continue;
|
||||
};
|
||||
// strict-package: a primary section's first real decl must be
|
||||
// preceded by a `package` clause. Imported (pathmod) and sep
|
||||
// primary-reset (resetmod) regions carry identity out-of-band,
|
||||
// so they are exempt. Wording mirrors Go's missing-`package`
|
||||
// diagnostic (rule 5; Hare has no clause to port).
|
||||
if (p.pathmod.len == 0 && p.resetmod.len == 0 && sawpackage == 0) {
|
||||
errmsg(p, "missing package clause");
|
||||
sawpackage = 1;
|
||||
};
|
||||
let attrs = parseattrs(p);
|
||||
let exported: i32 = 0;
|
||||
if (p.curkind == tkind.TK_EXPORT) { exported = 1; advance(p); };
|
||||
|
||||
Reference in New Issue
Block a user