stage1 支持更多语法 修复更多问题 暂时stage1功能结束

This commit is contained in:
zzy committed 2026-09-17 13:37:59 +08:00
1 parent 54425a50c7
commit acfbbeee8b
11 files changed
+802 -183

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ VarDecl = { DeclHeader ~ KEYWORD_var ~ VarBody }
ConstDecl = { DeclHeader ~ KEYWORD_const ~ VarBody }
VarBody = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? }
TypeDecl = { DeclHeader ~ KEYWORD_type ~ IDENTIFIER ~ EQUAL ~ TypeExpr }
TypeDecl = { DeclHeader ~ KEYWORD_type ~ Pattern ~ EQUAL ~ TypeExpr }
MemberDecl = { DeclHeader ~ IDENTIFIER ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? }
+15
View File
@@ -272,6 +272,21 @@ static bool test_once_with_dump(const char *fname, void *user_data) {
return nob_cmd_run(&cmd);
}
static bool is_stage_name(const char *s) {
return strcmp(s, "stage1") == 0 || strcmp(s, "stage2") == 0 || strcmp(s, "diff") == 0;
}
static bool is_dump_mode(const char *s) {
return strcmp(s, "lex") == 0 || strcmp(s, "ast") == 0 || strcmp(s, "sema") == 0 ||
strcmp(s, "ir") == 0 || strcmp(s, "vm") == 0;
}
static const char *stage_dir_of(const char *stage) {
if (strcmp(stage, "stage2") == 0)
return "./stage2/";
return "./tests/stage1/";
}
typedef bool (*test_fn_t)(const char *fname, void *user_data);
static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) {
const char *test_folder = "./tests/stage1/";
+3
View File
@@ -134,6 +134,9 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t
break;
case SPL_AST_TYPE_DECL:
dump_vec(ast, node->type_decl.attr_list, stack);
if (node->type_decl.pattern)
dump_node(ast, node->type_decl.pattern, stack, false);
if (node->type_decl.type_expr)
dump_node(ast, node->type_decl.type_expr, stack, true);
break;
+1 -1
View File
@@ -184,7 +184,7 @@ struct spl_ast_node {
struct {
spl_ast_node_ref_vec_t attr_list;
const char *name;
spl_ast_node_ref_t pattern;
spl_ast_node_ref_t type_expr;
} type_decl;
+319 -37
View File
@@ -29,6 +29,12 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_ir_node_ref_t src_ptr, spl_type_id_t tid);
static spl_ir_node_ref_t emit_match_check(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_type_id_t scrut_ir, spl_ir_node_ref_t scrut_slot);
static void emit_fn_reserve(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
@@ -111,6 +117,181 @@ static spl_ir_node_ref_t emit_zero_value(spl_ast2ir_t *a, spl_type_id_t tid) {
}
}
/* 把 pattern 里的 ident 绑到 src_ptr 指向内存的对应位置。
- PATTERN_IDENT: def2ir_map[def_id] = src_ptr
- PATTERN_DOT: src_ptr 指向 enum,payload 在 mem_field(tid, src_ptr, vidx+1)
- PATTERN_TUPLE / PATTERN_AGGREGATE: 递归 mem_field
UB 语义:不做 tag 检查,调用者保证变体正确。
*/
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_ir_node_ref_t src_ptr, spl_type_id_t tid) {
if (!pat_ref || !src_ptr)
return;
spl_ast_node_t *pat = spl_ast_node(a->ast, pat_ref);
if (!pat)
return;
switch (pat->kind) {
case SPL_AST_PATTERN_IDENT: {
if (pat->resolved_def_id)
map_put(a->def2ir_map, pat->resolved_def_id, src_ptr);
return;
}
case SPL_AST_EXPR_INT_LIT:
case SPL_AST_EXPR_FLOAT_LIT:
case SPL_AST_EXPR_CHAR_LIT:
case SPL_AST_EXPR_STRING_LIT:
case SPL_AST_EXPR_BOOL_LIT:
case SPL_AST_EXPR_NULL_LIT:
return; /* 字面量不绑定 */
case SPL_AST_PATTERN_UNDERSCORE:
return;
case SPL_AST_PATTERN_LIST:
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
emit_pattern_bind(a, vec_at(pat->pattern_list.patterns, i), src_ptr, tid);
return;
case SPL_AST_PATTERN_TUPLE: {
spl_type_node_t *tn = spl_type_node(&a->sema->type->ir, tid);
if (!tn || tn->kind != SPL_TYPE_STRUCT)
return;
usize n = vec_size(pat->pattern_tuple.patterns);
usize nf = vec_size(tn->agg_type.variants);
if (n > nf)
return;
for (usize i = 0; i < n; ++i) {
spl_type_id_t ft = vec_at(tn->agg_type.variants, i).type_id;
spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, i);
emit_pattern_bind(a, vec_at(pat->pattern_tuple.patterns, i), fp, ft);
}
return;
}
case SPL_AST_PATTERN_DOT: {
spl_type_node_t *tn = spl_type_node(&a->sema->type->ir, tid);
if (!tn || tn->kind != SPL_TYPE_ENUM)
return;
usize vidx = pat->resolved_def_id;
if (vidx == 0)
return;
vidx -= 1;
if (vidx >= vec_size(tn->agg_type.variants))
return;
spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id;
spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, tid, src_ptr, vidx + 1);
if (pat->pattern_dot.sub_pattern)
emit_pattern_bind(a, pat->pattern_dot.sub_pattern, pptr, payload_ir);
return;
}
case SPL_AST_PATTERN_AGGREGATE: {
spl_type_node_t *tn = spl_type_node(&a->sema->type->ir, tid);
if (!tn || (tn->kind != SPL_TYPE_STRUCT && tn->kind != SPL_TYPE_UNION))
return;
for (usize i = 0; i < vec_size(pat->pattern_aggregate.fields); ++i) {
spl_ast_node_t *f = spl_ast_node(a->ast, vec_at(pat->pattern_aggregate.fields, i));
if (!f || f->kind != SPL_AST_PATTERN_FIELD)
continue;
usize idx = f->resolved_def_id;
if (idx >= vec_size(tn->agg_type.variants))
continue;
spl_type_id_t ft = vec_at(tn->agg_type.variants, idx).type_id;
spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, idx);
if (f->pattern_field.pattern)
emit_pattern_bind(a, f->pattern_field.pattern, fp, ft);
}
return;
}
default:
return;
}
}
/* 计算 pattern 对 scrutinee 的匹配条件。
返回 0 表示无条件命中(IDENT / UNDERSCORE),否则返回 bool 节点。 */
static spl_ir_node_ref_t emit_match_check(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_type_id_t scrut_ir, spl_ir_node_ref_t scrut_slot) {
spl_ast_node_t *pat = spl_ast_node(a->ast, pat_ref);
if (!pat)
return 0;
switch (pat->kind) {
case SPL_AST_PATTERN_UNDERSCORE:
case SPL_AST_PATTERN_IDENT:
return 0;
case SPL_AST_PATTERN_LIST: {
spl_lang_type_id_t bt = spl_lang_make_bool(a->sema->type);
spl_type_id_t bt_ir = to_ir_type(a, bt);
spl_ir_node_ref_t combined = 0;
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i) {
spl_ir_node_ref_t c =
emit_match_check(a, vec_at(pat->pattern_list.patterns, i), scrut_ir, scrut_slot);
if (!c)
return 0;
combined = combined ? spl_ir_builder_arith_or(a->ir, bt_ir, combined, c) : c;
}
return combined;
}
case SPL_AST_PATTERN_DOT: {
spl_type_node_t *tn = spl_type_node(&a->sema->type->ir, scrut_ir);
if (!tn || tn->kind != SPL_TYPE_ENUM)
return 0;
usize vidx = pat->resolved_def_id;
if (vidx == 0)
return 0;
vidx -= 1;
spl_type_id_t tag_ir = tn->agg_type.tag_type;
spl_ir_node_ref_t tag_ptr =
spl_ir_builder_mem_field(a->ir, scrut_ir, scrut_slot, SPL_ENUM_TAG_FIELD_IDX);
spl_ir_node_ref_t tag_val = spl_ir_builder_mem_load(a->ir, tag_ir, tag_ptr);
spl_ir_node_ref_t vidx_const = spl_ir_builder_type_const_int(a->ir, tag_ir, vidx);
return spl_ir_builder_cmp_eq(a->ir, tag_ir, tag_val, vidx_const);
}
case SPL_AST_EXPR_INT_LIT:
case SPL_AST_EXPR_FLOAT_LIT:
case SPL_AST_EXPR_CHAR_LIT:
case SPL_AST_EXPR_STRING_LIT:
case SPL_AST_EXPR_BOOL_LIT:
case SPL_AST_EXPR_NULL_LIT: {
spl_ir_node_ref_t val = emit_expr(a, pat_ref);
if (!val)
return 0;
spl_ir_node_ref_t loaded = spl_ir_builder_mem_load(a->ir, scrut_ir, scrut_slot);
return spl_ir_builder_cmp_eq(a->ir, scrut_ir, loaded, val);
}
default:
/* tuple / aggregate pattern 暂不作为 match 条件 */
return 0;
}
}
/* 分配 slot → store init 值 → bind pattern。
返回指向变量内存的指针(*tid),调用者可用于读取初值。 */
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n) {
spl_type_id_t var_ir = node_ir(a, n);
if (!var_ir)
return 0;
spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, var_ir, const_usize(a, 1));
if (n->var_const_decl.init_expr) {
spl_ir_node_ref_t v = emit_expr(a, n->var_const_decl.init_expr);
if (v)
spl_ir_builder_mem_store(a->ir, var_ir, slot, v);
}
emit_pattern_bind(a, n->var_const_decl.pattern, slot, var_ir);
return slot;
}
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;
@@ -843,7 +1024,6 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
item->struct_init_item.name);
spl_type_id_t tag_ir = tn->agg_type.tag_type;
spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id;
spl_ir_node_ref_t eptr = spl_ir_builder_mem_alloca(a->ir, t, const_usize(a, 1));
@@ -852,11 +1032,14 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
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_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, payload_ir, pptr, payload);
if (item->struct_init_item.expr) {
spl_type_id_t payload_ir = 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, payload_ir, pptr, payload);
}
return eptr;
}
@@ -931,9 +1114,117 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
case SPL_AST_EXPR_IF:
case SPL_AST_EXPR_IFVAR:
return emit_if_like(a, ref);
case SPL_AST_EXPR_MATCH: {
spl_ast_node_ref_t matched_ref = n->match_expr.matched_expr;
spl_ast_node_t *matched_node = spl_ast_node(a->ast, matched_ref);
spl_lang_type_id_t matched_lang = node_lang(a, matched_node);
spl_type_id_t matched_ir = to_ir_type(a, matched_lang);
if (!matched_ir)
return 0;
spl_ir_node_ref_t scrut_slot =
spl_ir_builder_mem_alloca(a->ir, matched_ir, const_usize(a, 1));
spl_ir_node_ref_t scrut_val = emit_expr(a, matched_ref);
if (!scrut_val)
return 0;
spl_ir_builder_mem_store(a->ir, matched_ir, scrut_slot, scrut_val);
usize narms = vec_size(n->match_expr.arms);
spl_ir_node_ref_vec_t arm_branches;
spl_ir_block_vec_t cond_blks;
vec_init(arm_branches);
vec_init(cond_blks);
for (usize i = 0; i < narms; ++i) {
vec_push(cond_blks, a->ir->current_block);
spl_ast_node_t *arm = spl_ast_node(a->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
spl_ir_node_ref_t cond =
emit_match_check(a, arm->match_arm.pattern, matched_ir, scrut_slot);
if (cond) {
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
vec_push(arm_branches, br);
} else {
spl_ir_node_ref_t j = spl_ir_builder_control_jmp(a->ir);
vec_push(arm_branches, j);
}
} else {
spl_ir_node_ref_t j = spl_ir_builder_control_jmp(a->ir);
vec_push(arm_branches, j);
}
spl_ir_builder_block_end(a->ir);
if (i + 1 < narms)
spl_ir_builder_block_begin(a->ir);
}
usize no_match_blk = spl_ir_builder_block_begin(a->ir);
spl_ir_node_ref_t no_match_jmp = spl_ir_builder_control_jmp(a->ir);
spl_ir_builder_block_end(a->ir);
spl_ir_node_ref_vec_t body_jmps;
spl_ir_block_vec_t body_blks;
vec_init(body_jmps);
vec_init(body_blks);
for (usize i = 0; i < narms; ++i) {
usize blk = spl_ir_builder_block_begin(a->ir);
vec_push(body_blks, blk);
spl_ast_node_t *arm = spl_ast_node(a->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
emit_pattern_bind(a, arm->match_arm.pattern, scrut_slot, matched_ir);
if (arm->match_arm.body)
emit_expr(a, arm->match_arm.body);
}
spl_ir_node_ref_t j = 0;
if (!a->ir->terminated)
j = spl_ir_builder_control_jmp(a->ir);
vec_push(body_jmps, j);
spl_ir_builder_block_end(a->ir);
}
usize end_blk = spl_ir_builder_block_begin(a->ir);
for (usize i = 0; i < narms; ++i) {
spl_ir_node_ref_t branch = vec_at(arm_branches, i);
if (!branch)
continue;
spl_ir_node_t *bn = spl_ir_node(&a->ir->ir, a->ir->current_fn, branch);
if (!bn)
continue;
usize body_blk = vec_at(body_blks, i);
if (bn->kind == SPL_IR_CONTROL_BR) {
usize next_blk = (i + 1 < narms) ? vec_at(cond_blks, i + 1) : no_match_blk;
spl_ir_builder_control_br_fixup(a->ir, branch, body_blk, next_blk);
} else if (bn->kind == SPL_IR_CONTROL_JMP) {
spl_ir_builder_control_jmp_fixup(a->ir, branch, body_blk);
}
}
for (usize i = 0; i < narms; ++i) {
spl_ir_node_ref_t j = vec_at(body_jmps, i);
if (j)
spl_ir_builder_control_jmp_fixup(a->ir, j, end_blk);
}
spl_ir_builder_control_jmp_fixup(a->ir, no_match_jmp, end_blk);
vec_free(arm_branches);
vec_free(cond_blks);
vec_free(body_jmps);
vec_free(body_blks);
return 0;
}
case SPL_AST_EXPR_WHILE:
case SPL_AST_EXPR_LOOP:
return emit_loop_like(a, ref);
case SPL_AST_EXPR_FOR:
spl_diag_fatal(a->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &n->dbg,
"for is not implemented yet");
return 0;
case SPL_AST_EXPR_SLICE: {
spl_ast_node_t *obj = spl_ast_node(a->ast, n->slice.obj);
spl_lang_type_id_t obj_lang = node_lang(a, obj);
@@ -1041,13 +1332,12 @@ static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
spl_ast_node_ref_t else_ref = 0;
if (is_ifvar) {
emit_decl(a, n->ifvar_expr.var_decl);
spl_ast_node_t *vd = spl_ast_node(a->ast, n->ifvar_expr.var_decl);
if (!vd || !vd->var_const_decl.init_expr)
Panic("ifvar requires initializer");
spl_ir_node_ref_t slot = 0;
if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot))
Panic("ifvar var slot not found");
if (!vd)
Panic("ifvar missing var_decl");
spl_ir_node_ref_t slot = emit_var_decl(a, vd);
if (!slot)
Panic("ifvar var_decl emit failed");
cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot);
then_ref = n->ifvar_expr.then_block;
else_ref = n->ifvar_expr.else_branch;
@@ -1172,7 +1462,7 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
for (usize i = 0; i < vec_size(top->breaks); ++i)
spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk);
vec_free(top->breaks);
vec_pop(a->loop_stack);
(void)vec_pop(a->loop_stack);
if (!result_slot)
return 0;
@@ -1309,32 +1599,11 @@ static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
switch (n->kind) {
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
case SPL_AST_CONST_DECL:
if (!a->ir->current_fn)
return;
if (!n->resolved_def_id)
return;
spl_ast_node_t *pat = spl_ast_node(a->ast, n->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
return;
spl_lang_type_id_t var_lang = spl_def_get_lang_id(a->sema->type, n->resolved_def_id);
spl_type_id_t var_ir = to_ir_type(a, var_lang);
if (!var_ir)
return;
spl_ir_node_ref_t one = const_usize(a, 1);
spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, var_ir, one);
map_put(a->def2ir_map, n->resolved_def_id, slot);
if (n->var_const_decl.init_expr) {
spl_ir_node_ref_t v = emit_expr(a, n->var_const_decl.init_expr);
if (v)
spl_ir_builder_mem_store(a->ir, var_ir, slot, v);
}
emit_var_decl(a, n);
return;
}
default:
return;
}
@@ -1344,6 +1613,13 @@ static void emit_fn_reserve(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (!n || !n->resolved_def_id)
return;
spl_ir_node_ref_t existing = 0;
if (map_get(a->def2ir_map, n->resolved_def_id, &existing)) {
spl_diag_error(a->diag, SPL_DIAG_KIND_INTERNAL, &n->dbg,
"fn `%s` reserved twice (def#%zu);", n->fn_decl.name, n->resolved_def_id);
return;
}
spl_lang_type_id_t fn_lang = spl_def_get_lang_id(a->sema->type, n->resolved_def_id);
spl_lang_type_node_t *fn_ln = spl_lang_type_node(a->sema->type, fn_lang);
if (!fn_ln || fn_ln->kind != SPL_LANG_TYPE_FN)
@@ -1438,7 +1714,7 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
while (vec_size(a->loop_stack) > loop_base) {
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
vec_free(top->breaks);
vec_pop(a->loop_stack);
(void)vec_pop(a->loop_stack);
}
a->cur_ret_lang = saved_ret;
@@ -1500,6 +1776,9 @@ static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
emit_fn_reserve(a, d);
break;
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *tpat = spl_ast_node(a->ast, d->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
break;
spl_ast_node_t *te = spl_ast_node(a->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_reserve(a, te);
@@ -1536,6 +1815,9 @@ static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
emit_fn_body(a, d);
break;
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *tpat = spl_ast_node(a->ast, d->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
break;
spl_ast_node_t *te = spl_ast_node(a->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_body(a, te);
+1 -2
View File
@@ -2,11 +2,10 @@
#define __SPL_IR_H__
#include "../stage0/include/utils.h"
#include "spl_attr.h"
#include "spl_dbg.h"
#include "spl_type.h"
#include "spl_attr.h"
/* clang-format off */
#define SPL_IR_FN_TABLE \
X(arith.add, V0, SPL_IR_ARITH_ADD) \
+20 -4
View File
@@ -24,13 +24,17 @@ static usize ir_type_size(spl_ir2vm_t *ctx, spl_type_id_t tid) {
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;
usize payload_align = 1;
usize payload_size = 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;
if (vs > payload_align)
payload_align = vs;
if (vs > payload_size)
payload_size = vs;
}
return align_up(tag_sz, 8) + max_payload;
usize payload_off = align_up(tag_sz, payload_align);
return align_up(payload_off + payload_size, payload_align);
}
case SPL_TYPE_STRUCT:
case SPL_TYPE_UNION: {
@@ -102,6 +106,18 @@ static usize ir_agg_field_off(spl_ir2vm_t *ctx, spl_type_id_t tid, usize idx) {
}
if (tn->kind == SPL_TYPE_ARRAY)
return idx * ir_type_size(ctx, tn->array_type.element);
if (tn->kind == SPL_TYPE_ENUM) {
if (idx == 0)
return 0;
usize tag_sz = ir_type_size(ctx, tn->agg_type.tag_type);
usize payload_align = 1;
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 > payload_align)
payload_align = vs;
}
return align_up(tag_sz, payload_align);
}
return 0;
}
+4 -2
View File
@@ -371,6 +371,8 @@ spl_lang_type_id_t spl_lang_make_fn(spl_lang_type_t *type, spl_lang_type_id_t re
spl_lang_type_id_t spl_lang_make_aggregate(spl_lang_type_t *type, spl_lang_type_kind_t kind,
const char *name, const spl_lang_type_id_t *members_lang,
usize nmembers) {
(void)name; // TODO
spl_type_node_kind_t tk;
switch (kind) {
case SPL_LANG_TYPE_STRUCT:
@@ -662,7 +664,7 @@ static void spl_lang_type_dump_rec(spl_lang_type_t *type, spl_lang_type_id_t id,
spl_lang_type_node_t *n = spl_lang_type_node(type, id);
if (!n) {
printf("none");
vec_pop(*stack);
(void)vec_pop(*stack);
return;
}
switch (n->kind) {
@@ -748,7 +750,7 @@ static void spl_lang_type_dump_rec(spl_lang_type_t *type, spl_lang_type_id_t id,
break;
}
vec_pop(*stack);
(void)vec_pop(*stack);
}
void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) {
+38 -21
View File
@@ -252,6 +252,30 @@ static int can_start_statement(spl_tok_type_t t) {
}
}
static int is_builtin_type_kw(spl_tok_type_t t) {
switch (t) {
// case KW_I8:
// case KW_U8:
// case KW_I16:
// case KW_U16:
// case KW_I32:
// case KW_U32:
// case KW_I64:
// case KW_U64:
// case KW_F32:
// case KW_F64:
// case KW_ISIZE:
// case KW_USIZE:
case KW_BOOL:
// case KW_VOID:
// case KW_PTR:
case KW_ANY:
return 1;
default:
return 0;
}
}
static spl_ast_node_ref_t parse_expr(spl_parser_t *p);
static spl_ast_node_ref_vec_t parse_expr_list(spl_parser_t *p);
static spl_ast_node_ref_t parse_block(spl_parser_t *p);
@@ -662,13 +686,12 @@ static spl_ast_node_ref_t parse_type_decl(spl_parser_t *p, spl_ast_node_ref_vec_
return 0;
advance(p);
const spl_tok_t *name = peek(p);
if (!name || name->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected type name");
spl_ast_node_ref_t pattern = parse_pattern(p);
if (!pattern) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, peek(p), "expected pattern after 'type'");
vec_free(tag_list);
return 0;
}
advance(p);
if (!expect(p, TOK_ASSIGN, "'=' in type declaration")) {
vec_free(tag_list);
@@ -678,9 +701,11 @@ static spl_ast_node_ref_t parse_type_decl(spl_parser_t *p, spl_ast_node_ref_vec_
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw);
spl_ast_node_t *td = node_at(p->ast, ref);
MOVE_VEC(td->type_decl.attr_list, tag_list);
SET_STR_FIELD(p->ast, td->type_decl.name, name);
td->type_decl.pattern = pattern;
spl_ast_node_ref_t type_expr = parse_type_expr(p);
node_at(p->ast, ref)->type_decl.type_expr = type_expr;
td = node_at(p->ast, ref); /* parse_type_expr 可能 push node_buckets,重新取 */
td->type_decl.type_expr = type_expr;
const spl_tok_t *t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON))
@@ -909,7 +934,8 @@ static spl_ast_node_ref_t parse_type_base(spl_parser_t *p) {
return ref;
}
if (bt->type == TOK_IDENT || bt->type == KW_BOOL) {
/* 内建类型 keyword + 普通标识符类型路径 */
if (bt->type == TOK_IDENT || is_builtin_type_kw(bt->type)) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt);
spl_ast_node_t *tp = node_at(p->ast, ref);
@@ -932,15 +958,6 @@ static spl_ast_node_ref_t parse_type_base(spl_parser_t *p) {
if (bt->type == TOK_AT || bt->type == TOK_SHARP)
return parse_type_comptime_call(p);
if (bt->type == KW_ANY) {
advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt);
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);
return ref;
}
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, bt, "unrecognized type");
return 0;
}
@@ -1950,8 +1967,6 @@ static spl_ast_node_ref_t parse_match_expr(spl_parser_t *p) {
if (!expect(p, TOK_RIGHT_FAT_ARROW, "'=>' in match arm"))
break;
if (!expect(p, TOK_L_BRACE, "'{' in match arm body"))
break;
spl_ast_node_ref_t body = parse_block(p);
vec_push(patterns, pat);
@@ -2164,8 +2179,12 @@ static spl_ast_node_ref_t parse_block(spl_parser_t *p) {
block = node_at(p->ast, ref);
if (stmt)
vec_push(block->block.stmts, stmt);
else
break;
} else if (can_start_expr(t->type)) {
spl_ast_node_ref_t expr = parse_expr(p);
if (!expr)
break;
block = node_at(p->ast, ref);
t = peek(p);
if (t && t->type == TOK_SEMICOLON) {
@@ -2218,12 +2237,10 @@ static void skip_to_sync(spl_parser_t *p) {
const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF)
return;
if (t->type == TOK_SEMICOLON) {
if (t->type == TOK_SEMICOLON || t->type == TOK_R_BRACE) {
advance(p);
return;
}
if (t->type == TOK_R_BRACE)
return;
advance(p);
}
}
+398 -113
View File
@@ -97,11 +97,14 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n,
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in);
static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id);
static spl_lang_type_id_t sema_infer_fn_signature(spl_sema_t *sema, spl_ast_node_t *n);
static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) {
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid);
return n && n->kind == SPL_LANG_TYPE_INFER;
}
static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
spl_lang_type_id_t matched_tid);
static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_node_t *pat,
spl_ast_node_ref_t type_expr_ref);
static void sema_type_unpack_walk(spl_sema_t *sema, spl_ast_node_t *pat,
spl_lang_type_id_t src_lang);
static void sema_type_unpack_one(spl_sema_t *sema, spl_ast_node_t *pat, const char *name,
spl_lang_type_id_t src_lang);
static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir) {
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
@@ -112,6 +115,15 @@ static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir)
return 0;
}
static spl_lang_type_kind_t sema_lang_kind(spl_sema_t *sema, spl_lang_type_id_t tid) {
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid);
return n ? n->kind : SPL_LANG_TYPE_ERROR;
}
static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) {
return sema_lang_kind(sema, tid) == SPL_LANG_TYPE_INFER;
}
static void sema_type_to_str(spl_sema_t *sema, spl_lang_type_id_t tid, char *buf, usize cap) {
if (!buf || cap == 0)
return;
@@ -311,19 +323,34 @@ static spl_lang_type_id_t sema_build_aggregate(spl_sema_t *sema, spl_ast_node_t
.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, sema->ast, mref);
mn->resolved_def_id = fn_def;
spl_def_id_t fn_def = mn->resolved_def_id;
if (!fn_def) {
fn_def = spl_def_alloc(sema->type, SPL_DEF_FN, mn->fn_decl.name, mn->dbg, sema->ast,
mref);
mn->resolved_def_id = fn_def;
}
spl_def_node_t *fn_d = spl_def_node(sema->type, fn_def);
if (fn_d)
fn_d->owner_def = owner_def_id;
spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def};
vec_push(methods, meth);
} else if (mn->kind == SPL_AST_TYPE_DECL) {
spl_def_id_t tdef = mn->resolved_def_id;
if (!tdef)
spl_ast_node_t *tpat = spl_ast_node(sema->ast, mn->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_lang_method_t meth = {.name = mn->type_decl.name, .def_id = tdef};
const char *tname = tpat->pattern_ident.name;
spl_def_id_t tdef = mn->resolved_def_id;
if (!tdef) {
spl_ast_node_kind_t tek =
mn->type_decl.type_expr ? spl_ast_node(sema->ast, mn->type_decl.type_expr)->kind
: 0;
spl_def_node_kind_t dk =
(tek == SPL_AST_TYPE_AGGREGATE) ? SPL_DEF_AGG : SPL_DEF_SCALAR;
tdef = spl_def_alloc(sema->type, dk, tname, mn->dbg, sema->ast, mref);
mn->resolved_def_id = tdef;
}
spl_lang_method_t meth = {.name = tname, .def_id = tdef};
vec_push(methods, meth);
}
}
@@ -402,15 +429,19 @@ static spl_lang_type_id_t sema_build_container_aggregate(spl_sema_t *sema, spl_a
spl_def_id_t tdef = d->resolved_def_id;
if (!tdef)
continue;
spl_lang_method_t meth = {.name = d->type_decl.name, .def_id = tdef};
spl_ast_node_t *tpat = spl_ast_node(sema->ast, d->type_decl.pattern);
if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_lang_method_t meth = {.name = tpat->pattern_ident.name, .def_id = tdef};
vec_push(methods, meth);
} else if (d->kind == SPL_AST_VAR_DECL || d->kind == SPL_AST_CONST_DECL) {
spl_def_id_t vdef = d->resolved_def_id;
if (!vdef)
continue;
/* def_id 现在挂在 pattern 上,不在 VAR_DECL 节点上 */
spl_ast_node_t *pat = spl_ast_node(sema->ast, d->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
continue;
spl_def_id_t vdef = pat->resolved_def_id;
if (!vdef)
continue;
spl_lang_method_t meth = {.name = pat->pattern_ident.name, .def_id = vdef};
vec_push(methods, meth);
}
@@ -550,6 +581,9 @@ static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id)
if (n) {
switch (n->kind) {
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
break;
if (n->type_decl.type_expr) {
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
@@ -628,21 +662,28 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
break;
}
case SPL_AST_TYPE_DECL: {
spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE};
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat)
return;
if (pat->kind != SPL_AST_PATTERN_IDENT)
return; /* 解包由 sema_collect_types 处理 */
const char *name = pat->pattern_ident.name;
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"type declaration `%s` missing type expression", n->type_decl.name);
"type declaration `%s` missing type expression", name);
return;
}
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_TYPE};
if (te->kind == SPL_AST_TYPE_AGGREGATE)
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, sema->ast, ref);
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, name, te->dbg, sema->ast, ref);
else
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, sema->ast, ref);
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, name, te->dbg, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", sym.name);
"duplicate symbol `%s`", name);
}
break;
}
@@ -659,18 +700,20 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (pat && pat->kind == SPL_AST_PATTERN_IDENT) {
const char *name = pat->pattern_ident.name;
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
} else {
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"unsupported variable pattern (only simple identifier)");
"container-level var only supports simple identifier; "
"move destructuring into a function body");
break;
}
const char *name = pat->pattern_ident.name;
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, sema->ast, ref);
/* def_id 挂在 pattern 的 ident 上,不在 VAR_DECL 节点上 */
pat->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
break;
}
@@ -692,8 +735,17 @@ static void sema_collect_types(spl_sema_t *sema, spl_ast_node_ref_t ref) {
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
spl_ast_node_ref_t dref = vec_at(n->container_members.declarations, i);
spl_ast_node_t *d = spl_ast_node(sema->ast, dref);
if (d && d->kind == SPL_AST_TYPE_DECL && d->resolved_def_id)
sema_eval_decl(sema, d->resolved_def_id);
if (!d || d->kind != SPL_AST_TYPE_DECL)
continue;
spl_ast_node_t *pat = spl_ast_node(sema->ast, d->type_decl.pattern);
if (!pat)
continue;
if (pat->kind == SPL_AST_PATTERN_IDENT) {
if (d->resolved_def_id)
sema_eval_decl(sema, d->resolved_def_id);
} else {
sema_do_type_unpack(sema, d, pat, d->type_decl.type_expr);
}
}
break;
case SPL_AST_TOP_LEVEL_BLOCK:
@@ -833,6 +885,23 @@ static spl_lang_type_id_t sema_block_body(spl_sema_t *sema, spl_ast_node_t *n,
return r;
}
static bool sema_pattern_is_literal(spl_ast_node_kind_t k) {
switch (k) {
case SPL_AST_EXPR_INT_LIT:
case SPL_AST_EXPR_FLOAT_LIT:
case SPL_AST_EXPR_CHAR_LIT:
case SPL_AST_EXPR_STRING_LIT:
case SPL_AST_EXPR_BOOL_LIT:
case SPL_AST_EXPR_NULL_LIT:
return true;
default:
return false;
}
}
/* 把 matched_tid 的绑定按 pattern 结构插进当前 scope。
调用前必须已经 push_scope。
约定:PATTERN_DOT 用 resolved_def_id = variant_idx + 1 保存变体位置。 */
static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
spl_lang_type_id_t matched_tid) {
if (!pat_ref)
@@ -841,9 +910,24 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
if (!pat)
return;
if (sema_pattern_is_literal(pat->kind)) {
spl_lang_type_id_t lt = sema_infer(sema, pat_ref);
if (lt && matched_tid)
sema_coerce(sema, pat_ref, matched_tid);
return;
}
switch (pat->kind) {
case SPL_AST_PATTERN_IDENT: {
const char *name = pat->pattern_ident.name;
if (!name || strcmp(name, "_") == 0)
return;
/* 容器级 var 已在 collect_names 阶段分配 def_id,这里只回填 lang。 */
if (pat->resolved_def_id) {
spl_def_resolve(sema->type, pat->resolved_def_id, matched_tid);
pat->resolved_lang_tid = matched_tid;
return;
}
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, pat->dbg, sema->ast, pat_ref);
spl_def_resolve(sema->type, sym.node, matched_tid);
@@ -859,11 +943,17 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
case SPL_AST_PATTERN_UNDERSCORE:
return;
case SPL_AST_PATTERN_LIST: {
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), matched_tid);
return;
}
case SPL_AST_PATTERN_TUPLE: {
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, matched_tid);
if (!tn || tn->kind != SPL_LANG_TYPE_TUPLE) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"tuple pattern requires a tuple value");
"tuple pattern requires tuple value");
return;
}
usize natoms = vec_size(pat->pattern_tuple.patterns);
@@ -873,7 +963,6 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
"tuple pattern arity mismatch (expected %zu, got %zu)", nelems, natoms);
return;
}
/* 递归 bind 会 push lang_table,tn 会悬垂;先把元素类型拷到本地 */
spl_lang_type_id_vec_t elem_tids;
vec_init(elem_tids);
for (usize i = 0; i < nelems; ++i)
@@ -885,13 +974,245 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
return;
}
case SPL_AST_PATTERN_DOT:
case SPL_AST_PATTERN_AGGREGATE:
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"pattern kind %d not yet supported", (int)pat->kind);
case SPL_AST_PATTERN_DOT: {
spl_lang_type_node_t *mn = spl_lang_type_node(sema->type, matched_tid);
if (!mn || mn->kind != SPL_LANG_TYPE_ENUM) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"variant pattern requires enum value");
return;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, matched_tid);
usize idx = 0;
if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, pat->pattern_dot.name, &idx)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &pat->dbg, "no variant `%s` in enum",
pat->pattern_dot.name);
return;
}
spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir);
if (!irn || idx >= vec_size(irn->agg_type.variants))
return;
spl_lang_type_id_t payload_lang =
sema_lang_from_ir(sema, vec_at(irn->agg_type.variants, idx).type_id);
pat->resolved_def_id = idx + 1;
pat->resolved_lang_tid = matched_tid;
if (pat->pattern_dot.sub_pattern && payload_lang)
sema_bind_pattern(sema, pat->pattern_dot.sub_pattern, payload_lang);
return;
}
case SPL_AST_PATTERN_AGGREGATE: {
spl_lang_type_node_t *an = spl_lang_type_node(sema->type, matched_tid);
if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION &&
an->kind != SPL_LANG_TYPE_ENUM)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"aggregate pattern requires struct or enum value");
return;
}
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, matched_tid);
usize nfields = vec_size(pat->pattern_aggregate.fields);
if (an->kind == SPL_LANG_TYPE_ENUM && nfields != 1) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"enum pattern must have exactly one variant");
return;
}
for (usize i = 0; i < nfields; ++i) {
spl_ast_node_t *f = spl_ast_node(sema->ast, vec_at(pat->pattern_aggregate.fields, i));
if (!f || f->kind != SPL_AST_PATTERN_FIELD)
continue;
usize idx = 0;
if (!spl_type_agg_member_idx(&sema->type->ir, agg_ir, f->pattern_field.name, &idx)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &f->dbg, "no field `%s`",
f->pattern_field.name);
continue;
}
spl_type_node_t *irn = spl_type_node(&sema->type->ir, agg_ir);
if (!irn || idx >= vec_size(irn->agg_type.variants))
continue;
spl_lang_type_id_t ft =
sema_lang_from_ir(sema, vec_at(irn->agg_type.variants, idx).type_id);
f->resolved_def_id = idx;
if (f->pattern_field.pattern && ft)
sema_bind_pattern(sema, f->pattern_field.pattern, ft);
}
pat->resolved_lang_tid = matched_tid;
return;
}
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"pattern kind %d not supported", (int)pat->kind);
return;
}
}
/* type 解包:把容器 struct 的 methods 里的名字引入当前 scope。
语法层由 pattern 承载,语义层在这里分派。
约束:
- 源类型必须是 LANG_TYPE_STRUCT 且 agg_type.variants 为空
(即 @import 返回的容器 struct,不是普通带字段的 struct)
- PATTERN_DOT 不允许有 sub_pattern(编译期没有 payload 概念)
- PATTERN_FIELD 不允许带 sub pattern(同上)
- 不做递归导出,显式即所得 */
static void sema_type_unpack_one(spl_sema_t *sema, spl_ast_node_t *pat, const char *name,
spl_lang_type_id_t src_lang) {
if (!name)
return;
spl_lang_type_node_t *src = spl_lang_type_node(sema->type, src_lang);
if (!src)
return;
for (usize i = 0; i < vec_size(src->methods); ++i) {
spl_lang_method_t *m = &vec_at(src->methods, i);
if (strcmp(m->name, name) != 0)
continue;
spl_def_node_t *d = spl_def_node(sema->type, m->def_id);
spl_symbol_kind_t k = SPL_SYMBOL_KIND_VAR;
if (d) {
switch (d->kind) {
case SPL_DEF_FN:
k = SPL_SYMBOL_KIND_FN;
break;
case SPL_DEF_AGG:
case SPL_DEF_SCALAR:
case SPL_DEF_DISTINCT:
case SPL_DEF_ALIAS:
case SPL_DEF_BUILTIN:
k = SPL_SYMBOL_KIND_TYPE;
break;
default:
k = SPL_SYMBOL_KIND_VAR;
break;
}
}
spl_symbol_t sym = {.name = name, .kind = k, .node = m->def_id};
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &pat->dbg,
"type unpack: duplicate symbol `%s`", name);
}
pat->resolved_def_id = m->def_id;
return;
}
spl_diag_error(sema->diag, SPL_DIAG_KIND_NO_FIELD, &pat->dbg,
"type unpack: no symbol `%s` in source container", name);
}
static void sema_type_unpack_walk(spl_sema_t *sema, spl_ast_node_t *pat,
spl_lang_type_id_t src_lang) {
if (!pat)
return;
switch (pat->kind) {
case SPL_AST_PATTERN_UNDERSCORE:
return;
case SPL_AST_PATTERN_DOT:
if (pat->pattern_dot.sub_pattern) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"type unpack: payload pattern not allowed in compile-time unpack");
return;
}
sema_type_unpack_one(sema, pat, pat->pattern_dot.name, src_lang);
return;
case SPL_AST_PATTERN_AGGREGATE:
for (usize i = 0; i < vec_size(pat->pattern_aggregate.fields); ++i) {
spl_ast_node_t *f = spl_ast_node(sema->ast, vec_at(pat->pattern_aggregate.fields, i));
if (!f || f->kind != SPL_AST_PATTERN_FIELD)
continue;
if (f->pattern_field.pattern) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &f->dbg,
"type unpack: field pattern not allowed");
continue;
}
sema_type_unpack_one(sema, f, f->pattern_field.name, src_lang);
}
return;
case SPL_AST_PATTERN_LIST:
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i) {
spl_ast_node_t *sub = spl_ast_node(sema->ast, vec_at(pat->pattern_list.patterns, i));
sema_type_unpack_walk(sema, sub, src_lang);
}
return;
case SPL_AST_PATTERN_IDENT:
/* collect_names 已分派,不应到这里 */
return;
default:
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg,
"type unpack: unsupported pattern kind %d", (int)pat->kind);
return;
}
}
static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_node_t *pat,
spl_ast_node_ref_t type_expr_ref) {
if (!type_expr_ref) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack missing source type expression");
return;
}
spl_lang_type_id_t src_lang = sema_infer(sema, type_expr_ref);
if (!src_lang)
return;
spl_lang_type_node_t *src = spl_lang_type_node(sema->type, src_lang);
if (!src)
return;
if (src->kind != SPL_LANG_TYPE_STRUCT) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source must be a container struct");
return;
}
spl_type_id_t src_ir = spl_lang_type_get_ir_type(sema->type, src_lang);
spl_type_node_t *irn = spl_type_node(&sema->type->ir, src_ir);
if (!irn) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source IR unresolved");
return;
}
if (vec_size(irn->agg_type.variants) != 0) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg,
"type unpack source has fields; only container struct allowed");
return;
}
sema_type_unpack_walk(sema, pat, src_lang);
}
/* var / const / if-var 共用的初始化推导 + bind。
当前 scope 必须已经是 bind 目标 scope(调用者负责 push)。 */
static spl_lang_type_id_t sema_var_body(spl_sema_t *sema, spl_ast_node_t *n) {
spl_lang_type_id_t decl_tid = 0;
if (n->var_const_decl.type)
decl_tid = sema_infer(sema, n->var_const_decl.type);
if (!n->var_const_decl.init_expr) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_VAR_UNINITIALIZED, &n->dbg,
"variable must be initialized");
return 0;
}
if (decl_tid) {
if (!sema_coerce(sema, n->var_const_decl.init_expr, decl_tid))
return 0;
} else {
decl_tid = sema_infer(sema, n->var_const_decl.init_expr);
if (!decl_tid || sema_is_infer(sema, decl_tid)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_CANNOT_INFER, &n->dbg,
"cannot infer variable type");
return 0;
}
}
sema_bind_pattern(sema, n->var_const_decl.pattern, decl_tid);
n->resolved_lang_tid = decl_tid;
return decl_tid;
}
static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref,
@@ -1842,9 +2163,15 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_EXPR_IFVAR: {
sema_infer(sema, n->ifvar_expr.var_decl);
if (!n->ifvar_expr.var_decl)
return 0;
spl_ast_node_t *vd = spl_ast_node(sema->ast, n->ifvar_expr.var_decl);
sema_push_scope(sema);
sema_var_body(sema, vd);
if (n->ifvar_expr.then_block)
sema_infer(sema, n->ifvar_expr.then_block);
sema_pop_scope(sema);
/* else 在 pattern scope 之外:绑定名在 else 不可见 */
if (n->ifvar_expr.else_branch)
sema_infer(sema, n->ifvar_expr.else_branch);
return 0;
@@ -1865,7 +2192,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->while_expr.else_branch)
sema_infer(sema, n->while_expr.else_branch);
vec_pop(sema->label_stack);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_LOOP: {
@@ -1880,7 +2207,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->loop_expr.body)
sema_infer(sema, n->loop_expr.body);
vec_pop(sema->label_stack);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_FOR: {
@@ -1891,7 +2218,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
lbl = ln->label.name;
}
vec_push(sema->label_stack, lbl);
sema_push_scope(sema);
usize nsrc = vec_size(n->for_expr.iter_exprs);
@@ -1900,49 +2226,47 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (pat && pat->kind == SPL_AST_PATTERN_LIST) {
usize natoms = vec_size(pat->pattern_list.patterns);
for (usize i = 0; i < nsrc; ++i) {
spl_lang_type_id_t container_tid =
sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
if (i < natoms)
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), elem_tid);
}
if (natoms > nsrc) {
if (natoms != nsrc) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"for: pattern has %zu atoms but only %zu sources", natoms, nsrc);
"for: %zu pattern atoms but %zu sources", natoms, nsrc);
}
for (usize i = 0; i < nsrc && i < natoms; ++i) {
spl_lang_type_id_t ct = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
spl_lang_type_id_t et = sema_for_elem_type(sema, ct);
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), et);
}
} else {
for (usize i = 0; i < nsrc; ++i) {
spl_lang_type_id_t container_tid =
sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
if (i == 0 && pat_ref) {
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
sema_bind_pattern(sema, pat_ref, elem_tid);
}
}
if (nsrc > 1 && pat_ref) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
if (nsrc > 1) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"for: multiple sources require pattern list");
}
for (usize i = 0; i < nsrc; ++i) {
spl_lang_type_id_t ct = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
if (i == 0)
sema_bind_pattern(sema, pat_ref, sema_for_elem_type(sema, ct));
}
}
if (n->for_expr.body)
sema_infer(sema, n->for_expr.body);
if (n->for_expr.else_branch)
sema_infer(sema, n->for_expr.else_branch);
sema_pop_scope(sema);
vec_pop(sema->label_stack);
sema_pop_scope(sema);
(void)vec_pop(sema->label_stack);
return 0;
}
case SPL_AST_EXPR_MATCH: {
sema_infer(sema, n->match_expr.matched_expr);
spl_lang_type_id_t matched = sema_infer(sema, n->match_expr.matched_expr);
for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) {
spl_ast_node_t *arm = spl_ast_node(sema->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
sema_infer(sema, arm->match_arm.pattern);
if (!arm || arm->kind != SPL_AST_MATCH_ARM)
continue;
sema_push_scope(sema);
sema_bind_pattern(sema, arm->match_arm.pattern, matched);
if (arm->match_arm.body)
sema_infer(sema, arm->match_arm.body);
}
sema_pop_scope(sema);
}
return 0;
}
@@ -2114,6 +2438,9 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_TYPE_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->type_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
return 0;
if (!n->type_decl.type_expr)
break;
spl_def_node_t *def =
@@ -2139,50 +2466,8 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
}
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"unsupported variable pattern");
return 0;
}
const char *name = pat->pattern_ident.name;
if (n->resolved_def_id == 0) {
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, sema->ast, ref);
n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", name);
}
}
spl_lang_type_id_t decl_tid = 0;
if (n->var_const_decl.type)
decl_tid = sema_infer(sema, n->var_const_decl.type);
if (!n->var_const_decl.init_expr) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_VAR_UNINITIALIZED, &n->dbg,
"variable `%s` must be initialized", name);
return 0;
}
if (decl_tid) {
sema_coerce(sema, n->var_const_decl.init_expr, decl_tid);
} else {
decl_tid = sema_infer(sema, n->var_const_decl.init_expr);
if (!decl_tid || sema_is_infer(sema, decl_tid)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_CANNOT_INFER, &n->dbg,
"cannot infer type of `%s`", name);
return 0;
}
}
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
n->resolved_lang_tid = decl_tid;
return decl_tid;
}
case SPL_AST_CONST_DECL:
return sema_var_body(sema, n);
case SPL_AST_MEMBER_DECL:
if (n->member_decl.type_expr)
+2 -2
View File
@@ -221,7 +221,7 @@ static void spl_type_pure_dump_rec(spl_type_t *type, spl_type_id_t id, spl_type_
spl_type_node_t *n = spl_type_node(type, id);
if (!n) {
printf("none");
vec_pop(*stack);
(void)vec_pop(*stack);
return;
}
switch (n->kind) {
@@ -301,7 +301,7 @@ static void spl_type_pure_dump_rec(spl_type_t *type, spl_type_id_t id, spl_type_
break;
}
vec_pop(*stack);
(void)vec_pop(*stack);
}
void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) {