selfhost: fix pointer field access, algebraic enums, string literal escaping

- hir_lower: use per-function scope instead of global scope for params
  fixes p->error emission for pointer parameters
- parser: assign variant4..variant7 in enum decls (was only 0..3)
- c_backend: escape quotes, backslash, newline, tab, cr in string literals
- runtime: bux_write_file now writes raw bytes (was un-escaping sequences)
- c_backend: emit algebraic enums as tagged unions (tag enum + data union + struct)
- hir_lower: add hBreak/hContinue lowering
- sema: skip empty variant names when collecting enum globals
This commit is contained in:
2026-06-06 23:54:09 +03:00
parent 3ae8c60ebb
commit 0bdef58182
6 changed files with 370 additions and 65 deletions
+1 -25
View File
@@ -507,31 +507,7 @@ int bux_write_file(const char* path, const char* content) {
FILE* f = fopen(path, "wb"); FILE* f = fopen(path, "wb");
if (!f) return 0; if (!f) return 0;
size_t len = strlen(content); size_t len = strlen(content);
size_t written = 0; size_t written = fwrite(content, 1, len, f);
for (size_t i = 0; i < len; i++) {
if (content[i] == '\\' && i + 1 < len && content[i + 1] == 'n') {
if (fputc('\n', f) == EOF) break;
i++;
} else if (content[i] == '\\' && i + 1 < len && content[i + 1] == 't') {
if (fputc('\t', f) == EOF) break;
i++;
} else if (content[i] == '\\' && i + 1 < len && content[i + 1] == 'r') {
if (fputc('\r', f) == EOF) break;
i++;
} else if (content[i] == '\\' && i + 1 < len && content[i + 1] == '\\') {
if (fputc('\\', f) == EOF) break;
i++;
} else if (content[i] == '\\' && i + 1 < len && content[i + 1] == '"') {
if (fputc('"', f) == EOF) break;
i++;
} else if (content[i] == '\\' && i + 1 < len && content[i + 1] == '\'') {
if (fputc('\'', f) == EOF) break;
i++;
} else {
if (fputc(content[i], f) == EOF) break;
}
written++;
}
fclose(f); fclose(f);
return written > 0 ? 1 : 0; return written > 0 ? 1 : 0;
} }
+228 -11
View File
@@ -2,6 +2,7 @@
// Generates C code from the HIR. // Generates C code from the HIR.
module CBackend { module CBackend {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Type → C type name // Type → C type name
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -102,13 +103,49 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
if node.intValue == tkNull { if node.intValue == tkNull {
StringBuilder_Append(&cbe.sb, "0"); StringBuilder_Append(&cbe.sb, "0");
} else { } else {
StringBuilder_Append(&cbe.sb, node.strValue); let s: String = node.strValue;
let slen: int = String_Len(s) as int;
var start: int = 0;
var end: int = slen;
// If the literal is wrapped in quotes (from lexer), preserve outer quotes
// and only escape the inner content.
if slen >= 2 && s[0] == 34 as char8 && s[slen - 1] == 34 as char8 {
StringBuilder_Append(&cbe.sb, "\"");
start = 1;
end = slen - 1;
}
var i: int = start;
while i < end {
let c: int = s[i] as int;
if c == 34 {
StringBuilder_Append(&cbe.sb, "\\\"");
} else if c == 92 {
StringBuilder_Append(&cbe.sb, "\\\\");
} else if c == 10 {
StringBuilder_Append(&cbe.sb, "\\n");
} else if c == 9 {
StringBuilder_Append(&cbe.sb, "\\t");
} else if c == 13 {
StringBuilder_Append(&cbe.sb, "\\r");
} else {
StringBuilder_AppendChar(&cbe.sb, c as char8);
}
i = i + 1;
}
if slen >= 2 && s[0] == 34 as char8 && s[slen - 1] == 34 as char8 {
StringBuilder_Append(&cbe.sb, "\"");
}
} }
return; return;
} }
// Variable // Variable
if kind == hVar { if kind == hVar {
if node.intValue != 0 {
StringBuilder_Append(&cbe.sb, "/* hVar tk=");
StringBuilder_AppendInt(&cbe.sb, node.intValue);
StringBuilder_Append(&cbe.sb, " */");
}
StringBuilder_Append(&cbe.sb, node.strValue); StringBuilder_Append(&cbe.sb, node.strValue);
return; return;
} }
@@ -228,6 +265,7 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
// If // If
if kind == hIf { if kind == hIf {
StringBuilder_Append(&cbe.sb, "if ("); StringBuilder_Append(&cbe.sb, "if (");
CBE_EmitExpr(cbe, node.child1); CBE_EmitExpr(cbe, node.child1);
StringBuilder_Append(&cbe.sb, ") {\n"); StringBuilder_Append(&cbe.sb, ") {\n");
@@ -296,10 +334,32 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
return; return;
} }
// Field access: obj.field — emit as obj->field (since most are pointers) // Break / Continue
if kind == hBreak {
StringBuilder_Append(&cbe.sb, "break");
return;
}
if kind == hContinue {
StringBuilder_Append(&cbe.sb, "continue");
return;
}
// Field access: obj.field — use -> if base is pointer, else .
if kind == hFieldPtr { if kind == hFieldPtr {
CBE_EmitExpr(cbe, node.child1); CBE_EmitExpr(cbe, node.child1);
StringBuilder_Append(&cbe.sb, "->"); var isPtr: bool = false;
if node.child1 != null as *HirNode {
if node.child1.typeKind == tyPointer {
isPtr = true;
} else if String_EndsWith(node.child1.typeName, "*") {
isPtr = true;
}
}
if isPtr {
StringBuilder_Append(&cbe.sb, "->");
} else {
StringBuilder_Append(&cbe.sb, ".");
}
StringBuilder_Append(&cbe.sb, node.strValue); StringBuilder_Append(&cbe.sb, node.strValue);
return; return;
} }
@@ -326,7 +386,53 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) {
} }
// Load: *ptr — emit as *ptr (dereference) // Load: *ptr — emit as *ptr (dereference)
// Optimize common patterns to avoid & / * temporaries
if kind == hLoad { if kind == hLoad {
if node.child1 != null as *HirNode {
let ptrNode: *HirNode = node.child1;
let ptrKind: int = ptrNode.kind;
// field access: load(field_ptr(base, field)) → base.field
if ptrKind == hFieldPtr {
CBE_EmitExpr(cbe, ptrNode.child1);
var isPtr: bool = false;
if ptrNode.child1 != null as *HirNode {
if ptrNode.child1.typeKind == tyPointer {
isPtr = true;
} else if String_EndsWith(ptrNode.child1.typeName, "*") {
isPtr = true;
}
}
if isPtr {
StringBuilder_Append(&cbe.sb, "->");
} else {
StringBuilder_Append(&cbe.sb, ".");
}
StringBuilder_Append(&cbe.sb, ptrNode.strValue);
return;
}
// arrow field: load(arrow_field(base, field)) → base->field
if ptrKind == hArrowField {
CBE_EmitExpr(cbe, ptrNode.child1);
StringBuilder_Append(&cbe.sb, "->");
StringBuilder_Append(&cbe.sb, ptrNode.strValue);
return;
}
// arrow field: load(arrow_field(base, field)) → base->field
if ptrKind == hArrowField {
CBE_EmitExpr(cbe, ptrNode.child1);
StringBuilder_Append(&cbe.sb, "->");
StringBuilder_Append(&cbe.sb, ptrNode.strValue);
return;
}
// index: load(index_ptr(base, idx)) → base[idx]
if ptrKind == hIndexPtr {
CBE_EmitExpr(cbe, ptrNode.child1);
StringBuilder_Append(&cbe.sb, "[");
CBE_EmitExpr(cbe, ptrNode.child2);
StringBuilder_Append(&cbe.sb, "]");
return;
}
}
StringBuilder_Append(&cbe.sb, "(*"); StringBuilder_Append(&cbe.sb, "(*");
CBE_EmitExpr(cbe, node.child1); CBE_EmitExpr(cbe, node.child1);
StringBuilder_Append(&cbe.sb, ")"); StringBuilder_Append(&cbe.sb, ")");
@@ -467,11 +573,18 @@ func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) {
func CBE_IsGenericTypeName(name: String) -> bool { func CBE_IsGenericTypeName(name: String) -> bool {
if String_Eq(name, "T") || String_Eq(name, "K") || String_Eq(name, "V") { return true; } if String_Eq(name, "T") || String_Eq(name, "K") || String_Eq(name, "V") { return true; }
if String_Eq(name, "T*") || String_Eq(name, "K*") || String_Eq(name, "V*") { return true; } if String_Eq(name, "T*") || String_Eq(name, "K*") || String_Eq(name, "V*") { return true; }
// Any type name containing '<' is a generic instantiation or parameter
if String_Contains(name, "<") { return true; }
// Generic container structs and their pointer variants // Generic container structs and their pointer variants
if String_Eq(name, "Array") || String_Eq(name, "Array*") { return true; } if String_Eq(name, "Array") || String_Eq(name, "Array*") { return true; }
if String_Eq(name, "Channel") || String_Eq(name, "Channel*") { return true; }
if String_Eq(name, "Iter") || String_Eq(name, "Iter*") { return true; }
if String_Eq(name, "Set") || String_Eq(name, "Set*") { return true; }
if String_Eq(name, "SetEntry") || String_Eq(name, "SetEntry*") { return true; } if String_Eq(name, "SetEntry") || String_Eq(name, "SetEntry*") { return true; }
if String_Eq(name, "StringMapEntry") || String_Eq(name, "StringMapEntry*") { return true; } if String_Eq(name, "Map") || String_Eq(name, "Map*") { return true; }
if String_Eq(name, "MapEntry") || String_Eq(name, "MapEntry*") { return true; } if String_Eq(name, "MapEntry") || String_Eq(name, "MapEntry*") { return true; }
if String_Eq(name, "StringMap") || String_Eq(name, "StringMap*") { return true; }
if String_Eq(name, "StringMapEntry") || String_Eq(name, "StringMapEntry*") { return true; }
return false; return false;
} }
@@ -550,17 +663,105 @@ func CBackend_Generate(mod: *HirModule) -> String {
} }
StringBuilder_Append(&cbe.sb, "\n"); StringBuilder_Append(&cbe.sb, "\n");
// Enum definitions (typedef to int) // Enum definitions
var ei: int = 0; var ei: int = 0;
while ei < mod.enumCount { while ei < mod.enumCount {
StringBuilder_Append(&cbe.sb, "typedef int "); let en: *HirEnum = &mod.enums[ei];
StringBuilder_Append(&cbe.sb, mod.enums[ei].name); var hasData: bool = false;
StringBuilder_Append(&cbe.sb, ";\n"); var vi: int = 0;
while vi < en.variantCount {
if en.variants[vi].fieldCount > 0 {
hasData = true;
}
vi = vi + 1;
}
if !hasData {
// Simple enum: typedef enum { A, B } Name;
StringBuilder_Append(&cbe.sb, "typedef enum {\n");
vi = 0;
while vi < en.variantCount {
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_");
StringBuilder_Append(&cbe.sb, en.variants[vi].name);
if vi < en.variantCount - 1 {
StringBuilder_Append(&cbe.sb, ",");
}
StringBuilder_Append(&cbe.sb, "\n");
vi = vi + 1;
}
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, ";\n\n");
} else {
// Algebraic enum: tag enum + data union + struct
// 1. Tag enum
StringBuilder_Append(&cbe.sb, "typedef enum {\n");
vi = 0;
while vi < en.variantCount {
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_");
StringBuilder_Append(&cbe.sb, en.variants[vi].name);
if vi < en.variantCount - 1 {
StringBuilder_Append(&cbe.sb, ",");
}
StringBuilder_Append(&cbe.sb, "\n");
vi = vi + 1;
}
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Tag;\n\n");
// 2. Data union
StringBuilder_Append(&cbe.sb, "typedef union {\n");
vi = 0;
while vi < en.variantCount {
let ev: *HirEnumVariant = &en.variants[vi];
if ev.fieldCount > 0 {
if ev.fieldCount == 1 {
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, CBackend_TypeToC(ev.fieldType0));
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, ev.name);
StringBuilder_Append(&cbe.sb, "_0;\n");
} else {
StringBuilder_Append(&cbe.sb, " struct {\n");
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, CBackend_TypeToC(ev.fieldType0));
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, ev.fieldName0);
StringBuilder_Append(&cbe.sb, ";\n");
if ev.fieldCount > 1 {
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, CBackend_TypeToC(ev.fieldType1));
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, ev.fieldName1);
StringBuilder_Append(&cbe.sb, ";\n");
}
StringBuilder_Append(&cbe.sb, " } ");
StringBuilder_Append(&cbe.sb, ev.name);
StringBuilder_Append(&cbe.sb, ";\n");
}
}
vi = vi + 1;
}
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Data;\n\n");
// 3. Main struct
StringBuilder_Append(&cbe.sb, "typedef struct {\n");
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Tag tag;\n");
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, "_Data data;\n");
StringBuilder_Append(&cbe.sb, "} ");
StringBuilder_Append(&cbe.sb, en.name);
StringBuilder_Append(&cbe.sb, ";\n\n");
}
ei = ei + 1; ei = ei + 1;
} }
if mod.enumCount > 0 {
StringBuilder_Append(&cbe.sb, "\n");
}
// Constant definitions // Constant definitions
var ci: int = 0; var ci: int = 0;
@@ -611,6 +812,22 @@ func CBackend_Generate(mod: *HirModule) -> String {
si = si + 1; si = si + 1;
} }
// Opaque forward declarations for generic structs (used only by pointer)
si = 0;
while si < mod.structCount {
if CBE_StructHasGeneric(&mod.structs[si]) {
StringBuilder_Append(&cbe.sb, "typedef struct ");
StringBuilder_Append(&cbe.sb, mod.structs[si].name);
StringBuilder_Append(&cbe.sb, " ");
StringBuilder_Append(&cbe.sb, mod.structs[si].name);
StringBuilder_Append(&cbe.sb, ";\n");
}
si = si + 1;
}
if mod.structCount > 0 {
StringBuilder_Append(&cbe.sb, "\n");
}
// Forward declarations for all functions (skip generics) // Forward declarations for all functions (skip generics)
var i: int = 0; var i: int = 0;
while i < mod.funcCount { while i < mod.funcCount {
+2
View File
@@ -129,6 +129,8 @@ struct HirConst {
struct HirEnum { struct HirEnum {
name: String; name: String;
variantCount: int;
variants: *HirEnumVariant;
} }
struct HirModule { struct HirModule {
+125 -28
View File
@@ -2,6 +2,7 @@
// Transforms the typed AST into a lower-level IR suitable for code generation. // Transforms the typed AST into a lower-level IR suitable for code generation.
module HirLower { module HirLower {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Lowering context // Lowering context
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -22,15 +23,7 @@ struct LowerCtx {
// resolves the correct Type.kind for codegen. // resolves the correct Type.kind for codegen.
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
func Lcx_ResolveTypeKind(te: *TypeExpr) -> int { func Lcx_ResolveTypeKindFromName(name: String) -> int {
if te == null as *TypeExpr { return tyUnknown; }
let name: String = te.typeName;
if te.kind == tekPointer { return tyPointer; }
if te.kind == tekSlice { return tySlice; }
if te.kind == tekTuple { return tyTuple; }
// Named types: resolve by name
if String_Eq(name, "void") { return tyVoid; } if String_Eq(name, "void") { return tyVoid; }
if String_Eq(name, "bool") { return tyBool; } if String_Eq(name, "bool") { return tyBool; }
if String_Eq(name, "bool8") { return tyBool8; } if String_Eq(name, "bool8") { return tyBool8; }
@@ -54,10 +47,19 @@ func Lcx_ResolveTypeKind(te: *TypeExpr) -> int {
if String_Eq(name, "float32") { return tyFloat32; } if String_Eq(name, "float32") { return tyFloat32; }
if String_Eq(name, "float64") { return tyFloat64; } if String_Eq(name, "float64") { return tyFloat64; }
if String_Eq(name, "float") { return tyFloat64; } if String_Eq(name, "float") { return tyFloat64; }
return tyNamed; return tyNamed;
} }
func Lcx_ResolveTypeKind(te: *TypeExpr) -> int {
if te == null as *TypeExpr { return tyUnknown; }
if te.kind == tekPointer { return tyPointer; }
if te.kind == tekSlice { return tySlice; }
if te.kind == tekTuple { return tyTuple; }
return Lcx_ResolveTypeKindFromName(te.typeName);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Fresh name generation // Fresh name generation
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -400,7 +402,7 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
alloca.typeName = stmt.refStmtType.typeName; alloca.typeName = stmt.refStmtType.typeName;
} }
} }
// Add to scope for field offset lookups // Add to scope for field offset lookups (skip if already defined)
var sym: Symbol; var sym: Symbol;
sym.kind = skVar; sym.kind = skVar;
sym.name = stmt.strValue; sym.name = stmt.strValue;
@@ -439,7 +441,6 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1); n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1);
} }
if stmt.refStmtElse != null as *Block { if stmt.refStmtElse != null as *Block {
// Store else block in extraData (child3 is reserved for block chaining)
n.extraData = Lcx_LowerBlock(ctx, stmt.refStmtElse, -1) as *void; n.extraData = Lcx_LowerBlock(ctx, stmt.refStmtElse, -1) as *void;
} }
return n; return n;
@@ -464,6 +465,18 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode {
return n; return n;
} }
// Break
if kind == skBreak {
n.kind = hBreak;
return n;
}
// Continue
if kind == skContinue {
n.kind = hContinue;
return n;
}
return n; return n;
} }
@@ -557,7 +570,10 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
f.retTypeKind = 0; f.retTypeKind = 0;
} }
// Add parameters to hir_lower scope for field offset lookups // Create function scope as child of current scope
var funcScope: Scope = Scope_NewChild(ctx.scope);
// Add parameters to function scope for field offset lookups
var pi: int = 0; var pi: int = 0;
while pi < decl.paramCount { while pi < decl.paramCount {
var p: *Param = null as *Param; var p: *Param = null as *Param;
@@ -575,20 +591,31 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc {
sym.kind = skVar; sym.kind = skVar;
sym.name = p.name; sym.name = p.name;
sym.typeKind = Lcx_ResolveTypeKind(p.refParamType); sym.typeKind = Lcx_ResolveTypeKind(p.refParamType);
sym.typeName = p.refParamType.typeName; // Build typeName same as Lcx_LowerParam
if !String_Eq(p.refParamType.typeName, "") {
sym.typeName = p.refParamType.typeName;
} else if p.refParamType.kind == tekPointer && p.refParamType.pointerPointee != null as *TypeExpr {
sym.typeName = String_Concat(p.refParamType.pointerPointee.typeName, "*");
} else {
sym.typeName = "";
}
sym.isMutable = false; sym.isMutable = false;
sym.isPublic = false; sym.isPublic = false;
sym.decl = null as *Decl; sym.decl = null as *Decl;
discard Scope_Define(ctx.scope, sym); discard Scope_Define(&funcScope, sym);
} }
pi = pi + 1; pi = pi + 1;
} }
// Lower body with function scope active
let prevScope: *Scope = ctx.scope;
ctx.scope = &funcScope;
if decl.refBody != null as *Block { if decl.refBody != null as *Block {
f.body = Lcx_LowerBlock(ctx, decl.refBody, -1); f.body = Lcx_LowerBlock(ctx, decl.refBody, -1);
} else { } else {
f.body = null as *HirNode; f.body = null as *HirNode;
} }
ctx.scope = prevScope;
return f; return f;
} }
@@ -666,6 +693,62 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
else if fi == 5 { fname = decl.field5.name; ftype = decl.field5.refFieldType; } else if fi == 5 { fname = decl.field5.name; ftype = decl.field5.refFieldType; }
else if fi == 6 { fname = decl.field6.name; ftype = decl.field6.refFieldType; } else if fi == 6 { fname = decl.field6.name; ftype = decl.field6.refFieldType; }
else if fi == 7 { fname = decl.field7.name; ftype = decl.field7.refFieldType; } else if fi == 7 { fname = decl.field7.name; ftype = decl.field7.refFieldType; }
else if fi == 8 { fname = decl.field8.name; ftype = decl.field8.refFieldType; }
else if fi == 9 { fname = decl.field9.name; ftype = decl.field9.refFieldType; }
else if fi == 10 { fname = decl.field10.name; ftype = decl.field10.refFieldType; }
else if fi == 11 { fname = decl.field11.name; ftype = decl.field11.refFieldType; }
else if fi == 12 { fname = decl.field12.name; ftype = decl.field12.refFieldType; }
else if fi == 13 { fname = decl.field13.name; ftype = decl.field13.refFieldType; }
else if fi == 14 { fname = decl.field14.name; ftype = decl.field14.refFieldType; }
else if fi == 15 { fname = decl.field15.name; ftype = decl.field15.refFieldType; }
else if fi == 16 { fname = decl.field16.name; ftype = decl.field16.refFieldType; }
else if fi == 17 { fname = decl.field17.name; ftype = decl.field17.refFieldType; }
else if fi == 18 { fname = decl.field18.name; ftype = decl.field18.refFieldType; }
else if fi == 19 { fname = decl.field19.name; ftype = decl.field19.refFieldType; }
else if fi == 20 { fname = decl.field20.name; ftype = decl.field20.refFieldType; }
else if fi == 21 { fname = decl.field21.name; ftype = decl.field21.refFieldType; }
else if fi == 22 { fname = decl.field22.name; ftype = decl.field22.refFieldType; }
else if fi == 23 { fname = decl.field23.name; ftype = decl.field23.refFieldType; }
else if fi == 24 { fname = decl.field24.name; ftype = decl.field24.refFieldType; }
else if fi == 25 { fname = decl.field25.name; ftype = decl.field25.refFieldType; }
else if fi == 26 { fname = decl.field26.name; ftype = decl.field26.refFieldType; }
else if fi == 27 { fname = decl.field27.name; ftype = decl.field27.refFieldType; }
else if fi == 28 { fname = decl.field28.name; ftype = decl.field28.refFieldType; }
else if fi == 29 { fname = decl.field29.name; ftype = decl.field29.refFieldType; }
else if fi == 30 { fname = decl.field30.name; ftype = decl.field30.refFieldType; }
else if fi == 31 { fname = decl.field31.name; ftype = decl.field31.refFieldType; }
else if fi == 32 { fname = decl.field32.name; ftype = decl.field32.refFieldType; }
else if fi == 33 { fname = decl.field33.name; ftype = decl.field33.refFieldType; }
else if fi == 34 { fname = decl.field34.name; ftype = decl.field34.refFieldType; }
else if fi == 35 { fname = decl.field35.name; ftype = decl.field35.refFieldType; }
else if fi == 36 { fname = decl.field36.name; ftype = decl.field36.refFieldType; }
else if fi == 37 { fname = decl.field37.name; ftype = decl.field37.refFieldType; }
else if fi == 38 { fname = decl.field38.name; ftype = decl.field38.refFieldType; }
else if fi == 39 { fname = decl.field39.name; ftype = decl.field39.refFieldType; }
else if fi == 40 { fname = decl.field40.name; ftype = decl.field40.refFieldType; }
else if fi == 41 { fname = decl.field41.name; ftype = decl.field41.refFieldType; }
else if fi == 42 { fname = decl.field42.name; ftype = decl.field42.refFieldType; }
else if fi == 43 { fname = decl.field43.name; ftype = decl.field43.refFieldType; }
else if fi == 44 { fname = decl.field44.name; ftype = decl.field44.refFieldType; }
else if fi == 45 { fname = decl.field45.name; ftype = decl.field45.refFieldType; }
else if fi == 46 { fname = decl.field46.name; ftype = decl.field46.refFieldType; }
else if fi == 47 { fname = decl.field47.name; ftype = decl.field47.refFieldType; }
else if fi == 48 { fname = decl.field48.name; ftype = decl.field48.refFieldType; }
else if fi == 49 { fname = decl.field49.name; ftype = decl.field49.refFieldType; }
else if fi == 50 { fname = decl.field50.name; ftype = decl.field50.refFieldType; }
else if fi == 51 { fname = decl.field51.name; ftype = decl.field51.refFieldType; }
else if fi == 52 { fname = decl.field52.name; ftype = decl.field52.refFieldType; }
else if fi == 53 { fname = decl.field53.name; ftype = decl.field53.refFieldType; }
else if fi == 54 { fname = decl.field54.name; ftype = decl.field54.refFieldType; }
else if fi == 55 { fname = decl.field55.name; ftype = decl.field55.refFieldType; }
else if fi == 56 { fname = decl.field56.name; ftype = decl.field56.refFieldType; }
else if fi == 57 { fname = decl.field57.name; ftype = decl.field57.refFieldType; }
else if fi == 58 { fname = decl.field58.name; ftype = decl.field58.refFieldType; }
else if fi == 59 { fname = decl.field59.name; ftype = decl.field59.refFieldType; }
else if fi == 60 { fname = decl.field60.name; ftype = decl.field60.refFieldType; }
else if fi == 61 { fname = decl.field61.name; ftype = decl.field61.refFieldType; }
else if fi == 62 { fname = decl.field62.name; ftype = decl.field62.refFieldType; }
else if fi == 63 { fname = decl.field63.name; ftype = decl.field63.refFieldType; }
// Skip empty field names // Skip empty field names
if String_Eq(fname, "") { if String_Eq(fname, "") {
fi = fi + 1; fi = fi + 1;
@@ -701,23 +784,37 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
if decl.kind == dkEnum { if decl.kind == dkEnum {
let ei: int = hm.enumCount; let ei: int = hm.enumCount;
hm.enums[ei].name = decl.strValue; hm.enums[ei].name = decl.strValue;
hm.enumCount = hm.enumCount + 1; // Populate variants
// Emit enum variants as constants: EnumName_VariantName = value hm.enums[ei].variantCount = decl.variantCount;
if decl.variantCount > 0 {
hm.enums[ei].variants = bux_alloc(decl.variantCount as uint * sizeof(HirEnumVariant)) as *HirEnumVariant;
}
var vi: int = 0; var vi: int = 0;
while vi < decl.variantCount && hm.constCount < 512 { while vi < decl.variantCount {
var vname: String = ""; var v: *EnumVariant = null as *EnumVariant;
if vi == 0 { vname = decl.variant0.name; } if vi == 0 { v = &decl.variant0; }
if vi == 1 { vname = decl.variant1.name; } if vi == 1 { v = &decl.variant1; }
if vi == 2 { vname = decl.variant2.name; } if vi == 2 { v = &decl.variant2; }
if vi == 3 { vname = decl.variant3.name; } if vi == 3 { v = &decl.variant3; }
if !String_Eq(vname, "") { if vi == 4 { v = &decl.variant4; }
let ci: int = hm.constCount; if vi == 5 { v = &decl.variant5; }
hm.consts[ci].name = String_Concat(String_Concat(decl.strValue, "_"), vname); if vi == 6 { v = &decl.variant6; }
hm.consts[ci].value = vi; if vi == 7 { v = &decl.variant7; }
hm.constCount = hm.constCount + 1; if v != null as *EnumVariant {
hm.enums[ei].variants[vi].name = v.name;
hm.enums[ei].variants[vi].fieldCount = v.fieldCount;
if v.fieldCount > 0 {
hm.enums[ei].variants[vi].fieldName0 = "value";
hm.enums[ei].variants[vi].fieldType0 = Lcx_ResolveTypeKindFromName(v.fieldTypeName0);
}
if v.fieldCount > 1 {
hm.enums[ei].variants[vi].fieldName1 = "value2";
hm.enums[ei].variants[vi].fieldType1 = Lcx_ResolveTypeKindFromName(v.fieldTypeName1);
}
} }
vi = vi + 1; vi = vi + 1;
} }
hm.enumCount = hm.enumCount + 1;
} }
decl = decl.childDecl2; decl = decl.childDecl2;
} }
+10
View File
@@ -666,6 +666,9 @@ func parserParseStmt(p: *Parser) -> *Stmt {
p.structInitAllowed = true; p.structInitAllowed = true;
let thenBlock: *Block = parserParseBlock(p); let thenBlock: *Block = parserParseBlock(p);
var elseBlock: *Block = null as *Block; var elseBlock: *Block = null as *Block;
while parserCheck(p, tkNewLine) {
discard parserAdvance(p);
}
if parserMatch(p, tkElse) { if parserMatch(p, tkElse) {
if parserCheck(p, tkIf) { if parserCheck(p, tkIf) {
// else if → parse the if statement, wrap in a synthetic block // else if → parse the if statement, wrap in a synthetic block
@@ -1226,6 +1229,9 @@ func parserParseEnumDecl(p: *Parser, isPublic: bool) -> *Decl {
var v: EnumVariant; var v: EnumVariant;
v.name = vName.text; v.name = vName.text;
v.fieldCount = 0;
v.fieldTypeName0 = "";
v.fieldTypeName1 = "";
// Optional (Type, Type) data // Optional (Type, Type) data
if parserMatch(p, tkLParen) { if parserMatch(p, tkLParen) {
@@ -1244,6 +1250,10 @@ func parserParseEnumDecl(p: *Parser, isPublic: bool) -> *Decl {
else if d.variantCount == 1 { d.variant1 = v; } else if d.variantCount == 1 { d.variant1 = v; }
else if d.variantCount == 2 { d.variant2 = v; } else if d.variantCount == 2 { d.variant2 = v; }
else if d.variantCount == 3 { d.variant3 = v; } else if d.variantCount == 3 { d.variant3 = v; }
else if d.variantCount == 4 { d.variant4 = v; }
else if d.variantCount == 5 { d.variant5 = v; }
else if d.variantCount == 6 { d.variant6 = v; }
else if d.variantCount == 7 { d.variant7 = v; }
d.variantCount = d.variantCount + 1; d.variantCount = d.variantCount + 1;
parserMatch(p, tkComma); parserMatch(p, tkComma);
+4 -1
View File
@@ -146,7 +146,6 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int {
if expr == null as *Expr { return tyUnknown; } if expr == null as *Expr { return tyUnknown; }
let kind: int = expr.kind; let kind: int = expr.kind;
// Debug: print expr kind // Debug: print expr kind
// Print("Sema_CheckExpr kind=");
// PrintInt(kind as int64); // PrintInt(kind as int64);
// PrintLine(""); // PrintLine("");
@@ -493,6 +492,10 @@ func Sema_CollectGlobals(sema: *Sema) {
else if vi == 5 { v = decl.variant5; } else if vi == 5 { v = decl.variant5; }
else if vi == 6 { v = decl.variant6; } else if vi == 6 { v = decl.variant6; }
else if vi == 7 { v = decl.variant7; } else if vi == 7 { v = decl.variant7; }
if v.name == null as String || String_Eq(v.name, "") {
vi = vi + 1;
continue;
}
let variantName: String = String_Concat(decl.strValue, "_"); let variantName: String = String_Concat(decl.strValue, "_");
let variantName2: String = String_Concat(variantName, v.name); let variantName2: String = String_Concat(variantName, v.name);
var vSym: Symbol; var vSym: Symbol;