feat: support existing io.print formatting

This commit is contained in:
2026-11-01 11:37:46 +01:00
parent e036070bf2
commit 1f457d6b41
23 changed files with 895 additions and 116 deletions
+22 -14
View File
@@ -251,10 +251,13 @@ FormatToken :: struct {
@hide:file
parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
tokens [N]mut FormatToken := undefined
mem.set(FormatToken, tokens[..], FormatToken{ kind = .unused, start = 0, end = 0, field = "" })
for (usize(0)..N) |index|
tokens[index] = FormatToken{ kind = .unused, start = 0, end = 0, field = "" }
field_count := 0
match typeinfo!(Args) {
# retained metadata makes parsing constant-input execution, including guarded errors.
info :: typeinfo!(Args)
field_count := usize(0)
match info {
.record |r|: {
if (!r.is_tuple) compile_error!("io.print arguments must be a tuple")
field_count = r.fields.len
@@ -262,10 +265,10 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
else: compile_error!("io.print arguments must be a tuple")
}
token_count := 0
argument_count := 0
literal_start := 0
cursor := 0
token_count := usize(0)
argument_count := usize(0)
literal_start := usize(0)
cursor := usize(0)
while cursor < format.len {
byte :: format[cursor]
if byte == '{' {
@@ -294,7 +297,7 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
}
kind FormatTokenKind := .default
width := 2
width := usize(2)
if next != '}' {
if (cursor + 2 >= format.len or format[cursor + 2] != '}') compile_error!("io.print format expects a one-character specifier")
@@ -367,7 +370,12 @@ parse_format proc($N usize, $format []u8, $Args type) [N]mut FormatToken {
@hide:file
format_field_name proc($T type, index usize) []u8 {
match typeinfo!(T) {
.record |r|: return r.fields[index].name
.record |r|: {
inline for r.fields |field| {
if (index == field.index) return field.name
}
unreachable
}
else: compile_error!("io.print arguments must be a tuple")
}
}
@@ -402,7 +410,7 @@ write_integer proc(
} else {
try write_integer_unsigned(output, u64(value), base, uppercase)
}
.distinct |backing|: if scalar_or_distinct_type(backing) {
.distinct |backing|: if $(scalar_or_distinct_type(backing)) {
try write_integer(output, distinct_value(backing, T, value), base, uppercase)
} else {
compile_error!("io.print integer format requires an integer argument")
@@ -429,7 +437,7 @@ write_float proc($T type, output Writer, value T, scientific bool) void ! WriteE
if (count < 0 or usize(count) >= buffer.len) return .write_failed
try write_all(output, buffer[0..usize(count)])
}
.distinct |backing|: if scalar_or_distinct_type(backing) {
.distinct |backing|: if $(scalar_or_distinct_type(backing)) {
try write_float(output, distinct_value(backing, T, value), scientific)
} else {
compile_error!("io.print float format requires a float argument")
@@ -443,7 +451,7 @@ write_decimal proc($T type, output Writer, value T) void ! WriteError {
match typeinfo!(T) {
.integer: try write_integer(output, value, 10, false)
.float: try write_float(output, value, false)
.distinct |backing|: if scalar_or_distinct_type(backing) {
.distinct |backing|: if $(scalar_or_distinct_type(backing)) {
try write_decimal(output, distinct_value(backing, T, value))
} else {
compile_error!("io.print '{d}' requires an integer or float argument")
@@ -460,7 +468,7 @@ write_character proc($T type, output Writer, value T) void ! WriteError {
buffer [1]u8 :: [u8(value)]
try write_all(output, buffer[..])
}
.distinct |backing|: if scalar_or_distinct_type(backing) {
.distinct |backing|: if $(scalar_or_distinct_type(backing)) {
try write_character(output, distinct_value(backing, T, value))
} else {
compile_error!("io.print '{c}' requires an unsigned integer that fits in u8")
@@ -492,7 +500,7 @@ write_default proc($T type, output Writer, value T) void ! WriteError {
}
return .write_failed
}
.distinct |backing|: if scalar_or_distinct_type(backing) {
.distinct |backing|: if $(scalar_or_distinct_type(backing)) {
try write_default(output, distinct_value(backing, T, value))
} else {
compile_error!("io.print '{}' does not support this argument type")