From 0bdef5818295bd11a5cae0de5aa9b5d97ec6472f Mon Sep 17 00:00:00 2001 From: dimgigov Date: Sat, 6 Jun 2026 23:54:09 +0300 Subject: [PATCH] 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 --- rt/runtime.c | 26 +---- src/c_backend.bux | 239 +++++++++++++++++++++++++++++++++++++++++++--- src/hir.bux | 2 + src/hir_lower.bux | 153 +++++++++++++++++++++++------ src/parser.bux | 10 ++ src/sema.bux | 5 +- 6 files changed, 370 insertions(+), 65 deletions(-) diff --git a/rt/runtime.c b/rt/runtime.c index 3f03c3e..30c4c5c 100644 --- a/rt/runtime.c +++ b/rt/runtime.c @@ -507,31 +507,7 @@ int bux_write_file(const char* path, const char* content) { FILE* f = fopen(path, "wb"); if (!f) return 0; size_t len = strlen(content); - size_t written = 0; - 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++; - } + size_t written = fwrite(content, 1, len, f); fclose(f); return written > 0 ? 1 : 0; } diff --git a/src/c_backend.bux b/src/c_backend.bux index 958d8b8..7d0e701 100644 --- a/src/c_backend.bux +++ b/src/c_backend.bux @@ -2,6 +2,7 @@ // Generates C code from the HIR. module CBackend { + // --------------------------------------------------------------------------- // Type → C type name // --------------------------------------------------------------------------- @@ -102,13 +103,49 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) { if node.intValue == tkNull { StringBuilder_Append(&cbe.sb, "0"); } 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; } // Variable 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); return; } @@ -228,6 +265,7 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) { // If if kind == hIf { + StringBuilder_Append(&cbe.sb, "if ("); CBE_EmitExpr(cbe, node.child1); StringBuilder_Append(&cbe.sb, ") {\n"); @@ -296,10 +334,32 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) { 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 { 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); return; } @@ -326,7 +386,53 @@ func CBE_EmitExpr(cbe: *CEmitter, node: *HirNode) { } // Load: *ptr — emit as *ptr (dereference) + // Optimize common patterns to avoid & / * temporaries 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, "(*"); CBE_EmitExpr(cbe, node.child1); StringBuilder_Append(&cbe.sb, ")"); @@ -467,11 +573,18 @@ func CBE_EmitFuncDecl(cbe: *CEmitter, f: *HirFunc) { 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; } + // Any type name containing '<' is a generic instantiation or parameter + if String_Contains(name, "<") { return true; } // Generic container structs and their pointer variants 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, "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, "StringMap") || String_Eq(name, "StringMap*") { return true; } + if String_Eq(name, "StringMapEntry") || String_Eq(name, "StringMapEntry*") { return true; } return false; } @@ -550,17 +663,105 @@ func CBackend_Generate(mod: *HirModule) -> String { } StringBuilder_Append(&cbe.sb, "\n"); - // Enum definitions (typedef to int) + // Enum definitions var ei: int = 0; while ei < mod.enumCount { - StringBuilder_Append(&cbe.sb, "typedef int "); - StringBuilder_Append(&cbe.sb, mod.enums[ei].name); - StringBuilder_Append(&cbe.sb, ";\n"); + let en: *HirEnum = &mod.enums[ei]; + var hasData: bool = false; + 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; } - if mod.enumCount > 0 { - StringBuilder_Append(&cbe.sb, "\n"); - } // Constant definitions var ci: int = 0; @@ -611,6 +812,22 @@ func CBackend_Generate(mod: *HirModule) -> String { 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) var i: int = 0; while i < mod.funcCount { diff --git a/src/hir.bux b/src/hir.bux index 2f37e06..06faf10 100644 --- a/src/hir.bux +++ b/src/hir.bux @@ -129,6 +129,8 @@ struct HirConst { struct HirEnum { name: String; + variantCount: int; + variants: *HirEnumVariant; } struct HirModule { diff --git a/src/hir_lower.bux b/src/hir_lower.bux index c83b7f9..5f78402 100644 --- a/src/hir_lower.bux +++ b/src/hir_lower.bux @@ -2,6 +2,7 @@ // Transforms the typed AST into a lower-level IR suitable for code generation. module HirLower { + // --------------------------------------------------------------------------- // Lowering context // --------------------------------------------------------------------------- @@ -22,15 +23,7 @@ struct LowerCtx { // resolves the correct Type.kind for codegen. // --------------------------------------------------------------------------- -func Lcx_ResolveTypeKind(te: *TypeExpr) -> 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 +func Lcx_ResolveTypeKindFromName(name: String) -> int { if String_Eq(name, "void") { return tyVoid; } if String_Eq(name, "bool") { return tyBool; } 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, "float64") { return tyFloat64; } if String_Eq(name, "float") { return tyFloat64; } - 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 // --------------------------------------------------------------------------- @@ -400,7 +402,7 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { 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; sym.kind = skVar; sym.name = stmt.strValue; @@ -439,7 +441,6 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { n.child2 = Lcx_LowerBlock(ctx, stmt.refStmtBlock, -1); } 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; } return n; @@ -464,6 +465,18 @@ func Lcx_LowerStmt(ctx: *LowerCtx, stmt: *Stmt) -> *HirNode { return n; } + // Break + if kind == skBreak { + n.kind = hBreak; + return n; + } + + // Continue + if kind == skContinue { + n.kind = hContinue; + return n; + } + return n; } @@ -557,7 +570,10 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc { 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; while pi < decl.paramCount { var p: *Param = null as *Param; @@ -575,20 +591,31 @@ func Lcx_LowerFunc(ctx: *LowerCtx, decl: *Decl) -> *HirFunc { sym.kind = skVar; sym.name = p.name; 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.isPublic = false; sym.decl = null as *Decl; - discard Scope_Define(ctx.scope, sym); + discard Scope_Define(&funcScope, sym); } pi = pi + 1; } + // Lower body with function scope active + let prevScope: *Scope = ctx.scope; + ctx.scope = &funcScope; if decl.refBody != null as *Block { f.body = Lcx_LowerBlock(ctx, decl.refBody, -1); } else { f.body = null as *HirNode; } + ctx.scope = prevScope; 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 == 6 { fname = decl.field6.name; ftype = decl.field6.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 if String_Eq(fname, "") { fi = fi + 1; @@ -701,23 +784,37 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule { if decl.kind == dkEnum { let ei: int = hm.enumCount; hm.enums[ei].name = decl.strValue; - hm.enumCount = hm.enumCount + 1; - // Emit enum variants as constants: EnumName_VariantName = value + // Populate variants + 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; - while vi < decl.variantCount && hm.constCount < 512 { - var vname: String = ""; - if vi == 0 { vname = decl.variant0.name; } - if vi == 1 { vname = decl.variant1.name; } - if vi == 2 { vname = decl.variant2.name; } - if vi == 3 { vname = decl.variant3.name; } - if !String_Eq(vname, "") { - let ci: int = hm.constCount; - hm.consts[ci].name = String_Concat(String_Concat(decl.strValue, "_"), vname); - hm.consts[ci].value = vi; - hm.constCount = hm.constCount + 1; + while vi < decl.variantCount { + var v: *EnumVariant = null as *EnumVariant; + if vi == 0 { v = &decl.variant0; } + if vi == 1 { v = &decl.variant1; } + if vi == 2 { v = &decl.variant2; } + if vi == 3 { v = &decl.variant3; } + if vi == 4 { v = &decl.variant4; } + if vi == 5 { v = &decl.variant5; } + if vi == 6 { v = &decl.variant6; } + if vi == 7 { v = &decl.variant7; } + 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; } + hm.enumCount = hm.enumCount + 1; } decl = decl.childDecl2; } diff --git a/src/parser.bux b/src/parser.bux index 187c1b2..07f84e0 100644 --- a/src/parser.bux +++ b/src/parser.bux @@ -666,6 +666,9 @@ func parserParseStmt(p: *Parser) -> *Stmt { p.structInitAllowed = true; let thenBlock: *Block = parserParseBlock(p); var elseBlock: *Block = null as *Block; + while parserCheck(p, tkNewLine) { + discard parserAdvance(p); + } if parserMatch(p, tkElse) { if parserCheck(p, tkIf) { // 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; v.name = vName.text; + v.fieldCount = 0; + v.fieldTypeName0 = ""; + v.fieldTypeName1 = ""; // Optional (Type, Type) data 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 == 2 { d.variant2 = 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; parserMatch(p, tkComma); diff --git a/src/sema.bux b/src/sema.bux index d1e9775..194fdee 100644 --- a/src/sema.bux +++ b/src/sema.bux @@ -146,7 +146,6 @@ func Sema_CheckExpr(sema: *Sema, expr: *Expr) -> int { if expr == null as *Expr { return tyUnknown; } let kind: int = expr.kind; // Debug: print expr kind - // Print("Sema_CheckExpr kind="); // PrintInt(kind as int64); // PrintLine(""); @@ -493,6 +492,10 @@ func Sema_CollectGlobals(sema: *Sema) { else if vi == 5 { v = decl.variant5; } else if vi == 6 { v = decl.variant6; } 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 variantName2: String = String_Concat(variantName, v.name); var vSym: Symbol;