stage2 提供c后端 提交stage1的测试

This commit is contained in:
zzy committed 2026-09-20 17:56:11 +08:00
1 parent 846f441e3a
commit 51d408d524
82 files changed
+6872 -65

No files matched your search

+6
View File
@@ -121,6 +121,8 @@ type Body = enum {
PatternList: struct { items: Vec },
PatternAggregate: struct { items: Vec },
PatternField: struct { name: ByteView, pattern: usize },
ExprComptime: struct { body: usize },
ExprComptimeInit: struct { name: ByteView, args: Vec, fields: Vec },
}
fn kind_name(body: Body): []u8 {
@@ -143,6 +145,7 @@ fn kind_name(body: Body): []u8 {
.StatementContinue(_) => { ret "statement_continue"; },
.StatementDefer(_) => { ret "statement_defer"; },
.StatementComptime(_) => { ret "statement_comptime"; },
.ExprComptime(_) => { ret "expr_comptime"; },
.StatementDecl(_) => { ret "statement_decl"; },
.StatementExpr(_) => { ret "statement_expr"; },
.AggregateMember(_) => { ret "aggregate_member"; },
@@ -168,6 +171,7 @@ fn kind_name(body: Body): []u8 {
.ExprArrayLit(_) => { ret "array_literal"; },
.ExprAggregateLit(_) => { ret "aggregate_literal"; },
.ExprComptimeCall(_) => { ret "comptime_call"; },
.ExprComptimeInit(_) => { ret "comptime_init"; },
.ExprBlock(_) => { ret "block"; },
.ExprIf(_) => { ret "if_expr"; },
.ExprIfvar(_) => { ret "ifvar_expr"; },
@@ -463,6 +467,7 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool):
.StatementContinue(x) => { ok = dump_opt(ast, buf, stack, x.label, true); },
.StatementDefer(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.StatementComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.ExprComptime(x) => { ok = dump_opt(ast, buf, stack, x.body, true); },
.StatementDecl(d) => { ok = dump_opt(ast, buf, stack, d.decl, true); },
.StatementExpr(e) => { ok = dump_opt(ast, buf, stack, e.expr, true); },
.AggregateMember(d) => {
@@ -514,6 +519,7 @@ fn dump_node(ast: *Ast, buf: *ByteBuffer, stack: *Vec, ref: usize, last: bool):
},
.ExprAggregateLit(a) => { ok = dump_list(ast, buf, stack, a.fields); },
.ExprComptimeCall(c) => { ok = dump_list(ast, buf, stack, c.args); },
.ExprComptimeInit(x) => { ok = dump_list(ast, buf, stack, x.fields); },
.ExprBlock(b) => {
ok = dump_list(ast, buf, stack, b.stmts) &&
dump_opt(ast, buf, stack, b.tail_expr, true);
+1304
View File
File diff suppressed because it is too large. Load diff
+179 -7
View File
@@ -25,6 +25,7 @@ failed: bool,
stop_agg: i32,
error_count: usize,
file: usize, // 当前源文件在 Sources 中的下标
comptime_depth: usize, // >0 表示处于 comptime 上下文(类型可作为表达式)
fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
ret Parser {
@@ -36,6 +37,7 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
.stop_agg = 0,
.error_count = 0,
.file = 0,
.comptime_depth = 0,
};
}
@@ -71,6 +73,21 @@ fn peek(self: *Parser): *Token {
ret base + i;
}
// 跳过 trivia,返回当前 token 之后的下一个非 trivia token(不移动 pos)。
fn peek_next(self: *Parser): *Token {
var n = self.toks.len;
var base = self.toks.data as *Token;
var i = self.pos + 1;
while i < n {
if base == null { break; }
var t = base + i;
if !is_trivia(t.kind) { break; }
i = i + 1;
}
if i >= n || base == null { ret null; }
ret base + i;
}
fn advance(self: *Parser): *Token {
var t = peek(self);
if t == null { ret null; }
@@ -264,6 +281,7 @@ fn can_start_expr(kind: TokenKind): bool {
.Loop => { ret true; },
.For => { ret true; },
.Match => { ret true; },
.Comptime => { ret true; },
_ => { ret false; },
}
},
@@ -655,7 +673,33 @@ fn parse_param_list(self: *Parser): Vec {
ret out;
}
fn parse_fn_decl(self: *Parser, tags: Vec): usize {
// 该 token 是否可能开始一个类型表达式(用于省略冒号的返回类型)。
fn token_starts_type(t: *Token): bool {
if t == null { ret false; }
match t.kind {
.Ident => { ret true; },
.Keyword(k) => {
if @enum2int(k) == @enum2int(Keyword.Type) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Bool) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Any) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Fn) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Struct) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Union) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Enum) { ret true; }
if @enum2int(k) == @enum2int(Keyword.Shape) { ret true; }
},
.Punct(p) => {
if @enum2int(p) == @enum2int(Punct.Mul) { ret true; }
if @enum2int(p) == @enum2int(Punct.LBracket) { ret true; }
if @enum2int(p) == @enum2int(Punct.At) { ret true; }
if @enum2int(p) == @enum2int(Punct.Sharp) { ret true; }
},
_ => {},
}
ret false;
}
fn parse_fn_decl(self: *Parser, tags: Vec, is_comptime: bool): usize {
var kw = peek(self);
if kw == null || !kind_is_keyword(kw.kind, .Fn) { ret 0; }
advance(self);
@@ -672,19 +716,26 @@ fn parse_fn_decl(self: *Parser, tags: Vec): usize {
advance(self);
ret_type = parse_type_expr(self);
t = peek(self);
} else if token_starts_type(t) {
// 省略冒号:`fn f() T { ... }`
ret_type = parse_type_expr(self);
t = peek(self);
}
var body: usize = 0;
if is_comptime { self.comptime_depth = self.comptime_depth + 1; }
if t != null && kind_is_punct(t.kind, .LBrace) {
body = parse_block(self);
} else if t != null && kind_is_punct(t.kind, .Semicolon) {
advance(self);
} else {
if is_comptime { self.comptime_depth = self.comptime_depth - 1; }
parse_error(self, t, "function declaration must end with ';' or block");
ret 0;
}
if is_comptime { self.comptime_depth = self.comptime_depth - 1; }
ret new_node(self, .FnDecl(.{
.tag_list = tags,
.is_comptime = false,
.is_comptime = is_comptime,
.name = name.text,
.params = params,
.ret_type = ret_type,
@@ -802,8 +853,10 @@ fn parse_comptime_decl(self: *Parser): usize {
advance(self);
var body: usize = 0;
var t = peek(self);
self.comptime_depth = self.comptime_depth + 1;
if t != null && kind_is_punct(t.kind, .LBrace) { body = parse_block(self); }
else { body = parse_expr(self); }
self.comptime_depth = self.comptime_depth - 1;
ret new_node(self, .ComptimeDecl(.{ .body = body }), kw);
}
@@ -815,7 +868,7 @@ fn parse_container_declaration(self: *Parser): usize {
match t.kind {
.Eof => { ret 0; },
.Keyword(k) => {
if @enum2int(k) == @enum2int(Keyword.Fn) { ret parse_fn_decl(self, tags); }
if @enum2int(k) == @enum2int(Keyword.Fn) { ret parse_fn_decl(self, tags, false); }
if @enum2int(k) == @enum2int(Keyword.Type) { ret parse_type_decl(self, tags); }
if @enum2int(k) == @enum2int(Keyword.Var) {
ret parse_var_const_decl(self, tags, false);
@@ -823,7 +876,15 @@ fn parse_container_declaration(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Const) {
ret parse_var_const_decl(self, tags, true);
}
if @enum2int(k) == @enum2int(Keyword.Comptime) { ret parse_comptime_decl(self); }
if @enum2int(k) == @enum2int(Keyword.Comptime) {
// `comptime fn ...` -> 标记为编译期函数;否则 `comptime { }` 声明。
var nxt = peek_next(self);
if nxt != null && kind_is_keyword(nxt.kind, .Fn) {
advance(self);
ret parse_fn_decl(self, tags, true);
}
ret parse_comptime_decl(self);
}
},
.Ident => { ret parse_member_decl(self, tags); },
.Punct(p) => {
@@ -951,15 +1012,41 @@ fn parse_type_base(self: *Parser): usize {
match bt.kind {
.Ident => {
advance(self);
// 类型调用 `Name(T, ...)`(comptime 类型构造,如 `vec(i32)`)。
if at_punct(self, .LParen) {
advance(self);
var ref = new_node(self, .TypePath(.{
.name = bt.text,
.generic_args = ref_vec(),
}), bt);
var args = ref_vec();
while !self.failed && !at_punct(self, .RParen) {
var a = parse_type_expr(self);
match Vec.push(&args, &a as *u8) { .Ok => {}, .Err(e) => { ret 0; } }
if at_punct(self, .Comma) { advance(self); continue; }
break;
}
expect_punct(self, .RParen, "')' in type call");
var tn = Ast.node(self.ast, ref);
match tn.body {
.TypePath(tp) => {
tp.generic_args = args;
tn.body = .TypePath(tp);
},
_ => {},
}
ret ref;
}
ret new_node(self, .TypePath(.{
.name = bt.text,
.generic_args = ref_vec(),
}), bt);
},
.Keyword(k) => {
// stage1 is_builtin_type_kw:bool / any 作为类型路径。
// stage1 is_builtin_type_kw:bool / any 作为类型路径;stage3 增加 `type`。
if @enum2int(k) == @enum2int(Keyword.Bool) ||
@enum2int(k) == @enum2int(Keyword.Any) {
@enum2int(k) == @enum2int(Keyword.Any) ||
@enum2int(k) == @enum2int(Keyword.Type) {
advance(self);
ret new_node(self, .TypePath(.{
.name = bt.text,
@@ -1357,6 +1444,21 @@ fn parse_primary(self: *Parser): usize {
if @enum2int(k) == @enum2int(Keyword.Loop) { ret parse_loop_expr(self); }
if @enum2int(k) == @enum2int(Keyword.For) { ret parse_for_expr(self); }
if @enum2int(k) == @enum2int(Keyword.Match) { ret parse_match_expr(self); }
// `comptime <expr>`:编译期表达式(可调用普通函数、返回类型等)。
if @enum2int(k) == @enum2int(Keyword.Comptime) {
advance(self);
var cbody = parse_expr(self);
ret new_node(self, .ExprComptime(.{ .body = cbody }), t);
}
// 类型即表达式:仅在 comptime 上下文内允许 `struct { ... }` 等聚合类型。
if self.comptime_depth > 0 {
if @enum2int(k) == @enum2int(Keyword.Struct) ||
@enum2int(k) == @enum2int(Keyword.Union) ||
@enum2int(k) == @enum2int(Keyword.Enum) ||
@enum2int(k) == @enum2int(Keyword.Shape) {
ret parse_type_base(self);
}
}
parse_error(self, t, "unrecognized expression");
ret 0;
},
@@ -1553,6 +1655,15 @@ fn parse_comptime_call(self: *Parser): usize {
args = parse_expr_list(self);
if !expect_punct(self, .RParen, "')' in comptime call") { ret 0; }
}
// `@name(args){ ... }`:构造该编译期类型的值(聚合初始化)。
if at_punct(self, .LBrace) && self.stop_agg == 0 {
var fields = parse_aggregate_fields(self);
ret new_node(self, .ExprComptimeInit(.{
.name = name.text,
.args = args,
.fields = fields,
}), start);
}
ret new_node(self, .ExprComptimeCall(.{ .name = name.text, .args = args }), start);
}
@@ -1791,7 +1902,18 @@ fn parse_ret_stmt(self: *Parser): usize {
advance(self);
var expr: usize = 0;
var t = peek(self);
if t != null && can_start_expr(t.kind) { expr = parse_expr(self); }
var can = false;
if t != null {
can = can_start_expr(t.kind);
// comptime 上下文:允许返回类型表达式(如 `ret struct { ... };`)。
if !can && self.comptime_depth > 0 {
if kind_is_keyword(t.kind, .Struct) || kind_is_keyword(t.kind, .Union) ||
kind_is_keyword(t.kind, .Enum) || kind_is_keyword(t.kind, .Shape) {
can = true;
}
}
}
if can { expr = parse_expr(self); }
t = peek(self);
if t != null && kind_is_punct(t.kind, .Semicolon) { advance(self); }
ret new_node(self, .StatementRet(.{ .expr = expr }), kw);
@@ -2223,10 +2345,60 @@ fn test_big_int_literal() {
check_int("0o_17", "15");
}
fn expect_contains(buf: *ByteBuffer, needle: []u8) {
var actual = ByteBuffer.as_slice(buf.*);
if needle.len > actual.len { @assert(false, "contains length"); }
var i: usize = 0;
while i + needle.len <= actual.len {
var j: usize = 0;
var ok = true;
while j < needle.len {
if actual.ptr[i + j] != needle.ptr[j] { ok = false; break; }
j = j + 1;
}
if ok { ret; }
i = i + 1;
}
@assert(false, "expected substring not found");
}
// stage3 语法:`comptime fn ... (t: type) type { ... }` 与省略冒号的返回类型。
fn test_parse_comptime_fn() {
var src: []u8 = "comptime fn vec(t: type) type { ret t; }\n";
var toks = lex_tokens(src);
defer { Vec.drop(&toks); }
var sources = set_new();
defer { set_drop(&sources); }
match set_add(&sources, ByteView.from_slice("test.spl"), ByteView.from_slice(src)) {
.Ok(index) => {},
.Err(error) => { @assert(false, "set_add"); },
}
var ast: Ast = undefined;
match Ast.new(&sources) {
.Ok(v) => { ast = v; },
.Err(error) => { @assert(false, "ast new"); },
}
defer { Ast.drop(&ast); }
var p = new(&ast, toks, null);
parse(&p);
@assert(!p.failed, "comptime fn parse ok");
@assert(p.error_count == 0, "comptime fn no errors");
var buf = ByteBuffer.new();
defer { ByteBuffer.drop(&buf); }
@assert(Ast.dump(&ast, &buf), "dump");
expect_contains(&buf, "fn_decl");
expect_contains(&buf, "type_path");
}
fn main() {
test_peek_advance();
test_new_node_span();
test_parse_decls();
test_parse_main();
test_big_int_literal();
test_parse_comptime_fn();
}
+35 -2
View File
@@ -13,7 +13,8 @@ type Ast = @import("./ast.spl");
type Parser = @import("./parser.spl");
type Sema = @import("./sema.spl");
type .{ .append_usize } = @import("./utils/fmt.spl");
type .{ .read_all, .print, .eprint } = @import("./utils/io.spl");
type .{ .read_all, .print, .eprint, .open_cstr, .write_all } = @import("./utils/io.spl");
type File = @import("./sys/file.spl");
type .{ .Sources, .Source, .set_new, .set_add, .set_at, .set_drop } = @import("./utils/source.spl");
type .{ .Diag, .Code, .span_none } = @import("./diag.spl");
type Logger = @import("./utils/log.spl");
@@ -25,6 +26,7 @@ type LayoutM = @import("./layout.spl");
type .{ .Layout } = @import("./layout.spl");
type Ir2VmM = @import("./ir2vm.spl");
type .{ .Ir2Vm } = @import("./ir2vm.spl");
type Ir2CM = @import("./ir2c.spl");
type .{ .alloc, .free } = @import("./sys/mem.spl");
fn token_at(tokens: *Vec, index: usize): Token {
@@ -566,6 +568,7 @@ type PipeMode = enum {
Vm, // 继续 layout + ir2vm,dump VM
Compile, // 继续 layout + ir2vm,写 outpath
State, // 只逐步打日志(诊断“卡在哪一步”)
C, // 继续 layout + ir2c,dump C
}
fn step(mode: PipeMode, s: []u8) {
@@ -723,6 +726,31 @@ fn run_pipeline(log: *Logger, path: ByteView, mode: PipeMode, outpath: ByteView)
LayoutM.resolve(&layout, &sema.types.ir);
step(mode, "state: layout ok\n");
if @enum2int(mode) == @enum2int(PipeMode.C) {
var cout = ByteBuffer.new();
defer { ByteBuffer.drop(&cout); }
var ok = Ir2CM.compile(&builder.ir, &sema.types.ir, &layout, &sema.attr, &cout);
if outpath.len != 0 {
var f = open_cstr(outpath, ByteView.from_slice("wb"));
if !File.valid(&f) {
Logger.error(log, "cannot open C output file");
ret 1;
}
match write_all(&f, ByteBuffer.as_slice(cout)) { .Ok => {}, .Err(error) => {} }
ignore_i32(File.close(&f));
} else {
match print(ByteBuffer.as_slice(cout)) {
.Ok => {},
.Err(error) => { ret 1; },
}
}
if !ok {
Logger.error(log, "ir2c failed (see generated C for unsupported markers)");
ret 1;
}
ret 0;
}
var ir2vm: Ir2Vm = undefined;
Ir2VmM.init(&ir2vm, &builder.ir, &sema.types.ir, &layout, &sema.attr);
defer { Ir2VmM.drop(&ir2vm); }
@@ -776,11 +804,13 @@ fn main(argc: i32, argv: **u8): i32 {
}
if argc < 4 {
Logger.fatal(&log, "usage: splc1 --dump <lex|ast|sema|ir|vm> <file> [out]");
Logger.fatal(&log, "usage: splc1 --dump <lex|ast|sema|ir|vm|c> <file> [out]");
ret 1;
}
var mode = ByteView.from_cstr(argv[2]);
var path = ByteView.from_cstr(argv[3]);
var dout = ByteView.empty();
if argc >= 5 { dout = ByteView.from_cstr(argv[4]); }
if ByteView.eq(mode, ByteView.from_slice("lex")) {
ret dump_lex(&log, path);
@@ -800,6 +830,9 @@ fn main(argc: i32, argv: **u8): i32 {
if ByteView.eq(mode, ByteView.from_slice("state")) {
ret run_pipeline(&log, path, .State, ByteView.empty());
}
if ByteView.eq(mode, ByteView.from_slice("c")) {
ret run_pipeline(&log, path, .C, dout);
}
Logger.fatal(&log, "dump mode not implemented");
ret 1;
}
+629
View File
@@ -0,0 +1,629 @@
/* spl_rt.h - SPL native runtime (header-only, C89-friendly)
*
* 提供 ir2c 生成代码所需的所有 `#extern(vm)` 符号,以及 SPL 基础类型别名。
* 目标:生成代码可用 C89 语法通过(不依赖 stdint/stdbool)。
*/
#ifndef __SPL_RT_H__
#define __SPL_RT_H__
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* 语义清晰的 inline:C99 用 static inline,GNU 用 __inline__,C89 退化为 static */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPL_INLINE static inline
#elif defined(__GNUC__) || defined(__clang__)
#define SPL_INLINE static __inline__
#else
#define SPL_INLINE static
#endif
/* ---- SPL 基础类型别名 ---- */
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef u64 usize;
typedef i64 isize;
/* 注:不定义 bool/true/false,避免与 C23 关键字冲突;生成代码用 u8 表示布尔。 */
/* ---- panic / trap ---- */
SPL_INLINE void spl_panic(const char *msg) {
fprintf(stderr, "%s\n", msg ? msg : "panic");
exit(1);
}
SPL_INLINE void spl_trap(void) { abort(); }
/* ---- mem ---- */
SPL_INLINE void *vm_alloc(u64 sz) {
if (sz == 0)
return NULL;
return malloc((size_t)sz);
}
SPL_INLINE void vm_free(void *p) {
if (p)
free(p);
}
SPL_INLINE void *vm_realloc(void *p, u64 sz) {
if (!p)
return vm_alloc(sz);
if (sz == 0) {
free(p);
return NULL;
}
return realloc(p, (size_t)sz);
}
SPL_INLINE void *vm_memcpy(void *dst, const void *src, u64 n) {
if (n)
memcpy(dst, src, (size_t)n);
return dst;
}
SPL_INLINE void *vm_memmove(void *dst, const void *src, u64 n) {
if (n)
memmove(dst, src, (size_t)n);
return dst;
}
SPL_INLINE i64 vm_memcmp(const void *a, const void *b, u64 n) {
if (n == 0)
return 0;
return (i64)memcmp(a, b, (size_t)n);
}
SPL_INLINE i32 vm_bytes_eq(const void *a, u64 alen, const void *b, u64 blen) {
if (alen != blen)
return 0;
if (alen == 0)
return 1;
if (!a || !b)
return 0;
return memcmp(a, b, (size_t)alen) == 0;
}
/* ---- Vec ---- */
typedef struct {
usize raw;
usize data;
usize len;
usize cap;
usize elem_size;
usize elem_align;
} spl_vec_t;
SPL_INLINE int spl_vec_is_valid(const spl_vec_t *v) {
usize a;
if (v->elem_size == 0)
return 0;
a = v->elem_align;
if (a == 0 || (a & (a - 1)) != 0)
return 0;
if (v->len > v->cap)
return 0;
if (v->cap == 0)
return v->raw == 0 && v->data == 0 && v->len == 0;
if (v->raw == 0 || v->data == 0)
return 0;
return (v->data & (a - 1)) == 0;
}
SPL_INLINE int spl_align_ok(usize a) { return a != 0 && (a & (a - 1)) == 0; }
SPL_INLINE void spl_grow(usize current, usize need, usize *out) {
usize cap = current < 8 ? 8 : current;
usize limit = ~(usize)0;
while (cap < need) {
if (cap > limit / 2) {
cap = need;
break;
}
cap = cap * 2;
}
*out = cap;
}
SPL_INLINE int spl_vec_allocate(spl_vec_t *out, usize capacity, usize elem_size, usize elem_align) {
usize bytes, mask, addr;
void *raw;
if (elem_size == 0)
return 1;
if (!spl_align_ok(elem_align))
return 4;
out->raw = 0;
out->data = 0;
out->len = 0;
out->cap = 0;
out->elem_size = elem_size;
out->elem_align = elem_align;
if (capacity == 0)
return 0;
if (capacity > ~(usize)0 / elem_size)
return 3;
bytes = capacity * elem_size;
mask = elem_align - 1;
if (bytes > ~(usize)0 - mask)
return 3;
raw = malloc(bytes + mask);
if (!raw)
return 3;
addr = (usize)raw;
if (addr > ~(usize)0 - mask) {
free(raw);
return 3;
}
out->raw = addr;
out->data = (addr + mask) & ~mask;
out->cap = capacity;
return 0;
}
SPL_INLINE int spl_vec_reserve_raw(spl_vec_t *v, usize need) {
usize new_cap = 0, used = 0, old;
spl_vec_t fresh;
int rc;
if (need <= v->cap)
return 0;
spl_grow(v->cap, need, &new_cap);
rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align);
if (rc)
return rc;
if (v->len != 0) {
if (v->len > ~(usize)0 / v->elem_size) {
free((void *)fresh.raw);
return 3;
}
used = v->len * v->elem_size;
}
if (used)
memcpy((void *)fresh.data, (void *)v->data, used);
fresh.len = v->len;
old = v->raw;
*v = fresh;
if (old)
free((void *)old);
return 0;
}
SPL_INLINE void spl_vec_release(spl_vec_t *v) {
usize es = v->elem_size, ea = v->elem_align;
if (v->raw)
free((void *)v->raw);
v->raw = 0;
v->data = 0;
v->len = 0;
v->cap = 0;
v->elem_size = es;
v->elem_align = ea;
}
SPL_INLINE i32 vm_vec_valid(void *vv) {
const spl_vec_t *v = (const spl_vec_t *)vv;
return v ? spl_vec_is_valid(v) : 0;
}
SPL_INLINE i32 vm_vec_push_raw(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem)
return 0;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 1;
}
return 0;
}
SPL_INLINE i32 vm_vec_get(void *vv, u64 index, void **out) {
const spl_vec_t *v = (const spl_vec_t *)vv;
if (!v || !out)
return 1;
if (!spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
*out = (void *)(v->data + index * v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_push(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
int rc;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
rc = spl_vec_reserve_raw(v, v->len + 1);
if (rc)
return rc;
memmove((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
SPL_INLINE i32 vm_vec_allocate(void *out, u64 capacity, u64 elem_size, u64 elem_align) {
return spl_vec_allocate((spl_vec_t *)out, capacity, elem_size, elem_align);
}
SPL_INLINE i32 vm_vec_reserve_raw(void *vv, u64 need) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v)
return 1;
return spl_vec_reserve_raw(v, need);
}
SPL_INLINE i32 vm_vec_append(void *vv, const void *elems, u64 count) {
spl_vec_t *v = (spl_vec_t *)vv;
usize copy_bytes, new_len, used, source_offset = 0;
int source_inside = 0, rc;
if (!v || !spl_vec_is_valid(v))
return 1;
if (count == 0)
return 0;
if (!elems)
return 1;
if (count > ~(usize)0 / v->elem_size)
return 3;
copy_bytes = count * v->elem_size;
if (v->len > ~(usize)0 - count)
return 3;
new_len = v->len + count;
used = v->len * v->elem_size;
if (used) {
usize base = v->data;
usize source = (usize)elems;
if (source >= base && source - base < used) {
source_offset = source - base;
if (copy_bytes > used - source_offset)
return 2;
source_inside = 1;
}
}
rc = spl_vec_reserve_raw(v, new_len);
if (rc)
return rc;
if (source_inside)
elems = (const void *)(v->data + source_offset);
memmove((void *)(v->data + used), elems, copy_bytes);
v->len = new_len;
return 0;
}
SPL_INLINE i32 vm_vec_set(void *vv, u64 index, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
memmove((void *)(v->data + index * v->elem_size), elem, v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_pop(void *vv, void *out) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !out || !spl_vec_is_valid(v))
return 1;
if (v->len == 0)
return 2;
memmove(out, (void *)(v->data + (v->len - 1) * v->elem_size), v->elem_size);
v->len--;
return 0;
}
SPL_INLINE i32 vm_vec_clone(void *outp, const void *srcp) {
spl_vec_t *out = (spl_vec_t *)outp;
const spl_vec_t *src = (const spl_vec_t *)srcp;
spl_vec_t fresh;
usize bytes;
int rc;
if (!out || !src || !spl_vec_is_valid(out) || !spl_vec_is_valid(src))
return 1;
if (out->elem_size != src->elem_size || out->elem_align != src->elem_align)
return 1;
fresh.raw = 0;
fresh.data = 0;
fresh.len = 0;
fresh.cap = 0;
fresh.elem_size = src->elem_size;
fresh.elem_align = src->elem_align;
rc = spl_vec_reserve_raw(&fresh, src->len);
if (rc)
return rc;
bytes = src->len * src->elem_size;
if (bytes)
memcpy((void *)fresh.data, (void *)src->data, bytes);
fresh.len = src->len;
if (out->raw)
free((void *)out->raw);
*out = fresh;
return 0;
}
SPL_INLINE void vm_vec_drop(void *vv) {
spl_vec_t *v = (spl_vec_t *)vv;
if (v)
spl_vec_release(v);
}
/* ---- Map ---- */
typedef struct {
spl_vec_t keys;
spl_vec_t vals;
spl_vec_t states;
usize size;
usize key_size;
usize val_size;
usize hash_kind;
} spl_map_t;
SPL_INLINE usize spl_hash_usize_value(usize value) {
usize prime = 1099511628211ull;
usize h = value;
h = (h ^ (h >> 30)) * prime;
h = h ^ (h >> 27);
h = h * prime;
h = h ^ (h >> 31);
if (h == 0)
return prime;
return h;
}
SPL_INLINE usize spl_hash_bytes(const void *data, usize len) {
const unsigned char *p = (const unsigned char *)data;
usize h = 14695981039346656037ull;
usize prime = 1099511628211ull;
usize i;
for (i = 0; i < len; i++)
h = (h ^ (usize)p[i]) * prime;
return h;
}
SPL_INLINE usize spl_map_hash(const spl_map_t *m, const void *key) {
const usize *v;
if (m->hash_kind == 0)
return spl_hash_usize_value(*(const usize *)key);
if (m->hash_kind == 2)
return 3;
v = (const usize *)key;
return spl_hash_bytes((const void *)v[0], v[1]);
}
SPL_INLINE int spl_map_eq(const spl_map_t *m, const void *a, const void *b) {
const usize *x;
const usize *y;
if (m->hash_kind == 0 || m->hash_kind == 2)
return *(const usize *)a == *(const usize *)b;
x = (const usize *)a;
y = (const usize *)b;
if (x[1] != y[1])
return 0;
if (x[1] == 0)
return 1;
return memcmp((const void *)x[0], (const void *)y[0], x[1]) == 0;
}
SPL_INLINE int spl_map_valid(const spl_map_t *m) {
if (m->key_size == 0 || m->val_size == 0)
return 0;
if (m->keys.len != m->states.len || m->vals.len != m->states.len)
return 0;
if (m->size > m->states.len)
return 0;
return 1;
}
SPL_INLINE usize spl_map_find_slot(const spl_map_t *m, const void *key) {
usize mask, i, probes;
unsigned char *st;
if (m->states.cap == 0)
return ~(usize)0;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 1 && spl_map_eq(m, (const void *)(m->keys.data + i * m->key_size), key))
return i;
i = (i + 1) & mask;
probes++;
}
return ~(usize)0;
}
SPL_INLINE void spl_map_place(spl_map_t *m, const void *key, const void *val) {
usize mask, i, first_deleted, probes;
unsigned char *st;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
first_deleted = ~(usize)0;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 2 && first_deleted == ~(usize)0)
first_deleted = i;
i = (i + 1) & mask;
probes++;
}
if (first_deleted != ~(usize)0)
i = first_deleted;
memcpy((void *)(m->keys.data + i * m->key_size), key, m->key_size);
memcpy((void *)(m->vals.data + i * m->val_size), val, m->val_size);
st[i] = 1;
m->size++;
}
SPL_INLINE int spl_map_reserve(spl_map_t *m, usize need) {
usize new_cap = 0, i;
spl_map_t fresh;
int rc;
if (!spl_map_valid(m))
return 1;
if (need <= m->states.cap)
return 0;
spl_grow(m->states.cap, need, &new_cap);
fresh = *m;
fresh.keys.raw = 0;
fresh.keys.data = 0;
fresh.keys.len = 0;
fresh.keys.cap = 0;
fresh.vals.raw = 0;
fresh.vals.data = 0;
fresh.vals.len = 0;
fresh.vals.cap = 0;
fresh.states.raw = 0;
fresh.states.data = 0;
fresh.states.len = 0;
fresh.states.cap = 0;
fresh.size = 0;
rc = spl_vec_reserve_raw(&fresh.keys, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.vals, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.states, new_cap);
if (rc)
goto fail;
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
memset((void *)fresh.states.data, 0, new_cap);
for (i = 0; i < m->states.len; i++) {
if (((unsigned char *)m->states.data)[i] == 1)
spl_map_place(&fresh, (const void *)(m->keys.data + i * m->key_size),
(const void *)(m->vals.data + i * m->val_size));
}
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
*m = fresh;
return 0;
fail:
spl_vec_release(&fresh.keys);
spl_vec_release(&fresh.vals);
spl_vec_release(&fresh.states);
return rc;
}
SPL_INLINE i32 vm_map_valid(void *mm) {
const spl_map_t *m = (const spl_map_t *)mm;
return m ? spl_map_valid(m) : 0;
}
SPL_INLINE i32 vm_map_reserve(void *mm, u64 need) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return 1;
return spl_map_reserve(m, need);
}
SPL_INLINE i32 vm_map_put(void *mm, const void *key, const void *val) {
spl_map_t *m = (spl_map_t *)mm;
usize existing;
if (!m || !key || !val || !spl_map_valid(m))
return 1;
existing = spl_map_find_slot(m, key);
if (existing != ~(usize)0) {
memcpy((void *)(m->vals.data + existing * m->val_size), val, m->val_size);
return 0;
}
if (m->states.cap == 0) {
int rc = spl_map_reserve(m, 8);
if (rc)
return rc;
} else {
usize next_size, scaled;
if (m->size > ~(usize)0 - 1)
return 3;
next_size = m->size + 1;
if (next_size > ~(usize)0 / 128)
return 3;
scaled = next_size * 128;
if (scaled / m->states.cap >= 70) {
int rc;
if (m->states.cap > ~(usize)0 / 2)
return 3;
rc = spl_map_reserve(m, m->states.cap * 2);
if (rc)
return rc;
}
}
spl_map_place(m, key, val);
return 0;
}
SPL_INLINE i32 vm_map_get(void *mm, const void *key, void *out) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !out || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size);
return 0;
}
SPL_INLINE i32 vm_map_del(void *mm, const void *key) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
((unsigned char *)m->states.data)[i] = 2;
m->size--;
return 0;
}
SPL_INLINE void vm_map_clear(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
if (m->states.data && m->states.len)
memset((void *)m->states.data, 0, m->states.len);
m->size = 0;
}
SPL_INLINE void vm_map_drop(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
m->size = 0;
}
/* ---- file ---- */
SPL_INLINE void *vm_fopen(void *path, void *mode) {
return (void *)fopen((const char *)path, (const char *)mode);
}
SPL_INLINE i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; }
SPL_INLINE u64 vm_fread(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fsize(void *f) {
long cur, end;
if (!f)
return 0;
cur = ftell((FILE *)f);
if (cur < 0)
return 0;
if (fseek((FILE *)f, 0, SEEK_END) != 0)
return 0;
end = ftell((FILE *)f);
fseek((FILE *)f, cur, SEEK_SET);
return end < 0 ? 0 : (u64)end;
}
SPL_INLINE void *vm_stdin(void) { return (void *)stdin; }
SPL_INLINE void *vm_stdout(void) { return (void *)stdout; }
SPL_INLINE void *vm_stderr(void) { return (void *)stderr; }
SPL_INLINE i32 vm_putchar(i32 c) { return fputc(c, stdout); }
SPL_INLINE i32 vm_getchar(void) { return fgetc(stdin); }
/* ---- misc ---- */
SPL_INLINE void vm_exit(i32 code) { exit(code); }
SPL_INLINE u64 vm_timestamp(u64 kind) {
time_t sec = time(NULL);
if (kind == 1)
return (u64)sec;
if (kind == 2)
return 0;
if (kind == 4)
return (u64)sec * 1000000000ull;
return 0;
}
/* ---- 内嵌 VM(comptime):实现在 spl_vm_embed.c,链接 stage0 VM ---- */
#define SPL_VM_EMBED_IMPLIMENTATION
#include "spl_vm_embed.h"
#endif /* __SPL_RT_H__ */
+109
View File
@@ -0,0 +1,109 @@
/* spl_vm_embed.h - 原生编译器内嵌 VM(comptime 执行)。
*
* 单 TU 合并式:定义 SPL_VM_EMBED_IMPLIMENTATION 后 include 本头,会把 stage0 的
* spl_mcode.c / spl_syscall.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。
*/
#ifndef __SPL_VM_EMBED_H__
#define __SPL_VM_EMBED_H__
void *vm_new(void);
void vm_drop(void *vm);
int vm_load_from_buffer(void *vm, const void *buf, unsigned long long len);
void vm_push(void *vm, unsigned long long val);
int vm_call(void *vm, const char *name, unsigned long long nargs);
int vm_run(void *vm);
#ifdef SPL_VM_EMBED_IMPLIMENTATION
#include "../../stage0/spl_mcode.h"
void spl_syscall_register(spl_prog_t *prog) { (void)prog; /* stub */ }
#include "../../stage0/spl_mcode.c"
#include "../../stage0/spl_vm.c"
void *vm_new(void) {
spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t));
if (!vm)
return 0;
spl_vm_init(vm);
return vm;
}
void vm_drop(void *p) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return;
if (vm->prog) {
spl_prog_drop(vm->prog);
free(vm->prog);
vm->prog = 0;
}
spl_vm_drop(vm);
free(vm);
}
int vm_load_from_buffer(void *p, const void *buf, unsigned long long len) {
spl_vm_t *vm = (spl_vm_t *)p;
spl_prog_t *prog;
if (!vm || !buf)
return -1;
prog = (spl_prog_t *)malloc(sizeof(spl_prog_t));
if (!prog)
return -1;
if (spl_prog_load_from_buffer((const char *)buf, (usize)len, prog) != 0) {
free(prog);
return -1;
}
spl_syscall_register(prog);
if (spl_vm_load_prog(vm, prog) != 0) {
spl_prog_drop(prog);
free(prog);
return -1;
}
return 0;
}
void vm_push(void *p, unsigned long long val) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return;
if (vm->sp >= vm->config.max_stack_depth)
return;
vm->stacks.data[vm->sp++] = (spl_vm_val_t)val;
}
int vm_call(void *p, const char *name, unsigned long long nargs) {
spl_vm_t *vm = (spl_vm_t *)p;
spl_vm_func_t *func;
if (!vm || !name)
return -1;
func = spl_prog_get_func(vm->prog, name);
if (!func)
return -1;
if (vm->cp >= vm->config.max_call_depth)
return -1;
/* 入口调用:ip=-1 作 sentinel;实参由 vm_push 压栈。 */
vm->ip = (usize)-1;
vm->cp = 0;
vm->fp = 0;
vm->frames.data[0].saved_sp = vm->sp - (usize)nargs;
vm->frames.data[0].saved_fp = vm->fp;
vm->frames.data[0].saved_ip = vm->ip;
vm->frames.data[0].nargs = (spl_vm_val_t)nargs;
vm->cp = 1;
vm->ip = (usize)func->address;
vm->fp = vm->sp - (usize)nargs;
return 0;
}
int vm_run(void *p) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return -1;
spl_vm_run_until(vm, 0);
return (int)vm->exit_code;
}
#endif /* SPL_VM_EMBED_IMPLIMENTATION */
#endif /* __SPL_VM_EMBED_H__ */
+1 -1
View File
@@ -5,7 +5,7 @@ type spl_vm_val_t = u64; // usize
#extern(vm) fn vm_drop(vm: *any): void;
#extern(vm) fn vm_load(vm: *any, fpath: *u8): void;
#extern(vm) fn vm_load_from_buffer(vm: *any, buffer: []u8): void;
#extern(vm) fn vm_load_from_buffer(vm: *any, buf: *any, len: usize): i32;
#extern(vm) fn vm_push(vm: *any, val: spl_vm_val_t): void;
// TODO