stage2 更多底层函数 stage1 layout正确使用 内置函数重新编写

This commit is contained in:
zzy committed 2026-09-17 22:03:23 +08:00
1 parent fb0ff9b663
commit 4141e7d574
15 files changed
+2588 -122

No files matched your search

+241
View File
@@ -0,0 +1,241 @@
// Expect retcode = 0
// 数值/布尔格式化,写入 ByteBuffer。radix 取值 2..36;uppercase 只影响 10..35 的字母形式。
// 不分配额外内存(除目标 ByteBuffer 自身扩容),失败不产生部分输出。
type .{ .Error, .Status, .make } = @import("error.spl");
type .{ .ByteBuffer } = @import("byte_buffer.spl");
type .{ .digit_char } = @import("ascii.spl");
// 注意:radix 边界直接用字面量。stage1 刻意不做常量求值/折叠,
// 顶层 const 不应用于运行时表达式。
fn valid_radix(radix: u8): bool {
ret radix >= 2 && radix <= 36;
}
fn append_u64(out: *ByteBuffer, value: u64, radix: u8, uppercase: bool): Status {
if !valid_radix(radix) { ret .Err(make(.InvalidArgument)); }
var digits: [64]u8 = undefined;
var count: usize = 0;
if value == 0 {
digits[0] = 48;
count = 1;
} else {
var v = value;
var base = radix as u64;
while v != 0 {
var d = (v % base) as u8;
match digit_char(d, uppercase) {
.Ok(c) => { digits[count] = c; },
.Err(error) => { ret .Err(error); },
}
count = count + 1;
v = v / base;
}
}
// digits 是低位在前,反向写入得到正常顺序。
var i = count;
while i > 0 {
i = i - 1;
match ByteBuffer.append_byte(out, digits[i]) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
}
ret .Ok;
}
fn append_i64(out: *ByteBuffer, value: i64, radix: u8, uppercase: bool): Status {
if !valid_radix(radix) { ret .Err(make(.InvalidArgument)); }
if value < 0 {
match ByteBuffer.append_byte(out, 45) { // '-'
.Ok => {},
.Err(error) => { ret .Err(error); },
}
// value 为补码,(0 - (value as u64)) 得到绝对值(含 i64 最小值)。
var magnitude = 0 - (value as u64);
ret append_u64(out, magnitude, radix, uppercase);
}
ret append_u64(out, value as u64, radix, uppercase);
}
fn append_usize(out: *ByteBuffer, value: usize, radix: u8, uppercase: bool): Status {
ret append_u64(out, value as u64, radix, uppercase);
}
fn append_isize(out: *ByteBuffer, value: isize, radix: u8, uppercase: bool): Status {
ret append_i64(out, value as i64, radix, uppercase);
}
fn append_bool(out: *ByteBuffer, value: bool): Status {
if value { ret ByteBuffer.append(out, "true"); }
ret ByteBuffer.append(out, "false");
}
// ---- 测试辅助 ----
fn expect_ok(result: Status) {
match result {
.Ok => {},
.Err(error) => { @assert(false, "unexpected fmt error"); },
}
}
fn expect_invalid(result: Status) {
match result {
.Ok => { @assert(false, "expected fmt error"); },
.Err(error) => {
match error.kind {
.InvalidArgument => {},
_ => { @assert(false, "unexpected fmt error kind"); },
}
},
}
}
fn expect_text(buffer: *ByteBuffer, expected: []u8) {
var actual = ByteBuffer.as_slice(buffer.*);
@assert(actual.len == expected.len, "formatted length");
var i: usize = 0;
while i < expected.len {
@assert(actual.ptr[i] == expected.ptr[i], "formatted byte");
i = i + 1;
}
}
fn test_unsigned() {
var b = ByteBuffer.new();
expect_ok(append_u64(&b, 0, 10, false));
expect_text(&b, "0");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 42, 10, false));
expect_text(&b, "42");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 1234567890, 10, false));
expect_text(&b, "1234567890");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 18446744073709551615, 10, false));
expect_text(&b, "18446744073709551615");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 255, 16, false));
expect_text(&b, "ff");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 255, 16, true));
expect_text(&b, "FF");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 4096, 16, false));
expect_text(&b, "1000");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 170, 2, false));
expect_text(&b, "10101010");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 35, 36, false));
expect_text(&b, "z");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 18446744073709551615, 2, false));
expect_text(&b, "1111111111111111111111111111111111111111111111111111111111111111");
ByteBuffer.clear(&b);
ByteBuffer.drop(&b);
}
fn test_signed() {
var b = ByteBuffer.new();
expect_ok(append_i64(&b, 0, 10, false));
expect_text(&b, "0");
ByteBuffer.clear(&b);
expect_ok(append_i64(&b, -123, 10, false));
expect_text(&b, "-123");
ByteBuffer.clear(&b);
expect_ok(append_i64(&b, 9223372036854775807, 10, false));
expect_text(&b, "9223372036854775807");
ByteBuffer.clear(&b);
expect_ok(append_i64(&b, -9223372036854775808, 10, false));
expect_text(&b, "-9223372036854775808");
ByteBuffer.clear(&b);
expect_ok(append_isize(&b, -16, 16, false));
expect_text(&b, "-10");
ByteBuffer.clear(&b);
expect_ok(append_u64(&b, 48879, 16, true));
expect_text(&b, "BEEF");
ByteBuffer.clear(&b);
ByteBuffer.drop(&b);
}
fn test_usize_bool_and_errors() {
var b = ByteBuffer.new();
expect_ok(append_usize(&b, 1000 as usize, 10, false));
expect_text(&b, "1000");
ByteBuffer.clear(&b);
expect_ok(append_bool(&b, true));
expect_text(&b, "true");
ByteBuffer.clear(&b);
expect_ok(append_bool(&b, false));
expect_text(&b, "false");
ByteBuffer.clear(&b);
expect_invalid(append_u64(&b, 1, 0, false));
expect_invalid(append_u64(&b, 1, 1, false));
expect_invalid(append_u64(&b, 1, 37, false));
expect_invalid(append_i64(&b, -1, 0, false));
@assert(ByteBuffer.size(b) == 0, "invalid radix writes nothing");
ByteBuffer.drop(&b);
}
fn test_composition_and_growth() {
var b = ByteBuffer.new();
expect_ok(ByteBuffer.append(&b, "x="));
expect_ok(append_i64(&b, -42, 10, false));
expect_ok(ByteBuffer.append(&b, " hex="));
expect_ok(append_u64(&b, 255, 16, false));
expect_ok(ByteBuffer.append(&b, " ok="));
expect_ok(append_bool(&b, true));
expect_text(&b, "x=-42 hex=ff ok=true");
ByteBuffer.clear(&b);
// 反复写入触发 ByteBuffer 扩容,校验累积内容。
var i: i32 = 0;
while i < 200 {
expect_ok(append_i64(&b, i as i64, 10, false));
expect_ok(ByteBuffer.append_byte(&b, 44)); // ','
i = i + 1;
}
expect_ok(append_i64(&b, 200, 10, false));
@assert(ByteBuffer.size(b) > 0, "growth content");
var s = ByteBuffer.as_slice(b);
@assert(s.ptr[0] == 48, "starts with 0");
@assert(s.ptr[1] == 44, "0 then comma");
ByteBuffer.drop(&b);
}
fn main() {
test_unsigned();
test_signed();
test_usize_bool_and_errors();
test_composition_and_growth();
}