Compare commits

..
3 Commits
12 changed files with 945 additions and 261 deletions

No files matched your search

+1 -1
View File
@@ -32,7 +32,7 @@ VarDecl = { DeclHeader ~ KEYWORD_var ~ VarBody }
ConstDecl = { DeclHeader ~ KEYWORD_const ~ VarBody } ConstDecl = { DeclHeader ~ KEYWORD_const ~ VarBody }
VarBody = { Pattern ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? } 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)? } MemberDecl = { DeclHeader ~ IDENTIFIER ~ (COLON ~ TypeExpr)? ~ (EQUAL ~ Expr)? }
+72 -30
View File
@@ -272,33 +272,71 @@ static bool test_once_with_dump(const char *fname, void *user_data) {
return nob_cmd_run(&cmd); 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); 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) { typedef struct {
const char *test_folder = "./tests/stage1/"; Nob_Files *files;
test_fn_t test_once;
void *user_data;
} test_walk_ctx_t;
if (!prepare_build()) { static bool test_walk_entry(Nob_Walk_Entry entry) {
return 1; if (entry.type != NOB_FILE_REGULAR)
} return true;
Nob_File_Paths paths = {0}; const char *dot = strrchr(entry.path, '.');
nob_read_entire_dir(test_folder, &paths); if (!dot || strcmp(dot, ".spl") != 0)
for (int i = 0; i < files->count; i += 1) { return true;
for (int j = 0; j < paths.count; j += 1) {
String_View sv = sv_from_cstr(paths.items[j]); test_walk_ctx_t *ctx = (test_walk_ctx_t *)entry.data;
// printf("--- test " SV_Fmt " ---\n", SV_Arg(sv)); bool run_all = (ctx->files->count == 0);
if (!strstr(paths.items[j], files->items[i])) { bool matched = run_all;
continue; for (int i = 0; !matched && i < ctx->files->count; i += 1) {
} if (strstr(entry.path, ctx->files->items[i]))
const char *tname = nob_temp_sprintf("%s%s", test_folder, paths.items[j]); matched = true;
printf("--- test %s ---\n", tname);
if (test_once(tname, user_data) == false)
return false;
}
} }
if (!matched)
return true;
printf("--- test %s ---\n", entry.path);
if (ctx->test_once(entry.path, ctx->user_data) == false)
return false;
return true; return true;
} }
static bool run_test(const char *stage, Nob_Files *files, test_fn_t test_once, void *user_data) {
const char *test_folder = stage_dir_of(stage);
if (!prepare_build())
return false;
if (!nob_file_exists(test_folder)) {
nob_log(NOB_INFO, "%s does not exist, skip", test_folder);
return true;
}
test_walk_ctx_t ctx = {
.files = files,
.test_once = test_once,
.user_data = user_data,
};
return nob_walk_dir(test_folder, test_walk_entry, .data = &ctx);
}
static bool delete_walk_entry(Nob_Walk_Entry entry) { return nob_delete_file(entry.path); } static bool delete_walk_entry(Nob_Walk_Entry entry) { return nob_delete_file(entry.path); }
static bool delete_directory_recursively(const char *dir_path) { static bool delete_directory_recursively(const char *dir_path) {
@@ -372,33 +410,37 @@ int main(int argc, char **argv) {
} }
if (strcmp(command_name, "test") == 0) { if (strcmp(command_name, "test") == 0) {
Nob_Files files = {0}; // 1. stage(可选,默认 stage1)
const char *stage = "stage1";
if (argc > 0 && is_stage_name(argv[0])) {
stage = nob_shift(argv, argc);
}
// 2. mode(可选)
test_fn_t tfn = test_once; test_fn_t tfn = test_once;
const char *mode_name = NULL; const char *mode_name = NULL;
if (argc > 0) { if (argc > 0) {
mode_name = nob_shift(argv, argc); if (is_dump_mode(argv[0])) {
if (strcmp(mode_name, "lex") == 0 || strcmp(mode_name, "ast") == 0 ||
strcmp(mode_name, "sema") == 0 || strcmp(mode_name, "ir") == 0 ||
strcmp(mode_name, "vm") == 0) {
tfn = test_once_with_dump; tfn = test_once_with_dump;
} else if (strcmp(mode_name, "run") == 0) { mode_name = nob_shift(argv, argc);
// HACK } else if (strcmp(argv[0], "run") == 0) {
nob_shift(argv, argc);
// HACK:只对 stage1 有意义,跑上次生成的 build/test.sir
Nob_Cmd cmd = {0}; Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, BUILD_FOLDER "spl_cli", "-d"); nob_cmd_append(&cmd, BUILD_FOLDER "spl_cli", "-d");
nob_cmd_append(&cmd, BUILD_FOLDER "test.sir"); nob_cmd_append(&cmd, BUILD_FOLDER "test.sir");
return nob_cmd_run(&cmd) ? 0 : 1; return nob_cmd_run(&cmd) ? 0 : 1;
} else {
da_append(&files, mode_name);
} }
} }
// 3. 剩下的都当 pattern
Nob_Files files = {0};
while (argc > 0) { while (argc > 0) {
da_append(&files, nob_shift(argv, argc)); da_append(&files, nob_shift(argv, argc));
} }
return run_test(&files, tfn, (void *)mode_name) ? 0 : 1; return run_test(stage, &files, tfn, (void *)mode_name) ? 0 : 1;
} }
if (strcmp(command_name, "clean") == 0) { if (strcmp(command_name, "clean") == 0) {
if (nob_file_exists(BUILD_FOLDER)) { if (nob_file_exists(BUILD_FOLDER)) {
if (!delete_directory_recursively(BUILD_FOLDER)) if (!delete_directory_recursively(BUILD_FOLDER))
+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; break;
case SPL_AST_TYPE_DECL: 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) if (node->type_decl.type_expr)
dump_node(ast, node->type_decl.type_expr, stack, true); dump_node(ast, node->type_decl.type_expr, stack, true);
break; break;
+1 -1
View File
@@ -184,7 +184,7 @@ struct spl_ast_node {
struct { struct {
spl_ast_node_ref_vec_t attr_list; spl_ast_node_ref_vec_t attr_list;
const char *name; spl_ast_node_ref_t pattern;
spl_ast_node_ref_t type_expr; spl_ast_node_ref_t type_expr;
} type_decl; } type_decl;
+380 -69
View File
@@ -28,7 +28,33 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n);
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_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 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_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
/* Emit one exit path without consuming the lexical registrations needed by
* sibling paths. A private stack also allows cleanup bodies to register defer. */
static void emit_deferred_until(spl_ast2ir_t *a, usize base) {
if (vec_size(a->defer_stack) <= base)
return;
spl_defer_stack_t saved = a->defer_stack;
vec_init(a->defer_stack);
for (usize i = 0; i < vec_size(saved); ++i)
vec_push(a->defer_stack, vec_at(saved, i));
while (!a->ir->terminated && vec_size(a->defer_stack) > base) {
spl_ast_node_ref_t body = vec_pop(a->defer_stack);
emit_stmt(a, body);
}
vec_free(a->defer_stack);
a->defer_stack = saved;
}
static void emit_decl(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_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_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); static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
@@ -111,6 +137,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) { 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) if (!ir_ref || !n || vec_size(n->attrs) == 0)
return; return;
@@ -843,7 +1044,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); item->struct_init_item.name);
spl_type_id_t tag_ir = tn->agg_type.tag_type; 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)); spl_ir_node_ref_t eptr = spl_ir_builder_mem_alloca(a->ir, t, const_usize(a, 1));
@@ -852,11 +1052,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_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_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); if (item->struct_init_item.expr) {
spl_ir_node_ref_t payload = emit_expr(a, item->struct_init_item.expr); spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id;
if (!payload) spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, t, eptr, vidx + 1);
Panic("enum payload emit failed"); spl_ir_node_ref_t payload = emit_expr(a, item->struct_init_item.expr);
spl_ir_builder_mem_store(a->ir, payload_ir, pptr, payload); if (!payload)
Panic("enum payload emit failed");
spl_ir_builder_mem_store(a->ir, payload_ir, pptr, payload);
}
return eptr; return eptr;
} }
@@ -922,18 +1125,131 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
return node; return node;
} }
case SPL_AST_EXPR_BLOCK: { case SPL_AST_EXPR_BLOCK: {
for (usize i = 0; i < vec_size(n->block.stmts); ++i) usize defer_base = vec_size(a->defer_stack);
for (usize i = 0; i < vec_size(n->block.stmts) && !a->ir->terminated; ++i)
emit_stmt(a, vec_at(n->block.stmts, i)); emit_stmt(a, vec_at(n->block.stmts, i));
if (n->block.tail_expr) spl_ir_node_ref_t value = 0;
return emit_expr(a, n->block.tail_expr); if (!a->ir->terminated && n->block.tail_expr)
return 0; value = emit_expr(a, n->block.tail_expr);
if (!a->ir->terminated)
emit_deferred_until(a, defer_base);
a->defer_stack.size = defer_base;
return value;
} }
case SPL_AST_EXPR_IF: case SPL_AST_EXPR_IF:
case SPL_AST_EXPR_IFVAR: case SPL_AST_EXPR_IFVAR:
return emit_if_like(a, ref); 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_WHILE:
case SPL_AST_EXPR_LOOP: case SPL_AST_EXPR_LOOP:
return emit_loop_like(a, ref); 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: { case SPL_AST_EXPR_SLICE: {
spl_ast_node_t *obj = spl_ast_node(a->ast, n->slice.obj); spl_ast_node_t *obj = spl_ast_node(a->ast, n->slice.obj);
spl_lang_type_id_t obj_lang = node_lang(a, obj); spl_lang_type_id_t obj_lang = node_lang(a, obj);
@@ -1041,13 +1357,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; spl_ast_node_ref_t else_ref = 0;
if (is_ifvar) { 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); spl_ast_node_t *vd = spl_ast_node(a->ast, n->ifvar_expr.var_decl);
if (!vd || !vd->var_const_decl.init_expr) if (!vd)
Panic("ifvar requires initializer"); Panic("ifvar missing var_decl");
spl_ir_node_ref_t slot = 0; spl_ir_node_ref_t slot = emit_var_decl(a, vd);
if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot)) if (!slot)
Panic("ifvar var slot not found"); Panic("ifvar var_decl emit failed");
cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot); cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot);
then_ref = n->ifvar_expr.then_block; then_ref = n->ifvar_expr.then_block;
else_ref = n->ifvar_expr.else_branch; else_ref = n->ifvar_expr.else_branch;
@@ -1132,6 +1447,7 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
spl_loop_ctx_t ctx = {0}; spl_loop_ctx_t ctx = {0};
ctx.cont_blk = cont_blk; ctx.cont_blk = cont_blk;
ctx.defer_base = vec_size(a->defer_stack);
ctx.label = NULL; ctx.label = NULL;
ctx.result_slot = result_slot; ctx.result_slot = result_slot;
ctx.result_tid = result_t; ctx.result_tid = result_t;
@@ -1172,7 +1488,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) 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); spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk);
vec_free(top->breaks); vec_free(top->breaks);
vec_pop(a->loop_stack); (void)vec_pop(a->loop_stack);
if (!result_slot) if (!result_slot)
return 0; return 0;
@@ -1190,29 +1506,34 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) {
lbl = ln->label.name; lbl = ln->label.name;
} }
spl_loop_ctx_t *target = NULL; usize target_index = vec_size(a->loop_stack);
if (lbl) { if (lbl) {
for (usize i = vec_size(a->loop_stack); i > 0; --i) { for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1); spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) { if (c->label && strcmp(c->label, lbl) == 0) {
target = c; target_index = i - 1;
break; break;
} }
} }
} else { } else {
target = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); target_index = vec_size(a->loop_stack) - 1;
} }
if (!target) if (target_index == vec_size(a->loop_stack))
return; return;
if (n->statement_break.expr && target->result_slot) { /* Emitting a value or a cleanup can grow/reallocate loop_stack. */
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
if (n->statement_break.expr && target.result_slot) {
spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr); spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr);
if (bv) if (bv)
spl_ir_builder_mem_store(a->ir, target->result_tid, target->result_slot, bv); spl_ir_builder_mem_store(a->ir, target.result_tid, target.result_slot, bv);
} }
emit_deferred_until(a, target.defer_base);
if (a->ir->terminated)
return;
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
vec_push(target->breaks, jmp); vec_push(vec_at(a->loop_stack, target_index).breaks, jmp);
} }
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) { static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
@@ -1228,12 +1549,10 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
if (n->statement_ret.expr) if (n->statement_ret.expr)
v = emit_expr(a, n->statement_ret.expr); v = emit_expr(a, n->statement_ret.expr);
while (vec_size(a->defer_stack) > a->cur_defer_base) { emit_deferred_until(a, a->cur_defer_base);
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
spl_ir_builder_control_ret(a->ir, ret_ir, v); if (!a->ir->terminated)
spl_ir_builder_control_ret(a->ir, ret_ir, v);
return; return;
} }
case SPL_AST_STATEMENT_DEFER: case SPL_AST_STATEMENT_DEFER:
@@ -1276,21 +1595,26 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
lbl = ln->label.name; lbl = ln->label.name;
} }
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir); usize target_index = vec_size(a->loop_stack) - 1;
if (lbl) { if (lbl) {
target_index = vec_size(a->loop_stack);
for (usize i = vec_size(a->loop_stack); i > 0; --i) { for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1); spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) { if (c->label && strcmp(c->label, lbl) == 0) {
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk); target_index = i - 1;
return; break;
} }
} }
return;
} }
if (target_index == vec_size(a->loop_stack))
return;
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk; spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont); emit_deferred_until(a, target.defer_base);
if (!a->ir->terminated) {
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
spl_ir_builder_control_jmp_fixup(a->ir, jmp, target.cont_blk);
}
return; return;
} }
case SPL_AST_EXPR_BLOCK: case SPL_AST_EXPR_BLOCK:
@@ -1309,32 +1633,11 @@ static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
switch (n->kind) { switch (n->kind) {
case SPL_AST_VAR_DECL: case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: { case SPL_AST_CONST_DECL:
if (!a->ir->current_fn) if (!a->ir->current_fn)
return; return;
if (!n->resolved_def_id) emit_var_decl(a, n);
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);
}
return; return;
}
default: default:
return; return;
} }
@@ -1344,6 +1647,13 @@ static void emit_fn_reserve(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (!n || !n->resolved_def_id) if (!n || !n->resolved_def_id)
return; 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_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); 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) if (!fn_ln || fn_ln->kind != SPL_LANG_TYPE_FN)
@@ -1415,12 +1725,10 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (n->fn_decl.body) if (n->fn_decl.body)
emit_expr(a, n->fn_decl.body); emit_expr(a, n->fn_decl.body);
if (!a->ir->terminated) { if (!a->ir->terminated)
while (vec_size(a->defer_stack) > defer_base) { emit_deferred_until(a, defer_base);
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
if (!a->ir->terminated) {
if (ret_is_unit) { if (ret_is_unit) {
spl_ir_builder_control_ret(a->ir, ret_ir, 0); spl_ir_builder_control_ret(a->ir, ret_ir, 0);
} else if (ret_ir) { } else if (ret_ir) {
@@ -1431,14 +1739,11 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
} }
} }
while (vec_size(a->defer_stack) > defer_base) { a->defer_stack.size = defer_base;
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
(void)d;
}
while (vec_size(a->loop_stack) > loop_base) { while (vec_size(a->loop_stack) > loop_base) {
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1); spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
vec_free(top->breaks); vec_free(top->breaks);
vec_pop(a->loop_stack); (void)vec_pop(a->loop_stack);
} }
a->cur_ret_lang = saved_ret; a->cur_ret_lang = saved_ret;
@@ -1500,6 +1805,9 @@ static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
emit_fn_reserve(a, d); emit_fn_reserve(a, d);
break; break;
case SPL_AST_TYPE_DECL: { 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); spl_ast_node_t *te = spl_ast_node(a->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE) if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_reserve(a, te); emit_aggregate_fns_reserve(a, te);
@@ -1536,6 +1844,9 @@ static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
emit_fn_body(a, d); emit_fn_body(a, d);
break; break;
case SPL_AST_TYPE_DECL: { 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); spl_ast_node_t *te = spl_ast_node(a->ast, d->type_decl.type_expr);
if (te && te->kind == SPL_AST_TYPE_AGGREGATE) if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
emit_aggregate_fns_body(a, te); emit_aggregate_fns_body(a, te);
+1
View File
@@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
typedef struct { typedef struct {
usize cont_blk; usize cont_blk;
usize defer_base;
const char *label; const char *label;
spl_ir_node_ref_vec_t breaks; spl_ir_node_ref_vec_t breaks;
spl_ir_node_ref_t result_slot; spl_ir_node_ref_t result_slot;
+1 -2
View File
@@ -2,11 +2,10 @@
#define __SPL_IR_H__ #define __SPL_IR_H__
#include "../stage0/include/utils.h" #include "../stage0/include/utils.h"
#include "spl_attr.h"
#include "spl_dbg.h" #include "spl_dbg.h"
#include "spl_type.h" #include "spl_type.h"
#include "spl_attr.h"
/* clang-format off */ /* clang-format off */
#define SPL_IR_FN_TABLE \ #define SPL_IR_FN_TABLE \
X(arith.add, V0, SPL_IR_ARITH_ADD) \ 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; return ir_type_size(ctx, tn->array_type.element) * tn->array_type.len;
case SPL_TYPE_ENUM: { case SPL_TYPE_ENUM: {
usize tag_sz = ir_type_size(ctx, tn->agg_type.tag_type); 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) { 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); usize vs = ir_type_size(ctx, vec_at(tn->agg_type.variants, i).type_id);
if (vs > max_payload) if (vs > payload_align)
max_payload = vs; 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_STRUCT:
case SPL_TYPE_UNION: { 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) if (tn->kind == SPL_TYPE_ARRAY)
return idx * ir_type_size(ctx, tn->array_type.element); 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; return 0;
} }
+7 -3
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, 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, const char *name, const spl_lang_type_id_t *members_lang,
usize nmembers) { usize nmembers) {
(void)name; // TODO
spl_type_node_kind_t tk; spl_type_node_kind_t tk;
switch (kind) { switch (kind) {
case SPL_LANG_TYPE_STRUCT: case SPL_LANG_TYPE_STRUCT:
@@ -631,8 +633,10 @@ spl_def_id_t spl_def_alloc(spl_lang_type_t *type, spl_def_node_kind_t kind, cons
void spl_def_resolve(spl_lang_type_t *type, spl_def_id_t id, spl_lang_type_id_t lang_id) { void spl_def_resolve(spl_lang_type_t *type, spl_def_id_t id, spl_lang_type_id_t lang_id) {
spl_def_node_t *d = spl_def_node(type, id); spl_def_node_t *d = spl_def_node(type, id);
if (d) if (d) {
d->lang_id = lang_id; d->lang_id = lang_id;
d->state = SPL_DECL_RESOLVED;
}
} }
spl_lang_type_id_t spl_def_get_lang_id(spl_lang_type_t *type, spl_def_id_t def_id) { spl_lang_type_id_t spl_def_get_lang_id(spl_lang_type_t *type, spl_def_id_t def_id) {
@@ -662,7 +666,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); spl_lang_type_node_t *n = spl_lang_type_node(type, id);
if (!n) { if (!n) {
printf("none"); printf("none");
vec_pop(*stack); (void)vec_pop(*stack);
return; return;
} }
switch (n->kind) { switch (n->kind) {
@@ -748,7 +752,7 @@ static void spl_lang_type_dump_rec(spl_lang_type_t *type, spl_lang_type_id_t id,
break; break;
} }
vec_pop(*stack); (void)vec_pop(*stack);
} }
void spl_lang_type_dump(spl_lang_type_t *type, spl_lang_type_id_t id) { 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_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_vec_t parse_expr_list(spl_parser_t *p);
static spl_ast_node_ref_t parse_block(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; return 0;
advance(p); advance(p);
const spl_tok_t *name = peek(p); spl_ast_node_ref_t pattern = parse_pattern(p);
if (!name || name->type != TOK_IDENT) { if (!pattern) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, name ? name : kw, "expected type name"); PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, peek(p), "expected pattern after 'type'");
vec_free(tag_list); vec_free(tag_list);
return 0; return 0;
} }
advance(p);
if (!expect(p, TOK_ASSIGN, "'=' in type declaration")) { if (!expect(p, TOK_ASSIGN, "'=' in type declaration")) {
vec_free(tag_list); 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_ref_t ref = new_node(p, SPL_AST_TYPE_DECL, kw);
spl_ast_node_t *td = node_at(p->ast, ref); spl_ast_node_t *td = node_at(p->ast, ref);
MOVE_VEC(td->type_decl.attr_list, tag_list); 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); 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); const spl_tok_t *t = peek(p);
if (t && (t->type == TOK_COMMA || t->type == TOK_SEMICOLON)) 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; 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); advance(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt); spl_ast_node_ref_t ref = new_node(p, SPL_AST_TYPE_PATH, bt);
spl_ast_node_t *tp = node_at(p->ast, ref); 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) if (bt->type == TOK_AT || bt->type == TOK_SHARP)
return parse_type_comptime_call(p); 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"); PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, bt, "unrecognized type");
return 0; 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")) if (!expect(p, TOK_RIGHT_FAT_ARROW, "'=>' in match arm"))
break; break;
if (!expect(p, TOK_L_BRACE, "'{' in match arm body"))
break;
spl_ast_node_ref_t body = parse_block(p); spl_ast_node_ref_t body = parse_block(p);
vec_push(patterns, pat); 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); block = node_at(p->ast, ref);
if (stmt) if (stmt)
vec_push(block->block.stmts, stmt); vec_push(block->block.stmts, stmt);
else
break;
} else if (can_start_expr(t->type)) { } else if (can_start_expr(t->type)) {
spl_ast_node_ref_t expr = parse_expr(p); spl_ast_node_ref_t expr = parse_expr(p);
if (!expr)
break;
block = node_at(p->ast, ref); block = node_at(p->ast, ref);
t = peek(p); t = peek(p);
if (t && t->type == TOK_SEMICOLON) { 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); const spl_tok_t *t = peek(p);
if (!t || t->type == TOK_EOF) if (!t || t->type == TOK_EOF)
return; return;
if (t->type == TOK_SEMICOLON) { if (t->type == TOK_SEMICOLON || t->type == TOK_R_BRACE) {
advance(p); advance(p);
return; return;
} }
if (t->type == TOK_R_BRACE)
return;
advance(p); advance(p);
} }
} }
+419 -128
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_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_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 spl_lang_type_id_t sema_infer_fn_signature(spl_sema_t *sema, spl_ast_node_t *n);
static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) { spl_lang_type_id_t matched_tid);
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid); static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_node_t *pat,
return n && n->kind == SPL_LANG_TYPE_INFER; 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) { 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) { 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; 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) { static void sema_type_to_str(spl_sema_t *sema, spl_lang_type_id_t tid, char *buf, usize cap) {
if (!buf || cap == 0) if (!buf || cap == 0)
return; 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}; .ast_node_ref = mref};
vec_push(members, m); vec_push(members, m);
} else if (mn->kind == SPL_AST_FN_DECL) { } else if (mn->kind == SPL_AST_FN_DECL) {
spl_def_id_t fn_def = spl_def_id_t fn_def = mn->resolved_def_id;
spl_def_alloc(sema->type, SPL_DEF_FN, mn->fn_decl.name, mn->dbg, sema->ast, mref); if (!fn_def) {
mn->resolved_def_id = 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); spl_def_node_t *fn_d = spl_def_node(sema->type, fn_def);
if (fn_d) if (fn_d)
fn_d->owner_def = owner_def_id; fn_d->owner_def = owner_def_id;
spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def}; spl_lang_method_t meth = {.name = mn->fn_decl.name, .def_id = fn_def};
vec_push(methods, meth); vec_push(methods, meth);
} else if (mn->kind == SPL_AST_TYPE_DECL) { } else if (mn->kind == SPL_AST_TYPE_DECL) {
spl_def_id_t tdef = mn->resolved_def_id; spl_ast_node_t *tpat = spl_ast_node(sema->ast, mn->type_decl.pattern);
if (!tdef) if (!tpat || tpat->kind != SPL_AST_PATTERN_IDENT)
continue; 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); 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; spl_def_id_t tdef = d->resolved_def_id;
if (!tdef) if (!tdef)
continue; 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); vec_push(methods, meth);
} else if (d->kind == SPL_AST_VAR_DECL || d->kind == SPL_AST_CONST_DECL) { } else if (d->kind == SPL_AST_VAR_DECL || d->kind == SPL_AST_CONST_DECL) {
spl_def_id_t vdef = d->resolved_def_id; /* def_id 现在挂在 pattern 上,不在 VAR_DECL 节点上 */
if (!vdef)
continue;
spl_ast_node_t *pat = spl_ast_node(sema->ast, d->var_const_decl.pattern); spl_ast_node_t *pat = spl_ast_node(sema->ast, d->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) if (!pat || pat->kind != SPL_AST_PATTERN_IDENT)
continue; 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}; spl_lang_method_t meth = {.name = pat->pattern_ident.name, .def_id = vdef};
vec_push(methods, meth); vec_push(methods, meth);
} }
@@ -487,8 +518,11 @@ static spl_lang_type_id_t sema_import(spl_sema_t *sema, spl_ast_node_t *n,
spl_lang_type_id_t t = 0; spl_lang_type_id_t t = 0;
spl_ast_node_t *cm_after = spl_ast_node(mod_ast, cm_ref); spl_ast_node_t *cm_after = spl_ast_node(mod_ast, cm_ref);
if (cm_after->resolved_def_id) if (cm_after->resolved_def_id) {
t = sema_eval_decl(sema, cm_after->resolved_def_id); spl_def_node_t *d = spl_def_node(sema->type, cm_after->resolved_def_id);
if (d)
t = d->lang_id;
}
sema->ast = saved_ast; sema->ast = saved_ast;
sema->scope->root_scope = saved_root; sema->scope->root_scope = saved_root;
@@ -550,6 +584,9 @@ static spl_lang_type_id_t sema_eval_decl(spl_sema_t *sema, spl_def_id_t def_id)
if (n) { if (n) {
switch (n->kind) { switch (n->kind) {
case SPL_AST_TYPE_DECL: { 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) { if (n->type_decl.type_expr) {
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 && te->kind == SPL_AST_TYPE_AGGREGATE) if (te && te->kind == SPL_AST_TYPE_AGGREGATE)
@@ -628,21 +665,28 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
break; break;
} }
case SPL_AST_TYPE_DECL: { 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); spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te) { if (!te) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, 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; return;
} }
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_TYPE};
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, sema->ast, ref); sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, name, te->dbg, sema->ast, ref);
else 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; n->resolved_def_id = sym.node;
if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) { if (!spl_scope_insert(sema->scope, sema->scope->current_scope, sym)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg, spl_diag_error(sema->diag, SPL_DIAG_KIND_DUPLICATE_SYMBOL, &n->dbg,
"duplicate symbol `%s`", sym.name); "duplicate symbol `%s`", name);
} }
break; break;
} }
@@ -659,18 +703,20 @@ static void sema_collect_names(spl_sema_t *sema, spl_ast_node_ref_t ref) {
case SPL_AST_VAR_DECL: case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: { case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern); spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (pat && pat->kind == SPL_AST_PATTERN_IDENT) { 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 {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, 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; break;
} }
@@ -692,8 +738,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) { 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_ref_t dref = vec_at(n->container_members.declarations, i);
spl_ast_node_t *d = spl_ast_node(sema->ast, dref); spl_ast_node_t *d = spl_ast_node(sema->ast, dref);
if (d && d->kind == SPL_AST_TYPE_DECL && d->resolved_def_id) if (!d || d->kind != SPL_AST_TYPE_DECL)
sema_eval_decl(sema, d->resolved_def_id); 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; break;
case SPL_AST_TOP_LEVEL_BLOCK: case SPL_AST_TOP_LEVEL_BLOCK:
@@ -714,12 +769,6 @@ static void sema_collect_signatures(spl_sema_t *sema) {
} }
} }
static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
sema_collect_names(sema, ref);
sema_collect_types(sema, ref);
sema_collect_signatures(sema);
}
static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in, static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in,
spl_ast_node_ref_vec_t *args) { spl_ast_node_ref_vec_t *args) {
const spl_intrin_info_t *info = spl_intrin_info(in); const spl_intrin_info_t *info = spl_intrin_info(in);
@@ -833,6 +882,23 @@ static spl_lang_type_id_t sema_block_body(spl_sema_t *sema, spl_ast_node_t *n,
return r; 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, static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
spl_lang_type_id_t matched_tid) { spl_lang_type_id_t matched_tid) {
if (!pat_ref) if (!pat_ref)
@@ -841,9 +907,24 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
if (!pat) if (!pat)
return; 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) { switch (pat->kind) {
case SPL_AST_PATTERN_IDENT: { case SPL_AST_PATTERN_IDENT: {
const char *name = pat->pattern_ident.name; 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}; 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); 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); spl_def_resolve(sema->type, sym.node, matched_tid);
@@ -859,11 +940,17 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
case SPL_AST_PATTERN_UNDERSCORE: case SPL_AST_PATTERN_UNDERSCORE:
return; 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: { case SPL_AST_PATTERN_TUPLE: {
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, matched_tid); spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, matched_tid);
if (!tn || tn->kind != SPL_LANG_TYPE_TUPLE) { if (!tn || tn->kind != SPL_LANG_TYPE_TUPLE) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"tuple pattern requires a tuple value"); "tuple pattern requires tuple value");
return; return;
} }
usize natoms = vec_size(pat->pattern_tuple.patterns); usize natoms = vec_size(pat->pattern_tuple.patterns);
@@ -873,7 +960,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); "tuple pattern arity mismatch (expected %zu, got %zu)", nelems, natoms);
return; return;
} }
/* 递归 bind 会 push lang_table,tn 会悬垂;先把元素类型拷到本地 */
spl_lang_type_id_vec_t elem_tids; spl_lang_type_id_vec_t elem_tids;
vec_init(elem_tids); vec_init(elem_tids);
for (usize i = 0; i < nelems; ++i) for (usize i = 0; i < nelems; ++i)
@@ -885,13 +971,245 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
return; return;
} }
case SPL_AST_PATTERN_DOT: case SPL_AST_PATTERN_DOT: {
case SPL_AST_PATTERN_AGGREGATE: spl_lang_type_node_t *mn = spl_lang_type_node(sema->type, matched_tid);
default: if (!mn || mn->kind != SPL_LANG_TYPE_ENUM) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_UNHANDLED_NODE, &pat->dbg, spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"pattern kind %d not yet supported", (int)pat->kind); "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; 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, static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref,
@@ -1842,9 +2160,15 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
} }
case SPL_AST_EXPR_IFVAR: { 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) if (n->ifvar_expr.then_block)
sema_infer(sema, 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) if (n->ifvar_expr.else_branch)
sema_infer(sema, n->ifvar_expr.else_branch); sema_infer(sema, n->ifvar_expr.else_branch);
return 0; return 0;
@@ -1865,7 +2189,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) if (n->while_expr.else_branch)
sema_infer(sema, 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; return 0;
} }
case SPL_AST_EXPR_LOOP: { case SPL_AST_EXPR_LOOP: {
@@ -1880,7 +2204,7 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (n->loop_expr.body) if (n->loop_expr.body)
sema_infer(sema, n->loop_expr.body); sema_infer(sema, n->loop_expr.body);
vec_pop(sema->label_stack); (void)vec_pop(sema->label_stack);
return 0; return 0;
} }
case SPL_AST_EXPR_FOR: { case SPL_AST_EXPR_FOR: {
@@ -1891,7 +2215,6 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
lbl = ln->label.name; lbl = ln->label.name;
} }
vec_push(sema->label_stack, lbl); vec_push(sema->label_stack, lbl);
sema_push_scope(sema); sema_push_scope(sema);
usize nsrc = vec_size(n->for_expr.iter_exprs); usize nsrc = vec_size(n->for_expr.iter_exprs);
@@ -1900,49 +2223,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) { if (pat && pat->kind == SPL_AST_PATTERN_LIST) {
usize natoms = vec_size(pat->pattern_list.patterns); usize natoms = vec_size(pat->pattern_list.patterns);
for (usize i = 0; i < nsrc; ++i) { if (natoms != nsrc) {
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) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg, 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 { } else {
for (usize i = 0; i < nsrc; ++i) { if (nsrc > 1) {
spl_lang_type_id_t container_tid = spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
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,
"for: multiple sources require pattern list"); "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) if (n->for_expr.body)
sema_infer(sema, n->for_expr.body); sema_infer(sema, n->for_expr.body);
if (n->for_expr.else_branch) if (n->for_expr.else_branch)
sema_infer(sema, 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; return 0;
} }
case SPL_AST_EXPR_MATCH: { 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) { 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)); 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) { if (!arm || arm->kind != SPL_AST_MATCH_ARM)
sema_infer(sema, arm->match_arm.pattern); 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_infer(sema, arm->match_arm.body);
} sema_pop_scope(sema);
} }
return 0; return 0;
} }
@@ -2114,6 +2435,9 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
} }
case SPL_AST_TYPE_DECL: { 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) if (!n->type_decl.type_expr)
break; break;
spl_def_node_t *def = spl_def_node_t *def =
@@ -2139,50 +2463,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_VAR_DECL:
case SPL_AST_CONST_DECL: { case SPL_AST_CONST_DECL:
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern); return sema_var_body(sema, n);
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_MEMBER_DECL: case SPL_AST_MEMBER_DECL:
if (n->member_decl.type_expr) if (n->member_decl.type_expr)
@@ -2324,10 +2606,23 @@ void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) {
spl_ast_node_t *mod = spl_ast_node(sema->ast, module_ref); spl_ast_node_t *mod = spl_ast_node(sema->ast, module_ref);
if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS) if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS)
return; return;
spl_scope_id_t saved = sema->scope->current_scope;
sema_collect(sema, module_ref); spl_scope_id_t saved_scope = sema->scope->current_scope;
spl_lang_type_id_t saved_agg = sema->current_aggregate_lang;
sema_collect_names(sema, module_ref);
spl_lang_type_id_t container_lang = 0;
if (mod->resolved_def_id)
container_lang = sema_eval_decl(sema, mod->resolved_def_id);
sema->current_aggregate_lang = container_lang;
sema_collect_types(sema, module_ref);
sema_collect_signatures(sema);
sema_infer(sema, module_ref); sema_infer(sema, module_ref);
sema->scope->current_scope = saved;
sema->current_aggregate_lang = saved_agg;
sema->scope->current_scope = saved_scope;
} }
void spl_sema_run(spl_sema_t *sema) { void spl_sema_run(spl_sema_t *sema) {
@@ -2337,10 +2632,6 @@ void spl_sema_run(spl_sema_t *sema) {
if (!root || root->kind != SPL_AST_ROOT) if (!root || root->kind != SPL_AST_ROOT)
return; return;
spl_sema_run_module(sema, root->root.members); spl_sema_run_module(sema, root->root.members);
spl_ast_node_t *cm = spl_ast_node(sema->ast, root->root.members);
if (cm && cm->resolved_def_id)
sema_eval_decl(sema, cm->resolved_def_id);
} }
void spl_sema_dump(spl_sema_t *sema) { void spl_sema_dump(spl_sema_t *sema) {
+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); spl_type_node_t *n = spl_type_node(type, id);
if (!n) { if (!n) {
printf("none"); printf("none");
vec_pop(*stack); (void)vec_pop(*stack);
return; return;
} }
switch (n->kind) { 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; break;
} }
vec_pop(*stack); (void)vec_pop(*stack);
} }
void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) { void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) {