fix comptime specialization, implement io.print
This commit is contained in:
+47
-34
@@ -130,13 +130,13 @@ hide FormatToken :: struct {
|
||||
kind FormatTokenKind
|
||||
start usize
|
||||
end usize
|
||||
arg usize
|
||||
field []u8
|
||||
}
|
||||
|
||||
hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
tokens [N]mut FormatToken = undefined
|
||||
for (usize(0))..format.len |index| {
|
||||
tokens[index] = FormatToken {kind = .unused, start = 0, end = 0, arg = 0}
|
||||
tokens[index] = FormatToken {kind = .unused, start = 0, end = 0, field = ""}
|
||||
}
|
||||
field_count usize = 0
|
||||
match typeinfo!(Args) {
|
||||
@@ -160,12 +160,12 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
compile_error!("io.print format has an unmatched '{'")
|
||||
}
|
||||
if cursor > literal_start {
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, arg = 0}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, field = ""}
|
||||
token_count += 1
|
||||
}
|
||||
next :: format[cursor + 1]
|
||||
if next == '{' {
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, arg = 0}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, field = ""}
|
||||
token_count += 1
|
||||
cursor += 2
|
||||
literal_start = cursor
|
||||
@@ -182,7 +182,15 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
} else {
|
||||
compile_error!("io.print format has an unknown specifier")
|
||||
}
|
||||
tokens[token_count] = FormatToken {kind = kind, start = 0, end = 0, arg = argument_count}
|
||||
if argument_count >= field_count {
|
||||
compile_error!("io.print format argument count does not match the tuple")
|
||||
}
|
||||
tokens[token_count] = FormatToken {
|
||||
kind = kind,
|
||||
start = 0,
|
||||
end = 0,
|
||||
field = format_field_name(Args, argument_count),
|
||||
}
|
||||
token_count += 1
|
||||
argument_count += 1
|
||||
cursor += 3
|
||||
@@ -194,10 +202,10 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
compile_error!("io.print format has an unmatched '}'")
|
||||
}
|
||||
if cursor > literal_start {
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, arg = 0}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = cursor, field = ""}
|
||||
token_count += 1
|
||||
}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, arg = 0}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = cursor, end = cursor + 1, field = ""}
|
||||
token_count += 1
|
||||
cursor += 2
|
||||
literal_start = cursor
|
||||
@@ -206,7 +214,7 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
cursor += 1
|
||||
}
|
||||
if literal_start < format.len {
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = format.len, arg = 0}
|
||||
tokens[token_count] = FormatToken {kind = .literal, start = literal_start, end = format.len, field = ""}
|
||||
}
|
||||
if argument_count != field_count {
|
||||
compile_error!("io.print format argument count does not match the tuple")
|
||||
@@ -214,39 +222,44 @@ hide parse_format func($N usize, $format []u8, $Args type) [N]mut FormatToken {
|
||||
return tokens
|
||||
}
|
||||
|
||||
hide format_field_name func($T type, index usize) []u8 {
|
||||
match typeinfo!(T) {
|
||||
.record |record|: return record.fields[index].name
|
||||
else: compile_error!("io.print arguments must be a tuple")
|
||||
}
|
||||
}
|
||||
|
||||
hide write_decimal func(writer Writer, $T type, value T) void ! WriteError {
|
||||
match typeinfo!(T) {
|
||||
.integer: if minval!(T) < 0 {
|
||||
try write_decimal_signed(writer, i64(value))
|
||||
} else {
|
||||
try write_decimal_unsigned(writer, u64(value))
|
||||
}
|
||||
else: compile_error!("io.print '{d}' requires an integer argument")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
print func(
|
||||
writer Writer,
|
||||
$format []u8,
|
||||
$Args type,
|
||||
args Args,
|
||||
) void ! WriteError {
|
||||
match typeinfo!(Args) {
|
||||
.record |record|: inline for $parse_format(format.len, format, Args) |token| {
|
||||
if (token.kind == .literal) {
|
||||
try write_all(writer, format[token.start..token.end])
|
||||
}
|
||||
if (token.kind == .string or token.kind == .decimal) {
|
||||
inline for record.fields |field| {
|
||||
if (field.index == token.arg) {
|
||||
if (token.kind == .string) {
|
||||
try write_all(writer, field!(args, field.name))
|
||||
} else {
|
||||
match typeinfo!(field.type) {
|
||||
.integer: {
|
||||
if minval!(field.type) < 0 {
|
||||
try write_decimal_signed(writer, i64(field!(args, field.name)))
|
||||
} else {
|
||||
try write_decimal_unsigned(writer, u64(field!(args, field.name)))
|
||||
}
|
||||
}
|
||||
else: compile_error!("io.print '{d}' requires an integer argument")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inline for parse_format(format.len, format, Args) |token| {
|
||||
if (token.kind == .unused) {
|
||||
break
|
||||
}
|
||||
else: compile_error!("io.print arguments must be a tuple")
|
||||
if (token.kind == .literal) {
|
||||
try write_all(writer, format[token.start..token.end])
|
||||
continue
|
||||
}
|
||||
if (token.kind == .string) {
|
||||
try write_all(writer, field!(args, token.field))
|
||||
continue
|
||||
}
|
||||
try write_decimal(writer, field!(args, token.field))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user