feat(selfhost): multi-file #line paths from Decl.sourceFile

Stamp each merged .bux path onto decls, propagate to HirFunc, and emit
#line N \"path\" per function without requiring BUX_DEBUG_FILE.

- Decl.sourceFile + Cli_StampSourceFile on merge/project parse
- HirFunc.sourceFile; CBE switches currentFile per function
- Stdlib and multi-file user packages get distinct paths automatically
This commit is contained in:
2026-07-19 23:13:02 +03:00
parent ed07cf8921
commit 70321075a6
7 changed files with 75 additions and 10 deletions
+3
View File
@@ -299,6 +299,8 @@ module Ast {
isDrop: int, // @[Drop] attribute (0/1)
isRelease: int, // @[Release] attribute (0/1)
isConst: int, // const func (0/1)
// Source file path for #line / diagnostics (multi-file projects)
sourceFile: String,
// Names
strValue: String, // decl name
strValue2: String, // interface name, dll name, module path
@@ -418,6 +420,7 @@ module Ast {
func Ast_MakeDecl(kind: int, line: uint32, col: uint32) -> Decl {
return Decl { kind: kind, line: line, column: col, isPublic: false,
sourceFile: "",
isAsync: false, isChecked: 0, isDrop: 0, isRelease: 0, isConst: 0,
strValue: "", strValue2: "",
typeParam0: "", typeParam1: "", typeParamCount: 0,
+12 -1
View File
@@ -1407,7 +1407,7 @@ module CBackend {
cbe.lastDebugLine = 0;
cbe.emitDebugLines = true;
cbe.currentFile = "";
// Optional: BUX_DEBUG_FILE sets the #line path for gdb (selfhost has no multi-file loc yet)
// Optional override for all #line paths (default: per-func Decl.sourceFile)
let dbgFile: String = bux_getenv("BUX_DEBUG_FILE");
if dbgFile != null as String && !String_Eq(dbgFile, "") {
cbe.currentFile = dbgFile;
@@ -1696,6 +1696,17 @@ module CBackend {
i = i + 1;
continue;
}
// Per-function source path for multi-file #line (overrides BUX_DEBUG_FILE only if set)
if !String_Eq(mod.funcs[i].sourceFile, "") {
cbe.currentFile = mod.funcs[i].sourceFile;
}
cbe.lastDebugLine = 0;
// #line before the function itself
if cbe.emitDebugLines && !String_Eq(cbe.currentFile, "") {
StringBuilder_Append(&cbe.sb, "#line 1 \"");
StringBuilder_Append(&cbe.sb, cbe.currentFile);
StringBuilder_Append(&cbe.sb, "\"\n");
}
CBE_EmitFuncDecl(cbe, &mod.funcs[i]);
StringBuilder_Append(&cbe.sb, " {\n");
// Capturing closure thunk: materialize env from fat-func env pointer
+33
View File
@@ -611,6 +611,27 @@ func Cli_CollectStdlibImports(mod: *Module, outPaths: *String, maxCount: int, st
return count;
}
/// Stamp sourceFile on a decl and nested module items (for multi-file #line).
func Cli_StampSourceFile(decl: *Decl, path: String) {
if decl == null as *Decl { return; }
decl.sourceFile = path;
if decl.kind == dkModule {
var inner: *Decl = decl.childDecl1;
while inner != null as *Decl {
Cli_StampSourceFile(inner, path);
inner = inner.childDecl2;
}
}
// Impl methods
if decl.kind == dkImpl {
var m: *Decl = decl.childDecl1;
while m != null as *Decl {
Cli_StampSourceFile(m, path);
m = m.childDecl2;
}
}
}
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
if !FileExists(path) {
Print("Error: stdlib file not found: ");
@@ -623,6 +644,12 @@ 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; }
// Tag every decl from this file for #line maps
var stamp: *Decl = mod.firstItem;
while stamp != null as *Decl {
Cli_StampSourceFile(stamp, path);
stamp = stamp.childDecl2;
}
var added: int = 0;
var decl: *Decl = mod.firstItem;
@@ -1431,6 +1458,12 @@ func Cli_BuildProject(projectDir: String, targetTriple: String, isRelease: bool)
PrintLine(path);
return 1;
}
// Tag decls with this source path for multi-file #line
var stampUser: *Decl = mod.firstItem;
while stampUser != null as *Decl {
Cli_StampSourceFile(stampUser, path);
stampUser = stampUser.childDecl2;
}
// Merge declarations from this module into userMerged
var decl: *Decl = mod.firstItem;
var fileDeclCount: int = 0;
+2
View File
@@ -115,6 +115,8 @@ module Hir {
envStructName: String;
envInstanceName: String;
checkedFunc: bool;
// Absolute/relative path for #line maps (multi-file selfhost)
sourceFile: String;
}
// ---------------------------------------------------------------------------
+1
View File
@@ -3423,6 +3423,7 @@ module HirLower {
f.name = decl.strValue;
f.isPublic = decl.isPublic;
f.checkedFunc = ctx.checkedFunc;
f.sourceFile = decl.sourceFile;
f.paramCount = decl.paramCount;
f.param0 = bux_alloc(sizeof(HirParam)) as *HirParam;
Lcx_LowerParam(f.param0, &decl.param0, ctx);