feat: 枚举关联数据 ADT — enum Option { Some(i64), None }
This commit is contained in:
+58
-18
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user