diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 834b826..326d01c 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -140,6 +140,8 @@ static int spl_type_size(spl_type_t t) { _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ break; \ case SPL_U64: \ + case SPL_USIZE: \ + case SPL_ISIZE: \ _r = _a OP _b; \ break; \ default: \ @@ -199,6 +201,8 @@ static int spl_type_size(spl_type_t t) { _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ break; \ case SPL_U64: \ + case SPL_USIZE: \ + case SPL_ISIZE: \ _r = (spl_val_t)((int64_t)_a OP(int64_t) _b); \ break; \ default: \ @@ -238,6 +242,8 @@ static int spl_type_size(spl_type_t t) { _r = (spl_val_t)((uint64_t)_a OP(uint64_t) _b); \ break; \ case SPL_U64: \ + case SPL_USIZE: \ + case SPL_ISIZE: \ _r = _a OP _b; \ break; \ default: \ @@ -274,6 +280,8 @@ static int spl_type_size(spl_type_t t) { _r = (int64_t)_a OP(int64_t) _b; \ break; \ case SPL_U64: \ + case SPL_USIZE: \ + case SPL_ISIZE: \ _r = _a OP _b; \ break; \ case SPL_F32: { \ @@ -325,7 +333,9 @@ static int spl_type_size(spl_type_t t) { _r = (int64_t)_a OP(int64_t) _b; \ break; \ case SPL_U64: \ - _r = (int64_t)_a OP(int64_t) _b; \ + case SPL_USIZE: \ + case SPL_ISIZE: \ + _r = _a OP _b; \ break; \ case SPL_F32: { \ float _fa, _fb; \ @@ -376,6 +386,8 @@ static int spl_type_size(spl_type_t t) { _r = (uint64_t)_a OP(uint64_t) _b; \ break; \ case SPL_U64: \ + case SPL_USIZE: \ + case SPL_ISIZE: \ _r = _a OP _b; \ break; \ default: \ diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 9d722c3..eb2cf72 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -97,7 +97,7 @@ static void emit_slice_create(spl_comp_t *ctx, usize stride) { /* --- 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_I32, 0); /* [base, begin, end, ptr, len] */ + 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] */ @@ -442,10 +442,25 @@ static spl_expr_result_t parse_prefix_op(spl_comp_t *ctx) { } break; case TOK_MUL: - /* *expr — dereference: push the pointer value, then load */ - /* right should evaluate to the pointer */ + /* *expr — dereference */ if (right.type && right.type->kind == TYPE_PTR && right.type->elem) { - spl_emit(ctx, SPL_LOAD, right.type->elem->basic_type, 0); + /* 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 }; + } } break; default: @@ -544,15 +559,19 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { if (strcmp(vec_at(left.type->fields, fi).name, fname) == 0) { spl_field_t *f = &vec_at(left.type->fields, fi); if (f->offset > 0) { - spl_emit(ctx, SPL_PUSH, SPL_I32, f->offset); - spl_emit(ctx, SPL_ADD, SPL_I32, 0); + 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) { - 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 }; + 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 }; } @@ -566,21 +585,27 @@ 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; - /* Left has the pointer value on stack. Load it to get the struct address. */ - spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); + /* 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); if (f->offset > 0) { - spl_emit(ctx, SPL_PUSH, SPL_I32, f->offset); - spl_emit(ctx, SPL_ADD, SPL_I32, 0); + 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) { - 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 }; + 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 }; } @@ -596,8 +621,8 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { /* Slice: 2 slots [ptr, len]. len is 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); - spl_emit(ctx, SPL_LOAD, SPL_I32, 0); - left = (spl_expr_result_t){ spl_type_basic(SPL_I32), 0 }; + spl_emit(ctx, SPL_LOAD, 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); @@ -606,22 +631,30 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { continue; } + /* Postfix dereference: expr.* */ + 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); + } + 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 }; + } + continue; + } + spl_comp_error(ctx, "unknown field '%s'", fname); continue; } - /* Postfix deref: expr.* */ - if (opt == TOK_MUL && ctx->tok_idx + 1 < vec_size(ctx->toks) && - peek(ctx)->type == TOK_MUL && vec_at(ctx->toks, ctx->tok_idx + 1).type == TOK_MUL) { - /* Handle .* — actually just * (multiplication) */ - /* The spec defines .* as postfix deref, but in token stream, - * the lexer tokenizes .* as TOK_DOT + TOK_MUL */ - /* Actually, .* is not a multi-char token. Let's check the lexer. */ - /* If we see . then *, it's field access then multiplication? No. */ - /* In .*, we see TOK_DOT then TOK_MUL. But after TOK_DOT we already consumed - * the next token as a field name. So .* doesn't work with the current approach. */ - } - /* Array/slice indexing: expr[expr] or expr[begin..end] */ if (opt == TOK_L_BRACKET) { advance(ctx); /* skip [ */ @@ -654,7 +687,7 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { 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); - spl_emit(ctx, SPL_LOAD, SPL_I32, 0); + spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0); } } @@ -695,9 +728,13 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { spl_emit(ctx, SPL_ADD, SPL_U64, 0); } if (elem && (elem->kind == TYPE_BASIC || elem->kind == TYPE_PTR)) { - 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 }; + 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 }; } @@ -752,7 +789,9 @@ 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 : 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 */ diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index d7a7b15..c05b0dc 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -124,14 +124,16 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { * Store len at slot+1, then ptr at slot. */ spl_emit(ctx, SPL_LADDR, SPL_PTR, slot + 1); spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); - spl_emit(ctx, SPL_STORE, SPL_I32, 0); + spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); spl_emit(ctx, SPL_LADDR, SPL_PTR, slot); spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); spl_emit(ctx, SPL_STORE, SPL_PTR, 0); } else { /* Single value store */ spl_emit(ctx, SPL_LADDR, SPL_PTR, slot); - spl_type_t bt = var_type->kind == TYPE_BASIC ? var_type->basic_type : SPL_I32; + spl_type_t bt = (var_type->kind == TYPE_BASIC) ? var_type->basic_type + : (var_type->kind == TYPE_PTR) ? SPL_PTR + : SPL_I32; spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); spl_emit(ctx, SPL_STORE, bt, 0); } @@ -293,23 +295,23 @@ static void parse_for_stmt(spl_comp_t *ctx) { iname[inl] = '\0'; spl_push_scope(ctx); - int islot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 0); + int islot = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0); /* Stack: [begin, end]; swap so TOS = begin */ spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* Store begin to i */ spl_emit(ctx, SPL_LADDR, SPL_PTR, islot); spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); - spl_emit(ctx, SPL_STORE, SPL_I32, 0); + spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* Stack: [end] */ spl_val_t loop_start = vec_size(ctx->prog.insns); /* Condition: i < end */ spl_emit(ctx, SPL_LADDR, SPL_PTR, islot); - spl_emit(ctx, SPL_LOAD, SPL_I32, 0); + spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0); spl_emit(ctx, SPL_PICK, SPL_VOID, 1); - spl_emit(ctx, SPL_SLT, SPL_I32, 0); + spl_emit(ctx, SPL_ULT, SPL_USIZE, 0); spl_val_t bz_addr = spl_emit_bz(ctx); int saved_loop = ctx->in_loop; @@ -324,10 +326,10 @@ static void parse_for_stmt(spl_comp_t *ctx) { /* Increment: i = i + 1 */ spl_emit(ctx, SPL_LADDR, SPL_PTR, islot); spl_emit(ctx, SPL_LADDR, SPL_PTR, islot); - spl_emit(ctx, SPL_LOAD, SPL_I32, 0); - spl_emit(ctx, SPL_PUSH, SPL_I32, 1); - spl_emit(ctx, SPL_ADD, SPL_I32, 0); - spl_emit(ctx, SPL_STORE, SPL_I32, 0); + spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0); + spl_emit(ctx, SPL_PUSH, SPL_USIZE, 1); + spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); + spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); /* JMP back to condition */ spl_val_t jmp_here = vec_size(ctx->prog.insns); @@ -395,7 +397,7 @@ static void parse_for_stmt(spl_comp_t *ctx) { int idx_slot = -1; if (iname[0]) - idx_slot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 0); + idx_slot = spl_declare_var(ctx, iname, spl_type_basic(SPL_USIZE), 0); spl_type_info_t *elem_type = NULL; if (start_expr.type) { @@ -414,8 +416,8 @@ static void parse_for_stmt(spl_comp_t *ctx) { spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t)); spl_emit(ctx, SPL_ADD, SPL_U64, 0); - spl_emit(ctx, SPL_LOAD, SPL_I32, 0); - spl_emit(ctx, SPL_PUSH, SPL_I32, 0); + spl_emit(ctx, SPL_LOAD, SPL_USIZE, 0); + spl_emit(ctx, SPL_PUSH, SPL_USIZE, 0); /* Stack: [ptr, len, idx=0] */ spl_val_t loop_start = vec_size(ctx->prog.insns); @@ -424,7 +426,7 @@ static void parse_for_stmt(spl_comp_t *ctx) { spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy len */ spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy idx */ spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); /* [idx, len] → [len, idx] → SWAP → [idx, len] */ - spl_emit(ctx, SPL_SLT, SPL_I32, 0); + spl_emit(ctx, SPL_ULT, SPL_USIZE, 0); spl_val_t bz_addr = spl_emit_bz(ctx); /* Store current idx to idx variable */ @@ -432,7 +434,7 @@ static void parse_for_stmt(spl_comp_t *ctx) { spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx (TOS) */ spl_emit(ctx, SPL_LADDR, SPL_PTR, idx_slot); spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); - spl_emit(ctx, SPL_STORE, SPL_I32, 0); + spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); } /* Load slice[idx] and store to val */ @@ -459,8 +461,8 @@ static void parse_for_stmt(spl_comp_t *ctx) { /* Increment idx */ spl_emit(ctx, SPL_PICK, SPL_VOID, 0); /* copy idx */ - spl_emit(ctx, SPL_PUSH, SPL_I32, 1); - spl_emit(ctx, SPL_ADD, SPL_I32, 0); + spl_emit(ctx, SPL_PUSH, SPL_USIZE, 1); + spl_emit(ctx, SPL_ADD, SPL_USIZE, 0); spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* replace old idx with new */ @@ -629,14 +631,23 @@ static void parse_expr_stmt(spl_comp_t *ctx) { int prev = ctx->tok_idx; - /* Look ahead past newlines for assignment operator */ + /* Look ahead for assignment operator (scan past expression tokens) */ int is_assign = 0; - if (peek(ctx)->type == TOK_IDENT) { - usize look = ctx->tok_idx + 1; - while (look < vec_size(ctx->toks) && vec_at(ctx->toks, look).type == TOK_ENDLINE) + { + usize look = ctx->tok_idx; + while (look < vec_size(ctx->toks)) { + spl_tok_type_t t = vec_at(ctx->toks, look).type; + if (t == TOK_SEMICOLON || t == TOK_ENDLINE || t == TOK_L_BRACE || t == TOK_R_BRACE || + t == TOK_EOF) + break; + if (t == TOK_L_PAREN) + break; /* function call, not assignment */ + if (is_assign_op(t)) { + is_assign = 1; + break; + } look++; - if (look < vec_size(ctx->toks)) - is_assign = is_assign_op(vec_at(ctx->toks, look).type); + } } if (is_assign)