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:
+1
-25
@@ -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;
|
||||
}
|
||||
|
||||
+228
-11
@@ -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 {
|
||||
|
||||
@@ -129,6 +129,8 @@ struct HirConst {
|
||||
|
||||
struct HirEnum {
|
||||
name: String;
|
||||
variantCount: int;
|
||||
variants: *HirEnumVariant;
|
||||
}
|
||||
|
||||
struct HirModule {
|
||||
|
||||
+125
-28
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+4
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user