rt: move slice append helpers from lib/slices/ into libwwrt.a

This commit is contained in:
2026-05-11 16:56:46 +09:00
parent 8ffe6dbee6
commit 5408160d49
5 changed files with 23 additions and 34 deletions

View File

@@ -39,7 +39,8 @@ W6L_SRC = cmd/w6l/main.c cmd/w6l/obj.c cmd/w6l/sym.c cmd/w6l/pass.c cmd/w6l/out.
W6L_OBJ = $(W6L_SRC:cmd/w6l/%.c=$(OBJ)/w6l/%.o)
RT_S = rt/start.s rt/syscall.s rt/alloc.s rt/streq.s rt/abort.s
RT_OBJ = $(RT_S:rt/%.s=$(OBJ)/rt/%.o)
RT_WW = rt/append.ww
RT_OBJ = $(RT_S:rt/%.s=$(OBJ)/rt/%.o) $(RT_WW:rt/%.ww=$(OBJ)/rt/%.o)
# Cstage: one-time C bootstrap (see BOOTSTRAP.md). Built by `cc`.
# Goes away at v1.0, replaced by a checked-in stage-0 binary.
@@ -191,6 +192,14 @@ $(BIN)/ww_ww: selfhost/cmd/ww/main.ww selfhost/cmd/wcc/mem.ww lib/os/os.ww \
$(OBJ)/rt/%.o: rt/%.s $(BIN)/w6a | $(OBJ)/rt
$(BIN)/w6a -o $@ $<
# ww-side runtime helpers (rt/*.ww): compile via w6c to .s, then w6a.
# Each .ww module is standalone — uses @symbol FFI for rt_alloc/rt_free
# rather than `use os;` so no bundling is required.
$(OBJ)/rt/%.s: rt/%.ww $(BIN)/w6c | $(OBJ)/rt
$(BIN)/w6c $< > $@
$(OBJ)/rt/%.o: $(OBJ)/rt/%.s $(BIN)/w6a | $(OBJ)/rt
$(BIN)/w6a -o $@ $<
$(LIB)/libwwrt.a: $(RT_OBJ) | $(LIB)
$(AR) rcs $@ $(RT_OBJ)

View File

@@ -1,25 +1,25 @@
// slices — generic slice helpers, written without generics.
// rt/append.ww — slice runtime helpers, archived into libwwrt.a.
//
// CLAUDE.md forbids generics, so we mint per-element-type variants.
// Hare's `append` builtin is what these stand in for: each takes a
// *[]T plus an item, grows the storage if needed, and updates the
// slice header in place. The user passes `&s` because we mutate
// through the pointer.
// The compiler lowers `append(s, v)` to a CALL to one of these by
// element size (1 byte → appendu8, else → appendi64). User code
// never `use`s this — the symbol comes in via the runtime archive,
// like rt_alloc and rt_streq.
use os;
@symbol("rt_alloc") fn alloc(n: u64) *void;
@symbol("rt_free") fn free(p: *void, n: u64) void;
export fn appendu8(s: *[]u8, v: u8) void = {
if (s.len >= s.cap) {
let nc: i32 = s.cap * 2;
if (nc < 8) { nc = 8; };
let np: *u8 = os.alloc(nc: u64): *u8;
let np: *u8 = alloc(nc: u64): *u8;
let i: i32 = 0;
for (i < s.len) {
np[i] = s.ptr[i];
i += 1;
};
if (s.cap > 0) {
os.free(s.ptr: *void, s.cap: u64);
free(s.ptr: *void, s.cap: u64);
};
s.ptr = np;
s.cap = nc;
@@ -32,14 +32,14 @@ export fn appendi64(s: *[]i64, v: i64) void = {
if (s.len >= s.cap) {
let nc: i32 = s.cap * 2;
if (nc < 8) { nc = 8; };
let np: *i64 = os.alloc((nc * 8): u64): *i64;
let np: *i64 = alloc((nc * 8): u64): *i64;
let i: i32 = 0;
for (i < s.len) {
np[i] = s.ptr[i];
i += 1;
};
if (s.cap > 0) {
os.free(s.ptr: *void, (s.cap * 8): u64);
free(s.ptr: *void, (s.cap * 8): u64);
};
s.ptr = np;
s.cap = nc;

View File

@@ -244,24 +244,10 @@ static const struct row rows[] = {
" x *= 2; x <<= 1; x >>= 2;\n"
" return x;\n"
"};", 96 },
/* user-defined slice append via *[]u8: stdlib slices.appendu8.
* Demonstrates allocator + ptr-to-slice fields + scaled index write. */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let s: []u8;\n"
" s.ptr = nil; s.len = 0; s.cap = 0;\n"
" slices.appendu8(&s, 65u8);\n"
" slices.appendu8(&s, 66u8);\n"
" slices.appendu8(&s, 67u8);\n"
" os.write(1, s.ptr, s.len: u64);\n"
" os.write(1, \"\\n\".ptr, 1u64);\n"
" return s.len;\n"
"};", 3 },
/* Hare-style builtins: append(s, v) and len(s). The compiler
* lowers these to slices.appendu8 / s.len access. */
* lowers append to a CALL into libwwrt.a's appendu8 / appendi64
* by element size — no `use rt;` or `use slices;` required. */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let s: []u8;\n"
" s.ptr = nil; s.len = 0; s.cap = 0;\n"
@@ -281,7 +267,6 @@ static const struct row rows[] = {
"};", 12 },
/* variadic append + static qualifier (Hare idiom) */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let s: []u8;\n"
" s.ptr = nil; s.len = 0; s.cap = 0;\n"
@@ -298,7 +283,6 @@ static const struct row rows[] = {
"};", 25 },
/* Hare-style range loop: for (let x .. slice) iterates elements */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let s: []u8;\n"
" s.ptr = nil; s.len = 0; s.cap = 0;\n"
@@ -309,7 +293,6 @@ static const struct row rows[] = {
"};", 100 },
/* alloc([], n): fresh empty slice with cap n */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let s: []u8 = alloc([], 16);\n"
" append(s, 72u8, 105u8);\n"
@@ -317,7 +300,6 @@ static const struct row rows[] = {
"};", 16 },
/* variadic spread: append(dst, src...) iterates src */
{ "use os;\n"
"use slices;\n"
"fn main() i32 = {\n"
" let src: []u8;\n"
" src.ptr = nil; src.len = 0; src.cap = 0;\n"

View File

@@ -28,7 +28,6 @@ static const char *modules[] = {
"lib/bufio/bufio.ww",
"lib/fmt/fmt.ww",
"lib/net/net.ww",
"lib/slices/slices.ww",
NULL
};

View File

@@ -210,7 +210,6 @@ probe_dump_diff(const char *bin)
"lib/types/types.ww",
"lib/sort/sort.ww",
"lib/path/path.ww",
"lib/slices/slices.ww",
"lib/net/net.ww",
"lib/encoding/utf8/utf8.ww",
"lib/encoding/hex/hex.ww",