diff --git a/project_desc.py b/project_desc.py index ba92d9a..d9ac56c 100644 --- a/project_desc.py +++ b/project_desc.py @@ -4,10 +4,20 @@ vm = [ "stage0/spl_vm.c", ] +splc0_part = [ + "stage1/spl_comp.c", + "stage1/spl_lexer.c", + "stage1/spl_type.c", + "stage1/spl_parser.c", + "stage1/spl_lex_util.c", + "stage1/spl_expr.c", + "stage1/spl_stmt.c", +] + exe = { "spl_cli": ["stage0/spl_cli.c"] + vm, - "splc_cli": ["stage1/splc_cli.c"] + vm + ["stage1/spl_comp.c", "stage1/spl_lexer.c", "stage1/spl_type.c", "stage1/spl_parser.c", "stage1/spl_lex_util.c", "stage1/spl_expr.c", "stage1/spl_stmt.c"], - "splc0": ["stage1/splc0.c"] + vm + ["stage1/spl_comp.c", "stage1/spl_lexer.c", "stage1/spl_type.c", "stage1/spl_parser.c", "stage1/spl_lex_util.c", "stage1/spl_expr.c", "stage1/spl_stmt.c"], + "splc_cli": ["stage1/splc_cli.c"] + vm + splc0_part, + "splc0": ["stage1/splc0.c"] + vm + splc0_part, "test": ["stage0/test_spl_vm.c"] + vm, "spl_disasm": ["stage0/spl_disasm.c"] + vm, } @@ -35,7 +45,7 @@ pipeline = { } spl = { - "splc1": {"src": "stage1/splc1.spl", "pipeline": "splc0r"}, + "splc1": {"src": "stage2/splc1.spl", "pipeline": "splc0r"}, "splc2": {"src": "stage2/splc2.spl", "pipeline": "splc1r"}, "splc3": {"src": "stage3/splc3.spl", "pipeline": "splc2r"}, "splc4": {"src": "stage4/splc4.spl", "pipeline": "splc3r"}, diff --git a/stage1/spl_comp.h b/stage1/spl_comp.h index 907e130..85b616b 100644 --- a/stage1/spl_comp.h +++ b/stage1/spl_comp.h @@ -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); diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index c3f8685..3111e0b 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -1,39 +1,46 @@ /* spl_expr.c — Expression parser + codegen (Pratt parser / precedence climbing) */ #include "spl_comp.h" +#include #include #include #include -#include /* ============================================================ * 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}; } diff --git a/stage1/spl_type.c b/stage1/spl_type.c index 1851514..73cd409 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -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 "";