stage1 支持聚合类型方法
This commit is contained in:
1 parent
9bdb7f892e
commit
5073c2b3ea
10 files changed
+368
-129
No files matched your search
+32
-35
@@ -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) {
|
while (!p->failed) {
|
||||||
const spl_tok_t *t = peek(p);
|
const spl_tok_t *t = peek(p);
|
||||||
if (!t || (t->type != TOK_AT && t->type != TOK_SHARP))
|
if (!t || (t->type != TOK_AT && t->type != TOK_SHARP))
|
||||||
return;
|
return;
|
||||||
|
if (!allow_at && t->type == TOK_AT)
|
||||||
|
return;
|
||||||
|
|
||||||
int is_at = (t->type == TOK_AT);
|
int is_at = (t->type == TOK_AT);
|
||||||
advance(p);
|
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) {
|
static spl_ast_node_ref_t parse_param_decl_impl(parser_t *p) {
|
||||||
spl_ast_node_ref_vec_t attr_list;
|
spl_ast_node_ref_vec_t attr_list;
|
||||||
vec_init(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);
|
const spl_tok_t *name = peek(p);
|
||||||
if (!name || (name->type != TOK_IDENT && name->type != KW_UNDERSCORE)) {
|
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);
|
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 type_expr = parse_type_expr(p);
|
||||||
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name);
|
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PARAM_DECL, name);
|
||||||
spl_ast_node_t *param = node_at(p->ast, ref);
|
spl_ast_node_t *param = node_at(p->ast, ref);
|
||||||
MOVE_VEC(param->param_decl.attr_list, attr_list);
|
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;
|
param->param_decl.type_expr = type_expr;
|
||||||
return ref;
|
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);
|
const spl_tok_t *t = peek(p);
|
||||||
if (t && t->type == TOK_COLON) {
|
if (t && t->type == TOK_COLON) {
|
||||||
advance(p);
|
advance(p);
|
||||||
|
parse_tag_list(p, &tag_list, 0, 0);
|
||||||
type_expr = parse_type_expr(p);
|
type_expr = parse_type_expr(p);
|
||||||
t = peek(p);
|
t = peek(p);
|
||||||
if (t && t->type == TOK_ASSIGN) {
|
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) {
|
static spl_ast_node_ref_t parse_container_declaration(parser_t *p) {
|
||||||
spl_ast_node_ref_vec_t tag_list;
|
spl_ast_node_ref_vec_t tag_list;
|
||||||
vec_init(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);
|
const spl_tok_t *t = peek(p);
|
||||||
if (!t || t->type == TOK_EOF) {
|
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) {
|
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);
|
const spl_tok_t *bt = peek(p);
|
||||||
if (!bt) {
|
if (!bt) {
|
||||||
vec_free(tag_list);
|
|
||||||
SPL_FATAL(bt, "expected type");
|
SPL_FATAL(bt, "expected type");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 函数类型 */
|
/* 函数类型 */
|
||||||
if (bt->type == KW_FN) {
|
if (bt->type == KW_FN) {
|
||||||
vec_free(tag_list);
|
|
||||||
advance(p);
|
advance(p);
|
||||||
const spl_tok_t *t = peek(p);
|
const spl_tok_t *t = peek(p);
|
||||||
if (!t || t->type != TOK_L_PAREN) {
|
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 */
|
/* 聚合类型:struct / union / enum / shape */
|
||||||
if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM ||
|
if (bt->type == KW_STRUCT || bt->type == KW_UNION || bt->type == KW_ENUM ||
|
||||||
bt->type == KW_SHAPE) {
|
bt->type == KW_SHAPE) {
|
||||||
vec_free(tag_list); /* 聚合类型不使用 tag_list */
|
|
||||||
const char *kind_name = (bt->type == KW_STRUCT) ? "struct"
|
const char *kind_name = (bt->type == KW_STRUCT) ? "struct"
|
||||||
: (bt->type == KW_UNION) ? "union"
|
: (bt->type == KW_UNION) ? "union"
|
||||||
: (bt->type == KW_ENUM) ? "enum"
|
: (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);
|
spl_ast_node_t *tp = node_at(p->ast, ref);
|
||||||
SET_STR_FIELD(p->ast, tp->type_path.name, bt);
|
SET_STR_FIELD(p->ast, tp->type_path.name, bt);
|
||||||
vec_init(tp->type_path.generic_args);
|
vec_init(tp->type_path.generic_args);
|
||||||
vec_free(tag_list);
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -885,12 +883,10 @@ static spl_ast_node_ref_t parse_type_base(parser_t *p) {
|
|||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
}
|
}
|
||||||
vec_free(tag_list);
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt->type == TOK_AT || bt->type == TOK_SHARP) {
|
if (bt->type == TOK_AT || bt->type == TOK_SHARP) {
|
||||||
vec_free(tag_list);
|
|
||||||
return parse_type_comptime_call(p);
|
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);
|
spl_ast_node_t *tp = node_at(p->ast, ref);
|
||||||
SET_STR_FIELD(p->ast, tp->type_path.name, bt);
|
SET_STR_FIELD(p->ast, tp->type_path.name, bt);
|
||||||
vec_init(tp->type_path.generic_args);
|
vec_init(tp->type_path.generic_args);
|
||||||
vec_free(tag_list);
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec_free(tag_list);
|
|
||||||
SPL_FATAL(bt, "unrecognized type");
|
SPL_FATAL(bt, "unrecognized type");
|
||||||
return 0;
|
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);
|
const spl_tok_t *name = peek(p);
|
||||||
if (!name || name->type != TOK_IDENT) {
|
if (!name || name->type != TOK_IDENT) {
|
||||||
SPL_FATAL(name, "expected comptime call name");
|
SPL_FATAL(name, "expected comptime name");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
|
|
||||||
|
spl_ast_node_ref_vec_t args;
|
||||||
|
vec_init(args);
|
||||||
|
|
||||||
const spl_tok_t *t = peek(p);
|
const spl_tok_t *t = peek(p);
|
||||||
if (!t || t->type != TOK_L_PAREN) {
|
if (t && t->type == TOK_L_PAREN) {
|
||||||
SPL_FATAL(t, "expected '(' in comptime call");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
advance(p);
|
advance(p);
|
||||||
|
args = parse_expr_list(p);
|
||||||
spl_ast_node_ref_vec_t args = parse_expr_list(p);
|
|
||||||
|
|
||||||
t = peek(p);
|
t = peek(p);
|
||||||
if (!t || t->type != TOK_R_PAREN) {
|
if (!t || t->type != TOK_R_PAREN) {
|
||||||
SPL_FATAL(t, "expected ')' in comptime call");
|
SPL_FATAL(t, "expected ')' in comptime type");
|
||||||
|
vec_free(args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
|
}
|
||||||
|
|
||||||
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_COMPTIME_CALL, start);
|
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);
|
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);
|
const spl_tok_t *name = peek(p);
|
||||||
if (!name || name->type != TOK_IDENT) {
|
if (!name || name->type != TOK_IDENT) {
|
||||||
SPL_FATAL(name, "expected comptime call name");
|
SPL_FATAL(name, "expected comptime name");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
|
|
||||||
|
spl_ast_node_ref_vec_t args;
|
||||||
|
vec_init(args);
|
||||||
|
int has_paren = 0;
|
||||||
|
|
||||||
const spl_tok_t *t = peek(p);
|
const spl_tok_t *t = peek(p);
|
||||||
if (!t || t->type != TOK_L_PAREN) {
|
if (t && t->type == TOK_L_PAREN) {
|
||||||
SPL_FATAL(t, "expected '(' in comptime call");
|
has_paren = 1;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
advance(p);
|
advance(p);
|
||||||
|
args = parse_expr_list(p);
|
||||||
spl_ast_node_ref_vec_t args = parse_expr_list(p);
|
|
||||||
|
|
||||||
t = peek(p);
|
t = peek(p);
|
||||||
if (!t || t->type != TOK_R_PAREN) {
|
if (!t || t->type != TOK_R_PAREN) {
|
||||||
SPL_FATAL(t, "expected ')' in comptime call");
|
SPL_FATAL(t, "expected ')' in comptime call");
|
||||||
|
vec_free(args);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
|
}
|
||||||
|
|
||||||
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_COMPTIME_CALL, start);
|
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);
|
spl_ast_node_t *cc = node_at(p->ast, ref);
|
||||||
SET_STR_FIELD(p->ast, cc->comptime_call.name, name);
|
SET_STR_FIELD(p->ast, cc->comptime_call.name, name);
|
||||||
cc->comptime_call.args = args;
|
cc->comptime_call.args = args;
|
||||||
|
(void)has_paren;
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2082,7 +2079,7 @@ static spl_ast_node_ref_t parse_statement(parser_t *p) {
|
|||||||
case KW_TYPE: {
|
case KW_TYPE: {
|
||||||
spl_ast_node_ref_vec_t tag_list;
|
spl_ast_node_ref_vec_t tag_list;
|
||||||
vec_init(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;
|
spl_ast_node_ref_t decl;
|
||||||
if (t->type == KW_VAR)
|
if (t->type == KW_VAR)
|
||||||
@@ -2214,7 +2211,7 @@ void spl_ast_parse(spl_ast_t *ast) {
|
|||||||
p.pos = save_pos;
|
p.pos = save_pos;
|
||||||
}
|
}
|
||||||
if (t2 && t2->type == TOK_NOT) {
|
if (t2 && t2->type == TOK_NOT) {
|
||||||
parse_tag_list(&p, &external_tags, 1);
|
parse_tag_list(&p, &external_tags, 1, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+73
-3
@@ -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))
|
if (!spl_type_agg_member_idx(a->sema->type, agg_ir, n->field.field, &idx))
|
||||||
return 0;
|
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);
|
return spl_ir_builder_mem_field(a->ir, agg_ir, base, idx);
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_INDEX: {
|
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)
|
if (in != SPL_INTRIN_NONE)
|
||||||
return ast2ir_intrin_field(a, n, in);
|
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);
|
spl_ir_node_ref_t ptr = emit_lvalue(a, ref);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
return 0;
|
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);
|
spl_type_node_t *tn = spl_type_node(a->sema->type, t);
|
||||||
if (!tn)
|
if (!tn)
|
||||||
Panic("aggregate type node missing");
|
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);
|
usize nfields = vec_size(tn->agg_type.variants);
|
||||||
|
|
||||||
/* 按字段名定位到 index,缺省值填 0(sema 已保证无缺省) */
|
|
||||||
spl_ir_node_ref_vec_t fields;
|
spl_ir_node_ref_vec_t fields;
|
||||||
vec_init(fields);
|
vec_init(fields);
|
||||||
for (usize i = 0; i < nfields; ++i)
|
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");
|
Panic("agg_construct failed for aggregate literal");
|
||||||
|
|
||||||
for (usize i = 0; i < nfields; ++i) {
|
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);
|
vec_free(fields);
|
||||||
return node;
|
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);
|
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) {
|
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);
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
if (!n)
|
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:
|
case SPL_AST_FN_DECL:
|
||||||
emit_fn(a, d);
|
emit_fn(a, d);
|
||||||
break;
|
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:
|
case SPL_AST_TOP_LEVEL_BLOCK:
|
||||||
emit_container(a, dref);
|
emit_container(a, dref);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ const char *spl_ir_kind_name(spl_ir_kind_t kind) {
|
|||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPL_ENUM_TAG_FIELD_IDX 0
|
|
||||||
|
|
||||||
void spl_ir_init(spl_ir_t *ir) {
|
void spl_ir_init(spl_ir_t *ir) {
|
||||||
vec_init(ir->funcs);
|
vec_init(ir->funcs);
|
||||||
vec_push(ir->funcs, (spl_ir_func_t){0});
|
vec_push(ir->funcs, (spl_ir_func_t){0});
|
||||||
|
|||||||
@@ -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 */
|
typedef usize spl_ir_func_ref_t; /* 0 is error */
|
||||||
|
|
||||||
|
#define SPL_ENUM_TAG_FIELD_IDX 0
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
spl_ir_kind_t kind;
|
spl_ir_kind_t kind;
|
||||||
spl_dbg_node_t dbg;
|
spl_dbg_node_t dbg;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "spl_ir2vm.h"
|
#include "spl_ir2vm.h"
|
||||||
#include "spl_layout.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) {
|
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);
|
spl_type_node_t *tn = spl_type_node(ctx->type, tid);
|
||||||
if (!tn)
|
if (!tn)
|
||||||
@@ -20,6 +22,16 @@ static usize ir_type_size(spl_ir2vm_t *ctx, spl_type_id_t tid) {
|
|||||||
return sizeof(void *);
|
return sizeof(void *);
|
||||||
case SPL_TYPE_ARRAY:
|
case SPL_TYPE_ARRAY:
|
||||||
return ir_type_size(ctx, tn->array_type.element) * tn->array_type.len;
|
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_STRUCT:
|
||||||
case SPL_TYPE_UNION: {
|
case SPL_TYPE_UNION: {
|
||||||
usize s = 0;
|
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);
|
spl_type_node_t *tn = spl_type_node(ctx->type, tid);
|
||||||
if (!tn)
|
if (!tn)
|
||||||
return 0;
|
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 (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_UNION) {
|
||||||
if (idx < vec_size(tn->agg_type.variants))
|
if (idx < vec_size(tn->agg_type.variants))
|
||||||
return vec_at(tn->agg_type.variants, idx).type_id;
|
return vec_at(tn->agg_type.variants, idx).type_id;
|
||||||
|
|||||||
+33
-1
@@ -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) {
|
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);
|
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) {
|
if (n == 0) {
|
||||||
out->size_bits = 0;
|
out->size_bits = 0;
|
||||||
out->align_bits = 8;
|
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;
|
max_align_bits = field_align_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 聚合对齐策略 */
|
|
||||||
usize final_align_bits = max_align_bits;
|
usize final_align_bits = max_align_bits;
|
||||||
if (layout->aggregate.align_rule == ALIGN_FIXED) {
|
if (layout->aggregate.align_rule == ALIGN_FIXED) {
|
||||||
final_align_bits = layout->aggregate.fixed_align * 8;
|
final_align_bits = layout->aggregate.fixed_align * 8;
|
||||||
|
|||||||
+162
-87
@@ -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) {
|
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);
|
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
|
||||||
if (!n)
|
if (!n)
|
||||||
@@ -240,25 +319,12 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
sema->error_count++;
|
sema->error_count++;
|
||||||
return;
|
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);
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref);
|
||||||
n->resolved_def_id = sym.node;
|
else
|
||||||
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 {
|
|
||||||
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref);
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref);
|
||||||
n->resolved_def_id = sym.node;
|
n->resolved_def_id = sym.node;
|
||||||
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPL_AST_FN_DECL: {
|
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: {
|
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
||||||
spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected);
|
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;
|
break;
|
||||||
|
|
||||||
if (n->aggregate_literal.name) {
|
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);
|
spl_type_node_t *irn = spl_type_node(sema->type, agg_ir);
|
||||||
if (!irn)
|
if (!irn)
|
||||||
return 0;
|
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);
|
usize nfields = vec_size(irn->agg_type.variants);
|
||||||
bool *seen = calloc(nfields ? nfields : 1, sizeof(bool));
|
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);
|
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);
|
free(seen);
|
||||||
n->resolved_lang_tid = expected;
|
n->resolved_lang_tid = expected;
|
||||||
n->expected_lang_tid = 0;
|
n->expected_lang_tid = 0;
|
||||||
@@ -892,18 +988,15 @@ 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)
|
if (obj->kind == SPL_LANG_TYPE_PTR)
|
||||||
agg_lang = obj->extra.elem;
|
agg_lang = obj->extra.elem;
|
||||||
spl_lang_type_node_t *agg = spl_lang_type_node(sema->type, agg_lang);
|
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");
|
SPL_ERROR(&n->dbg, "field access on non-aggregate type");
|
||||||
sema->error_count++;
|
sema->error_count++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
|
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);
|
const spl_type_member_t *m = spl_type_agg_member(sema->type, agg_ir, n->field.field);
|
||||||
if (!m) {
|
if (m) {
|
||||||
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
|
|
||||||
sema->error_count++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id);
|
spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id);
|
||||||
if (!ft) {
|
if (!ft) {
|
||||||
SPL_ERROR(&n->dbg, "cannot resolve field type");
|
SPL_ERROR(&n->dbg, "cannot resolve field type");
|
||||||
@@ -914,6 +1007,23 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
|
||||||
|
sema->error_count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- INDEX ---------- */
|
/* ---------- INDEX ---------- */
|
||||||
case SPL_AST_EXPR_INDEX: {
|
case SPL_AST_EXPR_INDEX: {
|
||||||
spl_lang_type_id_t obj_tid = sema_infer(sema, n->index.obj);
|
spl_lang_type_id_t obj_tid = sema_infer(sema, n->index.obj);
|
||||||
@@ -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_id_t agg = def->lang_id;
|
||||||
spl_lang_type_node_t *an = spl_lang_type_node(sema->type, agg);
|
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)) {
|
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);
|
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++;
|
sema->error_count++;
|
||||||
return 0;
|
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;
|
return t;
|
||||||
}
|
}
|
||||||
case SPL_AST_TYPE_AGGREGATE:
|
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;
|
return 0;
|
||||||
|
}
|
||||||
|
n->resolved_lang_tid = sema->current_aggregate_lang;
|
||||||
|
return sema->current_aggregate_lang;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- 顶层声明 ---------- */
|
/* ---------- 顶层声明 ---------- */
|
||||||
case SPL_AST_CONTAINER_MEMBERS:
|
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);
|
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
|
||||||
if (!te)
|
if (!te)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
|
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
|
||||||
spl_type_member_vec_t members;
|
spl_lang_type_id_t agg_lang = sema_build_aggregate(sema, te);
|
||||||
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_def_resolve(sema->type, n->resolved_def_id, agg_lang);
|
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
|
||||||
n->resolved_lang_tid = 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 {
|
} else {
|
||||||
spl_lang_type_id_t tid = sema_infer(sema, n->type_decl.type_expr);
|
spl_lang_type_id_t tid = sema_infer(sema, n->type_decl.type_expr);
|
||||||
spl_def_resolve(sema->type, n->resolved_def_id, tid);
|
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;
|
return;
|
||||||
spl_scope_id_t saved = sema->scope->current_scope;
|
spl_scope_id_t saved = sema->scope->current_scope;
|
||||||
sema_collect(sema, module_ref);
|
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_infer(sema, module_ref);
|
||||||
sema->scope->current_scope = saved;
|
sema->scope->current_scope = saved;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -47,7 +47,8 @@ typedef struct {
|
|||||||
int error_count;
|
int error_count;
|
||||||
spl_scope_id_t store_scope;
|
spl_scope_id_t store_scope;
|
||||||
spl_attr_t *attr;
|
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;
|
} spl_sema_t;
|
||||||
|
|
||||||
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope,
|
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope,
|
||||||
|
|||||||
@@ -166,6 +166,20 @@ static usize spl_lang_type_hash(spl_lang_type_node_t n) {
|
|||||||
hash += vec_at(n.extra.fn.params, i);
|
hash += vec_at(n.extra.fn.params, i);
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
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 1;
|
||||||
}
|
}
|
||||||
return 0;
|
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:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -213,6 +244,12 @@ static void spl_lang_node_free_extra(spl_lang_type_node_t *n) {
|
|||||||
case SPL_LANG_TYPE_FN:
|
case SPL_LANG_TYPE_FN:
|
||||||
vec_free(n->extra.fn.params);
|
vec_free(n->extra.fn.params);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,9 +104,16 @@ typedef enum {
|
|||||||
SPL_LANG_TYPE_VARARGS,
|
SPL_LANG_TYPE_VARARGS,
|
||||||
} spl_lang_type_kind_t;
|
} 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 {
|
typedef struct {
|
||||||
spl_lang_type_kind_t kind;
|
spl_lang_type_kind_t kind;
|
||||||
spl_type_id_t ir_type_id;
|
spl_type_id_t ir_type_id;
|
||||||
|
spl_lang_method_vec_t methods;
|
||||||
union {
|
union {
|
||||||
spl_lang_type_id_t elem;
|
spl_lang_type_id_t elem;
|
||||||
spl_lang_type_id_vec_t elems;
|
spl_lang_type_id_vec_t elems;
|
||||||
|
|||||||
Reference in new issue
Block a user