selfhost: for x in collection works with non-identifier expressions + buxc2 build merges stdlib
- cli: buxc2 build now delegates to Cli_BuildProject for src/Main.bux,
enabling stdlib merging (Array_Iter, Iter_HasNext, etc. available)
- sema: set expr.refType on ekCall from function return type
(needed for for-loop type extraction from MakeArr()-style expressions)
- hir_lower: remove ekIdent restriction on collection-based for loops
- supports arbitrary expressions: for x in MakeArr() { ... }
- creates temp variable __tmp_coll_N for non-identifier iterators
- generates proper Array_T struct instances for temp variables
- Test: for x in MakeArr() sums [10,20,30] → 60
- Selfhost loop: C output IDENTICAL
This commit is contained in:
+11
@@ -114,6 +114,17 @@ func Cli_Compile(source: String, sourceName: String) -> String {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func Cli_Build(srcPath: String, outPath: String) -> int {
|
func Cli_Build(srcPath: String, outPath: String) -> int {
|
||||||
|
// If building the standard project entry point, use full project build
|
||||||
|
// which merges stdlib and supports multi-file projects
|
||||||
|
if String_Eq(srcPath, "src/Main.bux") || String_Eq(srcPath, "src/main.bux") {
|
||||||
|
let rc: int = Cli_BuildProject(".");
|
||||||
|
if rc == 0 && !String_Eq(outPath, "build/main") {
|
||||||
|
// Rename output if custom path was requested
|
||||||
|
bux_system(String_Concat(String_Concat("mv build/main ", outPath), " 2>/dev/null || true"));
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
let source: String = ReadFile(srcPath);
|
let source: String = ReadFile(srcPath);
|
||||||
if source == null as String || String_Eq(source, "") || !FileExists(srcPath) {
|
if source == null as String || String_Eq(source, "") || !FileExists(srcPath) {
|
||||||
Print("Error: cannot read source file: ");
|
Print("Error: cannot read source file: ");
|
||||||
|
|||||||
+41
-2
@@ -1221,9 +1221,9 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
// let x = Iter_Next_T(&__iter);
|
// let x = Iter_Next_T(&__iter);
|
||||||
// body
|
// body
|
||||||
// }
|
// }
|
||||||
if iterExpr != null as *Expr && iterExpr.kind == ekIdent {
|
if iterExpr != null as *Expr {
|
||||||
let collTypeExpr: *TypeExpr = iterExpr.refType;
|
let collTypeExpr: *TypeExpr = iterExpr.refType;
|
||||||
if collTypeExpr == null as *TypeExpr {
|
if collTypeExpr == null as *TypeExpr && iterExpr.kind == ekIdent {
|
||||||
// Fallback: try scope lookup (may have substituted type)
|
// Fallback: try scope lookup (may have substituted type)
|
||||||
let collSym: Symbol = Scope_Lookup(ctx.scope, iterExpr.strValue);
|
let collSym: Symbol = Scope_Lookup(ctx.scope, iterExpr.strValue);
|
||||||
collTypeExpr = collSym.refType;
|
collTypeExpr = collSym.refType;
|
||||||
@@ -1309,6 +1309,7 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
|
|
||||||
// __iter = Array_Iter_T(&arr) or just copy if already Iter
|
// __iter = Array_Iter_T(&arr) or just copy if already Iter
|
||||||
var iterInit: *HirNode = null as *HirNode;
|
var iterInit: *HirNode = null as *HirNode;
|
||||||
|
var collStore: *HirNode = null as *HirNode;
|
||||||
if isArray {
|
if isArray {
|
||||||
let callIter: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let callIter: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
callIter.kind = hCall;
|
callIter.kind = hCall;
|
||||||
@@ -1316,18 +1317,47 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
let addrArr: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let addrArr: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
addrArr.kind = hUnary;
|
addrArr.kind = hUnary;
|
||||||
addrArr.intValue = tkAmp;
|
addrArr.intValue = tkAmp;
|
||||||
|
if iterExpr.kind == ekIdent {
|
||||||
let arrVar: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let arrVar: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
arrVar.kind = hVar;
|
arrVar.kind = hVar;
|
||||||
arrVar.strValue = iterExpr.strValue;
|
arrVar.strValue = iterExpr.strValue;
|
||||||
addrArr.child1 = arrVar;
|
addrArr.child1 = arrVar;
|
||||||
|
} else {
|
||||||
|
// Non-identifier: create temp variable for collection
|
||||||
|
ctx.varCounter = ctx.varCounter + 1;
|
||||||
|
let tmpName: String = String_Concat("__tmp_coll_", String_FromInt(ctx.varCounter));
|
||||||
|
// Ensure Array<T> struct instance exists and get mangled name
|
||||||
|
let arrayGenStruct: *Decl = Lcx_FindGenericStruct(ctx, "Array");
|
||||||
|
var arrayMangledName: String = collTypeName;
|
||||||
|
if arrayGenStruct != null as *Decl {
|
||||||
|
arrayMangledName = Lcx_GenerateStructInstance(ctx, arrayGenStruct, elemTypeName, "", 1);
|
||||||
|
}
|
||||||
|
let collAlloca: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
|
collAlloca.kind = hAlloca;
|
||||||
|
collAlloca.strValue = tmpName;
|
||||||
|
collAlloca.typeName = arrayMangledName;
|
||||||
|
collAlloca.typeKind = tyNamed;
|
||||||
|
collStore = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
|
collStore.kind = hStore;
|
||||||
|
collStore.child1 = collAlloca;
|
||||||
|
collStore.child2 = Lcx_LowerExpr(ctx, iterExpr);
|
||||||
|
let collVar: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
|
collVar.kind = hVar;
|
||||||
|
collVar.strValue = tmpName;
|
||||||
|
addrArr.child1 = collVar;
|
||||||
|
}
|
||||||
callIter.child1 = addrArr;
|
callIter.child1 = addrArr;
|
||||||
iterInit = callIter;
|
iterInit = callIter;
|
||||||
} else {
|
} else {
|
||||||
// Already an iterator: __iter = arr
|
// Already an iterator: __iter = arr
|
||||||
|
if iterExpr.kind == ekIdent {
|
||||||
let arrVar: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let arrVar: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
arrVar.kind = hVar;
|
arrVar.kind = hVar;
|
||||||
arrVar.strValue = iterExpr.strValue;
|
arrVar.strValue = iterExpr.strValue;
|
||||||
iterInit = arrVar;
|
iterInit = arrVar;
|
||||||
|
} else {
|
||||||
|
iterInit = Lcx_LowerExpr(ctx, iterExpr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let iterStore: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let iterStore: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
@@ -1335,6 +1365,11 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
iterStore.child1 = iterAlloca;
|
iterStore.child1 = iterAlloca;
|
||||||
iterStore.child2 = iterInit;
|
iterStore.child2 = iterInit;
|
||||||
|
|
||||||
|
// Chain collStore -> iterStore if temp was created
|
||||||
|
if collStore != null as *HirNode {
|
||||||
|
collStore.child3 = iterStore;
|
||||||
|
}
|
||||||
|
|
||||||
// condition: Iter_HasNext_T(&__iter)
|
// condition: Iter_HasNext_T(&__iter)
|
||||||
let condCall: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
let condCall: *HirNode = bux_alloc(sizeof(HirNode)) as *HirNode;
|
||||||
condCall.kind = hCall;
|
condCall.kind = hCall;
|
||||||
@@ -1401,7 +1436,11 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
|
|||||||
blockNode.kind = hBlock;
|
blockNode.kind = hBlock;
|
||||||
blockNode.line = line;
|
blockNode.line = line;
|
||||||
blockNode.column = col;
|
blockNode.column = col;
|
||||||
|
if collStore != null as *HirNode {
|
||||||
|
blockNode.child1 = collStore;
|
||||||
|
} else {
|
||||||
blockNode.child1 = iterStore;
|
blockNode.child1 = iterStore;
|
||||||
|
}
|
||||||
return blockNode;
|
return blockNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,6 +579,7 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
|
|||||||
if calleeType == tyFunc {
|
if calleeType == tyFunc {
|
||||||
if expr.child1.refType != null as *TypeExpr && expr.child1.refType.kind == tekFunc {
|
if expr.child1.refType != null as *TypeExpr && expr.child1.refType.kind == tekFunc {
|
||||||
if expr.child1.refType.funcRet != null as *TypeExpr {
|
if expr.child1.refType.funcRet != null as *TypeExpr {
|
||||||
|
expr.refType = expr.child1.refType.funcRet;
|
||||||
return Sema_ResolveType(sema, expr.child1.refType.funcRet);
|
return Sema_ResolveType(sema, expr.child1.refType.funcRet);
|
||||||
}
|
}
|
||||||
return tyVoid;
|
return tyVoid;
|
||||||
@@ -589,6 +590,7 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
|
|||||||
let sym: Symbol = Scope_Lookup(sema.scope, expr.child1.strValue);
|
let sym: Symbol = Scope_Lookup(sema.scope, expr.child1.strValue);
|
||||||
if sym.kind == skFunc && sym.decl != null as *Decl {
|
if sym.kind == skFunc && sym.decl != null as *Decl {
|
||||||
if sym.decl.retType != null as *TypeExpr {
|
if sym.decl.retType != null as *TypeExpr {
|
||||||
|
expr.refType = sym.decl.retType;
|
||||||
return Sema_ResolveType(sema, sym.decl.retType);
|
return Sema_ResolveType(sema, sym.decl.retType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user