stage1 完成09,10测试

This commit is contained in:
zzy
2026-07-06 10:52:31 +08:00
parent 777b6b42d1
commit 0182b8ed5c
4 changed files with 257 additions and 142 deletions

View File

@@ -72,6 +72,8 @@ void spl_type_add_variant(spl_type_info_t *et, const char *name, spl_type_info_t
void spl_type_compute_layout(spl_type_info_t *t);
usize spl_type_size(spl_type_info_t *t);
usize spl_type_slot_count(spl_type_info_t *t);
/* Byte stride between consecutive elements in storage (slot-based layout) */
usize spl_type_elem_stride(spl_type_info_t *elem);
const char *spl_type_str(spl_type_info_t *t);
int spl_type_is_integer(spl_type_t bt);
spl_type_info_t *spl_type_clone(spl_type_info_t *t);

View File

@@ -1,39 +1,46 @@
/* spl_expr.c — Expression parser + codegen (Pratt parser / precedence climbing) */
#include "spl_comp.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* ============================================================
* Token helpers
* ============================================================ */
static spl_tok_t *peek(spl_comp_t *ctx) {
return &vec_at(ctx->toks, ctx->tok_idx);
}
static spl_tok_t *peek(spl_comp_t *ctx) { return &vec_at(ctx->toks, ctx->tok_idx); }
static spl_tok_t *advance(spl_comp_t *ctx) {
spl_tok_t *t = &vec_at(ctx->toks, ctx->tok_idx);
if (t->type != TOK_EOF) ctx->tok_idx++;
if (t->type != TOK_EOF)
ctx->tok_idx++;
return t;
}
static int match(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { advance(ctx); return 1; }
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
return 0;
}
static int expect(spl_comp_t *ctx, spl_tok_type_t type) {
if (peek(ctx)->type == type) { advance(ctx); return 1; }
spl_comp_error(ctx, "expected '%s', got '%s'", spl_tok_type_name(type), spl_tok_type_name(peek(ctx)->type));
if (peek(ctx)->type == type) {
advance(ctx);
return 1;
}
spl_comp_error(ctx, "expected '%s', got '%s'", spl_tok_type_name(type),
spl_tok_type_name(peek(ctx)->type));
return 0;
}
/* Skip newline tokens */
static void skip_nl(spl_comp_t *ctx) {
while (peek(ctx)->type == TOK_ENDLINE) advance(ctx);
while (peek(ctx)->type == TOK_ENDLINE)
advance(ctx);
}
/* Check if current token starts a statement */
@@ -48,22 +55,48 @@ static int is_stmt_start(spl_comp_t *ctx) {
static int tok_prec(spl_tok_type_t t) {
switch (t) {
case TOK_OR_OR: return PREC_LOGOR;
case TOK_AND_AND: return PREC_LOGAND;
case TOK_OR: return PREC_OR;
case TOK_XOR: return PREC_XOR;
case TOK_AND: return PREC_AND;
case TOK_EQ: case TOK_NEQ: return PREC_CMPEQ;
case TOK_LT: case TOK_LE: case TOK_GT: case TOK_GE: return PREC_CMP;
case TOK_L_SH: case TOK_R_SH: return PREC_SHIFT;
case TOK_ADD: case TOK_SUB: return PREC_ADD;
case TOK_MUL: case TOK_DIV: case TOK_MOD: return PREC_MUL;
case TOK_ASSIGN: case TOK_ASSIGN_ADD: case TOK_ASSIGN_SUB:
case TOK_ASSIGN_MUL: case TOK_ASSIGN_DIV: case TOK_ASSIGN_MOD:
case TOK_ASSIGN_AND: case TOK_ASSIGN_OR: case TOK_ASSIGN_XOR:
case TOK_ASSIGN_L_SH: case TOK_ASSIGN_R_SH:
case TOK_OR_OR:
return PREC_LOGOR;
case TOK_AND_AND:
return PREC_LOGAND;
case TOK_OR:
return PREC_OR;
case TOK_XOR:
return PREC_XOR;
case TOK_AND:
return PREC_AND;
case TOK_EQ:
case TOK_NEQ:
return PREC_CMPEQ;
case TOK_LT:
case TOK_LE:
case TOK_GT:
case TOK_GE:
return PREC_CMP;
case TOK_L_SH:
case TOK_R_SH:
return PREC_SHIFT;
case TOK_ADD:
case TOK_SUB:
return PREC_ADD;
case TOK_MUL:
case TOK_DIV:
case TOK_MOD:
return PREC_MUL;
case TOK_ASSIGN:
case TOK_ASSIGN_ADD:
case TOK_ASSIGN_SUB:
case TOK_ASSIGN_MUL:
case TOK_ASSIGN_DIV:
case TOK_ASSIGN_MOD:
case TOK_ASSIGN_AND:
case TOK_ASSIGN_OR:
case TOK_ASSIGN_XOR:
case TOK_ASSIGN_L_SH:
case TOK_ASSIGN_R_SH:
return PREC_ASSIGN;
default: return PREC_MIN;
default:
return PREC_MIN;
}
}
@@ -88,24 +121,24 @@ static void emit_slice_create(spl_comp_t *ctx, usize stride) {
/* Stack: [base, begin, end] */
/* --- Compute ptr = base + begin * stride --- */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [base, begin, end, base] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [base, begin, end, base, begin] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [base, begin, end, base] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [base, begin, end, base, begin] */
spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
spl_emit(ctx, SPL_MUL, SPL_U64, 0); /* [base, begin, end, base, begin*stride] */
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [base, begin, end, ptr] */
spl_emit(ctx, SPL_MUL, SPL_U64, 0); /* [base, begin, end, base, begin*stride] */
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [base, begin, end, ptr] */
/* --- Compute len = end - begin --- */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [base, begin, end, ptr, end] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [base, begin, end, ptr, end, begin] */
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [base, begin, end, ptr, len] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [base, begin, end, ptr, end] */
spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [base, begin, end, ptr, end, begin] */
spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [base, begin, end, ptr, len] */
/* --- Cleanup: drop [base, begin, end], keep [ptr, len] --- */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [base, begin, ptr, len, end] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [base, begin, ptr, len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [base, ptr, len, begin] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [base, ptr, len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [ptr, len, base] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [ptr, len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [base, begin, ptr, len, end] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [base, begin, ptr, len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [base, ptr, len, begin] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [base, ptr, len] */
spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [ptr, len, base] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [ptr, len] */
}
/* Emit code to access slice element by index.
@@ -114,13 +147,13 @@ static void emit_slice_create(spl_comp_t *ctx, usize stride) {
* Stack in: [slice_struct_addr, index]
* Stack out: [element_addr] */
static void emit_slice_index(spl_comp_t *ctx, spl_type_info_t *elem) {
usize elem_size = elem ? elem->byte_size : 4;
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [index, slice_struct_addr] */
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [index, data_ptr] */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [data_ptr, index] */
usize elem_size = spl_type_elem_stride(elem);
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [index, slice_struct_addr] */
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [index, data_ptr] */
spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [data_ptr, index] */
spl_emit(ctx, SPL_PUSH, SPL_U64, elem_size);
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [data_ptr + index * elem_size] */
spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [data_ptr + index * elem_size] */
}
/* ============================================================
@@ -130,23 +163,40 @@ static void emit_slice_index(spl_comp_t *ctx, spl_type_info_t *elem) {
static int binop_to_sir(spl_tok_type_t t, spl_type_t bt) {
int is_signed = (bt == SPL_I32 || bt == SPL_I64 || bt == SPL_I8 || bt == SPL_I16);
switch (t) {
case TOK_ADD: return SPL_ADD;
case TOK_SUB: return SPL_SUB;
case TOK_MUL: return SPL_MUL;
case TOK_DIV: return is_signed ? SPL_DIV_S : SPL_DIV_U;
case TOK_MOD: return is_signed ? SPL_REM_S : SPL_REM_U;
case TOK_AND: return SPL_AND;
case TOK_OR: return SPL_OR;
case TOK_XOR: return SPL_XOR;
case TOK_L_SH: return SPL_SHL;
case TOK_R_SH: return is_signed ? SPL_SHR_S : SPL_SHR_U;
case TOK_EQ: return SPL_EQ;
case TOK_NEQ: return SPL_NE;
case TOK_LT: return is_signed ? SPL_SLT : SPL_ULT;
case TOK_LE: return is_signed ? SPL_SLE : SPL_ULE;
case TOK_GT: return is_signed ? SPL_SGT : SPL_UGT;
case TOK_GE: return is_signed ? SPL_SGE : SPL_UGE;
default: return -1;
case TOK_ADD:
return SPL_ADD;
case TOK_SUB:
return SPL_SUB;
case TOK_MUL:
return SPL_MUL;
case TOK_DIV:
return is_signed ? SPL_DIV_S : SPL_DIV_U;
case TOK_MOD:
return is_signed ? SPL_REM_S : SPL_REM_U;
case TOK_AND:
return SPL_AND;
case TOK_OR:
return SPL_OR;
case TOK_XOR:
return SPL_XOR;
case TOK_L_SH:
return SPL_SHL;
case TOK_R_SH:
return is_signed ? SPL_SHR_S : SPL_SHR_U;
case TOK_EQ:
return SPL_EQ;
case TOK_NEQ:
return SPL_NE;
case TOK_LT:
return is_signed ? SPL_SLT : SPL_ULT;
case TOK_LE:
return is_signed ? SPL_SLE : SPL_ULE;
case TOK_GT:
return is_signed ? SPL_SGT : SPL_UGT;
case TOK_GE:
return is_signed ? SPL_SGE : SPL_UGE;
default:
return -1;
}
}
@@ -157,11 +207,15 @@ static int binop_to_sir(spl_tok_type_t t, spl_type_t bt) {
static int64_t parse_int(const char *s, usize len) {
char buf[64];
usize clen = len < 63 ? len : 63;
memcpy(buf, s, clen); buf[clen] = '\0';
memcpy(buf, s, clen);
buf[clen] = '\0';
if (clen > 2 && buf[0] == '0') {
if (buf[1] == 'x' || buf[1] == 'X') return (int64_t)strtoll(buf, NULL, 16);
if (buf[1] == 'b' || buf[1] == 'B') return (int64_t)strtoll(buf + 2, NULL, 2);
if (buf[1] == 'o' || buf[1] == 'O') return (int64_t)strtoll(buf + 2, NULL, 8);
if (buf[1] == 'x' || buf[1] == 'X')
return (int64_t)strtoll(buf, NULL, 16);
if (buf[1] == 'b' || buf[1] == 'B')
return (int64_t)strtoll(buf + 2, NULL, 2);
if (buf[1] == 'o' || buf[1] == 'O')
return (int64_t)strtoll(buf + 2, NULL, 8);
}
return (int64_t)strtoll(buf, NULL, 10);
}
@@ -174,7 +228,7 @@ static spl_expr_result_t parse_int_literal(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
int64_t val = parse_int(t->lexeme, t->len);
spl_emit(ctx, SPL_PUSH, SPL_I32, (spl_val_t)val);
spl_expr_result_t r = { spl_type_basic(SPL_I32), 0 };
spl_expr_result_t r = {spl_type_basic(SPL_I32), 0};
return r;
}
@@ -182,11 +236,12 @@ static spl_expr_result_t parse_float_literal(spl_comp_t *ctx) {
spl_tok_t *t = advance(ctx);
char buf[64];
usize clen = t->len < 63 ? t->len : 63;
memcpy(buf, t->lexeme, clen); buf[clen] = '\0';
memcpy(buf, t->lexeme, clen);
buf[clen] = '\0';
double val = strtod(buf, NULL);
spl_emit(ctx, SPL_PUSH, SPL_F64, (spl_val_t)(int64_t)val);
(void)val;
spl_expr_result_t r = { spl_type_basic(SPL_F64), 0 };
spl_expr_result_t r = {spl_type_basic(SPL_F64), 0};
return r;
}
@@ -208,7 +263,7 @@ static spl_expr_result_t parse_char_literal(spl_comp_t *ctx) {
}
}
spl_emit(ctx, SPL_PUSH, SPL_I32, (spl_val_t)val);
spl_expr_result_t r = { spl_type_basic(SPL_I32), 0 };
spl_expr_result_t r = {spl_type_basic(SPL_I32), 0};
return r;
}
@@ -238,7 +293,7 @@ static spl_expr_result_t parse_string_literal(spl_comp_t *ctx) {
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_expr_result_t r = { spl_type_ptr(spl_type_basic(SPL_U8)), 0 };
spl_expr_result_t r = {spl_type_ptr(spl_type_basic(SPL_U8)), 0};
return r;
}
@@ -251,7 +306,8 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
spl_tok_t *len_tok = advance(ctx);
if (len_tok->type != TOK_INT_LITERAL) {
spl_comp_error(ctx, "expected array length");
spl_expr_result_t r = {0}; return r;
spl_expr_result_t r = {0};
return r;
}
usize len = (usize)strtoull(len_tok->lexeme, NULL, 0);
@@ -262,7 +318,8 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
/* Parse element type */
spl_type_info_t *elem_type = spl_parse_type(ctx);
if (!elem_type) {
spl_expr_result_t r = {0}; return r;
spl_expr_result_t r = {0};
return r;
}
skip_nl(ctx);
@@ -272,19 +329,21 @@ static spl_expr_result_t parse_array_literal(spl_comp_t *ctx) {
/* Parse each element value */
for (usize i = 0; i < 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_parse_expr(ctx, PREC_MIN);
skip_nl(ctx);
}
if (peek(ctx)->type == TOK_COMMA) advance(ctx); /* trailing comma */
if (peek(ctx)->type == TOK_COMMA)
advance(ctx); /* trailing comma */
skip_nl(ctx);
expect(ctx, TOK_R_BRACE);
spl_type_info_t *arr_type = spl_type_array(elem_type, len);
return (spl_expr_result_t){ arr_type, 0 };
return (spl_expr_result_t){arr_type, 0};
}
/* Parse a type name with optional .field suffix for enum variants:
@@ -300,7 +359,8 @@ static spl_type_info_t *parse_qualified_type(spl_comp_t *ctx, const char *name)
spl_tok_t *vtok = advance(ctx);
char vname[256];
usize vn = vtok->len < 255 ? vtok->len : 255;
memcpy(vname, vtok->lexeme, vn); vname[vn] = '\0';
memcpy(vname, vtok->lexeme, vn);
vname[vn] = '\0';
/* For enum values, just emit the tag as integer */
if (t->kind == TYPE_ENUM) {
vec_for(t->variants, vi) {
@@ -318,14 +378,16 @@ 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';
memcpy(name, t->lexeme, nlen);
name[nlen] = '\0';
/* Check if it's a function call: ident(...) */
if (peek(ctx)->type == TOK_L_PAREN) {
int fi = spl_lookup_func(ctx, name);
if (fi < 0) {
spl_comp_error(ctx, "unknown function '%s'", name);
spl_expr_result_t r = {0}; return r;
spl_expr_result_t r = {0};
return r;
}
spl_func_info_t *f = &vec_at(ctx->funcs, fi);
advance(ctx); /* skip ( */
@@ -336,7 +398,10 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_expr_result_t arg = spl_parse_expr(ctx, PREC_MIN);
(void)arg;
nargs++;
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); continue; }
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
@@ -347,7 +412,8 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
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;
nidx = (int)ni;
break;
}
}
if (nidx < 0) {
@@ -369,7 +435,7 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_emit(ctx, SPL_CALL, SPL_VOID, nargs);
}
spl_expr_result_t r = { f->ret_type, 0 };
spl_expr_result_t r = {f->ret_type, 0};
return r;
}
@@ -380,7 +446,7 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
spl_val_t cv = 0;
if (map_get(ctx->const_values, name, &cv)) {
spl_emit(ctx, SPL_PUSH, SPL_I32, cv);
spl_expr_result_t r = { v->type, 0 };
spl_expr_result_t r = {v->type, 0};
return r;
}
@@ -392,15 +458,15 @@ static spl_expr_result_t parse_ident(spl_comp_t *ctx) {
/* 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 };
spl_expr_result_t r = {vt, 0};
return r;
}
/* In addr_of_mode, keep address on stack */
spl_expr_result_t r = { vt, 1 };
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 = {vt, 1};
return r;
}
@@ -419,9 +485,11 @@ static spl_expr_result_t parse_group(spl_comp_t *ctx) {
static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
spl_tok_t *op = advance(ctx);
if (op->type == TOK_AND) ctx->addr_of_mode = 1;
if (op->type == TOK_AND)
ctx->addr_of_mode = 1;
spl_expr_result_t right = spl_parse_expr(ctx, PREC_PREFIX);
if (op->type == TOK_AND) ctx->addr_of_mode = 0;
if (op->type == TOK_AND)
ctx->addr_of_mode = 0;
switch (op->type) {
case TOK_SUB:
@@ -453,13 +521,13 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) {
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 };
right = (spl_expr_result_t){elem, 0};
} else {
right = (spl_expr_result_t){ elem, 1 };
right = (spl_expr_result_t){elem, 1};
}
} else {
/* Struct/array/slice: keep address on stack */
right = (spl_expr_result_t){ elem, 1 };
right = (spl_expr_result_t){elem, 1};
}
}
break;
@@ -478,38 +546,55 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
skip_nl(ctx);
spl_tok_t *tok = peek(ctx);
if (!tok) { spl_expr_result_t r = {0}; return r; }
if (!tok) {
spl_expr_result_t r = {0};
return r;
}
spl_expr_result_t left = {0};
switch (tok->type) {
case TOK_INT_LITERAL: left = parse_int_literal(ctx); break;
case TOK_FLOAT_LITERAL: left = parse_float_literal(ctx); break;
case TOK_CHAR_LITERAL: left = parse_char_literal(ctx); break;
case TOK_STRING_LITERAL: left = parse_string_literal(ctx); break;
case TOK_INT_LITERAL:
left = parse_int_literal(ctx);
break;
case TOK_FLOAT_LITERAL:
left = parse_float_literal(ctx);
break;
case TOK_CHAR_LITERAL:
left = parse_char_literal(ctx);
break;
case TOK_STRING_LITERAL:
left = parse_string_literal(ctx);
break;
case KW_TRUE:
advance(ctx);
spl_emit(ctx, SPL_PUSH, SPL_I32, 1);
left = (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
break;
case KW_FALSE:
advance(ctx);
spl_emit(ctx, SPL_PUSH, SPL_I32, 0);
left = (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
break;
case KW_NULL:
advance(ctx);
spl_emit(ctx, SPL_PUSH, SPL_PTR, 0);
left = (spl_expr_result_t){ spl_type_basic(SPL_PTR), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_PTR), 0};
break;
case TOK_IDENT:
case KW_BOOL: case KW_VOID: case KW_ANY:
case KW_BOOL:
case KW_VOID:
case KW_ANY:
left = parse_ident(ctx);
break;
case TOK_L_PAREN:
left = parse_group(ctx);
break;
case TOK_SUB: case TOK_NOT: case TOK_BIT_NOT: case TOK_AND: case TOK_MUL:
case TOK_SUB:
case TOK_NOT:
case TOK_BIT_NOT:
case TOK_AND:
case TOK_MUL:
left = parse_prefix_op(ctx);
break;
case TOK_L_BRACKET:
@@ -526,7 +611,8 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
}
char bname[256];
usize bnlen = tok->len < 255 ? tok->len : 255;
memcpy(bname, tok->lexeme, bnlen); bname[bnlen] = '\0';
memcpy(bname, tok->lexeme, bnlen);
bname[bnlen] = '\0';
advance(ctx); /* consume builtin name */
if (strcmp(bname, "dbg") == 0) {
@@ -538,7 +624,10 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
for (;;) {
spl_parse_expr(ctx, PREC_MIN);
nargs++;
if (peek(ctx)->type == TOK_COMMA) { advance(ctx); continue; }
if (peek(ctx)->type == TOK_COMMA) {
advance(ctx);
continue;
}
break;
}
}
@@ -557,14 +646,15 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
spl_emit(ctx, SPL_DBG, SPL_VOID, 0);
}
/* @dbg is a void expression */
left = (spl_expr_result_t){ spl_type_basic(SPL_VOID), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_VOID), 0};
} else {
spl_comp_error(ctx, "unknown builtin '@%s'", bname);
}
break;
}
default:
/* If it's a keyword-as-type (i32, u8, etc.), parse as function call target or type constructor */
/* If it's a keyword-as-type (i32, u8, etc.), parse as function call target or type
* constructor */
if (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY) {
left = parse_ident(ctx);
} else {
@@ -585,7 +675,8 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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';
memcpy(fname, field->lexeme, fnl);
fname[fnl] = '\0';
/* Check for enum variant: Type.Variant */
if (left.type && left.type->kind == TYPE_ENUM) {
@@ -593,7 +684,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
vec_for(left.type->variants, vi) {
if (strcmp(vec_at(left.type->variants, vi).name, fname) == 0) {
spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(left.type->variants, vi).value);
left = (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
break;
}
}
@@ -616,12 +707,12 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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 };
left = (spl_expr_result_t){ft, 0};
} else {
left = (spl_expr_result_t){ ft, 1 };
left = (spl_expr_result_t){ft, 1};
}
} else {
left = (spl_expr_result_t){ ft, 1 };
left = (spl_expr_result_t){ft, 1};
}
break;
}
@@ -650,12 +741,12 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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 };
left = (spl_expr_result_t){ft, 0};
} else {
left = (spl_expr_result_t){ ft, 1 };
left = (spl_expr_result_t){ft, 1};
}
} else {
left = (spl_expr_result_t){ ft, 1 };
left = (spl_expr_result_t){ft, 1};
}
break;
}
@@ -670,17 +761,20 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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);
left = (spl_expr_result_t){ spl_type_basic(SPL_USIZE), 0 };
left = (spl_expr_result_t){spl_type_basic(SPL_USIZE), 0};
} else if (strcmp(fname, "ptr") == 0) {
/* ptr is at offset 0 */
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
left = (spl_expr_result_t){ left.type->elem ? spl_type_ptr(left.type->elem) : spl_type_basic(SPL_PTR), 0 };
left = (spl_expr_result_t){left.type->elem ? spl_type_ptr(left.type->elem)
: spl_type_basic(SPL_PTR),
0};
}
continue;
}
/* Postfix dereference: expr.* */
if (strcmp(fname, "*") == 0 && left.type && left.type->kind == TYPE_PTR && left.type->elem) {
if (strcmp(fname, "*") == 0 && left.type && left.type->kind == TYPE_PTR &&
left.type->elem) {
if (left.is_lvalue) {
spl_emit(ctx, SPL_LOAD, SPL_PTR, 0);
}
@@ -689,12 +783,12 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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 };
left = (spl_expr_result_t){elem, 0};
} else {
left = (spl_expr_result_t){ elem, 1 };
left = (spl_expr_result_t){elem, 1};
}
} else {
left = (spl_expr_result_t){ elem, 1 };
left = (spl_expr_result_t){elem, 1};
}
continue;
}
@@ -741,7 +835,7 @@ 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 = (left.type->kind == TYPE_ARRAY) ? sizeof(spl_val_t) : (left.type->elem ? left.type->elem->byte_size : 4);
usize stride = spl_type_elem_stride(left.type->elem);
/* For TYPE_SLICE: convert [struct_addr, begin, end] → [data_ptr, begin, end] */
if (left.type->kind == TYPE_SLICE) {
@@ -754,14 +848,15 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
emit_slice_create(ctx, stride);
}
left = (spl_expr_result_t){ left.type ? spl_type_slice(left.type->elem) : NULL, 0 };
left = (spl_expr_result_t){left.type ? spl_type_slice(left.type->elem) : NULL, 0};
continue;
}
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)) {
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) {
@@ -769,9 +864,9 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
* Load data ptr first, then compute element address. */
emit_slice_index(ctx, elem);
} else {
/* Stack arrays: each element occupies a full slot (sizeof(spl_val_t)) */
usize elem_size = (left.type->kind == TYPE_ARRAY) ? sizeof(spl_val_t) : (elem ? elem->byte_size : 4);
spl_emit(ctx, SPL_PUSH, SPL_U64, elem_size);
/* Stack arrays and pointer indexing */
usize stride = spl_type_elem_stride(elem);
spl_emit(ctx, SPL_PUSH, SPL_U64, stride);
spl_emit(ctx, SPL_MUL, SPL_U64, 0);
spl_emit(ctx, SPL_ADD, SPL_U64, 0);
}
@@ -779,12 +874,12 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
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 };
left = (spl_expr_result_t){elem, 0};
} else {
left = (spl_expr_result_t){ elem, 1 };
left = (spl_expr_result_t){elem, 1};
}
} else {
left = (spl_expr_result_t){ elem, 1 };
left = (spl_expr_result_t){elem, 1};
}
}
continue;
@@ -792,7 +887,8 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) {
/* Binary operators */
int prec = tok_prec(opt);
if (prec == 0 || prec < min_prec) break;
if (prec == 0 || prec < min_prec)
break;
advance(ctx);
left = parse_infix(ctx, left, opt);
}
@@ -814,21 +910,21 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
spl_val_t bz_addr = spl_emit_bz(ctx);
spl_expr_result_t right = spl_parse_expr(ctx, next_prec);
spl_patch_to_here(ctx, bz_addr);
return (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
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_expr_result_t right = spl_parse_expr(ctx, next_prec);
spl_patch_to_here(ctx, bnz_addr);
return (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
}
/* Assignment operators */
if (op == TOK_ASSIGN || op == TOK_ASSIGN_ADD || op == TOK_ASSIGN_SUB ||
op == TOK_ASSIGN_MUL || op == TOK_ASSIGN_DIV || op == TOK_ASSIGN_MOD ||
op == TOK_ASSIGN_AND || op == TOK_ASSIGN_OR || op == TOK_ASSIGN_XOR ||
op == TOK_ASSIGN_L_SH || op == TOK_ASSIGN_R_SH) {
if (op == TOK_ASSIGN || op == TOK_ASSIGN_ADD || op == TOK_ASSIGN_SUB || op == TOK_ASSIGN_MUL ||
op == TOK_ASSIGN_DIV || op == TOK_ASSIGN_MOD || op == TOK_ASSIGN_AND ||
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;
@@ -837,20 +933,21 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
ctx->addr_of_mode = saved_addr_of_mode;
if (left.is_lvalue) {
spl_type_t bt = left.type ?
(left.type->kind == TYPE_BASIC ? left.type->basic_type :
left.type->kind == TYPE_PTR ? SPL_PTR : SPL_I32) : SPL_I32;
spl_type_t bt = left.type ? (left.type->kind == TYPE_BASIC ? left.type->basic_type
: left.type->kind == TYPE_PTR ? SPL_PTR
: SPL_I32)
: 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_DUP, SPL_VOID, 0); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
spl_emit(ctx, SPL_DUP, SPL_VOID, 0); /* [addr, rhs, addr] */
spl_emit(ctx, SPL_LOAD, bt, 0); /* [addr, rhs, old_val] */
/* FIXME: compound needs to compute old_val op rhs, then store */
/* For now just drop old_val and store rhs */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [addr, rhs] */
spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [addr, rhs] */
spl_emit(ctx, SPL_STORE, bt, 0);
}
}
@@ -864,5 +961,5 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp
if (sop >= 0) {
spl_emit(ctx, sop, bt, 0);
}
return (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 };
return (spl_expr_result_t){spl_type_basic(SPL_I32), 0};
}

View File

@@ -224,6 +224,12 @@ usize spl_type_slot_count(spl_type_info_t *t) {
return t->slot_count;
}
/* Byte stride between consecutive elements in storage (slot-based layout) */
usize spl_type_elem_stride(spl_type_info_t *elem) {
(void)elem;
return sizeof(spl_val_t);
}
const char *spl_type_str(spl_type_info_t *t) {
if (!t)
return "<null>";