Compare commits

...
2 Commits
Author SHA1 Message Date
zzy 0e38858785 stage2 支持左值的引用绑定 2026-09-29 23:00:24 +08:00
zzy 40cffa9cb5 stage0 新增内存复制指令 重构vm交互 2026-09-29 21:11:15 +08:00
22 changed files with 826 additions and 356 deletions

No files matched your search

+1
View File
@@ -97,6 +97,7 @@ typedef enum {
/* 间接内存访问 */ \ /* 间接内存访问 */ \
X(SPL_LOAD, "load", 0, 1, 1, "load sizeof(type)-bits zero-extended") \ X(SPL_LOAD, "load", 0, 1, 1, "load sizeof(type)-bits zero-extended") \
X(SPL_STORE, "store", 0, 2, 0, "store low sizeof(type)-bits") \ X(SPL_STORE, "store", 0, 2, 0, "store low sizeof(type)-bits") \
X(SPL_MEMCPY, "memcpy", 0, 3, 0, "copy n bytes: pop dst, src, n (VM address space)") \
/* 原生接口 */ \ /* 原生接口 */ \
X(SPL_NCALL, "ncall", 1, 0, 1, "call native function by index") \ X(SPL_NCALL, "ncall", 1, 0, 1, "call native function by index") \
X(SPL_NLIB, "nlib", 1, 0, 0, "dlopen library (name idx)") \ X(SPL_NLIB, "nlib", 1, 0, 0, "dlopen library (name idx)") \
-28
View File
@@ -87,32 +87,4 @@ SPL_FN u64 vm_timestamp(u64 kind) {
#define SPL_VM_EMBED_IMPLIMENTATION #define SPL_VM_EMBED_IMPLIMENTATION
#include "spl_vm_embed.h" #include "spl_vm_embed.h"
/* 配置层外部函数处理器(native 端):把 nested VM 未解析的 native 按名分发到
* 编译器生成的 `ct_*` 函数(表由 ir2c 生成,见 stage2/ir2c.spl)。 */
extern void *spl_ct_lookup(const char *name);
typedef spl_vm_val_t (*spl_native_ct_fn_t)(void *, spl_vm_val_t, spl_vm_val_t, spl_vm_val_t);
SPL_FN spl_vm_val_t spl_native_foreign(spl_vm_t *vm, const spl_vm_call_t *call, void *user) {
void *fn;
spl_vm_val_t a0 = 0, a1 = 0;
(void)vm;
if (!call)
return 0;
fn = spl_ct_lookup(call->name);
if (!fn)
return 0;
if (call->nargs > 0)
a0 = call->args[0];
if (call->nargs > 1)
a1 = call->args[1];
/* ct_* 统一形状:返回 u64,参数 (ctx, u64, u64);多余参数被忽略。 */
return ((spl_native_ct_fn_t)fn)(user, a0, a1, 0);
}
SPL_FN void vm_set_foreign(void *p, unsigned long long handler, void *ctx) {
(void)handler;
spl_vm_set_foreign((spl_vm_t *)p, spl_native_foreign, ctx);
}
#endif /* __SPL_RT_H__ */ #endif /* __SPL_RT_H__ */
+58 -33
View File
@@ -615,33 +615,51 @@ static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
* nested-VM syscalls * nested-VM syscalls
* ================================================================= */ * ================================================================= */
/* ---- 配置层的“外部函数处理器”:把某个 VM 未解析的 native 交给调用者 VM。 /* 通用双向桥(配置层策略,非 VM 平台 API):
* 这是配置策略,不属于 VM 库 API;VM 本身只有通用 foreign 钩子。 ---- */ * 在子 VM 上安装「未解析 native 处理器」,把子 VM 的未解析调用按名转发到
* 宿主(调用者)VM 中由 `entry` 指定的函数。宿主函数收到:
* (ctx, name_off, name_len, nested_vm, arg_base, nargs)
* 平台/C 侧**纯转发**:不复制实参、不限元数、不了解类型;聚合读写由宿主用
* vm_stack_get / vm_mem_read / vm_mem_alloc / vm_mem_write 自行完成。
* `entry` 由宿主显式给出,平台不预设任何函数名。 */
typedef struct { typedef struct {
spl_vm_t *caller; spl_vm_t *host;
void *ctx; void *ctx;
} spl_foreign_t; char entry[128];
} spl_bridge_t;
static spl_vm_val_t spl_foreign_reenter(spl_vm_t *vm, const spl_vm_call_t *call, void *user) { static spl_vm_val_t spl_bridge_forward(spl_vm_t *nested, const spl_vm_call_t *call, void *user) {
spl_foreign_t *f = (spl_foreign_t *)user; spl_bridge_t *b = (spl_bridge_t *)user;
spl_vm_val_t tmp[20]; spl_vm_val_t name_off;
spl_vm_call_t c2; spl_vm_val_t args[6];
int i; spl_vm_call_t back;
(void)vm; usize n;
if (!f || !f->caller || !call || !call->name) usize arg_base;
if (!b || !b->host || !call || !call->name || b->entry[0] == '\0')
return 0; return 0;
if (call->nargs + 1 > (usize)(sizeof(tmp) / sizeof(tmp[0]))) n = strlen(call->name);
/* 名拷进宿主 VM 内存,宿主按偏移读取。 */
name_off = spl_vm_mem_alloc(b->host, n + 1);
if (!name_off)
return 0; return 0;
tmp[0] = (spl_vm_val_t)(uintptr_t)f->ctx; if (spl_vm_mem_write(b->host, name_off, call->name, n + 1) != 0)
for (i = 0; i < (int)call->nargs; i++)
tmp[1 + i] = call->args ? call->args[i] : 0;
c2.name = call->name;
c2.args = tmp;
c2.nargs = call->nargs + 1;
c2.ret = 0;
if (spl_vm_invoke(f->caller, &c2) != 0)
return 0; return 0;
return c2.ret; arg_base = spl_vm_call_arg_base(nested, call);
if (arg_base == (usize)-1)
return 0;
args[0] = (spl_vm_val_t)(uintptr_t)b->ctx;
args[1] = name_off;
args[2] = (spl_vm_val_t)n;
args[3] = (spl_vm_val_t)(uintptr_t)nested;
args[4] = (spl_vm_val_t)arg_base;
args[5] = (spl_vm_val_t)call->nargs;
back.name = b->entry;
back.args = args;
back.nargs = 6;
back.ret = 0;
if (spl_vm_invoke(b->host, &back) != 0)
return 0;
return back.ret;
} }
static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
@@ -655,25 +673,32 @@ static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
return (spl_vm_val_t)(uintptr_t)vm; return (spl_vm_val_t)(uintptr_t)vm;
} }
/* 配置入口:vm_set_foreign(vm, handler, ctx)。handler=0:把未解析 native 重入 /* vm_set_foreign(vm, entry, ctx):宿主显式指定处理器函数名。 */
* 当前调用者(_vm),ctx 透传前置。名与语义由配置层定义;VM 库不认识 foreign handler。 */
static spl_vm_val_t sc_vm_set_foreign(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { static spl_vm_val_t sc_vm_set_foreign(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
spl_vm_t *vm; spl_vm_t *vm;
spl_foreign_t *f; spl_bridge_t *b;
const spl_vm_val_t *entry;
const char *eptr;
usize elen;
CHECK_NARGS("vm_set_foreign", 3); CHECK_NARGS("vm_set_foreign", 3);
vm = (spl_vm_t *)(uintptr_t)args[0]; vm = (spl_vm_t *)(uintptr_t)args[0];
if (!vm || !_vm) if (!vm || !_vm)
return -1; return -1;
if (args[1] != 0) /* 仅注册 handler 0(重入调用者) */ entry = (const spl_vm_val_t *)VM_XN(_vm, args[1], 2 * sizeof(spl_vm_val_t));
if (!entry)
return -1; return -1;
if (vm->foreign == spl_foreign_reenter && vm->foreign_ctx) eptr = (const char *)VM_X(_vm, entry[0]);
free(vm->foreign_ctx); elen = (usize)entry[1];
f = (spl_foreign_t *)malloc(sizeof(*f)); if (!eptr || elen == 0 || elen >= sizeof(((spl_bridge_t *)0)->entry))
if (!f)
return -1; return -1;
f->caller = _vm; b = (spl_bridge_t *)malloc(sizeof(*b));
f->ctx = (void *)(uintptr_t)args[2]; if (!b)
spl_vm_set_foreign(vm, spl_foreign_reenter, f); return -1;
b->host = _vm;
b->ctx = (void *)(uintptr_t)args[2];
memcpy(b->entry, eptr, elen);
b->entry[elen] = '\0';
spl_vm_set_foreign(vm, spl_bridge_forward, b);
return 0; return 0;
} }
@@ -683,7 +708,7 @@ static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0];
if (!vm) if (!vm)
return 0; return 0;
if (vm->foreign == spl_foreign_reenter && vm->foreign_ctx) if (vm->foreign == spl_bridge_forward && vm->foreign_ctx)
free(vm->foreign_ctx); free(vm->foreign_ctx);
if (vm->prog) { if (vm->prog) {
spl_prog_drop(vm->prog); spl_prog_drop(vm->prog);
+23
View File
@@ -785,6 +785,14 @@ int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val) {
return 0; return 0;
} }
usize spl_vm_call_arg_base(spl_vm_t *vm, const spl_vm_call_t *call) {
if (!vm || !call || !call->args || !vm->stacks.data)
return (usize)-1;
if (call->args < vm->stacks.data)
return (usize)-1;
return (usize)(call->args - vm->stacks.data);
}
spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size) { return spl_vm_asp_alloc(vm, size); } spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size) { return spl_vm_asp_alloc(vm, size); }
int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n) { int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n) {
@@ -1358,6 +1366,7 @@ static int vm_loop(spl_vm_t *vm, size_t limit) {
DT(SPL_CALLI), DT(SPL_RET), DT(SPL_ALLOC), DT(SPL_CALLI), DT(SPL_RET), DT(SPL_ALLOC),
DT(SPL_LADDR), DT(SPL_GADDR), DT(SPL_LOAD), DT(SPL_LADDR), DT(SPL_GADDR), DT(SPL_LOAD),
DT(SPL_STORE), DT(SPL_NCALL), DT(SPL_NLIB), DT(SPL_STORE), DT(SPL_NCALL), DT(SPL_NLIB),
DT(SPL_MEMCPY),
DT(SPL_BK), DT(SPL_DBG), [SPL_ERROR] = &&L_default, DT(SPL_BK), DT(SPL_DBG), [SPL_ERROR] = &&L_default,
}; };
@@ -1679,6 +1688,20 @@ L_SPL_STORE:
memcpy(_addr, &_v, spl_type_size(ins->type)); memcpy(_addr, &_v, spl_type_size(ins->type));
DISPATCH(); DISPATCH();
} }
L_SPL_MEMCPY:
{
spl_vm_val_t _n = POP();
spl_vm_val_t _src = POP();
spl_vm_val_t _dst = POP();
if (_n) {
void *_d = spl_vm_xlate(vm, _dst, (usize)_n);
void *_s = spl_vm_xlate(vm, _src, (usize)_n);
if (!_d || !_s)
VM_ERROR("MEMCPY: invalid address");
memmove(_d, _s, (usize)_n);
}
DISPATCH();
}
/* ========== Type Conversion ========== */ /* ========== Type Conversion ========== */
L_SPL_TRUNC: L_SPL_TRUNC:
+3
View File
@@ -127,6 +127,9 @@ usize spl_vm_sp(spl_vm_t *vm);
usize spl_vm_fp(spl_vm_t *vm); usize spl_vm_fp(spl_vm_t *vm);
spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index); spl_vm_val_t spl_vm_stack_get(spl_vm_t *vm, usize index);
int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val); int spl_vm_stack_set(spl_vm_t *vm, usize index, spl_vm_val_t val);
/* 本次调用实参在 VM 栈中的起始下标(外部处理器可按需用 stack_get 逐个读取,
* 无需在 C 侧了解参数类型/元数上限)。失败返回 (usize)-1。 */
usize spl_vm_call_arg_base(spl_vm_t *vm, const spl_vm_call_t *call);
spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size); spl_vm_val_t spl_vm_mem_alloc(spl_vm_t *vm, usize size);
int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n); int spl_vm_mem_read(spl_vm_t *vm, spl_vm_val_t off, void *dst, usize n);
int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n); int spl_vm_mem_write(spl_vm_t *vm, spl_vm_val_t off, const void *src, usize n);
+5
View File
@@ -424,6 +424,11 @@ static void dump_node(spl_ast_t *ast, spl_ast_node_ref_t node_ref, dump_stack_t
dump_node(ast, node->pattern_field.pattern, stack, true); dump_node(ast, node->pattern_field.pattern, stack, true);
break; break;
case SPL_AST_PATTERN_REF:
if (node->pattern_ref.pat)
dump_node(ast, node->pattern_ref.pat, stack, true);
break;
default: default:
break; break;
} }
+6 -1
View File
@@ -73,7 +73,8 @@
X(SPL_AST_PATTERN_TUPLE, V0, pattern_tuple) \ X(SPL_AST_PATTERN_TUPLE, V0, pattern_tuple) \
X(SPL_AST_PATTERN_LIST, V0, pattern_list) \ X(SPL_AST_PATTERN_LIST, V0, pattern_list) \
X(SPL_AST_PATTERN_AGGREGATE, V0, pattern_aggregate) \ X(SPL_AST_PATTERN_AGGREGATE, V0, pattern_aggregate) \
X(SPL_AST_PATTERN_FIELD, V0, pattern_field) X(SPL_AST_PATTERN_FIELD, V0, pattern_field) \
X(SPL_AST_PATTERN_REF, V0, pattern_ref)
/* clang-format on */ /* clang-format on */
typedef enum { typedef enum {
@@ -452,6 +453,10 @@ struct spl_ast_node {
const char *name; const char *name;
spl_ast_node_ref_t pattern; spl_ast_node_ref_t pattern;
} pattern_field; } pattern_field;
struct {
spl_ast_node_ref_t pat;
} pattern_ref;
}; };
}; };
+119 -17
View File
@@ -51,7 +51,8 @@ static void emit_deferred_until(spl_ast2ir_t *a, usize base) {
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref); static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n); static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref, static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_ir_node_ref_t src_ptr, spl_type_id_t tid); spl_ir_node_ref_t src_ptr, spl_type_id_t tid, int place_mode);
static int pattern_has_ref(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref);
static spl_ir_node_ref_t emit_match_check(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref, static spl_ir_node_ref_t emit_match_check(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_type_id_t scrut_ir, spl_ir_node_ref_t scrut_slot); spl_type_id_t scrut_ir, spl_ir_node_ref_t scrut_slot);
@@ -140,14 +141,52 @@ static spl_ir_node_ref_t emit_zero_value(spl_ast2ir_t *a, spl_type_id_t tid) {
} }
} }
/* 判断 pattern 是否包含 `&` 引用绑定(PATTERN_REF)。 */
static int pattern_has_ref(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref) {
if (!pat_ref)
return 0;
spl_ast_node_t *pat = spl_ast_node(a->ast, pat_ref);
if (!pat)
return 0;
switch (pat->kind) {
case SPL_AST_PATTERN_REF:
return 1;
case SPL_AST_PATTERN_LIST:
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
if (pattern_has_ref(a, vec_at(pat->pattern_list.patterns, i)))
return 1;
return 0;
case SPL_AST_PATTERN_TUPLE:
for (usize i = 0; i < vec_size(pat->pattern_tuple.patterns); ++i)
if (pattern_has_ref(a, vec_at(pat->pattern_tuple.patterns, i)))
return 1;
return 0;
case SPL_AST_PATTERN_DOT:
return pattern_has_ref(a, pat->pattern_dot.sub_pattern);
case SPL_AST_PATTERN_AGGREGATE:
for (usize i = 0; i < vec_size(pat->pattern_aggregate.fields); ++i) {
spl_ast_node_t *f =
spl_ast_node(a->ast, vec_at(pat->pattern_aggregate.fields, i));
if (f && f->kind == SPL_AST_PATTERN_FIELD &&
pattern_has_ref(a, f->pattern_field.pattern))
return 1;
}
return 0;
default:
return 0;
}
}
/* 把 pattern 里的 ident 绑到 src_ptr 指向内存的对应位置。 /* 把 pattern 里的 ident 绑到 src_ptr 指向内存的对应位置。
- PATTERN_IDENT: def2ir_map[def_id] = src_ptr - PATTERN_IDENT: def2ir_map[def_id] = src_ptr(place_mode=0,值绑定别名源);
place_mode=1 时强制拷贝到新 slot(源为真实左值,值绑定必须拷贝)。
- PATTERN_REF: src_ptr 是该子位置的地址;分配 *T slot 存该地址,内层名绑到 slot。
- PATTERN_DOT: src_ptr 指向 enum,payload 在 mem_field(tid, src_ptr, vidx+1) - PATTERN_DOT: src_ptr 指向 enum,payload 在 mem_field(tid, src_ptr, vidx+1)
- PATTERN_TUPLE / PATTERN_AGGREGATE: 递归 mem_field - PATTERN_TUPLE / PATTERN_AGGREGATE: 递归 mem_field
UB 语义:不做 tag 检查,调用者保证变体正确。 UB 语义:不做 tag 检查,调用者保证变体正确。
*/ */
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref, static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_ir_node_ref_t src_ptr, spl_type_id_t tid) { spl_ir_node_ref_t src_ptr, spl_type_id_t tid, int place_mode) {
if (!pat_ref || !src_ptr) if (!pat_ref || !src_ptr)
return; return;
spl_ast_node_t *pat = spl_ast_node(a->ast, pat_ref); spl_ast_node_t *pat = spl_ast_node(a->ast, pat_ref);
@@ -156,8 +195,30 @@ static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
switch (pat->kind) { switch (pat->kind) {
case SPL_AST_PATTERN_IDENT: { case SPL_AST_PATTERN_IDENT: {
if (pat->resolved_def_id) if (!pat->resolved_def_id)
return;
if (place_mode) {
spl_ir_node_ref_t slot =
spl_ir_builder_mem_alloca(a->ir, tid, const_usize(a, 1));
spl_ir_node_ref_t v = spl_ir_builder_mem_load(a->ir, tid, src_ptr);
spl_ir_builder_mem_store(a->ir, tid, slot, v);
map_put(a->def2ir_map, pat->resolved_def_id, slot);
} else {
map_put(a->def2ir_map, pat->resolved_def_id, src_ptr); map_put(a->def2ir_map, pat->resolved_def_id, src_ptr);
}
return;
}
case SPL_AST_PATTERN_REF: {
spl_ast_node_ref_t inner = pat->pattern_ref.pat;
spl_ast_node_t *in = spl_ast_node(a->ast, inner);
spl_type_id_t ptr_tid = in ? node_ir(a, in) : 0;
if (!ptr_tid)
ptr_tid = spl_type_builder_ptr(&a->sema->type->ir, tid);
spl_ir_node_ref_t slot =
spl_ir_builder_mem_alloca(a->ir, ptr_tid, const_usize(a, 1));
spl_ir_builder_mem_store(a->ir, ptr_tid, slot, src_ptr);
emit_pattern_bind(a, inner, slot, ptr_tid, 0);
return; return;
} }
@@ -174,7 +235,7 @@ static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
case SPL_AST_PATTERN_LIST: case SPL_AST_PATTERN_LIST:
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i) for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
emit_pattern_bind(a, vec_at(pat->pattern_list.patterns, i), src_ptr, tid); emit_pattern_bind(a, vec_at(pat->pattern_list.patterns, i), src_ptr, tid, place_mode);
return; return;
case SPL_AST_PATTERN_TUPLE: { case SPL_AST_PATTERN_TUPLE: {
@@ -188,7 +249,7 @@ static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
for (usize i = 0; i < n; ++i) { for (usize i = 0; i < n; ++i) {
spl_type_id_t ft = vec_at(tn->agg_type.variants, i).type_id; spl_type_id_t ft = vec_at(tn->agg_type.variants, i).type_id;
spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, i); spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, i);
emit_pattern_bind(a, vec_at(pat->pattern_tuple.patterns, i), fp, ft); emit_pattern_bind(a, vec_at(pat->pattern_tuple.patterns, i), fp, ft, place_mode);
} }
return; return;
} }
@@ -206,7 +267,7 @@ static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id; spl_type_id_t payload_ir = vec_at(tn->agg_type.variants, vidx).type_id;
spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, tid, src_ptr, vidx + 1); spl_ir_node_ref_t pptr = spl_ir_builder_mem_field(a->ir, tid, src_ptr, vidx + 1);
if (pat->pattern_dot.sub_pattern) if (pat->pattern_dot.sub_pattern)
emit_pattern_bind(a, pat->pattern_dot.sub_pattern, pptr, payload_ir); emit_pattern_bind(a, pat->pattern_dot.sub_pattern, pptr, payload_ir, place_mode);
return; return;
} }
@@ -224,7 +285,7 @@ static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
spl_type_id_t ft = vec_at(tn->agg_type.variants, idx).type_id; spl_type_id_t ft = vec_at(tn->agg_type.variants, idx).type_id;
spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, idx); spl_ir_node_ref_t fp = spl_ir_builder_mem_field(a->ir, tid, src_ptr, idx);
if (f->pattern_field.pattern) if (f->pattern_field.pattern)
emit_pattern_bind(a, f->pattern_field.pattern, fp, ft); emit_pattern_bind(a, f->pattern_field.pattern, fp, ft, place_mode);
} }
return; return;
} }
@@ -297,12 +358,32 @@ static spl_ir_node_ref_t emit_match_check(spl_ast2ir_t *a, spl_ast_node_ref_t pa
} }
/* 分配 slot → store init 值 → bind pattern。 /* 分配 slot → store init 值 → bind pattern。
返回指向变量内存的指针(*tid),调用者可用于读取初值。 */ 返回指向变量内存的指针(*tid),调用者可用于读取初值。
若 pattern 含 `&` 引用绑定:源必须是可寻址左值,直接在源 place 上绑定
(值绑定拷贝子值,引用绑定取子位置地址),返回该 place。 */
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n) { static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n) {
spl_type_id_t var_ir = node_ir(a, n); spl_type_id_t var_ir = node_ir(a, n);
if (!var_ir) if (!var_ir)
return 0; return 0;
spl_ast_node_ref_t pat_ref = n->var_const_decl.pattern;
if (pattern_has_ref(a, pat_ref)) {
if (!n->var_const_decl.init_expr) {
spl_diag_error(a->diag, SPL_DIAG_KIND_NO_LVALUE, &n->dbg,
"reference binding requires an initialized place");
return 0;
}
spl_ir_node_ref_t place = emit_lvalue(a, n->var_const_decl.init_expr);
if (!place) {
spl_ast_node_t *in = spl_ast_node(a->ast, n->var_const_decl.init_expr);
spl_diag_error(a->diag, SPL_DIAG_KIND_NO_LVALUE, in ? &in->dbg : &n->dbg,
"cannot bind by reference: initializer is not an lvalue");
return 0;
}
emit_pattern_bind(a, pat_ref, place, var_ir, 1);
return place;
}
spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, var_ir, const_usize(a, 1)); spl_ir_node_ref_t slot = spl_ir_builder_mem_alloca(a->ir, var_ir, const_usize(a, 1));
if (n->var_const_decl.init_expr) { if (n->var_const_decl.init_expr) {
@@ -311,7 +392,7 @@ static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n) {
spl_ir_builder_mem_store(a->ir, var_ir, slot, v); spl_ir_builder_mem_store(a->ir, var_ir, slot, v);
} }
emit_pattern_bind(a, n->var_const_decl.pattern, slot, var_ir); emit_pattern_bind(a, pat_ref, slot, var_ir, 0);
return slot; return slot;
} }
@@ -1396,12 +1477,32 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
if (!matched_ir) if (!matched_ir)
return 0; return 0;
spl_ir_node_ref_t scrut_slot = spl_ir_node_ref_t scrut_slot = 0;
spl_ir_builder_mem_alloca(a->ir, matched_ir, const_usize(a, 1)); int matched_place_mode = 0;
spl_ir_node_ref_t scrut_val = emit_expr(a, matched_ref); for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) {
if (!scrut_val) spl_ast_node_t *arm = spl_ast_node(a->ast, vec_at(n->match_expr.arms, i));
return 0; if (arm && arm->kind == SPL_AST_MATCH_ARM &&
spl_ir_builder_mem_store(a->ir, matched_ir, scrut_slot, scrut_val); pattern_has_ref(a, arm->match_arm.pattern)) {
matched_place_mode = 1;
break;
}
}
if (matched_place_mode) {
scrut_slot = emit_lvalue(a, matched_ref);
if (!scrut_slot) {
spl_diag_error(a->diag, SPL_DIAG_KIND_NO_LVALUE,
matched_node ? &matched_node->dbg : &n->dbg,
"cannot bind by reference: matched value is not an lvalue");
return 0;
}
} else {
scrut_slot = spl_ir_builder_mem_alloca(a->ir, matched_ir, const_usize(a, 1));
spl_ir_node_ref_t scrut_val = emit_expr(a, matched_ref);
if (!scrut_val)
return 0;
spl_ir_builder_mem_store(a->ir, matched_ir, scrut_slot, scrut_val);
}
usize narms = vec_size(n->match_expr.arms); usize narms = vec_size(n->match_expr.arms);
spl_ir_node_ref_vec_t arm_branches; spl_ir_node_ref_vec_t arm_branches;
@@ -1448,7 +1549,8 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
spl_ast_node_t *arm = spl_ast_node(a->ast, vec_at(n->match_expr.arms, i)); spl_ast_node_t *arm = spl_ast_node(a->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) { if (arm && arm->kind == SPL_AST_MATCH_ARM) {
emit_pattern_bind(a, arm->match_arm.pattern, scrut_slot, matched_ir); emit_pattern_bind(a, arm->match_arm.pattern, scrut_slot, matched_ir,
matched_place_mode);
if (arm->match_arm.body) if (arm->match_arm.body)
emit_expr(a, arm->match_arm.body); emit_expr(a, arm->match_arm.body);
} }
+1 -4
View File
@@ -1016,10 +1016,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
CG_LOAD(cg, SPL_PTR); CG_LOAD(cg, SPL_PTR);
cg_load_slot(cg, n->control_ret.val, SPL_PTR); cg_load_slot(cg, n->control_ret.val, SPL_PTR);
CG_PUSH(cg, SPL_U64, sz); CG_PUSH(cg, SPL_U64, sz);
int nat = get_or_add_native(ctx, "vm_memcpy"); emit(cg, SPL_MEMCPY, SPL_VOID, 0);
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat);
emit(cg, SPL_NCALL, SPL_VOID, 3);
emit(cg, SPL_DROP, SPL_VOID, 0);
} }
emit(cg, SPL_RET, SPL_VOID, 0); emit(cg, SPL_RET, SPL_VOID, 0);
break; break;
+14
View File
@@ -417,6 +417,20 @@ static spl_ast_node_ref_t parse_pattern_atom(spl_parser_t *p) {
return ref; return ref;
} }
case TOK_AND: {
/* `&name`:解包左值引用绑定。仅允许作用于绑定名。 */
advance(p);
const spl_tok_t *nx = peek(p);
if (!nx || nx->type != TOK_IDENT) {
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, nx, "expected binding name after '&'");
return 0;
}
spl_ast_node_ref_t inner = parse_pattern_atom(p);
spl_ast_node_ref_t ref = new_node(p, SPL_AST_PATTERN_REF, t);
node_at(p->ast, ref)->pattern_ref.pat = inner;
return ref;
}
default: default:
PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected token in pattern"); PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_UNRECOGNIZED, t, "unexpected token in pattern");
return 0; return 0;
+12
View File
@@ -1136,6 +1136,18 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref,
case SPL_AST_PATTERN_UNDERSCORE: case SPL_AST_PATTERN_UNDERSCORE:
return; return;
case SPL_AST_PATTERN_REF: {
if (!matched_tid) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &pat->dbg,
"ref pattern requires a concrete type");
return;
}
spl_lang_type_id_t ptr = spl_lang_make_ptr(sema->type, matched_tid);
sema_bind_pattern(sema, pat->pattern_ref.pat, ptr);
pat->resolved_lang_tid = ptr;
return;
}
case SPL_AST_PATTERN_LIST: { case SPL_AST_PATTERN_LIST: {
for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i) for (usize i = 0; i < vec_size(pat->pattern_list.patterns); ++i)
sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), matched_tid); sema_bind_pattern(sema, vec_at(pat->pattern_list.patterns, i), matched_tid);
+4 -1
View File
@@ -45,7 +45,7 @@ type Body = enum {
type_expr: usize, type_expr: usize,
init_expr: usize, init_expr: usize,
}, },
ParamDecl: struct { attr_list: Vec, name: ByteView, type_expr: usize }, ParamDecl: struct { attr_list: Vec, is_comptime: bool, name: ByteView, type_expr: usize },
StatementRet: struct { expr: usize }, StatementRet: struct { expr: usize },
StatementBreak: struct { label: usize, expr: usize }, StatementBreak: struct { label: usize, expr: usize },
StatementContinue: struct { label: usize }, StatementContinue: struct { label: usize },
@@ -124,6 +124,7 @@ type Body = enum {
PatternList: struct { items: Vec }, PatternList: struct { items: Vec },
PatternAggregate: struct { items: Vec }, PatternAggregate: struct { items: Vec },
PatternField: struct { name: ByteView, pattern: usize }, PatternField: struct { name: ByteView, pattern: usize },
PatternRef: struct { pat: usize },
ExprComptime: struct { body: usize }, ExprComptime: struct { body: usize },
ExprComptimeInit: struct { name: ByteView, args: Vec, fields: Vec }, ExprComptimeInit: struct { name: ByteView, args: Vec, fields: Vec },
} }
@@ -201,6 +202,7 @@ fn kind_name(body: Body): []u8 {
.PatternList(_) => { ret "pattern_list"; }, .PatternList(_) => { ret "pattern_list"; },
.PatternAggregate(_) => { ret "pattern_aggregate"; }, .PatternAggregate(_) => { ret "pattern_aggregate"; },
.PatternField(_) => { ret "pattern_field"; }, .PatternField(_) => { ret "pattern_field"; },
.PatternRef(_) => { ret "pattern_ref"; },
} }
ret "?"; ret "?";
} }
@@ -590,6 +592,7 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool):
.PatternList(v) => { ok = dump_list(ast, buf, stack, v.items); }, .PatternList(v) => { ok = dump_list(ast, buf, stack, v.items); },
.PatternAggregate(v) => { ok = dump_list(ast, buf, stack, v.items); }, .PatternAggregate(v) => { ok = dump_list(ast, buf, stack, v.items); },
.PatternField(p) => { ok = dump_opt(ast, buf, stack, p.pattern, true); }, .PatternField(p) => { ok = dump_opt(ast, buf, stack, p.pattern, true); },
.PatternRef(p) => { ok = dump_opt(ast, buf, stack, p.pat, true); },
} }
stack.len = stack.len - 1; stack.len = stack.len - 1;
+202 -87
View File
@@ -182,7 +182,7 @@ fn is_assign_arith(op: Punct): bool {
fn int_lit_u64(n: *Node): u64 { fn int_lit_u64(n: *Node): u64 {
match n.body { match n.body {
.ExprIntLit(x) => { .ExprIntLit(&x) => {
var out: u64 = 0; var out: u64 = 0;
match BigInt.to_u64(&out, x.value) { .Ok => {}, .Err(e) => {} } match BigInt.to_u64(&out, x.value) { .Ok => {}, .Err(e) => {} }
ret out; ret out;
@@ -217,14 +217,14 @@ fn emit_zero_value(self: *Ast2Ir, tid: usize): usize {
var variants = Vec.blank(@sizeof(usize), @alignof(usize)); var variants = Vec.blank(@sizeof(usize), @alignof(usize));
match tn.node { match tn.node {
.Bool => { is_bool = true; }, .Bool => { is_bool = true; },
.Int(x) => { is_int = true; }, .Int(&x) => { is_int = true; },
.Float(x) => { is_float = true; }, .Float(&x) => { is_float = true; },
.Ptr(x) => { is_ptr = true; }, .Ptr(&x) => { is_ptr = true; },
.Fn(x) => { is_fn = true; }, .Fn(&x) => { is_fn = true; },
.Array(x) => { is_arr = true; arr_len = x.len; arr_elem = x.element; }, .Array(&x) => { is_arr = true; arr_len = x.len; arr_elem = x.element; },
.Struct(x) => { is_struct = true; variants = x.variants; }, .Struct(&x) => { is_struct = true; variants = x.variants; },
.Shape(x) => { is_shape = true; variants = x.variants; }, .Shape(&x) => { is_shape = true; variants = x.variants; },
.Union(x) => { is_union = true; variants = x.variants; }, .Union(&x) => { is_union = true; variants = x.variants; },
_ => { ret 0; }, _ => { ret 0; },
} }
if is_bool { ret IrBuilder.type_const_bool(self.ir, tid, false); } if is_bool { ret IrBuilder.type_const_bool(self.ir, tid, false); }
@@ -279,14 +279,77 @@ fn variant_at(v: Vec, idx: usize): usize {
// ---- 模式绑定 ---- // ---- 模式绑定 ----
fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize) { fn pattern_has_ref(self: *Ast2Ir, pat_ref: usize): bool {
if pat_ref == 0 { ret false; }
var pat = Ast.node(self.ast, pat_ref);
if pat == null { ret false; }
match pat.body {
.PatternRef(_) => { ret true; },
.PatternList(x) => {
var i: usize = 0;
while i < x.items.len {
if pattern_has_ref(self, list_at(x.items, i)) { ret true; }
i = i + 1;
}
ret false;
},
.PatternTuple(x) => {
var i: usize = 0;
while i < x.items.len {
if pattern_has_ref(self, list_at(x.items, i)) { ret true; }
i = i + 1;
}
ret false;
},
.PatternDot(x) => { ret pattern_has_ref(self, x.sub_pattern); },
.PatternAggregate(x) => {
var i: usize = 0;
while i < x.items.len {
var f = Ast.node(self.ast, list_at(x.items, i));
if f != null {
match f.body {
.PatternField(pf) => {
if pattern_has_ref(self, pf.pattern) { ret true; }
},
_ => {},
}
}
i = i + 1;
}
ret false;
},
_ => { ret false; },
}
ret false;
}
fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize, place_mode: bool) {
if pat_ref == 0 || src_ptr == 0 { ret; } if pat_ref == 0 || src_ptr == 0 { ret; }
var pat = Ast.node(self.ast, pat_ref); var pat = Ast.node(self.ast, pat_ref);
if pat == null { ret; } if pat == null { ret; }
match pat.body { match pat.body {
.PatternIdent(x) => { .PatternIdent(x) => {
if pat.resolved_def_id != 0 { ir_map_put(self, pat.resolved_def_id, src_ptr); } if pat.resolved_def_id != 0 {
if place_mode {
var slot = IrBuilder.mem_alloca(self.ir, tid, const_usize(self, 1));
var v = IrBuilder.mem_load(self.ir, tid, src_ptr);
ignore_usize(IrBuilder.mem_store(self.ir, tid, slot, v));
ir_map_put(self, pat.resolved_def_id, slot);
} else {
ir_map_put(self, pat.resolved_def_id, src_ptr);
}
}
ret;
},
.PatternRef(x) => {
var in = Ast.node(self.ast, x.pat);
var ptr_tid: usize = 0;
if in != null { ptr_tid = node_ir(self, in); }
if ptr_tid == 0 { ptr_tid = TypeTable.make_ptr(&self.sema.types.ir, tid); }
var slot = IrBuilder.mem_alloca(self.ir, ptr_tid, const_usize(self, 1));
ignore_usize(IrBuilder.mem_store(self.ir, ptr_tid, slot, src_ptr));
emit_pattern_bind(self, x.pat, slot, ptr_tid, false);
ret; ret;
}, },
.ExprIntLit(x) => { ret; }, .ExprIntLit(x) => { ret; },
@@ -299,7 +362,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize)
.PatternList(x) => { .PatternList(x) => {
var i: usize = 0; var i: usize = 0;
while i < x.items.len { while i < x.items.len {
emit_pattern_bind(self, list_at(x.items, i), src_ptr, tid); emit_pattern_bind(self, list_at(x.items, i), src_ptr, tid, place_mode);
i = i + 1; i = i + 1;
} }
ret; ret;
@@ -316,7 +379,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize)
while i < n { while i < n {
var ft = variant_at(variants, i); var ft = variant_at(variants, i);
var fp = IrBuilder.mem_field(self.ir, tid, src_ptr, i); var fp = IrBuilder.mem_field(self.ir, tid, src_ptr, i);
emit_pattern_bind(self, list_at(x.items, i), fp, ft); emit_pattern_bind(self, list_at(x.items, i), fp, ft, place_mode);
i = i + 1; i = i + 1;
} }
ret; ret;
@@ -333,7 +396,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize)
var payload_ir = variant_at(variants, vidx); var payload_ir = variant_at(variants, vidx);
var pptr = IrBuilder.mem_field(self.ir, tid, src_ptr, vidx + 1); var pptr = IrBuilder.mem_field(self.ir, tid, src_ptr, vidx + 1);
if x.sub_pattern != 0 { if x.sub_pattern != 0 {
emit_pattern_bind(self, x.sub_pattern, pptr, payload_ir); emit_pattern_bind(self, x.sub_pattern, pptr, payload_ir, place_mode);
} }
ret; ret;
}, },
@@ -357,7 +420,7 @@ fn emit_pattern_bind(self: *Ast2Ir, pat_ref: usize, src_ptr: usize, tid: usize)
var ft = variant_at(variants, idx); var ft = variant_at(variants, idx);
var fp = IrBuilder.mem_field(self.ir, tid, src_ptr, idx); var fp = IrBuilder.mem_field(self.ir, tid, src_ptr, idx);
if pf.pattern != 0 { if pf.pattern != 0 {
emit_pattern_bind(self, pf.pattern, fp, ft); emit_pattern_bind(self, pf.pattern, fp, ft, place_mode);
} }
} }
}, },
@@ -429,7 +492,6 @@ fn match_check_literal(self: *Ast2Ir, pat_ref: usize, scrut_ir: usize, scrut_slo
fn emit_var_decl(self: *Ast2Ir, n: *Node): usize { fn emit_var_decl(self: *Ast2Ir, n: *Node): usize {
var var_ir = node_ir(self, n); var var_ir = node_ir(self, n);
if var_ir == 0 { ret 0; } if var_ir == 0 { ret 0; }
var slot = IrBuilder.mem_alloca(self.ir, var_ir, const_usize(self, 1));
var iref: usize = 0; var iref: usize = 0;
var pat_ref: usize = 0; var pat_ref: usize = 0;
@@ -438,11 +500,35 @@ fn emit_var_decl(self: *Ast2Ir, n: *Node): usize {
.ConstDecl(x) => { iref = x.init_expr; pat_ref = x.pattern; }, .ConstDecl(x) => { iref = x.init_expr; pat_ref = x.pattern; },
_ => {}, _ => {},
} }
if pattern_has_ref(self, pat_ref) {
if iref == 0 {
Diag.err(self.diag, n.span, .NoLvalue,
"reference binding requires an initialized place");
ret 0;
}
var place = emit_lvalue(self, iref);
if place == 0 {
var in = Ast.node(self.ast, iref);
if in != null {
Diag.err(self.diag, in.span, .NoLvalue,
"cannot bind by reference: initializer is not an lvalue");
} else {
Diag.err(self.diag, n.span, .NoLvalue,
"cannot bind by reference: initializer is not an lvalue");
}
ret 0;
}
emit_pattern_bind(self, pat_ref, place, var_ir, true);
ret place;
}
var slot = IrBuilder.mem_alloca(self.ir, var_ir, const_usize(self, 1));
if iref != 0 { if iref != 0 {
var v = emit_expr(self, iref); var v = emit_expr(self, iref);
if v != 0 { IrBuilder.mem_store(self.ir, var_ir, slot, v); } if v != 0 { IrBuilder.mem_store(self.ir, var_ir, slot, v); }
} }
emit_pattern_bind(self, pat_ref, slot, var_ir); emit_pattern_bind(self, pat_ref, slot, var_ir, false);
ret slot; ret slot;
} }
@@ -631,7 +717,7 @@ fn ast2ir_intrin_field(self: *Ast2Ir, n: *Node, in: Intrin): usize {
fn ast2ir_intrin_len(self: *Ast2Ir, n: *Node): usize { fn ast2ir_intrin_len(self: *Ast2Ir, n: *Node): usize {
var obj_ref: usize = 0; var obj_ref: usize = 0;
var fname = ByteView.empty(); var fname = ByteView.empty();
match n.body { .ExprField(x) => { obj_ref = x.obj; fname = x.name; }, _ => {} } match n.body { .ExprField(&x) => { obj_ref = x.obj; fname = x.name; }, _ => {} }
var obj = Ast.node(self.ast, obj_ref); var obj = Ast.node(self.ast, obj_ref);
var recv_lang = node_lang(obj); var recv_lang = node_lang(obj);
var recv = ltn(self, recv_lang); var recv = ltn(self, recv_lang);
@@ -662,7 +748,7 @@ fn emit_lvalue(self: *Ast2Ir, ref: usize): usize {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret 0; } if n == null { ret 0; }
match n.body { match n.body {
.ExprIdent(x) => { .ExprIdent(&x) => {
var d = defn(self, n.resolved_def_id); var d = defn(self, n.resolved_def_id);
if d != null && @enum2int(d.kind) == @enum2int(DefKind.Fn) { ret 0; } if d != null && @enum2int(d.kind) == @enum2int(DefKind.Fn) { ret 0; }
var g: usize = 0; var g: usize = 0;
@@ -676,12 +762,12 @@ fn emit_lvalue(self: *Ast2Ir, ref: usize): usize {
if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; } if !ir_map_get(self, n.resolved_def_id, &slot) { ret 0; }
ret slot; ret slot;
}, },
.ExprUnary(x) => { .ExprUnary(&x) => {
if !punct_is(x.op, .Mul) { ret 0; } if !punct_is(x.op, .Mul) { ret 0; }
ret emit_expr(self, x.operand); ret emit_expr(self, x.operand);
}, },
.ExprField(x) => { ret lvalue_field(self, n, x.obj, x.name); }, .ExprField(&x) => { ret lvalue_field(self, n, x.obj, x.name); },
.ExprIndex(x) => { ret lvalue_index(self, n, x.obj, x.index); }, .ExprIndex(&x) => { ret lvalue_index(self, n, x.obj, x.index); },
_ => { ret 0; }, _ => { ret 0; },
} }
ret 0; ret 0;
@@ -758,7 +844,7 @@ fn lvalue_index(self: *Ast2Ir, n: *Node, obj_ref: usize, index_ref: usize): usiz
} }
fn is_int_lit(n: *Node): bool { fn is_int_lit(n: *Node): bool {
match n.body { .ExprIntLit(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprIntLit(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -816,7 +902,7 @@ fn ir_float_cast(self: *Ast2Ir, ft: usize, tt: usize, v: usize): usize {
fn emit_cast(self: *Ast2Ir, n: *Node): usize { fn emit_cast(self: *Ast2Ir, n: *Node): usize {
var eref: usize = 0; var eref: usize = 0;
var tref: usize = 0; var tref: usize = 0;
match n.body { .ExprCast(x) => { eref = x.expr; tref = x.type_expr; }, _ => {} } match n.body { .ExprCast(&x) => { eref = x.expr; tref = x.type_expr; }, _ => {} }
var v = emit_expr_raw(self, eref); var v = emit_expr_raw(self, eref);
if v == 0 { ret 0; } if v == 0 { ret 0; }
var src = Ast.node(self.ast, eref); var src = Ast.node(self.ast, eref);
@@ -835,7 +921,7 @@ fn emit_cast(self: *Ast2Ir, n: *Node): usize {
fn ast2ir_field_from_value(self: *Ast2Ir, n: *Node): usize { fn ast2ir_field_from_value(self: *Ast2Ir, n: *Node): usize {
var obj_ref: usize = 0; var obj_ref: usize = 0;
var field_name = ByteView.empty(); var field_name = ByteView.empty();
match n.body { .ExprField(x) => { obj_ref = x.obj; field_name = x.name; }, _ => {} } match n.body { .ExprField(&x) => { obj_ref = x.obj; field_name = x.name; }, _ => {} }
var obj = Ast.node(self.ast, obj_ref); var obj = Ast.node(self.ast, obj_ref);
if obj == null { ret 0; } if obj == null { ret 0; }
var obj_lang = node_lang(obj); var obj_lang = node_lang(obj);
@@ -873,7 +959,7 @@ fn ast2ir_enum_variant(self: *Ast2Ir, n: *Node): usize {
var tn = irt(self, t); var tn = irt(self, t);
if tn == null { ret 0; } if tn == null { ret 0; }
var field_name = ByteView.empty(); var field_name = ByteView.empty();
match n.body { .ExprField(x) => { field_name = x.name; }, _ => {} } match n.body { .ExprField(&x) => { field_name = x.name; }, _ => {} }
var vidx: usize = 0; var vidx: usize = 0;
if !TypeTable.agg_member_idx(&self.sema.types.ir, t, field_name, &vidx) { ret 0; } if !TypeTable.agg_member_idx(&self.sema.types.ir, t, field_name, &vidx) { ret 0; }
var tag_ir: usize = 0; var tag_ir: usize = 0;
@@ -915,39 +1001,39 @@ fn emit_expr_raw(self: *Ast2Ir, ref: usize): usize {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret 0; } if n == null { ret 0; }
match n.body { match n.body {
.ExprIntLit(x) => { ret emit_int_lit(self, n); }, .ExprIntLit(&x) => { ret emit_int_lit(self, n); },
.ExprFloatLit(x) => { ret IrBuilder.type_const_float(self.ir, node_ir(self, n), 0.0); }, .ExprFloatLit(&x) => { ret IrBuilder.type_const_float(self.ir, node_ir(self, n), 0.0); },
.ExprCharLit(x) => { ret IrBuilder.type_const_char(self.ir, node_ir(self, n), x.value); }, .ExprCharLit(&x) => { ret IrBuilder.type_const_char(self.ir, node_ir(self, n), x.value); },
.ExprStringLit(sl) => { ret emit_string_lit(self, n, sl.data); }, .ExprStringLit(&sl) => { ret emit_string_lit(self, n, sl.data); },
.ExprBoolLit(x) => { ret IrBuilder.type_const_bool(self.ir, node_ir(self, n), x.value); }, .ExprBoolLit(&x) => { ret IrBuilder.type_const_bool(self.ir, node_ir(self, n), x.value); },
.ExprNullLit => { ret IrBuilder.type_const_ptr(self.ir, node_ir(self, n), 0); }, .ExprNullLit => { ret IrBuilder.type_const_ptr(self.ir, node_ir(self, n), 0); },
.ExprUndefinedLit => { ret 0; }, .ExprUndefinedLit => { ret 0; },
.ExprIdent(x) => { ret emit_ident(self, n); }, .ExprIdent(&x) => { ret emit_ident(self, n); },
.ExprUnary(x) => { ret emit_unary(self, n, ref, x.op, x.operand); }, .ExprUnary(&x) => { ret emit_unary(self, n, ref, x.op, x.operand); },
.ExprBinary(x) => { ret emit_binary(self, n, x.op, x.left, x.right); }, .ExprBinary(&x) => { ret emit_binary(self, n, x.op, x.left, x.right); },
.ExprCall(x) => { ret emit_call(self, n, x.callee, x.args); }, .ExprCall(&x) => { ret emit_call(self, n, x.callee, x.args); },
.ExprField(x) => { ret emit_field(self, n, ref, x.obj, x.name); }, .ExprField(&x) => { ret emit_field(self, n, ref, x.obj, x.name); },
.ExprIndex(x) => { .ExprIndex(&x) => {
var ptr = emit_lvalue(self, ref); var ptr = emit_lvalue(self, ref);
if ptr == 0 { ret 0; } if ptr == 0 { ret 0; }
ret IrBuilder.mem_load(self.ir, node_ir(self, n), ptr); ret IrBuilder.mem_load(self.ir, node_ir(self, n), ptr);
}, },
.ExprCast(x) => { ret emit_cast(self, n); }, .ExprCast(&x) => { ret emit_cast(self, n); },
.ExprTuple(x) => { ret emit_tuple(self, n, x.items); }, .ExprTuple(&x) => { ret emit_tuple(self, n, x.items); },
.ExprArrayLit(x) => { ret emit_array_lit(self, n, x.elems); }, .ExprArrayLit(&x) => { ret emit_array_lit(self, n, x.elems); },
.ExprAggregateLit(x) => { ret emit_aggregate_lit(self, n, x.name, x.fields); }, .ExprAggregateLit(&x) => { ret emit_aggregate_lit(self, n, x.name, x.fields); },
.ExprBlock(x) => { ret emit_block(self, n, x.stmts, x.tail_expr); }, .ExprBlock(&x) => { ret emit_block(self, n, x.stmts, x.tail_expr); },
.ExprIf(x) => { ret emit_if_like(self, ref); }, .ExprIf(&x) => { ret emit_if_like(self, ref); },
.ExprIfvar(x) => { ret emit_if_like(self, ref); }, .ExprIfvar(&x) => { ret emit_if_like(self, ref); },
.ExprMatch(x) => { ret emit_match(self, n, x.matched_expr, x.arms); }, .ExprMatch(&x) => { ret emit_match(self, n, x.matched_expr, x.arms); },
.ExprWhile(x) => { ret emit_loop_like(self, ref); }, .ExprWhile(&x) => { ret emit_loop_like(self, ref); },
.ExprLoop(x) => { ret emit_loop_like(self, ref); }, .ExprLoop(&x) => { ret emit_loop_like(self, ref); },
.ExprFor(x) => { .ExprFor(&x) => {
Diag.err(self.diag, n.span, .UnhandledNode, "for is not implemented yet"); Diag.err(self.diag, n.span, .UnhandledNode, "for is not implemented yet");
ret 0; ret 0;
}, },
.ExprSlice(x) => { ret emit_slice(self, n, x.obj, x.begin, x.end); }, .ExprSlice(&x) => { ret emit_slice(self, n, x.obj, x.begin, x.end); },
.ExprComptimeCall(x) => { .ExprComptimeCall(&x) => {
var in = IntrinOps.lookup_call(x.name); var in = IntrinOps.lookup_call(x.name);
if @enum2int(in) == @enum2int(Intrin.None) { ret 0; } if @enum2int(in) == @enum2int(Intrin.None) { ret 0; }
ret ast2ir_intrin_call(self, n, in, x.args); ret ast2ir_intrin_call(self, n, in, x.args);
@@ -1176,12 +1262,12 @@ fn emit_call(self: *Ast2Ir, n: *Node, callee_ref: usize, args: Vec): usize {
} }
fn is_ident(n: *Node): bool { fn is_ident(n: *Node): bool {
match n.body { .ExprIdent(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprIdent(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn ident_name(n: *Node): ByteView { fn ident_name(n: *Node): ByteView {
match n.body { .ExprIdent(x) => { ret x.name; }, _ => { ret ByteView.empty(); } } match n.body { .ExprIdent(&x) => { ret x.name; }, _ => { ret ByteView.empty(); } }
ret ByteView.empty(); ret ByteView.empty();
} }
@@ -1428,10 +1514,39 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize {
var matched_lang = node_lang(matched_node); var matched_lang = node_lang(matched_node);
var matched_ir = to_ir_type(self, matched_lang); var matched_ir = to_ir_type(self, matched_lang);
if matched_ir == 0 { ret 0; } if matched_ir == 0 { ret 0; }
var scrut_slot = IrBuilder.mem_alloca(self.ir, matched_ir, const_usize(self, 1));
var scrut_val = emit_expr(self, matched_ref); var matched_place_mode = false;
if scrut_val == 0 { ret 0; } var scan: usize = 0;
ignore_usize(IrBuilder.mem_store(self.ir, matched_ir, scrut_slot, scrut_val)); while scan < arms.len && !matched_place_mode {
var sa = Ast.node(self.ast, list_at(arms, scan));
if sa != null {
var spat: usize = 0;
match sa.body { .MatchArm(ma) => { spat = ma.pattern; }, _ => {} }
if pattern_has_ref(self, spat) { matched_place_mode = true; }
}
scan = scan + 1;
}
var scrut_slot: usize = 0;
if matched_place_mode {
scrut_slot = emit_lvalue(self, matched_ref);
if scrut_slot == 0 {
var mn = Ast.node(self.ast, matched_ref);
if mn != null {
Diag.err(self.diag, mn.span, .NoLvalue,
"cannot bind by reference: matched value is not an lvalue");
} else {
Diag.err(self.diag, n.span, .NoLvalue,
"cannot bind by reference: matched value is not an lvalue");
}
ret 0;
}
} else {
scrut_slot = IrBuilder.mem_alloca(self.ir, matched_ir, const_usize(self, 1));
var scrut_val = emit_expr(self, matched_ref);
if scrut_val == 0 { ret 0; }
ignore_usize(IrBuilder.mem_store(self.ir, matched_ir, scrut_slot, scrut_val));
}
var narms = arms.len; var narms = arms.len;
var arm_branches = Vec.blank(@sizeof(usize), @alignof(usize)); var arm_branches = Vec.blank(@sizeof(usize), @alignof(usize));
@@ -1469,7 +1584,7 @@ fn emit_match(self: *Ast2Ir, n: *Node, matched_ref: usize, arms: Vec): usize {
var pat: usize = 0; var pat: usize = 0;
var body: usize = 0; var body: usize = 0;
match arm.body { .MatchArm(ma) => { pat = ma.pattern; body = ma.body; }, _ => {} } match arm.body { .MatchArm(ma) => { pat = ma.pattern; body = ma.body; }, _ => {} }
emit_pattern_bind(self, pat, scrut_slot, matched_ir); emit_pattern_bind(self, pat, scrut_slot, matched_ir, matched_place_mode);
if body != 0 { ignore_usize(emit_expr(self, body)); } if body != 0 { ignore_usize(emit_expr(self, body)); }
} }
var j: usize = 0; var j: usize = 0;
@@ -1573,7 +1688,7 @@ fn emit_if_like(self: *Ast2Ir, ref: usize): usize {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret 0; } if n == null { ret 0; }
var is_ifvar = false; var is_ifvar = false;
match n.body { .ExprIfvar(x) => { is_ifvar = true; }, _ => {} } match n.body { .ExprIfvar(&x) => { is_ifvar = true; }, _ => {} }
var result_t = node_ir(self, n); var result_t = node_ir(self, n);
var need_result = false; var need_result = false;
@@ -1589,7 +1704,7 @@ fn emit_if_like(self: *Ast2Ir, ref: usize): usize {
var else_ref: usize = 0; var else_ref: usize = 0;
if is_ifvar { if is_ifvar {
var vd_ref: usize = 0; var vd_ref: usize = 0;
match n.body { .ExprIfvar(x) => { vd_ref = x.var_decl; }, _ => {} } match n.body { .ExprIfvar(&x) => { vd_ref = x.var_decl; }, _ => {} }
var vd = Ast.node(self.ast, vd_ref); var vd = Ast.node(self.ast, vd_ref);
if vd == null { ret 0; } if vd == null { ret 0; }
var slot = emit_var_decl(self, vd); var slot = emit_var_decl(self, vd);
@@ -1648,7 +1763,7 @@ fn emit_loop_like(self: *Ast2Ir, ref: usize): usize {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret 0; } if n == null { ret 0; }
var is_while = false; var is_while = false;
match n.body { .ExprWhile(x) => { is_while = true; }, _ => {} } match n.body { .ExprWhile(&x) => { is_while = true; }, _ => {} }
var result_t = node_ir(self, n); var result_t = node_ir(self, n);
var need_result = false; var need_result = false;
@@ -1668,7 +1783,7 @@ fn emit_loop_like(self: *Ast2Ir, ref: usize): usize {
if is_while { if is_while {
head_blk = IrBuilder.block_begin(self.ir); head_blk = IrBuilder.block_begin(self.ir);
var cond: usize = 0; var cond: usize = 0;
match n.body { .ExprWhile(x) => { cond = emit_expr(self, x.cond); }, _ => {} } match n.body { .ExprWhile(&x) => { cond = emit_expr(self, x.cond); }, _ => {} }
if cond == 0 { ret 0; } if cond == 0 { ret 0; }
br = IrBuilder.control_br(self.ir, cond); br = IrBuilder.control_br(self.ir, cond);
IrBuilder.block_end(self.ir); IrBuilder.block_end(self.ir);
@@ -1769,7 +1884,7 @@ fn emit_break_stmt(self: *Ast2Ir, n: *Node): usize {
var lbl = ByteView.empty(); var lbl = ByteView.empty();
var expr_ref: usize = 0; var expr_ref: usize = 0;
match n.body { match n.body {
.StatementBreak(x) => { lbl = label_name_of(self, x.label); expr_ref = x.expr; }, .StatementBreak(&x) => { lbl = label_name_of(self, x.label); expr_ref = x.expr; },
_ => {}, _ => {},
} }
var target_index = self.loop_stack.len - 1; var target_index = self.loop_stack.len - 1;
@@ -1798,24 +1913,24 @@ fn emit_stmt(self: *Ast2Ir, ref: usize) {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret; } if n == null { ret; }
match n.body { match n.body {
.StatementRet(x) => { .StatementRet(&x) => {
var ret_ir = to_ir_type(self, self.cur_ret_lang); var ret_ir = to_ir_type(self, self.cur_ret_lang);
var v: usize = 0; var v: usize = 0;
if x.expr != 0 { v = emit_expr(self, x.expr); } if x.expr != 0 { v = emit_expr(self, x.expr); }
emit_deferred_until(self, self.cur_defer_base); emit_deferred_until(self, self.cur_defer_base);
if !self.ir.terminated { ignore_usize(IrBuilder.control_ret(self.ir, ret_ir, v)); } if !self.ir.terminated { ignore_usize(IrBuilder.control_ret(self.ir, ret_ir, v)); }
}, },
.StatementDefer(x) => { if x.body != 0 { push_u(&self.defer_stack, x.body); } }, .StatementDefer(&x) => { if x.body != 0 { push_u(&self.defer_stack, x.body); } },
.StatementComptime(x) => { if x.body != 0 { ignore_usize(emit_expr(self, x.body)); } }, .StatementComptime(&x) => { if x.body != 0 { ignore_usize(emit_expr(self, x.body)); } },
.StatementDecl(x) => { if x.decl != 0 { emit_decl(self, x.decl); } }, .StatementDecl(&x) => { if x.decl != 0 { emit_decl(self, x.decl); } },
.StatementExpr(x) => { if x.expr != 0 { ignore_usize(emit_expr(self, x.expr)); } }, .StatementExpr(&x) => { if x.expr != 0 { ignore_usize(emit_expr(self, x.expr)); } },
.ExprIf(x) => { ignore_usize(emit_if_like(self, ref)); }, .ExprIf(&x) => { ignore_usize(emit_if_like(self, ref)); },
.ExprIfvar(x) => { ignore_usize(emit_if_like(self, ref)); }, .ExprIfvar(&x) => { ignore_usize(emit_if_like(self, ref)); },
.ExprWhile(x) => { ignore_usize(emit_loop_like(self, ref)); }, .ExprWhile(&x) => { ignore_usize(emit_loop_like(self, ref)); },
.ExprLoop(x) => { ignore_usize(emit_loop_like(self, ref)); }, .ExprLoop(&x) => { ignore_usize(emit_loop_like(self, ref)); },
.StatementBreak(x) => { ignore_usize(emit_break_stmt(self, n)); }, .StatementBreak(&x) => { ignore_usize(emit_break_stmt(self, n)); },
.StatementContinue(x) => { emit_continue_stmt(self, n); }, .StatementContinue(&x) => { emit_continue_stmt(self, n); },
.ExprBlock(x) => { ignore_usize(emit_expr(self, ref)); }, .ExprBlock(&x) => { ignore_usize(emit_expr(self, ref)); },
_ => { ignore_usize(emit_expr(self, ref)); }, _ => { ignore_usize(emit_expr(self, ref)); },
} }
} }
@@ -1823,7 +1938,7 @@ fn emit_stmt(self: *Ast2Ir, ref: usize) {
fn emit_continue_stmt(self: *Ast2Ir, n: *Node) { fn emit_continue_stmt(self: *Ast2Ir, n: *Node) {
if self.loop_stack.len == 0 { ret; } if self.loop_stack.len == 0 { ret; }
var lbl = ByteView.empty(); var lbl = ByteView.empty();
match n.body { .StatementContinue(x) => { lbl = label_name_of(self, x.label); }, _ => {} } match n.body { .StatementContinue(&x) => { lbl = label_name_of(self, x.label); }, _ => {} }
var target_index = self.loop_stack.len - 1; var target_index = self.loop_stack.len - 1;
if lbl.len != 0 { target_index = find_loop_with_label(self, lbl); } if lbl.len != 0 { target_index = find_loop_with_label(self, lbl); }
if target_index == ~(0 as usize) { ret; } if target_index == ~(0 as usize) { ret; }
@@ -1842,8 +1957,8 @@ fn emit_decl(self: *Ast2Ir, ref: usize) {
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
if n == null { ret; } if n == null { ret; }
match n.body { match n.body {
.VarDecl(x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } }, .VarDecl(&x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } },
.ConstDecl(x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } }, .ConstDecl(&x) => { if self.ir.current_fn != 0 { ignore_usize(emit_var_decl(self, n)); } },
_ => {}, _ => {},
} }
} }
@@ -1867,7 +1982,7 @@ fn emit_fn_reserve(self: *Ast2Ir, n: *Node): usize {
} }
fn fn_name_of(n: *Node): ByteView { fn fn_name_of(n: *Node): ByteView {
match n.body { .FnDecl(x) => { ret x.name; }, _ => { ret ByteView.empty(); } } match n.body { .FnDecl(&x) => { ret x.name; }, _ => { ret ByteView.empty(); } }
ret ByteView.empty(); ret ByteView.empty();
} }
@@ -1903,7 +2018,7 @@ fn emit_fn_body(self: *Ast2Ir, n: *Node) {
var params = Vec.blank(@sizeof(usize), @alignof(usize)); var params = Vec.blank(@sizeof(usize), @alignof(usize));
var body_ref: usize = 0; var body_ref: usize = 0;
match n.body { .FnDecl(x) => { params = x.params; body_ref = x.body; }, _ => {} } match n.body { .FnDecl(&x) => { params = x.params; body_ref = x.body; }, _ => {} }
var i: usize = 0; var i: usize = 0;
while i < params.len { while i < params.len {
var pref = list_at(params, i); var pref = list_at(params, i);
@@ -1956,7 +2071,7 @@ fn fn_ret(e: LangEntry): usize {
fn emit_aggregate_fns_reserve(self: *Ast2Ir, te: *Node) { fn emit_aggregate_fns_reserve(self: *Ast2Ir, te: *Node) {
var members = Vec.blank(@sizeof(usize), @alignof(usize)); var members = Vec.blank(@sizeof(usize), @alignof(usize));
match te.body { .TypeAggregate(x) => { members = x.members; }, _ => { ret; } } match te.body { .TypeAggregate(&x) => { members = x.members; }, _ => { ret; } }
var i: usize = 0; var i: usize = 0;
while i < members.len { while i < members.len {
var mn = Ast.node(self.ast, list_at(members, i)); var mn = Ast.node(self.ast, list_at(members, i));
@@ -1978,7 +2093,7 @@ fn emit_aggregate_fns_reserve(self: *Ast2Ir, te: *Node) {
fn emit_aggregate_fns_body(self: *Ast2Ir, te: *Node) { fn emit_aggregate_fns_body(self: *Ast2Ir, te: *Node) {
var members = Vec.blank(@sizeof(usize), @alignof(usize)); var members = Vec.blank(@sizeof(usize), @alignof(usize));
match te.body { .TypeAggregate(x) => { members = x.members; }, _ => { ret; } } match te.body { .TypeAggregate(&x) => { members = x.members; }, _ => { ret; } }
var i: usize = 0; var i: usize = 0;
while i < members.len { while i < members.len {
var mn = Ast.node(self.ast, list_at(members, i)); var mn = Ast.node(self.ast, list_at(members, i));
@@ -1999,7 +2114,7 @@ fn emit_aggregate_fns_body(self: *Ast2Ir, te: *Node) {
} }
fn is_type_aggregate(n: *Node): bool { fn is_type_aggregate(n: *Node): bool {
match n.body { .TypeAggregate(x) => { ret true; }, _ => { ret false; } } match n.body { .TypeAggregate(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -2008,14 +2123,14 @@ fn emit_container_reserve(self: *Ast2Ir, ref: usize) {
if n == null { ret; } if n == null { ret; }
var is_tlb = false; var is_tlb = false;
var tlb_block: usize = 0; var tlb_block: usize = 0;
match n.body { .TopLevelBlock(x) => { is_tlb = true; tlb_block = x.block; }, _ => {} } match n.body { .TopLevelBlock(&x) => { is_tlb = true; tlb_block = x.block; }, _ => {} }
if is_tlb { if is_tlb {
if tlb_block != 0 { emit_container_reserve(self, tlb_block); } if tlb_block != 0 { emit_container_reserve(self, tlb_block); }
ret; ret;
} }
var decls = Vec.blank(@sizeof(usize), @alignof(usize)); var decls = Vec.blank(@sizeof(usize), @alignof(usize));
var is_cm = false; var is_cm = false;
match n.body { .ContainerMembers(x) => { is_cm = true; decls = x.declarations; }, _ => {} } match n.body { .ContainerMembers(&x) => { is_cm = true; decls = x.declarations; }, _ => {} }
if !is_cm { ret; } if !is_cm { ret; }
var i: usize = 0; var i: usize = 0;
while i < decls.len { while i < decls.len {
@@ -2046,14 +2161,14 @@ fn emit_container_body(self: *Ast2Ir, ref: usize) {
if n == null { ret; } if n == null { ret; }
var is_tlb = false; var is_tlb = false;
var tlb_block: usize = 0; var tlb_block: usize = 0;
match n.body { .TopLevelBlock(x) => { is_tlb = true; tlb_block = x.block; }, _ => {} } match n.body { .TopLevelBlock(&x) => { is_tlb = true; tlb_block = x.block; }, _ => {} }
if is_tlb { if is_tlb {
if tlb_block != 0 { emit_container_body(self, tlb_block); } if tlb_block != 0 { emit_container_body(self, tlb_block); }
ret; ret;
} }
var decls = Vec.blank(@sizeof(usize), @alignof(usize)); var decls = Vec.blank(@sizeof(usize), @alignof(usize));
var is_cm = false; var is_cm = false;
match n.body { .ContainerMembers(x) => { is_cm = true; decls = x.declarations; }, _ => {} } match n.body { .ContainerMembers(&x) => { is_cm = true; decls = x.declarations; }, _ => {} }
if !is_cm { ret; } if !is_cm { ret; }
var i: usize = 0; var i: usize = 0;
while i < decls.len { while i < decls.len {
@@ -2080,7 +2195,7 @@ fn emit_container_body(self: *Ast2Ir, ref: usize) {
} }
fn is_pattern_ident(n: *Node): bool { fn is_pattern_ident(n: *Node): bool {
match n.body { .PatternIdent(x) => { ret true; }, _ => { ret false; } } match n.body { .PatternIdent(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
+2 -1
View File
@@ -202,6 +202,7 @@ fn register_builtins(self: *Attr) {
registry_add(self, make_info("", "align", .Layout, .Type, .Required, 1, 1)); registry_add(self, make_info("", "align", .Layout, .Type, .Required, 1, 1));
registry_add(self, make_info("", "volatile", .Ir, .Expr, .Required, 0, 0)); registry_add(self, make_info("", "volatile", .Ir, .Expr, .Required, 0, 0));
registry_add(self, make_info("", "atomic", .Ir, .Expr, .Required, 0, 1)); registry_add(self, make_info("", "atomic", .Ir, .Expr, .Required, 0, 1));
registry_add(self, make_info("", "export", .Ir, .Decl, .Optional, 1, 1));
} }
// ---- dump(镜像 stage1 spl_attr_dump / spl_attr_dump_id)---- // ---- dump(镜像 stage1 spl_attr_dump / spl_attr_dump_id)----
@@ -360,7 +361,7 @@ fn test_registry() {
} }
defer { drop(&at); } defer { drop(&at); }
@assert(at.registry.len == 7, "1 sentinel + 6 builtins"); @assert(at.registry.len == 8, "1 sentinel + 7 builtins");
var i = lookup(&at, ByteView.empty(), ByteView.from_slice("extern")); var i = lookup(&at, ByteView.empty(), ByteView.from_slice("extern"));
@assert(i != 0, "extern found"); @assert(i != 0, "extern found");
-29
View File
@@ -1283,7 +1283,6 @@ fn run(self: *Ir2C) {
} }
i = i + 1; i = i + 1;
} }
emit_ct_table(self);
var m = find_main(self); var m = find_main(self);
if m != 0 { if m != 0 {
var f = IrM.func(self.ir, m); var f = IrM.func(self.ir, m);
@@ -1311,34 +1310,6 @@ fn run(self: *Ir2C) {
} }
} }
// compiler function(`ct_` 前缀)回调表:供 native 端 vm_set_foreign 按名分发。
fn emit_ct_table(self: *Ir2C) {
put(self, "static const struct { const char *name; void *fn; } spl_ct_tab[] = {\n");
var n: usize = 0;
var i: usize = 1;
while i < self.ir.funcs.len {
var f = IrM.func(self.ir, i);
if f != null && !fn_is_extern(self, f) &&
ByteView.starts_with(f.name, ByteView.from_slice("ct_")) {
put(self, " {\"");
put_bv(self, f.name);
put(self, "\", (void*)f");
put_u(self, i);
put(self, "},\n");
n = n + 1;
}
i = i + 1;
}
if n == 0 { put(self, " {0, 0},\n"); }
put(self, "};\n");
put(self, "void *spl_ct_lookup(const char *name) {\n");
put(self, " unsigned long i;\n");
put(self, " for (i = 0; i < sizeof(spl_ct_tab)/sizeof(spl_ct_tab[0]); i++)\n");
put(self, " if (spl_ct_tab[i].name && strcmp(spl_ct_tab[i].name, name) == 0) return spl_ct_tab[i].fn;\n");
put(self, " return 0;\n");
put(self, "}\n");
}
fn new(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): Ir2C { fn new(ir: *Ir, ty: *TypeTable, layout: *Layout, attr: *Attr, out: *ByteBuffer): Ir2C {
ret Ir2C { ret Ir2C {
.ir = ir, .ir = ir,
+10 -12
View File
@@ -456,20 +456,20 @@ fn cg_swap(cg: *Cgen) { emit(cg, .Swap, .Void, 0); }
fn cg_gaddr(cg: *Cgen, idx: usize) { emit(cg, .Gaddr, .Void, idx); } fn cg_gaddr(cg: *Cgen, idx: usize) { emit(cg, .Gaddr, .Void, idx); }
fn cg_load_slot(cg: *Cgen, ref: usize, k: VmKind) { fn cg_load_slot(cg: *Cgen, ref: usize, k: VmKind) {
cg_laddr(cg, slot_result(&cg.frame, ref)); emit(cg, .Laddr, .Void, slot_result(&cg.frame, ref));
cg_load(cg, k); emit(cg, .Load, k, 0);
} }
fn cg_store_slot(cg: *Cgen, ref: usize, k: VmKind) { fn cg_store_slot(cg: *Cgen, ref: usize, k: VmKind) {
cg_laddr(cg, slot_result(&cg.frame, ref)); emit(cg, .Laddr, .Void, slot_result(&cg.frame, ref));
cg_swap(cg); emit(cg, .Swap, .Void, 0);
cg_store(cg, k); emit(cg, .Store, k, 0);
} }
fn cg_store_at(cg: *Cgen, addr: usize, k: VmKind) { fn cg_store_at(cg: *Cgen, addr: usize, k: VmKind) {
cg_laddr(cg, addr); emit(cg, .Laddr, .Void, addr);
cg_swap(cg); emit(cg, .Swap, .Void, 0);
cg_store(cg, k); emit(cg, .Store, k, 0);
} }
type DataLoc = struct { type DataLoc = struct {
@@ -638,6 +638,7 @@ fn cg_const(cg: *Cgen, ref: usize, n: *IrEntry) {
} }
}, },
.Int(x) => { imm = const_usize(n); }, .Int(x) => { imm = const_usize(n); },
.Any => { imm = const_usize(n); },
.Float => { .Float => {
var fv: f64 = 0.0; var fv: f64 = 0.0;
match n.body { match n.body {
@@ -915,10 +916,7 @@ fn cg_control(cg: *Cgen, ref: usize, n: *IrEntry) {
cg_load(cg, .Ptr); cg_load(cg, .Ptr);
cg_load_slot(cg, r.val, .Ptr); cg_load_slot(cg, r.val, .Ptr);
cg_push(cg, .U64, sz); cg_push(cg, .U64, sz);
var nat = Mcode.get_or_add_native(&ctx.prog, ByteView.from_slice("vm_memcpy")); emit(cg, .Memcpy, .Void, 0);
cg_push(cg, .U64, nat as usize);
emit(cg, .Ncall, .Void, 3);
emit(cg, .Drop, .Void, 0);
} }
emit(cg, .Ret, .Void, 0); emit(cg, .Ret, .Void, 0);
} else { } else {
+3 -3
View File
@@ -122,11 +122,11 @@ fn fn_end(self: *IrBuilder) {
if fx.block < self.blocks.len { target = list_at(self.blocks, fx.block); } if fx.block < self.blocks.len { target = list_at(self.blocks, fx.block); }
if target != 0 { if target != 0 {
if @enum2int(fx.slot) == @enum2int(FixKind.BrTrue) { if @enum2int(fx.slot) == @enum2int(FixKind.BrTrue) {
match e.body { .Br(b) => { b.true_label = target; e.body = .Br(b); }, _ => {} } match e.body { .Br(&b) => { b.true_label = target; }, _ => {} }
} else if @enum2int(fx.slot) == @enum2int(FixKind.BrFalse) { } else if @enum2int(fx.slot) == @enum2int(FixKind.BrFalse) {
match e.body { .Br(b) => { b.false_label = target; e.body = .Br(b); }, _ => {} } match e.body { .Br(&b) => { b.false_label = target; }, _ => {} }
} else { } else {
match e.body { .Jmp(j) => { j.label = target; e.body = .Jmp(j); }, _ => {} } match e.body { .Jmp(&j) => { j.label = target; }, _ => {} }
} }
} }
} }
+36 -27
View File
@@ -72,6 +72,7 @@ type Op = enum {
Gaddr, Gaddr,
Load, Load,
Store, Store,
Memcpy,
Ncall, Ncall,
Nlib, Nlib,
Bk, Bk,
@@ -177,6 +178,7 @@ fn op_name(op: Op): []u8 {
.Gaddr => { ret "gaddr"; }, .Gaddr => { ret "gaddr"; },
.Load => { ret "load"; }, .Load => { ret "load"; },
.Store => { ret "store"; }, .Store => { ret "store"; },
.Memcpy => { ret "memcpy"; },
.Ncall => { ret "ncall"; }, .Ncall => { ret "ncall"; },
.Nlib => { ret "nlib"; }, .Nlib => { ret "nlib"; },
.Bk => { ret "breakpoint"; }, .Bk => { ret "breakpoint"; },
@@ -570,33 +572,34 @@ fn encode(self: *Prog, out: *ByteBuffer): Status {
// 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。 // 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。
var total: usize = 48; var total: usize = 48;
var fi: usize = 0; var fi: usize = 0;
var func_base = self.funcs.data as *VmFunc;
var nat_base = self.natives.data as *VmNative;
var str_base = self.strtab.data as *ByteView;
var gd_base = self.gdata.data as *ByteBuffer;
while fi < self.funcs.len { while fi < self.funcs.len {
var f = func_at(self, fi); var f = func_base + fi;
if f != null { var nlen = f.name.len + 1;
var nlen = f.name.len + 1; total = total + 8 + align8(nlen) + 32;
total = total + 8 + align8(nlen) + 32;
}
fi = fi + 1; fi = fi + 1;
} }
total = total + self.insns.len * 12; total = total + self.insns.len * 12;
fi = 0; fi = 0;
while fi < self.natives.len { while fi < self.natives.len {
var n = native_at(self, fi); var n = nat_base + fi;
if n != null { var nlen = n.name.len + 1;
var nlen = n.name.len + 1; total = total + 8 + align8(nlen) + 8;
total = total + 8 + align8(nlen) + 8;
}
fi = fi + 1; fi = fi + 1;
} }
fi = 0; fi = 0;
while fi < self.strtab.len { while fi < self.strtab.len {
total = total + 8 + align8(str_at(self, fi).len); var s = str_base + fi;
total = total + 8 + align8(s.len);
fi = fi + 1; fi = fi + 1;
} }
fi = 1; fi = 1;
while fi < self.gdata.len { while fi < self.gdata.len {
var e = gdata_at(self, fi); var e = gd_base + fi;
if e != null { total = total + 8 + align8(e.storage.len); } total = total + 8 + align8(e.storage.len);
fi = fi + 1; fi = fi + 1;
} }
match ByteBuffer.reserve(out, total) { .Ok => {}, .Err(error) => {} } match ByteBuffer.reserve(out, total) { .Ok => {}, .Err(error) => {} }
@@ -620,8 +623,7 @@ fn encode(self: *Prog, out: *ByteBuffer): Status {
var i: usize = 0; var i: usize = 0;
while i < nfuncs { while i < nfuncs {
var f = func_at(self, i); var f = func_base + i;
if f == null { ret .Err(make(.Io)); }
if !put_name_field(out, f.name) { ret .Err(make(.Io)); } if !put_name_field(out, f.name) { ret .Err(make(.Io)); }
if !put_u64(out, f.idx_of_strtab) { ret .Err(make(.Io)); } if !put_u64(out, f.idx_of_strtab) { ret .Err(make(.Io)); }
if !put_u64(out, f.nargs) { ret .Err(make(.Io)); } if !put_u64(out, f.nargs) { ret .Err(make(.Io)); }
@@ -631,20 +633,23 @@ fn encode(self: *Prog, out: *ByteBuffer): Status {
} }
i = 0; i = 0;
var ins_base = self.insns.data as *VmIns;
var out_base = out.storage.data;
var out_len = out.storage.len;
while i < ninsns { while i < ninsns {
var ins = ins_at(self, i); var p = ins_base + i;
var d = out.storage.data + out.storage.len; var d = out_base + out_len;
(d as *u16).* = @enum2int(ins.opcode) as u16; (d as *u16).* = @enum2int(p.opcode) as u16;
((d + 2) as *u16).* = @enum2int(ins.ty) as u16; ((d + 2) as *u16).* = @enum2int(p.ty) as u16;
((d + 4) as *u64).* = ins.imm as u64; ((d + 4) as *u64).* = p.imm as u64;
out.storage.len = out.storage.len + 12; out_len = out_len + 12;
i = i + 1; i = i + 1;
} }
out.storage.len = out_len;
i = 0; i = 0;
while i < nnatives { while i < nnatives {
var n = native_at(self, i); var n = nat_base + i;
if n == null { ret .Err(make(.Io)); }
if !put_name_field(out, n.name) { ret .Err(make(.Io)); } if !put_name_field(out, n.name) { ret .Err(make(.Io)); }
if !put_u64(out, n.idx_of_strtab) { ret .Err(make(.Io)); } if !put_u64(out, n.idx_of_strtab) { ret .Err(make(.Io)); }
i = i + 1; i = i + 1;
@@ -652,17 +657,16 @@ fn encode(self: *Prog, out: *ByteBuffer): Status {
i = 0; i = 0;
while i < nstrs { while i < nstrs {
var s = str_at(self, i); var s = str_base + i;
if !put_u64(out, s.len) { ret .Err(make(.Io)); } if !put_u64(out, s.len) { ret .Err(make(.Io)); }
if !put_view(out, s) { ret .Err(make(.Io)); } if !put_view(out, s.*) { ret .Err(make(.Io)); }
if !put_zeros(out, align8(s.len) - s.len) { ret .Err(make(.Io)); } if !put_zeros(out, align8(s.len) - s.len) { ret .Err(make(.Io)); }
i = i + 1; i = i + 1;
} }
i = 1; i = 1;
while i < self.gdata.len { while i < self.gdata.len {
var e = gdata_at(self, i); var e = gd_base + i;
if e == null { ret .Err(make(.Io)); }
var dsize = e.storage.len; var dsize = e.storage.len;
if !put_u64(out, dsize) { ret .Err(make(.Io)); } if !put_u64(out, dsize) { ret .Err(make(.Io)); }
if !put_view(out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); } if !put_view(out, ByteView.from_slice(ByteBuffer.as_slice(e.*))) { ret .Err(make(.Io)); }
@@ -693,6 +697,11 @@ fn store(self: *Prog, path: ByteView): Status {
ret .Ok; ret .Ok;
} }
// 序列化到内存缓冲(供内嵌 VM 直接装载)。
fn serialize(self: *Prog, out: *ByteBuffer): Status {
ret encode(self, out);
}
fn ignore_ptr(p: *any) {} fn ignore_ptr(p: *any) {}
fn ignore_usize(v: usize) {} fn ignore_usize(v: usize) {}
+66 -23
View File
@@ -460,9 +460,8 @@ fn parse_pattern_atom(self: *Parser): usize {
var sub = parse_pattern(self); var sub = parse_pattern(self);
var pn = Ast.node(self.ast, ref); var pn = Ast.node(self.ast, ref);
match pn.body { match pn.body {
.PatternDot(pd) => { .PatternDot(&pd) => {
pd.sub_pattern = sub; pd.sub_pattern = sub;
pn.body = .PatternDot(pd);
}, },
_ => {}, _ => {},
} }
@@ -508,6 +507,24 @@ fn parse_pattern_atom(self: *Parser): usize {
} }
ret ref; ret ref;
}, },
.And => {
// `&name`:解包左值引用绑定。仅允许作用于绑定名。
advance(self);
var nx = peek(self);
if nx == null {
parse_error(self, nx, "expected binding name after '&'");
ret 0;
}
match nx.kind {
.Ident => {},
_ => {
parse_error(self, nx, "expected binding name after '&'");
ret 0;
},
}
var inner = parse_pattern_atom(self);
ret new_node(self, .PatternRef(.{ .pat = inner }), t);
},
_ => {}, _ => {},
} }
}, },
@@ -547,7 +564,7 @@ fn parse_pattern(self: *Parser): usize {
// ---- 声明 ---- // ---- 声明 ----
fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool) { fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool, bang_only: bool) {
while !self.failed { while !self.failed {
var t = peek(self); var t = peek(self);
if t == null { ret; } if t == null { ret; }
@@ -556,14 +573,21 @@ fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool) {
else if kind_is_punct(t.kind, .Sharp) { is_at = false; } else if kind_is_punct(t.kind, .Sharp) { is_at = false; }
else { ret; } else { ret; }
if !allow_at && is_at { ret; } if !allow_at && is_at { ret; }
advance(self); if bang_only {
if is_external { // 仅消费 `#!`/`@!` 形式的当前层 tag;遇到普通 `#name` 即停。
t = peek(self); var save = self.pos;
if t == null || !kind_is_punct(t.kind, .Not) {
parse_error(self, t, "expected '!' in external tag");
ret;
}
advance(self); advance(self);
var nt = peek(self);
var has_bang = nt != null && kind_is_punct(nt.kind, .Not);
self.pos = save;
if !has_bang { ret; }
}
advance(self);
t = peek(self);
var ext_here = is_external;
if t != null && kind_is_punct(t.kind, .Not) {
advance(self);
ext_here = true;
} }
t = peek(self); t = peek(self);
if t == null { ret; } if t == null { ret; }
@@ -572,14 +596,14 @@ fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool) {
// stage1 先分配 tag 节点,再解析参数。 // stage1 先分配 tag 节点,再解析参数。
var body: Body = .TagItem(.{ var body: Body = .TagItem(.{
.is_at = is_at, .is_at = is_at,
.is_external = is_external, .is_external = ext_here,
.name = t.text, .name = t.text,
.args = ref_vec(), .args = ref_vec(),
}); });
if is_external { if ext_here {
body = .ExternalTagItem(.{ body = .ExternalTagItem(.{
.is_at = is_at, .is_at = is_at,
.is_external = is_external, .is_external = ext_here,
.name = t.text, .name = t.text,
.args = ref_vec(), .args = ref_vec(),
}); });
@@ -608,7 +632,13 @@ fn parse_tag_list(self: *Parser, out: *Vec, is_external: bool, allow_at: bool) {
fn parse_param_decl_impl(self: *Parser): usize { fn parse_param_decl_impl(self: *Parser): usize {
var attrs = ref_vec(); var attrs = ref_vec();
parse_tag_list(self, &attrs, false, true); var is_comptime = false;
var c0 = peek(self);
if c0 != null && kind_is_keyword(c0.kind, .Comptime) {
advance(self);
is_comptime = true;
}
parse_tag_list(self, &attrs, false, true, false);
var name = peek(self); var name = peek(self);
if name == null { ret 0; } if name == null { ret 0; }
var ok = false; var ok = false;
@@ -620,10 +650,10 @@ fn parse_param_decl_impl(self: *Parser): usize {
if !ok { ret 0; } if !ok { ret 0; }
advance(self); advance(self);
if !expect_punct(self, .Colon, "':' in parameter declaration") { ret 0; } if !expect_punct(self, .Colon, "':' in parameter declaration") { ret 0; }
parse_tag_list(self, &attrs, false, false); parse_tag_list(self, &attrs, false, false, false);
var ty = parse_type_expr(self); var ty = parse_type_expr(self);
ret new_node(self, ret new_node(self,
.ParamDecl(.{ .attr_list = attrs, .name = name.text, .type_expr = ty }), .ParamDecl(.{ .attr_list = attrs, .is_comptime = is_comptime, .name = name.text, .type_expr = ty }),
name); name);
} }
@@ -651,11 +681,24 @@ fn parse_param_list(self: *Parser): Vec {
if at_punct(self, .Comma) { advance(self); continue; } if at_punct(self, .Comma) { advance(self); continue; }
break; break;
}, },
.Keyword(k) => {
if @enum2int(k) == @enum2int(Keyword.Comptime) {
var pd2 = parse_param_decl_impl(self);
if pd2 != 0 {
match Vec.push(&out, &pd2 as *u8) { .Ok => {}, .Err(e) => { ret out; } }
}
if at_punct(self, .Comma) { advance(self); continue; }
break;
}
parse_error(self, t, "unexpected token in parameter list");
break;
},
.Punct(p) => { .Punct(p) => {
if @enum2int(p) == @enum2int(Punct.Ellipsis) { if @enum2int(p) == @enum2int(Punct.Ellipsis) {
advance(self); advance(self);
var pd = new_node(self, .ParamDecl(.{ var pd = new_node(self, .ParamDecl(.{
.attr_list = ref_vec(), .attr_list = ref_vec(),
.is_comptime = false,
.name = ByteView.empty(), .name = ByteView.empty(),
.type_expr = 0, .type_expr = 0,
}), t); }), t);
@@ -825,7 +868,7 @@ fn parse_member_decl(self: *Parser, tags: Vec): usize {
var t = peek(self); var t = peek(self);
if t != null && kind_is_punct(t.kind, .Colon) { if t != null && kind_is_punct(t.kind, .Colon) {
advance(self); advance(self);
parse_tag_list(self, &tags, false, false); parse_tag_list(self, &tags, false, false, false);
te = parse_type_expr(self); te = parse_type_expr(self);
t = peek(self); t = peek(self);
if t != null && kind_is_punct(t.kind, .Assign) { if t != null && kind_is_punct(t.kind, .Assign) {
@@ -864,7 +907,7 @@ fn parse_comptime_decl(self: *Parser): usize {
fn parse_container_declaration(self: *Parser): usize { fn parse_container_declaration(self: *Parser): usize {
var tags = ref_vec(); var tags = ref_vec();
parse_tag_list(self, &tags, false, false); parse_tag_list(self, &tags, false, false, false);
var t = peek(self); var t = peek(self);
if t == null { ret 0; } if t == null { ret 0; }
match t.kind { match t.kind {
@@ -1282,9 +1325,9 @@ fn parse_prefix(self: *Parser): usize {
if ref == 0 { ret 0; } if ref == 0 { ret 0; }
var n = Ast.node(self.ast, ref); var n = Ast.node(self.ast, ref);
match n.body { match n.body {
.ExprWhile(w) => { w.label = label; n.body = .ExprWhile(w); }, .ExprWhile(&w) => { w.label = label; },
.ExprLoop(l) => { l.label = label; n.body = .ExprLoop(l); }, .ExprLoop(&l) => { l.label = label; },
.ExprFor(f) => { f.label = label; n.body = .ExprFor(f); }, .ExprFor(&f) => { f.label = label; },
_ => {}, _ => {},
} }
ret ref; ret ref;
@@ -2021,7 +2064,7 @@ fn parse_statement(self: *Parser): usize {
@enum2int(k) == @enum2int(Keyword.Const) || @enum2int(k) == @enum2int(Keyword.Const) ||
@enum2int(k) == @enum2int(Keyword.Type) { @enum2int(k) == @enum2int(Keyword.Type) {
var tags = ref_vec(); var tags = ref_vec();
parse_tag_list(self, &tags, false, false); parse_tag_list(self, &tags, false, false, false);
var decl: usize = 0; var decl: usize = 0;
if @enum2int(k) == @enum2int(Keyword.Var) { if @enum2int(k) == @enum2int(Keyword.Var) {
decl = parse_var_const_decl(self, tags, false); decl = parse_var_const_decl(self, tags, false);
@@ -2188,7 +2231,7 @@ fn parse(self: *Parser) {
var t2 = peek(self); var t2 = peek(self);
self.pos = save; self.pos = save;
if t2 != null && kind_is_punct(t2.kind, .Not) { if t2 != null && kind_is_punct(t2.kind, .Not) {
parse_tag_list(self, &external_tags, true, true); parse_tag_list(self, &external_tags, true, true, true);
continue; continue;
} }
} }
+98 -89
View File
@@ -337,13 +337,13 @@ fn resolve_attr_item(self: *Sema, a: *Node): usize {
fn resolve_attrs(self: *Sema, n: *Node) { fn resolve_attrs(self: *Sema, n: *Node) {
if n.attrs.len != 0 { ret; } if n.attrs.len != 0 { ret; }
match n.body { match n.body {
.FnDecl(x) => { node_attr_raw(self, n, x.tag_list); }, .FnDecl(&x) => { node_attr_raw(self, n, x.tag_list); },
.VarDecl(x) => { node_attr_raw(self, n, x.attr_list); }, .VarDecl(&x) => { node_attr_raw(self, n, x.attr_list); },
.ConstDecl(x) => { node_attr_raw(self, n, x.attr_list); }, .ConstDecl(&x) => { node_attr_raw(self, n, x.attr_list); },
.TypeDecl(x) => { node_attr_raw(self, n, x.attr_list); }, .TypeDecl(&x) => { node_attr_raw(self, n, x.attr_list); },
.MemberDecl(x) => { node_attr_raw(self, n, x.attr_list); }, .MemberDecl(&x) => { node_attr_raw(self, n, x.attr_list); },
.ParamDecl(x) => { node_attr_raw(self, n, x.attr_list); }, .ParamDecl(&x) => { node_attr_raw(self, n, x.attr_list); },
.TopLevelBlock(x) => { node_attr_raw(self, n, x.tag_list); }, .TopLevelBlock(&x) => { node_attr_raw(self, n, x.tag_list); },
_ => {}, _ => {},
} }
} }
@@ -353,7 +353,7 @@ fn resolve_attrs(self: *Sema, n: *Node) {
fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize { fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize {
var kind_name = ByteView.empty(); var kind_name = ByteView.empty();
match te.body { match te.body {
.TypeAggregate(x) => { kind_name = x.kind_name; }, .TypeAggregate(&x) => { kind_name = x.kind_name; },
_ => {}, _ => {},
} }
var lk: LangKind = .Struct; var lk: LangKind = .Struct;
@@ -389,7 +389,7 @@ fn build_aggregate(self: *Sema, te: *Node, owner_def_id: usize): usize {
var mlist = ref_vec(); var mlist = ref_vec();
match te.body { match te.body {
.TypeAggregate(x) => { mlist = x.members; }, .TypeAggregate(&x) => { mlist = x.members; },
_ => {}, _ => {},
} }
var i: usize = 0; var i: usize = 0;
@@ -554,41 +554,41 @@ fn container_var_method(self: *Sema, pat_ref: usize, methods: *Vec) {
} }
fn is_pattern_ident(n: *Node): bool { fn is_pattern_ident(n: *Node): bool {
match n.body { .PatternIdent(x) => { ret true; }, _ => { ret false; } } match n.body { .PatternIdent(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_type_aggregate(n: *Node): bool { fn is_type_aggregate(n: *Node): bool {
match n.body { .TypeAggregate(x) => { ret true; }, _ => { ret false; } } match n.body { .TypeAggregate(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_param_decl(n: *Node): bool { fn is_param_decl(n: *Node): bool {
match n.body { .ParamDecl(x) => { ret true; }, _ => { ret false; } } match n.body { .ParamDecl(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_type_decl(n: *Node): bool { fn is_type_decl(n: *Node): bool {
match n.body { .TypeDecl(x) => { ret true; }, _ => { ret false; } } match n.body { .TypeDecl(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_pattern_field(n: *Node): bool { fn is_pattern_field(n: *Node): bool {
match n.body { .PatternField(x) => { ret true; }, _ => { ret false; } } match n.body { .PatternField(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_expr_string_lit(n: *Node): bool { fn is_expr_string_lit(n: *Node): bool {
match n.body { .ExprStringLit(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprStringLit(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_expr_ident(n: *Node): bool { fn is_expr_ident(n: *Node): bool {
match n.body { .ExprIdent(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprIdent(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn is_expr_int_lit(n: *Node): bool { fn is_expr_int_lit(n: *Node): bool {
match n.body { .ExprIntLit(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprIntLit(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
fn pattern_name(pat: *Node): ByteView { fn pattern_name(pat: *Node): ByteView {
match pat.body { match pat.body {
.PatternIdent(x) => { ret x.name; }, .PatternIdent(&x) => { ret x.name; },
_ => { ret ByteView.empty(); }, _ => { ret ByteView.empty(); },
} }
} }
@@ -774,7 +774,7 @@ fn infer_fn_signature(self: *Sema, n: *Node): usize {
var pd = node(self, list_at(params_list, i)); var pd = node(self, list_at(params_list, i));
if pd != null && is_param_decl(pd) { if pd != null && is_param_decl(pd) {
var tref: usize = 0; var tref: usize = 0;
match pd.body { .ParamDecl(x) => { tref = x.type_expr; }, _ => {} } match pd.body { .ParamDecl(&x) => { tref = x.type_expr; }, _ => {} }
if tref != 0 { if tref != 0 {
push_u(&params, infer(self, tref)); push_u(&params, infer(self, tref));
} else { } else {
@@ -951,7 +951,7 @@ fn infer_type_context(self: *Sema, ref: usize): usize {
var n = node(self, ref); var n = node(self, ref);
if n == null { ret 0; } if n == null { ret 0; }
match n.body { match n.body {
.ExprIdent(x) => { .ExprIdent(&x) => {
var builtin = LangType.lookup_builtin(&self.types, x.name); var builtin = LangType.lookup_builtin(&self.types, x.name);
if builtin != 0 { if builtin != 0 {
n.resolved_lang_tid = builtin; n.resolved_lang_tid = builtin;
@@ -971,7 +971,7 @@ fn infer_type_context(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprField(x) => { .ExprField(&x) => {
var owner_id = infer_type_context(self, x.obj); var owner_id = infer_type_context(self, x.obj);
var owner = lang_of(self, owner_id); var owner = lang_of(self, owner_id);
if owner == null { ret 0; } if owner == null { ret 0; }
@@ -990,7 +990,7 @@ fn infer_type_context(self: *Sema, ref: usize): usize {
diag_name(self, n.span, .TypeMismatch, "not a type member `", x.name); diag_name(self, n.span, .TypeMismatch, "not a type member `", x.name);
ret 0; ret 0;
}, },
.ExprUnary(x) => { .ExprUnary(&x) => {
if punct_is(x.op, .Mul) { if punct_is(x.op, .Mul) {
var pointee = infer_type_context(self, x.operand); var pointee = infer_type_context(self, x.operand);
if pointee == 0 { ret 0; } if pointee == 0 { ret 0; }
@@ -1000,7 +1000,7 @@ fn infer_type_context(self: *Sema, ref: usize): usize {
} }
ret 0; ret 0;
}, },
.ExprTuple(x) => { .ExprTuple(&x) => {
var elems = ref_vec(); var elems = ref_vec();
var i: usize = 0; var i: usize = 0;
while i < x.items.len { while i < x.items.len {
@@ -1013,7 +1013,7 @@ fn infer_type_context(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
}, },
.ExprComptimeCall(x) => { .ExprComptimeCall(&x) => {
var r = infer(self, ref); var r = infer(self, ref);
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
@@ -1160,7 +1160,7 @@ fn intrin_call(self: *Sema, n: *Node, in: Intrin, args: Vec): usize {
if fnode == null { ret 0; } if fnode == null { ret 0; }
if is_expr_ident(fnode) { if is_expr_ident(fnode) {
var fname = ByteView.empty(); var fname = ByteView.empty();
match fnode.body { .ExprIdent(x) => { fname = x.name; }, _ => {} } match fnode.body { .ExprIdent(&x) => { fname = x.name; }, _ => {} }
var idx: usize = 0; var idx: usize = 0;
if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, fname, &idx) { if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, fname, &idx) {
diag_name(self, n.span, .NoField, "no field `", fname); diag_name(self, n.span, .NoField, "no field `", fname);
@@ -1268,6 +1268,15 @@ fn bind_pattern(self: *Sema, pat_ref: usize, matched_tid: usize) {
pat.resolved_lang_tid = matched_tid; pat.resolved_lang_tid = matched_tid;
}, },
.PatternUnderscore => {}, .PatternUnderscore => {},
.PatternRef(x) => {
if matched_tid == 0 {
diag(self, pat.span, .TypeMismatch, "ref pattern requires a concrete type");
ret;
}
var ptr = LangType.make_ptr(&self.types, matched_tid);
bind_pattern(self, x.pat, ptr);
pat.resolved_lang_tid = ptr;
},
.PatternList(x) => { .PatternList(x) => {
var i: usize = 0; var i: usize = 0;
while i < x.items.len { while i < x.items.len {
@@ -1672,13 +1681,13 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
var result: usize = 0; var result: usize = 0;
match n.body { match n.body {
.ExprUnary(x) => { .ExprUnary(&x) => {
if !(punct_is(x.op, .And) || punct_is(x.op, .Mul)) { if !(punct_is(x.op, .And) || punct_is(x.op, .Mul)) {
handled = true; handled = true;
result = coerce(self, x.operand, expected); result = coerce(self, x.operand, expected);
} }
}, },
.ExprBinary(x) => { .ExprBinary(&x) => {
handled = true; handled = true;
var op = x.op; var op = x.op;
if punct_is(op, .Assign) || is_assign_arith(op) { if punct_is(op, .Assign) || is_assign_arith(op) {
@@ -1735,7 +1744,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
result = expected; result = expected;
} }
}, },
.ExprArrayLit(x) => { .ExprArrayLit(&x) => {
var en = lang_of(self, expected); var en = lang_of(self, expected);
if en != null && (kind_is(self, expected, .Array) || kind_is(self, expected, .Slice)) { if en != null && (kind_is(self, expected, .Array) || kind_is(self, expected, .Slice)) {
handled = true; handled = true;
@@ -1748,7 +1757,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
result = expected; result = expected;
} }
}, },
.ExprTuple(x) => { .ExprTuple(&x) => {
var en = lang_of(self, expected); var en = lang_of(self, expected);
if en != null && kind_is(self, expected, .Tuple) { if en != null && kind_is(self, expected, .Tuple) {
handled = true; handled = true;
@@ -1766,7 +1775,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
result = expected; result = expected;
} }
}, },
.ExprAggregateLit(x) => { .ExprAggregateLit(&x) => {
var en = lang_of(self, expected); var en = lang_of(self, expected);
if en != null && (kind_is(self, expected, .Struct) || kind_is(self, expected, .Union) || if en != null && (kind_is(self, expected, .Struct) || kind_is(self, expected, .Union) ||
kind_is(self, expected, .Enum) || kind_is(self, expected, .Slice)) { kind_is(self, expected, .Enum) || kind_is(self, expected, .Slice)) {
@@ -1797,7 +1806,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
} }
var iname = ByteView.empty(); var iname = ByteView.empty();
var iexpr: usize = 0; var iexpr: usize = 0;
match item.body { .StructInitItem(si) => { iname = si.name; iexpr = si.expr; }, _ => {} } match item.body { .StructInitItem(&si) => { iname = si.name; iexpr = si.expr; }, _ => {} }
var idx: usize = 0; var idx: usize = 0;
if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, iname, &idx) { if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, iname, &idx) {
diag_name(self, item.span, .NoField, "no variant `", iname); diag_name(self, item.span, .NoField, "no variant `", iname);
@@ -1816,7 +1825,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
if item != null && kind_is_body_struct_init(item) { if item != null && kind_is_body_struct_init(item) {
var iname = ByteView.empty(); var iname = ByteView.empty();
var iexpr: usize = 0; var iexpr: usize = 0;
match item.body { .StructInitItem(si) => { iname = si.name; iexpr = si.expr; }, _ => {} } match item.body { .StructInitItem(&si) => { iname = si.name; iexpr = si.expr; }, _ => {} }
var idx: usize = 0; var idx: usize = 0;
if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, iname, &idx) { if !TypeTable.agg_member_idx(&self.types.ir, agg_ir, iname, &idx) {
diag_name(self, item.span, .NoField, "no field `", iname); diag_name(self, item.span, .NoField, "no field `", iname);
@@ -1836,7 +1845,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
} }
} }
}, },
.ExprIf(x) => { .ExprIf(&x) => {
handled = true; handled = true;
var bt = make_bool(self); var bt = make_bool(self);
ignore_usize(coerce(self, x.cond, bt)); ignore_usize(coerce(self, x.cond, bt));
@@ -1844,7 +1853,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
if x.else_branch != 0 { ignore_usize(coerce(self, x.else_branch, expected)); } if x.else_branch != 0 { ignore_usize(coerce(self, x.else_branch, expected)); }
result = expected; result = expected;
}, },
.ExprLoop(x) => { .ExprLoop(&x) => {
handled = true; handled = true;
var saved = self.current_loop_break_tid; var saved = self.current_loop_break_tid;
self.current_loop_break_tid = expected; self.current_loop_break_tid = expected;
@@ -1852,7 +1861,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
self.current_loop_break_tid = saved; self.current_loop_break_tid = saved;
result = expected; result = expected;
}, },
.ExprBlock(x) => { .ExprBlock(&x) => {
ret block_body(self, n, expected); ret block_body(self, n, expected);
}, },
_ => {}, _ => {},
@@ -1872,7 +1881,7 @@ fn coerce(self: *Sema, ref: usize, expected: usize): usize {
if is_expr_int_lit(n) && int_bits(self, expected) != 0 { if is_expr_int_lit(n) && int_bits(self, expected) != 0 {
var fits = true; var fits = true;
match n.body { match n.body {
.ExprIntLit(v) => { .ExprIntLit(&v) => {
if !LangType.int_fits(&self.types, expected, v.value) { fits = false; } if !LangType.int_fits(&self.types, expected, v.value) { fits = false; }
}, },
_ => {}, _ => {},
@@ -1907,7 +1916,7 @@ fn elem_of_lang(e: LangEntry): usize {
} }
fn kind_is_body_struct_init(n: *Node): bool { fn kind_is_body_struct_init(n: *Node): bool {
match n.body { .StructInitItem(x) => { ret true; }, _ => { ret false; } } match n.body { .StructInitItem(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -1920,28 +1929,28 @@ fn infer(self: *Sema, ref: usize): usize {
resolve_attrs(self, n); resolve_attrs(self, n);
match n.body { match n.body {
.ExprIntLit(x) => { .ExprIntLit(&x) => {
var t = LangType.make_int(&self.types, 0, true); var t = LangType.make_int(&self.types, 0, true);
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprFloatLit(x) => { .ExprFloatLit(&x) => {
var t = LangType.make_float(&self.types, 0); var t = LangType.make_float(&self.types, 0);
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprCharLit(x) => { .ExprCharLit(&x) => {
var t = LangType.make_int(&self.types, 8, false); var t = LangType.make_int(&self.types, 8, false);
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprStringLit(x) => { .ExprStringLit(&x) => {
var u8t = LangType.make_int(&self.types, 8, false); var u8t = LangType.make_int(&self.types, 8, false);
var s = LangType.make_slice(&self.types, u8t); var s = LangType.make_slice(&self.types, u8t);
n.resolved_lang_tid = s; n.resolved_lang_tid = s;
ret s; ret s;
}, },
.ExprBoolLit(x) => { .ExprBoolLit(&x) => {
var t = make_bool(self); var t = make_bool(self);
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
@@ -1957,7 +1966,7 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprIdent(x) => { .ExprIdent(&x) => {
var sym = Symbol { .name = ByteView.empty(), .kind = .Error, .node = 0 }; var sym = Symbol { .name = ByteView.empty(), .kind = .Error, .node = 0 };
if !Scope.find(&self.scope, x.name, &sym) { if !Scope.find(&self.scope, x.name, &sym) {
diag_name(self, n.span, .UndefinedSymbol, "undefined identifier `", x.name); diag_name(self, n.span, .UndefinedSymbol, "undefined identifier `", x.name);
@@ -1972,7 +1981,7 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprUnary(x) => { .ExprUnary(&x) => {
var op = infer(self, x.operand); var op = infer(self, x.operand);
if op == 0 { ret 0; } if op == 0 { ret 0; }
var tn = lang_of(self, op); var tn = lang_of(self, op);
@@ -2023,25 +2032,25 @@ fn infer(self: *Sema, ref: usize): usize {
} }
ret 0; ret 0;
}, },
.ExprBinary(x) => { .ExprBinary(&x) => {
ret infer_binary(self, n, x.op, x.left, x.right); ret infer_binary(self, n, x.op, x.left, x.right);
}, },
.ExprCall(x) => { .ExprCall(&x) => {
ret infer_call(self, n, x.callee, x.args); ret infer_call(self, n, x.callee, x.args);
}, },
.ExprField(x) => { .ExprField(&x) => {
ret infer_field(self, n, x.obj, x.name); ret infer_field(self, n, x.obj, x.name);
}, },
.ExprIndex(x) => { .ExprIndex(&x) => {
ret infer_index(self, n, x.obj, x.index); ret infer_index(self, n, x.obj, x.index);
}, },
.ExprSlice(x) => { .ExprSlice(&x) => {
ret infer_slice(self, n, x.obj, x.begin, x.end); ret infer_slice(self, n, x.obj, x.begin, x.end);
}, },
.ExprCast(x) => { .ExprCast(&x) => {
ret infer_cast(self, n, x.expr, x.type_expr); ret infer_cast(self, n, x.expr, x.type_expr);
}, },
.ExprTuple(x) => { .ExprTuple(&x) => {
var es = ref_vec(); var es = ref_vec();
var i: usize = 0; var i: usize = 0;
while i < x.items.len { while i < x.items.len {
@@ -2052,13 +2061,13 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprArrayLit(x) => { .ExprArrayLit(&x) => {
ret infer_array(self, n, x.elem_type, x.has_len, x.len, x.is_underscore_len, x.elems); ret infer_array(self, n, x.elem_type, x.has_len, x.len, x.is_underscore_len, x.elems);
}, },
.ExprAggregateLit(x) => { .ExprAggregateLit(&x) => {
ret infer_aggregate(self, n, x.name, x.fields); ret infer_aggregate(self, n, x.name, x.fields);
}, },
.ExprComptimeCall(x) => { .ExprComptimeCall(&x) => {
if ByteView.eq(x.name, ByteView.from_slice("import")) { if ByteView.eq(x.name, ByteView.from_slice("import")) {
var t = sema_import(self, n, x.args); var t = sema_import(self, n, x.args);
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
@@ -2081,10 +2090,10 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.ExprBlock(x) => { .ExprBlock(&x) => {
ret block_body(self, n, 0); ret block_body(self, n, 0);
}, },
.ExprIf(x) => { .ExprIf(&x) => {
var bt = make_bool(self); var bt = make_bool(self);
ignore_usize(coerce(self, x.cond, bt)); ignore_usize(coerce(self, x.cond, bt));
var then_t = if x.then_block != 0 { infer(self, x.then_block) } else { 0 }; var then_t = if x.then_block != 0 { infer(self, x.then_block) } else { 0 };
@@ -2100,7 +2109,7 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = result; n.resolved_lang_tid = result;
ret result; ret result;
}, },
.ExprIfvar(x) => { .ExprIfvar(&x) => {
if x.var_decl == 0 { ret 0; } if x.var_decl == 0 { ret 0; }
var vd = node(self, x.var_decl); var vd = node(self, x.var_decl);
if vd == null { ret 0; } if vd == null { ret 0; }
@@ -2111,7 +2120,7 @@ fn infer(self: *Sema, ref: usize): usize {
if x.else_branch != 0 { ignore_usize(infer(self, x.else_branch)); } if x.else_branch != 0 { ignore_usize(infer(self, x.else_branch)); }
ret 0; ret 0;
}, },
.ExprWhile(x) => { .ExprWhile(&x) => {
push_view(&self.label_stack, label_name(self, x.label)); push_view(&self.label_stack, label_name(self, x.label));
var bt = make_bool(self); var bt = make_bool(self);
ignore_usize(coerce(self, x.cond, bt)); ignore_usize(coerce(self, x.cond, bt));
@@ -2120,16 +2129,16 @@ fn infer(self: *Sema, ref: usize): usize {
pop_label(self); pop_label(self);
ret 0; ret 0;
}, },
.ExprLoop(x) => { .ExprLoop(&x) => {
push_view(&self.label_stack, label_name(self, x.label)); push_view(&self.label_stack, label_name(self, x.label));
if x.body != 0 { ignore_usize(infer(self, x.body)); } if x.body != 0 { ignore_usize(infer(self, x.body)); }
pop_label(self); pop_label(self);
ret 0; ret 0;
}, },
.ExprFor(x) => { .ExprFor(&x) => {
ret infer_for(self, n, x.label, x.iter_exprs, x.pattern, x.body, x.else_branch); ret infer_for(self, n, x.label, x.iter_exprs, x.pattern, x.body, x.else_branch);
}, },
.ExprMatch(x) => { .ExprMatch(&x) => {
var matched = infer(self, x.matched_expr); var matched = infer(self, x.matched_expr);
var i: usize = 0; var i: usize = 0;
while i < x.arms.len { while i < x.arms.len {
@@ -2153,7 +2162,7 @@ fn infer(self: *Sema, ref: usize): usize {
} }
ret 0; ret 0;
}, },
.ExprFnType(x) => { .ExprFnType(&x) => {
var ps = ref_vec(); var ps = ref_vec();
var i: usize = 0; var i: usize = 0;
while i < x.params.len { while i < x.params.len {
@@ -2165,7 +2174,7 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = fn_lang; n.resolved_lang_tid = fn_lang;
ret fn_lang; ret fn_lang;
}, },
.TypePath(x) => { .TypePath(&x) => {
var b = LangType.lookup_builtin(&self.types, x.name); var b = LangType.lookup_builtin(&self.types, x.name);
if b != 0 { if b != 0 {
n.resolved_lang_tid = b; n.resolved_lang_tid = b;
@@ -2180,13 +2189,13 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.TypePointer(x) => { .TypePointer(&x) => {
var p = infer(self, x.pointee); var p = infer(self, x.pointee);
var r = LangType.make_ptr(&self.types, p); var r = LangType.make_ptr(&self.types, p);
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
}, },
.TypeArray(x) => { .TypeArray(&x) => {
var e = infer(self, x.elem_type); var e = infer(self, x.elem_type);
var len: usize = 0; var len: usize = 0;
if x.has_len { len = x.len as usize; } if x.has_len { len = x.len as usize; }
@@ -2194,13 +2203,13 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
}, },
.TypeSlice(x) => { .TypeSlice(&x) => {
var e = infer(self, x.elem_type); var e = infer(self, x.elem_type);
var r = LangType.make_slice(&self.types, e); var r = LangType.make_slice(&self.types, e);
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
}, },
.TypeFn(x) => { .TypeFn(&x) => {
var ps = ref_vec(); var ps = ref_vec();
var i: usize = 0; var i: usize = 0;
while i < x.params.len { while i < x.params.len {
@@ -2212,7 +2221,7 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = r; n.resolved_lang_tid = r;
ret r; ret r;
}, },
.TypeParen(x) => { .TypeParen(&x) => {
if x.types.len == 0 { if x.types.len == 0 {
var u = make_unit(self); var u = make_unit(self);
n.resolved_lang_tid = u; n.resolved_lang_tid = u;
@@ -2233,10 +2242,10 @@ fn infer(self: *Sema, ref: usize): usize {
n.resolved_lang_tid = t; n.resolved_lang_tid = t;
ret t; ret t;
}, },
.TypeAggregate(x) => { .TypeAggregate(&x) => {
ret build_aggregate(self, n, 0); ret build_aggregate(self, n, 0);
}, },
.TypeComptimeCall(x) => { .TypeComptimeCall(&x) => {
if ByteView.eq(x.name, ByteView.from_slice("self")) { if ByteView.eq(x.name, ByteView.from_slice("self")) {
if self.current_aggregate_lang == 0 { if self.current_aggregate_lang == 0 {
diag(self, n.span, .UndefinedSymbol, "`@self` outside of aggregate"); diag(self, n.span, .UndefinedSymbol, "`@self` outside of aggregate");
@@ -2252,7 +2261,7 @@ fn infer(self: *Sema, ref: usize): usize {
} }
ret 0; ret 0;
}, },
.ContainerMembers(x) => { .ContainerMembers(&x) => {
var i: usize = 0; var i: usize = 0;
while i < x.declarations.len { while i < x.declarations.len {
ignore_usize(infer(self, list_at(x.declarations, i))); ignore_usize(infer(self, list_at(x.declarations, i)));
@@ -2260,48 +2269,48 @@ fn infer(self: *Sema, ref: usize): usize {
} }
ret 0; ret 0;
}, },
.FnDecl(x) => { .FnDecl(&x) => {
ret infer_fn_decl(self, n, x.params, x.ret_type, x.body); ret infer_fn_decl(self, n, x.params, x.ret_type, x.body);
}, },
.TypeDecl(x) => { .TypeDecl(&x) => {
ret infer_type_decl(self, n, x.pattern, x.type_expr); ret infer_type_decl(self, n, x.pattern, x.type_expr);
}, },
.VarDecl(x) => { ret var_body(self, n); }, .VarDecl(&x) => { ret var_body(self, n); },
.ConstDecl(x) => { ret var_body(self, n); }, .ConstDecl(&x) => { ret var_body(self, n); },
.MemberDecl(x) => { .MemberDecl(&x) => {
if x.type_expr != 0 { ret infer(self, x.type_expr); } if x.type_expr != 0 { ret infer(self, x.type_expr); }
ret 0; ret 0;
}, },
.ParamDecl(x) => { .ParamDecl(&x) => {
if x.type_expr != 0 { ret infer(self, x.type_expr); } if x.type_expr != 0 { ret infer(self, x.type_expr); }
ret 0; ret 0;
}, },
.StatementRet(x) => { .StatementRet(&x) => {
ret infer_ret(self, n, x.expr); ret infer_ret(self, n, x.expr);
}, },
.StatementBreak(x) => { .StatementBreak(&x) => {
ret infer_break(self, n, x.label, x.expr); ret infer_break(self, n, x.label, x.expr);
}, },
.StatementContinue(x) => { .StatementContinue(&x) => {
ret infer_continue(self, n, x.label); ret infer_continue(self, n, x.label);
}, },
.StatementDefer(x) => { .StatementDefer(&x) => {
if x.body != 0 { ignore_usize(infer(self, x.body)); } if x.body != 0 { ignore_usize(infer(self, x.body)); }
ret 0; ret 0;
}, },
.StatementComptime(x) => { .StatementComptime(&x) => {
if x.body != 0 { ignore_usize(infer(self, x.body)); } if x.body != 0 { ignore_usize(infer(self, x.body)); }
ret 0; ret 0;
}, },
.StatementDecl(x) => { .StatementDecl(&x) => {
if x.decl != 0 { ignore_usize(infer(self, x.decl)); } if x.decl != 0 { ignore_usize(infer(self, x.decl)); }
ret 0; ret 0;
}, },
.StatementExpr(x) => { .StatementExpr(&x) => {
if x.expr != 0 { ignore_usize(infer(self, x.expr)); } if x.expr != 0 { ignore_usize(infer(self, x.expr)); }
ret 0; ret 0;
}, },
.TopLevelBlock(x) => { .TopLevelBlock(&x) => {
if x.block != 0 { ignore_usize(infer(self, x.block)); } if x.block != 0 { ignore_usize(infer(self, x.block)); }
ret 0; ret 0;
}, },
@@ -2311,7 +2320,7 @@ fn infer(self: *Sema, ref: usize): usize {
} }
fn kind_is_body_ident(n: *Node): bool { fn kind_is_body_ident(n: *Node): bool {
match n.body { .ExprIdent(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprIdent(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -2605,7 +2614,7 @@ fn infer_cast(self: *Sema, n: *Node, expr_ref: usize, type_ref: usize): usize {
} }
fn is_expr_float_lit(n: *Node): bool { fn is_expr_float_lit(n: *Node): bool {
match n.body { .ExprFloatLit(x) => { ret true; }, _ => { ret false; } } match n.body { .ExprFloatLit(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -2726,7 +2735,7 @@ fn infer_for(self: *Sema, n: *Node, label_ref: usize, iter_exprs: Vec, pattern_r
} }
fn kind_is_body_pattern_list(n: *Node): bool { fn kind_is_body_pattern_list(n: *Node): bool {
match n.body { .PatternList(x) => { ret true; }, _ => { ret false; } } match n.body { .PatternList(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
@@ -2810,7 +2819,7 @@ fn infer_type_decl(self: *Sema, n: *Node, pattern_ref: usize, type_ref: usize):
} }
fn kind_is_body_fn_decl(n: *Node): bool { fn kind_is_body_fn_decl(n: *Node): bool {
match n.body { .FnDecl(x) => { ret true; }, _ => { ret false; } } match n.body { .FnDecl(&x) => { ret true; }, _ => { ret false; } }
ret false; ret false;
} }
+8 -1
View File
@@ -8,6 +8,13 @@ type spl_vm_val_t = u64; // usize
#extern(vm) fn vm_load_from_buffer(vm: *any, buf: *any, len: usize): i32; #extern(vm) fn vm_load_from_buffer(vm: *any, buf: *any, len: usize): i32;
#extern(vm) fn vm_push(vm: *any, val: spl_vm_val_t): void; #extern(vm) fn vm_push(vm: *any, val: spl_vm_val_t): void;
// TODO #extern(vm) fn vm_call(vm: *any, name: *u8, nargs: u64): i32;
#extern(vm) fn vm_run(vm: *any): i32;
#extern(vm) fn vm_ret_val(vm: *any): spl_vm_val_t;
#extern(vm) fn vm_mem_alloc(vm: *any, size: usize): spl_vm_val_t;
#extern(vm) fn vm_mem_read(vm: *any, off: spl_vm_val_t, dst: *any, n: usize): i32;
#extern(vm) fn vm_mem_write(vm: *any, off: spl_vm_val_t, src: *any, n: usize): i32;
#extern(vm) fn vm_stack_get(vm: *any, index: usize): spl_vm_val_t;
#extern(vm) fn vm_set_foreign(vm: *any, entry: []u8, ctx: u64): i32;
fn main() {} fn main() {}
+155
View File
@@ -0,0 +1,155 @@
// Expect retcode = 0
type Pair = struct {
x: i32,
y: i32,
}
type Option = enum {
None,
Some: i32,
}
type Nested = struct {
inner: Pair,
tag: i32,
}
// 对照:无 & 的值绑定是拷贝,写回不作用于源。
fn test_value_binding_is_copy() {
var p: Pair = .{ .x = 1, .y = 2 };
var .{ .x = a, .y = b } = p;
a = 10;
b = 20;
@assert(a == 10, "value binding a is local copy");
@assert(p.x == 1, "value binding does not write back x");
@assert(p.y == 2, "value binding does not write back y");
}
// 普通结构体解构:& 引用绑定。
fn test_struct_ref_binding() {
var p: Pair = .{ .x = 1, .y = 2 };
var .{ .x = &a, .y = &b } = p;
@assert(a.* == 1, "struct ref reads x");
@assert(b.* == 2, "struct ref reads y");
a.* = 10;
b.* = 20;
@assert(p.x == 10, "struct ref writes back x");
@assert(p.y == 20, "struct ref writes back y");
}
// 混合:值绑定 + 引用绑定。
fn test_struct_mixed_binding() {
var p: Pair = .{ .x = 1, .y = 2 };
var .{ .x = val, .y = &ref } = p;
@assert(val == 1, "mixed value reads x");
val = 100;
ref.* = 200;
@assert(p.x == 1, "mixed value does not write back");
@assert(p.y == 200, "mixed ref writes back");
}
// 部分字段 & 引用绑定。
fn test_struct_partial_ref() {
var p: Pair = .{ .x = 1, .y = 2 };
var .{ .y = &b } = p;
b.* = 99;
@assert(p.y == 99, "partial ref writes back y");
@assert(p.x == 1, "partial ref leaves x untouched");
}
// 嵌套结构体解构:& 引用绑定。
fn test_nested_ref() {
var n: Nested = .{ .inner = .{ .x = 1, .y = 2 }, .tag = 3 };
var .{ .inner = .{ .x = &a, .y = &b }, .tag = &t } = n;
a.* = 7;
b.* = 8;
t.* = 9;
@assert(n.inner.x == 7, "nested ref writes back inner.x");
@assert(n.inner.y == 8, "nested ref writes back inner.y");
@assert(n.tag == 9, "nested ref writes back tag");
}
// 源本身是左值子表达式(字段):& 引用绑定。
fn test_field_source_ref() {
var n: Nested = .{ .inner = .{ .x = 1, .y = 2 }, .tag = 3 };
var .{ .x = &a, .y = &b } = n.inner;
a.* = 11;
b.* = 12;
@assert(n.inner.x == 11, "field source ref writes back x");
@assert(n.inner.y == 12, "field source ref writes back y");
}
// 枚举解构:& 引用绑定。
fn test_enum_ref() {
var o: Option = .Some(1);
var .Some(&n) = o;
@assert(n.* == 1, "enum ref reads payload");
n.* = 42;
match o {
.None => { @assert(false, "enum ref: expected Some"); },
.Some(m) => { @assert(m == 42, "enum ref writes back payload"); },
}
}
// 元组解构:& 引用绑定。
fn test_tuple_ref() {
var t: (i32, i32) = (1, 2);
var (&a, &b) = t;
@assert(a.* == 1, "tuple ref reads [0]");
@assert(b.* == 2, "tuple ref reads [1]");
a.* = 10;
b.* = 20;
@assert(t[0] == 10, "tuple ref writes back [0]");
@assert(t[1] == 20, "tuple ref writes back [1]");
}
// if var:& 引用绑定(枚举)。
fn test_ifvar_enum_ref() {
var o: Option = .Some(1);
if var .Some(&n) = o {
n.* = 77;
}
match o {
.None => { @assert(false, "if var ref: expected Some"); },
.Some(m) => { @assert(m == 77, "if var ref writes back payload"); },
}
}
// if var:& 引用绑定(元组)。
fn test_ifvar_tuple_ref() {
var t: (i32, i32) = (1, 2);
if var (&a, &b) = t {
a.* = 5;
b.* = 6;
}
@assert(t[0] == 5, "if var tuple ref writes back [0]");
@assert(t[1] == 6, "if var tuple ref writes back [1]");
}
// match arm:& 引用绑定。
fn test_match_enum_ref() {
var o: Option = .Some(1);
match o {
.None => { @assert(false, "match ref: expected Some"); },
.Some(&n) => { n.* = 55; },
}
match o {
.None => { @assert(false, "match ref: expected Some after"); },
.Some(m) => { @assert(m == 55, "match arm ref writes back payload"); },
}
}
fn main() {
test_value_binding_is_copy();
test_struct_ref_binding();
test_struct_mixed_binding();
test_struct_partial_ref();
test_nested_ref();
test_field_source_ref();
test_enum_ref();
test_tuple_ref();
test_ifvar_enum_ref();
test_ifvar_tuple_ref();
test_match_enum_ref();
}