feat: keyword-as-identifier, C struct defs with forward decls, field4-7 in HIR
This commit is contained in:
@@ -446,6 +446,49 @@ func CBackend_Generate(mod: *HirModule) -> String {
|
||||
StringBuilder_Append(&cbe.sb, "void* bux_alloc(unsigned int size);\n");
|
||||
StringBuilder_Append(&cbe.sb, "void bux_free(void* ptr);\n\n");
|
||||
|
||||
// Forward declare all struct types
|
||||
var si: int = 0;
|
||||
while si < mod.structCount {
|
||||
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;
|
||||
}
|
||||
StringBuilder_Append(&cbe.sb, "\n");
|
||||
|
||||
// Struct definitions
|
||||
si = 0;
|
||||
while si < mod.structCount {
|
||||
StringBuilder_Append(&cbe.sb, "typedef struct {\n");
|
||||
var fi: int = 0;
|
||||
while fi < mod.structs[si].fieldCount {
|
||||
StringBuilder_Append(&cbe.sb, " ");
|
||||
var ft: String = mod.structs[si].fields[fi].typeName;
|
||||
if String_Eq(ft, "int") || String_Eq(ft, "") {
|
||||
StringBuilder_Append(&cbe.sb, "int");
|
||||
} else if String_Eq(ft, "String") {
|
||||
StringBuilder_Append(&cbe.sb, "String");
|
||||
} else if String_Eq(ft, "bool") {
|
||||
StringBuilder_Append(&cbe.sb, "bool");
|
||||
} else if String_Eq(ft, "uint32") {
|
||||
StringBuilder_Append(&cbe.sb, "uint32");
|
||||
} else {
|
||||
// Use the type name directly (handles "Foo*", "Bar", etc.)
|
||||
StringBuilder_Append(&cbe.sb, ft);
|
||||
}
|
||||
StringBuilder_Append(&cbe.sb, " ");
|
||||
StringBuilder_Append(&cbe.sb, mod.structs[si].fields[fi].name);
|
||||
StringBuilder_Append(&cbe.sb, ";\n");
|
||||
fi = fi + 1;
|
||||
}
|
||||
StringBuilder_Append(&cbe.sb, "} ");
|
||||
StringBuilder_Append(&cbe.sb, mod.structs[si].name);
|
||||
StringBuilder_Append(&cbe.sb, ";\n\n");
|
||||
si = si + 1;
|
||||
}
|
||||
|
||||
// Forward declarations for all functions
|
||||
var i: int = 0;
|
||||
while i < mod.funcCount {
|
||||
|
||||
@@ -97,12 +97,24 @@ struct HirEnumVariant {
|
||||
// HirModule
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
struct HirStructField {
|
||||
name: String,
|
||||
typeName: String,
|
||||
}
|
||||
|
||||
struct HirStruct {
|
||||
name: String,
|
||||
fieldCount: int,
|
||||
fields: *HirStructField,
|
||||
}
|
||||
|
||||
struct HirModule {
|
||||
funcCount: int,
|
||||
funcs: *HirFunc,
|
||||
externCount: int,
|
||||
externFuncs: *HirFunc,
|
||||
structCount: int,
|
||||
structs: *HirStruct,
|
||||
enumCount: int,
|
||||
}
|
||||
|
||||
|
||||
@@ -382,6 +382,12 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
|
||||
let hm: *HirModule = bux_alloc(sizeof(HirModule)) as *HirModule;
|
||||
hm.funcCount = 0;
|
||||
hm.funcs = ctx.funcs;
|
||||
hm.structCount = 0;
|
||||
hm.structs = bux_alloc(64 as uint * sizeof(HirStruct)) as *HirStruct;
|
||||
|
||||
// First pass: count structs (to allocate field arrays later)
|
||||
// Second pass: actually collect them
|
||||
// For simplicity, do single pass with pre-allocated field arrays
|
||||
|
||||
// Iterate declarations
|
||||
var decl: *Decl = mod.firstItem;
|
||||
@@ -397,6 +403,41 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
|
||||
ctx.externCount = ctx.externCount + 1;
|
||||
}
|
||||
if decl.kind == dkStruct {
|
||||
// Collect struct definition for C codegen
|
||||
let si: int = hm.structCount;
|
||||
hm.structs[si].name = decl.strValue;
|
||||
hm.structs[si].fieldCount = decl.fieldCount;
|
||||
hm.structs[si].fields = bux_alloc(decl.fieldCount as uint * sizeof(HirStructField)) as *HirStructField;
|
||||
var fi: int = 0;
|
||||
while fi < decl.fieldCount {
|
||||
var fname: String = "";
|
||||
var ftype: *TypeExpr = null as *TypeExpr;
|
||||
if fi == 0 { fname = decl.field0.name; ftype = decl.field0.refFieldType; }
|
||||
else if fi == 1 { fname = decl.field1.name; ftype = decl.field1.refFieldType; }
|
||||
else if fi == 2 { fname = decl.field2.name; ftype = decl.field2.refFieldType; }
|
||||
else if fi == 3 { fname = decl.field3.name; ftype = decl.field3.refFieldType; }
|
||||
else if fi == 4 { fname = decl.field4.name; ftype = decl.field4.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 == 7 { fname = decl.field7.name; ftype = decl.field7.refFieldType; }
|
||||
// Skip empty field names
|
||||
if String_Eq(fname, "") {
|
||||
fi = fi + 1;
|
||||
continue;
|
||||
}
|
||||
hm.structs[si].fields[fi].name = fname;
|
||||
if ftype != null as *TypeExpr {
|
||||
if ftype.kind == tekPointer && ftype.pointerPointee != null as *TypeExpr {
|
||||
// Pointer type: emit "TypeName*"
|
||||
if !String_Eq(ftype.pointerPointee.typeName, "") {
|
||||
hm.structs[si].fields[fi].typeName = String_Concat(ftype.pointerPointee.typeName, "*");
|
||||
}
|
||||
} else if !String_Eq(ftype.typeName, "") {
|
||||
hm.structs[si].fields[fi].typeName = ftype.typeName;
|
||||
}
|
||||
}
|
||||
fi = fi + 1;
|
||||
}
|
||||
hm.structCount = hm.structCount + 1;
|
||||
}
|
||||
if decl.kind == dkEnum {
|
||||
|
||||
+24
-6
@@ -92,6 +92,24 @@ func parserEmitDiag(p: *Parser, line: uint32, col: uint32, msg: String) {
|
||||
p.diagCount = p.diagCount + 1;
|
||||
}
|
||||
|
||||
func parserIsKeyword(kind: int) -> bool {
|
||||
if kind >= tkIf && kind <= tkSuper { return true; }
|
||||
if kind == tkSizeOf { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
func parserExpectIdentOrKeyword(p: *Parser, msg: String) -> LexToken {
|
||||
let tok: LexToken = parserCurToken(p);
|
||||
if tok.kind == tkIdent || parserIsKeyword(tok.kind) {
|
||||
return parserAdvance(p);
|
||||
}
|
||||
p.diags[p.diagCount] = ParserDiag {
|
||||
line: tok.line, column: tok.column, message: msg
|
||||
};
|
||||
p.diagCount = p.diagCount + 1;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Type parsing
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -379,7 +397,7 @@ func parserParsePostfix(p: *Parser) -> *Expr {
|
||||
while parserCheck(p, tkNewLine) { discard parserAdvance(p); }
|
||||
if parserCheck(p, tkRBrace) || parserPeek(p, 0) == tkEndOfFile { break; }
|
||||
let sip: int = p.pos;
|
||||
let fName: LexToken = parserExpect(p, tkIdent, "expected field name");
|
||||
let fName: LexToken = parserExpectIdentOrKeyword(p, "expected field name");
|
||||
discard parserExpect(p, tkColon, "expected ':'");
|
||||
let fValue: *Expr = parserParseExpr(p);
|
||||
let fExpr: *Expr = parserMakeExpr(ekField, fName.line, fName.column);
|
||||
@@ -487,7 +505,7 @@ func parserParseStmt(p: *Parser) -> *Stmt {
|
||||
if kind == tkLet || kind == tkVar {
|
||||
let isVar: bool = (kind == tkVar);
|
||||
discard parserAdvance(p);
|
||||
let nameTok: LexToken = parserExpect(p, tkIdent, "expected variable name");
|
||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected variable name");
|
||||
var typeExpr: *TypeExpr = null as *TypeExpr;
|
||||
if parserMatch(p, tkColon) {
|
||||
typeExpr = parserParseType(p);
|
||||
@@ -711,7 +729,7 @@ func parserParseParamList(p: *Parser) -> *Decl {
|
||||
discard parserExpect(p, tkLParen, "expected '('");
|
||||
while !parserCheck(p, tkRParen) && parserPeek(p, 0) != tkEndOfFile {
|
||||
if d.paramCount >= 6 { break; }
|
||||
let nameTok: LexToken = parserExpect(p, tkIdent, "expected parameter name");
|
||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected parameter name");
|
||||
discard parserExpect(p, tkColon, "expected ':' in parameter");
|
||||
let ptype: *TypeExpr = parserParseType(p);
|
||||
|
||||
@@ -752,7 +770,7 @@ func parserParseFuncDecl(p: *Parser, isPublic: bool, isExtern: bool) -> *Decl {
|
||||
let col: uint32 = parserCurToken(p).column;
|
||||
discard parserExpect(p, tkFunc, "expected 'func'");
|
||||
|
||||
let nameTok: LexToken = parserExpect(p, tkIdent, "expected function name");
|
||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected function name");
|
||||
let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl;
|
||||
d.kind = dkFunc;
|
||||
d.line = line;
|
||||
@@ -803,7 +821,7 @@ func parserParseStructDecl(p: *Parser, isPublic: bool) -> *Decl {
|
||||
let line: uint32 = parserCurToken(p).line;
|
||||
let col: uint32 = parserCurToken(p).column;
|
||||
discard parserExpect(p, tkStruct, "expected 'struct'");
|
||||
let nameTok: LexToken = parserExpect(p, tkIdent, "expected struct name");
|
||||
let nameTok: LexToken = parserExpectIdentOrKeyword(p, "expected struct name");
|
||||
|
||||
let d: *Decl = bux_alloc(sizeof(Decl)) as *Decl;
|
||||
d.kind = dkStruct;
|
||||
@@ -832,7 +850,7 @@ func parserParseStructDecl(p: *Parser, isPublic: bool) -> *Decl {
|
||||
if parserCheck(p, tkNewLine) { discard parserAdvance(p); continue; }
|
||||
if parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; }
|
||||
let beforePos: int = p.pos;
|
||||
let fName: LexToken = parserExpect(p, tkIdent, "expected field name");
|
||||
let fName: LexToken = parserExpectIdentOrKeyword(p, "expected field name");
|
||||
discard parserExpect(p, tkColon, "expected ':' in struct field");
|
||||
let fType: *TypeExpr = parserParseType(p);
|
||||
parserMatch(p, tkSemicolon);
|
||||
|
||||
Reference in New Issue
Block a user