build: omit named test source operands

This commit is contained in:
2026-08-22 21:53:10 +09:00
parent 3922f1c34e
commit 2e5451a601
13 changed files with 1666 additions and 21 deletions

View File

@@ -35,6 +35,17 @@ advance(Parser *p)
}
}
static int
advanceheaderimport(Parser *p)
{
Tok next;
if (!lexheaderimport(p->l, &next))
return 0;
p->cur = next;
p->hasla = 0;
return 1;
}
static Tok
peek(Parser *p)
{
@@ -1359,6 +1370,140 @@ parseuse(Parser *p)
return n;
}
/* Parse one initial import without pulling the declaration that follows it
* into the header pass. This intentionally has stricter, single-error
* recovery than parseuse: named test-source build loading needs only decide
* whether the package/import header itself is valid. */
static Node *
parseheaderuse(Parser *p)
{
Pos pp = p->cur.pos;
advance(p);
Node *n = newnode(p->a, N_USE, pp);
n->usefile = p->cur.pos.file;
n->useline = p->cur.pos.line;
n->usecol = p->cur.pos.col;
const char *alias = NULL;
const char *first;
if (p->cur.kind == TK_UNDER) {
n->useblank = 1;
advance(p);
} else if (p->cur.kind != TK_IDENT) {
errorf(p->cur.pos, "expected identifier, got %s",
tokname(p->cur.kind));
p->errs++;
return n;
}
if (p->cur.kind != TK_IDENT) {
errorf(p->cur.pos, "expected identifier, got %s",
tokname(p->cur.kind));
p->errs++;
return n;
}
first = p->cur.text;
advance(p);
if (!n->useblank && p->cur.kind == TK_IDENT) {
alias = first;
first = p->cur.text;
advance(p);
}
const char *leaf = first;
const char *path = leaf;
while (p->cur.kind == TK_DOT) {
advance(p);
if (p->cur.kind != TK_IDENT) {
errorf(p->cur.pos, "expected identifier, got %s",
tokname(p->cur.kind));
p->errs++;
return n;
}
leaf = p->cur.text;
path = aprintf(p->a, "%s.%s", path, leaf);
advance(p);
}
if (!n->useblank) {
n->str = alias ? alias : leaf;
n->strlen = strlen(n->str);
}
n->usesource = path;
n->usepath = path;
n->usealias = alias;
if (p->cur.kind != TK_SEMI) {
errorf(p->cur.pos, "expected ';' after import");
p->errs++;
return n;
}
return n;
}
/* Go's named-file loader parses a valid source only through its initial
* package/import section. Keep the broader parseimports recovery pass for
* graph-bearing sources, but give actionless test-source omission a boundary
* that cannot diagnose late imports or an invalid ordinary declaration body. */
Node *
parsepackageheader(Parser *p)
{
Pos fp = { p->l->file, 1, 1 };
Node *file = newnode(p->a, N_FILE, fp);
Node *head = NULL, *tail = NULL;
while (p->cur.kind == TK_MODPATH || p->cur.kind == TK_MODRESET) {
if (p->cur.kind == TK_MODPATH) {
p->pathmod = p->cur.text;
p->curmod = p->cur.text;
p->resetmod = NULL;
} else {
p->pathmod = NULL;
p->curmod = p->cur.text;
p->resetmod = p->cur.text;
}
p->sourceid++;
advance(p);
}
if (p->cur.kind != TK_MODULE) {
errorf(p->cur.pos, "invalid or missing package clause");
p->errs++;
return file;
}
Pos pp = p->cur.pos;
advance(p);
if (p->cur.kind != TK_IDENT) {
errorf(p->cur.pos, "invalid or missing package clause");
p->errs++;
return file;
}
const char *name = p->cur.text;
advance(p);
if (p->cur.kind != TK_SEMI) {
errorf(p->cur.pos, "expected ';' after package name");
p->errs++;
return file;
}
p->curpkg = name;
if (p->pathmod == NULL && p->resetmod == NULL)
p->curmod = name;
file->module = name;
file->pkgname = name;
file->sourceid = p->sourceid;
file->pos = pp;
while (advanceheaderimport(p)) {
Node *d = parseheaderuse(p);
d->module = p->curmod;
d->pkgname = p->curpkg;
d->sourceid = p->sourceid;
if (head == NULL)
head = d;
else
tail->next = d;
tail = d;
if (p->errs != 0)
break;
}
file->list = head;
return file;
}
Node *
parseimports(Parser *p)
{