fix(selfhost-parser): accept comma-separated struct fields, multi-line import braces, glob imports

- struct fields: ',' is a valid separator, incl. trailing comma before '}'
- imports: stop path scan before '::*' (glob) and allow newlines before
  the closing '}' of braced multi-imports
- interfaces: skip ';' after bodyless method signatures
- null-guard all diag emitters (interp-fragment sub-parser has diags=null)
This commit is contained in:
2026-07-28 22:20:17 +03:00
parent 869fb9c7d3
commit a538e05041
+13 -4
View File
@@ -113,7 +113,7 @@ module Parser {
return parserAdvance(p); return parserAdvance(p);
} }
let tok: LexToken = parserCurToken(p); let tok: LexToken = parserCurToken(p);
if p.diagCount < 256 { if p.diagCount < 256 && p.diags != null as *ParserDiag {
p.diags[p.diagCount] = ParserDiag { p.diags[p.diagCount] = ParserDiag {
line: tok.line, column: tok.column, message: msg, severity: 1 line: tok.line, column: tok.column, message: msg, severity: 1
}; };
@@ -123,7 +123,7 @@ module Parser {
} }
func parserEmitDiag(p: *Parser, line: uint32, col: uint32, msg: String) { func parserEmitDiag(p: *Parser, line: uint32, col: uint32, msg: String) {
if p.diagCount < 256 { if p.diagCount < 256 && p.diags != null as *ParserDiag {
p.diags[p.diagCount] = ParserDiag { p.diags[p.diagCount] = ParserDiag {
line: line, column: col, message: msg, severity: 1 line: line, column: col, message: msg, severity: 1
}; };
@@ -142,7 +142,7 @@ module Parser {
if tok.kind == tkIdent || parserIsKeyword(tok.kind) { if tok.kind == tkIdent || parserIsKeyword(tok.kind) {
return parserAdvance(p); return parserAdvance(p);
} }
if p.diagCount < 256 { if p.diagCount < 256 && p.diags != null as *ParserDiag {
p.diags[p.diagCount] = ParserDiag { p.diags[p.diagCount] = ParserDiag {
line: tok.line, column: tok.column, message: msg, severity: 1 line: tok.line, column: tok.column, message: msg, severity: 1
}; };
@@ -2175,6 +2175,8 @@ module Parser {
} }
if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; } if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; }
if parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; } if parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; }
// Commas are also valid field separators (incl. trailing comma before '}')
if parserCheck(p, tkComma) { discard parserAdvance(p); continue; }
let beforePos: int = p.pos; let beforePos: int = p.pos;
let fName: LexToken = parserExpectIdentOrKeyword(p, "expected field name"); let fName: LexToken = parserExpectIdentOrKeyword(p, "expected field name");
if fieldCount >= 250 && fieldCount <= 256 { if fieldCount >= 250 && fieldCount <= 256 {
@@ -2274,9 +2276,10 @@ module Parser {
d.isPublic = isPublic; d.isPublic = isPublic;
// Parse path: Std::Io::PrintLine // Parse path: Std::Io::PrintLine
// Stop before `::{` (multi-import) and `::*` (glob import)
var pathStr: String = ""; var pathStr: String = "";
var segCount: int = 0; var segCount: int = 0;
while parserCheck(p, tkIdent) || (segCount > 0 && parserCheck(p, tkColonColon) && parserPeek(p, 1) != tkLBrace) { while parserCheck(p, tkIdent) || (segCount > 0 && parserCheck(p, tkColonColon) && parserPeek(p, 1) != tkLBrace && parserPeek(p, 1) != tkStar) {
if segCount > 0 { if segCount > 0 {
discard parserAdvance(p); // :: discard parserAdvance(p); // ::
if String_Len(pathStr) > 0 { if String_Len(pathStr) > 0 {
@@ -2308,6 +2311,10 @@ module Parser {
names = String_Concat(names, ","); names = String_Concat(names, ",");
if !parserMatch(p, tkComma) { break; } if !parserMatch(p, tkComma) { break; }
} }
// Allow newlines before the closing brace (multi-line import lists)
while parserCheck(p, tkNewLine) {
discard parserAdvance(p);
}
discard parserExpect(p, tkRBrace, "expected '}'"); discard parserExpect(p, tkRBrace, "expected '}'");
d.useNames = names; d.useNames = names;
d.useKind = 2; // ukMulti d.useKind = 2; // ukMulti
@@ -2366,6 +2373,8 @@ module Parser {
var lastMethod: *Decl = null as *Decl; var lastMethod: *Decl = null as *Decl;
while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile {
if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; } if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; }
// Bodyless method signatures end with ';'
if parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; }
if parserCheck(p, tkFunc) { if parserCheck(p, tkFunc) {
let m: *Decl = parserParseFuncDecl(p, false, false, false); let m: *Decl = parserParseFuncDecl(p, false, false, false);
if methods == null as *Decl { if methods == null as *Decl {