From 67c8a137ddaa079f239de1c4644e5705539c478b Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Sun, 5 Jul 2026 22:47:00 +0800 Subject: [PATCH] =?UTF-8?q?stage1=20=E5=AE=9E=E7=8E=B006=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- stage1/spl_expr.c | 23 ++- stage1/spl_lex_util.c | 9 +- stage1/spl_lexer.c | 1 - stage1/spl_parser.c | 98 ++++++++---- stage1/spl_stmt.c | 363 +++++++++++++++++++++++++++++++----------- stage1/spl_type.c | 3 +- 6 files changed, 365 insertions(+), 132 deletions(-) diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 93b48b3..9d722c3 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -638,18 +638,37 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { is_slice = 1; advance(ctx); /* skip .. */ spl_expr_result_t end_expr = {0}; - if (peek(ctx)->type != TOK_R_BRACKET) { + int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET); + if (has_explicit_end) { end_expr = spl_parse_expr(ctx, PREC_MIN); } 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); + spl_emit(ctx, SPL_LOAD, SPL_I32, 0); + } + } + /* 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); - /* For TYPE_SLICE, load data ptr from slice struct first */ + /* For TYPE_SLICE: convert [struct_addr, begin, end] → [data_ptr, begin, end] */ if (left.type->kind == TYPE_SLICE) { + spl_emit(ctx, SPL_PICK, SPL_VOID, 2); spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); + spl_emit(ctx, SPL_ROT, SPL_VOID, 0); + spl_emit(ctx, SPL_ROT, SPL_VOID, 0); + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); } emit_slice_create(ctx, stride); diff --git a/stage1/spl_lex_util.c b/stage1/spl_lex_util.c index 84a5fb0..962077a 100644 --- a/stage1/spl_lex_util.c +++ b/stage1/spl_lex_util.c @@ -2,13 +2,12 @@ #include "spl_lexer.h" #include -#include #include const char *spl_tok_type_name(spl_tok_type_t type) { switch (type) { -#define X(name, enum_name, dummy) \ - case enum_name: \ +#define X(name, enum_name, dummy) \ + case enum_name: \ return #name; KEYWORD_TABLE TOKEN_TABLE @@ -33,9 +32,7 @@ void spl_tok_dump(spl_tok_t *tok) { buf[i] = ' '; } - printf("%s:%zu:%zu %-20s '%s'", - tok->fname ? tok->fname : "", - tok->line, tok->col, + printf("%s:%zu:%zu %-20s '%s'", tok->fname ? tok->fname : "", tok->line, tok->col, spl_tok_type_name(tok->type), buf); if (tok->type == TOK_INT_LITERAL) { diff --git a/stage1/spl_lexer.c b/stage1/spl_lexer.c index e06e5de..3beaa10 100644 --- a/stage1/spl_lexer.c +++ b/stage1/spl_lexer.c @@ -2,7 +2,6 @@ #include "spl_lexer.h" #include -#include #include #include diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c index 6b5f2e5..47350ca 100644 --- a/stage1/spl_parser.c +++ b/stage1/spl_parser.c @@ -1,28 +1,30 @@ /* spl_parser.c — Top-level parser: function declarations, type declarations, etc. */ #include "spl_comp.h" -#include -#include #include -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 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; } static void skip_nl(spl_comp_t *ctx) { - while (peek(ctx)->type == TOK_ENDLINE) advance(ctx); + while (peek(ctx)->type == TOK_ENDLINE) + advance(ctx); } /* ============================================================ @@ -38,7 +40,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { spl_tok_t *fname_tok = advance(ctx); char fn_name[256]; usize fnl = fname_tok->len < 255 ? fname_tok->len : 255; - memcpy(fn_name, fname_tok->lexeme, fnl); fn_name[fnl] = '\0'; + memcpy(fn_name, fname_tok->lexeme, fnl); + fn_name[fnl] = '\0'; skip_nl(ctx); expect(ctx, TOK_L_PAREN); @@ -65,8 +68,15 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { } nparams++; skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); continue; } - if (peek(ctx)->type == TOK_ELLIPSIS) { advance(ctx); skip_nl(ctx); } + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + skip_nl(ctx); + continue; + } + if (peek(ctx)->type == TOK_ELLIPSIS) { + advance(ctx); + skip_nl(ctx); + } break; } } @@ -77,7 +87,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { spl_type_info_t *ret_type = spl_type_basic(SPL_VOID); if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) { ret_type = spl_parse_type(ctx); - if (!ret_type) ret_type = spl_type_basic(SPL_VOID); + if (!ret_type) + ret_type = spl_type_basic(SPL_VOID); skip_nl(ctx); } @@ -88,7 +99,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { int found = -1; vec_for(ctx->prog.natives, ni) { if (strcmp(vec_at(ctx->prog.natives, ni).name, fn_name) == 0) { - found = (int)ni; break; + found = (int)ni; + break; } } if (found < 0) { @@ -99,7 +111,8 @@ static void parse_fn_decl(spl_comp_t *ctx, int is_extern, int is_pub) { nat.impl_fn = NULL; /* resolved by VM at runtime */ vec_push(ctx->prog.natives, nat); } - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); return; } @@ -170,7 +183,8 @@ void parse_type_decl(spl_comp_t *ctx) { spl_tok_t *name_tok = advance(ctx); char tname[256]; usize tnl = name_tok->len < 255 ? name_tok->len : 255; - memcpy(tname, name_tok->lexeme, tnl); tname[tnl] = '\0'; + memcpy(tname, name_tok->lexeme, tnl); + tname[tnl] = '\0'; skip_nl(ctx); expect(ctx, TOK_ASSIGN); @@ -192,13 +206,18 @@ void parse_type_decl(spl_comp_t *ctx) { spl_type_info_t *ftype = spl_parse_type(ctx); char fname[256]; usize fnl = ftok->len < 255 ? ftok->len : 255; - memcpy(fname, ftok->lexeme, fnl); fname[fnl] = '\0'; + memcpy(fname, ftok->lexeme, fnl); + fname[fnl] = '\0'; spl_type_add_field(st, fname, ftype); } skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); } + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + skip_nl(ctx); + } } - if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); + if (peek(ctx)->type == TOK_R_BRACE) + advance(ctx); } spl_type_compute_layout(st); map_put(ctx->type_defs, strdup(tname), st); @@ -218,22 +237,29 @@ void parse_type_decl(spl_comp_t *ctx) { spl_type_info_t *dtype = spl_parse_type(ctx); char vname[256]; usize vnl = vtok->len < 255 ? vtok->len : 255; - memcpy(vname, vtok->lexeme, vnl); vname[vnl] = '\0'; + memcpy(vname, vtok->lexeme, vnl); + vname[vnl] = '\0'; spl_type_add_variant(et, vname, dtype); } else { char vname[256]; usize vnl = vtok->len < 255 ? vtok->len : 255; - memcpy(vname, vtok->lexeme, vnl); vname[vnl] = '\0'; + memcpy(vname, vtok->lexeme, vnl); + vname[vnl] = '\0'; spl_type_add_variant(et, vname, NULL); } skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); } + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + skip_nl(ctx); + } } - if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); + if (peek(ctx)->type == TOK_R_BRACE) + advance(ctx); } spl_type_compute_layout(et); map_put(ctx->type_defs, strdup(tname), et); - } else if (peek(ctx)->type == TOK_IDENT || (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) { + } else if (peek(ctx)->type == TOK_IDENT || + (peek(ctx)->type >= KW_AS && peek(ctx)->type <= KW_ANY)) { spl_type_info_t *base = spl_parse_type(ctx); if (base) { spl_type_info_t *alias = spl_type_clone(base); @@ -244,7 +270,8 @@ void parse_type_decl(spl_comp_t *ctx) { } skip_nl(ctx); - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } /* ============================================================ @@ -254,7 +281,8 @@ void parse_type_decl(spl_comp_t *ctx) { void spl_parse_prog(spl_comp_t *ctx) { while (peek(ctx)->type != TOK_EOF) { skip_nl(ctx); - if (peek(ctx)->type == TOK_EOF) break; + if (peek(ctx)->type == TOK_EOF) + break; switch (peek(ctx)->type) { case KW_FN: @@ -266,8 +294,10 @@ void spl_parse_prog(spl_comp_t *ctx) { case KW_PUB: { advance(ctx); /* skip pub */ skip_nl(ctx); - if (peek(ctx)->type == KW_FN) parse_fn_decl(ctx, 0, 1); - else if (peek(ctx)->type == KW_TYPE) parse_type_decl(ctx); + if (peek(ctx)->type == KW_FN) + parse_fn_decl(ctx, 0, 1); + else if (peek(ctx)->type == KW_TYPE) + parse_type_decl(ctx); break; } case TOK_SHARP: @@ -275,18 +305,22 @@ void spl_parse_prog(spl_comp_t *ctx) { advance(ctx); /* # */ if (peek(ctx)->type == TOK_L_BRACKET) { advance(ctx); /* [ */ - while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) advance(ctx); - if (peek(ctx)->type == TOK_R_BRACKET) advance(ctx); + while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) + advance(ctx); + if (peek(ctx)->type == TOK_R_BRACKET) + advance(ctx); } skip_nl(ctx); - if (peek(ctx)->type == KW_FN) parse_fn_decl(ctx, 1, 0); + if (peek(ctx)->type == KW_FN) + parse_fn_decl(ctx, 1, 0); break; default: { int prev = ctx->tok_idx; /* Try to parse as a statement */ spl_parse_stmt(ctx); /* Safety: prevent infinite loop on unrecognized tokens */ - if (ctx->tok_idx == prev) advance(ctx); + if (ctx->tok_idx == prev) + advance(ctx); break; } } diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index f01b6f4..d7a7b15 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -1,33 +1,39 @@ /* spl_stmt.c — Statement parser + codegen */ #include "spl_comp.h" -#include #include #include -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 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; } 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 void skip_nl(spl_comp_t *ctx) { - while (peek(ctx)->type == TOK_ENDLINE) advance(ctx); + while (peek(ctx)->type == TOK_ENDLINE) + advance(ctx); } /* ============================================================ @@ -48,7 +54,8 @@ static void parse_ret_stmt(spl_comp_t *ctx) { spl_type_t rt = ctx->current_ret_type ? ctx->current_ret_type->basic_type : SPL_VOID; spl_emit(ctx, SPL_RET, rt, 0); } - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } /* ============================================================ @@ -62,7 +69,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { spl_tok_t *name_tok = advance(ctx); char vname[256]; usize nlen = name_tok->len < 255 ? name_tok->len : 255; - memcpy(vname, name_tok->lexeme, nlen); vname[nlen] = '\0'; + memcpy(vname, name_tok->lexeme, nlen); + vname[nlen] = '\0'; spl_type_info_t *var_type = NULL; int has_init = 0; @@ -84,12 +92,15 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { if (peek(ctx)->type == TOK_COLON_ASSIGN || peek(ctx)->type == TOK_ASSIGN) { has_init = 1; - if (peek(ctx)->type == TOK_COLON_ASSIGN) advance(ctx); - else advance(ctx); /* = */ + if (peek(ctx)->type == TOK_COLON_ASSIGN) + advance(ctx); + else + advance(ctx); /* = */ } /* Allocate stack slot */ - if (!var_type) var_type = spl_type_basic(SPL_I32); /* default type */ + if (!var_type) + var_type = spl_type_basic(SPL_I32); /* default type */ int slot = spl_declare_var(ctx, vname, var_type, is_const); skip_nl(ctx); @@ -126,7 +137,8 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { } } - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } /* ============================================================ @@ -145,7 +157,8 @@ void spl_parse_block(spl_comp_t *ctx) { } spl_pop_scope(ctx); - if (peek(ctx)->type == TOK_R_BRACE) advance(ctx); + if (peek(ctx)->type == TOK_R_BRACE) + advance(ctx); } else { /* Single statement */ spl_parse_stmt(ctx); @@ -257,68 +270,218 @@ static void parse_for_stmt(spl_comp_t *ctx) { skip_nl(ctx); /* Parse the iteration expression(s) */ - spl_expr_result_t start = spl_parse_expr(ctx, PREC_MIN); - (void)start; + spl_expr_result_t start_expr = spl_parse_expr(ctx, PREC_MIN); if (peek(ctx)->type == TOK_RANGE) { - /* for begin..end as i { body } */ - advance(ctx); /* .. */ - spl_expr_result_t end = spl_parse_expr(ctx, PREC_MIN); - (void)end; + /* ===== Numeric range: for begin..end as i { body } ===== */ + advance(ctx); /* .. */ + spl_parse_expr(ctx, PREC_MIN); /* end expression */ + /* Stack: [begin, end] */ skip_nl(ctx); - if (peek(ctx)->type == KW_AS) { - advance(ctx); /* as */ - spl_tok_t *ivar = advance(ctx); - char iname[256]; - usize inl = ivar->len < 255 ? ivar->len : 255; - memcpy(iname, ivar->lexeme, inl); iname[inl] = '\0'; - - /* Declare loop variable */ - spl_type_info_t *itype = spl_type_basic(SPL_I32); - int islot = spl_declare_var(ctx, iname, itype, 0); - - /* The loop variable was already set up by the range operator */ - /* Store initial value */ - /* For now: we need to emit proper loop code. This is a simplification. */ - int saved_loop = ctx->in_loop; - usize saved_continue = ctx->continue_target; - usize saved_bp_count = ctx->break_patch_count; - - ctx->in_loop = 1; - ctx->continue_target = 0; /* will set after store */ - - /* Loop: store begin to i, check i < end, body, i++ */ - /* Stack has: begin, end (from parsing the range expression) */ - /* Actually we need to emit proper code here. For bootstrap, - let me just handle the simple numeric for loop. */ - - /* For now, emit a basic loop body */ + if (peek(ctx)->type != KW_AS) { + skip_nl(ctx); spl_parse_block(ctx); + return; + } + advance(ctx); /* as */ + + spl_tok_t *ivar = advance(ctx); + char iname[256]; + usize inl = ivar->len < 255 ? ivar->len : 255; + memcpy(iname, ivar->lexeme, inl); + iname[inl] = '\0'; + + spl_push_scope(ctx); + int islot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 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); + /* 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_PICK, SPL_VOID, 1); + spl_emit(ctx, SPL_SLT, SPL_I32, 0); + spl_val_t bz_addr = spl_emit_bz(ctx); + + int saved_loop = ctx->in_loop; + usize saved_continue = ctx->continue_target; + usize saved_bp_count = ctx->break_patch_count; + ctx->in_loop = 1; + ctx->continue_target = loop_start; - ctx->in_loop = saved_loop; - ctx->continue_target = saved_continue; - ctx->break_patch_count = saved_bp_count; - } - } else if (peek(ctx)->type == TOK_COMMA) { - /* for slice, 0.. as val, idx { body } — skip for now */ - advance(ctx); /* , */ - spl_parse_expr(ctx, PREC_MIN); /* skip the range */ - if (peek(ctx)->type == KW_AS) { - advance(ctx); - advance(ctx); /* val */ - if (peek(ctx)->type == TOK_COMMA) { - advance(ctx); - advance(ctx); /* idx */ - } - } skip_nl(ctx); - spl_parse_block(ctx); - } else { - /* for ident in ... — skip */ - skip_nl(ctx); - spl_parse_block(ctx); + spl_parse_block(ctx); /* body */ + + /* 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); + + /* JMP back to condition */ + spl_val_t jmp_here = vec_size(ctx->prog.insns); + spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)jmp_here - 1)); + + /* Exit: patch bz, drop end */ + spl_patch_to_here(ctx, bz_addr); + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); + + /* Patch breaks */ + for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) + spl_patch_to_here(ctx, ctx->break_patches[i]); + ctx->break_patch_count = saved_bp_count; + ctx->in_loop = saved_loop; + ctx->continue_target = saved_continue; + + spl_pop_scope(ctx); + return; } + + /* ===== Slice iteration: for slice [as val |, range as val, idx] ===== */ + int has_idx = 0; + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); /* , */ + spl_parse_expr(ctx, PREC_MIN); /* parse start of range (e.g. 0) */ + if (peek(ctx)->type == TOK_RANGE) { + advance(ctx); /* .. */ + /* consume optional end expression */ + if (peek(ctx)->type != KW_AS && peek(ctx)->type != TOK_COMMA && + peek(ctx)->type != TOK_L_BRACE && peek(ctx)->type != TOK_ENDLINE && + peek(ctx)->type != TOK_EOF) + spl_parse_expr(ctx, PREC_MIN); + } + has_idx = 1; + /* Range pushed a value; we manage our own idx, drop it */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); + } + + if (peek(ctx)->type != KW_AS) { + skip_nl(ctx); + spl_parse_block(ctx); + return; + } + advance(ctx); /* as */ + + /* Parse val variable name */ + 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'; + + /* Parse optional idx variable name */ + char iname[256] = {0}; + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + spl_tok_t *itok = advance(ctx); + usize inl = itok->len < 255 ? itok->len : 255; + memcpy(iname, itok->lexeme, inl); + iname[inl] = '\0'; + } + + /* Stack: [slice_addr] or whatever the slice expression left */ + spl_push_scope(ctx); + + int idx_slot = -1; + if (iname[0]) + idx_slot = spl_declare_var(ctx, iname, spl_type_basic(SPL_I32), 0); + + spl_type_info_t *elem_type = NULL; + if (start_expr.type) { + if (start_expr.type->kind == TYPE_SLICE) + elem_type = start_expr.type->elem; + else if (start_expr.type->kind == TYPE_PTR && start_expr.type->elem) + elem_type = start_expr.type->elem; + } + if (!elem_type) + elem_type = spl_type_basic(SPL_I32); + int val_slot = spl_declare_var(ctx, vname, elem_type, 0); + + /* Extract ptr and len from slice, push index=0: stack [ptr, len, idx] */ + spl_emit(ctx, SPL_DUP, SPL_VOID, 0); + spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); + 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); + /* Stack: [ptr, len, idx=0] */ + + spl_val_t loop_start = vec_size(ctx->prog.insns); + + /* Condition: idx < len */ + 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_val_t bz_addr = spl_emit_bz(ctx); + + /* Store current idx to idx variable */ + if (idx_slot >= 0) { + 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); + } + + /* Load slice[idx] and store to val */ + spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* copy ptr: [ptr, len, idx, ptr] */ + spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* copy idx: [ptr, len, idx, ptr, idx] */ + usize elem_byte_size = (elem_type && elem_type->byte_size) ? elem_type->byte_size : 4; + spl_emit(ctx, SPL_PUSH, SPL_U64, sizeof(spl_val_t)); + spl_emit(ctx, SPL_MUL, SPL_U64, 0); + spl_emit(ctx, SPL_ADD, SPL_U64, 0); + spl_emit(ctx, SPL_LOAD, SPL_I32, 0); + spl_emit(ctx, SPL_LADDR, SPL_PTR, val_slot); + spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); + spl_emit(ctx, SPL_STORE, SPL_I32, 0); + + /* Loop context */ + int saved_loop = ctx->in_loop; + usize saved_continue = ctx->continue_target; + usize saved_bp_count = ctx->break_patch_count; + ctx->in_loop = 1; + ctx->continue_target = loop_start; + + skip_nl(ctx); + spl_parse_block(ctx); /* body */ + + /* 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_SWAP, SPL_VOID, 0); + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* replace old idx with new */ + + /* JMP back to condition */ + spl_val_t jmp_here = vec_size(ctx->prog.insns); + spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)loop_start - (isize)jmp_here - 1)); + + /* Exit: patch bz, drop idx, len, ptr */ + spl_patch_to_here(ctx, bz_addr); + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop idx */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop len */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* drop ptr */ + + /* Patch breaks */ + for (usize i = saved_bp_count; i < ctx->break_patch_count; i++) + spl_patch_to_here(ctx, ctx->break_patches[i]); + ctx->break_patch_count = saved_bp_count; + ctx->in_loop = saved_loop; + ctx->continue_target = saved_continue; + + spl_pop_scope(ctx); } /* ============================================================ @@ -338,7 +501,8 @@ static void parse_break_stmt(spl_comp_t *ctx) { ctx->break_patch_cap = new_cap; } ctx->break_patches[ctx->break_patch_count++] = addr; - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } static void parse_continue_stmt(spl_comp_t *ctx) { @@ -349,7 +513,8 @@ static void parse_continue_stmt(spl_comp_t *ctx) { /* Emit JMP with relative offset to continue_target */ spl_val_t here = vec_size(ctx->prog.insns); spl_emit(ctx, SPL_JMP, SPL_VOID, (spl_val_t)((isize)ctx->continue_target - (isize)here - 1)); - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } /* ============================================================ @@ -379,8 +544,10 @@ static void parse_extern_decl(spl_comp_t *ctx) { advance(ctx); /* # */ expect(ctx, TOK_L_BRACKET); /* Skip extern("vm") or just look for fn */ - while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) advance(ctx); - if (peek(ctx)->type == TOK_R_BRACKET) advance(ctx); + while (peek(ctx)->type != TOK_R_BRACKET && peek(ctx)->type != TOK_EOF) + advance(ctx); + if (peek(ctx)->type == TOK_R_BRACKET) + advance(ctx); skip_nl(ctx); @@ -390,7 +557,8 @@ static void parse_extern_decl(spl_comp_t *ctx) { spl_tok_t *fname_tok = advance(ctx); char fn_name[256]; usize fnl = fname_tok->len < 255 ? fname_tok->len : 255; - memcpy(fn_name, fname_tok->lexeme, fnl); fn_name[fnl] = '\0'; + memcpy(fn_name, fname_tok->lexeme, fnl); + fn_name[fnl] = '\0'; skip_nl(ctx); expect(ctx, TOK_L_PAREN); @@ -409,8 +577,15 @@ static void parse_extern_decl(spl_comp_t *ctx) { } nparams++; skip_nl(ctx); - if (peek(ctx)->type == TOK_COMMA) { advance(ctx); skip_nl(ctx); continue; } - if (peek(ctx)->type == TOK_ELLIPSIS) { advance(ctx); skip_nl(ctx); } /* variadic */ + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + skip_nl(ctx); + continue; + } + if (peek(ctx)->type == TOK_ELLIPSIS) { + advance(ctx); + skip_nl(ctx); + } /* variadic */ break; } } @@ -421,13 +596,15 @@ static void parse_extern_decl(spl_comp_t *ctx) { spl_type_info_t *ret_type = spl_type_basic(SPL_VOID); if (peek(ctx)->type != TOK_SEMICOLON && peek(ctx)->type != TOK_L_BRACE) { ret_type = spl_parse_type(ctx); - if (!ret_type) ret_type = spl_type_basic(SPL_VOID); + if (!ret_type) + ret_type = spl_type_basic(SPL_VOID); skip_nl(ctx); } spl_declare_func(ctx, fn_name, ret_type, nparams, 1, 0); - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); } } @@ -437,10 +614,10 @@ static void parse_extern_decl(spl_comp_t *ctx) { /* Check if token type is an assignment operator */ static int is_assign_op(spl_tok_type_t t) { - return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB || - t == TOK_ASSIGN_MUL || t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD || - t == TOK_ASSIGN_AND || t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR || - t == TOK_ASSIGN_L_SH || t == TOK_ASSIGN_R_SH; + return t == TOK_ASSIGN || t == TOK_ASSIGN_ADD || t == TOK_ASSIGN_SUB || t == TOK_ASSIGN_MUL || + t == TOK_ASSIGN_DIV || t == TOK_ASSIGN_MOD || t == TOK_ASSIGN_AND || + t == TOK_ASSIGN_OR || t == TOK_ASSIGN_XOR || t == TOK_ASSIGN_L_SH || + t == TOK_ASSIGN_R_SH; } static void parse_expr_stmt(spl_comp_t *ctx) { @@ -462,14 +639,19 @@ static void parse_expr_stmt(spl_comp_t *ctx) { is_assign = is_assign_op(vec_at(ctx->toks, look).type); } - if (is_assign) ctx->addr_of_mode = 1; + if (is_assign) + ctx->addr_of_mode = 1; spl_expr_result_t expr = spl_parse_expr(ctx, PREC_MIN); - if (is_assign) ctx->addr_of_mode = 0; + if (is_assign) + ctx->addr_of_mode = 0; - if (!is_assign && expr.type) spl_emit(ctx, SPL_DROP, SPL_VOID, 0); - if (peek(ctx)->type == TOK_SEMICOLON) advance(ctx); + if (!is_assign && expr.type) + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); + if (peek(ctx)->type == TOK_SEMICOLON) + advance(ctx); /* Safety: if no token was consumed, advance to prevent infinite loop */ - if (ctx->tok_idx == prev) advance(ctx); + if (ctx->tok_idx == prev) + advance(ctx); } /* ============================================================ @@ -479,7 +661,8 @@ static void parse_expr_stmt(spl_comp_t *ctx) { void spl_parse_stmt(spl_comp_t *ctx) { skip_nl(ctx); - if (peek(ctx)->type == TOK_EOF || peek(ctx)->type == TOK_R_BRACE) return; + if (peek(ctx)->type == TOK_EOF || peek(ctx)->type == TOK_R_BRACE) + return; switch (peek(ctx)->type) { case KW_RET: @@ -521,7 +704,7 @@ void spl_parse_stmt(spl_comp_t *ctx) { case TOK_LINE_COMMENT: advance(ctx); break; -case TOK_SHARP: /* #[extern(...)] */ + case TOK_SHARP: /* #[extern(...)] */ parse_extern_decl(ctx); break; default: diff --git a/stage1/spl_type.c b/stage1/spl_type.c index fd5157d..1851514 100644 --- a/stage1/spl_type.c +++ b/stage1/spl_type.c @@ -391,7 +391,8 @@ spl_type_info_t *spl_parse_type(spl_comp_t *ctx) { } spl_type_info_t *spl_resolve_type(spl_comp_t *ctx, const char *name) { - if (!ctx || !name) return NULL; + if (!ctx || !name) + return NULL; spl_type_info_t *found = NULL; map_get(ctx->type_defs, name, &found); return found;