build: omit named test source operands
This commit is contained in:
@@ -410,6 +410,75 @@ fn skipws(l: *lex) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Return the next initial import without lexing the first ordinary body token.
|
||||
// Header trivia is still decoded, so reached NUL and comment diagnostics keep
|
||||
// loader precedence; a malformed UTF-8 byte or middle BOM that begins the body
|
||||
// is deliberately outside this pass.
|
||||
export fn lexheaderimport(l: *lex, out: *tok) bool = {
|
||||
for (true) {
|
||||
if (l.lpos >= l.srclen) { return false; };
|
||||
let c: i32 = srcb(l, l.lpos);
|
||||
if (c == 0) {
|
||||
lskipnul(l);
|
||||
return false;
|
||||
};
|
||||
if ((c >= 128 && !utf8bytevalid(l.src, l.srclen, l.lpos))
|
||||
|| bomat(l.src, l.srclen, l.lpos)) {
|
||||
return false;
|
||||
};
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
|
||||
lget(l);
|
||||
continue;
|
||||
};
|
||||
if (c == '/' && l.lpos + 1u64 < l.srclen
|
||||
&& srcb(l, l.lpos + 1u64) == '/') {
|
||||
lget(l); lget(l);
|
||||
linecomment(l);
|
||||
if (l.errs != 0) { return false; };
|
||||
continue;
|
||||
};
|
||||
if (c == '/' && l.lpos + 1u64 < l.srclen
|
||||
&& srcb(l, l.lpos + 1u64) == '*') {
|
||||
lget(l); lget(l);
|
||||
let prev: i32 = -1;
|
||||
for (true) {
|
||||
let x: i32 = lget(l);
|
||||
if (x < 0) {
|
||||
let cp: pos;
|
||||
curpos(l, &cp);
|
||||
errat(l, &cp, "unterminated /* comment");
|
||||
return false;
|
||||
};
|
||||
if (prev == '*' && x == '/') { break; };
|
||||
prev = x;
|
||||
};
|
||||
if (l.errs != 0) { return false; };
|
||||
continue;
|
||||
};
|
||||
break;
|
||||
};
|
||||
if (l.modreset != 0 || l.modpathset != 0) { return false; };
|
||||
let kw: str = tokname(tkind.TK_USE);
|
||||
if (l.srclen - l.lpos < kw.len: u64) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < kw.len) {
|
||||
if (srcb(l, l.lpos + (i: u64)) != kw[i]: i32) {
|
||||
return false;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (l.srclen - l.lpos > kw.len: u64) {
|
||||
let next: i32 = srcb(l, l.lpos + (kw.len: u64));
|
||||
if ((next >= 'a' && next <= 'z')
|
||||
|| (next >= 'A' && next <= 'Z')
|
||||
|| (next >= '0' && next <= '9') || next == '_') {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
lexnext(l, out);
|
||||
return out.kind == tkind.TK_USE;
|
||||
};
|
||||
|
||||
fn parseint(p: *u8, n: u64, base: i32, ok: *bool) u64 = {
|
||||
let v: u64 = 0u64;
|
||||
let b: u64 = base: u64;
|
||||
|
||||
@@ -57,9 +57,7 @@ export type parser = struct {
|
||||
commandpackage: bool,
|
||||
};
|
||||
|
||||
fn refill(p: *parser) void = {
|
||||
let t: tok;
|
||||
lexnext(p.l, &t);
|
||||
fn installtok(p: *parser, t: *tok) void = {
|
||||
p.curkind = t.kind;
|
||||
p.curfile = t.file;
|
||||
p.curline = t.line;
|
||||
@@ -70,6 +68,19 @@ fn refill(p: *parser) void = {
|
||||
p.curtsuffix = t.tsuffix;
|
||||
};
|
||||
|
||||
fn refill(p: *parser) void = {
|
||||
let t: tok;
|
||||
lexnext(p.l, &t);
|
||||
installtok(p, &t);
|
||||
};
|
||||
|
||||
fn advanceheaderimport(p: *parser) bool = {
|
||||
let t: tok;
|
||||
if (!lexheaderimport(p.l, &t)) { return false; };
|
||||
installtok(p, &t);
|
||||
return true;
|
||||
};
|
||||
|
||||
export fn parserinit(p: *parser, l: *lex) void = {
|
||||
p.l = l;
|
||||
p.errs = 0;
|
||||
@@ -490,6 +501,121 @@ fn skipimportattrs(p: *parser) void = {
|
||||
};
|
||||
};
|
||||
|
||||
// Parse one initial import for the named-source header pass. Unlike the full
|
||||
// recovery scanner, this stops on the first malformed header token and never
|
||||
// consumes an ordinary declaration body.
|
||||
fn parseheaderuse(p: *parser) *node = {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
advance(p);
|
||||
let n: *node = newnode(nkind.N_USE, pf, pl, pc);
|
||||
n.usefile = p.curfile;
|
||||
n.useline = p.curline;
|
||||
n.usecol = p.curcol;
|
||||
let alias: str;
|
||||
let first: str;
|
||||
if (p.curkind == tkind.TK_UNDER) {
|
||||
n.useblank = 1;
|
||||
advance(p);
|
||||
};
|
||||
if (p.curkind != tkind.TK_IDENT) {
|
||||
errmsg(p, strings.concat("expected identifier, got ",
|
||||
tokname(p.curkind)));
|
||||
return n;
|
||||
};
|
||||
first = p.curtext;
|
||||
advance(p);
|
||||
if (n.useblank == 0 && p.curkind == tkind.TK_IDENT) {
|
||||
alias = first;
|
||||
first = p.curtext;
|
||||
advance(p);
|
||||
};
|
||||
let leaf: str = first;
|
||||
let path: str = leaf;
|
||||
for (p.curkind == tkind.TK_DOT) {
|
||||
advance(p);
|
||||
if (p.curkind != tkind.TK_IDENT) {
|
||||
errmsg(p, strings.concat("expected identifier, got ",
|
||||
tokname(p.curkind)));
|
||||
return n;
|
||||
};
|
||||
leaf = p.curtext;
|
||||
path = strings.concat(path, ".", leaf);
|
||||
advance(p);
|
||||
};
|
||||
if (n.useblank != 0) { n.str = ""; }
|
||||
else { if (alias.len > 0) { n.str = alias; } else { n.str = leaf; }; };
|
||||
n.usesource = path;
|
||||
n.usepath = path;
|
||||
n.usealias = alias;
|
||||
if (p.curkind != tkind.TK_SEMI) {
|
||||
errmsg(p, "expected ';' after import");
|
||||
return n;
|
||||
};
|
||||
return n;
|
||||
};
|
||||
|
||||
// A valid named source is loader-visible only through its initial package and
|
||||
// contiguous import section. Keep parseimports for graph-bearing source
|
||||
// recovery; this boundary deliberately ignores every ordinary declaration.
|
||||
export fn parsepackageheader(p: *parser) *node = {
|
||||
let f: *node = newnode(nkind.N_FILE, p.curfile, 1, 1);
|
||||
let head: *node = nil;
|
||||
let tail: *node = nil;
|
||||
for (p.curkind == tkind.TK_MODPATH
|
||||
|| p.curkind == tkind.TK_MODRESET) {
|
||||
if (p.curkind == tkind.TK_MODPATH) {
|
||||
p.pathmod = p.curtext;
|
||||
p.curmod = p.curtext;
|
||||
p.resetmod = "";
|
||||
} else {
|
||||
p.pathmod = "";
|
||||
p.curmod = p.curtext;
|
||||
p.resetmod = p.curtext;
|
||||
};
|
||||
p.sourceid += 1;
|
||||
advance(p);
|
||||
};
|
||||
if (p.curkind != tkind.TK_MODULE) {
|
||||
errmsg(p, "invalid or missing package clause");
|
||||
return f;
|
||||
};
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
advance(p);
|
||||
if (p.curkind != tkind.TK_IDENT) {
|
||||
errmsg(p, "invalid or missing package clause");
|
||||
return f;
|
||||
};
|
||||
let name: str = p.curtext;
|
||||
advance(p);
|
||||
if (p.curkind != tkind.TK_SEMI) {
|
||||
errmsg(p, "expected ';' after package name");
|
||||
return f;
|
||||
};
|
||||
p.curpkg = name;
|
||||
if (p.pathmod.len == 0 && p.resetmod.len == 0) { p.curmod = name; };
|
||||
f.nmod = name;
|
||||
f.pkgname = name;
|
||||
f.sourceid = p.sourceid;
|
||||
f.file = pf;
|
||||
f.line = pl;
|
||||
f.col = pc;
|
||||
for (advanceheaderimport(p)) {
|
||||
let d: *node = parseheaderuse(p);
|
||||
d.nmod = p.curmod;
|
||||
d.pkgname = p.curpkg;
|
||||
d.sourceid = p.sourceid;
|
||||
if (head == nil) { head = d; } else { tail.next = d; };
|
||||
tail = d;
|
||||
if (p.errs != 0) { break; };
|
||||
};
|
||||
f.list = head;
|
||||
return f;
|
||||
};
|
||||
|
||||
export fn parseimports(p: *parser) *node = {
|
||||
let f = newnode(nkind.N_FILE, p.curfile, 1, 1);
|
||||
let head: *node = nil;
|
||||
|
||||
Reference in New Issue
Block a user