selfhost: C backend becomes primary backend; QBE path removed from CLI

Major changes:
- Cli_BuildProject now uses CBackend_Generate instead of QBE SSA generation
- Replaced QBE invocation (vendor/qbe/qbe) with direct cc compilation
- Cli_Build (single-file) now compiles C output with cc including runtime.c/io.c
- Added import-based stdlib merging: only imported Std::* modules are merged,
  eliminating unused generic code from Array/Map/Set/Channel in simple programs

C backend fixes:
- Fixed struct typedef redefinition: struct definitions now use 'struct Name {}'
  instead of 'typedef struct {} Name' to avoid conflicting with forward typedefs
- Added enum support: HirEnum struct, enum emission in C backend, variant
  constants emitted as #define Name_Value
- Added char8 typedef
- Skip generic structs/functions (T/K/V type parameters) in C emission

Sema fixes:
- Fixed Sema_IsNumeric: now correctly recognizes uint, float32, float64
- Fixed return type check: allow pointer compatibility (String <-> *T)

Tested: hello, fibonacci, factorial, enums examples build and run via buxc2
This commit is contained in:
2026-06-05 14:42:18 +03:00
parent 5ae85d5bd9
commit 0c1f230286
10 changed files with 614 additions and 242 deletions
+9 -3
View File
@@ -96,7 +96,10 @@ func Sema_ResolveType(sema: *Sema, te: *TypeExpr) -> int {
func Sema_IsNumeric(kind: int) -> bool {
if kind == tyUnknown || kind == tyNamed || kind == tyTypeParam { return true; }
return kind >= tyInt8 && kind <= tyUInt64;
if kind == tyInt8 || kind == tyInt16 || kind == tyInt32 || kind == tyInt64 || kind == tyInt { return true; }
if kind == tyUInt8 || kind == tyUInt16 || kind == tyUInt32 || kind == tyUInt64 || kind == tyUInt { return true; }
if kind == tyFloat32 || kind == tyFloat64 { return true; }
return false;
}
func Sema_IsBool(kind: int) -> bool {
@@ -328,9 +331,12 @@ func Sema_CheckStmt(sema: *Sema, stmt: *Stmt) {
let retType: int = Sema_CheckExpr(sema, stmt.child1);
if sema.currentRetType != tyUnknown && retType != tyUnknown {
if retType != sema.currentRetType {
// Be permissive: allow numeric widening, pointer/named mismatch
// Be permissive: allow numeric widening, pointer compatibility
if !Sema_IsNumeric(retType) || !Sema_IsNumeric(sema.currentRetType) {
if retType != sema.currentRetType {
// Allow pointer-type compatibility (String <-> *T, *T <-> *U)
let retIsPtr: bool = retType == tyPointer || retType == tyStr;
let expectedIsPtr: bool = sema.currentRetType == tyPointer || sema.currentRetType == tyStr;
if !retIsPtr || !expectedIsPtr {
Sema_EmitError(sema, stmt.line, stmt.column, "return type mismatch");
}
}