Compare commits

...
2 Commits
Author SHA1 Message Date
zzy 5073c2b3ea stage1 支持聚合类型方法 2026-09-14 15:36:43 +08:00
zzy 9bdb7f892e stage1 支持结构体初始化 2026-09-14 10:09:32 +08:00
9 changed files with 445 additions and 149 deletions

No files matched your search

+43 -46
View File
@@ -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;
}
}
+129 -3
View File
@@ -38,6 +38,56 @@ static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n,
static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in);
static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n);
static spl_ir_node_ref_t emit_zero_value(spl_ast2ir_t *a, spl_type_id_t tid) {
spl_type_node_t *tn = spl_type_node(a->sema->type, tid);
if (!tn)
return 0;
switch (tn->kind) {
case SPL_TYPE_BOOL:
return spl_ir_builder_type_const_bool(a->ir, tid, false);
case SPL_TYPE_INT:
return spl_ir_builder_type_const_int(a->ir, tid, 0);
case SPL_TYPE_FLOAT:
return spl_ir_builder_type_const_float(a->ir, tid, 0.0);
case SPL_TYPE_PTR:
case SPL_TYPE_FN:
return spl_ir_builder_type_const_ptr(a->ir, tid, NULL);
case SPL_TYPE_ARRAY: {
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
for (usize i = 0; i < tn->array_type.len; ++i) {
spl_ir_node_ref_t f = emit_zero_value(a, tn->array_type.element);
if (!f)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, f);
}
return node;
}
case SPL_TYPE_STRUCT:
case SPL_TYPE_SHAPE: {
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) {
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(tn->agg_type.variants, i).type_id);
if (!f)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, f);
}
return node;
}
case SPL_TYPE_UNION: {
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, tid);
if (vec_size(tn->agg_type.variants) == 0)
return node;
spl_ir_node_ref_t f = emit_zero_value(a, vec_at(tn->agg_type.variants, 0).type_id);
if (!f)
return 0;
spl_ir_builder_agg_construct_field(a->ir, node, f);
return node;
}
default:
return 0;
}
}
static void copy_attrs_to_ir_node(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_node_ref_t ir_ref) {
if (!ir_ref || !n || vec_size(n->attrs) == 0)
return;
@@ -205,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: {
@@ -534,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;
@@ -604,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)
@@ -629,12 +726,20 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
vec_at(fields, idx) = f;
}
for (usize i = 0; i < nfields; ++i) {
if (!vec_at(fields, i)) {
spl_type_id_t ftid = vec_at(tn->agg_type.variants, i).type_id;
spl_ir_node_ref_t f = emit_zero_value(a, ftid);
if (!f)
Panic("cannot zero-init aggregate field #%zu", i);
vec_at(fields, i) = f;
}
}
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
if (!node)
Panic("agg_construct failed for aggregate literal");
/* 顺序非常关键:agg_construct_field 是 vec_push,
必须严格按字段 index 0..n-1 顺序 push */
for (usize i = 0; i < nfields; ++i) {
spl_ir_node_ref_t f = vec_at(fields, i);
if (!f)
@@ -1075,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)
@@ -1096,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;
+2
View File
@@ -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;
+22 -2
View File
@@ -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;
@@ -858,8 +878,8 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid);
if (tn && tn->kind == SPL_TYPE_BOOL) {
cg_load_slot(cg, n->arith.left, SPL_BOOL);
CG_PUSH(cg, SPL_U8, 0);
CG_OP(cg, SPL_EQ, SPL_U8);
CG_PUSH(cg, SPL_BOOL, 0);
CG_OP(cg, SPL_EQ, SPL_BOOL);
cg_store_slot(cg, ref, SPL_BOOL);
} else {
cg_unop(cg, ref, n, SPL_NOT);
+33 -1
View File
@@ -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;
+170 -96
View File
@@ -139,7 +139,6 @@ static void sema_resolve_attrs(spl_sema_t *sema, spl_ast_node_ref_vec_t *raw,
}
}
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref);
static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref);
static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
spl_lang_type_id_t expected);
@@ -201,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)
@@ -241,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: {
@@ -439,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) {
@@ -462,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));
@@ -493,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;
@@ -893,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 ---------- */
@@ -1048,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;
}
@@ -1271,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:
@@ -1330,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);
@@ -1523,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;
}
+2 -1
View File
@@ -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,
+37
View File
@@ -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;
}
+7
View File
@@ -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;