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
+6 -2
View File
@@ -200,19 +200,23 @@ AstNode* ast_make_type_alias(void* alloc, const char* name, TypeKind aliased,
// === 枚举相关工厂函数 === // === 枚举相关工厂函数 ===
AstNode* ast_make_enum_decl(void* alloc, const char* name, const char** variants, AstNode* ast_make_enum_decl(void* alloc, const char* name, const char** variants,
size_t count, SourceLoc loc) { TypeKind* payload_types, const char** payload_struct_names,
size_t count, SourceLoc loc) {
NEW(alloc, AST_ENUM_DECL); NEW(alloc, AST_ENUM_DECL);
n->as.enum_decl.name = name; n->as.enum_decl.name = name;
n->as.enum_decl.variants = variants; n->as.enum_decl.variants = variants;
n->as.enum_decl.variant_payload_types = payload_types;
n->as.enum_decl.variant_payload_struct_names = payload_struct_names;
n->as.enum_decl.variant_count = count; n->as.enum_decl.variant_count = count;
return n; return n;
} }
AstNode* ast_make_enum_variant(void* alloc, const char* enum_name, AstNode* ast_make_enum_variant(void* alloc, const char* enum_name,
const char* variant_name, SourceLoc loc) { const char* variant_name, AstNode* payload, SourceLoc loc) {
NEW(alloc, AST_ENUM_VARIANT); NEW(alloc, AST_ENUM_VARIANT);
n->as.enum_variant.enum_name = enum_name; n->as.enum_variant.enum_name = enum_name;
n->as.enum_variant.variant_name = variant_name; n->as.enum_variant.variant_name = variant_name;
n->as.enum_variant.payload = payload;
n->as.enum_variant.variant_index = -1; n->as.enum_variant.variant_index = -1;
return n; return n;
} }
+12 -4
View File
@@ -104,9 +104,14 @@ struct AstNode {
// AST_TYPE_ALIAS // AST_TYPE_ALIAS
struct { const char* name; TypeKind aliased_type; const char* aliased_struct_name; } type_alias; struct { const char* name; TypeKind aliased_type; const char* aliased_struct_name; } type_alias;
// AST_ENUM_DECL // AST_ENUM_DECL
struct { const char* name; const char** variants; size_t variant_count; } enum_decl; struct { const char* name; const char** variants;
TypeKind* variant_payload_types; // 每个变体的 payload 类型(TYPE_VOID=无)
const char** variant_payload_struct_names; // payload 为 struct 时的类型名
size_t variant_count; } enum_decl;
// AST_ENUM_VARIANT // AST_ENUM_VARIANT
struct { const char* enum_name; const char* variant_name; int variant_index; } enum_variant; struct { const char* enum_name; const char* variant_name;
AstNode* payload; // payload 表达式 (NULL=无 payload)
int variant_index; } enum_variant;
// AST_INDEX_EXPR // AST_INDEX_EXPR
struct { struct AstNode* array; struct AstNode* index; } index_expr; struct { struct AstNode* array; struct AstNode* index; } index_expr;
// AST_ARRAY_ASSIGN_STMT // AST_ARRAY_ASSIGN_STMT
@@ -150,8 +155,11 @@ AstNode* ast_make_struct_init(void* alloc, const char* type_name, const char** f
AstNode* ast_make_field_access(void* alloc, AstNode* object, const char* field, SourceLoc loc); AstNode* ast_make_field_access(void* alloc, AstNode* object, const char* field, SourceLoc loc);
AstNode* ast_make_type_alias(void* alloc, const char* name, TypeKind aliased, AstNode* ast_make_type_alias(void* alloc, const char* name, TypeKind aliased,
const char* aliased_struct, SourceLoc loc); const char* aliased_struct, SourceLoc loc);
AstNode* ast_make_enum_decl(void* alloc, const char* name, const char** variants, size_t count, SourceLoc loc); AstNode* ast_make_enum_decl(void* alloc, const char* name, const char** variants,
AstNode* ast_make_enum_variant(void* alloc, const char* enum_name, const char* variant_name, SourceLoc loc); TypeKind* payload_types, const char** payload_struct_names,
size_t count, SourceLoc loc);
AstNode* ast_make_enum_variant(void* alloc, const char* enum_name, const char* variant_name,
AstNode* payload, SourceLoc loc);
AstNode* ast_make_index_expr(void* alloc, AstNode* array, AstNode* index, SourceLoc loc); AstNode* ast_make_index_expr(void* alloc, AstNode* array, AstNode* index, SourceLoc loc);
AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc); AstNode* ast_make_array_assign(void* alloc, const char* name, AstNode* index, AstNode* value, SourceLoc loc);
AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc); AstNode* ast_make_impl_block(void* alloc, const char* struct_name, AstNode** methods, size_t count, SourceLoc loc);
+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_CHAR: return LLVMInt8TypeInContext(ctx->context);
case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0); case TYPE_STR: return LLVMPointerType(LLVMInt8TypeInContext(ctx->context), 0);
case TYPE_STRUCT: 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_UNKNOWN:
case TYPE_ERROR: case TYPE_ERROR:
default: return LLVMVoidTypeInContext(ctx->context); default: return LLVMVoidTypeInContext(ctx->context);
@@ -159,8 +164,11 @@ static LLVMTypeRef type_info_to_llvm(CgCtx* ctx, const TypeInfo* ti) {
if (st) return st; if (st) return st;
} }
return LLVMVoidTypeInContext(ctx->context); return LLVMVoidTypeInContext(ctx->context);
case TYPE_ENUM: case TYPE_ENUM: {
return LLVMInt64TypeInContext(ctx->context); LLVMTypeRef f[] = { LLVMInt64TypeInContext(ctx->context),
LLVMInt64TypeInContext(ctx->context) };
return LLVMStructTypeInContext(ctx->context, f, 2, false);
}
default: default:
return to_llvm_type(ctx, ti->kind); return to_llvm_type(ctx, ti->kind);
} }
@@ -258,23 +266,36 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
case OP_MOD: case OP_MOD:
return LLVMBuildSRem(ctx->builder, l, r, "srem"); return LLVMBuildSRem(ctx->builder, l, r, "srem");
case OP_EQ: case OP_EQ:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOEQ, l, r, "feq")
: LLVMBuildICmp(ctx->builder, LLVMIntEQ, l, r, "ieq");
case OP_NE: case OP_NE:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealONE, l, r, "fne")
: LLVMBuildICmp(ctx->builder, LLVMIntNE, l, r, "ine");
case OP_LT: case OP_LT:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOLT, l, r, "flt")
: LLVMBuildICmp(ctx->builder, LLVMIntSLT, l, r, "ilt");
case OP_GT: case OP_GT:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOGT, l, r, "fgt")
: LLVMBuildICmp(ctx->builder, LLVMIntSGT, l, r, "igt");
case OP_LE: case OP_LE:
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOLE, l, r, "fle") case OP_GE: {
: LLVMBuildICmp(ctx->builder, LLVMIntSLE, l, r, "ile"); // 枚举比较: 提取 tag 字段再比较
case OP_GE: LLVMValueRef cl = l, cr = r;
return is_float ? LLVMBuildFCmp(ctx->builder, LLVMRealOGE, l, r, "fge") if (node->as.binary.left->type.kind == TYPE_ENUM) {
: LLVMBuildICmp(ctx->builder, LLVMIntSGE, l, r, "ige"); 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: case OP_AND:
return LLVMBuildAnd(ctx->builder, l, r, "and"); return LLVMBuildAnd(ctx->builder, l, r, "and");
case OP_OR: case OP_OR:
@@ -289,6 +310,9 @@ static LLVMValueRef codegen_expr(CgCtx* ctx, AstNode* node) {
if (strcmp(node->as.call.name, "print_i64") == 0) { if (strcmp(node->as.call.name, "print_i64") == 0) {
LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]); LLVMValueRef arg = codegen_expr(ctx, node->as.call.args[0]);
if (!arg) return NULL; 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); LLVMTypeRef i64_ty = LLVMInt64TypeInContext(ctx->context);
arg = coerce_int(ctx, arg, LLVMTypeOf(arg), i64_ty); arg = coerce_int(ctx, arg, LLVMTypeOf(arg), i64_ty);
LLVMValueRef fmt = LLVMBuildGlobalStringPtr(ctx->builder, "%lld\n", "fmt_i64"); 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"); return LLVMBuildLoad2(ctx->builder, struct_ty, alloca, "struct_val");
} }
case AST_ENUM_VARIANT: case AST_ENUM_VARIANT: {
return LLVMConstInt(LLVMInt64TypeInContext(ctx->context), // tagged union: { tag, payload }
LLVMValueRef tag = LLVMConstInt(LLVMInt64TypeInContext(ctx->context),
(unsigned long long)node->as.enum_variant.variant_index, true); (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: { case AST_METHOD_CALL: {
const char* struct_name = node->as.method_call.receiver->type.struct_name; const char* struct_name = node->as.method_call.receiver->type.struct_name;
+32 -5
View File
@@ -187,15 +187,21 @@ static AstNode* parse_struct_init(Parser* p, const Token* name, ErrorInfo* error
static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) { static AstNode* parse_ident_or_call(Parser* p, ErrorInfo* error) {
const Token* name = advance(p); const Token* name = advance(p);
// 枚举变体引用: Name::Variant // 枚举变体引用: Name::Variant 或 Name::Variant(payload)
if (peek(p)->kind == TOK_COLON_COLON) { if (peek(p)->kind == TOK_COLON_COLON) {
advance(p); // 跳过 :: advance(p); // 跳过 ::
const Token* variant = expect(p, TOK_IDENT, error, "枚举变体名"); const Token* variant = expect(p, TOK_IDENT, error, "枚举变体名");
if (!variant) return NULL; if (!variant) return NULL;
AstNode* payload = NULL;
if (match(p, TOK_LPAREN)) {
payload = parse_expr(p, error);
if (!payload) return NULL;
if (!expect(p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
}
return ast_make_enum_variant(p->arena, return ast_make_enum_variant(p->arena,
arena_strdup_impl(p->arena, name->start, name->length), arena_strdup_impl(p->arena, name->start, name->length),
arena_strdup_impl(p->arena, variant->start, variant->length), arena_strdup_impl(p->arena, variant->start, variant->length),
tok_loc(name)); payload, tok_loc(name));
} }
// 结构体初始化: Name { field: val, ... } // 结构体初始化: Name { field: val, ... }
@@ -898,18 +904,39 @@ AstNode* parse(Arena* a, const Token* tokens, size_t count,
const Token* name = expect(&p, TOK_IDENT, error, "enum 后应为枚举名"); const Token* name = expect(&p, TOK_IDENT, error, "enum 后应为枚举名");
if (!name) return NULL; if (!name) return NULL;
if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL; if (!expect(&p, TOK_LBRACE, error, "缺少 '{'")) return NULL;
const char* variants[64]; int vcount = 0; const char* variants[64];
TypeKind payload_types[64];
const char* payload_snames[64];
int vcount = 0;
while (peek(&p)->kind != TOK_RBRACE && !error->message) { while (peek(&p)->kind != TOK_RBRACE && !error->message) {
if (vcount >= 64) { error->message = "枚举变体过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } if (vcount >= 64) { error->message = "枚举变体过多(最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
const Token* vname = expect(&p, TOK_IDENT, error, "变体名"); const Token* vname = expect(&p, TOK_IDENT, error, "变体名");
if (!vname) return NULL; if (!vname) return NULL;
variants[vcount++] = arena_strdup_impl(p.arena, vname->start, vname->length); variants[vcount] = arena_strdup_impl(p.arena, vname->start, vname->length);
payload_types[vcount] = TYPE_VOID;
payload_snames[vcount] = NULL;
// 可选 payload: Variant(Type)
if (peek(&p)->kind == TOK_LPAREN) {
advance(&p);
TypeInfo pti = parse_type_expr(&p, error);
if (pti.kind == TYPE_ERROR) return NULL;
payload_types[vcount] = pti.kind;
payload_snames[vcount] = pti.struct_name;
if (!expect(&p, TOK_RPAREN, error, "缺少 ')'")) return NULL;
}
vcount++;
if (peek(&p)->kind == TOK_COMMA) advance(&p); else break; if (peek(&p)->kind == TOK_COMMA) advance(&p); else break;
} }
if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL; if (!expect(&p, TOK_RBRACE, error, "缺少 '}'")) return NULL;
const char** v_arr = arena_alloc_impl(p.arena, vcount * sizeof(const char*)); const char** v_arr = arena_alloc_impl(p.arena, vcount * sizeof(const char*));
memcpy(v_arr, variants, vcount * sizeof(const char*)); memcpy(v_arr, variants, vcount * sizeof(const char*));
AstNode* enum_decl = ast_make_enum_decl(p.arena, arena_strdup_impl(p.arena, name->start, name->length), v_arr, vcount, tok_loc(name)); TypeKind* pt_arr = arena_alloc_impl(p.arena, vcount * sizeof(TypeKind));
memcpy(pt_arr, payload_types, vcount * sizeof(TypeKind));
const char** ps_arr = arena_alloc_impl(p.arena, vcount * sizeof(const char*));
memcpy(ps_arr, payload_snames, vcount * sizeof(const char*));
AstNode* enum_decl = ast_make_enum_decl(p.arena,
arena_strdup_impl(p.arena, name->start, name->length),
v_arr, pt_arr, ps_arr, vcount, tok_loc(name));
if (enum_count >= 64) { error->message = "枚举过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; } if (enum_count >= 64) { error->message = "枚举过多 (最多64)"; error->filename = p.filename; error->line = peek(&p)->line; error->col = peek(&p)->col; return NULL; }
enums[enum_count++] = enum_decl; enums[enum_count++] = enum_decl;
} else if (peek(&p)->kind == TOK_EXTEND) { } else if (peek(&p)->kind == TOK_EXTEND) {
+26
View File
@@ -346,6 +346,30 @@ static void analyze_enum_variant(AstNode* node, Scope* scope, ErrorList* errors,
node->type.kind = TYPE_ERROR; return; node->type.kind = TYPE_ERROR; return;
} }
node->as.enum_variant.variant_index = vi; node->as.enum_variant.variant_index = vi;
// ADT: 检查 payload
TypeKind expected_pt = TYPE_VOID;
if (enum_sym->variant_payload_types)
expected_pt = enum_sym->variant_payload_types[vi];
if (node->as.enum_variant.payload) {
if (expected_pt == TYPE_VOID && enum_sym->variant_payload_types) {
error_add(errors, "<sema>", node->loc.line, node->loc.col,
"枚举变体 '%s::%s' 不接受 payload",
node->as.enum_variant.enum_name, node->as.enum_variant.variant_name);
node->type.kind = TYPE_ERROR; return;
}
analyze_expr(node->as.enum_variant.payload, scope, errors, a);
TypeKind actual = node->as.enum_variant.payload->type.kind;
if (actual != TYPE_ERROR && actual != expected_pt) {
error_add(errors, "<sema>", node->loc.line, node->loc.col,
"枚举变体 payload 类型不匹配: 期望 '%s',得到 '%s'",
type_name(expected_pt), type_name(actual));
}
} else if (expected_pt != TYPE_VOID) {
error_add(errors, "<sema>", node->loc.line, node->loc.col,
"枚举变体 '%s::%s' 需要 payload 类型 '%s'",
node->as.enum_variant.enum_name, node->as.enum_variant.variant_name,
type_name(expected_pt));
}
node->type.kind = TYPE_ENUM; node->type.kind = TYPE_ENUM;
} }
@@ -451,6 +475,8 @@ static void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena*
AstNode* ed = node->as.program.enums[i]; AstNode* ed = node->as.program.enums[i];
scope_insert_enum(scope, a, ed->as.enum_decl.name, scope_insert_enum(scope, a, ed->as.enum_decl.name,
ed->as.enum_decl.variants, ed->as.enum_decl.variants,
ed->as.enum_decl.variant_payload_types,
ed->as.enum_decl.variant_payload_struct_names,
ed->as.enum_decl.variant_count); ed->as.enum_decl.variant_count);
} }
// 第一遍:收集所有结构体定义 // 第一遍:收集所有结构体定义
+10 -1
View File
@@ -35,6 +35,8 @@ Symbol* scope_insert(Scope* scope, void* alloc, const char* name,
sym->struct_field_types = NULL; sym->struct_field_types = NULL;
sym->struct_field_count = 0; sym->struct_field_count = 0;
sym->struct_type_name = NULL; sym->struct_type_name = NULL;
sym->variant_payload_types = NULL;
sym->variant_payload_struct_names = NULL;
sym->array_element_type = 0; sym->array_element_type = 0;
sym->array_element_struct_name = NULL; sym->array_element_struct_name = NULL;
sym->array_size = 0; sym->array_size = 0;
@@ -66,6 +68,8 @@ Symbol* scope_insert_function(Scope* scope, void* alloc, const char* name,
sym->struct_field_types = NULL; sym->struct_field_types = NULL;
sym->struct_field_count = 0; sym->struct_field_count = 0;
sym->struct_type_name = NULL; sym->struct_type_name = NULL;
sym->variant_payload_types = NULL;
sym->variant_payload_struct_names = NULL;
sym->array_element_type = 0; sym->array_element_type = 0;
sym->array_element_struct_name = NULL; sym->array_element_struct_name = NULL;
sym->array_size = 0; sym->array_size = 0;
@@ -93,6 +97,8 @@ Symbol* scope_insert_struct(Scope* scope, void* alloc, const char* name,
sym->struct_field_struct_names = fstruct_names; sym->struct_field_struct_names = fstruct_names;
sym->struct_field_count = fc; sym->struct_field_count = fc;
sym->struct_type_name = NULL; sym->struct_type_name = NULL;
sym->variant_payload_types = NULL;
sym->variant_payload_struct_names = NULL;
sym->array_element_type = 0; sym->array_element_type = 0;
sym->array_element_struct_name = NULL; sym->array_element_struct_name = NULL;
sym->array_size = 0; sym->array_size = 0;
@@ -122,7 +128,8 @@ int scope_struct_field_index(const Symbol* sym, const char* field_name) {
} }
Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name,
const char** vnames, size_t vc) { const char** vnames, TypeKind* ptypes,
const char** pstruct_names, size_t vc) {
if (scope->head) { if (scope->head) {
for (Symbol* sym = scope->head; sym; sym = sym->next) { for (Symbol* sym = scope->head; sym; sym = sym->next) {
if (strcmp(sym->name, name) == 0) return NULL; if (strcmp(sym->name, name) == 0) return NULL;
@@ -138,6 +145,8 @@ Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name,
sym->struct_field_struct_names = NULL; sym->struct_field_struct_names = NULL;
sym->struct_field_count = vc; sym->struct_field_count = vc;
sym->struct_type_name = NULL; sym->struct_type_name = NULL;
sym->variant_payload_types = ptypes;
sym->variant_payload_struct_names = pstruct_names;
sym->array_element_type = 0; sym->array_element_type = 0;
sym->array_element_struct_name = NULL; sym->array_element_struct_name = NULL;
sym->array_size = 0; sym->array_size = 0;
+5 -1
View File
@@ -29,6 +29,9 @@ typedef struct Symbol {
TypeKind array_element_type; TypeKind array_element_type;
const char* array_element_struct_name; const char* array_element_struct_name;
int64_t array_size; int64_t array_size;
// 枚举特有(ADT payload
TypeKind* variant_payload_types;
const char** variant_payload_struct_names;
// 类型别名标记 // 类型别名标记
bool is_type_alias; bool is_type_alias;
// 链表(同一作用域内的下一个符号) // 链表(同一作用域内的下一个符号)
@@ -69,7 +72,8 @@ int scope_struct_field_index(const Symbol* sym, const char* field_name);
// 插入枚举符号 // 插入枚举符号
Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name, Symbol* scope_insert_enum(Scope* scope, void* alloc, const char* name,
const char** vnames, size_t vc); const char** vnames, TypeKind* ptypes,
const char** pstruct_names, size_t vc);
// 在枚举符号中查找变体索引(返回 -1 表示未找到) // 在枚举符号中查找变体索引(返回 -1 表示未找到)
int scope_enum_variant_index(const Symbol* sym, const char* variant_name); int scope_enum_variant_index(const Symbol* sym, const char* variant_name);
+17
View File
@@ -0,0 +1,17 @@
enum Option { Some(i64), None }
fn main() -> i64 {
let s = Option::Some(42);
let n = Option::None;
// 打印 tag 值 (Some=0, None=1)
print_i64(s);
print_i64(n);
// match 判断是 Some 还是 None(只比较 tag
match s {
Option::None => { print_i64(999); }
_ => { print_i64(100); }
}
return 0;
}
+6 -6
View File
@@ -243,11 +243,11 @@ void test_codegen_enum() {
/* 构造 AST: enum Color { Red, Green, Blue } /* 构造 AST: enum Color { Red, Green, Blue }
fn main() -> i64 { let c = Color::Green; print_i64(c); return 0; } */ fn main() -> i64 { let c = Color::Green; print_i64(c); return 0; } */
const char* cvariants[] = {"Red", "Green", "Blue"}; const char* cvariants[] = {"Red", "Green", "Blue"};
AstNode* enum_decl = ast_make_enum_decl(&a, "Color", cvariants, 3, loc_at(1, 1)); AstNode* enum_decl = ast_make_enum_decl(&a, "Color", cvariants, NULL, NULL, 3, loc_at(1, 1));
AstNode* enums[] = { enum_decl }; AstNode* enums[] = { enum_decl };
/* let c = Color::Green; */ /* let c = Color::Green; */
AstNode* cv = ast_make_enum_variant(&a, "Color", "Green", loc_at(1, 1)); AstNode* cv = ast_make_enum_variant(&a, "Color", "Green", NULL, loc_at(1, 1));
cv->as.enum_variant.variant_index = 1; /* Green = index 1 */ cv->as.enum_variant.variant_index = 1; /* Green = index 1 */
cv->type.kind = TYPE_ENUM; cv->type.kind = TYPE_ENUM;
@@ -426,7 +426,7 @@ void test_codegen_match() {
/* enum Color { Red, Green, Blue } */ /* enum Color { Red, Green, Blue } */
const char* variants[] = {"Red", "Green", "Blue"}; const char* variants[] = {"Red", "Green", "Blue"};
AstNode* enum_decl = ast_make_enum_decl(&a, "Color", variants, 3, loc_at(1, 1)); AstNode* enum_decl = ast_make_enum_decl(&a, "Color", variants, NULL, NULL, 3, loc_at(1, 1));
AstNode* enums[] = { enum_decl }; AstNode* enums[] = { enum_decl };
/* fn main() -> i64 { /* fn main() -> i64 {
@@ -445,7 +445,7 @@ void test_codegen_match() {
else { return 0; } else { return 0; }
} }
*/ */
AstNode* match_val = ast_make_enum_variant(&a, "Color", "Green", loc_at(1, 1)); AstNode* match_val = ast_make_enum_variant(&a, "Color", "Green", NULL, loc_at(1, 1));
match_val->type.kind = TYPE_ENUM; match_val->type.kind = TYPE_ENUM;
AstNode* let_stmt = ast_make_let(&a, "__match_val", TYPE_UNKNOWN, false, false, AstNode* let_stmt = ast_make_let(&a, "__match_val", TYPE_UNKNOWN, false, false,
@@ -456,7 +456,7 @@ void test_codegen_match() {
match_ident->type.kind = TYPE_ENUM; match_ident->type.kind = TYPE_ENUM;
// if __match_val == Color::Red { return 1; } // if __match_val == Color::Red { return 1; }
AstNode* red_variant = ast_make_enum_variant(&a, "Color", "Red", loc_at(1, 1)); AstNode* red_variant = ast_make_enum_variant(&a, "Color", "Red", NULL, loc_at(1, 1));
red_variant->type.kind = TYPE_ENUM; red_variant->type.kind = TYPE_ENUM;
AstNode* red_cond = ast_make_binary(&a, OP_EQ, match_ident, red_variant, loc_at(1, 1)); AstNode* red_cond = ast_make_binary(&a, OP_EQ, match_ident, red_variant, loc_at(1, 1));
red_cond->type.kind = TYPE_BOOL; red_cond->type.kind = TYPE_BOOL;
@@ -467,7 +467,7 @@ void test_codegen_match() {
// if __match_val == Color::Green { return 2; } // if __match_val == Color::Green { return 2; }
AstNode* match_ident2 = ast_make_ident(&a, "__match_val", loc_at(1, 1)); AstNode* match_ident2 = ast_make_ident(&a, "__match_val", loc_at(1, 1));
match_ident2->type.kind = TYPE_ENUM; match_ident2->type.kind = TYPE_ENUM;
AstNode* green_variant = ast_make_enum_variant(&a, "Color", "Green", loc_at(1, 1)); AstNode* green_variant = ast_make_enum_variant(&a, "Color", "Green", NULL, loc_at(1, 1));
green_variant->type.kind = TYPE_ENUM; green_variant->type.kind = TYPE_ENUM;
AstNode* green_cond = ast_make_binary(&a, OP_EQ, match_ident2, green_variant, loc_at(1, 1)); AstNode* green_cond = ast_make_binary(&a, OP_EQ, match_ident2, green_variant, loc_at(1, 1));
green_cond->type.kind = TYPE_BOOL; green_cond->type.kind = TYPE_BOOL;