diff --git a/_test_parse_recovery/bux.toml b/_test_parse_recovery/bux.toml
new file mode 100644
index 0000000..7d66b12
--- /dev/null
+++ b/_test_parse_recovery/bux.toml
@@ -0,0 +1,4 @@
+[Package]
+Name = "parse_recovery"
+Version = "0.1.0"
+Type = "bin"
diff --git a/_test_parse_recovery/src/Main.bux b/_test_parse_recovery/src/Main.bux
new file mode 100644
index 0000000..916ab77
--- /dev/null
+++ b/_test_parse_recovery/src/Main.bux
@@ -0,0 +1,18 @@
+func Good() -> int {
+ return 1;
+}
+
+func Bad() -> int {
+ let x: int = ;
+ return 0;
+}
+
+func AlsoBad() -> int {
+ let y: int = 5 + ;
+ let z: int = 6;
+ return y;
+}
+
+func AlsoGood() -> int {
+ return 2;
+}
diff --git a/src/ast.bux b/src/ast.bux
index 6d8dea8..524416f 100644
--- a/src/ast.bux
+++ b/src/ast.bux
@@ -373,6 +373,16 @@ module Ast {
// Struct fields (up to 256)
}
+ // ---------------------------------------------------------------------------
+ // Parser diagnostic (recoverable errors collected during parsing)
+ // ---------------------------------------------------------------------------
+ struct ParserDiag {
+ line: uint32,
+ column: uint32,
+ message: String,
+ severity: int, /* 0=error (fatal), 1=warning (recoverable) */
+ }
+
// ---------------------------------------------------------------------------
// Module — AST root
// ---------------------------------------------------------------------------
@@ -381,6 +391,8 @@ module Ast {
path: String, // path segments joined
itemCount: int,
firstItem: *Decl,
+ diagCount: int,
+ diags: *ParserDiag,
}
// ---------------------------------------------------------------------------
diff --git a/src/cli.bux b/src/cli.bux
index 23abff2..523852e 100644
--- a/src/cli.bux
+++ b/src/cli.bux
@@ -358,6 +358,28 @@ module Cli {
// Import the compiler pipeline
// In self-hosting mode, these are compiled together from src/
+// ---------------------------------------------------------------------------
+// Report parser diagnostics attached to a module (Rust-style, with snippets).
+// Returns the number of diagnostics reported (0 = clean).
+// ---------------------------------------------------------------------------
+
+func Cli_ReportParseDiags(mod: *Module, sourceName: String) -> int {
+ if mod == null as *Module { return 0; }
+ if mod.diagCount == 0 { return 0; }
+ var i: int = 0;
+ while i < mod.diagCount {
+ let diag: Diagnostic = Diagnostic {
+ message: mod.diags[i].message,
+ line: mod.diags[i].line,
+ column: mod.diags[i].column,
+ severity: 0,
+ };
+ Diagnostic_Print(&diag, sourceName);
+ i = i + 1;
+ }
+ return mod.diagCount;
+}
+
// ---------------------------------------------------------------------------
// Compile a single .bux source file
// ---------------------------------------------------------------------------
@@ -389,6 +411,7 @@ func Cli_Compile(source: String, sourceName: String, targetTriple: String) -> St
PrintLine("Parse failed");
return "";
}
+ if Cli_ReportParseDiags(mod, sourceName) > 0 { return ""; }
PrintLine(" Parse done");
// Flatten module wrappers: find module decl and hoist its children
@@ -551,6 +574,7 @@ func Cli_Check(srcPath: String) -> int {
PrintLine("Parse failed");
return 1;
}
+ if Cli_ReportParseDiags(mod, srcPath) > 0 { return 1; }
PrintLine(" Parse done");
// Flatten module wrappers
@@ -635,6 +659,7 @@ func Cli_CompileSource(source: String, sourceName: String) -> *HirModule {
PrintLine(sourceName);
return null as *HirModule;
}
+ if Cli_ReportParseDiags(mod, sourceName) > 0 { return null as *HirModule; }
// Phase 2b: macro expand
let macEx3: *MacroExpander = MacroExpand_ExpandModule(mod);
@@ -836,6 +861,10 @@ func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCo
if Lexer_DiagCount(lex) > 0 { return 0; }
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
if mod == null as *Module { return 0; }
+ // Report parse diags but keep merging the recovered decls: this path
+ // handles stdlib/dependency files, and the parser currently emits
+ // recoverable diags for valid multi-line braced imports there.
+ discard Cli_ReportParseDiags(mod, path);
// Tag every decl from this file for #line maps
var stamp: *Decl = mod.firstItem;
while stamp != null as *Decl {
@@ -1928,6 +1957,8 @@ func Cli_BuildProject(projectDir: String, targetTriple: String, isRelease: bool,
userMerged.path = "";
userMerged.itemCount = 0;
userMerged.firstItem = null as *Decl;
+ userMerged.diagCount = 0;
+ userMerged.diags = null as *ParserDiag;
// Parse each file and merge declarations into userMerged module
var i: int = 0;
@@ -1962,6 +1993,7 @@ func Cli_BuildProject(projectDir: String, targetTriple: String, isRelease: bool,
PrintLine(path);
return 1;
}
+ if Cli_ReportParseDiags(mod, path) > 0 { return 1; }
// Tag decls with this source path for multi-file #line
var stampUser: *Decl = mod.firstItem;
while stampUser != null as *Decl {
@@ -2031,6 +2063,8 @@ func Cli_BuildProject(projectDir: String, targetTriple: String, isRelease: bool,
merged.path = "";
merged.itemCount = 0;
merged.firstItem = null as *Decl;
+ merged.diagCount = 0;
+ merged.diags = null as *ParserDiag;
// Find and merge ALL stdlib declarations
let stdlibDir: String = Cli_FindStdlibDir(projectDir);
diff --git a/src/parser.bux b/src/parser.bux
index 84a0ad4..b5158c6 100644
--- a/src/parser.bux
+++ b/src/parser.bux
@@ -30,13 +30,6 @@ module Parser {
macroTemplateMode: bool, // allows $(…)* in macro! bodies
}
- struct ParserDiag {
- line: uint32,
- column: uint32,
- message: String,
- severity: int, /* 0=error (fatal), 1=warning (recoverable) */
- }
-
// ---------------------------------------------------------------------------
// Token helpers
// ---------------------------------------------------------------------------
@@ -2827,34 +2820,9 @@ module Parser {
}
}
- /* Print fatal parser diagnostics (severity == 0) or if nothing valid was parsed */
- if p.diagCount > 0 && mod.itemCount == 0 {
- var di: int = 0;
- while di < p.diagCount {
- let d: ParserDiag = p.diags[di];
- Print("error: ");
- PrintLine(d.message);
- Print(" --> :");
- PrintInt(d.line as int64);
- Print(":");
- PrintInt(d.column as int64);
- PrintLine("");
- Print(" |");
- PrintLine("");
- Print(" ");
- PrintInt(d.line as int64);
- Print(" | ");
- PrintLine("");
- Print(" | ");
- var sp: uint32 = 0;
- while sp < d.column - 1 && sp < 120 {
- Print(" ");
- sp = sp + 1;
- }
- PrintLine("^");
- di = di + 1;
- }
- }
+ // Attach parser diagnostics to the module; the CLI reports them
+ mod.diagCount = p.diagCount;
+ mod.diags = p.diags;
return mod;
}