Files
spl/stage1/spl_ast2ir.c

3101 lines
120 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* spl_ast2ir.c AST IR lowering
*
* 设计要点 * - 名称解析自包含局部变类型用自身环境栈顶层类函数sema root scope 与聚合成员表 * -
* 变量落在内存槽(@mem.alloca写走 @mem.load/store表达式临时值为 SSA * - 控制流用"块表 +
* fixup 补丁"分跳转目标在函数末尾回填为块首指令node ref * -
* 聚合字段访问:读@agg.extract写字节地址直写"@mem.offset + @mem.store<72>?* - 枚举=
* agg.construct(enum)([tag, payload?])match tag 分发 * - defer 按作用域逆序执行(正常退/ ret /
* break / continue 全覆盖) */
#include "spl_ast2ir.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<45>?*/
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;
}
/* 命名空间成员类型<EFBC88>?嵌套类型/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 的位置<E7BDAE>?type.agg_field_types 按序对齐<E5AFB9>?*/
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_DECLvar/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 <20>?SPL_DEF_MEMBER 条目<E69DA1>?*/
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;
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);
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) <20>?*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 已作用域解析绕开同名遮蔽歧义<EFBC89>?def_id 时兜底名<E5BA95>?*/
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 是否<E698AF>?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 <20>?def <20>?类型<EFBC88>?别名/命名类型<E7B1BB>?*/
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;
}
/* 兜底<EFBC9A>?内置类型sema 不为其建 def <20>?*T、[]T、fn(...)、关键字、别名到组合<E7BB84>?*/
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防御性报<E680A7>?*/
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 地址 + 字段类型<E7B1BB>?*/
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 <20>?lvalue = <20>?gdata 地址<E59CB0>?*/
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) {
spl_ir_node_ref_t slv = base_lv ? emit_load(a, fc, base_t, base_lv) : base_addr;
elem_t = bt->slice_element;
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);
} 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;
}
/* 顶层 / 命名空间全局 varlvalue = 全局分配地址 */
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自动取地址<E59CB0>?left = expr 语义<E8AFAD>?*/
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, &lt);
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自动取地址<E59CB0>?left = expr 语义<E8AFAD>?*/
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, &lt);
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;
if (strcmp(id, "sizeof") == 0 && pn->primary_expr.builtin_expr.expr_list.size) {
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, "sizeof: cannot resolve type");
return 0;
}
spl_ir_node_ref_t n = emit_node(a, fc);
spl_ir_node_t *e = enode(a, fc, n);
e->kind = SPL_IR_TYPE_SIZEOF;
e->ir_sizeof.tid = t;
set_ntype(fc, n, kw_type(a, "usize"));
return n;
}
if (strcmp(id, "dbg") == 0) {
for (usize i = 0; i < pn->primary_expr.builtin_expr.expr_list.size; 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;
}
diag(a, fc, 0, "unsupported builtin call");
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 <20>?全局数据 */
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_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 = emit_load(a, fc, bt, base_lv);
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<EFBC88>?/ 命名空间裸名<E8A3B8>?*/
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;
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);
}
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_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;
if (is_enum && pk->packed_expr.ident) {
isize vidx = enum_variant_index(a, st, pk->packed_expr.ident);
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)直接提<E68EA5>?payloadfield_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:
diag(a, fc, ref, "if-var not supported");
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 已记<E5B7B2>?fn_tidspl_type_fn 不去重fn_tid 唯一<E594AF>?*/
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);
}
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);
}
/* ================================================================
* 全局数据(聚合类型下 / 顶层<E9A1B6>?var、const<73>?
* ================================================================ */
/* 常量折叠仅支持字面量int/char/float/string/null与一元负<E58583>?*/
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 {
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 <20>?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);
}
}
}