diff --git a/stage0/spl_ir.c b/stage0/spl_ir.c index c278ac4..5ece8dc 100644 --- a/stage0/spl_ir.c +++ b/stage0/spl_ir.c @@ -207,7 +207,7 @@ int spl_prog_load_from_file(const char *fname, spl_prog_t *prog) { int spl_prog_store_to_file(const char *fname, spl_prog_t *prog) { unsigned char *buf, *p; - int i; + spl_val_t i; size_t total; spl_val_t nfuncs, ninsns, nnatives, nstrs, ndata; usize nlen, pad; diff --git a/stage0/spl_syscall.c b/stage0/spl_syscall.c index 5d21576..52256ff 100644 --- a/stage0/spl_syscall.c +++ b/stage0/spl_syscall.c @@ -180,7 +180,7 @@ static spl_val_t vm_printf(int nargs, spl_val_t *args) { int arg_idx = 0; char tmp_buf[32]; memset(tmp_buf, 0, sizeof(tmp_buf)); - for (int i = 0; i < fmt_len; ++i) { + for (usize i = 0; i < fmt_len; ++i) { if (fmt[i] != '%') { vec_push(buffer, fmt[i]); continue; @@ -192,7 +192,7 @@ static spl_val_t vm_printf(int nargs, spl_val_t *args) { switch (fmt[i]) { case 'd': snprintf(tmp_buf, sizeof(tmp_buf), "%zd", args[arg_idx]); - for (int j = 0; j < strlen(tmp_buf); ++j) { + for (usize j = 0; j < strlen(tmp_buf); ++j) { vec_push(buffer, tmp_buf[j]); } break; @@ -200,7 +200,7 @@ static spl_val_t vm_printf(int nargs, spl_val_t *args) { vec_push(buffer, (char)args[arg_idx]); break; case 's': - for (int j = 0; j < strlen((const char *)args[arg_idx]); ++j) { + for (usize j = 0; j < strlen((const char *)args[arg_idx]); ++j) { vec_push(buffer, ((const char *)args[arg_idx])[j]); } break; diff --git a/stage0/spl_vm.c b/stage0/spl_vm.c index 12a5f41..f794f8f 100644 --- a/stage0/spl_vm.c +++ b/stage0/spl_vm.c @@ -76,10 +76,10 @@ static int spl_type_size(spl_type_t t) { do { \ if (vm->sp >= vm->config.max_stack_depth) \ VM_ERROR("stack overflow"); \ - vm->stacks.data[vm->sp++] = (spl_val_t)(v); \ + vm->stacks.data[(vm->sp)++] = (spl_val_t)(v); \ } while (0) -#define POP() vm->stacks.data[--vm->sp] +#define POP() vm->stacks.data[--(vm->sp)] /* ================================================================ * Type-dispatch macros for arithmetic / comparison @@ -641,7 +641,7 @@ int spl_vm_run_once(spl_vm_t *vm) { return -1; prog = vm->prog; - if (vm->ip < 0 || vm->ip >= vec_size(prog->insns)) { + if (vm->ip >= vec_size(prog->insns)) { fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); vm->exit_code = 1; return -1; @@ -687,7 +687,7 @@ int spl_vm_run_once(spl_vm_t *vm) { case SPL_PICK: { isize _idx = ins->imm; - if (_idx >= vm->sp) + if ((usize)_idx >= vm->sp) VM_ERROR("PICK: index out of range"); PUSH(vm->stacks.data[vm->sp - 1 - _idx]); break; diff --git a/stage1/spl_expr.c b/stage1/spl_expr.c index 5fef9d7..6a2207c 100644 --- a/stage1/spl_expr.c +++ b/stage1/spl_expr.c @@ -6,16 +6,6 @@ #include #include -/* ============================================================ - * Token helpers - * ============================================================ */ - -/* Check if current token starts a statement */ -static int is_stmt_start(spl_comp_t *ctx) { - spl_tok_type_t t = peek(ctx)->type; - return t == TOK_EOF || t == TOK_R_BRACE ? 0 : 1; -} - /* ============================================================ * Precedence table * ============================================================ */ @@ -71,7 +61,6 @@ static int tok_prec(spl_tok_type_t t) { * Forward declarations * ============================================================ */ -static spl_expr_result_t parse_prefix(spl_comp_t *ctx); static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, spl_tok_type_t op); /* Slice creation from array/slice range expression. @@ -544,29 +533,6 @@ static spl_expr_result_t parse_struct_literal(spl_comp_t *ctx, spl_type_info_t * return (spl_expr_result_t){type, 1}; /* address on stack */ } } -static spl_type_info_t *parse_qualified_type(spl_comp_t *ctx, const char *name) { - /* Check if it's a known type */ - spl_type_info_t *t = spl_resolve_type(ctx, name); - if (t && peek(ctx)->type == TOK_DOT) { - /* Enum type with variant: Type.variant */ - advance(ctx); /* skip . */ - 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'; - /* For enum values, just emit the tag as integer */ - if (t->kind == TYPE_ENUM) { - vec_for(t->variants, vi) { - if (strcmp(vec_at(t->variants, vi).name, vname) == 0) { - spl_emit(ctx, SPL_PUSH, SPL_I32, vec_at(t->variants, vi).value); - break; - } - } - } - } - return t; -} static spl_expr_result_t parse_ident(spl_comp_t *ctx) { spl_tok_t *t = advance(ctx); @@ -1045,16 +1011,14 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { } else if (strcmp(fname, "ptr") == 0) { if (ctx->addr_of_mode) { /* lvalue: ptr is at offset 0, address already on stack */ - left = (spl_expr_result_t){ - left.type->elem ? spl_type_ptr(left.type->elem) - : spl_type_basic(SPL_PTR), - 1}; + left = (spl_expr_result_t){left.type->elem ? spl_type_ptr(left.type->elem) + : spl_type_basic(SPL_PTR), + 1}; } else { 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; @@ -1094,11 +1058,8 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { } /* Check for slice: expr[begin..end] or expr[begin..] */ - int is_slice = 0; - usize slice_start = ctx->tok_idx; spl_expr_result_t index = spl_parse_expr(ctx, PREC_MIN); if (peek(ctx)->type == TOK_RANGE) { - is_slice = 1; advance(ctx); /* skip .. */ spl_expr_result_t end_expr = {0}; int has_explicit_end = (peek(ctx)->type != TOK_R_BRACKET); @@ -1125,16 +1086,28 @@ spl_expr_result_t spl_parse_expr(spl_comp_t *ctx, int min_prec) { if (left.type && (left.type->kind == TYPE_ARRAY || left.type->kind == TYPE_SLICE)) { 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) { + /* Stack: [struct_addr, begin, end]. + * Inline ptr/len: ptr = data_ptr + begin*stride, len = end - begin. */ spl_emit(ctx, SPL_PICK, SPL_VOID, 2); - spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); - spl_emit(ctx, SPL_ROT, SPL_VOID, 0); - spl_emit(ctx, SPL_ROT, SPL_VOID, 0); - spl_emit(ctx, SPL_DROP, SPL_VOID, 0); + spl_emit(ctx, SPL_LOAD, SPL_PTR, 0); /* [s,b,e,data_ptr] */ + spl_emit(ctx, SPL_PICK, SPL_VOID, 2); /* [s,b,e,d,begin] */ + spl_emit(ctx, SPL_PUSH, SPL_U64, stride); + spl_emit(ctx, SPL_MUL, SPL_U64, 0); + spl_emit(ctx, SPL_ADD, SPL_U64, 0); /* [s,b,e,ptr] */ + spl_emit(ctx, SPL_PICK, SPL_VOID, 1); /* [s,b,e,ptr,end] */ + spl_emit(ctx, SPL_PICK, SPL_VOID, 3); /* [s,b,e,ptr,end,begin] */ + spl_emit(ctx, SPL_SUB, SPL_USIZE, 0); /* [s,b,e,ptr,len] */ + /* cleanup: drop [s,b,e] */ + spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,b,ptr,len,e] */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,b,ptr,len] */ + spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [s,ptr,len,b] */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [s,ptr,len] */ + spl_emit(ctx, SPL_ROT, SPL_VOID, 0); /* [ptr,len,s] */ + spl_emit(ctx, SPL_DROP, SPL_VOID, 0); /* [ptr,len] */ + } else { + emit_slice_create(ctx, stride); } - - emit_slice_create(ctx, stride); } left = (spl_expr_result_t){left.type ? spl_type_slice(left.type->elem) : NULL, 0}; continue; @@ -1196,14 +1169,14 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp if (op == TOK_AND_AND) { /* left is already evaluated and on stack. If it's false (0), skip right. */ spl_val_t bz_addr = spl_emit_bz(ctx); - spl_expr_result_t right = spl_parse_expr(ctx, next_prec); + spl_parse_expr(ctx, next_prec); spl_patch_to_here(ctx, bz_addr); return (spl_expr_result_t){spl_type_basic(SPL_I32), 0}; } if (op == TOK_OR_OR) { /* If left is true (non-zero), skip right. */ spl_val_t bnz_addr = spl_emit_bnz(ctx); - spl_expr_result_t right = spl_parse_expr(ctx, next_prec); + spl_parse_expr(ctx, next_prec); spl_patch_to_here(ctx, bnz_addr); return (spl_expr_result_t){spl_type_basic(SPL_I32), 0}; } @@ -1244,7 +1217,7 @@ static spl_expr_result_t parse_infix(spl_comp_t *ctx, spl_expr_result_t left, sp } /* Regular binary op */ - spl_expr_result_t right = spl_parse_expr(ctx, next_prec); + spl_parse_expr(ctx, next_prec); int sop = binop_to_sir(op, left.type ? left.type->basic_type : SPL_I32); spl_type_t bt = left.type && left.type->kind == TYPE_BASIC ? left.type->basic_type : SPL_I32; if (sop >= 0) { diff --git a/stage1/spl_stmt.c b/stage1/spl_stmt.c index c132599..ebac0b9 100644 --- a/stage1/spl_stmt.c +++ b/stage1/spl_stmt.c @@ -96,7 +96,44 @@ static void parse_var_decl(spl_comp_t *ctx, int is_const) { /* Store init value */ if (has_init) { - if (var_type && (var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM)) { + /* Handle slice struct literal: { .ptr = ..., .len = ... } */ + if (var_type && var_type->kind == TYPE_SLICE && peek(ctx)->type == TOK_L_BRACE && !init.type) { + advance(ctx); /* { */ + skip_nl(ctx); + while (peek(ctx)->type != TOK_R_BRACE && peek(ctx)->type != TOK_EOF) { + if (peek(ctx)->type == TOK_COMMA) { + advance(ctx); + skip_nl(ctx); + continue; + } + if (peek(ctx)->type == TOK_DOT) + advance(ctx); + spl_tok_t *ftok = advance(ctx); + char fname[256]; + usize fnl = ftok->len < 255 ? ftok->len : 255; + memcpy(fname, ftok->lexeme, fnl); + fname[fnl] = '\0'; + skip_nl(ctx); + if (peek(ctx)->type == TOK_ASSIGN) + advance(ctx); + skip_nl(ctx); + + spl_expr_result_t fv = spl_parse_expr(ctx, PREC_MIN); + (void)fv; + + if (strcmp(fname, "ptr") == 0) { + spl_emit(ctx, SPL_LADDR, SPL_PTR, offset); + spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); + spl_emit(ctx, SPL_STORE, SPL_PTR, 0); + } else if (strcmp(fname, "len") == 0) { + spl_emit(ctx, SPL_LADDR, SPL_PTR, offset + (int)sizeof(spl_val_t)); + spl_emit(ctx, SPL_SWAP, SPL_VOID, 0); + spl_emit(ctx, SPL_STORE, SPL_USIZE, 0); + } + skip_nl(ctx); + } + expect(ctx, TOK_R_BRACE); + } else if (var_type && (var_type->kind == TYPE_STRUCT || var_type->kind == TYPE_ENUM)) { /* Struct/enum initialization */ usize sz = spl_type_size(var_type); if (sz <= sizeof(spl_val_t)) { @@ -364,7 +401,6 @@ static void parse_for_stmt(spl_comp_t *ctx) { } /* ===== 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) */ @@ -376,7 +412,6 @@ static void parse_for_stmt(spl_comp_t *ctx) { 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); } @@ -614,7 +649,6 @@ static void parse_match_stmt(spl_comp_t *ctx) { /* Find the variant in the enum type */ spl_enum_variant_t *variant = NULL; - int vi; vec_for(enum_type->variants, vi) { if (strcmp(vec_at(enum_type->variants, vi).name, vname) == 0) { variant = &vec_at(enum_type->variants, vi); @@ -853,7 +887,7 @@ static void parse_expr_stmt(spl_comp_t *ctx) { return; } - int prev = ctx->tok_idx; + usize prev = ctx->tok_idx; /* Look ahead for assignment operator (scan past expression tokens) */ int is_assign = 0; diff --git a/stage1/test10_struct.spl b/stage1/test10_struct.spl index 36e4183..e266387 100644 --- a/stage1/test10_struct.spl +++ b/stage1/test10_struct.spl @@ -46,12 +46,12 @@ fn main() i32 { if r != 25 { ret 6; } /* 结构体嵌套 */ - type Inner = struct { - val: i32, - } type Outer = struct { inner: Inner, extra: i32, + type Inner = struct { + val: i32, + } } var o: Outer; diff --git a/stage1/test19_hardarray.spl b/stage1/test19_hardarray.spl new file mode 100644 index 0000000..5313b1a --- /dev/null +++ b/stage1/test19_hardarray.spl @@ -0,0 +1,184 @@ +/* ===== 进阶数组与切片 ===== + * test19_hardarray — 多维数组、多维切片、切片构造、字符串测试 + * 难度:4/5 + * 验证点:多维数组索引与修改、多维切片、切片字段读写、扁平指针访问、字符串切片 + */ +fn test_string() i32 { + /* ============================ + * String test: str is []u8 + * ============================ */ + var data: *u8 = "hello"; + var s: []u8 = { .ptr = data, .len = 5 }; + + if s.len != 5 { ret 100; } + if s[0] != 104 { ret 101; } /* 'h' */ + if s[1] != 101 { ret 102; } /* 'e' */ + if s[4] != 111 { ret 103; } /* 'o' */ + + /* Slice the string slice */ + var sub: []u8 = s[1..4]; + if sub.len != 3 { ret 104; } + if sub[0] != 101 { ret 105; } /* 'e' */ + if sub[2] != 108 { ret 106; } /* 'l' */ + + /* Modify through slice → original changes */ + s[0] = 72; /* 'H' */ + if data[0] != 72 { ret 107; } + + /* Full slice */ + var full: []u8 = s[0..]; + if full.len != 5 { ret 108; } + if full[0] != 72 { ret 109; } + + /* Construct slice from pointer via field assignment */ + var s2: []u8; + s2.ptr = data; + s2.len = 3; + if s2.len != 3 { ret 110; } + if s2[0] != 72 { ret 111; } + + ret 0; +} + +fn main() i32 { + /* ============================ + * Part 1: 多维数组(逐元素初始化) + * ============================ */ + var matrix: [2][3]i32; + matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3; + matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6; + + if matrix[0][0] != 1 { ret 1; } + if matrix[0][1] != 2 { ret 2; } + if matrix[0][2] != 3 { ret 3; } + if matrix[1][0] != 4 { ret 4; } + if matrix[1][1] != 5 { ret 5; } + if matrix[1][2] != 6 { ret 6; } + + /* 元素修改 */ + matrix[0][0] = 10; + matrix[1][2] = 60; + if matrix[0][0] != 10 { ret 7; } + if matrix[1][2] != 60 { ret 8; } + + /* ============================ + * Part 2: 嵌套循环遍历多维数组 + * ============================ */ + var big: [3][4]i32; + big[0][0] = 1; big[0][1] = 2; big[0][2] = 3; big[0][3] = 4; + big[1][0] = 5; big[1][1] = 6; big[1][2] = 7; big[1][3] = 8; + big[2][0] = 9; big[2][1] = 10; big[2][2] = 11; big[2][3] = 12; + + var total: i32 = 0; + var i: i32 = 0; + while i < 3 { + var j: i32 = 0; + while j < 4 { + total = total + big[i][j]; + j = j + 1; + } + i = i + 1; + } + if total != 78 { ret 9; } + + /* ============================ + * Part 3: &取地址 + 扁平指针访问 + * ============================ */ + var flat: *i32 = &matrix[0][0]; + if flat[0] != 10 { ret 10; } + if flat[1] != 2 { ret 11; } + if flat[2] != 3 { ret 12; } + if flat[3] != 4 { ret 13; } + if flat[4] != 5 { ret 14; } + if flat[5] != 60 { ret 15; } + + /* ============================ + * Part 4: 多维数组切片 + * ============================ */ + var row: []i32 = matrix[0][0..3]; + if row.len != 3 { ret 16; } + if row[0] != 10 { ret 17; } + if row[1] != 2 { ret 18; } + if row[2] != 3 { ret 19; } + + /* 切取第二行 */ + var row2: []i32 = matrix[1][0..]; + if row2.len != 3 { ret 20; } + if row2[0] != 4 { ret 21; } + if row2[2] != 60 { ret 22; } + + /* ============================ + * Part 5: 切片的切片 + * ============================ */ + var sub: []i32 = row[1..3]; + if sub.len != 2 { ret 23; } + if sub[0] != 2 { ret 24; } + if sub[1] != 3 { ret 25; } + + /* ============================ + * Part 6: 切片字段读写 + * ============================ */ + var arr: [4]i32; + arr[0] = 100; arr[1] = 200; arr[2] = 300; arr[3] = 400; + var custom: []i32; + custom.ptr = &arr[1]; + custom.len = 2; + + if custom.len != 2 { ret 26; } + if custom[0] != 200 { ret 27; } + if custom[1] != 300 { ret 28; } + + /* 修改切片长度 */ + custom.len = 3; + if custom.len != 3 { ret 29; } + if custom[2] != 400 { ret 30; } + + /* ============================ + * Part 7: 空范围 / 全切片 + * ============================ */ + var full: []i32 = arr[0..]; + if full.len != 4 { ret 31; } + if full[0] != 100 { ret 32; } + if full[3] != 400 { ret 33; } + + /* ============================ + * Part 8: 从指针构造切片 + * ============================ */ + var data: [5]i32; + data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50; + var p: *i32 = &data[2]; + var from_ptr: []i32 = { .ptr = p, .len = 2 }; + var from_ptr2: []i32; + from_ptr2.ptr = p; + from_ptr2.len = 2; + + if from_ptr.len != 2 { ret 34; } + if from_ptr[0] != 30 { ret 35; } + if from_ptr[1] != 40 { ret 36; } + + if from_ptr2.len != 2 { ret 37; } + if from_ptr2[0] != 30 { ret 38; } + if from_ptr2[1] != 40 { ret 39; } + + /* ============================ + * Part 9: 切片元素修改反映到原始数组 + * ============================ */ + row2[0] = 99; + if matrix[1][0] != 99 { ret 40; } + + /* ============================ + * Part 10: 1D 数组字面量仍然正常 + * ============================ */ + var literal: [3]i32 = [3]i32{10, 20, 30}; + if literal[0] != 10 { ret 41; } + if literal[1] != 20 { ret 42; } + if literal[2] != 30 { ret 43; } + + /* ============================ + * Part 11: 字符串切片测试 + * ============================ */ + var r: i32 = test_string(); + if r != 0 { ret r; } + + ret 0; +}