feat: add selfhost-loop determinism check, golden tests, improve sema diagnostics

- Makefile: new targets `test-golden` and `selfhost-loop`
  - selfhost-loop verifies C codegen determinism (2-pass bootstrap)
  - test-golden compares C output against expected.c golden files
  - Updated clean-all to clean new build dirs
- tests/golden/hello/: first golden test (hello world)
- src/sema.bux:
  - Fix: import stubs only registered if symbol doesn't already exist
  - Improve: error message now includes identifier name
This commit is contained in:
2026-06-07 15:47:48 +03:00
parent 3b4456f01f
commit 1f0baefa5a
5 changed files with 3006 additions and 5 deletions
+11 -3
View File
@@ -165,7 +165,9 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
if kind == ekIdent {
let sym: Symbol = Scope_Lookup(sema.scope, expr.strValue);
if sym.kind == 0 && !String_Eq(sym.name, expr.strValue) {
Sema_EmitError(sema, expr.line, expr.column, "undeclared identifier");
let errMsg: String = String_Concat("undeclared identifier '", expr.strValue);
let errMsg2: String = String_Concat(errMsg, "'");
Sema_EmitError(sema, expr.line, expr.column, errMsg2);
return tyUnknown;
}
if sym.typeName != null as String && !String_Eq(sym.typeName, "") {
@@ -565,7 +567,10 @@ func Sema_CollectGlobals(sema: *Sema) {
sym.isMutable = false;
sym.isPublic = true;
sym.decl = null as *Decl;
discard Scope_Define(sema.scope, sym);
let existing: Symbol = Scope_LookupLocal(sema.scope, name);
if !String_Eq(existing.name, name) {
discard Scope_Define(sema.scope, sym);
}
}
start = pos + 1;
}
@@ -600,7 +605,10 @@ func Sema_CollectGlobals(sema: *Sema) {
sym.isMutable = false;
sym.isPublic = true;
sym.decl = null as *Decl;
discard Scope_Define(sema.scope, sym);
let existing: Symbol = Scope_LookupLocal(sema.scope, lastSeg);
if !String_Eq(existing.name, lastSeg) {
discard Scope_Define(sema.scope, sym);
}
}
}
}