feat: add algebraic enums (tagged unions) support

- Generate tagged unions in C backend for enums with data
- Add HirEnumVariant type with fields and namedFields
- Support _Tag and _Data field access in sema
- Support enum variant constants (Result_Ok, Result_Err)
- Support _Data union field access (Ok_0, Err_0, etc.)
- Add algebraic_enums.bux example

Example:
  enum Result {
      Ok(int),
      Err(String)
  }

  let r: Result = Result { tag: Result_Ok };
  r.data.Ok_0 = 42;
This commit is contained in:
2026-05-30 23:50:33 +03:00
parent b59e852330
commit cf074bec89
5 changed files with 181 additions and 22 deletions
+64 -11
View File
@@ -355,17 +355,70 @@ proc emitStruct*(be: var CBackend, name: string, fields: seq[tuple[name: string,
be.emitLine(&"}} {name};")
be.emitLine("")
proc emitEnum*(be: var CBackend, name: string, variants: seq[string]) =
be.emitLine(&"typedef enum {{")
inc be.indent
for i, v in variants:
if i < variants.len - 1:
be.emitLine(&"{name}_{v},")
else:
be.emitLine(&"{name}_{v}")
dec be.indent
be.emitLine(&"}} {name};")
be.emitLine("")
proc emitEnum*(be: var CBackend, name: string, variants: seq[HirEnumVariant]) =
# Check if this is a simple enum (no data) or algebraic enum (with data)
var hasData = false
for v in variants:
if v.fields.len > 0 or v.namedFields.len > 0:
hasData = true
break
if not hasData:
# Simple enum - generate as before
be.emitLine(&"typedef enum {{")
inc be.indent
for i, v in variants:
if i < variants.len - 1:
be.emitLine(&"{name}_{v.name},")
else:
be.emitLine(&"{name}_{v.name}")
dec be.indent
be.emitLine(&"}} {name};")
be.emitLine("")
else:
# Algebraic enum - generate tagged union
# 1. Generate tag enum
be.emitLine(&"typedef enum {{")
inc be.indent
for i, v in variants:
if i < variants.len - 1:
be.emitLine(&"{name}_{v.name},")
else:
be.emitLine(&"{name}_{v.name}")
dec be.indent
be.emitLine(&"}} {name}_Tag;")
be.emitLine("")
# 2. Generate union for data
be.emitLine(&"typedef union {{")
inc be.indent
for v in variants:
if v.fields.len > 0:
# Positional fields
for i, f in v.fields:
let typ = typeToC(f)
be.emitLine(&"{typ} {v.name}_{i};")
elif v.namedFields.len > 0:
# Named fields - generate as struct
be.emitLine(&"struct {{")
inc be.indent
for nf in v.namedFields:
let typ = typeToC(nf.typ)
be.emitLine(&"{typ} {nf.name};")
dec be.indent
be.emitLine(&"}} {v.name};")
dec be.indent
be.emitLine(&"}} {name}_Data;")
be.emitLine("")
# 3. Generate main struct with tag + union
be.emitLine(&"typedef struct {{")
inc be.indent
be.emitLine(&"{name}_Tag tag;")
be.emitLine(&"{name}_Data data;")
dec be.indent
be.emitLine(&"}} {name};")
be.emitLine("")
proc emitExternDecl*(be: var CBackend, efunc: HirFunc) =
let retType = typeToC(efunc.retType)