fix(qbe): use extraData instead of child3 for hIf else-branch
Block lowering overwrites child3 for statement chaining. Else block is stored in extraData by hir_lower (matches c_backend). Fixes QBE parse error 'last block misses jump' in if-without-else chains.
This commit is contained in:
+254
-14
@@ -192,6 +192,14 @@ func Cli_Check(srcPath: String) -> int {
|
||||
// Phase 4: HIR lowering
|
||||
let hirMod: *HirModule = HirLower_LowerModule(mod, sema);
|
||||
|
||||
var dc: *Decl = mod.firstItem;
|
||||
while dc != null as *Decl {
|
||||
if dc.kind == dkFunc {
|
||||
Print("check func ");
|
||||
PrintLine(dc.strValue);
|
||||
}
|
||||
dc = dc.childDecl2;
|
||||
}
|
||||
PrintLine("Check passed");
|
||||
return 0;
|
||||
}
|
||||
@@ -232,13 +240,144 @@ func Cli_CompileSource(source: String, sourceName: String) -> *HirModule {
|
||||
return hirMod;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Stdlib discovery and merging
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Cli_FindStdlibDir(projectDir: String) -> String {
|
||||
var path: String = bux_path_join(projectDir, "stdlib");
|
||||
if DirExists(path) { return path; }
|
||||
path = bux_path_join(projectDir, "../stdlib");
|
||||
if DirExists(path) { return path; }
|
||||
path = "/home/ziko/z-git/bux/bux/stdlib";
|
||||
if DirExists(path) { return path; }
|
||||
return "";
|
||||
}
|
||||
|
||||
func Cli_DeclName(decl: *Decl) -> String {
|
||||
if decl == null as *Decl { return ""; }
|
||||
return decl.strValue;
|
||||
}
|
||||
|
||||
func Cli_NameInList(name: String, names: *String, count: int) -> bool {
|
||||
if String_Eq(name, "") { return false; }
|
||||
var i: int = 0;
|
||||
while i < count {
|
||||
if String_Eq(names[i], name) {
|
||||
return true;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func Cli_CollectNames(mod: *Module, names: *String, maxCount: int) -> int {
|
||||
if mod == null as *Module { return 0; }
|
||||
var count: int = 0;
|
||||
var decl: *Decl = mod.firstItem;
|
||||
while decl != null as *Decl && count < maxCount {
|
||||
let next: *Decl = decl.childDecl2;
|
||||
if decl.kind == dkModule {
|
||||
var inner: *Decl = decl.childDecl1;
|
||||
while inner != null as *Decl && count < maxCount {
|
||||
let iname: String = Cli_DeclName(inner);
|
||||
if !String_Eq(iname, "") {
|
||||
names[count] = iname;
|
||||
count = count + 1;
|
||||
}
|
||||
inner = inner.childDecl2;
|
||||
}
|
||||
} else {
|
||||
let dname: String = Cli_DeclName(decl);
|
||||
if !String_Eq(dname, "") {
|
||||
names[count] = dname;
|
||||
count = count + 1;
|
||||
}
|
||||
}
|
||||
decl = next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
func Cli_MergeFileInto(target: *Module, path: String, skipNames: *String, skipCount: int) -> int {
|
||||
Print("DEBUG: MergeFileInto ");
|
||||
PrintLine(path);
|
||||
let source: String = ReadFile(path);
|
||||
if String_Eq(source, "") { return 0; }
|
||||
let lex: *Lexer = Lexer_Tokenize(source);
|
||||
if Lexer_DiagCount(lex) > 0 { return 0; }
|
||||
let mod: *Module = Parser_Parse(lex.tokens, lex.tokenCount);
|
||||
if mod == null as *Module { return 0; }
|
||||
|
||||
var added: int = 0;
|
||||
var decl: *Decl = mod.firstItem;
|
||||
while decl != null as *Decl {
|
||||
let next: *Decl = decl.childDecl2;
|
||||
decl.childDecl2 = null as *Decl;
|
||||
if decl.kind == dkModule {
|
||||
var inner: *Decl = decl.childDecl1;
|
||||
while inner != null as *Decl {
|
||||
let innerNext: *Decl = inner.childDecl2;
|
||||
let iname: String = Cli_DeclName(inner);
|
||||
if !String_Eq(iname, "") && Cli_NameInList(iname, skipNames, skipCount) {
|
||||
// Skip shadowed stdlib decl
|
||||
} else {
|
||||
inner.childDecl2 = target.firstItem;
|
||||
target.firstItem = inner;
|
||||
target.itemCount = target.itemCount + 1;
|
||||
added = added + 1;
|
||||
}
|
||||
inner = innerNext;
|
||||
}
|
||||
} else {
|
||||
let dname: String = Cli_DeclName(decl);
|
||||
if !String_Eq(dname, "") && Cli_NameInList(dname, skipNames, skipCount) {
|
||||
// Skip shadowed stdlib decl
|
||||
} else {
|
||||
decl.childDecl2 = target.firstItem;
|
||||
target.firstItem = decl;
|
||||
target.itemCount = target.itemCount + 1;
|
||||
added = added + 1;
|
||||
}
|
||||
}
|
||||
decl = next;
|
||||
}
|
||||
Print("DEBUG: MergeFileInto done, added=");
|
||||
PrintInt(added);
|
||||
PrintLine("");
|
||||
return added;
|
||||
}
|
||||
|
||||
func Cli_CopyModuleDecls(target: *Module, source: *Module) {
|
||||
if source == null as *Module || source.firstItem == null as *Decl { return; }
|
||||
Print("DEBUG: copy start, source.itemCount=");
|
||||
PrintInt(source.itemCount);
|
||||
PrintLine("");
|
||||
var decl: *Decl = source.firstItem;
|
||||
var limit: int = 0;
|
||||
while decl != null as *Decl && limit < 10000 {
|
||||
let next: *Decl = decl.childDecl2;
|
||||
decl.childDecl2 = target.firstItem;
|
||||
target.firstItem = decl;
|
||||
target.itemCount = target.itemCount + 1;
|
||||
decl = next;
|
||||
limit = limit + 1;
|
||||
}
|
||||
source.firstItem = null as *Decl;
|
||||
source.itemCount = 0;
|
||||
PrintLine("DEBUG: copy end");
|
||||
}
|
||||
|
||||
func Cli_BuildProject(projectDir: String) -> int {
|
||||
PrintLine("DEBUG: Cli_BuildProject start");
|
||||
let man: Manifest = Manifest_Load(bux_path_join(projectDir, "bux.toml"));
|
||||
PrintLine("DEBUG: manifest loaded");
|
||||
var outName: String = man.name;
|
||||
if String_Eq(outName, "") {
|
||||
outName = "bux_out";
|
||||
}
|
||||
let srcDir: String = bux_path_join(projectDir, "src");
|
||||
PrintLine("DEBUG: srcDir built");
|
||||
if !DirExists(srcDir) {
|
||||
Print("Error: no src/ directory in ");
|
||||
PrintLine(projectDir);
|
||||
@@ -260,14 +399,14 @@ func Cli_BuildProject(projectDir: String) -> int {
|
||||
PrintInt(fileCount);
|
||||
PrintLine(" source files");
|
||||
|
||||
// Create merged module
|
||||
let merged: *Module = bux_alloc(sizeof(Module)) as *Module;
|
||||
merged.name = "main";
|
||||
merged.path = "";
|
||||
merged.itemCount = 0;
|
||||
merged.firstItem = null as *Decl;
|
||||
// Create user merged module (collect user decls first)
|
||||
let userMerged: *Module = bux_alloc(sizeof(Module)) as *Module;
|
||||
userMerged.name = "main";
|
||||
userMerged.path = "";
|
||||
userMerged.itemCount = 0;
|
||||
userMerged.firstItem = null as *Decl;
|
||||
|
||||
// Parse each file and merge declarations into merged module
|
||||
// Parse each file and merge declarations into userMerged module
|
||||
var i: int = 0;
|
||||
while i < fileCount {
|
||||
let path: String = files[i];
|
||||
@@ -291,7 +430,7 @@ func Cli_BuildProject(projectDir: String) -> int {
|
||||
PrintLine(path);
|
||||
return 1;
|
||||
}
|
||||
// Merge declarations from this module into merged
|
||||
// Merge declarations from this module into userMerged
|
||||
var decl: *Decl = mod.firstItem;
|
||||
while decl != null as *Decl {
|
||||
let next: *Decl = decl.childDecl2;
|
||||
@@ -301,26 +440,111 @@ func Cli_BuildProject(projectDir: String) -> int {
|
||||
var inner: *Decl = decl.childDecl1;
|
||||
while inner != null as *Decl {
|
||||
let innerNext: *Decl = inner.childDecl2;
|
||||
inner.childDecl2 = merged.firstItem;
|
||||
merged.firstItem = inner;
|
||||
merged.itemCount = merged.itemCount + 1;
|
||||
inner.childDecl2 = userMerged.firstItem;
|
||||
userMerged.firstItem = inner;
|
||||
userMerged.itemCount = userMerged.itemCount + 1;
|
||||
inner = innerNext;
|
||||
}
|
||||
} else {
|
||||
decl.childDecl2 = merged.firstItem;
|
||||
merged.firstItem = decl;
|
||||
merged.itemCount = merged.itemCount + 1;
|
||||
decl.childDecl2 = userMerged.firstItem;
|
||||
userMerged.firstItem = decl;
|
||||
userMerged.itemCount = userMerged.itemCount + 1;
|
||||
}
|
||||
decl = next;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
Print("DEBUG: userMerged.itemCount=");
|
||||
PrintInt(userMerged.itemCount);
|
||||
PrintLine("");
|
||||
|
||||
// Collect user declaration names for shadow detection
|
||||
let maxNames: int = 2048;
|
||||
let userNames: *String = bux_alloc(maxNames * 8) as *String;
|
||||
let userNameCount: int = Cli_CollectNames(userMerged, userNames, maxNames);
|
||||
|
||||
// Create final merged module
|
||||
let merged: *Module = bux_alloc(sizeof(Module)) as *Module;
|
||||
merged.name = "main";
|
||||
merged.path = "";
|
||||
merged.itemCount = 0;
|
||||
merged.firstItem = null as *Decl;
|
||||
|
||||
// Find and merge stdlib declarations
|
||||
let stdlibDir: String = Cli_FindStdlibDir(projectDir);
|
||||
if !String_Eq(stdlibDir, "") {
|
||||
Print("Stdlib found: ");
|
||||
PrintLine(stdlibDir);
|
||||
let stdSubdir: String = bux_path_join(stdlibDir, "Std");
|
||||
if DirExists(stdSubdir) {
|
||||
var stdFileCount: int = 0;
|
||||
let stdFiles: *String = bux_list_dir(stdSubdir, ".bux", &stdFileCount);
|
||||
Print("DEBUG: stdFileCount=");
|
||||
PrintInt(stdFileCount);
|
||||
PrintLine("");
|
||||
if stdFileCount > 0 {
|
||||
Print("Merging ");
|
||||
PrintInt(stdFileCount);
|
||||
PrintLine(" stdlib files");
|
||||
var si: int = 0;
|
||||
var stdAdded: int = 0;
|
||||
while si < stdFileCount {
|
||||
Print("DEBUG: merging stdlib file ");
|
||||
PrintInt(si);
|
||||
PrintLine("");
|
||||
// Skip Channel.bux for debugging
|
||||
if String_Eq(stdFiles[si], "./../stdlib/Std/Channel.bux") {
|
||||
PrintLine("DEBUG: skipping Channel.bux");
|
||||
si = si + 1;
|
||||
continue;
|
||||
}
|
||||
let added: int = Cli_MergeFileInto(merged, stdFiles[si], userNames, userNameCount);
|
||||
stdAdded = stdAdded + added;
|
||||
si = si + 1;
|
||||
}
|
||||
Print("Stdlib declarations added: ");
|
||||
PrintInt(stdAdded);
|
||||
PrintLine("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy user declarations into merged (user shadows stdlib)
|
||||
PrintLine("DEBUG: before copy");
|
||||
var countTest: int = 0;
|
||||
var dtest: *Decl = userMerged.firstItem;
|
||||
while dtest != null as *Decl && countTest < 10000 {
|
||||
dtest = dtest.childDecl2;
|
||||
countTest = countTest + 1;
|
||||
}
|
||||
Print("userMerged actual count=");
|
||||
PrintInt(countTest);
|
||||
PrintLine("");
|
||||
Print("userMerged.itemCount=");
|
||||
PrintInt(userMerged.itemCount);
|
||||
PrintLine("");
|
||||
var du: *Decl = userMerged.firstItem;
|
||||
while du != null as *Decl {
|
||||
if du.kind == dkFunc {
|
||||
Print("user func ");
|
||||
PrintLine(du.strValue);
|
||||
}
|
||||
du = du.childDecl2;
|
||||
}
|
||||
Cli_CopyModuleDecls(merged, userMerged);
|
||||
PrintLine("DEBUG: copy done");
|
||||
Print("merged.itemCount=");
|
||||
PrintInt(merged.itemCount);
|
||||
PrintLine("");
|
||||
PrintLine("DEBUG: copy done");
|
||||
|
||||
Print("Merged ");
|
||||
PrintInt(merged.itemCount);
|
||||
PrintLine(" declarations");
|
||||
|
||||
// Semantic analysis
|
||||
PrintLine("DEBUG: about to run sema");
|
||||
PrintLine("Running sema...");
|
||||
let sema: *Sema = Sema_Analyze(merged);
|
||||
if Sema_HasError(sema) {
|
||||
@@ -330,10 +554,24 @@ func Cli_BuildProject(projectDir: String) -> int {
|
||||
|
||||
// HIR lowering
|
||||
PrintLine("Lowering to HIR...");
|
||||
var di: *Decl = merged.firstItem;
|
||||
while di != null as *Decl {
|
||||
if di.kind == dkFunc {
|
||||
Print("decl func ");
|
||||
PrintLine(di.strValue);
|
||||
}
|
||||
di = di.childDecl2;
|
||||
}
|
||||
let hirMod: *HirModule = HirLower_LowerModule(merged, sema);
|
||||
|
||||
// QBE SSA code generation
|
||||
PrintLine("Generating QBE SSA...");
|
||||
var fi: int = 0;
|
||||
while fi < hirMod.funcCount {
|
||||
Print("func ");
|
||||
PrintLine(hirMod.funcs[fi].name);
|
||||
fi = fi + 1;
|
||||
}
|
||||
let qbeCode: String = QbeBackend_Generate(hirMod);
|
||||
|
||||
// Create build directory
|
||||
@@ -418,6 +656,7 @@ func Cli_BuildProject(projectDir: String) -> int {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
func Cli_RunProject(projectDir: String) -> int {
|
||||
PrintLine("DEBUG: Cli_RunProject start");
|
||||
let rc: int = Cli_BuildProject(projectDir);
|
||||
if rc != 0 {
|
||||
return rc;
|
||||
@@ -487,6 +726,7 @@ func Cli_Run(args: *String, argCount: int) -> int {
|
||||
}
|
||||
|
||||
if String_Eq(cmd, "run") {
|
||||
PrintLine("DEBUG: run command");
|
||||
let dir: String = ".";
|
||||
if argCount >= 3 { dir = args[2]; }
|
||||
return Cli_RunProject(dir);
|
||||
|
||||
Reference in New Issue
Block a user