compiler: implement blank package name semantics
This commit is contained in:
@@ -92,6 +92,24 @@ expectident(Parser *p)
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Package declarations admit the blank identifier syntactically. Keep this
|
||||
* private to the package-name slot: every ordinary identifier production must
|
||||
* retain expectident's rejection of TK_UNDER. The checker owns the semantic
|
||||
* BlankPkgName rejection. */
|
||||
static const char *
|
||||
expectpackagename(Parser *p)
|
||||
{
|
||||
if (p->cur.kind != TK_IDENT && p->cur.kind != TK_UNDER) {
|
||||
errorf(p->cur.pos, "expected identifier, got %s",
|
||||
tokname(p->cur.kind));
|
||||
p->errs++;
|
||||
return "<err>";
|
||||
}
|
||||
const char *s = p->cur.text;
|
||||
advance(p);
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Like expectident but also accepts a bare `_` discard marker. The
|
||||
* returned string is the empty string "" so the checker skips
|
||||
* scope_define. Callers that care can detect this with `s[0] == '\0'`. */
|
||||
@@ -1340,19 +1358,25 @@ parseuse(Parser *p)
|
||||
n->usefile = p->cur.pos.file;
|
||||
n->useline = p->cur.pos.line;
|
||||
n->usecol = p->cur.pos.col;
|
||||
Pos pathpos = p->cur.pos;
|
||||
const char *alias = NULL;
|
||||
const char *first;
|
||||
if (p->cur.kind == TK_UNDER) {
|
||||
n->useblank = 1;
|
||||
advance(p);
|
||||
pathpos = p->cur.pos;
|
||||
first = expectident(p);
|
||||
} else {
|
||||
first = expectident(p);
|
||||
if (p->cur.kind == TK_IDENT) {
|
||||
alias = first;
|
||||
pathpos = p->cur.pos;
|
||||
first = expectident(p);
|
||||
}
|
||||
}
|
||||
n->usepathfile = pathpos.file;
|
||||
n->usepathline = pathpos.line;
|
||||
n->usepathcol = pathpos.col;
|
||||
const char *leaf = first;
|
||||
const char *path = leaf;
|
||||
while (accept(p, TK_DOT)) {
|
||||
@@ -1383,11 +1407,13 @@ parseheaderuse(Parser *p)
|
||||
n->usefile = p->cur.pos.file;
|
||||
n->useline = p->cur.pos.line;
|
||||
n->usecol = p->cur.pos.col;
|
||||
Pos pathpos = p->cur.pos;
|
||||
const char *alias = NULL;
|
||||
const char *first;
|
||||
if (p->cur.kind == TK_UNDER) {
|
||||
n->useblank = 1;
|
||||
advance(p);
|
||||
pathpos = p->cur.pos;
|
||||
} else if (p->cur.kind != TK_IDENT) {
|
||||
errorf(p->cur.pos, "expected identifier, got %s",
|
||||
tokname(p->cur.kind));
|
||||
@@ -1404,9 +1430,13 @@ parseheaderuse(Parser *p)
|
||||
advance(p);
|
||||
if (!n->useblank && p->cur.kind == TK_IDENT) {
|
||||
alias = first;
|
||||
pathpos = p->cur.pos;
|
||||
first = p->cur.text;
|
||||
advance(p);
|
||||
}
|
||||
n->usepathfile = pathpos.file;
|
||||
n->usepathline = pathpos.line;
|
||||
n->usepathcol = pathpos.col;
|
||||
const char *leaf = first;
|
||||
const char *path = leaf;
|
||||
while (p->cur.kind == TK_DOT) {
|
||||
@@ -1467,13 +1497,12 @@ parsepackageheader(Parser *p)
|
||||
}
|
||||
Pos pp = p->cur.pos;
|
||||
advance(p);
|
||||
if (p->cur.kind != TK_IDENT) {
|
||||
if (p->cur.kind != TK_IDENT && p->cur.kind != TK_UNDER) {
|
||||
errorf(p->cur.pos, "invalid or missing package clause");
|
||||
p->errs++;
|
||||
return file;
|
||||
}
|
||||
const char *name = p->cur.text;
|
||||
advance(p);
|
||||
const char *name = expectpackagename(p);
|
||||
if (p->cur.kind != TK_SEMI) {
|
||||
errorf(p->cur.pos, "expected ';' after package name");
|
||||
p->errs++;
|
||||
@@ -1548,14 +1577,14 @@ parseimports(Parser *p)
|
||||
Pos pp = p->cur.pos;
|
||||
previmport = 1;
|
||||
advance(p);
|
||||
if (p->cur.kind != TK_IDENT) {
|
||||
if (p->cur.kind != TK_IDENT && p->cur.kind != TK_UNDER) {
|
||||
errorf(p->cur.pos, "invalid or missing package clause");
|
||||
p->errs++;
|
||||
sawpackage = 1;
|
||||
skipdecl(p);
|
||||
continue;
|
||||
}
|
||||
const char *name = expectident(p);
|
||||
const char *name = expectpackagename(p);
|
||||
expect(p, TK_SEMI);
|
||||
p->curpkg = name;
|
||||
if (p->pathmod == NULL && p->resetmod == NULL)
|
||||
@@ -1754,13 +1783,16 @@ parsefile(Parser *p)
|
||||
sawpackage = 1;
|
||||
previmport = 1;
|
||||
advance(p);
|
||||
const char *name = expectident(p);
|
||||
Pos namepos = p->cur.pos;
|
||||
const char *name = expectpackagename(p);
|
||||
expect(p, TK_SEMI);
|
||||
p->curpkg = name;
|
||||
if (p->pathmod == NULL && p->resetmod == NULL) {
|
||||
p->curmod = name;
|
||||
}
|
||||
Node *package = newnode(p->a, N_FILE, packagepos);
|
||||
Pos markerpos = strcmp(name, "_") == 0
|
||||
? namepos : packagepos;
|
||||
Node *package = newnode(p->a, N_FILE, markerpos);
|
||||
package->module = p->curmod;
|
||||
package->pkgname = name;
|
||||
package->sourceid = p->sourceid;
|
||||
|
||||
Reference in New Issue
Block a user