Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5de4937637 | ||
|
|
2594a81034 | ||
|
|
acfbbeee8b |
No files matched your search
+1
-1
@@ -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)? }
|
||||
|
||||
|
||||
@@ -272,33 +272,71 @@ 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/";
|
||||
typedef struct {
|
||||
Nob_Files *files;
|
||||
test_fn_t test_once;
|
||||
void *user_data;
|
||||
} test_walk_ctx_t;
|
||||
|
||||
if (!prepare_build()) {
|
||||
return 1;
|
||||
}
|
||||
static bool test_walk_entry(Nob_Walk_Entry entry) {
|
||||
if (entry.type != NOB_FILE_REGULAR)
|
||||
return true;
|
||||
|
||||
Nob_File_Paths paths = {0};
|
||||
nob_read_entire_dir(test_folder, &paths);
|
||||
for (int i = 0; i < files->count; i += 1) {
|
||||
for (int j = 0; j < paths.count; j += 1) {
|
||||
String_View sv = sv_from_cstr(paths.items[j]);
|
||||
// printf("--- test " SV_Fmt " ---\n", SV_Arg(sv));
|
||||
if (!strstr(paths.items[j], files->items[i])) {
|
||||
continue;
|
||||
}
|
||||
const char *tname = nob_temp_sprintf("%s%s", test_folder, paths.items[j]);
|
||||
printf("--- test %s ---\n", tname);
|
||||
if (test_once(tname, user_data) == false)
|
||||
return false;
|
||||
}
|
||||
const char *dot = strrchr(entry.path, '.');
|
||||
if (!dot || strcmp(dot, ".spl") != 0)
|
||||
return true;
|
||||
|
||||
test_walk_ctx_t *ctx = (test_walk_ctx_t *)entry.data;
|
||||
bool run_all = (ctx->files->count == 0);
|
||||
bool matched = run_all;
|
||||
for (int i = 0; !matched && i < ctx->files->count; i += 1) {
|
||||
if (strstr(entry.path, ctx->files->items[i]))
|
||||
matched = true;
|
||||
}
|
||||
if (!matched)
|
||||
return true;
|
||||
|
||||
printf("--- test %s ---\n", entry.path);
|
||||
if (ctx->test_once(entry.path, ctx->user_data) == false)
|
||||
return false;
|
||||
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_directory_recursively(const char *dir_path) {
|
||||
@@ -372,33 +410,37 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
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;
|
||||
const char *mode_name = NULL;
|
||||
if (argc > 0) {
|
||||
mode_name = nob_shift(argv, argc);
|
||||
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) {
|
||||
if (is_dump_mode(argv[0])) {
|
||||
tfn = test_once_with_dump;
|
||||
} else if (strcmp(mode_name, "run") == 0) {
|
||||
// HACK
|
||||
mode_name = nob_shift(argv, argc);
|
||||
} else if (strcmp(argv[0], "run") == 0) {
|
||||
nob_shift(argv, argc);
|
||||
// HACK:只对 stage1 有意义,跑上次生成的 build/test.sir
|
||||
Nob_Cmd cmd = {0};
|
||||
nob_cmd_append(&cmd, BUILD_FOLDER "spl_cli", "-d");
|
||||
nob_cmd_append(&cmd, BUILD_FOLDER "test.sir");
|
||||
return nob_cmd_run(&cmd) ? 0 : 1;
|
||||
} else {
|
||||
da_append(&files, mode_name);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 剩下的都当 pattern
|
||||
Nob_Files files = {0};
|
||||
while (argc > 0) {
|
||||
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 (nob_file_exists(BUILD_FOLDER)) {
|
||||
if (!delete_directory_recursively(BUILD_FOLDER))
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
+380
-69
@@ -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_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);
|
||||
/* 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 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 +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) {
|
||||
if (!ir_ref || !n || vec_size(n->attrs) == 0)
|
||||
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);
|
||||
|
||||
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 +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_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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
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));
|
||||
if (n->block.tail_expr)
|
||||
return emit_expr(a, n->block.tail_expr);
|
||||
return 0;
|
||||
spl_ir_node_ref_t value = 0;
|
||||
if (!a->ir->terminated && n->block.tail_expr)
|
||||
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_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 +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;
|
||||
|
||||
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;
|
||||
@@ -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};
|
||||
ctx.cont_blk = cont_blk;
|
||||
ctx.defer_base = vec_size(a->defer_stack);
|
||||
ctx.label = NULL;
|
||||
ctx.result_slot = result_slot;
|
||||
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)
|
||||
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;
|
||||
@@ -1190,29 +1506,34 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||
lbl = ln->label.name;
|
||||
}
|
||||
|
||||
spl_loop_ctx_t *target = NULL;
|
||||
usize target_index = vec_size(a->loop_stack);
|
||||
if (lbl) {
|
||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||
target = c;
|
||||
target_index = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
@@ -1228,12 +1549,10 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||
if (n->statement_ret.expr)
|
||||
v = emit_expr(a, n->statement_ret.expr);
|
||||
|
||||
while (vec_size(a->defer_stack) > a->cur_defer_base) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
emit_stmt(a, d);
|
||||
}
|
||||
emit_deferred_until(a, a->cur_defer_base);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
||||
|
||||
usize target_index = vec_size(a->loop_stack) - 1;
|
||||
if (lbl) {
|
||||
target_index = vec_size(a->loop_stack);
|
||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
|
||||
return;
|
||||
target_index = i - 1;
|
||||
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_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
|
||||
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
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 +1647,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)
|
||||
@@ -1415,12 +1725,10 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||
if (n->fn_decl.body)
|
||||
emit_expr(a, n->fn_decl.body);
|
||||
|
||||
if (!a->ir->terminated) {
|
||||
while (vec_size(a->defer_stack) > defer_base) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
emit_stmt(a, d);
|
||||
}
|
||||
if (!a->ir->terminated)
|
||||
emit_deferred_until(a, defer_base);
|
||||
|
||||
if (!a->ir->terminated) {
|
||||
if (ret_is_unit) {
|
||||
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
|
||||
} 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) {
|
||||
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
|
||||
(void)d;
|
||||
}
|
||||
a->defer_stack.size = defer_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);
|
||||
vec_free(top->breaks);
|
||||
vec_pop(a->loop_stack);
|
||||
(void)vec_pop(a->loop_stack);
|
||||
}
|
||||
|
||||
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);
|
||||
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 +1844,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);
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
|
||||
|
||||
typedef struct {
|
||||
usize cont_blk;
|
||||
usize defer_base;
|
||||
const char *label;
|
||||
spl_ir_node_ref_vec_t breaks;
|
||||
spl_ir_node_ref_t result_slot;
|
||||
|
||||
+1
-2
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -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) {
|
||||
spl_def_node_t *d = spl_def_node(type, id);
|
||||
if (d)
|
||||
if (d) {
|
||||
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) {
|
||||
@@ -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);
|
||||
if (!n) {
|
||||
printf("none");
|
||||
vec_pop(*stack);
|
||||
(void)vec_pop(*stack);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+419
-128
@@ -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);
|
||||
}
|
||||
@@ -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_ast_node_t *cm_after = spl_ast_node(mod_ast, cm_ref);
|
||||
if (cm_after->resolved_def_id)
|
||||
t = sema_eval_decl(sema, cm_after->resolved_def_id);
|
||||
if (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->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) {
|
||||
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 +665,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 +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_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 +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) {
|
||||
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:
|
||||
@@ -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,
|
||||
spl_ast_node_ref_vec_t *args) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 +907,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 +940,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 +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);
|
||||
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 +971,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 +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: {
|
||||
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 +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)
|
||||
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 +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)
|
||||
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 +2215,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 +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) {
|
||||
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 +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: {
|
||||
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 +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_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)
|
||||
@@ -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);
|
||||
if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS)
|
||||
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->scope->current_scope = saved;
|
||||
|
||||
sema->current_aggregate_lang = saved_agg;
|
||||
sema->scope->current_scope = saved_scope;
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
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) {
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user