fix(selfhost): green fixed-point buxc2→buxc3→buxc4
Raise scope/HIR buffer caps, parenthesize unary operands, fix fat-func typedef and param access so selfhost-built compilers recompile src identically (path-normalized C + stripped ELF).
This commit is contained in:
@@ -62,7 +62,7 @@ clean:
|
|||||||
rm -rf _test_cast _test_cast2 _test_cast3 _test_channel
|
rm -rf _test_cast _test_cast2 _test_cast3 _test_channel
|
||||||
|
|
||||||
clean-all: clean
|
clean-all: clean
|
||||||
rm -rf build/selfhost build/selfhost-loop-a build/selfhost-loop-b
|
rm -rf build/selfhost build/selfhost-loop-a build/selfhost-loop-b build/selfhost-loop-c
|
||||||
rm -rf tests/golden/*/build
|
rm -rf tests/golden/*/build
|
||||||
|
|
||||||
selfhost: build
|
selfhost: build
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ make test-registry # add greet → install → build temp app
|
|||||||
|
|
||||||
# Selfhost determinism (optional CI job; not in default `make test`)
|
# Selfhost determinism (optional CI job; not in default `make test`)
|
||||||
make selfhost-loop
|
make selfhost-loop
|
||||||
# Experimental fixed-point (buxc2 → buxc3):
|
# Full fixed-point: buxc2 → buxc3 → buxc4 (gen2 vs gen3 C+ELF identical)
|
||||||
# BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop
|
# BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop
|
||||||
|
|
||||||
# Clean build artifacts
|
# Clean build artifacts
|
||||||
|
|||||||
@@ -192,11 +192,12 @@ Use `Std::Test` module for assertions inside test code.
|
|||||||
### Selfhost loop (optional CI)
|
### Selfhost loop (optional CI)
|
||||||
```bash
|
```bash
|
||||||
make selfhost-loop # bootstrap builds src/ twice; C+ELF match
|
make selfhost-loop # bootstrap builds src/ twice; C+ELF match
|
||||||
BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop # also buxc2→buxc3 (experimental)
|
BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop # buxc2→buxc3→buxc4 fixed-point
|
||||||
```
|
```
|
||||||
Not part of default `make test`. GitHub Actions workflow
|
Fixed-point compares **gen2 vs gen3** (same selfhost C backend), not bootstrap
|
||||||
`.github/workflows/selfhost-loop.yml` runs it on:
|
vs selfhost. Not part of default `make test`. GitHub Actions workflow
|
||||||
- manual `workflow_dispatch`
|
`.github/workflows/selfhost-loop.yml` runs the fast determinism check on:
|
||||||
|
- manual `workflow_dispatch` (optional fixed_point input)
|
||||||
- weekly schedule
|
- weekly schedule
|
||||||
- pushes to `main` that touch `src/`, `lib/`, bootstrap, or the loop script
|
- pushes to `main` that touch `src/`, `lib/`, bootstrap, or the loop script
|
||||||
|
|
||||||
|
|||||||
+19
-5
@@ -1,7 +1,7 @@
|
|||||||
# Bux — План към „добър“ език (v0.5 → v1.0)
|
# Bux — План към „добър“ език (v0.5 → v1.0)
|
||||||
|
|
||||||
> **Дата:** 2026-07-19
|
> **Дата:** 2026-07-19
|
||||||
> **Текущо:** v0.5.x — Expr/Stmt sourceFile, LSP 0.14, selfhost-loop CI
|
> **Текущо:** v0.5.x — **selfhost fixed-point green**, Expr/Stmt sourceFile, LSP 0.14
|
||||||
> **Цел:** Език, с който се пишат реални проекти комфортно, безопасно (по избор) и с надежден toolchain.
|
> **Цел:** Език, с който се пишат реални проекти комфортно, безопасно (по избор) и с надежден toolchain.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -812,9 +812,23 @@ A (stdlib ergonomics) → B (compiler holes) → C (ownership depth)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Сесия 52 (selfhost fixed-point buxc2→buxc3→buxc4 green)
|
||||||
|
|
||||||
|
1. **Sema global scope:** allocate via `Scope_New` (8192), not 1024 — heap
|
||||||
|
overflow on ~1200 decls crashed buxc2 in `Scope_Lookup`
|
||||||
|
2. **HIR buffers:** funcs 512→4096, structs 64→512, enums/consts/gen* raised
|
||||||
|
3. **`CBE_FuncParam`:** avoid nested `.paramN.name` on `*HirParam` (wrong `.` vs `->`)
|
||||||
|
4. **Adapters:** `__fat_env` not `env` (no clash with `CtfeEnv* env`)
|
||||||
|
5. **Unary `!`:** parenthesize operand so `!(a && b)` ≠ `!a && b`
|
||||||
|
6. **Fat typedef skip-void:** rewritten without nested `!` for older gens
|
||||||
|
7. **Fixed-point loop:** compare gen2 vs gen3 (same CBE), not bootstrap vs selfhost
|
||||||
|
8. Verified: `BUX_SELFHOST_FIXED_POINT=1 make selfhost-loop` — C+ELF IDENTICAL
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Следващи стъпки
|
## Следващи стъпки
|
||||||
|
|
||||||
1. Fix selfhost C backend so buxc2→buxc3 fixed-point is green
|
1. Main PR CI workflow (`make test`) beyond optional selfhost-loop
|
||||||
2. Main PR CI workflow (`make test`) beyond optional selfhost-loop
|
2. LSP type hierarchy / prepareTypeHierarchy (optional)
|
||||||
3. LSP type hierarchy / prepareTypeHierarchy (optional)
|
3. Macro / quote hygiene using Expr.sourceFile grafts
|
||||||
4. Macro / quote hygiene using Expr.sourceFile grafts
|
4. Parenthesize binary ops in CBE for full C precedence safety
|
||||||
|
|||||||
+49
-36
@@ -385,10 +385,12 @@ module CBackend {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unary
|
// Unary — always parenthesize operand so `!(a && b)` is not `!a && b`
|
||||||
if kind == hUnary {
|
if kind == hUnary {
|
||||||
StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue));
|
StringBuilder_Append(&cbe.sb, CBackend_OpToC(node.intValue));
|
||||||
|
StringBuilder_Append(&cbe.sb, "(");
|
||||||
CBE_EmitExpr(cbe, node.child1);
|
CBE_EmitExpr(cbe, node.child1);
|
||||||
|
StringBuilder_Append(&cbe.sb, ")");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -938,15 +940,8 @@ module CBackend {
|
|||||||
var p: int = 0;
|
var p: int = 0;
|
||||||
while p < mod.funcs[i].paramCount {
|
while p < mod.funcs[i].paramCount {
|
||||||
var ptype: String = "";
|
var ptype: String = "";
|
||||||
if p == 0 { ptype = mod.funcs[i].param0.typeName; }
|
let hp: *HirParam = CBE_FuncParam(&mod.funcs[i], p);
|
||||||
else if p == 1 { ptype = mod.funcs[i].param1.typeName; }
|
if hp != null as *HirParam { ptype = hp.typeName; }
|
||||||
else if p == 2 { ptype = mod.funcs[i].param2.typeName; }
|
|
||||||
else if p == 3 { ptype = mod.funcs[i].param3.typeName; }
|
|
||||||
else if p == 4 { ptype = mod.funcs[i].param4.typeName; }
|
|
||||||
else if p == 5 { ptype = mod.funcs[i].param5.typeName; }
|
|
||||||
else if p == 6 { ptype = mod.funcs[i].param6.typeName; }
|
|
||||||
else if p == 7 { ptype = mod.funcs[i].param7.typeName; }
|
|
||||||
else if p == 8 { ptype = mod.funcs[i].param8.typeName; }
|
|
||||||
CBE_MaybeEmitExtraFat(cbe, ptype);
|
CBE_MaybeEmitExtraFat(cbe, ptype);
|
||||||
p = p + 1;
|
p = p + 1;
|
||||||
}
|
}
|
||||||
@@ -961,6 +956,22 @@ module CBackend {
|
|||||||
CBE_EmitOneFatTypedef(cbe, name);
|
CBE_EmitOneFatTypedef(cbe, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load param pointer by index (avoids nested `.paramN.name` on *HirParam —
|
||||||
|
/// selfhost CBE may emit `.` instead of `->` for chained pointer fields).
|
||||||
|
func CBE_FuncParam(f: *HirFunc, idx: int) -> *HirParam {
|
||||||
|
if f == null as *HirFunc { return null as *HirParam; }
|
||||||
|
if idx == 0 { return f.param0; }
|
||||||
|
if idx == 1 { return f.param1; }
|
||||||
|
if idx == 2 { return f.param2; }
|
||||||
|
if idx == 3 { return f.param3; }
|
||||||
|
if idx == 4 { return f.param4; }
|
||||||
|
if idx == 5 { return f.param5; }
|
||||||
|
if idx == 6 { return f.param6; }
|
||||||
|
if idx == 7 { return f.param7; }
|
||||||
|
if idx == 8 { return f.param8; }
|
||||||
|
return null as *HirParam;
|
||||||
|
}
|
||||||
|
|
||||||
func CBE_CollectBuxFn(names: *String, count: *int, name: String) {
|
func CBE_CollectBuxFn(names: *String, count: *int, name: String) {
|
||||||
if String_Eq(name, "") { return; }
|
if String_Eq(name, "") { return; }
|
||||||
if !String_StartsWith(name, "BuxFn_") { return; }
|
if !String_StartsWith(name, "BuxFn_") { return; }
|
||||||
@@ -1001,7 +1012,15 @@ module CBackend {
|
|||||||
var pi: uint = 1;
|
var pi: uint = 1;
|
||||||
while pi < partCount {
|
while pi < partCount {
|
||||||
let pPart: String = String_SplitPart(rest, "_", pi);
|
let pPart: String = String_SplitPart(rest, "_", pi);
|
||||||
if !(pi == 1 && String_Eq(pPart, "void") && partCount == 2) {
|
// Skip sole `void` param (BuxFn_ret_void); always emit real params.
|
||||||
|
// Written without nested `!` so older selfhost CBE stays correct.
|
||||||
|
var skipVoid: bool = false;
|
||||||
|
if pi == 1 {
|
||||||
|
if String_Eq(pPart, "void") {
|
||||||
|
if partCount == 2 { skipVoid = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !skipVoid {
|
||||||
StringBuilder_Append(&cbe.sb, ", ");
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
StringBuilder_Append(&cbe.sb, CBE_FatPartToC(pPart));
|
StringBuilder_Append(&cbe.sb, CBE_FatPartToC(pPart));
|
||||||
}
|
}
|
||||||
@@ -1148,21 +1167,17 @@ module CBackend {
|
|||||||
StringBuilder_Append(&cbe.sb, retC);
|
StringBuilder_Append(&cbe.sb, retC);
|
||||||
StringBuilder_Append(&cbe.sb, " __adapt_");
|
StringBuilder_Append(&cbe.sb, " __adapt_");
|
||||||
StringBuilder_Append(&cbe.sb, fname);
|
StringBuilder_Append(&cbe.sb, fname);
|
||||||
StringBuilder_Append(&cbe.sb, "(void* env");
|
// Use __fat_env so we never clash with a user param named `env` (CtfeEnv, etc.)
|
||||||
|
StringBuilder_Append(&cbe.sb, "(void* __fat_env");
|
||||||
var p: int = 0;
|
var p: int = 0;
|
||||||
while p < mod.funcs[i].paramCount {
|
while p < mod.funcs[i].paramCount {
|
||||||
// Skip if first param is already __env (shouldn't for named funcs)
|
|
||||||
var pname: String = "";
|
var pname: String = "";
|
||||||
var ptype: String = "int";
|
var ptype: String = "int";
|
||||||
if p == 0 { pname = mod.funcs[i].param0.name; ptype = mod.funcs[i].param0.typeName; }
|
let hp: *HirParam = CBE_FuncParam(&mod.funcs[i], p);
|
||||||
else if p == 1 { pname = mod.funcs[i].param1.name; ptype = mod.funcs[i].param1.typeName; }
|
if hp != null as *HirParam {
|
||||||
else if p == 2 { pname = mod.funcs[i].param2.name; ptype = mod.funcs[i].param2.typeName; }
|
pname = hp.name;
|
||||||
else if p == 3 { pname = mod.funcs[i].param3.name; ptype = mod.funcs[i].param3.typeName; }
|
ptype = hp.typeName;
|
||||||
else if p == 4 { pname = mod.funcs[i].param4.name; ptype = mod.funcs[i].param4.typeName; }
|
}
|
||||||
else if p == 5 { pname = mod.funcs[i].param5.name; ptype = mod.funcs[i].param5.typeName; }
|
|
||||||
else if p == 6 { pname = mod.funcs[i].param6.name; ptype = mod.funcs[i].param6.typeName; }
|
|
||||||
else if p == 7 { pname = mod.funcs[i].param7.name; ptype = mod.funcs[i].param7.typeName; }
|
|
||||||
else if p == 8 { pname = mod.funcs[i].param8.name; ptype = mod.funcs[i].param8.typeName; }
|
|
||||||
if String_Eq(ptype, "") { ptype = "int"; }
|
if String_Eq(ptype, "") { ptype = "int"; }
|
||||||
StringBuilder_Append(&cbe.sb, ", ");
|
StringBuilder_Append(&cbe.sb, ", ");
|
||||||
StringBuilder_Append(&cbe.sb, ptype);
|
StringBuilder_Append(&cbe.sb, ptype);
|
||||||
@@ -1170,7 +1185,7 @@ module CBackend {
|
|||||||
StringBuilder_Append(&cbe.sb, pname);
|
StringBuilder_Append(&cbe.sb, pname);
|
||||||
p = p + 1;
|
p = p + 1;
|
||||||
}
|
}
|
||||||
StringBuilder_Append(&cbe.sb, ") {\n (void)env;\n");
|
StringBuilder_Append(&cbe.sb, ") {\n (void)__fat_env;\n");
|
||||||
if String_Eq(retC, "void") {
|
if String_Eq(retC, "void") {
|
||||||
StringBuilder_Append(&cbe.sb, " ");
|
StringBuilder_Append(&cbe.sb, " ");
|
||||||
StringBuilder_Append(&cbe.sb, fname);
|
StringBuilder_Append(&cbe.sb, fname);
|
||||||
@@ -1184,15 +1199,8 @@ module CBackend {
|
|||||||
while p < mod.funcs[i].paramCount {
|
while p < mod.funcs[i].paramCount {
|
||||||
if p > 0 { StringBuilder_Append(&cbe.sb, ", "); }
|
if p > 0 { StringBuilder_Append(&cbe.sb, ", "); }
|
||||||
var pname: String = "";
|
var pname: String = "";
|
||||||
if p == 0 { pname = mod.funcs[i].param0.name; }
|
let hp2: *HirParam = CBE_FuncParam(&mod.funcs[i], p);
|
||||||
else if p == 1 { pname = mod.funcs[i].param1.name; }
|
if hp2 != null as *HirParam { pname = hp2.name; }
|
||||||
else if p == 2 { pname = mod.funcs[i].param2.name; }
|
|
||||||
else if p == 3 { pname = mod.funcs[i].param3.name; }
|
|
||||||
else if p == 4 { pname = mod.funcs[i].param4.name; }
|
|
||||||
else if p == 5 { pname = mod.funcs[i].param5.name; }
|
|
||||||
else if p == 6 { pname = mod.funcs[i].param6.name; }
|
|
||||||
else if p == 7 { pname = mod.funcs[i].param7.name; }
|
|
||||||
else if p == 8 { pname = mod.funcs[i].param8.name; }
|
|
||||||
StringBuilder_Append(&cbe.sb, pname);
|
StringBuilder_Append(&cbe.sb, pname);
|
||||||
p = p + 1;
|
p = p + 1;
|
||||||
}
|
}
|
||||||
@@ -1386,7 +1394,8 @@ module CBackend {
|
|||||||
if node.typeName != null as String { return node.typeName; }
|
if node.typeName != null as String { return node.typeName; }
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if node.kind == hFieldPtr {
|
// Field access (both hFieldPtr and hFieldAccess): resolve field type from structs
|
||||||
|
if node.kind == hFieldPtr || node.kind == hFieldAccess {
|
||||||
let baseType: String = CBE_GetExprTypeName(mod, node.child1);
|
let baseType: String = CBE_GetExprTypeName(mod, node.child1);
|
||||||
var structName: String = baseType;
|
var structName: String = baseType;
|
||||||
if String_EndsWith(baseType, "*") {
|
if String_EndsWith(baseType, "*") {
|
||||||
@@ -1396,7 +1405,10 @@ module CBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !String_Eq(structName, "") {
|
if !String_Eq(structName, "") {
|
||||||
return CBE_LookupFieldType(mod, structName, node.strValue);
|
let ft: String = CBE_LookupFieldType(mod, structName, node.strValue);
|
||||||
|
if ft != null as String && !String_Eq(ft, "") {
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.typeName != null as String { return node.typeName; }
|
if node.typeName != null as String { return node.typeName; }
|
||||||
@@ -1409,7 +1421,7 @@ module CBackend {
|
|||||||
|
|
||||||
func CBackend_Generate(mod: *HirModule) -> String {
|
func CBackend_Generate(mod: *HirModule) -> String {
|
||||||
let cbe: *CEmitter = bux_alloc(sizeof(CEmitter)) as *CEmitter;
|
let cbe: *CEmitter = bux_alloc(sizeof(CEmitter)) as *CEmitter;
|
||||||
cbe.sb = StringBuilder_NewCap(8192);
|
cbe.sb = StringBuilder_NewCap(262144);
|
||||||
cbe.indent = 0;
|
cbe.indent = 0;
|
||||||
cbe.mod = mod;
|
cbe.mod = mod;
|
||||||
cbe.deferCount = 0;
|
cbe.deferCount = 0;
|
||||||
@@ -1737,7 +1749,8 @@ module CBackend {
|
|||||||
StringBuilder_Append(&cbe.sb, "*)__env);\n");
|
StringBuilder_Append(&cbe.sb, "*)__env);\n");
|
||||||
} else if mod.funcs[i].paramCount > 0 {
|
} else if mod.funcs[i].paramCount > 0 {
|
||||||
// Capture-less closure still has __env
|
// Capture-less closure still has __env
|
||||||
if String_Eq(mod.funcs[i].param0.name, "__env") {
|
let envP: *HirParam = CBE_FuncParam(&mod.funcs[i], 0);
|
||||||
|
if envP != null as *HirParam && String_Eq(envP.name, "__env") {
|
||||||
StringBuilder_Append(&cbe.sb, " (void)__env;\n");
|
StringBuilder_Append(&cbe.sb, " (void)__env;\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-8
@@ -4038,15 +4038,17 @@ module HirLower {
|
|||||||
let ctx: *LowerCtx = bux_alloc(sizeof(LowerCtx)) as *LowerCtx;
|
let ctx: *LowerCtx = bux_alloc(sizeof(LowerCtx)) as *LowerCtx;
|
||||||
ctx.module = mod;
|
ctx.module = mod;
|
||||||
ctx.scope = sema.scope;
|
ctx.scope = sema.scope;
|
||||||
ctx.funcs = bux_alloc(512 as uint * sizeof(HirFunc)) as *HirFunc;
|
// Capacities sized for full selfhost compile (~600 funcs, ~120 structs).
|
||||||
|
// Undersized buffers overflowed heap → corrupt main.c / buxc2→buxc3 fail.
|
||||||
|
ctx.funcs = bux_alloc(4096 as uint * sizeof(HirFunc)) as *HirFunc;
|
||||||
ctx.funcCount = 0;
|
ctx.funcCount = 0;
|
||||||
ctx.externFuncs = bux_alloc(512 as uint * sizeof(HirFunc)) as *HirFunc;
|
ctx.externFuncs = bux_alloc(1024 as uint * sizeof(HirFunc)) as *HirFunc;
|
||||||
ctx.externCount = 0;
|
ctx.externCount = 0;
|
||||||
ctx.varCounter = 0;
|
ctx.varCounter = 0;
|
||||||
ctx.genFuncCount = 0;
|
ctx.genFuncCount = 0;
|
||||||
ctx.genFuncs = bux_alloc(256 as uint * sizeof(Decl)) as *Decl;
|
ctx.genFuncs = bux_alloc(1024 as uint * sizeof(Decl)) as *Decl;
|
||||||
ctx.genStructCount = 0;
|
ctx.genStructCount = 0;
|
||||||
ctx.genStructs = bux_alloc(256 as uint * sizeof(Decl)) as *Decl;
|
ctx.genStructs = bux_alloc(1024 as uint * sizeof(Decl)) as *Decl;
|
||||||
ctx.substParam0 = "";
|
ctx.substParam0 = "";
|
||||||
ctx.substArg0 = "";
|
ctx.substArg0 = "";
|
||||||
ctx.substParam1 = "";
|
ctx.substParam1 = "";
|
||||||
@@ -4056,11 +4058,11 @@ module HirLower {
|
|||||||
hm.funcCount = 0;
|
hm.funcCount = 0;
|
||||||
hm.funcs = ctx.funcs;
|
hm.funcs = ctx.funcs;
|
||||||
hm.structCount = 0;
|
hm.structCount = 0;
|
||||||
hm.structs = bux_alloc(64 as uint * sizeof(HirStruct)) as *HirStruct;
|
hm.structs = bux_alloc(512 as uint * sizeof(HirStruct)) as *HirStruct;
|
||||||
hm.enumCount = 0;
|
hm.enumCount = 0;
|
||||||
hm.enums = bux_alloc(64 as uint * sizeof(HirEnum)) as *HirEnum;
|
hm.enums = bux_alloc(256 as uint * sizeof(HirEnum)) as *HirEnum;
|
||||||
hm.constCount = 0;
|
hm.constCount = 0;
|
||||||
hm.consts = bux_alloc(512 as uint * sizeof(HirConst)) as *HirConst;
|
hm.consts = bux_alloc(2048 as uint * sizeof(HirConst)) as *HirConst;
|
||||||
ctx.hm = hm;
|
ctx.hm = hm;
|
||||||
|
|
||||||
// First pass: count structs (to allocate field arrays later)
|
// First pass: count structs (to allocate field arrays later)
|
||||||
@@ -4175,7 +4177,7 @@ module HirLower {
|
|||||||
ctx.externCount = ctx.externCount + 1;
|
ctx.externCount = ctx.externCount + 1;
|
||||||
}
|
}
|
||||||
// Pass 1: collect const names (expressions evaluated in Pass 2)
|
// Pass 1: collect const names (expressions evaluated in Pass 2)
|
||||||
if decl.kind == dkConst && hm.constCount < 512 {
|
if decl.kind == dkConst && hm.constCount < 2048 {
|
||||||
let ci: int = hm.constCount;
|
let ci: int = hm.constCount;
|
||||||
hm.consts[ci].name = decl.strValue;
|
hm.consts[ci].name = decl.strValue;
|
||||||
hm.consts[ci].value = 0;
|
hm.consts[ci].value = 0;
|
||||||
|
|||||||
+13
-9
@@ -1721,7 +1721,7 @@ module Sema {
|
|||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
if dk == dkInterface {
|
if dk == dkInterface {
|
||||||
if sema.interfaceCount < 64 {
|
if sema.interfaceCount < 256 {
|
||||||
sema.interfaceTable[sema.interfaceCount].name = decl.strValue;
|
sema.interfaceTable[sema.interfaceCount].name = decl.strValue;
|
||||||
sema.interfaceTable[sema.interfaceCount].decl = decl;
|
sema.interfaceTable[sema.interfaceCount].decl = decl;
|
||||||
sema.interfaceCount = sema.interfaceCount + 1;
|
sema.interfaceCount = sema.interfaceCount + 1;
|
||||||
@@ -1734,7 +1734,7 @@ module Sema {
|
|||||||
var m: *Decl = decl.childDecl1;
|
var m: *Decl = decl.childDecl1;
|
||||||
while m != null as *Decl {
|
while m != null as *Decl {
|
||||||
if m.kind == dkFunc {
|
if m.kind == dkFunc {
|
||||||
if sema.methodCount < 256 {
|
if sema.methodCount < 2048 {
|
||||||
sema.methodEntries[sema.methodCount].typeName = implTypeName;
|
sema.methodEntries[sema.methodCount].typeName = implTypeName;
|
||||||
sema.methodEntries[sema.methodCount].methodName = m.strValue;
|
sema.methodEntries[sema.methodCount].methodName = m.strValue;
|
||||||
sema.methodEntries[sema.methodCount].decl = m;
|
sema.methodEntries[sema.methodCount].decl = m;
|
||||||
@@ -1865,7 +1865,7 @@ module Sema {
|
|||||||
}
|
}
|
||||||
if !String_Eq(typeName, "") {
|
if !String_Eq(typeName, "") {
|
||||||
let methodName: String = bux_str_slice(decl.strValue, (i + 1) as uint, bux_strlen(decl.strValue) - (i + 1) as uint);
|
let methodName: String = bux_str_slice(decl.strValue, (i + 1) as uint, bux_strlen(decl.strValue) - (i + 1) as uint);
|
||||||
if sema.methodCount < 256 {
|
if sema.methodCount < 2048 {
|
||||||
sema.methodEntries[sema.methodCount].typeName = typeName;
|
sema.methodEntries[sema.methodCount].typeName = typeName;
|
||||||
sema.methodEntries[sema.methodCount].methodName = methodName;
|
sema.methodEntries[sema.methodCount].methodName = methodName;
|
||||||
sema.methodEntries[sema.methodCount].decl = decl;
|
sema.methodEntries[sema.methodCount].decl = decl;
|
||||||
@@ -2225,19 +2225,23 @@ module Sema {
|
|||||||
func Sema_Analyze(mod: *Module) -> *Sema {
|
func Sema_Analyze(mod: *Module) -> *Sema {
|
||||||
let s: *Sema = bux_alloc(sizeof(Sema)) as *Sema;
|
let s: *Sema = bux_alloc(sizeof(Sema)) as *Sema;
|
||||||
s.module = mod;
|
s.module = mod;
|
||||||
|
// Global scope must use Scope_New capacity (maxSymbols=8192).
|
||||||
|
// Allocating only 1024 slots while Scope_Define allows 8192 overflowed
|
||||||
|
// the heap when analyzing full compiler sources (~1200 decls) — buxc2 crash.
|
||||||
s.scope = bux_alloc(sizeof(Scope)) as *Scope;
|
s.scope = bux_alloc(sizeof(Scope)) as *Scope;
|
||||||
s.scope.symbols = bux_alloc(1024 as uint * sizeof(Symbol)) as *Symbol;
|
let globalScope: Scope = Scope_New();
|
||||||
s.scope.count = 0;
|
s.scope.symbols = globalScope.symbols;
|
||||||
s.scope.parent = null as *Scope;
|
s.scope.count = globalScope.count;
|
||||||
|
s.scope.parent = globalScope.parent;
|
||||||
s.hasError = false;
|
s.hasError = false;
|
||||||
s.diagCount = 0;
|
s.diagCount = 0;
|
||||||
s.diags = bux_alloc(256 as uint * sizeof(SemaDiag)) as *SemaDiag;
|
s.diags = bux_alloc(1024 as uint * sizeof(SemaDiag)) as *SemaDiag;
|
||||||
s.typeTable = null as *void;
|
s.typeTable = null as *void;
|
||||||
s.methodTable = null as *void;
|
s.methodTable = null as *void;
|
||||||
s.currentRetType = tyVoid;
|
s.currentRetType = tyVoid;
|
||||||
s.interfaceTable = bux_alloc(64 as uint * sizeof(InterfaceEntry)) as *InterfaceEntry;
|
s.interfaceTable = bux_alloc(256 as uint * sizeof(InterfaceEntry)) as *InterfaceEntry;
|
||||||
s.interfaceCount = 0;
|
s.interfaceCount = 0;
|
||||||
s.methodEntries = bux_alloc(256 as uint * sizeof(MethodEntry)) as *MethodEntry;
|
s.methodEntries = bux_alloc(2048 as uint * sizeof(MethodEntry)) as *MethodEntry;
|
||||||
s.methodCount = 0;
|
s.methodCount = 0;
|
||||||
|
|
||||||
// First pass: collect globals
|
// First pass: collect globals
|
||||||
|
|||||||
+24
-11
@@ -112,35 +112,48 @@ if [[ "${BUX_SELFHOST_FIXED_POINT:-0}" != "1" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "=== Fixed-point: buxc2 → buxc3 (experimental) ==="
|
echo "=== Fixed-point: buxc2 → buxc3 → buxc4 (same-backend gen) ==="
|
||||||
|
# True fixed-point: compiler_n and compiler_n+1 (both from selfhost backend)
|
||||||
|
# must produce identical C/ELF. Bootstrap vs selfhost CBE differ intentionally.
|
||||||
|
C="$ROOT/build/selfhost-loop-c"
|
||||||
BUXC2="$A/build/buxc2"
|
BUXC2="$A/build/buxc2"
|
||||||
if [[ ! -x "$BUXC2" ]]; then
|
if [[ ! -x "$BUXC2" ]]; then
|
||||||
echo "error: buxc2 missing at $BUXC2" >&2
|
echo "error: buxc2 missing at $BUXC2" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rebuild B with buxc2
|
echo "--- Gen2: buxc2 → buxc3 ---"
|
||||||
prepare_tree "$B"
|
prepare_tree "$B"
|
||||||
set +e
|
if ! (cd "$B" && "$BUXC2" build); then
|
||||||
(cd "$B" && "$BUXC2" build)
|
|
||||||
fp_status=$?
|
|
||||||
set -e
|
|
||||||
if [[ $fp_status -ne 0 ]]; then
|
|
||||||
echo "=== Fixed-point FAILED (buxc2 could not build gen2) ==="
|
echo "=== Fixed-point FAILED (buxc2 could not build gen2) ==="
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BUXC3="$B/build/buxc2"
|
BUXC3="$B/build/buxc2"
|
||||||
if [[ ! -x "$BUXC3" ]]; then
|
if [[ ! -x "$BUXC3" ]]; then
|
||||||
echo "error: gen2 binary missing" >&2
|
echo "error: gen2 binary missing" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
echo " buxc3: $BUXC3"
|
||||||
|
|
||||||
|
echo "--- Gen3: buxc3 → buxc4 ---"
|
||||||
|
prepare_tree "$C"
|
||||||
|
if ! (cd "$C" && "$BUXC3" build); then
|
||||||
|
echo "=== Fixed-point FAILED (buxc3 could not build gen3) ==="
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
BUXC4="$C/build/buxc2"
|
||||||
|
if [[ ! -x "$BUXC4" ]]; then
|
||||||
|
echo "error: gen3 binary missing" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo " buxc4: $BUXC4"
|
||||||
|
|
||||||
|
# Compare gen2 vs gen3 artifacts (not bootstrap vs selfhost)
|
||||||
if ! compare_c_and_elf \
|
if ! compare_c_and_elf \
|
||||||
"buxc2" "$BUXC2" "$A/build/main.c" \
|
"buxc3" "$BUXC3" "$B/build/main.c" \
|
||||||
"buxc3" "$BUXC3" "$B/build/main.c"
|
"buxc4" "$BUXC4" "$C/build/main.c"
|
||||||
then
|
then
|
||||||
echo "=== Fixed-point FAILED (gen1 vs gen2 mismatch) ==="
|
echo "=== Fixed-point FAILED (gen2 vs gen3 mismatch) ==="
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user