diff --git a/stage1/spl_ast.c b/stage1/spl_ast.c index 01f01dc..948c77f 100644 --- a/stage1/spl_ast.c +++ b/stage1/spl_ast.c @@ -279,11 +279,14 @@ static int can_start_statement(spl_tok_type_t t) { } } -static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_external) { +static void parse_tag_list(parser_t *p, spl_ast_node_ref_vec_t *out, int is_external, + int allow_at) { while (!p->failed) { const spl_tok_t *t = peek(p); if (!t || (t->type != TOK_AT && t->type != TOK_SHARP)) return; + if (!allow_at && t->type == TOK_AT) + return; int is_at = (t->type == TOK_AT); advance(p); @@ -370,7 +373,7 @@ static void parse_param_list(parser_t *p, spl_ast_node_ref_vec_t *out) { static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { spl_ast_node_ref_vec_t attr_list; vec_init(attr_list); - parse_tag_list(p, &attr_list, 0); + parse_tag_list(p, &attr_list, 0, 1); const spl_tok_t *name = peek(p); if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) { @@ -386,11 +389,13 @@ static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) { } advance(p); + parse_tag_list(p, &attr_list, 0, 0); + spl_ast_node_ref_t type_expr = parse_type_expr(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name); spl_ast_node_t *param = node_at(p->ast, ref); MOVE_VEC(param->param_decl.attr_list, attr_list); - SET_STR_FIELD(p->ast, param->param_decl.name, name); // 若为下划线则存储 "_" + SET_STR_FIELD(p->ast, param->param_decl.name, name); param->param_decl.type_expr = type_expr; return ref; } @@ -545,6 +550,7 @@ static spl_ast_node_ref_t parse_member_decl(parser_t *p, spl_ast_node_ref_vec_t const spl_tok_t *t = peek(p); if (t && t->type == TOK_COLON) { advance(p); + parse_tag_list(p, &tag_list, 0, 0); type_expr = parse_type_expr(p); t = peek(p); if (t && t->type == TOK_ASSIGN) { @@ -592,7 +598,7 @@ static spl_ast_node_ref_t parse_comptime_decl(parser_t *p) { static spl_ast_node_ref_t parse_container_declaration(parser_t *p) { spl_ast_node_ref_vec_t tag_list; vec_init(tag_list); - parse_tag_list(p, &tag_list, 0); /* 只解析普通 tag */ + parse_tag_list(p, &tag_list, 0, 0); /* 只解析普通 tag */ const spl_tok_t *t = peek(p); if (!t || t->type == TOK_EOF) { @@ -738,20 +744,14 @@ static spl_ast_node_ref_t parse_match_pattern(parser_t *p) { } static spl_ast_node_ref_t parse_type_base(parser_t *p) { - spl_ast_node_ref_vec_t tag_list; - vec_init(tag_list); - parse_tag_list(p, &tag_list, 0); - const spl_tok_t *bt = peek(p); if (!bt) { - vec_free(tag_list); SPL_FATAL(bt, "expected type"); return 0; } /* 函数类型 */ if (bt->type == KW_FN) { - vec_free(tag_list); advance(p); const spl_tok_t *t = peek(p); if (!t || t->type != TOK_L_PAREN) { @@ -794,7 +794,6 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { /* 聚合类型:struct / union / enum / shape */ if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM || bt->type == KW_SHAPE) { - vec_free(tag_list); /* 聚合类型不使用 tag_list */ const char *kind_name = (bt->type == KW_STRUCT) ? "struct" : (bt->type == KW_UNION) ? "union" : (bt->type == KW_ENUM) ? "enum" @@ -865,7 +864,6 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); - vec_free(tag_list); return ref; } @@ -885,12 +883,10 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { } advance(p); } - vec_free(tag_list); return ref; } if (bt->type == TOK_AT || bt->type == TOK_SHARP) { - vec_free(tag_list); return parse_type_comptime_call(p); } @@ -900,11 +896,9 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) { spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); - vec_free(tag_list); return ref; } - vec_free(tag_list); SPL_FATAL(bt, "unrecognized type"); return 0; } @@ -917,26 +911,26 @@ static spl_ast_node_ref_t parse_type_comptime_call(parser_t *p) { const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected comptime call name"); + SPL_FATAL(name, "expected comptime name"); return 0; } advance(p); + spl_ast_node_ref_vec_t args; + vec_init(args); + const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_PAREN) { - SPL_FATAL(t, "expected '(' in comptime call"); - return 0; + if (t && t->type == TOK_L_PAREN) { + advance(p); + args = parse_expr_list(p); + t = peek(p); + if (!t || t->type != TOK_R_PAREN) { + SPL_FATAL(t, "expected ')' in comptime type"); + vec_free(args); + return 0; + } + advance(p); } - advance(p); - - spl_ast_node_ref_vec_t args = parse_expr_list(p); - - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in comptime call"); - return 0; - } - advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_COMPTIME_CALL, start); spl_ast_node_t *cc = node_at(p->ast, ref); @@ -1606,31 +1600,34 @@ static spl_ast_node_ref_t parse_comptime_call(parser_t *p) { const spl_tok_t *name = peek(p); if (!name || name->type != TOK_IDENT) { - SPL_FATAL(name, "expected comptime call name"); + SPL_FATAL(name, "expected comptime name"); return 0; } advance(p); + spl_ast_node_ref_vec_t args; + vec_init(args); + int has_paren = 0; + const spl_tok_t *t = peek(p); - if (!t || t->type != TOK_L_PAREN) { - SPL_FATAL(t, "expected '(' in comptime call"); - return 0; + if (t && t->type == TOK_L_PAREN) { + has_paren = 1; + advance(p); + args = parse_expr_list(p); + t = peek(p); + if (!t || t->type != TOK_R_PAREN) { + SPL_FATAL(t, "expected ')' in comptime call"); + vec_free(args); + return 0; + } + advance(p); } - advance(p); - - spl_ast_node_ref_vec_t args = parse_expr_list(p); - - t = peek(p); - if (!t || t->type != TOK_R_PAREN) { - SPL_FATAL(t, "expected ')' in comptime call"); - return 0; - } - advance(p); spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_COMPTIME_CALL, start); spl_ast_node_t *cc = node_at(p->ast, ref); SET_STR_FIELD(p->ast, cc->comptime_call.name, name); cc->comptime_call.args = args; + (void)has_paren; return ref; } @@ -2082,7 +2079,7 @@ static spl_ast_node_ref_t parse_statement(parser_t *p) { case KW_TYPE: { spl_ast_node_ref_vec_t tag_list; vec_init(tag_list); - parse_tag_list(p, &tag_list, 0); // 解析声明前的普通 tag + parse_tag_list(p, &tag_list, 0, 0); // 解析声明前的普通 tag spl_ast_node_ref_t decl; if (t->type == KW_VAR) @@ -2214,7 +2211,7 @@ void spl_ast_parse(spl_ast_t *ast) { p.pos = save_pos; } if (t2 && t2->type == TOK_NOT) { - parse_tag_list(&p, &external_tags, 1); + parse_tag_list(&p, &external_tags, 1, 1); continue; } } diff --git a/stage1/spl_ast2ir.c b/stage1/spl_ast2ir.c index 17663ec..f04984b 100644 --- a/stage1/spl_ast2ir.c +++ b/stage1/spl_ast2ir.c @@ -255,6 +255,10 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { if (!spl_type_agg_member_idx(a->sema->type, agg_ir, n->field.field, &idx)) return 0; + spl_lang_type_node_t *agg_ln = spl_lang_type_node(a->sema->type, agg_lang); + if (agg_ln && agg_ln->kind == SPL_LANG_TYPE_ENUM) + idx += 1; + return spl_ir_builder_mem_field(a->ir, agg_ir, base, idx); } case SPL_AST_EXPR_INDEX: { @@ -584,6 +588,18 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) if (in != SPL_INTRIN_NONE) return ast2ir_intrin_field(a, n, in); } + + if (n->resolved_def_id) { + spl_def_node_t *fd = spl_def_node(a->sema->type, n->resolved_def_id); + if (fd && fd->kind == SPL_DEF_FN) { + spl_ir_node_ref_t fn_ref = 0; + if (!map_get(a->def2ir_map, n->resolved_def_id, &fn_ref)) + return 0; + return spl_ir_builder_type_const_fn(a->ir, node_ir(a, n), + (spl_ir_func_ref_t)fn_ref); + } + } + spl_ir_node_ref_t ptr = emit_lvalue(a, ref); if (!ptr) return 0; @@ -654,9 +670,40 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) spl_type_node_t *tn = spl_type_node(a->sema->type, t); if (!tn) Panic("aggregate type node missing"); + + if (tn->kind == SPL_TYPE_ENUM) { + if (vec_size(n->aggregate_literal.fields) != 1) + Panic("enum literal must have exactly one variant"); + spl_ast_node_t *item = + spl_ast_node(a->sema->ast, vec_at(n->aggregate_literal.fields, 0)); + if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) + Panic("invalid enum literal"); + + usize vidx = 0; + if (!spl_type_agg_member_idx(a->sema->type, t, item->struct_init_item.name, &vidx)) + Panic("enum variant `%s` not found (sema should have caught this)", + item->struct_init_item.name); + + spl_ir_node_ref_t eptr = spl_ir_builder_mem_alloca(a->ir, t, const_usize(a, 1)); + + spl_type_id_t tag_ir = tn->agg_type.tag_type; + spl_ir_node_ref_t tptr = + spl_ir_builder_mem_field(a->ir, t, eptr, SPL_ENUM_TAG_FIELD_IDX); + spl_ir_node_ref_t tag_val = spl_ir_builder_type_const_int(a->ir, tag_ir, vidx); + spl_ir_builder_mem_store(a->ir, tag_ir, tptr, tag_val); + + spl_type_id_t ftid = vec_at(tn->agg_type.variants, vidx).type_id; + spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, t, eptr, vidx + 1); + spl_ir_node_ref_t payload = emit_expr(a, item->struct_init_item.expr); + if (!payload) + Panic("enum payload emit failed"); + spl_ir_builder_mem_store(a->ir, ftid, pptr, payload); + + return eptr; + } + usize nfields = vec_size(tn->agg_type.variants); - /* 按字段名定位到 index,缺省值填 0(sema 已保证无缺省) */ spl_ir_node_ref_vec_t fields; vec_init(fields); for (usize i = 0; i < nfields; ++i) @@ -694,9 +741,11 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref) Panic("agg_construct failed for aggregate literal"); for (usize i = 0; i < nfields; ++i) { - spl_ir_builder_agg_construct_field(a->ir, node, vec_at(fields, i)); + spl_ir_node_ref_t f = vec_at(fields, i); + if (!f) + Panic("aggregate field #%zu missing (sema should have caught this)", i); + spl_ir_builder_agg_construct_field(a->ir, node, f); } - vec_free(fields); return node; } @@ -1131,6 +1180,21 @@ static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n) { spl_ir_builder_fn_end(a->ir); } +static void emit_aggregate_fns(spl_ast2ir_t *a, spl_ast_node_t *te) { + for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { + spl_ast_node_t *mn = spl_ast_node(a->sema->ast, vec_at(te->type_aggregate.members, i)); + if (!mn) + continue; + if (mn->kind == SPL_AST_FN_DECL) { + emit_fn(a, mn); + } else if (mn->kind == SPL_AST_MEMBER_DECL && mn->member_decl.type_expr) { + spl_ast_node_t *mt = spl_ast_node(a->sema->ast, mn->member_decl.type_expr); + if (mt && mt->kind == SPL_AST_TYPE_AGGREGATE) + emit_aggregate_fns(a, mt); + } + } +} + static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref); if (!n) @@ -1152,6 +1216,12 @@ static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { case SPL_AST_FN_DECL: emit_fn(a, d); break; + case SPL_AST_TYPE_DECL: { + spl_ast_node_t *te = spl_ast_node(a->sema->ast, d->type_decl.type_expr); + if (te && te->kind == SPL_AST_TYPE_AGGREGATE) + emit_aggregate_fns(a, te); + break; + } case SPL_AST_TOP_LEVEL_BLOCK: emit_container(a, dref); break; diff --git a/stage1/spl_ir.c b/stage1/spl_ir.c index 555e00a..95f95f7 100644 --- a/stage1/spl_ir.c +++ b/stage1/spl_ir.c @@ -11,8 +11,6 @@ const char *spl_ir_kind_name(spl_ir_kind_t kind) { return "?"; } -#define SPL_ENUM_TAG_FIELD_IDX 0 - void spl_ir_init(spl_ir_t *ir) { vec_init(ir->funcs); vec_push(ir->funcs, (spl_ir_func_t){0}); diff --git a/stage1/spl_ir.h b/stage1/spl_ir.h index e052c3e..0203a11 100644 --- a/stage1/spl_ir.h +++ b/stage1/spl_ir.h @@ -82,6 +82,8 @@ typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t; typedef usize spl_ir_func_ref_t; /* 0 is error */ +#define SPL_ENUM_TAG_FIELD_IDX 0 + typedef struct { spl_ir_kind_t kind; spl_dbg_node_t dbg; diff --git a/stage1/spl_ir2vm.c b/stage1/spl_ir2vm.c index bd6ed83..1db3504 100644 --- a/stage1/spl_ir2vm.c +++ b/stage1/spl_ir2vm.c @@ -1,6 +1,8 @@ #include "spl_ir2vm.h" #include "spl_layout.h" +static usize align_up(usize x, usize a); + static usize ir_type_size(spl_ir2vm_t *ctx, spl_type_id_t tid) { spl_type_node_t *tn = spl_type_node(ctx->type, tid); if (!tn) @@ -20,6 +22,16 @@ static usize ir_type_size(spl_ir2vm_t *ctx, spl_type_id_t tid) { return sizeof(void *); case SPL_TYPE_ARRAY: return ir_type_size(ctx, tn->array_type.element) * tn->array_type.len; + case SPL_TYPE_ENUM: { + usize tag_sz = ir_type_size(ctx, tn->agg_type.tag_type); + usize max_payload = 0; + for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) { + usize vs = ir_type_size(ctx, vec_at(tn->agg_type.variants, i).type_id); + if (vs > max_payload) + max_payload = vs; + } + return align_up(tag_sz, 8) + max_payload; + } case SPL_TYPE_STRUCT: case SPL_TYPE_UNION: { usize s = 0; @@ -44,6 +56,14 @@ static spl_type_id_t ir_agg_field_tid(spl_ir2vm_t *ctx, spl_type_id_t tid, usize spl_type_node_t *tn = spl_type_node(ctx->type, tid); if (!tn) return 0; + if (tn->kind == SPL_TYPE_ENUM) { + if (idx == SPL_ENUM_TAG_FIELD_IDX) + return tn->agg_type.tag_type; + usize vidx = idx - 1; + if (vidx < vec_size(tn->agg_type.variants)) + return vec_at(tn->agg_type.variants, vidx).type_id; + return 0; + } if (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_UNION) { if (idx < vec_size(tn->agg_type.variants)) return vec_at(tn->agg_type.variants, idx).type_id; diff --git a/stage1/spl_layout.c b/stage1/spl_layout.c index 9acd7e9..7868eb3 100644 --- a/stage1/spl_layout.c +++ b/stage1/spl_layout.c @@ -130,6 +130,39 @@ static usize round_up_bits(usize x, usize align_bits) { static bool layout_agg(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) { usize n = vec_size(tn->agg_type.variants); + + if (tn->kind == SPL_TYPE_ENUM) { + spl_type_id_t tag_tid = tn->agg_type.tag_type; + if (!tag_tid) + return false; + spl_layout_info_t *tag_info = infos_at(layout, tag_tid); + if (!tag_info || !tag_info->resolved) + return false; + + usize tag_align_bits = tag_info->align_bits ? tag_info->align_bits : 8; + usize payload_align_bits = 8; + usize payload_size_bits = 0; + + for (usize i = 0; i < n; ++i) { + spl_type_member_t *m = &vec_at(tn->agg_type.variants, i); + spl_layout_info_t *fi = infos_at(layout, m->type_id); + if (!fi || !fi->resolved) + return false; + usize fa = fi->align_bits ? fi->align_bits : 8; + if (fa > payload_align_bits) + payload_align_bits = fa; + if (fi->size_bits > payload_size_bits) + payload_size_bits = fi->size_bits; + } + + usize payload_off = round_up_bits(tag_info->size_bits, payload_align_bits); + usize final_align_bits = + tag_align_bits > payload_align_bits ? tag_align_bits : payload_align_bits; + out->size_bits = round_up_bits(payload_off + payload_size_bits, final_align_bits); + out->align_bits = final_align_bits; + return true; + } + if (n == 0) { out->size_bits = 0; out->align_bits = 8; @@ -163,7 +196,6 @@ static bool layout_agg(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_inf max_align_bits = field_align_bits; } - /* 聚合对齐策略 */ usize final_align_bits = max_align_bits; if (layout->aggregate.align_rule == ALIGN_FIXED) { final_align_bits = layout->aggregate.fixed_align * 8; diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index 83a5578..49fbf82 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -200,6 +200,85 @@ static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_ } } +static spl_lang_type_id_t sema_build_aggregate(spl_sema_t *sema, spl_ast_node_t *te) { + spl_type_member_vec_t members; + vec_init(members); + spl_lang_method_vec_t methods; + vec_init(methods); + spl_ast_node_ref_vec_t fn_nodes; + vec_init(fn_nodes); + + for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { + spl_ast_node_ref_t mref = vec_at(te->type_aggregate.members, i); + spl_ast_node_t *mn = spl_ast_node(sema->ast, mref); + if (!mn) + continue; + + if (mn->kind == SPL_AST_MEMBER_DECL) { + spl_lang_type_id_t mtid = sema_infer(sema, mn->member_decl.type_expr); + spl_type_member_t m = {.name = mn->member_decl.name, + .type_id = spl_lang_type_get_ir_type(sema->type, mtid), + .ast_node_ref = mref}; + vec_push(members, m); + } else if (mn->kind == SPL_AST_FN_DECL) { + spl_def_id_t fn_def = + spl_def_alloc(sema->type, SPL_DEF_FN, mn->fn_decl.name, mn->dbg, mref); + mn->resolved_def_id = fn_def; + spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def}; + vec_push(methods, meth); + vec_push(fn_nodes, mref); + } + } + + spl_type_node_kind_t tk; + if (strcmp(te->type_aggregate.kind_name, "struct") == 0) + tk = SPL_TYPE_STRUCT; + else if (strcmp(te->type_aggregate.kind_name, "union") == 0) + tk = SPL_TYPE_UNION; + else if (strcmp(te->type_aggregate.kind_name, "enum") == 0) + tk = SPL_TYPE_ENUM; + else + tk = SPL_TYPE_STRUCT; + + spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO}; + spl_type_id_t agg_ir = spl_type_builder_agg(sema->type, tk, &members, + spl_type_builder_int(sema->type, 32, 1), layout); + vec_free(members); + + spl_lang_type_kind_t lk; + switch (tk) { + case SPL_TYPE_STRUCT: + lk = SPL_LANG_TYPE_STRUCT; + break; + case SPL_TYPE_UNION: + lk = SPL_LANG_TYPE_UNION; + break; + case SPL_TYPE_ENUM: + lk = SPL_LANG_TYPE_ENUM; + break; + case SPL_TYPE_SHAPE: + lk = SPL_LANG_TYPE_SHAPE; + break; + default: + lk = SPL_LANG_TYPE_STRUCT; + break; + } + spl_lang_type_node_t ln = {0}; + ln.kind = lk; + ln.ir_type_id = agg_ir; + ln.methods = methods; + spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &ln); + + spl_lang_type_id_t saved_agg = sema->current_aggregate_lang; + sema->current_aggregate_lang = agg_lang; + for (usize i = 0; i < vec_size(fn_nodes); ++i) + sema_infer(sema, vec_at(fn_nodes, i)); + sema->current_aggregate_lang = saved_agg; + + vec_free(fn_nodes); + return agg_lang; +} + static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = spl_ast_node(sema->ast, ref); if (!n) @@ -240,25 +319,12 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) { sema->error_count++; return; } - - if (te->kind == SPL_AST_TYPE_AGGREGATE) { + if (te->kind == SPL_AST_TYPE_AGGREGATE) sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref); - n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); - - spl_scope_id_t old_scope = sema->scope->current_scope; - spl_scope_id_t inner_scope = spl_scope_alloc(sema->scope); - sema->scope->current_scope = inner_scope; - - for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { - sema_collect(sema, vec_at(te->type_aggregate.members, i)); - } - sema->scope->current_scope = old_scope; - } else { + else sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref); - n->resolved_def_id = sym.node; - spl_scope_insert(sema->scope, sema->scope->current_scope, sym); - } + n->resolved_def_id = sym.node; + spl_scope_insert(sema->scope, sema->scope->current_scope, sym); break; } case SPL_AST_FN_DECL: { @@ -438,7 +504,8 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, case SPL_AST_EXPR_AGGREGATE_LIT: { spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); - if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION)) + if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION && + en->kind != SPL_LANG_TYPE_ENUM)) break; if (n->aggregate_literal.name) { @@ -461,6 +528,41 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_node_t *irn = spl_type_node(sema->type, agg_ir); if (!irn) return 0; + + if (en->kind == SPL_LANG_TYPE_ENUM) { + if (vec_size(n->aggregate_literal.fields) != 1) { + SPL_ERROR(&n->dbg, "enum literal must have exactly one variant"); + sema->error_count++; + return 0; + } + spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, 0)); + if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) { + SPL_ERROR(&n->dbg, "invalid enum literal"); + sema->error_count++; + return 0; + } + usize idx = 0; + if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) { + SPL_ERROR(&item->dbg, "no variant `%s`", item->struct_init_item.name); + sema->error_count++; + return 0; + } + spl_type_member_t *m = &vec_at(irn->agg_type.variants, idx); + spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); + if (!ft) + return 0; + if (!item->struct_init_item.expr) { + SPL_ERROR(&item->dbg, "variant `%s` requires initializer", + item->struct_init_item.name); + sema->error_count++; + return 0; + } + sema_check(sema, item->struct_init_item.expr, ft); + n->resolved_lang_tid = expected; + n->expected_lang_tid = 0; + return expected; + } + usize nfields = vec_size(irn->agg_type.variants); bool *seen = calloc(nfields ? nfields : 1, sizeof(bool)); @@ -492,12 +594,6 @@ static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref, } sema_check(sema, item->struct_init_item.expr, ft); } - // for (usize i = 0; i < nfields; ++i) { - // if (!seen[i]) { - // SPL_ERROR(&n->dbg, "missing field `%s`", vec_at(irn->agg_type.variants, i).name); - // sema->error_count++; - // } - // } free(seen); n->resolved_lang_tid = expected; n->expected_lang_tid = 0; @@ -892,26 +988,40 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { if (obj->kind == SPL_LANG_TYPE_PTR) agg_lang = obj->extra.elem; spl_lang_type_node_t *agg = spl_lang_type_node(sema->type, agg_lang); - if (!agg || (agg->kind != SPL_LANG_TYPE_STRUCT && agg->kind != SPL_LANG_TYPE_UNION)) { + if (!agg || (agg->kind != SPL_LANG_TYPE_STRUCT && agg->kind != SPL_LANG_TYPE_UNION && + agg->kind != SPL_LANG_TYPE_ENUM)) { SPL_ERROR(&n->dbg, "field access on non-aggregate type"); sema->error_count++; return 0; } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang); const spl_type_member_t *m = spl_type_agg_member(sema->type, agg_ir, n->field.field); - if (!m) { - SPL_ERROR(&n->dbg, "no field `%s`", n->field.field); - sema->error_count++; - return 0; + if (m) { + spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); + if (!ft) { + SPL_ERROR(&n->dbg, "cannot resolve field type"); + sema->error_count++; + return 0; + } + n->resolved_lang_tid = ft; + return ft; } - spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id); - if (!ft) { - SPL_ERROR(&n->dbg, "cannot resolve field type"); - sema->error_count++; - return 0; + + for (usize i = 0; i < vec_size(agg->methods); ++i) { + spl_lang_method_t *meth = &vec_at(agg->methods, i); + if (strcmp(meth->name, n->field.field) != 0) + continue; + spl_def_node_t *fd = spl_def_node(sema->type, meth->def_id); + if (!fd) + return 0; + n->resolved_def_id = meth->def_id; + n->resolved_lang_tid = fd->lang_id; + return fd->lang_id; } - n->resolved_lang_tid = ft; - return ft; + + SPL_ERROR(&n->dbg, "no field `%s`", n->field.field); + sema->error_count++; + return 0; } /* ---------- INDEX ---------- */ @@ -1047,8 +1157,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { } spl_lang_type_id_t agg = def->lang_id; spl_lang_type_node_t *an = spl_lang_type_node(sema->type, agg); - if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION)) { - SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name); + if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION && + an->kind != SPL_LANG_TYPE_ENUM)) { + SPL_ERROR(&n->dbg, "`%s` is not a struct/union/enum", type_name); + sema->error_count++; + return 0; + } + if (an->kind == SPL_LANG_TYPE_ENUM && vec_size(n->aggregate_literal.fields) != 1) { + SPL_ERROR(&n->dbg, "enum literal must have exactly one variant"); sema->error_count++; return 0; } @@ -1270,8 +1386,20 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { return t; } case SPL_AST_TYPE_AGGREGATE: - case SPL_AST_TYPE_COMPTIME_CALL: + return sema_build_aggregate(sema, n); + case SPL_AST_TYPE_COMPTIME_CALL: { + const char *name = n->type_comptime_call.name; + if (name && strcmp(name, "self") == 0) { + if (sema->current_aggregate_lang == 0) { + SPL_ERROR(&n->dbg, "`@self` outside of aggregate"); + sema->error_count++; + return 0; + } + n->resolved_lang_tid = sema->current_aggregate_lang; + return sema->current_aggregate_lang; + } return 0; + } /* ---------- 顶层声明 ---------- */ case SPL_AST_CONTAINER_MEMBERS: @@ -1329,65 +1457,10 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr); if (!te) break; - if (te->kind == SPL_AST_TYPE_AGGREGATE) { - spl_type_member_vec_t members; - vec_init(members); - for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { - spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i)); - if (mn && mn->kind == SPL_AST_MEMBER_DECL) { - spl_lang_type_id_t mtid = sema_infer(sema, mn->member_decl.type_expr); - spl_type_member_t m = {.name = mn->member_decl.name, - .type_id = spl_lang_type_get_ir_type(sema->type, mtid), - .ast_node_ref = vec_at(te->type_aggregate.members, i)}; - vec_push(members, m); - } - } - spl_type_node_kind_t tk; - if (strcmp(te->type_aggregate.kind_name, "struct") == 0) - tk = SPL_TYPE_STRUCT; - else if (strcmp(te->type_aggregate.kind_name, "union") == 0) - tk = SPL_TYPE_UNION; - else if (strcmp(te->type_aggregate.kind_name, "enum") == 0) - tk = SPL_TYPE_ENUM; - else - tk = SPL_TYPE_STRUCT; - - spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO}; - spl_type_id_t agg_ir = spl_type_builder_agg( - sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout); - vec_free(members); - - spl_lang_type_kind_t lk; - switch (tk) { - case SPL_TYPE_STRUCT: - lk = SPL_LANG_TYPE_STRUCT; - break; - case SPL_TYPE_UNION: - lk = SPL_LANG_TYPE_UNION; - break; - case SPL_TYPE_ENUM: - lk = SPL_LANG_TYPE_ENUM; - break; - case SPL_TYPE_SHAPE: - lk = SPL_LANG_TYPE_SHAPE; - break; - default: - lk = SPL_LANG_TYPE_STRUCT; - break; - } - spl_lang_type_node_t ln = {0}; - ln.kind = lk; - ln.ir_type_id = agg_ir; - spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &ln); + spl_lang_type_id_t agg_lang = sema_build_aggregate(sema, te); spl_def_resolve(sema->type, n->resolved_def_id, agg_lang); n->resolved_lang_tid = agg_lang; - - for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { - spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i)); - if (mn && mn->kind == SPL_AST_FN_DECL) - sema_infer(sema, vec_at(te->type_aggregate.members, i)); - } } else { spl_lang_type_id_t tid = sema_infer(sema, n->type_decl.type_expr); spl_def_resolve(sema->type, n->resolved_def_id, tid); @@ -1522,6 +1595,8 @@ void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) { return; spl_scope_id_t saved = sema->scope->current_scope; sema_collect(sema, module_ref); + fprintf(stderr, "after collect: current=%zu root=%zu\n", sema->scope->current_scope, + sema->scope->root_scope); sema_infer(sema, module_ref); sema->scope->current_scope = saved; } diff --git a/stage1/spl_sema.h b/stage1/spl_sema.h index 57ef1bc..5fa78cd 100644 --- a/stage1/spl_sema.h +++ b/stage1/spl_sema.h @@ -47,7 +47,8 @@ typedef struct { int error_count; spl_scope_id_t store_scope; spl_attr_t *attr; - spl_type_id_t current_fn_ret_tid; // TODO + spl_lang_type_id_t current_aggregate_lang; + spl_lang_type_id_t current_fn_ret_tid; } spl_sema_t; void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope, diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 17f6e40..1ca2e56 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -166,6 +166,20 @@ static usize spl_lang_type_hash(spl_lang_type_node_t n) { hash += vec_at(n.extra.fn.params, i); } break; + case SPL_LANG_TYPE_STRUCT: + case SPL_LANG_TYPE_UNION: + case SPL_LANG_TYPE_ENUM: + case SPL_LANG_TYPE_SHAPE: + for (usize i = 0; i < vec_size(n.methods); i++) { + spl_lang_method_t *m = &vec_at(n.methods, i); + hash += m->def_id * 31; + if (m->name) { + const char *s = m->name; + while (*s) + hash = hash * 31 + (usize)(*s++); + } + } + break; default: break; } @@ -197,6 +211,23 @@ static int spl_lang_type_eq(spl_lang_type_node_t n1, spl_lang_type_node_t n2) { return 1; } return 0; + case SPL_LANG_TYPE_STRUCT: + case SPL_LANG_TYPE_UNION: + case SPL_LANG_TYPE_ENUM: + case SPL_LANG_TYPE_SHAPE: + if (vec_size(n1.methods) != vec_size(n2.methods)) + return 1; + for (usize i = 0; i < vec_size(n1.methods); i++) { + spl_lang_method_t *a = &vec_at(n1.methods, i); + spl_lang_method_t *b = &vec_at(n2.methods, i); + if (a->def_id != b->def_id) + return 1; + if ((a->name == NULL) != (b->name == NULL)) + return 1; + if (a->name && strcmp(a->name, b->name) != 0) + return 1; + } + return 0; default: return 0; } @@ -213,6 +244,12 @@ static void spl_lang_node_free_extra(spl_lang_type_node_t *n) { case SPL_LANG_TYPE_FN: vec_free(n->extra.fn.params); break; + case SPL_LANG_TYPE_STRUCT: + case SPL_LANG_TYPE_UNION: + case SPL_LANG_TYPE_ENUM: + case SPL_LANG_TYPE_SHAPE: + vec_free(n->methods); + break; default: break; } diff --git a/stage1/spl_type.h b/stage1/spl_type.h index 54efa7e..aa16049 100644 --- a/stage1/spl_type.h +++ b/stage1/spl_type.h @@ -104,9 +104,16 @@ typedef enum { SPL_LANG_TYPE_VARARGS, } spl_lang_type_kind_t; +typedef struct { + const char *name; + spl_def_id_t def_id; +} spl_lang_method_t; +typedef VEC(spl_lang_method_t) spl_lang_method_vec_t; + typedef struct { spl_lang_type_kind_t kind; spl_type_id_t ir_type_id; + spl_lang_method_vec_t methods; union { spl_lang_type_id_t elem; spl_lang_type_id_vec_t elems;