3249 lines
127 KiB
C
3249 lines
127 KiB
C
/* spl_ast2ir.c AST IR lowering
|
||
*
|
||
* 设计要点 * - 名称解析自包含:局部变类型用自身环境栈;顶层类函数sema root scope 与聚合成员表 * -
|
||
* 变量落在内存槽(@mem.alloca),写走 @mem.load/store;表达式临时值为 SSA * - 控制流用"块表 +
|
||
* fixup 补丁":分跳转目标在函数末尾回填为块首指令node ref * -
|
||
* 聚合字段访问:读@agg.extract,写字节地址直写"(@mem.offset + @mem.store* - 枚举=
|
||
* agg.construct(enum)([tag, payload?]);match tag 分发 * - defer 按作用域逆序执行(正常退/ ret /
|
||
* break / continue 全覆盖) */
|
||
|
||
#include "spl_ast2ir.h"
|
||
#include "spl_builtin.h"
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
/* ================================================================
|
||
* 基础访问
|
||
* ================================================================ */
|
||
|
||
static spl_ast_node_t *node_at(const spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||
if (!ref || ref >= sema->ast->buckets.size)
|
||
return NULL;
|
||
return &sema->ast->buckets.data[ref];
|
||
}
|
||
|
||
static spl_type_node_t *tn(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
return spl_type_node((spl_type_t *)&sema->type, tid);
|
||
}
|
||
|
||
static spl_def_node_t *def_at(const spl_sema_t *sema, spl_def_id_t id) {
|
||
return spl_type_def((spl_type_t *)&sema->type, id);
|
||
}
|
||
|
||
static spl_type_id_t underlying(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
spl_type_node_t *t = tn(sema, tid);
|
||
return (t && t->kind == SPL_TYPE_ID) ? t->type_id : tid;
|
||
}
|
||
|
||
static int type_same(const spl_sema_t *sema, spl_type_id_t a, spl_type_id_t b) {
|
||
if (a == b)
|
||
return 1;
|
||
a = underlying(sema, a);
|
||
b = underlying(sema, b);
|
||
if (a == b)
|
||
return 1;
|
||
spl_type_node_t *na = tn(sema, a);
|
||
spl_type_node_t *nb = tn(sema, b);
|
||
if (!na || !nb || na->kind != nb->kind)
|
||
return 0;
|
||
switch (na->kind) {
|
||
case SPL_TYPE_INT:
|
||
return na->int_type.bits == nb->int_type.bits &&
|
||
na->int_type.is_signed == nb->int_type.is_signed;
|
||
case SPL_TYPE_FLOAT:
|
||
return na->float_type.bits == nb->float_type.bits;
|
||
case SPL_TYPE_PTR:
|
||
return type_same(sema, na->ptr_pointee, nb->ptr_pointee);
|
||
case SPL_TYPE_SLICE:
|
||
return type_same(sema, na->slice_element, nb->slice_element);
|
||
case SPL_TYPE_RANGE:
|
||
return type_same(sema, na->range_element, nb->range_element);
|
||
case SPL_TYPE_ARRAY:
|
||
return na->array_type.len == nb->array_type.len &&
|
||
type_same(sema, na->array_type.element, nb->array_type.element);
|
||
case SPL_TYPE_FN: {
|
||
if (na->fn_type.params.size != nb->fn_type.params.size)
|
||
return 0;
|
||
for (usize i = 0; i < na->fn_type.params.size; i++)
|
||
if (!type_same(sema, na->fn_type.params.data[i], nb->fn_type.params.data[i]))
|
||
return 0;
|
||
return type_same(sema, na->fn_type.ret, nb->fn_type.ret);
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static int is_int_type(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
spl_type_node_t *t = tn(sema, underlying(sema, tid));
|
||
return t && t->kind == SPL_TYPE_INT;
|
||
}
|
||
static int is_float_type(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
spl_type_node_t *t = tn(sema, underlying(sema, tid));
|
||
return t && t->kind == SPL_TYPE_FLOAT;
|
||
}
|
||
static int is_num_type(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
spl_type_node_t *t = tn(sema, underlying(sema, tid));
|
||
return t && (t->kind == SPL_TYPE_INT || t->kind == SPL_TYPE_FLOAT);
|
||
}
|
||
static int is_ptr_type(const spl_sema_t *sema, spl_type_id_t tid) {
|
||
spl_type_node_t *t = tn(sema, underlying(sema, tid));
|
||
return t && t->kind == SPL_TYPE_PTR;
|
||
}
|
||
|
||
/* ---- 符号解析 ---- */
|
||
|
||
static spl_type_id_t agg_field_tid_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx);
|
||
static isize gdata_index_by_def(spl_ast2ir_t *a, spl_def_id_t def_id);
|
||
|
||
static spl_type_id_t kw_type(spl_ast2ir_t *a, const char *name) {
|
||
spl_def_id_t def = 0;
|
||
if (map_get(a->sema->scopes.data[a->sema->root_scope].symbols, name, &def)) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d)
|
||
return d->type_id;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_def_id_t root_lookup(spl_ast2ir_t *a, const char *name) {
|
||
spl_def_id_t def = 0;
|
||
if (map_get(a->sema->scopes.data[a->sema->root_scope].symbols, name, &def))
|
||
return def;
|
||
return 0;
|
||
}
|
||
|
||
/* 匿名类型 id 拥有它的 def(聚合优先,别名/distinct 兜底*/
|
||
static spl_def_id_t def_for_type(spl_ast2ir_t *a, spl_type_id_t tid) {
|
||
if (!tid)
|
||
return 0;
|
||
tid = underlying(a->sema, tid);
|
||
spl_def_id_t fallback = 0;
|
||
for (usize i = 1; i < a->sema->type.def_table.size; i++) {
|
||
spl_def_node_t *d = &a->sema->type.def_table.data[i];
|
||
spl_type_id_t dt = underlying(a->sema, d->type_id);
|
||
if (dt == tid) {
|
||
if (d->kind == SPL_DEF_AGG)
|
||
return i;
|
||
if (!fallback && (d->kind == SPL_DEF_ALIAS || d->kind == SPL_DEF_DISTINCT))
|
||
fallback = i;
|
||
}
|
||
}
|
||
return fallback;
|
||
}
|
||
|
||
/* 判断 agg_def 条目是否为结构字段(SPL_DEF_MEMBER*/
|
||
static int agg_entry_is_field(spl_ast2ir_t *a, const spl_var_def_t *e) {
|
||
if (!e->def_id)
|
||
return 0;
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
return ed && ed->kind == SPL_DEF_MEMBER;
|
||
}
|
||
|
||
/* 命名空间成员类型(方嵌套类型/static var):按名任意 kind */
|
||
static spl_type_id_t agg_member_type(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) {
|
||
agg_tid = underlying(a->sema, agg_tid);
|
||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||
if (!d)
|
||
return 0;
|
||
spl_def_node_t *def = def_at(a->sema, d);
|
||
for (usize i = 0; i < def->agg_def.size; i++) {
|
||
if (def->agg_def.data[i].name && strcmp(def->agg_def.data[i].name, name) == 0)
|
||
return def->agg_def.data[i].type_id;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 结构字段序号 = 相对 SPL_DEF_MEMBER 的位置(type.agg_field_types 按序对齐*/
|
||
static isize agg_member_index(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) {
|
||
agg_tid = underlying(a->sema, agg_tid);
|
||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||
if (!d)
|
||
return -1;
|
||
spl_def_node_t *def = def_at(a->sema, d);
|
||
isize fidx = 0;
|
||
for (usize i = 0; i < def->agg_def.size; i++) {
|
||
spl_var_def_t *e = &def->agg_def.data[i];
|
||
int is_field = agg_entry_is_field(a, e);
|
||
if (is_field && e->name && strcmp(e->name, name) == 0)
|
||
return fidx;
|
||
if (is_field)
|
||
fidx++;
|
||
}
|
||
/* 字段访问只认结构字段(MEMBER_DECL);var/fn/type 成员是命名空间实体,不在此列 */
|
||
return -1;
|
||
}
|
||
|
||
static spl_type_id_t agg_field_tid_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) {
|
||
spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid));
|
||
if (!t || (t->kind != SPL_TYPE_STRUCT && t->kind != SPL_TYPE_UNION && t->kind != SPL_TYPE_ENUM))
|
||
return 0;
|
||
if (idx >= 0 && (usize)idx < t->agg_field_types.size)
|
||
return t->agg_field_types.data[idx];
|
||
if (t->kind == SPL_TYPE_ENUM && idx >= 0 && (usize)idx < t->enum_type.variants.size) {
|
||
spl_type_id_t v = underlying(a->sema, t->enum_type.variants.data[idx]);
|
||
return (v == underlying(a->sema, agg_tid)) ? 0 : v;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 按字段序号查成员名(agg_def 中第 idx SPL_DEF_MEMBER 条目*/
|
||
static const char *agg_field_name_at(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) {
|
||
agg_tid = underlying(a->sema, agg_tid);
|
||
spl_def_id_t d = def_for_type(a, agg_tid);
|
||
if (!d)
|
||
return NULL;
|
||
spl_def_node_t *def = def_at(a->sema, d);
|
||
isize fidx = 0;
|
||
for (usize i = 0; i < def->agg_def.size; i++) {
|
||
spl_var_def_t *e = &def->agg_def.data[i];
|
||
if (agg_entry_is_field(a, e)) {
|
||
if (fidx == idx)
|
||
return e->name;
|
||
fidx++;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/* 切片/区间内置字段(ptr/len/begin/end)并入成员查*/
|
||
static isize agg_index_or_builtin(spl_ast2ir_t *a, spl_type_id_t agg_tid, const char *name) {
|
||
spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid));
|
||
if (t && t->kind == SPL_TYPE_SLICE) {
|
||
if (strcmp(name, "ptr") == 0)
|
||
return 0;
|
||
if (strcmp(name, "len") == 0)
|
||
return 1;
|
||
}
|
||
if (t && t->kind == SPL_TYPE_RANGE) {
|
||
if (strcmp(name, "begin") == 0)
|
||
return 0;
|
||
if (strcmp(name, "end") == 0)
|
||
return 1;
|
||
}
|
||
return agg_member_index(a, agg_tid, name);
|
||
}
|
||
|
||
static spl_type_id_t agg_field_tid_or_builtin(spl_ast2ir_t *a, spl_type_id_t agg_tid, isize idx) {
|
||
spl_type_node_t *t = tn(a->sema, underlying(a->sema, agg_tid));
|
||
if (t && t->kind == SPL_TYPE_SLICE) {
|
||
if (idx == 0)
|
||
return spl_type_ptr((spl_type_t *)&a->sema->type, t->slice_element);
|
||
if (idx == 1)
|
||
return kw_type(a, "usize");
|
||
}
|
||
if (t && t->kind == SPL_TYPE_RANGE)
|
||
return t->range_element;
|
||
return agg_field_tid_at(a, agg_tid, idx);
|
||
}
|
||
|
||
/* ================================================================
|
||
* IR 发射(per-function 上下文)
|
||
* ================================================================ */
|
||
|
||
typedef struct {
|
||
const char *name;
|
||
spl_def_id_t def_id; /* 0 = 未知(名字兜底) */
|
||
spl_type_id_t tid;
|
||
spl_ir_node_ref_t slot; /* 0 = 非内存绑*/
|
||
spl_ir_node_ref_t value; /* SSA 值绑*/
|
||
int is_type;
|
||
int mut;
|
||
} ir_env_t;
|
||
typedef struct {
|
||
VEC(ir_env_t) syms;
|
||
VEC(spl_ast_node_ref_t) defers; /* 本作用域defer */
|
||
} ir_env_scope_t;
|
||
typedef VEC(ir_env_scope_t) ir_env_stack_t;
|
||
|
||
typedef struct {
|
||
spl_ir_node_ref_t first;
|
||
} ir_block_t;
|
||
typedef VEC(ir_block_t) ir_block_vec_t;
|
||
|
||
typedef struct {
|
||
spl_ir_node_ref_t node;
|
||
int slot; /* 0=true_label 1=false_label 2=jmp.label */
|
||
usize block;
|
||
} ir_fix_t;
|
||
typedef VEC(ir_fix_t) ir_fix_vec_t;
|
||
|
||
typedef struct {
|
||
usize brk;
|
||
usize cont;
|
||
usize env_mark; /* 循环体作用域起始下标(defer 边界*/
|
||
} ir_loop_t;
|
||
typedef VEC(ir_loop_t) ir_loop_vec_t;
|
||
|
||
typedef struct {
|
||
spl_ir_func_ref_t fn;
|
||
spl_ast2ir_t *a;
|
||
spl_type_id_t ret_tid;
|
||
spl_type_id_t ns_tid; /* 所在聚合类型(方法命名空间);顶层0 */
|
||
ir_env_stack_t env;
|
||
ir_block_vec_t blocks;
|
||
usize cur_block;
|
||
ir_fix_vec_t fixups;
|
||
ir_loop_vec_t loops;
|
||
VEC(spl_type_id_t) types; /* nodes 平行的结果类型表 */
|
||
int terminated;
|
||
spl_type_id_t hint;
|
||
usize cur_src; /* 当前语句AST 节点 ref(调试行号) */
|
||
int err;
|
||
} fnctx_t;
|
||
|
||
static void fc_init(fnctx_t *fc, spl_ast2ir_t *a, spl_ir_func_ref_t fn, spl_type_id_t ret) {
|
||
memset(fc, 0, sizeof *fc);
|
||
fc->a = a;
|
||
fc->fn = fn;
|
||
fc->ret_tid = ret;
|
||
vec_init(fc->env);
|
||
vec_init(fc->blocks);
|
||
vec_init(fc->fixups);
|
||
vec_init(fc->loops);
|
||
vec_init(fc->types);
|
||
}
|
||
|
||
static void fc_init_ns(fnctx_t *fc, spl_ast2ir_t *a, spl_ir_func_ref_t fn, spl_type_id_t ret,
|
||
spl_type_id_t ns) {
|
||
fc_init(fc, a, fn, ret);
|
||
fc->ns_tid = ns;
|
||
}
|
||
|
||
static void fc_drop(fnctx_t *fc) {
|
||
for (usize i = 0; i < fc->env.size; i++) {
|
||
vec_free(fc->env.data[i].syms);
|
||
vec_free(fc->env.data[i].defers);
|
||
}
|
||
vec_free(fc->env);
|
||
vec_free(fc->blocks);
|
||
vec_free(fc->fixups);
|
||
vec_free(fc->loops);
|
||
vec_free(fc->types);
|
||
}
|
||
|
||
static void diag(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref, const char *msg) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
fc->err++;
|
||
if (n)
|
||
LOG_WARN("ast2ir: %s (%s:%d:%d)", msg, n->loc.fname ? n->loc.fname : "?", n->loc.line,
|
||
n->loc.col);
|
||
else
|
||
LOG_WARN("ast2ir: %s [fn=%s]", msg,
|
||
spl_ir_func(&a->ir, fc->fn)->name ? spl_ir_func(&a->ir, fc->fn)->name : "?");
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_node(spl_ast2ir_t *a, fnctx_t *fc) {
|
||
if (fc->terminated) {
|
||
ir_block_t b;
|
||
memset(&b, 0, sizeof b);
|
||
vec_push(fc->blocks, b);
|
||
fc->cur_block = fc->blocks.size - 1;
|
||
fc->terminated = 0;
|
||
}
|
||
spl_ir_node_ref_t r = spl_ir_alloc_node(&a->ir, fc->fn);
|
||
spl_ir_node(&a->ir, fc->fn, r)->src_ref = fc->cur_src; /* 调试行号 */
|
||
if (fc->cur_block < fc->blocks.size && !fc->blocks.data[fc->cur_block].first)
|
||
fc->blocks.data[fc->cur_block].first = r;
|
||
if (fc->types.size == 0) {
|
||
spl_type_id_t t0 = 0;
|
||
vec_push(fc->types, t0);
|
||
}
|
||
spl_type_id_t t1 = 0;
|
||
vec_push(fc->types, t1);
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_t *enode(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t r) {
|
||
return spl_ir_node(&a->ir, fc->fn, r);
|
||
}
|
||
|
||
static void set_ntype(fnctx_t *fc, spl_ir_node_ref_t r, spl_type_id_t tid) {
|
||
if (r && r < fc->types.size)
|
||
fc->types.data[r] = tid;
|
||
}
|
||
|
||
static spl_type_id_t node_type(fnctx_t *fc, spl_ir_node_ref_t r) {
|
||
if (!r || r >= fc->types.size)
|
||
return 0;
|
||
return fc->types.data[r];
|
||
}
|
||
|
||
static usize new_block(fnctx_t *fc) {
|
||
ir_block_t b;
|
||
memset(&b, 0, sizeof b);
|
||
vec_push(fc->blocks, b);
|
||
return fc->blocks.size - 1;
|
||
}
|
||
|
||
static void begin_block(fnctx_t *fc, usize id) {
|
||
fc->cur_block = id;
|
||
fc->terminated = 0;
|
||
}
|
||
|
||
static void emit_jmp(spl_ast2ir_t *a, fnctx_t *fc, usize target) {
|
||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||
spl_ir_node_t *n = enode(a, fc, r);
|
||
n->kind = SPL_IR_CONTROL_JMP;
|
||
n->control_jmp.label = 0;
|
||
ir_fix_t f = {r, 2, target};
|
||
vec_push(fc->fixups, f);
|
||
fc->terminated = 1;
|
||
}
|
||
|
||
static void emit_br(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t cond, usize t, usize f) {
|
||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||
spl_ir_node_t *n = enode(a, fc, r);
|
||
n->kind = SPL_IR_CONTROL_BR;
|
||
n->control_br.cond = cond;
|
||
n->control_br.true_label = 0;
|
||
n->control_br.false_label = 0;
|
||
ir_fix_t a1 = {r, 0, t};
|
||
ir_fix_t a2 = {r, 1, f};
|
||
vec_push(fc->fixups, a1);
|
||
vec_push(fc->fixups, a2);
|
||
fc->terminated = 1;
|
||
}
|
||
|
||
static void emit_ret(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, spl_ir_node_ref_t val) {
|
||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||
spl_ir_node_t *n = enode(a, fc, r);
|
||
n->kind = SPL_IR_CONTROL_RET;
|
||
n->control_ret.tid = tid;
|
||
n->control_ret.val = val;
|
||
fc->terminated = 1;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_const(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) {
|
||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||
spl_ir_node_t *n = enode(a, fc, r);
|
||
n->kind = SPL_IR_TYPE_CONST;
|
||
n->type_const.tid = tid;
|
||
set_ntype(fc, r, tid);
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t const_int(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, usize v) {
|
||
spl_ir_node_ref_t r = emit_const(a, fc, tid);
|
||
enode(a, fc, r)->type_const.int_lit = v;
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t const_bool(spl_ast2ir_t *a, fnctx_t *fc, int v) {
|
||
return const_int(a, fc, kw_type(a, "bool"), (usize)(v ? 1 : 0));
|
||
}
|
||
|
||
static spl_ir_node_ref_t const_float(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, double v) {
|
||
spl_ir_node_ref_t r = emit_const(a, fc, tid);
|
||
enode(a, fc, r)->type_const.float_lit = v;
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t const_str(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, const char *s) {
|
||
spl_ir_node_ref_t r = emit_const(a, fc, tid);
|
||
enode(a, fc, r)->type_const.cstr_lit = s;
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t const_fnref(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t fn_tid,
|
||
spl_ir_func_ref_t fid) {
|
||
spl_ir_node_ref_t r = emit_const(a, fc, fn_tid);
|
||
enode(a, fc, r)->type_const.fn = fid;
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_arith(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k,
|
||
spl_type_id_t tid, spl_ir_node_ref_t l, spl_ir_node_ref_t r) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = k;
|
||
e->arith.tid = tid;
|
||
e->arith.left = l;
|
||
e->arith.right = r;
|
||
set_ntype(fc, n, tid);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_cmp(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k, spl_type_id_t tid,
|
||
spl_ir_node_ref_t x, spl_ir_node_ref_t y) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = k;
|
||
e->cmp.tid = tid;
|
||
e->cmp.a = x;
|
||
e->cmp.b = y;
|
||
set_ntype(fc, n, kw_type(a, "bool"));
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_kind_t k,
|
||
spl_type_id_t from, spl_type_id_t to, spl_ir_node_ref_t v) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = k;
|
||
e->cast.from_tid = from;
|
||
e->cast.to_tid = to;
|
||
e->cast.val = v;
|
||
set_ntype(fc, n, to);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_alloca(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) {
|
||
spl_ir_node_ref_t cnt = const_int(a, fc, kw_type(a, "usize"), 1);
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_ALLOCA;
|
||
e->mem_alloc.tid = tid;
|
||
e->mem_alloc.count = cnt;
|
||
spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, tid);
|
||
set_ntype(fc, n, pt);
|
||
return n;
|
||
}
|
||
|
||
static void emit_store(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid, spl_ir_node_ref_t ptr,
|
||
spl_ir_node_ref_t val) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_STORE;
|
||
e->mem_store.tid = tid;
|
||
e->mem_store.ptr = ptr;
|
||
e->mem_store.val = val;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_load(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
spl_ir_node_ref_t ptr) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_LOAD;
|
||
e->mem_load.tid = tid;
|
||
e->mem_load.ptr = ptr;
|
||
set_ntype(fc, n, tid);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_offset(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
spl_ir_node_ref_t ptr, spl_ir_node_ref_t off) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_OFFSET;
|
||
e->mem_offset.tid = tid;
|
||
e->mem_offset.ptr = ptr;
|
||
e->mem_offset.offset = off;
|
||
spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, tid);
|
||
set_ntype(fc, n, pt);
|
||
return n;
|
||
}
|
||
|
||
/* 字段地址:mem.field_ptr(agg_tid, agg, idx) *field_type。布局偏移ir2vm 算,ast2ir 不算*/
|
||
static spl_ir_node_ref_t emit_field(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t agg_tid,
|
||
spl_ir_node_ref_t ptr, isize fidx) {
|
||
spl_type_id_t fty = agg_field_tid_or_builtin(a, agg_tid, fidx);
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_FIELD_PTR;
|
||
e->mem_field_ptr.tid = underlying(a->sema, agg_tid);
|
||
e->mem_field_ptr.agg = ptr;
|
||
e->mem_field_ptr.field_idx = (usize)fidx;
|
||
spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, fty);
|
||
set_ntype(fc, n, pt);
|
||
return n;
|
||
}
|
||
|
||
/* 全局静态数据地址:mem.global_alloc(tid, gdata_idx) *tid */
|
||
static spl_ir_node_ref_t emit_global_alloc(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
usize gdata_idx) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_MEM_GLOBAL_ALLOC;
|
||
e->mem_global_alloc.tid = tid;
|
||
e->mem_global_alloc.const_node = gdata_idx;
|
||
spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, tid);
|
||
set_ntype(fc, n, pt);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_agg_construct(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_AGG_CONSTRUCT;
|
||
e->agg_construct.tid = tid;
|
||
vec_init(e->agg_construct.fields);
|
||
set_ntype(fc, n, tid);
|
||
return n;
|
||
}
|
||
|
||
static void agg_construct_add(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t agg,
|
||
spl_ir_node_ref_t field) {
|
||
spl_ir_node_t *e = enode(a, fc, agg);
|
||
vec_push(e->agg_construct.fields, field);
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_agg_extract(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
spl_type_id_t field_tid, isize fidx,
|
||
spl_ir_node_ref_t val) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_AGG_EXTRACT;
|
||
e->agg_extract.tid = tid;
|
||
e->agg_extract.field_tid = field_tid;
|
||
e->agg_extract.field_idx = fidx;
|
||
e->agg_extract.val = val;
|
||
set_ntype(fc, n, field_tid);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_agg_insert(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
isize fidx, spl_ir_node_ref_t agg,
|
||
spl_ir_node_ref_t field) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_AGG_INSERT;
|
||
e->agg_insert.tid = tid;
|
||
e->agg_insert.field_idx = fidx;
|
||
e->agg_insert.agg = agg;
|
||
e->agg_insert.field = field;
|
||
set_ntype(fc, n, tid);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_call(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t fn_tid,
|
||
spl_ir_node_ref_t callee, spl_ir_node_ref_t *args, usize nargs) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_CONTROL_CALL;
|
||
e->control_call.tid = fn_tid;
|
||
e->control_call.func = callee;
|
||
vec_init(e->control_call.params);
|
||
for (usize i = 0; i < nargs; i++)
|
||
vec_push(e->control_call.params, args[i]);
|
||
spl_type_node_t *ft = tn(a->sema, fn_tid);
|
||
spl_type_id_t ret = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.ret : 0;
|
||
set_ntype(fc, n, ret);
|
||
return n;
|
||
}
|
||
|
||
static spl_ir_node_ref_t emit_select(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t tid,
|
||
spl_ir_node_ref_t c, spl_ir_node_ref_t t,
|
||
spl_ir_node_ref_t f) {
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_CONTROL_SELECT;
|
||
e->control_select.tid = tid;
|
||
e->control_select.cond = c;
|
||
e->control_select.true_val = t;
|
||
e->control_select.false_val = f;
|
||
set_ntype(fc, n, tid);
|
||
return n;
|
||
}
|
||
|
||
/* ================================================================
|
||
* 环境(变类型绑定 * ================================================================ */
|
||
|
||
static void env_push(fnctx_t *fc) {
|
||
ir_env_scope_t s;
|
||
memset(&s, 0, sizeof s);
|
||
vec_init(s.syms);
|
||
vec_init(s.defers);
|
||
vec_push(fc->env, s);
|
||
}
|
||
|
||
static void env_pop(fnctx_t *fc) {
|
||
if (!fc->env.size)
|
||
return;
|
||
vec_free(fc->env.data[fc->env.size - 1].syms);
|
||
vec_free(fc->env.data[fc->env.size - 1].defers);
|
||
vec_pop(fc->env);
|
||
}
|
||
|
||
static ir_env_t *env_find(fnctx_t *fc, const char *name) {
|
||
for (usize i = fc->env.size; i > 0; i--) {
|
||
ir_env_scope_t *s = &fc->env.data[i - 1];
|
||
for (usize j = 0; j < s->syms.size; j++) {
|
||
if (s->syms.data[j].name && strcmp(s->syms.data[j].name, name) == 0)
|
||
return &s->syms.data[j];
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/* def_id 优先定位(sema 已作用域解析,绕开同名遮蔽歧义);def_id 时兜底名*/
|
||
static ir_env_t *env_find_def(fnctx_t *fc, spl_def_id_t def_id, const char *name) {
|
||
if (def_id) {
|
||
for (usize i = fc->env.size; i > 0; i--) {
|
||
ir_env_scope_t *s = &fc->env.data[i - 1];
|
||
for (usize j = 0; j < s->syms.size; j++) {
|
||
if (s->syms.data[j].def_id == def_id)
|
||
return &s->syms.data[j];
|
||
}
|
||
}
|
||
}
|
||
return name ? env_find(fc, name) : NULL;
|
||
}
|
||
|
||
static void env_add(fnctx_t *fc, const char *name, spl_def_id_t def_id, spl_type_id_t tid,
|
||
spl_ir_node_ref_t slot, spl_ir_node_ref_t value, int is_type, int mut) {
|
||
if (!fc->env.size)
|
||
env_push(fc);
|
||
ir_env_t it;
|
||
memset(&it, 0, sizeof it);
|
||
it.name = name;
|
||
it.def_id = def_id;
|
||
it.tid = tid;
|
||
it.slot = slot;
|
||
it.value = value;
|
||
it.is_type = is_type;
|
||
it.mut = mut;
|
||
vec_push(fc->env.data[fc->env.size - 1].syms, it);
|
||
}
|
||
|
||
/* ================================================================
|
||
* 枚举
|
||
* ================================================================ */
|
||
|
||
static spl_type_id_t enum_tag_tid(spl_ast2ir_t *a) { return kw_type(a, "usize"); }
|
||
|
||
static isize enum_variant_index(spl_ast2ir_t *a, spl_type_id_t enum_tid, const char *name) {
|
||
enum_tid = underlying(a->sema, enum_tid);
|
||
spl_def_id_t d = def_for_type(a, enum_tid);
|
||
if (!d)
|
||
return -1;
|
||
spl_def_node_t *def = def_at(a->sema, d);
|
||
isize vidx = 0;
|
||
for (usize i = 0; i < def->agg_def.size; i++) {
|
||
spl_var_def_t *e = &def->agg_def.data[i];
|
||
if (agg_entry_is_field(a, e)) {
|
||
if (e->name && strcmp(e->name, name) == 0)
|
||
return vidx;
|
||
vidx++;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
static spl_type_id_t enum_payload_tid(spl_ast2ir_t *a, spl_type_id_t enum_tid, isize idx) {
|
||
enum_tid = underlying(a->sema, enum_tid);
|
||
spl_type_node_t *t = tn(a->sema, enum_tid);
|
||
if (!t || t->kind != SPL_TYPE_ENUM || idx < 0 || (usize)idx >= t->enum_type.variants.size)
|
||
return 0;
|
||
spl_type_id_t v = underlying(a->sema, t->enum_type.variants.data[idx]);
|
||
return (v == enum_tid) ? 0 : v;
|
||
}
|
||
|
||
static spl_ir_node_ref_t enum_variant_value(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t enum_tid,
|
||
isize idx) {
|
||
spl_ir_node_ref_t agg = emit_agg_construct(a, fc, enum_tid);
|
||
agg_construct_add(a, fc, agg, const_int(a, fc, enum_tag_tid(a), (usize)idx));
|
||
return agg;
|
||
}
|
||
|
||
static spl_ir_node_ref_t enum_tag_of(spl_ast2ir_t *a, fnctx_t *fc, spl_type_id_t enum_tid,
|
||
spl_ir_node_ref_t val) {
|
||
return emit_agg_extract(a, fc, enum_tid, enum_tag_tid(a), 0, val);
|
||
}
|
||
|
||
/* tid 是否enum */
|
||
static int is_enum_expand(spl_ast2ir_t *a, spl_type_id_t tid, spl_type_id_t *out_enum) {
|
||
spl_type_node_t *t = tn(a->sema, underlying(a->sema, tid));
|
||
if (t && t->kind == SPL_TYPE_ENUM) {
|
||
if (out_enum)
|
||
*out_enum = underlying(a->sema, tid);
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* 表达式当作类型引用解析(a / a.b.c,用于枚举变嵌套类型路径*/
|
||
static spl_type_id_t type_of_type_ref(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t bref) {
|
||
spl_ast_node_t *n = node_at(a->sema, bref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
if (n->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_IDENT) {
|
||
ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident);
|
||
if (it && it->is_type)
|
||
return underlying(a->sema, it->tid);
|
||
spl_def_id_t def = root_lookup(a, pn->primary_expr.ident);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->type_id)
|
||
return underlying(a->sema, d->type_id);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
if (n->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||
spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) {
|
||
spl_type_id_t bt = type_of_type_ref(a, fc, pf->postfix_expr.primary_expr);
|
||
if (bt) {
|
||
spl_type_id_t mt = agg_member_type(a, bt, pf->postfix_expr.field_expr);
|
||
return underlying(a->sema, mt);
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* ================================================================
|
||
* 类型解析(自包含 * ================================================================ */
|
||
|
||
static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref);
|
||
|
||
static spl_type_id_t resolve_type_atom(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n)
|
||
return 0;
|
||
switch (n->type_atom.kind) {
|
||
case SPL_AST_TYPE_VOID:
|
||
return kw_type(a, "void");
|
||
case SPL_AST_TYPE_BOOL:
|
||
return kw_type(a, "bool");
|
||
case SPL_AST_TYPE_I8:
|
||
return kw_type(a, "i8");
|
||
case SPL_AST_TYPE_U8:
|
||
return kw_type(a, "u8");
|
||
case SPL_AST_TYPE_I16:
|
||
return kw_type(a, "i16");
|
||
case SPL_AST_TYPE_U16:
|
||
return kw_type(a, "u16");
|
||
case SPL_AST_TYPE_I32:
|
||
return kw_type(a, "i32");
|
||
case SPL_AST_TYPE_U32:
|
||
return kw_type(a, "u32");
|
||
case SPL_AST_TYPE_I64:
|
||
return kw_type(a, "i64");
|
||
case SPL_AST_TYPE_U64:
|
||
return kw_type(a, "u64");
|
||
case SPL_AST_TYPE_ISIZE:
|
||
return kw_type(a, "isize");
|
||
case SPL_AST_TYPE_USIZE:
|
||
return kw_type(a, "usize");
|
||
case SPL_AST_TYPE__F32:
|
||
return kw_type(a, "f32");
|
||
case SPL_AST_TYPE__F64:
|
||
return kw_type(a, "f64");
|
||
case SPL_AST_TYPE_PTR:
|
||
case SPL_AST_TYPE_ANY:
|
||
return kw_type(a, "void");
|
||
case SPL_AST_TYPE_IDENT: {
|
||
const char *name = n->type_atom.ident;
|
||
ir_env_t *it = env_find(fc, name);
|
||
if (it && it->is_type)
|
||
return it->tid;
|
||
spl_def_id_t def = root_lookup(a, name);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->type_id)
|
||
return d->type_id;
|
||
}
|
||
return 0;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_type_id_t resolve_type_path(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_vec_t *path) {
|
||
if (!path->size)
|
||
return 0;
|
||
spl_type_id_t tid = resolve_type_atom(a, fc, path->data[0]);
|
||
if (!tid)
|
||
return 0;
|
||
for (usize i = 1; i < path->size; i++) {
|
||
spl_ast_node_t *atom = node_at(a->sema, path->data[i]);
|
||
if (!atom)
|
||
return 0;
|
||
spl_type_id_t mt = agg_member_type(a, tid, atom->type_atom.ident);
|
||
if (!mt)
|
||
return 0;
|
||
tid = mt;
|
||
}
|
||
return tid;
|
||
}
|
||
|
||
static spl_type_id_t resolve_type_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n)
|
||
return 0;
|
||
/* 首sema 注解:resolved_def_id def 类型(聚别名/命名类型*/
|
||
if (n->resolved_def_id) {
|
||
spl_def_node_t *d = def_at(a->sema, n->resolved_def_id);
|
||
if (d && d->type_id)
|
||
return d->type_id;
|
||
}
|
||
/* 兜底:组内置类型(sema 不为其建 def *T、[]T、fn(...)、关键字、别名到组合*/
|
||
spl_type_id_t base = 0;
|
||
switch (n->type_expr.kind) {
|
||
case SPL_AST_BASE_TYPE_PATH:
|
||
base = resolve_type_path(a, fc, &n->type_expr.type_path);
|
||
break;
|
||
case SPL_AST_BASE_TYPE_FN: {
|
||
spl_type_id_vec_t params;
|
||
vec_init(params);
|
||
for (usize i = 0; i < n->type_expr.fn_type.param_list.size; i++) {
|
||
spl_ast_node_t *pd = node_at(a->sema, n->type_expr.fn_type.param_list.data[i]);
|
||
spl_type_id_t pt = 0;
|
||
if (pd && pd->param_decl.type_expr)
|
||
pt = resolve_type_expr(a, fc, pd->param_decl.type_expr);
|
||
vec_push(params, pt);
|
||
}
|
||
spl_type_id_t ret = 0;
|
||
if (n->type_expr.fn_type.type_expr)
|
||
ret = resolve_type_expr(a, fc, n->type_expr.fn_type.type_expr);
|
||
else
|
||
ret = kw_type(a, "void");
|
||
base = spl_type_fn((spl_type_t *)&a->sema->type, params, ret);
|
||
break;
|
||
}
|
||
case SPL_AST_TYPE_STRUCT:
|
||
case SPL_AST_TYPE_UNION:
|
||
case SPL_AST_TYPE_ENUM:
|
||
/* 内联聚合不应走到这里(sema 已注解其 def);防御性报*/
|
||
diag(a, fc, ref, "inline aggregate not annotated by sema");
|
||
return 0;
|
||
default:
|
||
return 0;
|
||
}
|
||
for (usize i = n->type_expr.type_prefixs.size; i > 0; i--) {
|
||
spl_ast_node_t *pf = node_at(a->sema, n->type_expr.type_prefixs.data[i - 1]);
|
||
if (!pf)
|
||
continue;
|
||
if (pf->prefix_type.pointer == 1)
|
||
base = spl_type_ptr((spl_type_t *)&a->sema->type, base);
|
||
else if (pf->prefix_type.pointer == 2) {
|
||
if (pf->prefix_type.array_size > 0)
|
||
base = spl_type_array((spl_type_t *)&a->sema->type, base,
|
||
(usize)pf->prefix_type.array_size);
|
||
else
|
||
base = spl_type_slice((spl_type_t *)&a->sema->type, base);
|
||
}
|
||
}
|
||
return base;
|
||
}
|
||
|
||
/* ================================================================
|
||
* 表达 * ================================================================ */
|
||
|
||
static spl_ir_node_ref_t lower_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref);
|
||
static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref);
|
||
static void emit_scope_defers(spl_ast2ir_t *a, fnctx_t *fc, usize scope_idx);
|
||
static void emit_defers_from(spl_ast2ir_t *a, fnctx_t *fc, usize mark);
|
||
static spl_ir_func_ref_t a2ir_fn_of(spl_ast2ir_t *a, spl_type_id_t fn_tid);
|
||
static spl_ir_node_ref_t lower_compound_op(spl_ast2ir_t *a, fnctx_t *fc, int op, spl_type_id_t tid,
|
||
spl_ir_node_ref_t cur, spl_ir_node_ref_t rhs);
|
||
|
||
static int expr_is_int_literal(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
switch (n->expr.op) {
|
||
case SPL_AST_PRIMARY_EXPR: {
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
return pn && pn->primary_expr.kind == SPL_AST_INTEGER;
|
||
}
|
||
case SPL_AST_PREFIX_EXPR: {
|
||
spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pf && pf->prefix_expr.kind == SPL_AST_MINUS_EXPR)
|
||
return expr_is_int_literal(a, pf->prefix_expr.postfix_expr);
|
||
return 0;
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static spl_ir_node_ref_t coerce_to(spl_ast2ir_t *a, fnctx_t *fc, spl_ir_node_ref_t v,
|
||
spl_type_id_t from, spl_type_id_t to) {
|
||
if (!v || !from || !to)
|
||
return v;
|
||
if (type_same(a->sema, from, to))
|
||
return v;
|
||
spl_type_id_t f = underlying(a->sema, from);
|
||
spl_type_id_t t = underlying(a->sema, to);
|
||
spl_type_node_t *ft = tn(a->sema, f);
|
||
spl_type_node_t *tt = tn(a->sema, t);
|
||
if (!ft || !tt)
|
||
return v;
|
||
if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) {
|
||
if (ft->int_type.bits == tt->int_type.bits)
|
||
return v;
|
||
if (tt->int_type.bits > ft->int_type.bits)
|
||
return emit_cast(a, fc, ft->int_type.is_signed ? SPL_IR_CAST_SEXT : SPL_IR_CAST_ZEXT,
|
||
from, to, v);
|
||
return emit_cast(a, fc, SPL_IR_CAST_TRUNC, from, to, v);
|
||
}
|
||
if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_FLOAT)
|
||
return emit_cast(a, fc, SPL_IR_CASE_INT2FLOAT, from, to, v);
|
||
if (ft->kind == SPL_TYPE_FLOAT && tt->kind == SPL_TYPE_INT)
|
||
return emit_cast(a, fc, SPL_IR_CASE_FLOAT2INT, from, to, v);
|
||
if (ft->kind == SPL_TYPE_FLOAT && tt->kind == SPL_TYPE_FLOAT)
|
||
return emit_cast(a, fc,
|
||
tt->float_type.bits > ft->float_type.bits ? SPL_IR_CAST_FEXT
|
||
: SPL_IR_CAST_FTRUNC,
|
||
from, to, v);
|
||
if (ft->kind == SPL_TYPE_PTR && tt->kind == SPL_TYPE_PTR)
|
||
return emit_cast(a, fc, SPL_IR_CAST_BITCAST, from, to, v);
|
||
if (ft->kind == SPL_TYPE_PTR && tt->kind == SPL_TYPE_INT)
|
||
return emit_cast(a, fc, SPL_IR_CAST_PTR2INT, from, to, v);
|
||
if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_PTR)
|
||
return emit_cast(a, fc, SPL_IR_CAST_INT2PTR, from, to, v);
|
||
if (ft->kind == SPL_TYPE_BOOL && tt->kind == SPL_TYPE_INT)
|
||
return emit_cast(a, fc, SPL_IR_CAST_BOOL2INT, from, to, v);
|
||
return v;
|
||
}
|
||
|
||
/* ---- 左值地址 ---- */
|
||
|
||
#define MAX_FIELD_CHAIN 16
|
||
|
||
static spl_ir_node_ref_t lower_lvalue(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref,
|
||
spl_type_id_t *out_tid);
|
||
|
||
/* 收集字段链(叶子在前):返回EXPR ref */
|
||
static spl_ast_node_ref_t field_chain_base(spl_ast2ir_t *a, spl_ast_node_t *pf, const char **names,
|
||
int *n) {
|
||
*n = 0;
|
||
names[(*n)++] = pf->postfix_expr.field_expr;
|
||
spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr;
|
||
spl_ast_node_t *base = node_at(a->sema, bref);
|
||
while (base && base->kind == SPL_AST_EXPR && base->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||
spl_ast_node_t *bpf = node_at(a->sema, base->expr.op_expr.left);
|
||
if (!bpf || bpf->postfix_expr.kind != SPL_AST_FIELD_EXPR)
|
||
break;
|
||
if (*n >= MAX_FIELD_CHAIN)
|
||
break;
|
||
names[(*n)++] = bpf->postfix_expr.field_expr;
|
||
bref = bpf->postfix_expr.primary_expr;
|
||
base = node_at(a->sema, bref);
|
||
}
|
||
return bref;
|
||
}
|
||
|
||
/* 字段链的存储地址(root.a.b 地址 + 字段类型*/
|
||
static spl_ir_node_ref_t lower_field_address(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t bref,
|
||
spl_type_id_t *out_tid) {
|
||
spl_ast_node_t *n = node_at(a->sema, bref);
|
||
if (!n || n->kind != SPL_AST_EXPR || n->expr.op != SPL_AST_POSTFIX_EXPR)
|
||
return 0;
|
||
spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left);
|
||
if (!pf || pf->postfix_expr.kind != SPL_AST_FIELD_EXPR)
|
||
return 0;
|
||
const char *names[MAX_FIELD_CHAIN];
|
||
int nf = 0;
|
||
spl_ast_node_ref_t root_ref = field_chain_base(a, pf, names, &nf);
|
||
/* 类型命名空间基址:Foo.counter(全局 var/const lvalue = gdata 地址*/
|
||
spl_type_id_t ns = type_of_type_ref(a, fc, root_ref);
|
||
if (ns && nf == 1) {
|
||
spl_def_id_t gdef = def_for_type(a, ns);
|
||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||
spl_var_def_t *e = &gd->agg_def.data[i];
|
||
if (e->name && strcmp(e->name, names[0]) == 0 && e->def_id) {
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
if (ed && ed->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, e->def_id);
|
||
if (gi >= 0) {
|
||
*out_tid = e->type_id;
|
||
return emit_global_alloc(a, fc, e->type_id, (usize)gi);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
spl_type_id_t cur_tid = 0;
|
||
spl_ir_node_ref_t addr = lower_lvalue(a, fc, root_ref, &cur_tid);
|
||
spl_type_node_t *curt = tn(a->sema, underlying(a->sema, cur_tid));
|
||
if (curt && curt->kind == SPL_TYPE_PTR) {
|
||
cur_tid = underlying(a->sema, curt->ptr_pointee);
|
||
spl_type_id_t pty = spl_type_ptr((spl_type_t *)&a->sema->type, cur_tid);
|
||
addr = emit_load(a, fc, pty, addr);
|
||
}
|
||
if (!addr || !cur_tid)
|
||
return 0;
|
||
for (int i = nf - 1; i >= 0; i--) {
|
||
spl_type_node_t *ct = tn(a->sema, underlying(a->sema, cur_tid));
|
||
if (!ct || (ct->kind != SPL_TYPE_STRUCT && ct->kind != SPL_TYPE_UNION &&
|
||
ct->kind != SPL_TYPE_SLICE && ct->kind != SPL_TYPE_RANGE))
|
||
return 0;
|
||
isize idx = agg_index_or_builtin(a, cur_tid, names[i]);
|
||
if (idx < 0)
|
||
return 0;
|
||
spl_type_id_t ft = agg_field_tid_or_builtin(a, cur_tid, idx);
|
||
addr = emit_field(a, fc, cur_tid, addr, idx);
|
||
cur_tid = ft;
|
||
if (i > 0) {
|
||
spl_type_node_t *ftt = tn(a->sema, underlying(a->sema, cur_tid));
|
||
if (ftt && ftt->kind == SPL_TYPE_PTR) {
|
||
cur_tid = underlying(a->sema, ftt->ptr_pointee);
|
||
spl_type_id_t pty = spl_type_ptr((spl_type_t *)&a->sema->type, cur_tid);
|
||
addr = emit_load(a, fc, pty, addr);
|
||
}
|
||
}
|
||
}
|
||
*out_tid = cur_tid;
|
||
return addr;
|
||
}
|
||
|
||
/* a[i] 内联 postfix 节点 元素地址 */
|
||
static spl_ir_node_ref_t index_addr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf,
|
||
spl_type_id_t *elem) {
|
||
spl_ir_node_ref_t idx = lower_expr(a, fc, pf->postfix_expr.index_expr);
|
||
spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr;
|
||
spl_type_id_t base_t = 0;
|
||
spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, bref, &base_t);
|
||
spl_ir_node_ref_t base_addr = 0;
|
||
spl_type_id_t elem_t = 0;
|
||
spl_type_node_t *bt = NULL;
|
||
if (base_lv) {
|
||
bt = tn(a->sema, underlying(a->sema, base_t));
|
||
} else {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, bref);
|
||
spl_type_id_t vt = underlying(a->sema, node_type(fc, v));
|
||
spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL;
|
||
if (vtt && vtt->kind == SPL_TYPE_PTR) {
|
||
base_addr = v;
|
||
base_t = vt;
|
||
bt = vtt;
|
||
} else if (vtt && vtt->kind == SPL_TYPE_SLICE) {
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, vtt->slice_element);
|
||
base_addr = emit_agg_extract(a, fc, vt, ep, 0, v);
|
||
base_t = vt;
|
||
bt = vtt;
|
||
} else if (vtt && vtt->kind == SPL_TYPE_ARRAY) {
|
||
spl_type_id_t fat = 0;
|
||
spl_ir_node_ref_t faddr = lower_field_address(a, fc, bref, &fat);
|
||
if (faddr) {
|
||
base_addr = faddr;
|
||
base_t = fat;
|
||
bt = tn(a->sema, underlying(a->sema, fat));
|
||
} else {
|
||
diag(a, fc, 0, "index on non-addressable array value");
|
||
return 0;
|
||
}
|
||
} else {
|
||
diag(a, fc, 0, "index requires array/slice/pointer");
|
||
return 0;
|
||
}
|
||
}
|
||
if (bt && bt->kind == SPL_TYPE_ARRAY) {
|
||
base_addr = base_lv ? base_lv : base_addr;
|
||
elem_t = bt->array_type.element;
|
||
} else if (bt && bt->kind == SPL_TYPE_PTR) {
|
||
base_addr = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr;
|
||
elem_t = underlying(a->sema, bt->ptr_pointee);
|
||
} else if (bt && bt->kind == SPL_TYPE_SLICE) {
|
||
elem_t = bt->slice_element;
|
||
if (base_lv) {
|
||
spl_ir_node_ref_t slv = emit_load(a, fc, base_t, base_lv);
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem_t);
|
||
base_addr = emit_agg_extract(a, fc, base_t, ep, 0, slv);
|
||
}
|
||
/* base_lv==0 时 base_addr 已是切片表达式中提取出的 ptr 标量,直接复用 */
|
||
} else {
|
||
diag(a, fc, 0, "index requires array/slice/pointer");
|
||
return 0;
|
||
}
|
||
if (!elem_t) {
|
||
diag(a, fc, 0, "index requires array/slice/pointer");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t o = coerce_to(a, fc, idx, node_type(fc, idx), kw_type(a, "isize"));
|
||
spl_ir_node_ref_t addr = emit_offset(a, fc, elem_t, base_addr, o);
|
||
*elem = elem_t;
|
||
return addr;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_lvalue(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref,
|
||
spl_type_id_t *out_tid) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
if (n->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_IDENT) {
|
||
ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident);
|
||
if (it && it->slot) {
|
||
*out_tid = it->tid;
|
||
return it->slot;
|
||
}
|
||
if (it) {
|
||
diag(a, fc, ref, "not an addressable variable");
|
||
return 0;
|
||
}
|
||
/* 顶层 / 命名空间全局 var:lvalue = 全局分配地址 */
|
||
spl_def_id_t def = pn->resolved_def_id;
|
||
if (!def)
|
||
def = root_lookup(a, pn->primary_expr.ident);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, def);
|
||
if (gi >= 0) {
|
||
*out_tid = d->type_id;
|
||
return emit_global_alloc(a, fc, *out_tid, (usize)gi);
|
||
}
|
||
}
|
||
if (fc->ns_tid) {
|
||
spl_def_id_t gdef = def_for_type(a, fc->ns_tid);
|
||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||
spl_var_def_t *e = &gd->agg_def.data[i];
|
||
if (e->name && strcmp(e->name, pn->primary_expr.ident) == 0 && e->def_id) {
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
if (ed && ed->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, e->def_id);
|
||
if (gi >= 0) {
|
||
*out_tid = e->type_id;
|
||
return emit_global_alloc(a, fc, e->type_id, (usize)gi);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
if (pn && pn->primary_expr.kind == SPL_AST_EXPR_EXPR)
|
||
return lower_lvalue(a, fc, pn->primary_expr.expr, out_tid);
|
||
return 0;
|
||
}
|
||
if (n->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||
spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left);
|
||
if (!pf)
|
||
return 0;
|
||
if (pf->postfix_expr.kind == SPL_AST_DEREF_EXPR) {
|
||
spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
spl_type_id_t pt = underlying(a->sema, node_type(fc, p));
|
||
spl_type_node_t *tt = tn(a->sema, pt);
|
||
if (!tt || tt->kind != SPL_TYPE_PTR) {
|
||
diag(a, fc, ref, ".* requires pointer");
|
||
return 0;
|
||
}
|
||
*out_tid = underlying(a->sema, tt->ptr_pointee);
|
||
return p;
|
||
}
|
||
if (pf->postfix_expr.kind == SPL_AST_INDEX_EXPR)
|
||
return index_addr(a, fc, pf, out_tid);
|
||
if (pf->postfix_expr.kind == SPL_AST_FIELD_EXPR)
|
||
return lower_field_address(a, fc, ref, out_tid);
|
||
return 0;
|
||
}
|
||
if (n->expr.op == SPL_AST_PREFIX_EXPR) {
|
||
spl_ast_node_t *pp = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pp && pp->prefix_expr.kind == SPL_AST_ASTERISK_EXPR) {
|
||
spl_ir_node_ref_t p = lower_expr(a, fc, pp->prefix_expr.postfix_expr);
|
||
spl_type_id_t pt = underlying(a->sema, node_type(fc, p));
|
||
spl_type_node_t *tt = tn(a->sema, pt);
|
||
if (!tt || tt->kind != SPL_TYPE_PTR) {
|
||
diag(a, fc, ref, "prefix * requires pointer");
|
||
return 0;
|
||
}
|
||
*out_tid = underlying(a->sema, tt->ptr_pointee);
|
||
return p;
|
||
}
|
||
return 0;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_ident(spl_ast2ir_t *a, fnctx_t *fc, const char *name,
|
||
spl_def_id_t def_id, spl_ast_node_ref_t ref) {
|
||
ir_env_t *it = env_find_def(fc, def_id, name);
|
||
if (it) {
|
||
if (it->is_type) {
|
||
diag(a, fc, ref, "type used as value");
|
||
return 0;
|
||
}
|
||
if (it->slot)
|
||
return emit_load(a, fc, it->tid, it->slot);
|
||
return it->value;
|
||
}
|
||
spl_def_id_t def = root_lookup(a, name);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d &&
|
||
(d->kind == SPL_DEF_AGG || d->kind == SPL_DEF_ALIAS || d->kind == SPL_DEF_DISTINCT)) {
|
||
diag(a, fc, ref, "type name used as value");
|
||
return 0;
|
||
}
|
||
if (d && d->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, def);
|
||
if (gi >= 0)
|
||
return emit_load(a, fc, d->type_id,
|
||
emit_global_alloc(a, fc, d->type_id, (usize)gi));
|
||
}
|
||
diag(a, fc, ref, "undefined identifier");
|
||
} else {
|
||
/* 命名空间内裸名:fc->ns_tid 聚合成员 static var/const */
|
||
if (fc->ns_tid) {
|
||
spl_def_id_t gdef = def_for_type(a, fc->ns_tid);
|
||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||
spl_var_def_t *e = &gd->agg_def.data[i];
|
||
if (e->name && strcmp(e->name, name) == 0 && e->def_id) {
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
if (ed && ed->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, e->def_id);
|
||
if (gi >= 0)
|
||
return emit_load(a, fc, e->type_id,
|
||
emit_global_alloc(a, fc, e->type_id, (usize)gi));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
diag(a, fc, ref, "undefined identifier");
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_type_id_t type_from_type_like(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
if (n->expr.op != SPL_AST_PRIMARY_EXPR)
|
||
return 0;
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
if (!pn || pn->primary_expr.kind != SPL_AST_IDENT)
|
||
return 0;
|
||
ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident);
|
||
if (it && it->is_type)
|
||
return it->tid;
|
||
spl_def_id_t def = root_lookup(a, pn->primary_expr.ident);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->type_id)
|
||
return d->type_id;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_block_expr(spl_ast2ir_t *a, fnctx_t *fc,
|
||
spl_ast_node_ref_vec_t *items) {
|
||
env_push(fc);
|
||
spl_ir_node_ref_t result = 0;
|
||
for (usize i = 0; i < items->size; i++) {
|
||
spl_ast_node_t *b = node_at(a->sema, items->data[i]);
|
||
if (i + 1 == items->size && b && b->kind == SPL_AST_EXPR) {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, items->data[i]);
|
||
if (v && !fc->terminated)
|
||
result = v;
|
||
break;
|
||
}
|
||
lower_stmt(a, fc, items->data[i]);
|
||
}
|
||
if (!fc->terminated)
|
||
emit_scope_defers(a, fc, fc->env.size - 1);
|
||
env_pop(fc);
|
||
return result;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_primary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pn) {
|
||
switch (pn->primary_expr.kind) {
|
||
case SPL_AST_INTEGER: {
|
||
spl_type_id_t t = kw_type(a, "i32");
|
||
if (fc->hint && is_int_type(a->sema, fc->hint))
|
||
t = underlying(a->sema, fc->hint);
|
||
return const_int(a, fc, t, (usize)pn->primary_expr.integer_expr);
|
||
}
|
||
case SPL_AST_FLOAT: {
|
||
spl_type_id_t t = kw_type(a, "f64");
|
||
if (fc->hint && is_float_type(a->sema, fc->hint))
|
||
t = underlying(a->sema, fc->hint);
|
||
return const_float(a, fc, t, pn->primary_expr.float_expr);
|
||
}
|
||
case SPL_AST_CHAR_LIT: {
|
||
spl_type_id_t t = kw_type(a, "u8");
|
||
if (fc->hint && is_int_type(a->sema, fc->hint))
|
||
t = underlying(a->sema, fc->hint);
|
||
return const_int(a, fc, t, (usize)(unsigned char)pn->primary_expr.char_lit_expr);
|
||
}
|
||
case SPL_AST_STRING_LIT: {
|
||
spl_type_id_t u8 = kw_type(a, "u8");
|
||
spl_type_id_t t = spl_type_ptr((spl_type_t *)&a->sema->type, u8);
|
||
return const_str(a, fc, t, pn->primary_expr.string_lit_expr);
|
||
}
|
||
case SPL_AST_TRUE:
|
||
case SPL_AST_FALSE:
|
||
return const_bool(a, fc, pn->primary_expr.kind == SPL_AST_TRUE);
|
||
case SPL_AST_NULL: {
|
||
spl_type_id_t ht = underlying(a->sema, fc->hint);
|
||
spl_type_node_t *htt = ht ? tn(a->sema, ht) : NULL;
|
||
if (htt && htt->kind == SPL_TYPE_SLICE) {
|
||
spl_ir_node_ref_t sl = emit_agg_construct(a, fc, ht);
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, htt->slice_element);
|
||
agg_construct_add(a, fc, sl, const_int(a, fc, ep, 0));
|
||
agg_construct_add(a, fc, sl, const_int(a, fc, kw_type(a, "usize"), 0));
|
||
return sl;
|
||
}
|
||
spl_type_id_t t = htt && htt->kind == SPL_TYPE_PTR
|
||
? ht
|
||
: spl_type_ptr((spl_type_t *)&a->sema->type, kw_type(a, "void"));
|
||
return const_int(a, fc, t, 0);
|
||
}
|
||
case SPL_AST_IDENT:
|
||
return lower_ident(a, fc, pn->primary_expr.ident, pn->resolved_def_id, 0);
|
||
case SPL_AST_EXPR_EXPR:
|
||
return lower_expr(a, fc, pn->primary_expr.expr);
|
||
case SPL_AST_BLOCK_EXPR:
|
||
return lower_block_expr(a, fc, &pn->primary_expr.block_expr);
|
||
case SPL_AST_ARRAY_LIT: {
|
||
spl_type_id_t elem = resolve_type_expr(a, fc, pn->primary_expr.array_lit_expr.type_expr);
|
||
if (!elem)
|
||
elem = kw_type(a, "i32");
|
||
spl_type_id_t arr = spl_type_array((spl_type_t *)&a->sema->type, elem,
|
||
(usize)pn->primary_expr.array_lit_expr.integer);
|
||
VEC(spl_ir_node_ref_t) vals;
|
||
vec_init(vals);
|
||
for (usize i = 0; i < pn->primary_expr.array_lit_expr.expr_list.size; i++) {
|
||
fc->hint = elem;
|
||
spl_ir_node_ref_t v =
|
||
lower_expr(a, fc, pn->primary_expr.array_lit_expr.expr_list.data[i]);
|
||
fc->hint = 0;
|
||
v = coerce_to(a, fc, v, node_type(fc, v), elem);
|
||
vec_push(vals, v);
|
||
}
|
||
spl_ir_node_ref_t agg = emit_agg_construct(a, fc, arr);
|
||
for (usize i = 0; i < vals.size; i++)
|
||
agg_construct_add(a, fc, agg, vals.data[i]);
|
||
vec_free(vals);
|
||
return agg;
|
||
}
|
||
case SPL_AST_ARGGREGATE_INIT: {
|
||
spl_type_id_t tid = 0;
|
||
if (pn->primary_expr.aggregate_init.name) {
|
||
spl_def_id_t def = root_lookup(a, pn->primary_expr.aggregate_init.name);
|
||
if (def)
|
||
tid = underlying(a->sema, def_at(a->sema, def)->type_id);
|
||
else {
|
||
ir_env_t *it = env_find(fc, pn->primary_expr.aggregate_init.name);
|
||
if (it && it->is_type)
|
||
tid = underlying(a->sema, it->tid);
|
||
}
|
||
} else {
|
||
spl_type_id_t hint_t = underlying(a->sema, fc->hint);
|
||
spl_type_node_t *htt = hint_t ? tn(a->sema, hint_t) : NULL;
|
||
if (!htt || (htt->kind != SPL_TYPE_STRUCT && htt->kind != SPL_TYPE_UNION &&
|
||
htt->kind != SPL_TYPE_SLICE && htt->kind != SPL_TYPE_RANGE)) {
|
||
diag(a, fc, 0, "anonymous aggregate literal without context type");
|
||
return 0;
|
||
}
|
||
VEC(spl_ir_node_ref_t) vals;
|
||
vec_init(vals);
|
||
for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) {
|
||
spl_ast_node_t *item =
|
||
node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]);
|
||
if (!item || !item->aggregate_init_item.ident)
|
||
continue;
|
||
isize fidx = agg_index_or_builtin(a, hint_t, item->aggregate_init_item.ident);
|
||
if (fidx < 0) {
|
||
diag(a, fc, 0, "unknown field in aggregate literal");
|
||
continue;
|
||
}
|
||
spl_type_id_t ft = agg_field_tid_or_builtin(a, hint_t, fidx);
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr);
|
||
/* 字段是指针、值是聚合 lvalue:自动取地址left = expr 语义*/
|
||
spl_type_node_t *fld_t = ft ? tn(a->sema, ft) : NULL;
|
||
spl_type_node_t *v_t = tn(a->sema, underlying(a->sema, node_type(fc, v)));
|
||
if (fld_t && fld_t->kind == SPL_TYPE_PTR && v_t &&
|
||
(v_t->kind == SPL_TYPE_STRUCT || v_t->kind == SPL_TYPE_UNION ||
|
||
v_t->kind == SPL_TYPE_ENUM)) {
|
||
spl_type_id_t lt = 0;
|
||
spl_ir_node_ref_t addr =
|
||
lower_lvalue(a, fc, item->aggregate_init_item.expr, <);
|
||
if (addr)
|
||
v = addr;
|
||
}
|
||
if (ft)
|
||
v = coerce_to(a, fc, v, node_type(fc, v), ft);
|
||
vec_push(vals, v);
|
||
}
|
||
spl_ir_node_ref_t agg = emit_agg_construct(a, fc, hint_t);
|
||
for (usize i = 0; i < vals.size; i++)
|
||
agg_construct_add(a, fc, agg, vals.data[i]);
|
||
vec_free(vals);
|
||
return agg;
|
||
}
|
||
spl_type_node_t *tt = tn(a->sema, tid);
|
||
if (!tt)
|
||
return 0;
|
||
if (tt->kind == SPL_TYPE_ENUM) {
|
||
VEC(spl_ir_node_ref_t) vals;
|
||
vec_init(vals);
|
||
for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) {
|
||
spl_ast_node_t *item =
|
||
node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]);
|
||
if (!item || !item->aggregate_init_item.ident)
|
||
continue;
|
||
isize vidx = enum_variant_index(a, tid, item->aggregate_init_item.ident);
|
||
if (vidx < 0) {
|
||
diag(a, fc, 0, "unknown enum variant");
|
||
continue;
|
||
}
|
||
vec_push(vals, const_int(a, fc, enum_tag_tid(a), (usize)vidx));
|
||
if (item->aggregate_init_item.expr) {
|
||
spl_type_id_t pt = enum_payload_tid(a, tid, vidx);
|
||
fc->hint = pt;
|
||
spl_ir_node_ref_t pv = lower_expr(a, fc, item->aggregate_init_item.expr);
|
||
fc->hint = 0;
|
||
if (pt)
|
||
pv = coerce_to(a, fc, pv, node_type(fc, pv), pt);
|
||
vec_push(vals, pv);
|
||
}
|
||
}
|
||
spl_ir_node_ref_t agg = emit_agg_construct(a, fc, tid);
|
||
for (usize i = 0; i < vals.size; i++)
|
||
agg_construct_add(a, fc, agg, vals.data[i]);
|
||
vec_free(vals);
|
||
return agg;
|
||
}
|
||
if (tt->kind != SPL_TYPE_STRUCT) {
|
||
diag(a, fc, 0, "aggregate literal target is not a struct");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t agg = 0;
|
||
usize nfields = tt->agg_field_types.size;
|
||
VEC(spl_ir_node_ref_t) vals;
|
||
vec_init(vals);
|
||
for (usize i = 0; i < nfields; i++) {
|
||
const char *fname = agg_field_name_at(a, tid, (isize)i);
|
||
spl_ast_node_ref_t found = 0;
|
||
for (usize j = 0; j < pn->primary_expr.aggregate_init.expr.size; j++) {
|
||
spl_ast_node_t *item =
|
||
node_at(a->sema, pn->primary_expr.aggregate_init.expr.data[j]);
|
||
if (item && fname && item->aggregate_init_item.ident &&
|
||
strcmp(item->aggregate_init_item.ident, fname) == 0) {
|
||
found = pn->primary_expr.aggregate_init.expr.data[j];
|
||
break;
|
||
}
|
||
}
|
||
if (!found) {
|
||
vec_push(vals, const_int(a, fc, tt->agg_field_types.data[i], 0));
|
||
continue;
|
||
}
|
||
spl_ast_node_t *item = node_at(a->sema, found);
|
||
fc->hint = tt->agg_field_types.data[i];
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, item->aggregate_init_item.expr);
|
||
fc->hint = 0;
|
||
/* 字段是指针、值是聚合 lvalue:自动取地址left = expr 语义*/
|
||
spl_type_node_t *fld_t = tn(a->sema, tt->agg_field_types.data[i]);
|
||
spl_type_node_t *v_t = tn(a->sema, underlying(a->sema, node_type(fc, v)));
|
||
if (fld_t && fld_t->kind == SPL_TYPE_PTR && v_t &&
|
||
(v_t->kind == SPL_TYPE_STRUCT || v_t->kind == SPL_TYPE_UNION ||
|
||
v_t->kind == SPL_TYPE_ENUM)) {
|
||
spl_type_id_t lt = 0;
|
||
spl_ir_node_ref_t addr = lower_lvalue(a, fc, item->aggregate_init_item.expr, <);
|
||
if (addr)
|
||
v = addr;
|
||
}
|
||
v = coerce_to(a, fc, v, node_type(fc, v), tt->agg_field_types.data[i]);
|
||
vec_push(vals, v);
|
||
}
|
||
agg = emit_agg_construct(a, fc, tid);
|
||
for (usize i = 0; i < vals.size; i++)
|
||
agg_construct_add(a, fc, agg, vals.data[i]);
|
||
vec_free(vals);
|
||
return agg;
|
||
}
|
||
case SPL_AST_BUILTIN_EXPR: {
|
||
const char *id = pn->primary_expr.builtin_expr.ident;
|
||
const spl_builtin_t *bi = spl_builtin_lookup(id);
|
||
if (!bi) {
|
||
diag(a, fc, 0, "unsupported builtin call");
|
||
return 0;
|
||
}
|
||
usize nargs = pn->primary_expr.builtin_expr.expr_list.size;
|
||
if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) {
|
||
diag(a, fc, 0, "builtin @arg count mismatch");
|
||
return 0;
|
||
}
|
||
/* @sizeof / @bitsizeof / @alignof / @field_count: 单类型参数 → 对应 IR 类型查询节点 */
|
||
if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF ||
|
||
bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_FIELD_COUNT) {
|
||
spl_type_id_t t =
|
||
type_from_type_like(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||
if (!t) {
|
||
diag(a, fc, 0, "builtin @type query: cannot resolve type");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
switch (bi->kind) {
|
||
case SPL_BUILTIN_SIZE_OF:
|
||
e->kind = SPL_IR_TYPE_SIZEOF;
|
||
e->ir_sizeof.tid = t;
|
||
break;
|
||
case SPL_BUILTIN_BITSIZE_OF:
|
||
e->kind = SPL_IR_TYPE_BITSIZEOF;
|
||
e->bitsizeof.tid = t;
|
||
break;
|
||
case SPL_BUILTIN_ALIGN_OF:
|
||
e->kind = SPL_IR_TYPE_ALIGNOF;
|
||
e->ir_alignof.tid = t;
|
||
break;
|
||
default:
|
||
e->kind = SPL_IR_TYPE_FIELD_COUNT;
|
||
e->field_count.tid = t;
|
||
break;
|
||
}
|
||
set_ntype(fc, n, kw_type(a, "usize"));
|
||
return n;
|
||
}
|
||
/* @offsetof(T, field): 字段名 → 索引常量节点 */
|
||
if (bi->kind == SPL_BUILTIN_OFFSET_OF) {
|
||
spl_type_id_t t =
|
||
type_from_type_like(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||
spl_ast_node_t *farg =
|
||
node_at(a->sema, pn->primary_expr.builtin_expr.expr_list.data[1]);
|
||
if (!t || !farg || farg->kind != SPL_AST_EXPR) {
|
||
diag(a, fc, 0, "@offsetof: invalid arguments");
|
||
return 0;
|
||
}
|
||
spl_ast_node_t *fn_ = farg->expr.op == SPL_AST_PRIMARY_EXPR
|
||
? node_at(a->sema, farg->expr.op_expr.left)
|
||
: NULL;
|
||
const char *fname =
|
||
(fn_ && fn_->primary_expr.kind == SPL_AST_IDENT) ? fn_->primary_expr.ident : NULL;
|
||
isize fidx = fname ? agg_index_or_builtin(a, t, fname) : -1;
|
||
if (fidx < 0) {
|
||
diag(a, fc, 0, "@offsetof: unknown field");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t idx = const_int(a, fc, kw_type(a, "usize"), (usize)fidx);
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_TYPE_OFFSETOF;
|
||
e->ir_offsetof.tid = t;
|
||
e->ir_offsetof.field_idx = idx;
|
||
set_ntype(fc, n, kw_type(a, "usize"));
|
||
return n;
|
||
}
|
||
/* @dbg(args...): 逐参数求值(副作用),发射断点 */
|
||
if (bi->kind == SPL_BUILTIN_DBG) {
|
||
for (usize i = 0; i < nargs; i++)
|
||
lower_expr(a, fc, pn->primary_expr.builtin_expr.expr_list.data[i]);
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_DBG_BREAKPOINT;
|
||
set_ntype(fc, n, kw_type(a, "void"));
|
||
return n;
|
||
}
|
||
/* @assert(cond): 若 cond 为假 → trap(HALT) */
|
||
if (bi->kind == SPL_BUILTIN_ASSERT) {
|
||
spl_ir_node_ref_t c =
|
||
lower_expr(a, fc, pn->primary_expr.builtin_expr.expr_list.data[0]);
|
||
usize trap_b = new_block(fc);
|
||
usize exit_b = new_block(fc);
|
||
emit_br(a, fc, c, exit_b, trap_b);
|
||
begin_block(fc, trap_b);
|
||
{
|
||
spl_ir_node_ref_t n = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, n);
|
||
e->kind = SPL_IR_CONTROL_TRAP;
|
||
set_ntype(fc, n, kw_type(a, "void"));
|
||
fc->terminated = 1;
|
||
}
|
||
begin_block(fc, exit_b);
|
||
spl_ir_node_ref_t r = emit_node(a, fc);
|
||
spl_ir_node_t *e = enode(a, fc, r);
|
||
e->kind = SPL_IR_TYPE_CONST;
|
||
e->type_const.tid = kw_type(a, "void");
|
||
set_ntype(fc, r, kw_type(a, "void"));
|
||
return r;
|
||
}
|
||
/* @import: 预留未实现 */
|
||
diag(a, fc, 0, "builtin @import not implemented");
|
||
return 0;
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_prefix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) {
|
||
switch (pf->prefix_expr.kind) {
|
||
case SPL_AST_MINUS_EXPR: {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr);
|
||
spl_type_id_t t = underlying(a->sema, node_type(fc, v));
|
||
if (!is_num_type(a->sema, t)) {
|
||
diag(a, fc, 0, "unary minus requires numeric");
|
||
return 0;
|
||
}
|
||
return emit_arith(a, fc, SPL_IR_ARITH_NEG, t, v, 0);
|
||
}
|
||
case SPL_AST_BANG_EXPR: {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr);
|
||
spl_ir_node_ref_t z = const_bool(a, fc, 0);
|
||
return emit_cmp(a, fc, SPL_IR_CMP_EQ, kw_type(a, "bool"), v, z);
|
||
}
|
||
case SPL_AST_TILDE_EXPR: {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr);
|
||
spl_type_id_t t = underlying(a->sema, node_type(fc, v));
|
||
if (!is_int_type(a->sema, t)) {
|
||
diag(a, fc, 0, "~ requires integer");
|
||
return 0;
|
||
}
|
||
return emit_arith(a, fc, SPL_IR_ARITH_NOT, t, v, 0);
|
||
}
|
||
case SPL_AST_AMPERSAND_EXPR: {
|
||
spl_type_id_t t = 0;
|
||
spl_ir_node_ref_t addr = lower_lvalue(a, fc, pf->prefix_expr.postfix_expr, &t);
|
||
if (addr) {
|
||
spl_type_id_t pt = spl_type_ptr((spl_type_t *)&a->sema->type, t);
|
||
set_ntype(fc, addr, pt);
|
||
return addr;
|
||
}
|
||
spl_ast_node_t *operand = node_at(a->sema, pf->prefix_expr.postfix_expr);
|
||
if (operand && operand->kind == SPL_AST_EXPR && operand->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, operand->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_IDENT) {
|
||
spl_def_id_t def = root_lookup(a, pn->primary_expr.ident);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->kind == SPL_DEF_FN_PARAMS && d->type_id) {
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, d->type_id);
|
||
if (fid)
|
||
return const_fnref(a, fc, d->type_id, fid);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
diag(a, fc, 0, "& requires addressable operand");
|
||
return 0;
|
||
}
|
||
case SPL_AST_ASTERISK_EXPR: {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, pf->prefix_expr.postfix_expr);
|
||
spl_type_id_t t = underlying(a->sema, node_type(fc, v));
|
||
spl_type_node_t *tt = tn(a->sema, t);
|
||
if (tt && tt->kind == SPL_TYPE_PTR) {
|
||
spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee);
|
||
return emit_load(a, fc, pointee, v);
|
||
}
|
||
return v;
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
/* ---- 调用目标 ---- */
|
||
|
||
typedef struct {
|
||
spl_type_id_t fn_tid;
|
||
spl_ir_node_ref_t callee;
|
||
} callee_t;
|
||
|
||
static int resolve_callee(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t base, callee_t *out) {
|
||
memset(out, 0, sizeof *out);
|
||
spl_ast_node_t *n = node_at(a->sema, base);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
if (n->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_IDENT) {
|
||
const char *name = pn->primary_expr.ident;
|
||
ir_env_t *it = env_find_def(fc, pn->resolved_def_id, name);
|
||
if (it && it->is_type) {
|
||
diag(a, fc, base, "type is not callable");
|
||
return 0;
|
||
}
|
||
spl_def_id_t def = root_lookup(a, name);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
if (d && d->kind == SPL_DEF_FN_PARAMS && d->type_id) {
|
||
out->fn_tid = d->type_id;
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, d->type_id);
|
||
if (fid) {
|
||
out->callee = const_fnref(a, fc, d->type_id, fid);
|
||
return 1;
|
||
}
|
||
diag(a, fc, base, "function has no IR function");
|
||
return 0;
|
||
}
|
||
}
|
||
/* 命名空间内裸名互调:Str.from_cstr 中调cstrlen(...) */
|
||
if (fc->ns_tid) {
|
||
spl_type_id_t mt = agg_member_type(a, fc->ns_tid, name);
|
||
spl_type_node_t *mtn = mt ? tn(a->sema, mt) : NULL;
|
||
if (mt && mtn && mtn->kind == SPL_TYPE_FN) {
|
||
out->fn_tid = mt;
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, mt);
|
||
if (fid) {
|
||
out->callee = const_fnref(a, fc, mt, fid);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (n->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||
spl_ast_node_t *pf = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) {
|
||
const char *fname = pf->postfix_expr.field_expr;
|
||
spl_ast_node_ref_t bref = pf->postfix_expr.primary_expr;
|
||
spl_type_id_t ttr = type_of_type_ref(a, fc, bref);
|
||
if (ttr) {
|
||
spl_type_id_t mt = agg_member_type(a, ttr, fname);
|
||
spl_type_node_t *mtn = tn(a->sema, mt);
|
||
if (mt && mtn && mtn->kind == SPL_TYPE_FN) {
|
||
out->fn_tid = mt;
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, mt);
|
||
if (fid) {
|
||
out->callee = const_fnref(a, fc, mt, fid);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
spl_ir_node_ref_t bv = lower_expr(a, fc, bref);
|
||
spl_type_id_t vt = underlying(a->sema, node_type(fc, bv));
|
||
spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL;
|
||
if (vtt && vtt->kind == SPL_TYPE_PTR) {
|
||
vt = underlying(a->sema, vtt->ptr_pointee);
|
||
vtt = tn(a->sema, vt);
|
||
}
|
||
/* enum 方法:在enum def 上查*/
|
||
spl_type_id_t lookup = vt;
|
||
spl_type_id_t e0 = 0;
|
||
if (vtt && is_enum_expand(a, vt, &e0))
|
||
lookup = e0;
|
||
spl_type_id_t mt = vtt ? agg_member_type(a, lookup, fname) : 0;
|
||
spl_type_node_t *mtn = mt ? tn(a->sema, mt) : NULL;
|
||
if (mt && mtn && mtn->kind == SPL_TYPE_FN) {
|
||
out->fn_tid = mt;
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, mt);
|
||
if (fid) {
|
||
out->callee = const_fnref(a, fc, mt, fid);
|
||
return 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
out->callee = lower_expr(a, fc, base);
|
||
out->fn_tid = node_type(fc, out->callee);
|
||
if (out->fn_tid) {
|
||
spl_type_node_t *ft = tn(a->sema, underlying(a->sema, out->fn_tid));
|
||
if (ft && ft->kind != SPL_TYPE_FN) {
|
||
diag(a, fc, base, "call requires function type");
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_field(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) {
|
||
const char *fname = pf->postfix_expr.field_expr;
|
||
spl_type_id_t ttr = type_of_type_ref(a, fc, pf->postfix_expr.primary_expr);
|
||
if (ttr) {
|
||
spl_type_node_t *ttr_t = tn(a->sema, ttr);
|
||
if (ttr_t && ttr_t->kind == SPL_TYPE_ENUM) {
|
||
isize vidx = enum_variant_index(a, ttr, fname);
|
||
if (vidx >= 0)
|
||
return enum_variant_value(a, fc, ttr, vidx);
|
||
}
|
||
/* 聚合命名空间成员:static var/const 全局数据 */
|
||
spl_def_id_t gdef = def_for_type(a, ttr);
|
||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||
spl_var_def_t *e = &gd->agg_def.data[i];
|
||
if (e->name && strcmp(e->name, fname) == 0 && e->def_id) {
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
if (ed && ed->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, e->def_id);
|
||
if (gi >= 0)
|
||
return emit_load(a, fc, e->type_id,
|
||
emit_global_alloc(a, fc, e->type_id, (usize)gi));
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
diag(a, fc, 0, "aggregate member is not a value");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t base = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
if (!base)
|
||
return 0;
|
||
spl_type_id_t bt = underlying(a->sema, node_type(fc, base));
|
||
spl_type_node_t *tt = tn(a->sema, bt);
|
||
if (!tt)
|
||
return 0;
|
||
spl_type_id_t agg_tid = bt;
|
||
spl_ir_node_ref_t agg_val = base;
|
||
if (tt->kind == SPL_TYPE_PTR) {
|
||
agg_tid = underlying(a->sema, tt->ptr_pointee);
|
||
tt = tn(a->sema, agg_tid);
|
||
agg_val = emit_load(a, fc, agg_tid, base);
|
||
}
|
||
if (!tt)
|
||
return 0;
|
||
if (tt->kind == SPL_TYPE_SLICE) {
|
||
if (strcmp(fname, "ptr") == 0) {
|
||
spl_type_id_t ft = spl_type_ptr((spl_type_t *)&a->sema->type, tt->slice_element);
|
||
return emit_agg_extract(a, fc, agg_tid, ft, 0, agg_val);
|
||
}
|
||
if (strcmp(fname, "len") == 0)
|
||
return emit_agg_extract(a, fc, agg_tid, kw_type(a, "usize"), 1, agg_val);
|
||
diag(a, fc, 0, "unknown slice field");
|
||
return 0;
|
||
}
|
||
if (tt->kind == SPL_TYPE_RANGE) {
|
||
if (strcmp(fname, "begin") == 0)
|
||
return emit_agg_extract(a, fc, agg_tid, tt->range_element, 0, agg_val);
|
||
if (strcmp(fname, "end") == 0)
|
||
return emit_agg_extract(a, fc, agg_tid, tt->range_element, 1, agg_val);
|
||
diag(a, fc, 0, "unknown range field");
|
||
return 0;
|
||
}
|
||
isize fidx = agg_member_index(a, agg_tid, fname);
|
||
if (fidx < 0) {
|
||
diag(a, fc, 0, "unknown field");
|
||
return 0;
|
||
}
|
||
spl_type_id_t ft = agg_field_tid_at(a, agg_tid, fidx);
|
||
return emit_agg_extract(a, fc, agg_tid, ft, fidx, agg_val);
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_postfix(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *pf) {
|
||
switch (pf->postfix_expr.kind) {
|
||
case SPL_AST_CALL_EXPR: {
|
||
callee_t cal;
|
||
if (!resolve_callee(a, fc, pf->postfix_expr.primary_expr, &cal))
|
||
return 0;
|
||
spl_type_node_t *ft = tn(a->sema, underlying(a->sema, cal.fn_tid));
|
||
usize nparams = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.params.size : 0;
|
||
spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr;
|
||
spl_ir_node_ref_t av[64];
|
||
usize na = args->size < 64 ? args->size : 64;
|
||
for (usize i = 0; i < na; i++) {
|
||
spl_type_id_t pt = 0;
|
||
if (i < nparams && ft && ft->kind == SPL_TYPE_FN)
|
||
pt = ft->fn_type.params.data[i];
|
||
fc->hint = pt;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, args->data[i]);
|
||
fc->hint = 0;
|
||
if (pt)
|
||
v = coerce_to(a, fc, v, node_type(fc, v), pt);
|
||
av[i] = v;
|
||
}
|
||
return emit_call(a, fc, cal.fn_tid, cal.callee, av, na);
|
||
}
|
||
case SPL_AST_FIELD_EXPR:
|
||
return lower_field(a, fc, pf);
|
||
case SPL_AST_DEREF_EXPR: {
|
||
spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
spl_type_id_t pt = underlying(a->sema, node_type(fc, p));
|
||
spl_type_node_t *tt = tn(a->sema, pt);
|
||
if (!tt || tt->kind != SPL_TYPE_PTR) {
|
||
diag(a, fc, 0, ".* requires pointer");
|
||
return 0;
|
||
}
|
||
spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee);
|
||
return emit_load(a, fc, pointee, p);
|
||
}
|
||
case SPL_AST_INDEX_EXPR: {
|
||
spl_type_id_t elem = 0;
|
||
spl_ir_node_ref_t addr = index_addr(a, fc, pf, &elem);
|
||
if (!addr)
|
||
return 0;
|
||
return emit_load(a, fc, elem, addr);
|
||
}
|
||
case SPL_AST_SLICE_EXPR: {
|
||
spl_type_id_t bt = 0;
|
||
spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, pf->postfix_expr.primary_expr, &bt);
|
||
spl_ir_node_ref_t base_val = 0;
|
||
if (!base_lv) {
|
||
/* base 是切片/数组表达式(如 arr[1..4][1..2]):取值后提取字段 */
|
||
base_val = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
bt = node_type(fc, base_val);
|
||
}
|
||
spl_type_node_t *tt = tn(a->sema, underlying(a->sema, bt));
|
||
if (!tt || (tt->kind != SPL_TYPE_ARRAY && tt->kind != SPL_TYPE_SLICE)) {
|
||
diag(a, fc, 0, "slice requires array/slice");
|
||
return 0;
|
||
}
|
||
spl_type_id_t elem =
|
||
tt->kind == SPL_TYPE_ARRAY ? tt->array_type.element : tt->slice_element;
|
||
spl_type_id_t slice_t = spl_type_slice((spl_type_t *)&a->sema->type, elem);
|
||
spl_ir_node_ref_t base_ptr = 0;
|
||
spl_ir_node_ref_t total_len = 0;
|
||
if (tt->kind == SPL_TYPE_ARRAY) {
|
||
base_ptr = base_lv;
|
||
total_len = const_int(a, fc, kw_type(a, "usize"), tt->array_type.len);
|
||
} else {
|
||
spl_ir_node_ref_t slv = base_lv ? emit_load(a, fc, bt, base_lv) : base_val;
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, elem);
|
||
base_ptr = emit_agg_extract(a, fc, bt, ep, 0, slv);
|
||
total_len = emit_agg_extract(a, fc, bt, kw_type(a, "usize"), 1, slv);
|
||
}
|
||
spl_ir_node_ref_t beg = 0, end = 0;
|
||
if (pf->postfix_expr.slice_expr.begin)
|
||
beg = lower_expr(a, fc, pf->postfix_expr.slice_expr.begin);
|
||
else
|
||
beg = const_int(a, fc, kw_type(a, "usize"), 0);
|
||
if (pf->postfix_expr.slice_expr.end)
|
||
end = lower_expr(a, fc, pf->postfix_expr.slice_expr.end);
|
||
spl_type_id_t iszt = kw_type(a, "isize");
|
||
spl_ir_node_ref_t ptr =
|
||
emit_offset(a, fc, elem, base_ptr, coerce_to(a, fc, beg, node_type(fc, beg), iszt));
|
||
spl_ir_node_ref_t len = 0;
|
||
spl_ir_node_ref_t begu = coerce_to(a, fc, beg, node_type(fc, beg), kw_type(a, "usize"));
|
||
if (end) {
|
||
len = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "usize"),
|
||
coerce_to(a, fc, end, node_type(fc, end), kw_type(a, "usize")), begu);
|
||
} else {
|
||
len = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "usize"), total_len, begu);
|
||
}
|
||
spl_ir_node_ref_t sl = emit_agg_construct(a, fc, slice_t);
|
||
agg_construct_add(a, fc, sl, ptr);
|
||
agg_construct_add(a, fc, sl, len);
|
||
return sl;
|
||
}
|
||
case SPL_AST_AS_EXPR: {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
spl_type_id_t dt = resolve_type_expr(a, fc, pf->postfix_expr.type_expr);
|
||
if (!dt)
|
||
return v;
|
||
return coerce_to(a, fc, v, node_type(fc, v), dt);
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_binary(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) {
|
||
spl_ast_node_ref_t lr = n->expr.op_expr.left;
|
||
spl_ast_node_ref_t rr = n->expr.op_expr.right;
|
||
switch (n->expr.op) {
|
||
case SPL_AST_ADD_EXPR:
|
||
case SPL_AST_SUB_EXPR:
|
||
case SPL_AST_MUL_EXPR:
|
||
case SPL_AST_DIV_EXPR:
|
||
case SPL_AST_MOD_EXPR:
|
||
case SPL_AST_BITOR_EXPR:
|
||
case SPL_AST_BITXOR_EXPR:
|
||
case SPL_AST_BITAND_EXPR:
|
||
case SPL_AST_LSHIFT_EXPR:
|
||
case SPL_AST_RSHIFT_EXPR: {
|
||
spl_ir_node_ref_t l = lower_expr(a, fc, lr);
|
||
spl_ir_node_ref_t r = lower_expr(a, fc, rr);
|
||
spl_type_id_t lt = underlying(a->sema, node_type(fc, l));
|
||
spl_type_id_t rt = underlying(a->sema, node_type(fc, r));
|
||
if ((n->expr.op == SPL_AST_ADD_EXPR || n->expr.op == SPL_AST_SUB_EXPR) &&
|
||
is_ptr_type(a->sema, lt) && is_int_type(a->sema, rt)) {
|
||
spl_type_node_t *ltt = tn(a->sema, lt);
|
||
spl_type_id_t elem = underlying(a->sema, ltt->ptr_pointee);
|
||
spl_ir_node_ref_t off = coerce_to(a, fc, r, rt, kw_type(a, "isize"));
|
||
if (n->expr.op == SPL_AST_SUB_EXPR) {
|
||
spl_ir_node_ref_t zero = const_int(a, fc, kw_type(a, "isize"), 0);
|
||
off = emit_arith(a, fc, SPL_IR_ARITH_SUB, kw_type(a, "isize"), zero, off);
|
||
}
|
||
return emit_offset(a, fc, elem, l, off);
|
||
}
|
||
spl_type_id_t res = lt;
|
||
if (!type_same(a->sema, lt, rt)) {
|
||
if (expr_is_int_literal(a, lr) && is_int_type(a->sema, rt))
|
||
res = rt;
|
||
else if (expr_is_int_literal(a, rr) && is_int_type(a->sema, lt))
|
||
res = lt;
|
||
else
|
||
res = lt;
|
||
}
|
||
spl_ir_kind_t k;
|
||
switch (n->expr.op) {
|
||
case SPL_AST_ADD_EXPR:
|
||
k = SPL_IR_ARITH_ADD;
|
||
break;
|
||
case SPL_AST_SUB_EXPR:
|
||
k = SPL_IR_ARITH_SUB;
|
||
break;
|
||
case SPL_AST_MUL_EXPR:
|
||
k = SPL_IR_ARITH_MUL;
|
||
break;
|
||
case SPL_AST_DIV_EXPR:
|
||
k = SPL_IR_ARITH_DIV;
|
||
break;
|
||
case SPL_AST_MOD_EXPR:
|
||
k = SPL_IR_ARITH_REM;
|
||
break;
|
||
case SPL_AST_BITOR_EXPR:
|
||
k = SPL_IR_ARITH_OR;
|
||
break;
|
||
case SPL_AST_BITXOR_EXPR:
|
||
k = SPL_IR_ARITH_XOR;
|
||
break;
|
||
case SPL_AST_BITAND_EXPR:
|
||
k = SPL_IR_ARITH_AND;
|
||
break;
|
||
case SPL_AST_LSHIFT_EXPR:
|
||
k = SPL_IR_ARITH_SHL;
|
||
break;
|
||
default:
|
||
k = SPL_IR_ARITH_SHR;
|
||
break;
|
||
}
|
||
spl_ir_node_ref_t l2 = coerce_to(a, fc, l, lt, res);
|
||
spl_ir_node_ref_t r2 = coerce_to(a, fc, r, rt, res);
|
||
return emit_arith(a, fc, k, res, l2, r2);
|
||
}
|
||
case SPL_AST_CMPEQ_EXPR:
|
||
case SPL_AST_CMPNE_EXPR:
|
||
case SPL_AST_CMP_LE_EXPR:
|
||
case SPL_AST_CMP_GE_EXPR:
|
||
case SPL_AST_CMP_LT_EXPR:
|
||
case SPL_AST_CMP_GT_EXPR: {
|
||
spl_ir_node_ref_t l = lower_expr(a, fc, lr);
|
||
spl_ir_node_ref_t r = lower_expr(a, fc, rr);
|
||
spl_type_id_t lt = underlying(a->sema, node_type(fc, l));
|
||
spl_type_id_t rt = underlying(a->sema, node_type(fc, r));
|
||
spl_type_id_t le = 0, re = 0;
|
||
int is_l_enum = is_enum_expand(a, lt, &le);
|
||
int is_r_enum = is_enum_expand(a, rt, &re);
|
||
if (is_l_enum && is_r_enum) {
|
||
spl_type_id_t tag_t = enum_tag_tid(a);
|
||
l = enum_tag_of(a, fc, le, l);
|
||
r = enum_tag_of(a, fc, re, r);
|
||
lt = tag_t;
|
||
rt = tag_t;
|
||
}
|
||
spl_type_id_t res = lt;
|
||
if (!type_same(a->sema, lt, rt)) {
|
||
if (is_int_type(a->sema, lt) && is_int_type(a->sema, rt))
|
||
res = expr_is_int_literal(a, lr) ? rt : lt;
|
||
else
|
||
res = lt;
|
||
}
|
||
l = coerce_to(a, fc, l, node_type(fc, l), res);
|
||
r = coerce_to(a, fc, r, node_type(fc, r), res);
|
||
spl_ir_kind_t k;
|
||
switch (n->expr.op) {
|
||
case SPL_AST_CMPEQ_EXPR:
|
||
k = SPL_IR_CMP_EQ;
|
||
break;
|
||
case SPL_AST_CMPNE_EXPR:
|
||
k = SPL_IR_CMP_NE;
|
||
break;
|
||
case SPL_AST_CMP_LE_EXPR:
|
||
k = SPL_IR_CMP_LE;
|
||
break;
|
||
case SPL_AST_CMP_GE_EXPR:
|
||
k = SPL_IR_CMP_GE;
|
||
break;
|
||
case SPL_AST_CMP_LT_EXPR:
|
||
k = SPL_IR_CMP_LT;
|
||
break;
|
||
default:
|
||
k = SPL_IR_CMP_GT;
|
||
break;
|
||
}
|
||
return emit_cmp(a, fc, k, res, l, r);
|
||
}
|
||
case SPL_AST_BOOLAND_EXPR:
|
||
case SPL_AST_BOOLOR_EXPR: {
|
||
spl_type_id_t bt = kw_type(a, "bool");
|
||
spl_ir_node_ref_t l = lower_expr(a, fc, lr);
|
||
usize t = new_block(fc), f = new_block(fc), join = new_block(fc);
|
||
spl_ir_node_ref_t slot = emit_alloca(a, fc, bt);
|
||
emit_br(a, fc, l, t, f);
|
||
begin_block(fc, t);
|
||
if (n->expr.op == SPL_AST_BOOLAND_EXPR) {
|
||
spl_ir_node_ref_t r = lower_expr(a, fc, rr);
|
||
emit_store(a, fc, bt, slot, r);
|
||
} else {
|
||
emit_store(a, fc, bt, slot, const_bool(a, fc, 1));
|
||
}
|
||
emit_jmp(a, fc, join);
|
||
begin_block(fc, f);
|
||
if (n->expr.op == SPL_AST_BOOLAND_EXPR) {
|
||
emit_store(a, fc, bt, slot, const_bool(a, fc, 0));
|
||
} else {
|
||
spl_ir_node_ref_t r = lower_expr(a, fc, rr);
|
||
emit_store(a, fc, bt, slot, r);
|
||
}
|
||
emit_jmp(a, fc, join);
|
||
begin_block(fc, join);
|
||
return emit_load(a, fc, bt, slot);
|
||
}
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_range_value(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) {
|
||
spl_ir_node_ref_t b = lower_expr(a, fc, n->expr.op_expr.left);
|
||
spl_type_id_t et = underlying(a->sema, node_type(fc, b));
|
||
spl_type_id_t range_t = spl_type_range((spl_type_t *)&a->sema->type, et);
|
||
spl_ir_node_ref_t e =
|
||
n->expr.op_expr.right ? lower_expr(a, fc, n->expr.op_expr.right) : const_int(a, fc, et, 0);
|
||
spl_ir_node_ref_t r = emit_agg_construct(a, fc, range_t);
|
||
agg_construct_add(a, fc, r, b);
|
||
agg_construct_add(a, fc, r, e);
|
||
return r;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_compound_op(spl_ast2ir_t *a, fnctx_t *fc, int op, spl_type_id_t tid,
|
||
spl_ir_node_ref_t cur, spl_ir_node_ref_t rhs) {
|
||
spl_ir_kind_t k;
|
||
switch (op) {
|
||
case SPL_AST_ASSIGN_ADD_EXPR:
|
||
k = SPL_IR_ARITH_ADD;
|
||
break;
|
||
case SPL_AST_ASSIGN_sUB_EXPR:
|
||
k = SPL_IR_ARITH_SUB;
|
||
break;
|
||
case SPL_AST_ASSIGN_MUL_EXPR:
|
||
k = SPL_IR_ARITH_MUL;
|
||
break;
|
||
case SPL_AST_ASSIGN_DIV_EXPR:
|
||
k = SPL_IR_ARITH_DIV;
|
||
break;
|
||
case SPL_AST_ASSIGN_MOD_EXPR:
|
||
k = SPL_IR_ARITH_REM;
|
||
break;
|
||
case SPL_AST_ASSIGN_AND_EXPR:
|
||
k = SPL_IR_ARITH_AND;
|
||
break;
|
||
case SPL_AST_ASSIGN_OR_EXPR:
|
||
k = SPL_IR_ARITH_OR;
|
||
break;
|
||
case SPL_AST_ASSIGN_XOR_EXPR:
|
||
k = SPL_IR_ARITH_XOR;
|
||
break;
|
||
case SPL_AST_ASSIGN_LSHIFT_EXPR:
|
||
k = SPL_IR_ARITH_SHL;
|
||
break;
|
||
case SPL_AST_ASSIGN_USHIFT_EXPR:
|
||
k = SPL_IR_ARITH_SHR;
|
||
break;
|
||
default:
|
||
return rhs;
|
||
}
|
||
spl_ir_node_ref_t r = coerce_to(a, fc, rhs, node_type(fc, rhs), tid);
|
||
return emit_arith(a, fc, k, tid, cur, r);
|
||
}
|
||
|
||
/* 字段链赋o.a.b = rhs:直接按字节地址写回(含指针中间字段*/
|
||
static void field_assign(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t target,
|
||
spl_ir_node_ref_t rhs) {
|
||
spl_type_id_t ft = 0;
|
||
spl_ir_node_ref_t addr = lower_field_address(a, fc, target, &ft);
|
||
if (!addr || !ft) {
|
||
diag(a, fc, target, "field assignment: unsupported base");
|
||
return;
|
||
}
|
||
rhs = coerce_to(a, fc, rhs, node_type(fc, rhs), ft);
|
||
emit_store(a, fc, ft, addr, rhs);
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_assign(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *n) {
|
||
spl_ast_node_ref_t lr = n->expr.op_expr.left;
|
||
spl_ast_node_ref_t rr = n->expr.op_expr.right;
|
||
spl_ast_node_t *ln = node_at(a->sema, lr);
|
||
if (!ln || ln->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
int compound = n->expr.op != SPL_AST_ASSIGN_EXPR;
|
||
spl_ast_node_t *pf = NULL;
|
||
if (ln->expr.op == SPL_AST_POSTFIX_EXPR)
|
||
pf = node_at(a->sema, ln->expr.op_expr.left);
|
||
|
||
if (ln->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, ln->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_IDENT) {
|
||
ir_env_t *it = env_find_def(fc, pn->resolved_def_id, pn->primary_expr.ident);
|
||
spl_type_id_t lt = 0;
|
||
spl_ir_node_ref_t target = 0;
|
||
if (it && it->slot) {
|
||
lt = it->tid;
|
||
target = it->slot;
|
||
} else {
|
||
/* 全局 var(顶/ 命名空间裸名*/
|
||
spl_def_id_t def = pn->resolved_def_id;
|
||
if (!def)
|
||
def = root_lookup(a, pn->primary_expr.ident);
|
||
if (def) {
|
||
spl_def_node_t *d = def_at(a->sema, def);
|
||
isize gi0 = (d && d->kind == SPL_DEF_VAR) ? gdata_index_by_def(a, def) : -1;
|
||
if (gi0 >= 0) {
|
||
lt = d->type_id;
|
||
target = emit_global_alloc(a, fc, lt, (usize)gi0);
|
||
} else if (fc->ns_tid) {
|
||
spl_def_id_t gdef = def_for_type(a, fc->ns_tid);
|
||
spl_def_node_t *gd = gdef ? def_at(a->sema, gdef) : NULL;
|
||
for (usize i = 0; gd && i < gd->agg_def.size; i++) {
|
||
spl_var_def_t *e = &gd->agg_def.data[i];
|
||
if (e->name && strcmp(e->name, pn->primary_expr.ident) == 0 &&
|
||
e->def_id) {
|
||
spl_def_node_t *ed = def_at(a->sema, e->def_id);
|
||
if (ed && ed->kind == SPL_DEF_VAR) {
|
||
isize gi = gdata_index_by_def(a, e->def_id);
|
||
if (gi >= 0) {
|
||
lt = e->type_id;
|
||
target = emit_global_alloc(a, fc, e->type_id, (usize)gi);
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!target || !lt) {
|
||
diag(a, fc, lr, "assignment target not writable");
|
||
return 0;
|
||
}
|
||
spl_ir_node_ref_t cur = compound ? emit_load(a, fc, lt, target) : 0;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, rr);
|
||
if (compound)
|
||
v = lower_compound_op(a, fc, n->expr.op, lt, cur, v);
|
||
v = coerce_to(a, fc, v, node_type(fc, v), lt);
|
||
emit_store(a, fc, lt, target, v);
|
||
return v;
|
||
}
|
||
}
|
||
if (ln->expr.op == SPL_AST_PREFIX_EXPR) {
|
||
spl_ast_node_t *pp = node_at(a->sema, ln->expr.op_expr.left);
|
||
if (pp && pp->prefix_expr.kind == SPL_AST_ASTERISK_EXPR) {
|
||
spl_ir_node_ref_t p = lower_expr(a, fc, pp->prefix_expr.postfix_expr);
|
||
spl_type_id_t pt = underlying(a->sema, node_type(fc, p));
|
||
spl_type_node_t *tt = tn(a->sema, pt);
|
||
if (tt && tt->kind == SPL_TYPE_PTR) {
|
||
spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee);
|
||
spl_ir_node_ref_t cur = compound ? emit_load(a, fc, pointee, p) : 0;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, rr);
|
||
if (compound)
|
||
v = lower_compound_op(a, fc, n->expr.op, pointee, cur, v);
|
||
v = coerce_to(a, fc, v, node_type(fc, v), pointee);
|
||
emit_store(a, fc, pointee, p, v);
|
||
return v;
|
||
}
|
||
}
|
||
}
|
||
if (pf && pf->postfix_expr.kind == SPL_AST_DEREF_EXPR) {
|
||
spl_ir_node_ref_t p = lower_expr(a, fc, pf->postfix_expr.primary_expr);
|
||
spl_type_id_t pt = underlying(a->sema, node_type(fc, p));
|
||
spl_type_node_t *tt = tn(a->sema, pt);
|
||
if (!tt || tt->kind != SPL_TYPE_PTR) {
|
||
diag(a, fc, lr, ".* requires pointer");
|
||
return 0;
|
||
}
|
||
spl_type_id_t pointee = underlying(a->sema, tt->ptr_pointee);
|
||
spl_ir_node_ref_t cur = compound ? emit_load(a, fc, pointee, p) : 0;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, rr);
|
||
if (compound)
|
||
v = lower_compound_op(a, fc, n->expr.op, pointee, cur, v);
|
||
v = coerce_to(a, fc, v, node_type(fc, v), pointee);
|
||
emit_store(a, fc, pointee, p, v);
|
||
return v;
|
||
}
|
||
if (pf && pf->postfix_expr.kind == SPL_AST_INDEX_EXPR) {
|
||
spl_type_id_t elem = 0;
|
||
spl_ir_node_ref_t addr = index_addr(a, fc, pf, &elem);
|
||
if (!addr)
|
||
return 0;
|
||
spl_ir_node_ref_t cur = compound ? emit_load(a, fc, elem, addr) : 0;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, rr);
|
||
if (compound)
|
||
v = lower_compound_op(a, fc, n->expr.op, elem, cur, v);
|
||
v = coerce_to(a, fc, v, node_type(fc, v), elem);
|
||
emit_store(a, fc, elem, addr, v);
|
||
return v;
|
||
}
|
||
if (pf && pf->postfix_expr.kind == SPL_AST_FIELD_EXPR) {
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, rr);
|
||
if (compound) {
|
||
spl_ir_node_ref_t cur = lower_expr(a, fc, lr);
|
||
v = lower_compound_op(a, fc, n->expr.op, node_type(fc, cur), cur, v);
|
||
}
|
||
field_assign(a, fc, lr, v);
|
||
return v;
|
||
}
|
||
diag(a, fc, lr, "unsupported assignment target");
|
||
return 0;
|
||
}
|
||
|
||
static spl_ir_node_ref_t lower_expr(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return 0;
|
||
if (ref)
|
||
fc->cur_src = ref; /* 调试行号:当前语*/
|
||
switch (n->expr.op) {
|
||
case SPL_AST_PRIMARY_EXPR:
|
||
return lower_primary(a, fc, node_at(a->sema, n->expr.op_expr.left));
|
||
case SPL_AST_PREFIX_EXPR:
|
||
return lower_prefix(a, fc, node_at(a->sema, n->expr.op_expr.left));
|
||
case SPL_AST_POSTFIX_EXPR:
|
||
return lower_postfix(a, fc, node_at(a->sema, n->expr.op_expr.left));
|
||
case SPL_AST_RANGE_EXPR:
|
||
return lower_range_value(a, fc, n);
|
||
case SPL_AST_ASSIGN_EXPR:
|
||
case SPL_AST_ASSIGN_ADD_EXPR:
|
||
case SPL_AST_ASSIGN_sUB_EXPR:
|
||
case SPL_AST_ASSIGN_MUL_EXPR:
|
||
case SPL_AST_ASSIGN_DIV_EXPR:
|
||
case SPL_AST_ASSIGN_MOD_EXPR:
|
||
case SPL_AST_ASSIGN_AND_EXPR:
|
||
case SPL_AST_ASSIGN_OR_EXPR:
|
||
case SPL_AST_ASSIGN_XOR_EXPR:
|
||
case SPL_AST_ASSIGN_LSHIFT_EXPR:
|
||
case SPL_AST_ASSIGN_USHIFT_EXPR:
|
||
return lower_assign(a, fc, n);
|
||
default:
|
||
return lower_binary(a, fc, n);
|
||
}
|
||
}
|
||
|
||
/* ================================================================
|
||
* 语句
|
||
* ================================================================ */
|
||
|
||
static void lower_block(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_vec_t *block) {
|
||
env_push(fc);
|
||
for (usize i = 0; i < block->size; i++)
|
||
lower_stmt(a, fc, block->data[i]);
|
||
if (!fc->terminated)
|
||
emit_scope_defers(a, fc, fc->env.size - 1);
|
||
env_pop(fc);
|
||
}
|
||
|
||
/* 登记 defer 体到当前作用*/
|
||
static void lower_defer(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
if (!fc->env.size)
|
||
env_push(fc);
|
||
vec_push(fc->env.data[fc->env.size - 1].defers, ref);
|
||
}
|
||
|
||
/* 逆序发射 scope_idx 作用域的 defer,并清空 */
|
||
static void emit_scope_defers(spl_ast2ir_t *a, fnctx_t *fc, usize scope_idx) {
|
||
if (scope_idx >= fc->env.size)
|
||
return;
|
||
for (usize i = fc->env.data[scope_idx].defers.size; i > 0; i--) {
|
||
spl_ast_node_t *d = node_at(a->sema, fc->env.data[scope_idx].defers.data[i - 1]);
|
||
if (d) {
|
||
lower_block(a, fc, &d->block_item.defer_statement.block_or_statement);
|
||
}
|
||
}
|
||
vec_free(fc->env.data[scope_idx].defers);
|
||
vec_init(fc->env.data[scope_idx].defers);
|
||
}
|
||
|
||
/* 从最内层作用域发射到 mark(含),用于 ret / break / continue */
|
||
static void emit_defers_from(spl_ast2ir_t *a, fnctx_t *fc, usize mark) {
|
||
for (usize i = fc->env.size; i > mark; i--)
|
||
emit_scope_defers(a, fc, i - 1);
|
||
}
|
||
|
||
static void lower_type_decl(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *td) {
|
||
spl_type_id_t tid = resolve_type_expr(a, fc, td->type_decl.type_expr);
|
||
env_add(fc, td->type_decl.name, td->resolved_def_id, tid, 0, 0, 1, 0);
|
||
}
|
||
|
||
static void lower_var_decl(spl_ast2ir_t *a, fnctx_t *fc, const char *name, spl_def_id_t def_id,
|
||
spl_ast_node_ref_t texpr, spl_ast_node_ref_t initexpr) {
|
||
spl_type_id_t tid = texpr ? resolve_type_expr(a, fc, texpr) : 0;
|
||
spl_ir_node_ref_t v = 0;
|
||
spl_type_id_t vt = 0;
|
||
if (initexpr) {
|
||
fc->hint = tid;
|
||
v = lower_expr(a, fc, initexpr);
|
||
fc->hint = 0;
|
||
vt = node_type(fc, v);
|
||
if (!tid && vt)
|
||
tid = vt;
|
||
}
|
||
if (!tid)
|
||
tid = kw_type(a, "void");
|
||
spl_ir_node_ref_t slot = emit_alloca(a, fc, tid);
|
||
if (v && vt && tid) {
|
||
if (!type_same(a->sema, vt, tid))
|
||
v = coerce_to(a, fc, v, vt, tid);
|
||
emit_store(a, fc, tid, slot, v);
|
||
}
|
||
env_add(fc, name, def_id, tid, slot, 0, 0, 1);
|
||
/* 调试:登记变量名 alloca 节点 */
|
||
spl_ir_dbg_var_t dv = {name, slot, tid, 0, 0};
|
||
vec_push(a->ir.funcs.data[fc->fn].dbg_vars, dv);
|
||
}
|
||
|
||
static void lower_if(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
spl_ir_node_ref_t c = lower_expr(a, fc, b->block_item.if_statement.expr);
|
||
int has_else = b->block_item.if_statement.else_block.size > 0;
|
||
usize then_b = new_block(fc);
|
||
usize else_b = has_else ? new_block(fc) : 0;
|
||
usize exit_b = new_block(fc);
|
||
emit_br(a, fc, c, then_b, has_else ? else_b : exit_b);
|
||
begin_block(fc, then_b);
|
||
lower_block(a, fc, &b->block_item.if_statement.if_block);
|
||
emit_jmp(a, fc, exit_b);
|
||
if (has_else) {
|
||
begin_block(fc, else_b);
|
||
lower_block(a, fc, &b->block_item.if_statement.else_block);
|
||
emit_jmp(a, fc, exit_b);
|
||
}
|
||
begin_block(fc, exit_b);
|
||
}
|
||
|
||
static void lower_while(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
usize cond_b = new_block(fc);
|
||
usize body_b = new_block(fc);
|
||
usize exit_b = new_block(fc);
|
||
begin_block(fc, cond_b);
|
||
spl_ir_node_ref_t c = lower_expr(a, fc, b->block_item.while_statement.expr);
|
||
emit_br(a, fc, c, body_b, exit_b);
|
||
begin_block(fc, body_b);
|
||
ir_loop_t lp = {exit_b, cond_b, fc->env.size};
|
||
vec_push(fc->loops, lp);
|
||
lower_block(a, fc, &b->block_item.while_statement.while_block);
|
||
emit_jmp(a, fc, cond_b);
|
||
vec_pop(fc->loops);
|
||
begin_block(fc, exit_b);
|
||
}
|
||
|
||
static void lower_loop(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
usize body_b = new_block(fc);
|
||
usize exit_b = new_block(fc);
|
||
begin_block(fc, body_b);
|
||
ir_loop_t lp = {exit_b, body_b, fc->env.size};
|
||
vec_push(fc->loops, lp);
|
||
lower_block(a, fc, &b->block_item.loop_statement.loop_block);
|
||
emit_jmp(a, fc, body_b);
|
||
vec_pop(fc->loops);
|
||
begin_block(fc, exit_b);
|
||
}
|
||
|
||
enum { FOR_RANGE, FOR_ARRAY, FOR_SLICE };
|
||
typedef struct {
|
||
int kind;
|
||
spl_type_id_t elem_tid;
|
||
spl_ir_node_ref_t len; /* 长度节点 = 无界 */
|
||
spl_ir_node_ref_t begin_slot; /* range: begin */
|
||
spl_ir_node_ref_t base_slot; /* array/slice: 元素基址*/
|
||
} for_seq_t;
|
||
|
||
static void for_seq_setup(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t eref, for_seq_t *s) {
|
||
memset(s, 0, sizeof *s);
|
||
spl_ast_node_t *n = node_at(a->sema, eref);
|
||
if (n && n->kind == SPL_AST_EXPR && n->expr.op == SPL_AST_RANGE_EXPR) {
|
||
s->kind = FOR_RANGE;
|
||
spl_ir_node_ref_t beg = lower_expr(a, fc, n->expr.op_expr.left);
|
||
s->elem_tid = underlying(a->sema, node_type(fc, beg));
|
||
s->begin_slot = emit_alloca(a, fc, s->elem_tid);
|
||
emit_store(a, fc, s->elem_tid, s->begin_slot, beg);
|
||
if (n->expr.op_expr.right) {
|
||
spl_ir_node_ref_t end = lower_expr(a, fc, n->expr.op_expr.right);
|
||
spl_ir_node_ref_t b = emit_load(a, fc, s->elem_tid, s->begin_slot);
|
||
s->len = emit_arith(a, fc, SPL_IR_ARITH_SUB, s->elem_tid,
|
||
coerce_to(a, fc, end, node_type(fc, end), s->elem_tid), b);
|
||
}
|
||
return;
|
||
}
|
||
spl_type_id_t bt = 0;
|
||
spl_ir_node_ref_t base_lv = lower_lvalue(a, fc, eref, &bt);
|
||
spl_type_node_t *tt = bt ? tn(a->sema, underlying(a->sema, bt)) : NULL;
|
||
if (base_lv && tt && tt->kind == SPL_TYPE_ARRAY) {
|
||
s->kind = FOR_ARRAY;
|
||
s->elem_tid = tt->array_type.element;
|
||
s->base_slot = base_lv;
|
||
s->len = const_int(a, fc, kw_type(a, "usize"), tt->array_type.len);
|
||
return;
|
||
}
|
||
if (base_lv && tt && tt->kind == SPL_TYPE_SLICE) {
|
||
s->kind = FOR_SLICE;
|
||
s->elem_tid = tt->slice_element;
|
||
spl_ir_node_ref_t slv = emit_load(a, fc, bt, base_lv);
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, s->elem_tid);
|
||
s->base_slot = emit_alloca(a, fc, ep);
|
||
s->len = emit_alloca(a, fc, kw_type(a, "usize"));
|
||
emit_store(a, fc, ep, s->base_slot, emit_agg_extract(a, fc, bt, ep, 0, slv));
|
||
emit_store(a, fc, kw_type(a, "usize"), s->len,
|
||
emit_agg_extract(a, fc, bt, kw_type(a, "usize"), 1, slv));
|
||
return;
|
||
}
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, eref);
|
||
spl_type_id_t vt = underlying(a->sema, node_type(fc, v));
|
||
spl_type_node_t *vtt = vt ? tn(a->sema, vt) : NULL;
|
||
if (vtt && vtt->kind == SPL_TYPE_RANGE) {
|
||
/* Range 值:内部 { begin, end },迭代 begin..end-1 */
|
||
s->kind = FOR_RANGE;
|
||
s->elem_tid = vtt->range_element;
|
||
s->begin_slot = emit_alloca(a, fc, s->elem_tid);
|
||
emit_store(a, fc, s->elem_tid, s->begin_slot,
|
||
emit_agg_extract(a, fc, vt, s->elem_tid, 0, v));
|
||
spl_ir_node_ref_t end = emit_agg_extract(a, fc, vt, s->elem_tid, 1, v);
|
||
spl_ir_node_ref_t b = emit_load(a, fc, s->elem_tid, s->begin_slot);
|
||
s->len = emit_arith(a, fc, SPL_IR_ARITH_SUB, s->elem_tid, end, b);
|
||
return;
|
||
}
|
||
if (vtt && vtt->kind == SPL_TYPE_SLICE) {
|
||
s->kind = FOR_SLICE;
|
||
s->elem_tid = vtt->slice_element;
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, s->elem_tid);
|
||
s->base_slot = emit_alloca(a, fc, ep);
|
||
s->len = emit_alloca(a, fc, kw_type(a, "usize"));
|
||
emit_store(a, fc, ep, s->base_slot, emit_agg_extract(a, fc, vt, ep, 0, v));
|
||
emit_store(a, fc, kw_type(a, "usize"), s->len,
|
||
emit_agg_extract(a, fc, vt, kw_type(a, "usize"), 1, v));
|
||
return;
|
||
}
|
||
if (vtt && vtt->kind == SPL_TYPE_ARRAY) {
|
||
spl_type_id_t fat = 0;
|
||
spl_ir_node_ref_t faddr = lower_field_address(a, fc, eref, &fat);
|
||
if (faddr) {
|
||
s->kind = FOR_ARRAY;
|
||
s->elem_tid = vtt->array_type.element;
|
||
s->base_slot = faddr;
|
||
s->len = const_int(a, fc, kw_type(a, "usize"), vtt->array_type.len);
|
||
return;
|
||
}
|
||
}
|
||
diag(a, fc, eref, "for: sequence must be Range/[]T/[N]T");
|
||
}
|
||
|
||
static void lower_for(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
spl_ast_node_ref_vec_t *expr_vec = &b->block_item.for_statement.expr_vec;
|
||
char **id_data = b->block_item.for_statement.ident_vec.data;
|
||
usize id_size = b->block_item.for_statement.ident_vec.size;
|
||
usize nseq = expr_vec->size;
|
||
if (nseq != id_size || nseq > 8) {
|
||
diag(a, fc, 0, "for: sequence/variable count mismatch");
|
||
return;
|
||
}
|
||
for_seq_t seqs[8];
|
||
for (usize i = 0; i < nseq; i++)
|
||
for_seq_setup(a, fc, expr_vec->data[i], &seqs[i]);
|
||
spl_type_id_t iszt = kw_type(a, "isize");
|
||
spl_ir_node_ref_t min_slot = 0;
|
||
int has_finite = 0;
|
||
for (usize i = 0; i < nseq; i++)
|
||
if (seqs[i].len)
|
||
has_finite = 1;
|
||
if (has_finite) {
|
||
spl_ir_node_ref_t m = 0;
|
||
for (usize i = 0; i < nseq; i++) {
|
||
if (!seqs[i].len)
|
||
continue;
|
||
spl_ir_node_ref_t lenv = seqs[i].len;
|
||
if (seqs[i].kind == FOR_SLICE)
|
||
lenv = emit_load(a, fc, kw_type(a, "usize"), seqs[i].len);
|
||
spl_ir_node_ref_t l = coerce_to(a, fc, lenv, node_type(fc, lenv), iszt);
|
||
if (!m) {
|
||
m = l;
|
||
} else {
|
||
spl_ir_node_ref_t c = emit_cmp(a, fc, SPL_IR_CMP_LT, iszt, l, m);
|
||
m = emit_select(a, fc, iszt, c, l, m);
|
||
}
|
||
}
|
||
min_slot = emit_alloca(a, fc, iszt);
|
||
emit_store(a, fc, iszt, min_slot, m);
|
||
}
|
||
spl_ir_node_ref_t ctr = emit_alloca(a, fc, iszt);
|
||
emit_store(a, fc, iszt, ctr, const_int(a, fc, iszt, 0));
|
||
env_push(fc);
|
||
for (usize i = 0; i < nseq; i++)
|
||
env_add(fc, id_data[i], 0, seqs[i].elem_tid, 0, 0, 0, 0);
|
||
usize cond_b = new_block(fc);
|
||
usize body_b = new_block(fc);
|
||
usize exit_b = new_block(fc);
|
||
begin_block(fc, cond_b);
|
||
if (has_finite) {
|
||
spl_ir_node_ref_t cur = emit_load(a, fc, iszt, ctr);
|
||
spl_ir_node_ref_t ml = emit_load(a, fc, iszt, min_slot);
|
||
spl_ir_node_ref_t c = emit_cmp(a, fc, SPL_IR_CMP_LT, iszt, cur, ml);
|
||
emit_br(a, fc, c, body_b, exit_b);
|
||
} else {
|
||
emit_jmp(a, fc, body_b);
|
||
}
|
||
begin_block(fc, body_b);
|
||
for (usize i = 0; i < nseq; i++) {
|
||
for_seq_t *s = &seqs[i];
|
||
spl_ir_node_ref_t cur = emit_load(a, fc, iszt, ctr);
|
||
spl_ir_node_ref_t v = 0;
|
||
if (s->kind == FOR_RANGE) {
|
||
spl_ir_node_ref_t bg = emit_load(a, fc, s->elem_tid, s->begin_slot);
|
||
v = emit_arith(a, fc, SPL_IR_ARITH_ADD, s->elem_tid, bg,
|
||
coerce_to(a, fc, cur, iszt, s->elem_tid));
|
||
} else {
|
||
spl_ir_node_ref_t base = s->base_slot;
|
||
if (s->kind == FOR_SLICE) {
|
||
spl_type_id_t ep = spl_type_ptr((spl_type_t *)&a->sema->type, s->elem_tid);
|
||
base = emit_load(a, fc, ep, s->base_slot);
|
||
}
|
||
spl_ir_node_ref_t addr = emit_offset(a, fc, s->elem_tid, base, cur);
|
||
v = emit_load(a, fc, s->elem_tid, addr);
|
||
}
|
||
ir_env_t *it = env_find(fc, id_data[i]);
|
||
if (it) {
|
||
it->tid = s->elem_tid;
|
||
it->value = v;
|
||
}
|
||
}
|
||
ir_loop_t lp = {exit_b, cond_b, fc->env.size};
|
||
vec_push(fc->loops, lp);
|
||
lower_block(a, fc, &b->block_item.for_statement.block);
|
||
spl_ir_node_ref_t cur2 = emit_load(a, fc, iszt, ctr);
|
||
spl_ir_node_ref_t one = const_int(a, fc, iszt, 1);
|
||
spl_ir_node_ref_t nxt = emit_arith(a, fc, SPL_IR_ARITH_ADD, iszt, cur2, one);
|
||
emit_store(a, fc, iszt, ctr, nxt);
|
||
emit_jmp(a, fc, cond_b);
|
||
vec_pop(fc->loops);
|
||
env_pop(fc);
|
||
begin_block(fc, exit_b);
|
||
}
|
||
|
||
static void lower_ret(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
emit_defers_from(a, fc, 0);
|
||
if (b->block_item.ret_statement.expr) {
|
||
fc->hint = fc->ret_tid;
|
||
spl_ir_node_ref_t v = lower_expr(a, fc, b->block_item.ret_statement.expr);
|
||
fc->hint = 0;
|
||
spl_type_id_t vt = node_type(fc, v);
|
||
if (fc->ret_tid && vt && !type_same(a->sema, vt, fc->ret_tid))
|
||
v = coerce_to(a, fc, v, vt, fc->ret_tid);
|
||
emit_ret(a, fc, fc->ret_tid, v);
|
||
} else {
|
||
emit_ret(a, fc, fc->ret_tid, 0);
|
||
}
|
||
}
|
||
|
||
static void lower_match(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_t *b) {
|
||
spl_ast_node_ref_vec_t *arms = &b->block_item.match_statement.paced_exprs;
|
||
spl_ast_node_ref_vec_t *bodies = &b->block_item.match_statement.match_block;
|
||
if (arms->size != bodies->size) {
|
||
diag(a, fc, 0, "match: arm pattern/body count mismatch");
|
||
return;
|
||
}
|
||
spl_ir_node_ref_t subj = lower_expr(a, fc, b->block_item.match_statement.expr);
|
||
spl_type_id_t st = underlying(a->sema, node_type(fc, subj));
|
||
spl_type_node_t *tt = tn(a->sema, st);
|
||
if (tt && tt->kind == SPL_TYPE_PTR) {
|
||
st = underlying(a->sema, tt->ptr_pointee);
|
||
tt = tn(a->sema, st);
|
||
subj = emit_load(a, fc, st, subj);
|
||
}
|
||
int is_enum = tt && tt->kind == SPL_TYPE_ENUM;
|
||
int is_int = tt && tt->kind == SPL_TYPE_INT;
|
||
if (!is_enum && !is_int) {
|
||
diag(a, fc, 0, "match subject must be enum/union/integer");
|
||
return;
|
||
}
|
||
spl_ir_node_ref_t subj_slot = emit_alloca(a, fc, st);
|
||
emit_store(a, fc, st, subj_slot, subj);
|
||
spl_type_id_t tag_t = enum_tag_tid(a);
|
||
spl_ir_node_ref_t tag_slot = 0;
|
||
if (is_enum) {
|
||
spl_ir_node_ref_t tagv =
|
||
emit_agg_extract(a, fc, st, tag_t, 0, emit_load(a, fc, st, subj_slot));
|
||
tag_slot = emit_alloca(a, fc, tag_t);
|
||
emit_store(a, fc, tag_t, tag_slot, tagv);
|
||
}
|
||
usize exit_b = new_block(fc);
|
||
for (usize i = 0; i < arms->size; i++) {
|
||
spl_ast_node_t *pk = node_at(a->sema, arms->data[i]);
|
||
usize body_b = new_block(fc);
|
||
usize next_b = (i + 1 < arms->size) ? new_block(fc) : 0;
|
||
int is_default = !pk || (!pk->packed_expr.ident && !pk->packed_expr.expr);
|
||
if (is_default) {
|
||
emit_jmp(a, fc, body_b);
|
||
} else {
|
||
spl_ir_node_ref_t cond = 0;
|
||
const char *vname = NULL;
|
||
if (is_enum) {
|
||
/* 变体名:`.Red`(ident)或 `Tag.ident`(expr 字段路径)两种形式 */
|
||
vname = pk->packed_expr.ident;
|
||
if (!vname && pk->packed_expr.expr) {
|
||
spl_ast_node_t *en = node_at(a->sema, pk->packed_expr.expr);
|
||
if (en && en->kind == SPL_AST_EXPR && en->expr.op == SPL_AST_POSTFIX_EXPR) {
|
||
spl_ast_node_t *epf = node_at(a->sema, en->expr.op_expr.left);
|
||
if (epf && epf->postfix_expr.kind == SPL_AST_FIELD_EXPR)
|
||
vname = epf->postfix_expr.field_expr;
|
||
}
|
||
}
|
||
if (vname) {
|
||
isize vidx = enum_variant_index(a, st, vname);
|
||
if (vidx < 0)
|
||
vidx = 0;
|
||
spl_ir_node_ref_t tv = emit_load(a, fc, tag_t, tag_slot);
|
||
spl_ir_node_ref_t idxc = const_int(a, fc, tag_t, (usize)vidx);
|
||
cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, tag_t, tv, idxc);
|
||
}
|
||
} else if (is_int && pk->packed_expr.expr) {
|
||
spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot);
|
||
spl_ir_node_ref_t pv = lower_expr(a, fc, pk->packed_expr.expr);
|
||
pv = coerce_to(a, fc, pv, node_type(fc, pv), st);
|
||
cond = emit_cmp(a, fc, SPL_IR_CMP_EQ, st, sv, pv);
|
||
}
|
||
if (cond)
|
||
emit_br(a, fc, cond, body_b, next_b ? next_b : exit_b);
|
||
else
|
||
emit_jmp(a, fc, body_b);
|
||
}
|
||
begin_block(fc, body_b);
|
||
env_push(fc);
|
||
if (is_enum && pk && pk->packed_expr.ident && pk->packed_expr.bind_ident) {
|
||
isize vidx = enum_variant_index(a, st, pk->packed_expr.ident);
|
||
spl_type_id_t pt = enum_payload_tid(a, st, vidx);
|
||
if (pt) {
|
||
spl_ir_node_ref_t sv = emit_load(a, fc, st, subj_slot);
|
||
/* enum 布局 = tag(0) + payload(8):直接提payload,field_tid = 变体具体类型 */
|
||
spl_ir_node_ref_t pv = emit_agg_extract(a, fc, st, pt, 1, sv);
|
||
spl_ir_node_ref_t bslot = emit_alloca(a, fc, pt);
|
||
emit_store(a, fc, pt, bslot, pv);
|
||
env_add(fc, pk->packed_expr.bind_ident, 0, pt, bslot, 0, 0, 0);
|
||
}
|
||
}
|
||
spl_ast_node_t *body = node_at(a->sema, bodies->data[i]);
|
||
if (body && body->kind == SPL_AST_EXPR && body->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, body->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR)
|
||
lower_block(a, fc, &pn->primary_expr.block_expr);
|
||
else
|
||
lower_expr(a, fc, bodies->data[i]);
|
||
} else {
|
||
lower_expr(a, fc, bodies->data[i]);
|
||
}
|
||
env_pop(fc);
|
||
emit_jmp(a, fc, exit_b);
|
||
if (next_b)
|
||
begin_block(fc, next_b);
|
||
}
|
||
begin_block(fc, exit_b);
|
||
}
|
||
|
||
static void lower_stmt(spl_ast2ir_t *a, fnctx_t *fc, spl_ast_node_ref_t ref) {
|
||
spl_ast_node_t *b = node_at(a->sema, ref);
|
||
if (!b)
|
||
return;
|
||
if (b->kind == SPL_AST_EXPR) {
|
||
if (b->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, b->expr.op_expr.left);
|
||
if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) {
|
||
lower_block_expr(a, fc, &pn->primary_expr.block_expr);
|
||
return;
|
||
}
|
||
}
|
||
lower_expr(a, fc, ref);
|
||
return;
|
||
}
|
||
switch (b->block_item.kind) {
|
||
case SPL_AST_VARDECL: {
|
||
spl_ast_node_t *vd = node_at(a->sema, b->block_item.var_decl);
|
||
if (vd)
|
||
lower_var_decl(a, fc, vd->var_decl.name, vd->resolved_def_id, vd->var_decl.type_expr,
|
||
vd->var_decl.expr);
|
||
break;
|
||
}
|
||
case SPL_AST_CONSTDECL: {
|
||
spl_ast_node_t *cd = node_at(a->sema, b->block_item.const_decl);
|
||
if (cd)
|
||
lower_var_decl(a, fc, cd->const_decl.name, cd->resolved_def_id,
|
||
cd->const_decl.type_expr, cd->const_decl.expr);
|
||
break;
|
||
}
|
||
case SPL_AST_TYPEDECL: {
|
||
spl_ast_node_t *td = node_at(a->sema, b->block_item.type_decl);
|
||
if (td)
|
||
lower_type_decl(a, fc, td);
|
||
break;
|
||
}
|
||
case SPL_AST_IF_STATEMENT:
|
||
lower_if(a, fc, b);
|
||
break;
|
||
case SPL_AST_IFVAR_STATEMENT: {
|
||
/* if var .x[y] = e { }:绑定新变量 y = e,进入 if 块(sema 语义)
|
||
* 若 bind_ident 为空(if var .x = e),则不绑定,仅进入 if 块 */
|
||
spl_ast_node_t *pk = node_at(a->sema, b->block_item.ifvar_statement.packed_expr);
|
||
if (pk && pk->packed_expr.bind_ident && pk->packed_expr.expr) {
|
||
spl_ir_node_ref_t ev = lower_expr(a, fc, pk->packed_expr.expr);
|
||
spl_type_id_t vt = underlying(a->sema, node_type(fc, ev));
|
||
spl_ir_node_ref_t bslot = emit_alloca(a, fc, vt);
|
||
emit_store(a, fc, vt, bslot, ev);
|
||
env_add(fc, pk->packed_expr.bind_ident, 0, vt, bslot, 0, 0, 0);
|
||
}
|
||
env_push(fc);
|
||
lower_block(a, fc, &b->block_item.ifvar_statement.if_block);
|
||
env_pop(fc);
|
||
/* else 分支:无失败语义,不发射 */
|
||
break;
|
||
}
|
||
case SPL_AST_WHILE_STATEMENT:
|
||
lower_while(a, fc, b);
|
||
break;
|
||
case SPL_AST_LOOP_STATEMENT:
|
||
lower_loop(a, fc, b);
|
||
break;
|
||
case SPL_AST_FOR_STATEMENT:
|
||
lower_for(a, fc, b);
|
||
break;
|
||
case SPL_AST_MATCH_STATEMENT:
|
||
lower_match(a, fc, b);
|
||
break;
|
||
case SPL_AST_RET_STATEMENT:
|
||
lower_ret(a, fc, b);
|
||
break;
|
||
case SPL_AST_BREAK_STATEMENT: {
|
||
if (!fc->loops.size) {
|
||
diag(a, fc, ref, "break outside loop");
|
||
break;
|
||
}
|
||
ir_loop_t *lp = &fc->loops.data[fc->loops.size - 1];
|
||
emit_defers_from(a, fc, lp->env_mark);
|
||
emit_jmp(a, fc, lp->brk);
|
||
break;
|
||
}
|
||
case SPL_AST_CONTINUE_STATEMENT: {
|
||
if (!fc->loops.size) {
|
||
diag(a, fc, ref, "continue outside loop");
|
||
break;
|
||
}
|
||
ir_loop_t *lp = &fc->loops.data[fc->loops.size - 1];
|
||
emit_defers_from(a, fc, lp->env_mark);
|
||
emit_jmp(a, fc, lp->cont);
|
||
break;
|
||
}
|
||
case SPL_AST_DEFER_STATEMENT:
|
||
lower_defer(a, fc, ref);
|
||
break;
|
||
case SPL_AST_EXPR_STATEMENT:
|
||
if (b->block_item.expr_statement)
|
||
lower_expr(a, fc, b->block_item.expr_statement);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* ================================================================
|
||
* 函数
|
||
* ================================================================ */
|
||
|
||
static spl_ir_func_ref_t a2ir_fn_of(spl_ast2ir_t *a, spl_type_id_t fn_tid) {
|
||
/* 懒扫描:IR func 已记fn_tid(spl_type_fn 不去重,fn_tid 唯一*/
|
||
for (usize i = 1; i < a->ir.funcs.size; i++) {
|
||
if (a->ir.funcs.data[i].fn_tid == fn_tid)
|
||
return i;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static void lower_func_body(spl_ast2ir_t *a, spl_ir_func_ref_t fid, spl_type_id_t fn_tid,
|
||
spl_ast_node_ref_t def_ref, spl_type_id_t ns_tid) {
|
||
spl_ast_node_t *fn = node_at(a->sema, def_ref);
|
||
if (!fn)
|
||
return;
|
||
spl_type_node_t *ft = tn(a->sema, fn_tid);
|
||
spl_type_id_t ret = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.ret : 0;
|
||
fnctx_t fc;
|
||
fc_init_ns(&fc, a, fid, ret, ns_tid);
|
||
spl_ast_node_ref_vec_t *pl = &fn->fn_decl.param_list;
|
||
usize nparams = (ft && ft->kind == SPL_TYPE_FN) ? ft->fn_type.params.size : 0;
|
||
env_push(&fc);
|
||
for (usize i = 0; i < pl->size && i < nparams; i++) {
|
||
spl_ast_node_t *pd = node_at(a->sema, pl->data[i]);
|
||
if (!pd || !pd->param_decl.name)
|
||
continue;
|
||
spl_type_id_t pt = ft->fn_type.params.data[i];
|
||
spl_ir_node_ref_t pr = emit_node(a, &fc);
|
||
spl_ir_node_t *e = enode(a, &fc, pr);
|
||
e->kind = SPL_IR_CONTROL_PARAM;
|
||
e->control_param.tid = pt;
|
||
e->control_param.idx = (usize)i;
|
||
set_ntype(&fc, pr, pt);
|
||
spl_ir_node_ref_t slot = emit_alloca(a, &fc, pt);
|
||
emit_store(a, &fc, pt, slot, pr);
|
||
env_add(&fc, pd->param_decl.name, pd->resolved_def_id, pt, slot, 0, 0, 0);
|
||
/* 调试:参数登记(值在参数区,fp 偏移ir2vm param_off 填) */
|
||
spl_ir_dbg_var_t dv = {pd->param_decl.name, slot, pt, 1, (usize)i};
|
||
vec_push(a->ir.funcs.data[fid].dbg_vars, dv);
|
||
}
|
||
begin_block(&fc, new_block(&fc));
|
||
lower_block(a, &fc, &fn->fn_decl.block);
|
||
if (!fc.terminated)
|
||
emit_ret(a, &fc, ret, 0);
|
||
spl_ir_func_t *ff = spl_ir_func(&a->ir, fid);
|
||
for (usize i = 0; i < fc.fixups.size; i++) {
|
||
ir_fix_t *fx = &fc.fixups.data[i];
|
||
spl_ir_node_t *nn = spl_ir_node(&a->ir, fid, fx->node);
|
||
spl_ir_node_ref_t target = fc.blocks.data[fx->block].first;
|
||
if (!target)
|
||
target = ff->nodes.size ? ff->nodes.size - 1 : 0;
|
||
if (fx->slot == 0)
|
||
nn->control_br.true_label = target;
|
||
else if (fx->slot == 1)
|
||
nn->control_br.false_label = target;
|
||
else
|
||
nn->control_jmp.label = target;
|
||
}
|
||
for (usize i = 0; i < fc.blocks.size; i++)
|
||
if (fc.blocks.data[i].first)
|
||
vec_push(ff->labels, fc.blocks.data[i].first);
|
||
for (usize i = 1; i < ff->labels.size; i++) {
|
||
spl_ir_node_ref_t k = ff->labels.data[i];
|
||
usize j = i;
|
||
while (j > 0 && ff->labels.data[j - 1] > k) {
|
||
ff->labels.data[j] = ff->labels.data[j - 1];
|
||
j--;
|
||
}
|
||
ff->labels.data[j] = k;
|
||
}
|
||
if (fc.err)
|
||
a->err_count += fc.err;
|
||
fc_drop(&fc);
|
||
}
|
||
|
||
void spl_ast2ir_init(spl_ast2ir_t *ast2ir, const spl_sema_t *sema) {
|
||
memset(ast2ir, 0, sizeof *ast2ir);
|
||
ast2ir->sema = sema;
|
||
spl_ir_init(&ast2ir->ir);
|
||
vec_init(ast2ir->owned_names);
|
||
}
|
||
|
||
void spl_ast2ir_drop(spl_ast2ir_t *ast2ir) {
|
||
for (usize i = 0; i < ast2ir->owned_names.size; i++)
|
||
free(ast2ir->owned_names.data[i]);
|
||
vec_free(ast2ir->owned_names);
|
||
vec_free(ast2ir->gdata_ref);
|
||
spl_ir_drop(&ast2ir->ir);
|
||
}
|
||
|
||
/* ================================================================
|
||
* 全局数据(聚合类型下 / 顶层var、const
|
||
* ================================================================ */
|
||
|
||
/* 常量折叠:仅支持字面量(int/char/float/string/null)与一元负*/
|
||
typedef struct {
|
||
int const_init;
|
||
isize int_v;
|
||
double float_v;
|
||
const char *cstr_v;
|
||
} gfold_t;
|
||
|
||
static void fold_const_init(spl_ast2ir_t *a, spl_ast_node_ref_t ref, gfold_t *g) {
|
||
spl_ast_node_t *n = node_at(a->sema, ref);
|
||
if (!n || n->kind != SPL_AST_EXPR)
|
||
return;
|
||
if (n->expr.op == SPL_AST_PRIMARY_EXPR) {
|
||
spl_ast_node_t *pn = node_at(a->sema, n->expr.op_expr.left);
|
||
if (!pn)
|
||
return;
|
||
switch (pn->primary_expr.kind) {
|
||
case SPL_AST_INTEGER:
|
||
g->const_init = 1;
|
||
g->int_v = pn->primary_expr.integer_expr;
|
||
return;
|
||
case SPL_AST_CHAR_LIT:
|
||
g->const_init = 1;
|
||
g->int_v = (isize)(unsigned char)pn->primary_expr.char_lit_expr;
|
||
return;
|
||
case SPL_AST_FLOAT:
|
||
g->const_init = 1;
|
||
g->float_v = pn->primary_expr.float_expr;
|
||
return;
|
||
case SPL_AST_NULL:
|
||
g->const_init = 1;
|
||
g->int_v = 0;
|
||
return;
|
||
case SPL_AST_STRING_LIT:
|
||
g->const_init = 1;
|
||
g->cstr_v = pn->primary_expr.string_lit_expr;
|
||
return;
|
||
default:
|
||
return;
|
||
}
|
||
}
|
||
if (n->expr.op == SPL_AST_PREFIX_EXPR) {
|
||
spl_ast_node_t *pp = node_at(a->sema, n->expr.op_expr.left);
|
||
if (pp && pp->prefix_expr.kind == SPL_AST_MINUS_EXPR) {
|
||
fold_const_init(a, pp->prefix_expr.postfix_expr, g);
|
||
if (g->const_init)
|
||
g->int_v = -g->int_v;
|
||
}
|
||
}
|
||
}
|
||
|
||
static void collect_gdata_list(spl_ast2ir_t *a, spl_ast_node_ref_vec_t *members) {
|
||
for (usize i = 0; i < members->size; i++) {
|
||
spl_ast_node_t *m = node_at(a->sema, members->data[i]);
|
||
if (!m)
|
||
continue;
|
||
const char *mname = NULL;
|
||
spl_ast_node_ref_t iexpr = 0;
|
||
if (m->kind == SPL_AST_VAR_DECL) {
|
||
mname = m->var_decl.name;
|
||
iexpr = m->var_decl.expr;
|
||
} else if (m->kind == SPL_AST_CONST_DECL) {
|
||
mname = m->const_decl.name;
|
||
iexpr = m->const_decl.expr;
|
||
} else if (m->kind == SPL_AST_MEMBER_DECL) {
|
||
/* 顶层裸成员(文件级 IDENT: T)视为全局 var;聚合体内 MEMBER_DECL 是字段不收集 */
|
||
spl_def_node_t *md = m->resolved_def_id ? def_at(a->sema, m->resolved_def_id) : NULL;
|
||
if (!md || md->kind != SPL_DEF_VAR)
|
||
continue;
|
||
mname = m->member_decl.name;
|
||
iexpr = 0;
|
||
} else {
|
||
continue;
|
||
}
|
||
if (!mname || !m->resolved_def_id)
|
||
continue;
|
||
spl_def_node_t *d = def_at(a->sema, m->resolved_def_id);
|
||
if (!d)
|
||
continue;
|
||
gfold_t g;
|
||
memset(&g, 0, sizeof g);
|
||
spl_type_id_t g_tid = d->type_id;
|
||
if (iexpr)
|
||
fold_const_init(a, iexpr, &g);
|
||
/* 全局 value = type.const 节点(标量折叠值;聚合/init 零) */
|
||
spl_ir_node_t v;
|
||
memset(&v, 0, sizeof v);
|
||
v.kind = SPL_IR_TYPE_CONST;
|
||
v.type_const.tid = g_tid;
|
||
spl_type_node_t *gt = tn(a->sema, underlying(a->sema, g_tid));
|
||
if (g.const_init && gt && gt->kind == SPL_TYPE_INT)
|
||
v.type_const.int_lit = (usize)g.int_v;
|
||
else if (g.const_init && gt && gt->kind == SPL_TYPE_FLOAT)
|
||
v.type_const.float_lit = g.float_v;
|
||
else
|
||
v.type_const.int_lit = 0;
|
||
vec_push(a->ir.gdata, v);
|
||
spl_ast2ir_gref_t gr = {m->resolved_def_id, a->ir.gdata.size - 1};
|
||
vec_push(a->gdata_ref, gr);
|
||
}
|
||
}
|
||
|
||
static void collect_gdata(spl_ast2ir_t *a) {
|
||
spl_ast_node_t *root = node_at(a->sema, a->sema->ast->root);
|
||
if (!root || root->kind != SPL_AST_CONTAINER_ITEM)
|
||
return;
|
||
collect_gdata_list(a, &root->container_item.members);
|
||
for (usize i = 0; i < root->container_item.members.size; i++) {
|
||
spl_ast_node_ref_t mref = root->container_item.members.data[i];
|
||
spl_ast_node_t *m = node_at(a->sema, mref);
|
||
if (!m || m->kind != SPL_AST_TYPE_DECL)
|
||
continue;
|
||
spl_ast_node_t *te = node_at(a->sema, m->type_decl.type_expr);
|
||
if (!te ||
|
||
(te->type_expr.kind != SPL_AST_TYPE_STRUCT &&
|
||
te->type_expr.kind != SPL_AST_TYPE_UNION && te->type_expr.kind != SPL_AST_TYPE_ENUM))
|
||
continue;
|
||
collect_gdata_list(a, &te->type_expr.aggregate_list);
|
||
}
|
||
}
|
||
|
||
/* def_id gdata value 节点索引;未命中返回 -1 */
|
||
static isize gdata_index_by_def(spl_ast2ir_t *a, spl_def_id_t def_id) {
|
||
for (usize i = 0; i < a->gdata_ref.size; i++)
|
||
if (a->gdata_ref.data[i].def_id == def_id)
|
||
return (isize)a->gdata_ref.data[i].gdata_idx;
|
||
return -1;
|
||
}
|
||
|
||
/* ================================================================
|
||
* 预登记:为所有函数(顶层 + 聚合方法)建 IR func
|
||
* ================================================================ */
|
||
|
||
/* 预登记:为所有函数(顶层 + 聚合方法)建 IR func */
|
||
static void register_funcs(spl_ast2ir_t *a) {
|
||
spl_ast_node_t *root = node_at(a->sema, a->sema->ast->root);
|
||
if (!root || root->kind != SPL_AST_CONTAINER_ITEM)
|
||
return;
|
||
for (usize i = 0; i < root->container_item.members.size; i++) {
|
||
spl_ast_node_ref_t mref = root->container_item.members.data[i];
|
||
spl_ast_node_t *m = node_at(a->sema, mref);
|
||
if (!m || (m->kind != SPL_AST_FN_DECL && m->kind != SPL_AST_FN_DEFINE))
|
||
continue;
|
||
spl_def_id_t def = root_lookup(a, m->fn_decl.name);
|
||
if (!def)
|
||
continue;
|
||
spl_type_id_t fn_tid = def_at(a->sema, def)->type_id;
|
||
spl_ir_func_ref_t fid = spl_ir_alloc_fn(&a->ir);
|
||
spl_ir_func_t *f = spl_ir_func(&a->ir, fid);
|
||
f->name = m->fn_decl.name;
|
||
f->fn_tid = fn_tid;
|
||
}
|
||
for (usize i = 0; i < root->container_item.members.size; i++) {
|
||
spl_ast_node_ref_t mref = root->container_item.members.data[i];
|
||
spl_ast_node_t *m = node_at(a->sema, mref);
|
||
if (!m || m->kind != SPL_AST_TYPE_DECL)
|
||
continue;
|
||
spl_ast_node_t *te = node_at(a->sema, m->type_decl.type_expr);
|
||
if (!te ||
|
||
(te->type_expr.kind != SPL_AST_TYPE_STRUCT &&
|
||
te->type_expr.kind != SPL_AST_TYPE_UNION && te->type_expr.kind != SPL_AST_TYPE_ENUM))
|
||
continue;
|
||
spl_def_id_t adef = root_lookup(a, m->type_decl.name);
|
||
if (!adef)
|
||
continue;
|
||
spl_type_id_t agg_tid = underlying(a->sema, def_at(a->sema, adef)->type_id);
|
||
for (usize j = 0; j < te->type_expr.aggregate_list.size; j++) {
|
||
spl_ast_node_ref_t mm = te->type_expr.aggregate_list.data[j];
|
||
spl_ast_node_t *mn = node_at(a->sema, mm);
|
||
if (!mn || (mn->kind != SPL_AST_FN_DECL && mn->kind != SPL_AST_FN_DEFINE))
|
||
continue;
|
||
spl_type_id_t mt = agg_member_type(a, agg_tid, mn->fn_decl.name);
|
||
if (!mt)
|
||
continue;
|
||
size_t nlen = strlen(m->type_decl.name) + 1 + strlen(mn->fn_decl.name) + 1;
|
||
char *fname = malloc(nlen);
|
||
snprintf(fname, nlen, "%s.%s", m->type_decl.name, mn->fn_decl.name);
|
||
spl_ir_func_ref_t fid = spl_ir_alloc_fn(&a->ir);
|
||
spl_ir_func_t *f = spl_ir_func(&a->ir, fid);
|
||
f->name = fname;
|
||
f->fn_tid = mt;
|
||
vec_push(a->owned_names, fname);
|
||
}
|
||
}
|
||
}
|
||
|
||
void spl_ast2ir_run(spl_ast2ir_t *a) {
|
||
spl_ast_node_t *root = node_at(a->sema, a->sema->ast->root);
|
||
if (!root || root->kind != SPL_AST_CONTAINER_ITEM)
|
||
return;
|
||
vec_init(a->gdata_ref);
|
||
collect_gdata(a);
|
||
register_funcs(a);
|
||
for (usize i = 0; i < root->container_item.members.size; i++) {
|
||
spl_ast_node_ref_t mref = root->container_item.members.data[i];
|
||
spl_ast_node_t *m = node_at(a->sema, mref);
|
||
if (!m || m->kind != SPL_AST_FN_DEFINE)
|
||
continue;
|
||
spl_def_id_t def = root_lookup(a, m->fn_decl.name);
|
||
if (!def)
|
||
continue;
|
||
spl_type_id_t fn_tid = def_at(a->sema, def)->type_id;
|
||
spl_ir_func_ref_t fid = a2ir_fn_of(a, fn_tid);
|
||
if (fid)
|
||
lower_func_body(a, fid, fn_tid, mref, 0);
|
||
}
|
||
for (usize i = 0; i < root->container_item.members.size; i++) {
|
||
spl_ast_node_ref_t mref = root->container_item.members.data[i];
|
||
spl_ast_node_t *m = node_at(a->sema, mref);
|
||
if (!m || m->kind != SPL_AST_TYPE_DECL)
|
||
continue;
|
||
spl_ast_node_t *te = node_at(a->sema, m->type_decl.type_expr);
|
||
if (!te ||
|
||
(te->type_expr.kind != SPL_AST_TYPE_STRUCT &&
|
||
te->type_expr.kind != SPL_AST_TYPE_UNION && te->type_expr.kind != SPL_AST_TYPE_ENUM))
|
||
continue;
|
||
spl_def_id_t adef = root_lookup(a, m->type_decl.name);
|
||
if (!adef)
|
||
continue;
|
||
spl_type_id_t agg_tid = underlying(a->sema, def_at(a->sema, adef)->type_id);
|
||
for (usize j = 0; j < te->type_expr.aggregate_list.size; j++) {
|
||
spl_ast_node_ref_t mm = te->type_expr.aggregate_list.data[j];
|
||
spl_ast_node_t *mn = node_at(a->sema, mm);
|
||
if (!mn || mn->kind != SPL_AST_FN_DEFINE)
|
||
continue;
|
||
spl_type_id_t mt = agg_member_type(a, agg_tid, mn->fn_decl.name);
|
||
spl_ir_func_ref_t fid = mt ? a2ir_fn_of(a, mt) : 0;
|
||
if (fid)
|
||
lower_func_body(a, fid, mt, mm, agg_tid);
|
||
}
|
||
}
|
||
}
|