diff --git a/src/cli.bux b/src/cli.bux index 033d2f5..e542a93 100644 --- a/src/cli.bux +++ b/src/cli.bux @@ -541,6 +541,9 @@ func Cli_BuildProject(projectDir: String) -> int { return 1; } let lex: *Lexer = Lexer_Tokenize(source); + Print(" [tokens: "); + PrintInt(lex.tokenCount as int64); + PrintLine("]"); if Lexer_DiagCount(lex) > 0 { Print(" Lex errors in "); PrintLine(path); diff --git a/src/parser.bux b/src/parser.bux index 03c5d88..31a0b02 100644 --- a/src/parser.bux +++ b/src/parser.bux @@ -1002,6 +1002,11 @@ func parserParseFuncDecl(p: *Parser, isPublic: bool, isExtern: bool, isAsync: bo // Body if !isExtern && parserCheck(p, tkLBrace) { d.refBody = parserParseBlock(p); + // HACK: consume any leftover } that parserParseBlock may have missed + // Without this, the module handler sees the } and exits early. + if parserCheck(p, tkRBrace) { + discard parserAdvance(p); + } } else { d.refBody = null as *Block; } @@ -2033,11 +2038,24 @@ func parserParseDecl(p: *Parser) -> *Decl { discard parserAdvance(p); // consume { var items: *Decl = null as *Decl; var lastItem: *Decl = null as *Decl; - while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile { + var moduleDepth: int = 1; + while moduleDepth > 0 && parserPeek(p, 0) != tkEndOfFile { if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; } + // Track stray braces that parserParseDecl may have left behind + if parserCheck(p, tkLBrace) { + moduleDepth = moduleDepth + 1; + discard parserAdvance(p); + continue; + } + if parserCheck(p, tkRBrace) { + moduleDepth = moduleDepth - 1; + discard parserAdvance(p); + if moduleDepth <= 0 { break; } + continue; + } let beforePos: int = p.pos; let item: *Decl = parserParseDecl(p); if item != null as *Decl { @@ -2055,7 +2073,6 @@ func parserParseDecl(p: *Parser) -> *Decl { discard parserAdvance(p); } } - discard parserExpect(p, tkRBrace, "expected '}' to close module"); d.childDecl1 = items; // first item of module } else { parserMatch(p, tkSemicolon);