diff --git a/stage1/spl_parser.c b/stage1/spl_parser.c index f06af9a..94a7bd8 100644 --- a/stage1/spl_parser.c +++ b/stage1/spl_parser.c @@ -941,17 +941,6 @@ static spl_ast_node_ref_t parse_type_base(spl_parser_t *p) { spl_ast_node_t *tp = node_at(p->ast, ref); SET_STR_FIELD(p->ast, tp->type_path.name, bt); vec_init(tp->type_path.generic_args); - - while (peek(p) && peek(p)->type == TOK_DOT) { - advance(p); - const spl_tok_t *seg = peek(p); - if (!seg || seg->type != TOK_IDENT) { - PARSE_ERROR(p, SPL_DIAG_KIND_PARSE_EXPECTED, seg, - "expected identifier after '.' in type path"); - break; - } - advance(p); - } return ref; } diff --git a/stage1/spl_sema.c b/stage1/spl_sema.c index c67bc2b..1f70584 100644 --- a/stage1/spl_sema.c +++ b/stage1/spl_sema.c @@ -764,7 +764,10 @@ static void sema_collect_signatures(spl_sema_t *sema) { usize n = vec_size(sema->type->def_table); for (usize i = 1; i < n; ++i) { spl_def_node_t *d = &vec_at(sema->type->def_table, i); - if (d->kind == SPL_DEF_FN && d->state == SPL_DECL_UNRESOLVED) + /* Nested imports share def_table, but each module has its own scope. + * Resolve other modules' signatures only when processing their AST. */ + if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && + d->state == SPL_DECL_UNRESOLVED) sema_eval_decl(sema, i); } } @@ -1042,11 +1045,10 @@ static void sema_bind_pattern(spl_sema_t *sema, spl_ast_node_ref_t pat_ref, } } -/* type 解包:把容器 struct 的 methods 里的名字引入当前 scope。 +/* type 解包:把 struct 的 methods 里的名字引入当前 scope。 语法层由 pattern 承载,语义层在这里分派。 约束: - - 源类型必须是 LANG_TYPE_STRUCT 且 agg_type.variants 为空 - (即 @import 返回的容器 struct,不是普通带字段的 struct) + - 源类型必须是 LANG_TYPE_STRUCT;实例字段不会被导入 - PATTERN_DOT 不允许有 sub_pattern(编译期没有 payload 概念) - PATTERN_FIELD 不允许带 sub pattern(同上) - 不做递归导出,显式即所得 */ @@ -1166,19 +1168,6 @@ static void sema_do_type_unpack(spl_sema_t *sema, spl_ast_node_t *decl, spl_ast_ return; } - spl_type_id_t src_ir = spl_lang_type_get_ir_type(sema->type, src_lang); - spl_type_node_t *irn = spl_type_node(&sema->type->ir, src_ir); - if (!irn) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg, - "type unpack source IR unresolved"); - return; - } - if (vec_size(irn->agg_type.variants) != 0) { - spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &decl->dbg, - "type unpack source has fields; only container struct allowed"); - return; - } - sema_type_unpack_walk(sema, pat, src_lang); } @@ -1373,7 +1362,7 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref, case SPL_AST_EXPR_AGGREGATE_LIT: { spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected); if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION && - en->kind != SPL_LANG_TYPE_ENUM)) + en->kind != SPL_LANG_TYPE_ENUM && en->kind != SPL_LANG_TYPE_SLICE)) break; if (n->aggregate_literal.name) { diff --git a/stage2/sys/exit.spl b/stage2/sys/exit.spl new file mode 100644 index 0000000..904fd7d --- /dev/null +++ b/stage2/sys/exit.spl @@ -0,0 +1,22 @@ +// Expect retcode = 6 + +// exit.spl +// usage: type exit = @import("exit.spl"); exit.ok(); + +#extern(vm) fn vm_exit(code: i32); + +fn now(code: i32) { + vm_exit(code); +} + +fn ok() { + vm_exit(0); +} + +fn fail() { + vm_exit(1); +} + +fn main(): void { + now(6); +} diff --git a/stage2/sys/file.spl b/stage2/sys/file.spl new file mode 100644 index 0000000..843f99a --- /dev/null +++ b/stage2/sys/file.spl @@ -0,0 +1,70 @@ +#extern(vm) fn vm_fopen(path: *any, mode: *any): *any; +#extern(vm) fn vm_fclose(f: *any): i32; +#extern(vm) fn vm_fread(buf: *any, sz: usize, n: usize, f: *any): usize; +#extern(vm) fn vm_fwrite(buf: *any, sz: usize, n: usize, f: *any): usize; +#extern(vm) fn vm_fsize(f: *any): usize; +#extern(vm) fn vm_stdin(): *any; +#extern(vm) fn vm_stdout(): *any; +#extern(vm) fn vm_stderr(): *any; +#extern(vm) fn vm_putchar(c: i32): i32; +#extern(vm) fn vm_getchar(): i32; + +handle: *any, +type File = @self; + +fn stdin(): File { ret File { .handle = vm_stdin() }; } +fn stdout(): File { ret File { .handle = vm_stdout() }; } +fn stderr(): File { ret File { .handle = vm_stderr() }; } + +fn open(path: *u8, mode: *u8): File { + ret File { .handle = vm_fopen(path as *any, mode as *any) }; +} + +fn valid(f: *File): bool { + ret f.handle != null; +} + +fn write(f: *File, data: *u8, n: u64): u64 { + if f.handle == null { ret 0; } + ret vm_fwrite(data as *any, 1, n, f.handle); +} + +fn write_byte(f: *File, b: u8): u64 { + var tmp: u8 = b; + ret write(f, &tmp, 1); +} + +fn read(f: *File, buf: *u8, n: u64): u64 { + if f.handle == null { ret 0; } + ret vm_fread(buf as *any, 1, n, f.handle); +} + +fn size(f: *File): u64 { + if f.handle == null { ret 0; } + ret vm_fsize(f.handle); +} + +fn close(f: *File): i32 { + if f.handle == null { ret -1; } + var r = vm_fclose(f.handle); + f.handle = null; + ret r; +} + +fn putchar(c: u8) { + vm_putchar(c as i32); +} + +fn getchar(): i32 { + ret vm_getchar(); +} + +fn main(): void { + var out = stdout(); + @assert(out.handle != null, "stdout"); + var msg = "file: ok\n"; + var n = write(&out, msg.ptr, msg.len); + @assert(n == msg.len, "write"); + putchar(46 as u8); + putchar(10 as u8); +} \ No newline at end of file diff --git a/stage2/sys/mem.spl b/stage2/sys/mem.spl new file mode 100644 index 0000000..8ed08d7 --- /dev/null +++ b/stage2/sys/mem.spl @@ -0,0 +1,79 @@ +#extern(vm) fn vm_alloc(sz: usize): *any; +#extern(vm) fn vm_free(p: *any); +#extern(vm) fn vm_realloc(p: *any, sz: usize): *any; +#extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any; +#extern(vm) fn vm_memcmp(a: *any, b: *any, n: usize): isize; + +fn alloc(sz: usize): *any { + if sz == 0 { ret null; } + ret vm_alloc(sz); +} + +fn free(p: *any) { + if p == null { ret; } + vm_free(p); +} + +fn realloc(p: *any, sz: usize): *any { + if p == null { ret alloc(sz); } + if sz == 0 { free(p); ret null; } + ret vm_realloc(p, sz); +} + +fn copy(dst: *any, src: *any, n: usize): *any { + if n == 0 { ret dst; } + ret vm_memcpy(dst, src, n); +} + +fn cmp(a: *any, b: *any, n: usize): isize { + if n == 0 { ret 0; } + ret vm_memcmp(a, b, n); +} + +fn set(dst: *any, byte: u8, n: usize): *any { + var d = dst as *u8; + var i: usize = 0; + while i < n { + d[i] = byte; + i = i + 1; + } + ret dst; +} + +fn zero(dst: *any, n: usize): *any { + ret set(dst, 0 as u8, n); +} + +fn main(): void { + var p = alloc(16); + @assert(p != null, "alloc"); + var q = alloc(16); + @assert(p != q, "distinct"); + @assert(alloc(0) == null, "alloc(0)"); + + var a: u8 = 42; + var b: u8 = 0; + copy(&b as *any, &a as *any, 1); + @assert(b == 42, "copy"); + + var x: u8 = 1; + var y: u8 = 2; + @assert(cmp(&x as *any, &y as *any, 1) < 0, "cmp lt"); + @assert(cmp(&y as *any, &x as *any, 1) > 0, "cmp gt"); + @assert(cmp(&x as *any, &x as *any, 1) == 0, "cmp eq"); + + var buf = alloc(8); + zero(buf, 8); + var bp = buf as *u8; + @assert(bp[0] == 0, "zero"); + @assert(bp[7] == 0, "zero end"); + set(buf, 0xAB as u8, 8); + @assert(bp[0] == 0xAB as u8, "set"); + + var r = realloc(p, 32); + @assert(r != null, "realloc"); + free(r); + free(q); + free(buf); + free(null); +} \ No newline at end of file