stage1 优化重构代码

This commit is contained in:
zzy
2026-07-12 10:01:57 +08:00
parent f1b4225c92
commit 118c153280
6 changed files with 316 additions and 655 deletions

View File

@@ -62,6 +62,9 @@ static int tok_prec(spl_tok_type_t t) {
* ============================================================ */
static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op);
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result,
spl_type_info_t *type);
static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left);
/* Slice creation from array/slice range expression.
* Stack in: [base_addr, begin, end]
@@ -273,13 +276,11 @@ static spl_expr_result_t parse_float_literal(spl_comp_t *ctx) {
static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
/* Lexeme: 'x' or '\n' etc, extract the character value */
const char *s = t->lexeme;
usize l = t->len;
int64_t val = 0;
if (l >= 3) {
if (s[1] == '\\' && l >= 4) {
/* Escape sequence */
char buf = 0;
const char *cp = s + 1;
spl_decode_escape(&cp, &buf);
@@ -295,12 +296,10 @@ static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
/* Decode the string content (strip quotes, process escapes) */
usize slen = t->len;
if (slen >= 2) {
slen -= 2; /* remove outer quotes */
slen -= 2;
}
/* Build decoded string */
char *decoded = malloc(slen + 1);
usize di = 0;
for (usize i = 1; i + 1 < t->len; i++) {
@@ -315,10 +314,9 @@ static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
}
}
decoded[di] = '\0';
/* Add to global data */
int gdi = spl_add_global_data(ctx, decoded, di + 1);
free(decoded);
spl_emit(ctx, SPL_GADDR, SPL_PTR, gdi - 1); /* gdi is 1-based from spl_prog_add_data */
spl_emit(ctx, SPL_GADDR, SPL_PTR, gdi - 1);
spl_expr_result_t r = {spl_type_ptr(spl_type_basic(SPL_U8)), 0};
return r;
}
@@ -328,7 +326,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
advance(ctx); /* skip [ */
skip_nl(ctx);
/* Parse array length */
int len_val;
if (!spl_parse_int_literal(ctx, &len_val)) {
spl_comp_error(ctx, "expected array length");
@@ -341,7 +338,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
expect(ctx, TOK_R_BRACKET);
skip_nl(ctx);
/* Parse element type */
spl_type_info_t *elem_type = spl_parse_type(ctx);
if (!elem_type) {
spl_expr_result_t r = {0};
@@ -352,7 +348,6 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
expect(ctx, TOK_L_BRACE);
skip_nl(ctx);
/* Parse each element value */
for (usize i = 0; i < len; i++) {
if (i > 0) {
if (peek(ctx)->type == TOK_COMMA)
@@ -363,7 +358,7 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
skip_nl(ctx);
}
if (peek(ctx)->type == TOK_COMMA)
advance(ctx); /* trailing comma */
advance(ctx);
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
@@ -373,7 +368,7 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
}
/* Parse slice inline literal: { .ptr = expr, .len = expr }
* Expects base address on TOS, consumes it. Stores ptr to base+0, len to base+sizeof(spl_val_t). */
* Expects base address on TOS, consumes it. */
static void parse_slice_inline(spl_comp_t *ctx) {
advance(ctx); /* { */
skip_nl(ctx);
@@ -387,36 +382,30 @@ static void parse_slice_inline(spl_comp_t *ctx) {
advance(ctx);
spl_tok_t *ftok = advance(ctx);
char fname[256];
usize fnl = ftok->len < 255 ? ftok->len : 255;
memcpy(fname, ftok->lexeme, fnl);
fname[fnl] = '\0';
spl_tok_copy_name(ftok, fname, sizeof(fname));
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
skip_nl(ctx);
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, addr] */
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
if (strcmp(fname, "ptr") == 0) {
spl_parse_expr(ctx, PREC_MIN);
spl_emit(ctx, SPL_STORE, SPL_PTR, 0); /* [addr] */
spl_emit(ctx, SPL_STORE, SPL_PTR, 0);
} else if (strcmp(fname, "len") == 0) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); /* [addr, addr+8] */
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
spl_parse_expr(ctx, PREC_MIN);
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* [addr] */
spl_emit(ctx, SPL_STORE, SPL_USIZE, 0);
}
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop addr */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
}
/* Parse a single .field = value in a struct literal.
* Iterates fields to find the match, emits LADDR + offset, and handles
* value parsing (slice inline, array inline, multi-slot struct, basic store).
* Reused by both TYPE_STRUCT and TYPE_ENUM variant struct data. */
static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
int base_offset, usize extra_offset) {
static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields, int base_offset,
usize extra_offset) {
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *ftok = advance(ctx);
@@ -436,13 +425,10 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
spl_emit(ctx, SPL_PUSH, SPL_USIZE, byte_off);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
if (f->type && f->type->kind == TYPE_SLICE &&
peek(ctx)->type == TOK_L_BRACE) {
if (f->type && f->type->kind == TYPE_SLICE && peek(ctx)->type == TOK_L_BRACE) {
parse_slice_inline(ctx);
} else if (f->type && f->type->kind == TYPE_ARRAY &&
peek(ctx)->type == TOK_L_BRACKET) {
/* Inline array initializer: [N]Type{val1, val2, ...} */
advance(ctx); /* [ */
} else if (f->type && f->type->kind == TYPE_ARRAY && peek(ctx)->type == TOK_L_BRACKET) {
advance(ctx);
skip_nl(ctx);
int len_val;
if (!spl_parse_int_literal(ctx, &len_val)) {
@@ -461,7 +447,8 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
spl_type_t st = spl_type_emit_type(elem_type);
for (usize i = 0; i < arr_len; i++) {
if (i > 0) {
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
if (peek(ctx)->type == TOK_COMMA)
advance(ctx);
skip_nl(ctx);
}
spl_emit(ctx, SPL_DUP, SPL_VOID, 0);
@@ -473,12 +460,12 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
spl_emit(ctx, SPL_STORE, st, 0);
skip_nl(ctx);
}
if (peek(ctx)->type == TOK_COMMA) advance(ctx);
if (peek(ctx)->type == TOK_COMMA)
advance(ctx);
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else if (f->type &&
(f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
} else if (f->type && (f->type->kind == TYPE_STRUCT || f->type->kind == TYPE_ENUM) &&
spl_type_size(f->type) > sizeof(spl_val_t)) {
spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN);
(void)fv;
@@ -495,9 +482,6 @@ static void parse_one_field_init(spl_comp_t *ctx, spl_field_vec_t *fields,
}
}
/* Parse struct/enum literal: Type { .field = val, ... }
* Allocates temp slots for the value, returns lvalue (addr on stack).
* For types fitting in one slot, pushes the packed value directly. */
spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *type) {
usize sz = spl_type_size(type);
int base_offset = ctx->current_local_bytes;
@@ -558,14 +542,11 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
skip_nl(ctx);
}
} else if (type->kind == TYPE_ENUM) {
/* Parse .Variant [= value] */
if (peek(ctx)->type == TOK_DOT)
advance(ctx);
spl_tok_t *vtok = advance(ctx);
char vname[256];
usize vnl = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vnl);
vname[vnl] = '\0';
spl_tok_copy_name(vtok, vname, sizeof(vname));
skip_nl(ctx);
if (peek(ctx)->type == TOK_ASSIGN)
advance(ctx);
@@ -576,16 +557,13 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
spl_enum_variant_t *v = &vec_at(type->variants, vi);
if (strcmp(v->name, vname) == 0) {
found = 1;
/* Store tag at offset 0 */
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
spl_emit(ctx, SPL_PUSH, SPL_I32, v->value);
spl_emit(ctx, SPL_STORE, SPL_I32, 0);
/* Store variant data at offset 4 */
const usize DATA_OFFSET = 4;
if (v->data_type) {
if (v->data_type->kind == TYPE_STRUCT && peek(ctx)->type == TOK_L_BRACE) {
/* Struct data: { .field = val, ... } */
advance(ctx); /* { */
skip_nl(ctx);
while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) {
@@ -596,7 +574,8 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
}
if (peek(ctx)->type != TOK_DOT)
break;
parse_one_field_init(ctx, &v->data_type->fields, base_offset, DATA_OFFSET);
parse_one_field_init(ctx, &v->data_type->fields, base_offset,
DATA_OFFSET);
skip_nl(ctx);
}
expect(ctx, TOK_R_BRACE);
@@ -604,7 +583,6 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
(v->data_type->kind == TYPE_STRUCT ||
v->data_type->kind == TYPE_ENUM) &&
spl_type_size(v->data_type) > sizeof(spl_val_t)) {
/* Multi-slot struct/enum data: copy from temp to enum data area */
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
(void)dv;
usize nslots = (spl_type_size(v->data_type) + sizeof(spl_val_t) - 1) /
@@ -612,7 +590,6 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
spl_emit_copy_slots(ctx, base_offset + (int)DATA_OFFSET, nslots);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else {
/* Simple data: parse expression */
spl_expr_result_t dv = spl_parse_expr(ctx, PREC_MIN);
(void)dv;
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
@@ -633,28 +610,40 @@ spl_expr_result_t spl_parse_struct_literal(spl_comp_t *ctx, spl_type_info_t *typ
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
/* Return: if size fits in one slot, push packed value. Otherwise push address. */
if (sz <= sizeof(spl_val_t)) {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
return (spl_expr_result_t){type, 0}; /* value on stack */
return (spl_expr_result_t){type, 0};
} else {
spl_emit(ctx, SPL_LADDR, SPL_PTR, base_offset);
return (spl_expr_result_t){type, 1}; /* address on stack */
return (spl_expr_result_t){type, 1};
}
}
static int parse_call_args(spl_comp_t *ctx) {
int nargs = 0;
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_parse_expr(ctx, PREC_MIN);
nargs++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
return nargs;
}
static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
char name[256];
usize nlen = t->len < 255 ? t->len : 255;
memcpy(name, t->lexeme, nlen);
name[nlen] = '\0';
spl_tok_copy_name(t, name, sizeof(name));
/* Check if it's a function call: ident(...) */
if (peek(ctx)->type == TOK_L_PAREN) {
int fi = spl_lookup_func(ctx, name);
/* Fallback: try qualified name for short-name resolution inside methods */
if (fi < 0 && ctx->current_type_name) {
char qualified[512];
snprintf(qualified, sizeof(qualified), "%s.%s", ctx->current_type_name, name);
@@ -668,44 +657,14 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
advance(ctx); /* skip ( */
int nargs = 0;
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
(void)arg;
nargs++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
int nargs = parse_call_args(ctx);
expect(ctx, TOK_R_PAREN);
if (f->is_extern) {
/* Find the native function index in prog */
int nidx = -1;
vec_for(ctx->prog.natives, ni) {
if (strcmp(vec_at(ctx->prog.natives, ni).name, f->name) == 0) {
nidx = (int)ni;
break;
}
}
if (nidx < 0) {
/* Register it */
spl_native_t nat;
nat.name = strdup(f->name);
nat.idx_of_strtab = 0;
nat.impl_fn = NULL;
vec_push(ctx->prog.natives, nat);
nidx = (int)vec_size(ctx->prog.natives) - 1;
}
/* Push native index, then NCALL with imm = nargs */
int nidx = spl_ensure_native(ctx, f->name);
spl_emit(ctx, SPL_PUSH, SPL_I32, nidx);
spl_emit(ctx, SPL_NCALL, SPL_VOID, nargs);
} else {
/* Regular function call: push func addr, then CALL */
spl_val_t addr = vec_at(ctx->prog.funcs, f->func_idx).address;
spl_emit(ctx, SPL_PUSH, SPL_PTR, addr);
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
@@ -718,7 +677,6 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
/* Variable reference */
spl_var_info_t *v = spl_lookup_var(ctx, name);
if (v) {
/* Check const values first */
spl_val_t cv = 0;
if (map_get(ctx->const_values, name, &cv)) {
spl_emit(ctx, SPL_PUSH, SPL_I32, cv);
@@ -729,27 +687,14 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_type_info_t *vt = v->type;
spl_emit(ctx, SPL_LADDR, SPL_PTR, v->offset);
if (vt->kind == TYPE_BASIC || vt->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
/* Load value for basic types and pointers */
spl_type_t bt = (vt->kind == TYPE_BASIC) ? vt->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
spl_expr_result_t r = {vt, 0};
return r;
}
/* In addr_of_mode, keep address on stack */
spl_expr_result_t r = {vt, 1};
return r;
}
/* Array/struct/slice: address stays on stack */
spl_expr_result_t r = {vt, 1};
spl_expr_result_t r;
emit_load_or_addr_type(ctx, &r, vt);
return r;
}
/* Check if it's a type name (for enum variant access like Color.Red) */
spl_type_info_t *ttype = spl_resolve_type(ctx, name);
if (ttype) {
/* Struct/enum literal: Type { .field = val, ... } */
if (peek(ctx)->type == TOK_L_BRACE &&
(ttype->kind == TYPE_STRUCT || ttype->kind == TYPE_ENUM)) {
return spl_parse_struct_literal(ctx, ttype);
@@ -770,6 +715,19 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
return r;
}
static void emit_load_or_addr_type(spl_comp_t *ctx, spl_expr_result_t *result,
spl_type_info_t *type) {
if (type->kind == TYPE_BASIC || type->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (type->kind == TYPE_BASIC) ? type->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
*result = (spl_expr_result_t){type, 0};
return;
}
}
*result = (spl_expr_result_t){type, 1};
}
static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
spl_tok_t *op = advance(ctx);
@@ -784,7 +742,6 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
spl_emit(ctx, SPL_NEG, SPL_I32, 0);
break;
case TOK_NOT:
/* !expr → EQ 0 */
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
spl_emit(ctx, SPL_EQ, SPL_I32, 0);
break;
@@ -792,31 +749,16 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
spl_emit(ctx, SPL_NOT, SPL_I32, 0);
break;
case TOK_AND:
/* &expr — address-of, already an lvalue */
if (!right.is_lvalue) {
spl_comp_error(ctx, "cannot take address of rvalue");
}
break;
case TOK_MUL:
/* *expr — dereference */
if (right.type && right.type->kind == TYPE_PTR && right.type->elem) {
/* If right is still an lvalue, load the pointer value for the target */
if (right.is_lvalue) {
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
}
spl_type_info_t *elem = right.type->elem;
if (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
right = (spl_expr_result_t){elem, 0};
} else {
right = (spl_expr_result_t){elem, 1};
}
} else {
/* Struct/array/slice: keep address on stack */
right = (spl_expr_result_t){elem, 1};
}
emit_load_or_addr_type(ctx, &right, right.type->elem);
}
break;
default:
@@ -876,7 +818,6 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
case TOK_L_BRACE:
return spl_parse_block_expr(ctx);
case TOK_AT: {
/* @builtin(...) — compiler intrinsic */
advance(ctx);
skip_nl(ctx);
tok = peek(ctx);
@@ -892,18 +833,7 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
if (strcmp(bname, "dbg") == 0) {
if (peek(ctx)->type == TOK_L_PAREN) {
advance(ctx);
int nargs = 0;
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_parse_expr(ctx, PREC_MIN);
nargs++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
int nargs = parse_call_args(ctx);
expect(ctx, TOK_R_PAREN);
for (int i = 0; i < nargs; i++) {
spl_emit(ctx, SPL_DBG, SPL_USIZE, 0);
@@ -931,28 +861,23 @@ static spl_expr_result_t parse_primary_expr(spl_comp_t *ctx) {
}
/* ============================================================
* Main expression parser (top-level)
* Postfix expression parser (.field, [index], [begin..end])
* ============================================================ */
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
skip_nl(ctx);
spl_expr_result_t left = parse_primary_expr(ctx);
static spl_expr_result_t parse_postfix_expr(spl_comp_t *ctx, spl_expr_result_t left) {
if (!left.type)
return left;
/* Infix parsing (precedence climbing) */
while (1) {
for (;;) {
skip_nl(ctx);
spl_tok_type_t opt = peek(ctx)->type;
/* Postfix operators */
/* Postfix . operator */
if (opt == TOK_DOT) {
advance(ctx);
spl_tok_t *field = advance(ctx);
char fname[256];
usize fnl = field->len < 255 ? field->len : 255;
memcpy(fname, field->lexeme, fnl);
fname[fnl] = '\0';
spl_tok_copy_name(field, fname, sizeof(fname));
/* Compile-time type member resolution (enum variants, nested types) */
if (left.type) {
@@ -965,7 +890,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
/* Method call on type/instance: left.field(args) */
if (left.type && peek(ctx)->type == TOK_L_PAREN) {
/* Determine the type that owns methods (deref pointer if needed) */
spl_type_info_t *methods_type = left.type;
int is_ptr_self = 0;
if (methods_type->kind == TYPE_PTR && methods_type->elem &&
@@ -986,7 +910,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
int nargs = 0;
/* Check if instance method: first param is self: *Type */
int is_instance = 0;
if (func->nparams > 0 && func->param_types[0] &&
func->param_types[0]->kind == TYPE_PTR &&
@@ -999,22 +922,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
spl_comp_error(ctx, "cannot call instance method '%s' on type",
fname);
}
nargs = 1; /* self already on stack */
nargs = 1;
}
/* Parse remaining arguments */
if (peek(ctx)->type != TOK_R_PAREN) {
for (;;) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
(void)arg;
nargs++;
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
nargs += parse_call_args(ctx);
expect(ctx, TOK_R_PAREN);
spl_val_t addr = vec_at(ctx->prog.funcs, func->func_idx).address;
@@ -1027,12 +938,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
if (found_method)
continue;
/* If method not found, fall through to field access below */
}
/* Struct field access */
if (left.type && left.type->kind == TYPE_STRUCT) {
/* The struct address is on stack (as lvalue or from previous computation) */
vec_for(left.type->fields, fi) {
if (strcmp(vec_at(left.type->fields, fi).name, fname) == 0) {
spl_field_t *f = &vec_at(left.type->fields, fi);
@@ -1040,19 +949,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
/* Load value if basic type */
spl_type_info_t *ft = f->type;
if (ft->kind == TYPE_BASIC || ft->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (ft->kind == TYPE_BASIC) ? ft->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
left = (spl_expr_result_t){ft, 0};
} else {
left = (spl_expr_result_t){ft, 1};
}
} else {
left = (spl_expr_result_t){ft, 1};
}
emit_load_or_addr_type(ctx, &left, f->type);
break;
}
}
@@ -1063,11 +960,9 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
if (left.type && left.type->kind == TYPE_PTR && left.type->elem &&
left.type->elem->kind == TYPE_STRUCT) {
spl_type_info_t *st = left.type->elem;
/* Load pointer value to get struct address if left is still lvalue */
if (left.is_lvalue) {
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
}
/* Now search field */
vec_for(st->fields, fi) {
if (strcmp(vec_at(st->fields, fi).name, fname) == 0) {
spl_field_t *f = &vec_at(st->fields, fi);
@@ -1075,18 +970,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
spl_emit(ctx, SPL_PUSH, SPL_USIZE, f->offset);
spl_emit(ctx, SPL_ADD, SPL_USIZE, 0);
}
spl_type_info_t *ft = f->type;
if (ft->kind == TYPE_BASIC || ft->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (ft->kind == TYPE_BASIC) ? ft->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
left = (spl_expr_result_t){ft, 0};
} else {
left = (spl_expr_result_t){ft, 1};
}
} else {
left = (spl_expr_result_t){ft, 1};
}
emit_load_or_addr_type(ctx, &left, f->type);
break;
}
}
@@ -1097,12 +981,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
if (left.type && left.type->kind == TYPE_SLICE) {
if (strcmp(fname, "len") == 0) {
if (ctx->addr_of_mode) {
/* lvalue: push address of len field at offset sizeof(spl_val_t) */
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
left = (spl_expr_result_t){spl_type_basic(SPL_USIZE), 1};
} else {
/* rvalue: load len value */
spl_emit(ctx, SPL_PUSH, SPL_U64, (spl_val_t)sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0);
@@ -1110,7 +992,6 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
} else if (strcmp(fname, "ptr") == 0) {
if (ctx->addr_of_mode) {
/* lvalue: ptr is at offset 0, address already on stack */
left = (spl_expr_result_t){left.type->elem ? spl_type_ptr(left.type->elem)
: spl_type_basic(SPL_PTR),
1};
@@ -1130,18 +1011,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
if (left.is_lvalue) {
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
}
spl_type_info_t *elem = left.type->elem;
if (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
left = (spl_expr_result_t){elem, 0};
} else {
left = (spl_expr_result_t){elem, 1};
}
} else {
left = (spl_expr_result_t){elem, 1};
}
emit_load_or_addr_type(ctx, &left, left.type->elem);
continue;
}
@@ -1153,16 +1023,14 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
if (opt == TOK_L_BRACKET) {
advance(ctx); /* skip [ */
if (peek(ctx)->type == TOK_R_BRACKET) {
advance(ctx); /* empty brackets */
advance(ctx);
continue;
}
/* Parse index/begin expression before checking for range */
spl_parse_expr(ctx, PREC_MIN);
/* Check for slice: expr[begin..end] or expr[begin..] */
if (peek(ctx)->type == TOK_RANGE) {
advance(ctx); /* skip .. */
advance(ctx);
spl_expr_result_t end_expr = {0};
int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET);
if (has_explicit_end) {
@@ -1170,13 +1038,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
expect(ctx, TOK_R_BRACKET);
/* Push implicit end value (array length/slice len) before the outer
* type-check so it always runs regardless of left.type validity. */
if (!has_explicit_end) {
if (left.type && left.type->kind == TYPE_ARRAY) {
spl_emit(ctx, SPL_PUSH, SPL_U64, left.type->array_len);
} else if (left.type && left.type->kind == TYPE_SLICE) {
/* TYPE_SLICE: load len from struct at offset sizeof(spl_val_t) */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t));
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
@@ -1184,29 +1049,25 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
}
/* Generate slice: compute ptr = base + begin * stride, len = end - begin */
if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_SLICE)) {
usize stride = spl_type_elem_stride(left.type->elem);
if (left.type->kind == TYPE_SLICE) {
/* Stack: [struct_addr, begin, end].
* Inline ptr/len: ptr = data_ptr + begin*stride, len = end - begin. */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [s,b,e,data_ptr] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [s,b,e,d,begin] */
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_PICK, SPL_VOID, 2);
spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [s,b,e,ptr] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [s,b,e,ptr,end] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [s,b,e,ptr,end,begin] */
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [s,b,e,ptr,len] */
/* cleanup: drop [s,b,e] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,b,ptr,len,e] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,b,ptr,len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,ptr,len,b] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,ptr,len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [ptr,len,s] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [ptr,len] */
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
spl_emit(ctx, SPL_PICK, SPL_VOID, 3);
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0);
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
spl_emit(ctx, SPL_ROT, SPL_VOID, 0);
spl_emit(ctx, SPL_DROP, SPL_VOID, 0);
} else {
emit_slice_create(ctx, stride);
}
@@ -1217,20 +1078,14 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
expect(ctx, TOK_R_BRACKET);
/* Array/slice/pointer indexing */
if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_PTR ||
left.type->kind == TYPE_SLICE)) {
spl_type_info_t *elem = left.type->elem;
if (left.type->kind == TYPE_SLICE) {
/* Slice: stack has [slice_struct_addr, index].
* Load data ptr first, then compute element address. */
emit_slice_index(ctx, elem);
} else {
/* Stack arrays and pointer indexing */
if (left.type->kind == TYPE_PTR && left.is_lvalue) {
/* Stack: [addr_of_ptr, index]. Swap to get addr on top, load ptr value,
* swap back */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
@@ -1240,21 +1095,34 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
}
if (elem && (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR)) {
if (!ctx->addr_of_mode) {
spl_type_t bt = (elem->kind == TYPE_BASIC) ? elem->basic_type : SPL_PTR;
spl_emit(ctx, SPL_LOAD, bt, 0);
left = (spl_expr_result_t){elem, 0};
} else {
left = (spl_expr_result_t){elem, 1};
}
} else {
left = (spl_expr_result_t){elem, 1};
}
if (elem)
emit_load_or_addr_type(ctx, &left, elem);
}
continue;
}
break;
}
return left;
}
/* ============================================================
* Main expression parser (top-level)
* ============================================================ */
spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
skip_nl(ctx);
spl_expr_result_t left = parse_primary_expr(ctx);
if (!left.type)
return left;
/* Infix parsing (precedence climbing) */
while (1) {
left = parse_postfix_expr(ctx, left);
skip_nl(ctx);
spl_tok_type_t opt = peek(ctx)->type;
/* Binary operators */
int prec = tok_prec(opt);
if (prec == 0 || prec < min_prec)
@@ -1276,14 +1144,12 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
/* Short-circuit logical operators */
if (op == TOK_AND_AND) {
/* left is already evaluated and on stack. If it's false (0), skip right. */
spl_val_t bz_addr = spl_emit_bz(ctx);
spl_parse_expr(ctx, next_prec);
spl_patch_to_here(ctx, bz_addr);
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
}
if (op == TOK_OR_OR) {
/* If left is true (non-zero), skip right. */
spl_val_t bnz_addr = spl_emit_bnz(ctx);
spl_parse_expr(ctx, next_prec);
spl_patch_to_here(ctx, bnz_addr);
@@ -1296,7 +1162,6 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR || op == TOK_ASSIGN_L_SH ||
op == TOK_ASSIGN_R_SH) {
/* RHS must not inherit addr_of_mode from LHS */
int saved_addr_of_mode = ctx->addr_of_mode;
ctx->addr_of_mode = 0;
spl_expr_result_t right = spl_parse_expr(ctx, PREC_MIN);
@@ -1307,17 +1172,14 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
? (left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_PTR)
: SPL_I32;
if (op == TOK_ASSIGN) {
/* Simple assignment: stack is [addr, rhs] */
/* STORE pops TOS=value, TOS-1=address — already correct order */
spl_emit(ctx, SPL_STORE, bt, 0);
} else {
/* Compound: left = left op right — stack: [addr, rhs] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [addr, old_val, rhs] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1);
spl_emit(ctx, SPL_LOAD, bt, 0);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0);
int sop = binop_to_sir(assign_to_binop(op), bt);
if (sop >= 0)
spl_emit(ctx, sop, bt, 0); /* [addr, result] */
spl_emit(ctx, sop, bt, 0);
spl_emit(ctx, SPL_STORE, bt, 0);
}
}
@@ -1349,9 +1211,7 @@ spl_enum_variant_t *spl_emit_match_enum_cmp(spl_comp_t *ctx, spl_type_info_t *en
advance(ctx);
spl_tok_t *vtok = advance(ctx);
char vname[256];
usize vnl = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vnl);
vname[vnl] = '\0';
spl_tok_copy_name(vtok, vname, sizeof(vname));
vec_for(enum_type->variants, vi) {
spl_enum_variant_t *v = &vec_at(enum_type->variants, vi);