stage1 重新实现ast2ir
This commit is contained in:
1 parent
bcd26d3021
commit
ab6e99c958
10 files changed
+1161
-663
No files matched your search
+3
-6
@@ -1452,9 +1452,10 @@ static spl_ast_node_ref_t parse_primary(parser_t *p) {
|
||||
return 0;
|
||||
}
|
||||
advance(p); // 消费 ']'
|
||||
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ANON_ARRAY_LIT, t);
|
||||
spl_ast_node_ref_t ref = new_node(p, SPL_AST_EXPR_ARRAY_LIT, t);
|
||||
spl_ast_node_t *arr = node_at(p->ast, ref);
|
||||
arr->anon_array_literal.elems = elems;
|
||||
arr->array_literal.elems = elems;
|
||||
arr->array_literal.elem_type = 0;
|
||||
return ref;
|
||||
} else {
|
||||
SPL_FATAL(nx, "expected '{' or '[' after '.'");
|
||||
@@ -2463,10 +2464,6 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t
|
||||
dump_vec(ast, node->array_literal.elems, stack);
|
||||
break;
|
||||
|
||||
case SPL_AST_EXPR_ANON_ARRAY_LIT:
|
||||
dump_vec(ast, node->anon_array_literal.elems, stack);
|
||||
break;
|
||||
|
||||
case SPL_AST_EXPR_AGGREGATE_LIT:
|
||||
|
||||
dump_vec(ast, node->aggregate_literal.fields, stack);
|
||||
|
||||
+2
-10
@@ -49,7 +49,6 @@
|
||||
X(SPL_AST_EXPR_CAST, V0, cast) \
|
||||
X(SPL_AST_EXPR_TUPLE, V0, tuple) \
|
||||
X(SPL_AST_EXPR_ARRAY_LIT, V0, array_literal) \
|
||||
X(SPL_AST_EXPR_ANON_ARRAY_LIT, V0, anon_array_literal) \
|
||||
X(SPL_AST_EXPR_AGGREGATE_LIT, V0, aggregate_literal) \
|
||||
X(SPL_AST_EXPR_COMPTIME_CALL, V0, comptime_call) \
|
||||
X(SPL_AST_EXPR_BLOCK, V0, block) \
|
||||
@@ -151,11 +150,8 @@ typedef VEC(spl_ast_node_ref_t) spl_ast_node_ref_vec_t;
|
||||
struct spl_ast_node {
|
||||
spl_ast_node_kind_t kind;
|
||||
spl_dbg_node_t dbg;
|
||||
|
||||
union {
|
||||
usize resolved_def_id;
|
||||
usize resolved_type_id;
|
||||
};
|
||||
|
||||
union {
|
||||
/* SPL_AST_ROOT */
|
||||
@@ -356,16 +352,12 @@ struct spl_ast_node {
|
||||
bool has_len;
|
||||
usize len;
|
||||
bool is_underscore_len;
|
||||
spl_ast_node_ref_t elem_type;
|
||||
spl_ast_node_ref_t elem_type; /* 可空 匿名时为 NULL */
|
||||
spl_ast_node_ref_vec_t elems;
|
||||
} array_literal;
|
||||
|
||||
struct {
|
||||
spl_ast_node_ref_vec_t elems;
|
||||
} anon_array_literal;
|
||||
|
||||
struct {
|
||||
const char *name; /* 可空,匿名时为 NULL */
|
||||
const char *name; /* 可空 匿名时为 NULL */
|
||||
spl_ast_node_ref_vec_t fields; /* struct_init_item 节点列表 */
|
||||
} aggregate_literal;
|
||||
|
||||
|
||||
+799
-469
File diff suppressed because it is too large.
Load diff
@@ -5,10 +5,22 @@
|
||||
#include "spl_sema.h"
|
||||
|
||||
typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
|
||||
|
||||
typedef struct {
|
||||
usize cont_blk;
|
||||
usize brk_blk;
|
||||
spl_ir_node_ref_vec_t breaks;
|
||||
} spl_loop_ctx_t;
|
||||
typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t;
|
||||
|
||||
typedef VEC(spl_ast_node_ref_t) spl_defer_stack_t;
|
||||
|
||||
typedef struct {
|
||||
const spl_sema_t *sema;
|
||||
spl_ir_builder_t *ir;
|
||||
spl_def2ir_map_t def2ir_map;
|
||||
spl_loop_ctx_vec_t loop_stack;
|
||||
spl_defer_stack_t defer_stack;
|
||||
int err_count;
|
||||
} spl_ast2ir_t;
|
||||
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ static void ir_dump_node(const spl_type_t *ty, spl_ir_node_t *n) {
|
||||
printf(" float=%f", n->type_const.float_lit);
|
||||
} else if (t && t->kind == SPL_TYPE_FN) {
|
||||
printf(" fn#%zu", n->type_const.fn);
|
||||
} else if (t && t->kind == SPL_TYPE_SLICE) {
|
||||
} else if (t && t->kind == SPL_TYPE_PTR) {
|
||||
printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?");
|
||||
} else if (t && t->kind == SPL_TYPE_INT && t->int_type.bits == 8) {
|
||||
printf(" char='%c'", n->type_const.ch_lit);
|
||||
|
||||
+221
-159
@@ -62,98 +62,6 @@ static inline void sema_pop_scope(spl_sema_t *sema) {
|
||||
sema->scope->current_scope = sema->store_scope;
|
||||
}
|
||||
|
||||
static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_lang_type_id_t to,
|
||||
spl_lang_type_id_t from) {
|
||||
if (to == 0 || from == 0)
|
||||
return 0;
|
||||
|
||||
spl_lang_type_node_t *to_node = spl_lang_type_node(sema->type, to);
|
||||
if (!to_node)
|
||||
return 0;
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_INFER)
|
||||
return from;
|
||||
|
||||
spl_lang_type_node_t *from_node = spl_lang_type_node(sema->type, from);
|
||||
if (!from_node)
|
||||
return 0;
|
||||
|
||||
if (from_node->kind == SPL_LANG_TYPE_INT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
|
||||
if (from_ir_node && from_ir_node->int_type.bits == 0 && to_node->kind == SPL_LANG_TYPE_INT)
|
||||
return to;
|
||||
}
|
||||
if (from_node->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
|
||||
if (from_ir_node && from_ir_node->float_type.bits == 0 &&
|
||||
to_node->kind == SPL_LANG_TYPE_FLOAT)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) {
|
||||
spl_lang_type_id_t to_elem = to_node->extra.elem;
|
||||
spl_lang_type_id_t from_elem = from_node->extra.elem;
|
||||
if (sema_coerce(sema, to_elem, from_elem) != 0)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (spl_lang_type_is_subtype(sema->type, from, to))
|
||||
return to;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static spl_lang_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_lang_type_id_t t1,
|
||||
spl_lang_type_id_t t2) {
|
||||
if (t1 == 0 || t2 == 0)
|
||||
return 0;
|
||||
if (t1 == t2)
|
||||
return t1;
|
||||
|
||||
spl_lang_type_node_t *n1 = spl_lang_type_node(sema->type, t1);
|
||||
spl_lang_type_node_t *n2 = spl_lang_type_node(sema->type, t2);
|
||||
if (!n1 || !n2)
|
||||
return 0;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY)
|
||||
return spl_lang_make_any(sema->type);
|
||||
if (n1->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t2;
|
||||
if (n2->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t1;
|
||||
|
||||
if (spl_lang_type_is_subtype(sema->type, t1, t2))
|
||||
return t2;
|
||||
if (spl_lang_type_is_subtype(sema->type, t2, t1))
|
||||
return t1;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT) {
|
||||
// 如果一个是另一个的子类型,直接返回父类型(已在前面通用检查中处理)
|
||||
// 否则符号不同且无法安全提升,返回 0
|
||||
return 0;
|
||||
}
|
||||
if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t ir1 = spl_lang_type_get_ir_type(sema->type, t1);
|
||||
spl_type_id_t ir2 = spl_lang_type_get_ir_type(sema->type, t2);
|
||||
spl_type_node_t *irn1 = spl_type_node(sema->type, ir1);
|
||||
spl_type_node_t *irn2 = spl_type_node(sema->type, ir2);
|
||||
if (irn1 && irn2) {
|
||||
usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits
|
||||
: irn2->float_type.bits;
|
||||
return spl_lang_make_float(sema->type, bits);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool sema_coerce_for_bool(spl_sema_t *sema, spl_lang_type_id_t from) {
|
||||
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
||||
return sema_coerce(sema, bool_tid, from) == bool_tid;
|
||||
}
|
||||
|
||||
static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) {
|
||||
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, lang_tid);
|
||||
if (!n)
|
||||
@@ -176,18 +84,29 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
switch (n->kind) {
|
||||
case SPL_AST_CONTAINER_MEMBERS: {
|
||||
/* root_scope 只在第一次创建,后续 module 复用 */
|
||||
if (sema->scope->root_scope == 0) {
|
||||
spl_scope_id_t root = spl_scope_alloc(sema->scope);
|
||||
sema->scope->root_scope = root;
|
||||
}
|
||||
|
||||
/* 进入 root_scope,再为当前 module 开一个子 scope */
|
||||
sema->scope->current_scope = sema->scope->root_scope;
|
||||
spl_scope_id_t mod_scope = spl_scope_alloc(sema->scope);
|
||||
sema->scope->current_scope = mod_scope;
|
||||
|
||||
spl_symbol_t file_sym = {.name = "$file", .kind = SPL_SYMBOL_KIND_TYPE};
|
||||
file_sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, "$file", n->dbg, ref);
|
||||
n->resolved_def_id = file_sym.node;
|
||||
|
||||
spl_scope_id_t root_scope = spl_scope_alloc(sema->scope);
|
||||
sema->scope->current_scope = root_scope;
|
||||
sema->scope->root_scope = root_scope;
|
||||
spl_scope_insert(sema->scope, root_scope, file_sym);
|
||||
spl_scope_insert(sema->scope, mod_scope, file_sym);
|
||||
|
||||
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
|
||||
sema_collect(sema, vec_at(n->container_members.declarations, i));
|
||||
}
|
||||
|
||||
/* 故意不恢复 current_scope
|
||||
保持 mod_scope 交给随后的 sema_parse 使用。
|
||||
恢复由 spl_sema_run_module 统一负责 */
|
||||
break;
|
||||
}
|
||||
case SPL_AST_TYPE_DECL: {
|
||||
@@ -417,15 +336,19 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_ast_node_t *init_node = spl_ast_node(sema->ast, n->var_const_decl.init_expr);
|
||||
spl_lang_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr);
|
||||
decl_tid = sema_coerce(sema, decl_tid, init_tid);
|
||||
if (decl_tid == 0) {
|
||||
SPL_ERROR(&n->dbg, "cannot infer type for variable `%s`", name);
|
||||
spl_lang_type_id_t coerce_result = spl_lang_type_coerce_to(sema->type, decl_tid, init_tid);
|
||||
if (coerce_result == 0) {
|
||||
SPL_ERROR(&n->dbg, "cannot coerce initializer to declared type");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
init_node->resolved_type_id = coerce_result;
|
||||
decl_tid = coerce_result;
|
||||
|
||||
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
|
||||
n->resolved_type_id = decl_tid; // 存储 lang_id
|
||||
n->resolved_type_id = decl_tid;
|
||||
return decl_tid;
|
||||
}
|
||||
|
||||
@@ -500,6 +423,7 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
n->resolved_type_id = def->lang_id;
|
||||
return def->lang_id;
|
||||
}
|
||||
|
||||
@@ -556,14 +480,18 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
spl_binary_op_t op = n->binary.op;
|
||||
|
||||
switch (op) {
|
||||
case SPL_OP_ASSIGN:
|
||||
if (sema_coerce(sema, lt, rt) == 0) {
|
||||
case SPL_OP_ASSIGN: {
|
||||
spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right);
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "assignment type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
rhs->resolved_type_id = r;
|
||||
n->resolved_type_id = lt;
|
||||
return lt;
|
||||
}
|
||||
|
||||
case SPL_OP_ASSIGN_ADD:
|
||||
case SPL_OP_ASSIGN_SUB:
|
||||
@@ -575,12 +503,20 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_ASSIGN_XOR:
|
||||
case SPL_OP_ASSIGN_LSHIFT:
|
||||
case SPL_OP_ASSIGN_RSHIFT: {
|
||||
spl_lang_type_id_t balanced = sema_coerce_balance(sema, lt, rt);
|
||||
spl_lang_type_id_t balanced = spl_lang_type_balance(sema->type, lt, rt);
|
||||
if (balanced == 0 || balanced != lt) {
|
||||
SPL_ERROR(&n->dbg, "compound assignment type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right);
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "compound assignment right type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
rhs->resolved_type_id = r;
|
||||
n->resolved_type_id = lt;
|
||||
return lt;
|
||||
}
|
||||
@@ -602,13 +538,22 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_BIT_OR:
|
||||
case SPL_OP_BIT_XOR:
|
||||
case SPL_OP_BIT_AND: {
|
||||
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
|
||||
spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt);
|
||||
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
|
||||
if (!bn || bn->kind != SPL_LANG_TYPE_INT) {
|
||||
SPL_ERROR(&n->dbg, "bitwise operands must be integers");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
/* 两边都 coerce 到 bal */
|
||||
if (lt != bal) {
|
||||
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left);
|
||||
ln->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, lt);
|
||||
}
|
||||
if (rt != bal) {
|
||||
spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right);
|
||||
rn->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, rt);
|
||||
}
|
||||
n->resolved_type_id = bal;
|
||||
return bal;
|
||||
}
|
||||
@@ -619,13 +564,12 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_CMP_GE:
|
||||
case SPL_OP_CMP_LT:
|
||||
case SPL_OP_CMP_GT: {
|
||||
// FIXME 不一定合理
|
||||
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
||||
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
|
||||
bool numeric =
|
||||
(ln && (ln->kind == SPL_LANG_TYPE_INT || ln->kind == SPL_LANG_TYPE_FLOAT)) &&
|
||||
(rn && (rn->kind == SPL_LANG_TYPE_INT || rn->kind == SPL_LANG_TYPE_FLOAT));
|
||||
if (!numeric && sema_coerce_balance(sema, lt, rt) == 0) {
|
||||
if (!numeric && spl_lang_type_balance(sema->type, lt, rt) == 0) {
|
||||
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
@@ -653,13 +597,21 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_MUL:
|
||||
case SPL_OP_DIV:
|
||||
case SPL_OP_MOD: {
|
||||
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
|
||||
spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt);
|
||||
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
|
||||
if (!bn || (bn->kind != SPL_LANG_TYPE_INT && bn->kind != SPL_LANG_TYPE_FLOAT)) {
|
||||
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
if (lt != bal) {
|
||||
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left);
|
||||
ln->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, lt);
|
||||
}
|
||||
if (rt != bal) {
|
||||
spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right);
|
||||
rn->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, rt);
|
||||
}
|
||||
n->resolved_type_id = bal;
|
||||
return bal;
|
||||
}
|
||||
@@ -699,35 +651,41 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
if (has_varargs) {
|
||||
// 可变参数函数:实参数量至少等于固定参数数量
|
||||
if (vec_size(n->call.args) < fixed_param_count) {
|
||||
SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed_param_count);
|
||||
sema->error_count++;
|
||||
} else {
|
||||
// 检查固定参数部分
|
||||
for (usize i = 0; i < fixed_param_count; ++i) {
|
||||
spl_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i));
|
||||
spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i);
|
||||
spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref);
|
||||
spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref);
|
||||
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
|
||||
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
|
||||
sema->error_count++;
|
||||
} else {
|
||||
arg_node->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
// 额外参数不进行类型检查(或可扩展为元组类型检查)
|
||||
}
|
||||
} else {
|
||||
// 非可变参数函数:实参数量必须严格匹配
|
||||
if (vec_size(n->call.args) != vec_size(fn->extra.fn.params)) {
|
||||
SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)",
|
||||
vec_size(fn->extra.fn.params), vec_size(n->call.args));
|
||||
sema->error_count++;
|
||||
} else {
|
||||
for (usize i = 0; i < vec_size(n->call.args); ++i) {
|
||||
spl_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i));
|
||||
spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i);
|
||||
spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref);
|
||||
spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref);
|
||||
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
|
||||
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
|
||||
sema->error_count++;
|
||||
} else {
|
||||
arg_node->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -880,56 +838,68 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_ARRAY_LIT: {
|
||||
/* elem_type 可空:匿名 .[...] 时从元素推导 */
|
||||
spl_lang_type_id_t elem_tid = 0;
|
||||
if (n->array_literal.elem_type) {
|
||||
elem_tid = sema_parse(sema, n->array_literal.elem_type);
|
||||
}
|
||||
|
||||
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) {
|
||||
spl_lang_type_id_t et = sema_parse(sema, vec_at(n->array_literal.elems, i));
|
||||
if (elem_tid == 0)
|
||||
spl_ast_node_ref_t elem_ref = vec_at(n->array_literal.elems, i);
|
||||
spl_ast_node_t *elem_node = spl_ast_node(sema->ast, elem_ref);
|
||||
spl_lang_type_id_t et = sema_parse(sema, elem_ref);
|
||||
if (elem_tid == 0) {
|
||||
elem_tid = et;
|
||||
else if (sema_coerce(sema, elem_tid, et) == 0) {
|
||||
} else {
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, elem_tid, et);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "array element type mismatch");
|
||||
sema->error_count++;
|
||||
} else {
|
||||
elem_node->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (elem_tid == 0) {
|
||||
SPL_ERROR(&n->dbg, "cannot infer array element type "
|
||||
"(empty literal without element type annotation)");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
usize len;
|
||||
if (n->array_literal.is_underscore_len) {
|
||||
len = vec_size(n->array_literal.elems);
|
||||
} else {
|
||||
len =
|
||||
n->array_literal.has_len ? n->array_literal.len : vec_size(n->array_literal.elems);
|
||||
}
|
||||
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
|
||||
n->resolved_type_id = arr_tid;
|
||||
return arr_tid;
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_ANON_ARRAY_LIT: {
|
||||
spl_lang_type_id_t elem_tid = 0;
|
||||
for (usize i = 0; i < vec_size(n->anon_array_literal.elems); ++i) {
|
||||
spl_lang_type_id_t et = sema_parse(sema, vec_at(n->anon_array_literal.elems, i));
|
||||
if (elem_tid == 0)
|
||||
elem_tid = et;
|
||||
else if (sema_coerce(sema, elem_tid, et) == 0) {
|
||||
SPL_ERROR(&n->dbg, "array element type mismatch");
|
||||
} else if (n->array_literal.has_len) {
|
||||
len = (usize)n->array_literal.len;
|
||||
if (len != vec_size(n->array_literal.elems)) {
|
||||
SPL_ERROR(&n->dbg, "array literal length mismatch: declared %zu, got %zu", len,
|
||||
vec_size(n->array_literal.elems));
|
||||
sema->error_count++;
|
||||
}
|
||||
} else {
|
||||
len = vec_size(n->array_literal.elems);
|
||||
}
|
||||
usize len = vec_size(n->anon_array_literal.elems);
|
||||
|
||||
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
|
||||
n->resolved_type_id = arr_tid;
|
||||
return arr_tid;
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
||||
const char *type_name = n->aggregate_literal.name;
|
||||
|
||||
/* 匿名 .{...}:需要类型上下文。
|
||||
SEMA 当前为自底向上,尚无"预期类型"传播机制;
|
||||
待上层注解散布到 init_expr 之前时启用。
|
||||
结构上已统一,只需在这里读取 n->resolved_type_id 即可。 */
|
||||
if (!type_name) {
|
||||
SPL_ERROR(&n->dbg, "anonymous aggregate literal not supported yet");
|
||||
SPL_ERROR(&n->dbg, "anonymous aggregate literal requires expected type context "
|
||||
"(not yet supported)");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_symbol_t sym;
|
||||
if (!spl_scope_find(sema->scope, type_name, &sym)) {
|
||||
SPL_ERROR(&n->dbg, "unknown type `%s`", type_name);
|
||||
@@ -952,23 +922,44 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
|
||||
spl_type_node_t *agg_ir_node = spl_type_node(sema->type, agg_ir);
|
||||
if (!agg_ir_node) {
|
||||
SPL_ERROR(&n->dbg, "aggregate IR type `%s` not found", type_name);
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
usize total_fields = vec_size(agg_ir_node->agg_type.variants);
|
||||
|
||||
/* 记录每个字段是否被初始化,最后检查缺省 */
|
||||
bool *seen = calloc(total_fields, sizeof(bool));
|
||||
if (!seen) {
|
||||
SPL_ERROR(&n->dbg, "out of memory");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) {
|
||||
spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i));
|
||||
if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM)
|
||||
continue;
|
||||
|
||||
const char *fname = item->struct_init_item.name;
|
||||
spl_lang_type_id_t field_lang = 0;
|
||||
if (item->struct_init_item.expr) {
|
||||
field_lang = sema_parse(sema, item->struct_init_item.expr);
|
||||
}
|
||||
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, fname);
|
||||
if (!member) {
|
||||
usize field_idx = 0;
|
||||
if (!spl_type_agg_member_idx(sema->type, agg_ir, fname, &field_idx)) {
|
||||
SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name);
|
||||
sema->error_count++;
|
||||
continue;
|
||||
}
|
||||
// 映射到底层类型对应的语言级类型
|
||||
if (seen[field_idx]) {
|
||||
SPL_ERROR(&item->dbg, "duplicate field `%s` in `%s`", fname, type_name);
|
||||
sema->error_count++;
|
||||
continue;
|
||||
}
|
||||
seen[field_idx] = true;
|
||||
|
||||
const spl_type_member_t *member = &vec_at(agg_ir_node->agg_type.variants, field_idx);
|
||||
|
||||
/* 通过字段的 ir 类型反查 lang 类型 */
|
||||
spl_lang_type_id_t expected_lang = 0;
|
||||
for (usize j = 1; j < vec_size(sema->type->lang_table); ++j) {
|
||||
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, j);
|
||||
@@ -978,15 +969,37 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
}
|
||||
if (!expected_lang) {
|
||||
SPL_ERROR(&item->dbg, "cannot resolve field type for `%s`", fname);
|
||||
SPL_ERROR(&item->dbg, "cannot resolve lang type for field `%s`", fname);
|
||||
sema->error_count++;
|
||||
continue;
|
||||
}
|
||||
if (sema_coerce(sema, expected_lang, field_lang) == 0) {
|
||||
|
||||
if (!item->struct_init_item.expr) {
|
||||
SPL_ERROR(&item->dbg, "field `%s` requires an initializer", fname);
|
||||
sema->error_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
spl_ast_node_t *fv = spl_ast_node(sema->ast, item->struct_init_item.expr);
|
||||
spl_lang_type_id_t field_lang = sema_parse(sema, item->struct_init_item.expr);
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected_lang, field_lang);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname);
|
||||
sema->error_count++;
|
||||
} else {
|
||||
fv->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
|
||||
/* 检查缺省字段 */
|
||||
for (usize i = 0; i < total_fields; ++i) {
|
||||
if (!seen[i]) {
|
||||
const spl_type_member_t *m = &vec_at(agg_ir_node->agg_type.variants, i);
|
||||
SPL_ERROR(&n->dbg, "missing field `%s` in `%s`", m->name, type_name);
|
||||
sema->error_count++;
|
||||
}
|
||||
}
|
||||
free(seen);
|
||||
|
||||
n->resolved_type_id = agg_lang;
|
||||
return agg_lang;
|
||||
@@ -1007,15 +1020,43 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
case SPL_AST_EXPR_IF: {
|
||||
spl_lang_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond);
|
||||
if (!sema_coerce_for_bool(sema, cond_tid)) {
|
||||
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
||||
if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) {
|
||||
SPL_ERROR(&n->dbg, "if condition must be bool");
|
||||
sema->error_count++;
|
||||
}
|
||||
sema_parse(sema, n->if_expr.then_block);
|
||||
if (n->if_expr.else_branch) {
|
||||
sema_parse(sema, n->if_expr.else_branch);
|
||||
|
||||
spl_lang_type_id_t then_t =
|
||||
n->if_expr.then_block ? sema_parse(sema, n->if_expr.then_block) : 0;
|
||||
spl_lang_type_id_t else_t =
|
||||
n->if_expr.else_branch ? sema_parse(sema, n->if_expr.else_branch) : 0;
|
||||
|
||||
spl_lang_type_id_t result_t = 0;
|
||||
if (then_t && else_t) {
|
||||
result_t = spl_lang_type_balance(sema->type, then_t, else_t);
|
||||
if (result_t == 0) {
|
||||
SPL_ERROR(&n->dbg, "if branches type mismatch");
|
||||
sema->error_count++;
|
||||
} else {
|
||||
if (then_t != result_t) {
|
||||
spl_ast_node_t *tn = spl_ast_node(sema->ast, n->if_expr.then_block);
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, then_t);
|
||||
if (r)
|
||||
tn->resolved_type_id = r;
|
||||
}
|
||||
return 0;
|
||||
if (else_t != result_t) {
|
||||
spl_ast_node_t *en = spl_ast_node(sema->ast, n->if_expr.else_branch);
|
||||
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, else_t);
|
||||
if (r)
|
||||
en->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result_t = then_t ? then_t : else_t;
|
||||
}
|
||||
|
||||
n->resolved_type_id = result_t;
|
||||
return result_t;
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_IFVAR: {
|
||||
@@ -1029,7 +1070,8 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
case SPL_AST_EXPR_WHILE: {
|
||||
spl_lang_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond);
|
||||
if (!sema_coerce_for_bool(sema, cond_tid)) {
|
||||
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
||||
if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) {
|
||||
SPL_ERROR(&n->dbg, "while condition must be bool");
|
||||
sema->error_count++;
|
||||
}
|
||||
@@ -1189,16 +1231,21 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
case SPL_AST_STATEMENT_RET: {
|
||||
if (n->statement_ret.expr) {
|
||||
spl_ast_node_t *en = spl_ast_node(sema->ast, n->statement_ret.expr);
|
||||
spl_lang_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr);
|
||||
if (sema->current_fn_ret_tid != 0 &&
|
||||
sema_coerce(sema, sema->current_fn_ret_tid, ret_tid) == 0) {
|
||||
if (sema->current_fn_ret_tid != 0) {
|
||||
spl_lang_type_id_t r =
|
||||
spl_lang_type_coerce_to(sema->type, sema->current_fn_ret_tid, ret_tid);
|
||||
if (r == 0) {
|
||||
SPL_ERROR(&n->dbg, "return type mismatch");
|
||||
sema->error_count++;
|
||||
} else {
|
||||
en->resolved_type_id = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SPL_AST_STATEMENT_BREAK:
|
||||
case SPL_AST_STATEMENT_CONTINUE:
|
||||
return 0;
|
||||
@@ -1245,6 +1292,22 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope
|
||||
|
||||
void spl_sema_drop(spl_sema_t *sema) { (void)sema; }
|
||||
|
||||
void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) {
|
||||
if (!sema->ast || !module_ref)
|
||||
return;
|
||||
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);
|
||||
/* 此时 current_scope == 该 module 的 mod_scope */
|
||||
sema_parse(sema, module_ref);
|
||||
|
||||
sema->scope->current_scope = saved;
|
||||
}
|
||||
|
||||
void spl_sema_run(spl_sema_t *sema) {
|
||||
if (!sema->ast || !sema->ast->root)
|
||||
return;
|
||||
@@ -1253,8 +1316,7 @@ void spl_sema_run(spl_sema_t *sema) {
|
||||
if (!root || root->kind != SPL_AST_ROOT)
|
||||
return;
|
||||
|
||||
sema_collect(sema, root->root.members);
|
||||
sema_parse(sema, root->root.members);
|
||||
spl_sema_run_module(sema, root->root.members);
|
||||
}
|
||||
|
||||
void spl_sema_dump(spl_sema_t *sema) {
|
||||
|
||||
@@ -50,6 +50,7 @@ typedef struct {
|
||||
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope);
|
||||
void spl_sema_drop(spl_sema_t *sema);
|
||||
|
||||
void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref);
|
||||
void spl_sema_run(spl_sema_t *sema);
|
||||
void spl_sema_dump(spl_sema_t *sema);
|
||||
|
||||
|
||||
+87
-1
@@ -363,6 +363,93 @@ bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub,
|
||||
return false;
|
||||
}
|
||||
|
||||
spl_lang_type_id_t spl_lang_type_coerce_to(spl_type_t *type, spl_lang_type_id_t to,
|
||||
spl_lang_type_id_t from) {
|
||||
if (to == 0 || from == 0)
|
||||
return 0;
|
||||
if (to == from)
|
||||
return to;
|
||||
|
||||
spl_lang_type_node_t *to_node = spl_lang_type_node(type, to);
|
||||
if (!to_node)
|
||||
return 0;
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_INFER)
|
||||
return from;
|
||||
|
||||
spl_lang_type_node_t *from_node = spl_lang_type_node(type, from);
|
||||
if (!from_node)
|
||||
return 0;
|
||||
|
||||
if (from_node->kind == SPL_LANG_TYPE_INT && to_node->kind == SPL_LANG_TYPE_INT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(type, from_ir);
|
||||
if (from_ir_node && from_ir_node->int_type.bits == 0)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (from_node->kind == SPL_LANG_TYPE_FLOAT && to_node->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(type, from_ir);
|
||||
if (from_ir_node && from_ir_node->float_type.bits == 0)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) {
|
||||
spl_lang_type_id_t to_elem = to_node->extra.elem;
|
||||
spl_lang_type_id_t from_elem = from_node->extra.elem;
|
||||
if (spl_lang_type_coerce_to(type, to_elem, from_elem) != 0)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (spl_lang_type_is_subtype(type, from, to))
|
||||
return to;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_lang_type_id_t spl_lang_type_balance(spl_type_t *type, spl_lang_type_id_t t1,
|
||||
spl_lang_type_id_t t2) {
|
||||
if (t1 == 0 || t2 == 0)
|
||||
return 0;
|
||||
if (t1 == t2)
|
||||
return t1;
|
||||
|
||||
spl_lang_type_node_t *n1 = spl_lang_type_node(type, t1);
|
||||
spl_lang_type_node_t *n2 = spl_lang_type_node(type, t2);
|
||||
if (!n1 || !n2)
|
||||
return 0;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY)
|
||||
return spl_lang_make_any(type);
|
||||
if (n1->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t2;
|
||||
if (n2->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t1;
|
||||
|
||||
if (spl_lang_type_is_subtype(type, t1, t2))
|
||||
return t2;
|
||||
if (spl_lang_type_is_subtype(type, t2, t1))
|
||||
return t1;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT)
|
||||
return 0;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t ir1 = spl_lang_type_get_ir_type(type, t1);
|
||||
spl_type_id_t ir2 = spl_lang_type_get_ir_type(type, t2);
|
||||
spl_type_node_t *irn1 = spl_type_node(type, ir1);
|
||||
spl_type_node_t *irn2 = spl_type_node(type, ir2);
|
||||
if (irn1 && irn2) {
|
||||
usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits
|
||||
: irn2->float_type.bits;
|
||||
return spl_lang_make_float(type, bits);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spl_def_id_t spl_def_alloc(spl_type_t *type, spl_def_node_kind_t kind, const char *name,
|
||||
spl_dbg_node_t dbg, usize ast_node_ref) {
|
||||
spl_def_node_t n = {0};
|
||||
@@ -766,7 +853,6 @@ spl_lang_type_id_t spl_type_lookup_builtin(spl_type_t *type, const char *name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ========== 转储函数 ========== */
|
||||
void spl_type_pure_dump(spl_type_t *type, spl_type_id_t id) {
|
||||
spl_type_node_t *n = spl_type_node(type, id);
|
||||
if (!n) {
|
||||
|
||||
@@ -169,6 +169,24 @@ bool spl_lang_type_is_subtype(const spl_type_t *type, spl_lang_type_id_t sub,
|
||||
spl_lang_type_id_t super);
|
||||
bool spl_type_is_subtype(const spl_type_t *type, spl_type_id_t sub, spl_type_id_t super);
|
||||
|
||||
/* 计算 from 是否可以隐式转换到 to。
|
||||
* - to 是 INFER 时视为"接受任意 from",返回 from。
|
||||
* - 成功返回"转换后的类型"(正常是 to,INFER 时是 from)。
|
||||
* - 失败返回 0。
|
||||
* 纯函数:不修改任何 AST,不产生副作用。 */
|
||||
spl_lang_type_id_t spl_lang_type_coerce_to(spl_type_t *type, spl_lang_type_id_t to,
|
||||
spl_lang_type_id_t from);
|
||||
|
||||
/* 合并两个类型(用于 if 分支、算术运算的对称平衡)。
|
||||
* - NEVER 与任意 T 平衡得到 T。
|
||||
* - ANY 与任意 T 平衡得到 ANY。
|
||||
* - 子类型与父类型平衡得到父类型。
|
||||
* - 两个浮点取位宽较大者。
|
||||
* - 两个整数不自动提升,除非一方是另一方的子类型。
|
||||
* 无法合并返回 0。纯函数。 */
|
||||
spl_lang_type_id_t spl_lang_type_balance(spl_type_t *type, spl_lang_type_id_t t1,
|
||||
spl_lang_type_id_t t2);
|
||||
|
||||
spl_def_id_t spl_def_alloc(spl_type_t *type, spl_def_node_kind_t kind, const char *name,
|
||||
spl_dbg_node_t dbg, usize ast_node_ref);
|
||||
void spl_def_resolve(spl_type_t *type, spl_def_id_t id, spl_lang_type_id_t lang_id);
|
||||
|
||||
+17
-17
@@ -111,23 +111,23 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// spl_ast2ir_t a2ir;
|
||||
// spl_ir_builder_t ir_builder;
|
||||
// spl_ir_builder_init(&ir_builder);
|
||||
// spl_ast2ir_init(&a2ir, &ir_builder, &sema);
|
||||
// spl_ast2ir_run(&a2ir);
|
||||
// if (a2ir.err_count) {
|
||||
// printf("ast2ir errors=%d, no output\n", a2ir.err_count);
|
||||
// spl_ast2ir_drop(&a2ir);
|
||||
// spl_sema_drop(&sema);
|
||||
// spl_ast_drop(&ast);
|
||||
// return 1;
|
||||
// }
|
||||
// if (dump == DUMP_IR) {
|
||||
// spl_ir_dump(&ir_builder.ir, &type);
|
||||
// // memory leak
|
||||
// return 0;
|
||||
// }
|
||||
spl_ast2ir_t a2ir;
|
||||
spl_ir_builder_t ir_builder;
|
||||
spl_ir_builder_init(&ir_builder);
|
||||
spl_ast2ir_init(&a2ir, &ir_builder, &sema);
|
||||
spl_ast2ir_run(&a2ir);
|
||||
if (a2ir.err_count) {
|
||||
printf("ast2ir errors=%d, no output\n", a2ir.err_count);
|
||||
spl_ast2ir_drop(&a2ir);
|
||||
spl_sema_drop(&sema);
|
||||
spl_ast_drop(&ast);
|
||||
return 1;
|
||||
}
|
||||
if (dump == DUMP_IR) {
|
||||
spl_ir_dump(&ir_builder.ir, &type);
|
||||
// memory leak
|
||||
return 0;
|
||||
}
|
||||
|
||||
// spl_ir2vm_t ir2vm;
|
||||
// spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, sema.type);
|
||||
|
||||
Reference in new issue
Block a user