ww imports: require imports before declarations

This commit is contained in:
2026-08-21 19:20:52 +09:00
parent b03bbb1428
commit ee4573bf55
9 changed files with 730 additions and 8 deletions

View File

@@ -497,12 +497,16 @@ export fn parseimports(p: *parser) *node = {
let packages: *node = nil;
let packagetail: *node = nil;
let sawpackage: bool = false;
// One import section precedes ordinary declarations. Keep parsing for
// recovery, diagnosing the first import in each later source section.
let previmport: bool = true;
for (p.curkind != tkind.TK_EOF) {
// Compiler/driver bundle markers carry package identity out of
// band. They are not source declarations, so keep scanning for
// the following package clause and imports.
if (p.curkind == tkind.TK_MODPATH) {
sawpackage = false;
previmport = true;
p.sourceid += 1;
p.pathmod = p.curtext;
p.curmod = p.curtext;
@@ -514,6 +518,7 @@ export fn parseimports(p: *parser) *node = {
if (p.curkind == tkind.TK_MODRESET) {
let rp: str = p.curtext;
sawpackage = false;
previmport = true;
p.sourceid += 1;
advance(p);
p.pathmod = "";
@@ -526,6 +531,7 @@ export fn parseimports(p: *parser) *node = {
let pf: str = p.curfile;
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
previmport = true;
advance(p);
if (p.curkind != tkind.TK_IDENT) {
errmsg(p, "invalid or missing package clause");
@@ -563,6 +569,10 @@ export fn parseimports(p: *parser) *node = {
sawpackage = true;
};
if (p.curkind == tkind.TK_USE) {
if (!previmport) {
errmsg(p, "imports must appear before other declarations");
};
previmport = true;
let d: *node = parseuse(p);
d.nmod = p.curmod;
d.pkgname = p.curpkg;
@@ -571,6 +581,7 @@ export fn parseimports(p: *parser) *node = {
tail = d;
continue;
};
previmport = false;
if (p.curkind == tkind.TK_AT) {
skipimportattrs(p);
if (p.curkind == tkind.TK_EXPORT) { advance(p); };
@@ -618,6 +629,8 @@ export fn parsefile(p: *parser) *node = {
let packages: *node = nil;
let packagetail: *node = nil;
let sawpackage: i32 = 0;
// Full/direct parsing is the semantic twin of the imports-only pass.
let previmport: bool = true;
for (p.curkind != tkind.TK_EOF) {
// `package foo;` — directory-as-module declaration. Every
// primary section opens with one (`package main;` for an
@@ -630,6 +643,7 @@ export fn parsefile(p: *parser) *node = {
let pl: i32 = p.curline;
let pc: i32 = p.curcol;
sawpackage = 1;
previmport = true;
advance(p);
let name: str;
expectident(p, &name);
@@ -658,6 +672,7 @@ export fn parsefile(p: *parser) *node = {
// root-only bare-`main` rule, #32).
if (p.curkind == tkind.TK_MODPATH) {
sawpackage = 0;
previmport = true;
p.sourceid += 1;
p.pathmod = p.curtext;
p.curmod = p.curtext;
@@ -677,6 +692,7 @@ export fn parsefile(p: *parser) *node = {
// decls to bare — that usage is deliberate-only.
if (p.curkind == tkind.TK_MODRESET) {
sawpackage = 0;
previmport = true;
p.sourceid += 1;
// #57: a path-carrying reset (sep primary body) mangles decls
// on the dotted path so definer == importer, but leaves
@@ -714,6 +730,11 @@ export fn parsefile(p: *parser) *node = {
errmsg(p, "missing package clause");
sawpackage = 1;
};
let thisimport: bool = p.curkind == tkind.TK_USE;
if (thisimport && !previmport) {
errmsg(p, "imports must appear before other declarations");
};
previmport = thisimport;
let attrs = parseattrs(p);
let exported: i32 = 0;
if (p.curkind == tkind.TK_EXPORT) { exported = 1; advance(p); };