feat: 枚举关联数据 ADT — enum Option { Some(i64), None }

This commit is contained in:
2026-06-06 14:21:43 +08:00
parent 0ec3c3d65f
commit 0e1f8c5795
9 changed files with 172 additions and 37 deletions
+58 -18
View File
@@ -67,7 +67,12 @@ static LLVMTypeRef to_llvm_type(CgCtx* ctx, TypeKind kind) {
case TYPE_CHAR: return LLVMInt8TypeInContext(ctx->context);
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
case TYPE_STRUCT:
case TYPE_ENUM: return LLVMInt64TypeInContext(ctx->context);
case TYPE_ENUM: {
// tagged union: { i64 tag, i64 payload }
LLVMTypeRef fields[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, fields, 2, false);
}
case TYPE_UNKNOWN:
case TYPE_ERROR:
default: return LLVMVoidTypeInContext(ctx->context);
@@ -159,8 +164,11 @@ static LLVMTypeRef type_info_to_llvm(CgCtx* ctx, const TypeInfo* ti) {
if (st) return st;
}
return LLVMVoidTypeInContext(ctx->context);
case TYPE_ENUM:
return LLVMInt64TypeInContext(ctx->context);
case TYPE_ENUM: {
LLVMTypeRef f[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, f, 2, false);
}
default:
return to_llvm_type(ctx, ti->kind);
}
@@ -258,23 +266,36 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
case OP_MOD:
return LLVMBuildSRem(ctx->builder, l, r, "srem");
case OP_EQ:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOEQ, l, r, "feq")
: LLVMBuildICmp(ctx->builder, LLVMIntEQ, l, r, "ieq");
case OP_NE:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealONE, l, r, "fne")
: LLVMBuildICmp(ctx->builder, LLVMIntNE, l, r, "ine");
case OP_LT:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOLT, l, r, "flt")
: LLVMBuildICmp(ctx->builder, LLVMIntSLT, l, r, "ilt");
case OP_GT:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOGT, l, r, "fgt")
: LLVMBuildICmp(ctx->builder, LLVMIntSGT, l, r, "igt");
case OP_LE:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOLE, l, r, "fle")
: LLVMBuildICmp(ctx->builder, LLVMIntSLE, l, r, "ile");
case OP_GE:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOGE, l, r, "fge")
: LLVMBuildICmp(ctx->builder, LLVMIntSGE, l, r, "ige");
case OP_GE: {
// 枚举比较: 提取 tag 字段再比较
LLVMValueRef cl = l, cr = r;
if (node->as.binary.left->type.kind == TYPE_ENUM) {
cl = LLVMBuildExtractValue(ctx->builder, l, 0, "enum_tag_l");
}
if (node->as.binary.right->type.kind == TYPE_ENUM) {
cr = LLVMBuildExtractValue(ctx->builder, r, 0, "enum_tag_r");
}
LLVMIntPredicate pred;
switch (node->as.binary.op) {
case OP_EQ: pred = LLVMIntEQ; break;
case OP_NE: pred = LLVMIntNE; break;
case OP_LT: pred = LLVMIntSLT; break;
case OP_GT: pred = LLVMIntSGT; break;
case OP_LE: pred = LLVMIntSLE; break;
case OP_GE: pred = LLVMIntSGE; break;
default: return NULL;
}
if (is_float)
return LLVMBuildFCmp(ctx->builder, pred == LLVMIntEQ ? LLVMRealOEQ :
pred == LLVMIntNE ? LLVMRealONE : pred == LLVMIntSLT ? LLVMRealOLT :
pred == LLVMIntSGT ? LLVMRealOGT : pred == LLVMIntSLE ? LLVMRealOLE :
LLVMRealOGE, cl, cr, "fcmp");
return LLVMBuildICmp(ctx->builder, pred, cl, cr, "icmp");
}
case OP_AND:
return LLVMBuildAnd(ctx->builder, l, r, "and");
case OP_OR:
@@ -289,6 +310,9 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
if (strcmp(node->as.call.name, "print_i64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL;
// 枚举类型: 提取 tag 字段
if (node->as.call.args[0]->type.kind == TYPE_ENUM)
arg = LLVMBuildExtractValue(ctx->builder, arg, 0, "tag");
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
arg = coerce_int(ctx, arg, LLVMTypeOf(arg), i64_ty);
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%lld\n", "fmt_i64");
@@ -384,9 +408,25 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
return LLVMBuildLoad2(ctx->builder, struct_ty, alloca, "struct_val");
}
case AST_ENUM_VARIANT:
return LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
case AST_ENUM_VARIANT: {
// tagged union: { tag, payload }
LLVMValueRef tag = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
(unsigned long long)node->as.enum_variant.variant_index, true);
LLVMValueRef payload = LLVMConstInt(LLVMInt64TypeInContext(ctx->context), 0, true);
if (node->as.enum_variant.payload) {
LLVMValueRef pv = codegen_expr(ctx, node->as.enum_variant.payload);
if (pv) {
// 将 payload 强制转换为 i64
LLVMTypeRef pv_ty = LLVMTypeOf(pv);
LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
if (pv_ty != i64_ty && LLVMGetTypeKind(pv_ty) == LLVMIntegerTypeKind)
pv = coerce_int(ctx, pv, pv_ty, i64_ty);
payload = pv;
}
}
LLVMValueRef fields[] = { tag, payload };
return LLVMConstStruct(fields, 2, false);
}
case AST_METHOD_CALL: {
const char* struct_name = node->as.method_call.receiver->type.struct_name;