formatter update
This commit is contained in:
parent
e2dd379fea
commit
d55fd895c9
|
@ -1,30 +1,49 @@
|
||||||
.{string, primitive, unsigned_int, signed_int, float, integer, memory, panic} := @use("stn")
|
.{string, pointer, primitive, unsigned_int, signed_int, float, integer, memory, panic} := @use("stn")
|
||||||
|
|
||||||
format_int := fn($T: type, v: T, str: ^u8): uint {
|
format_int := fn($T: type, v: T, str: ^u8, radix: T): uint {
|
||||||
if integer(T) {
|
if integer(T) {
|
||||||
is_negative := signed_int(T) & v < 0
|
is_negative := signed_int(T) & v < 0
|
||||||
i := 0
|
|
||||||
if is_negative v = -v
|
if is_negative v = -v
|
||||||
|
|
||||||
if v == 0 {
|
prefix_len := 0
|
||||||
*str = '0'
|
if radix == 16 {
|
||||||
return 1
|
*str = '0';
|
||||||
|
*(str + 1) = 'x'
|
||||||
|
prefix_len = 2
|
||||||
|
} else if radix == 2 {
|
||||||
|
*str = '0';
|
||||||
|
*(str + 1) = 'b'
|
||||||
|
prefix_len = 2
|
||||||
|
} else if radix == 8 {
|
||||||
|
*str = '0';
|
||||||
|
*(str + 1) = 'o'
|
||||||
|
prefix_len = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
loop if v == 0 break else {
|
if v == 0 {
|
||||||
remainder := v % 10
|
*(str + prefix_len) = '0'
|
||||||
v /= 10;
|
return prefix_len + 1
|
||||||
*(str + i) = @intcast(remainder + '0')
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
loop if v <= 0 break else {
|
||||||
|
remainder := v % radix
|
||||||
|
v /= radix
|
||||||
|
if remainder > 9 {
|
||||||
|
*(str + prefix_len + i) = @intcast(remainder - 10 + 'A')
|
||||||
|
} else {
|
||||||
|
*(str + prefix_len + i) = @intcast(remainder + '0')
|
||||||
|
}
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_negative {
|
if is_negative {
|
||||||
*(str + i) = '-'
|
*(str + prefix_len + i) = '-'
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline(string.reverse, str)
|
@inline(string.reverse, str + prefix_len)
|
||||||
return i
|
return prefix_len + i
|
||||||
} else {
|
} else {
|
||||||
panic("Type is not an integer\0")
|
panic("Type is not an integer\0")
|
||||||
}
|
}
|
||||||
|
@ -32,85 +51,110 @@ format_int := fn($T: type, v: T, str: ^u8): uint {
|
||||||
|
|
||||||
format_bool := fn(v: bool, str: ^u8): uint {
|
format_bool := fn(v: bool, str: ^u8): uint {
|
||||||
if v {
|
if v {
|
||||||
memory.copy(u8, "true\0", str, 4)
|
*@as(^[u8; 4], @bitcast(str)) = *@bitcast("true\0")
|
||||||
return 4
|
return 4
|
||||||
} else {
|
} else {
|
||||||
memory.copy(u8, "false\0", str, 5)
|
*@as(^[u8; 5], @bitcast(str)) = *@bitcast("false\0")
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_float := fn($T: type, v: T, str: ^u8, precision: uint): uint {
|
format_float := fn($T: type, v: T, str: ^u8, precision: uint, radix: int): uint {
|
||||||
if float(T) {
|
if float(T) {
|
||||||
is_negative := v < 0
|
is_negative := v < 0
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
|
prefix_len := 0
|
||||||
|
if radix == 16 {
|
||||||
|
*str = '0';
|
||||||
|
*(str + 1) = 'x'
|
||||||
|
prefix_len = 2
|
||||||
|
} else if radix == 2 {
|
||||||
|
*str = '0';
|
||||||
|
*(str + 1) = 'b'
|
||||||
|
prefix_len = 2
|
||||||
|
} else if radix == 8 {
|
||||||
|
*str = '0';
|
||||||
|
*(str + 1) = 'o'
|
||||||
|
prefix_len = 2
|
||||||
|
}
|
||||||
|
|
||||||
if is_negative v = -v
|
if is_negative v = -v
|
||||||
|
|
||||||
integer_part := @fti(v)
|
integer_part := @fti(v)
|
||||||
fractional_part := v - @itf(integer_part)
|
fractional_part := v - @itf(integer_part)
|
||||||
|
|
||||||
loop if integer_part == 0 & i > 0 break else {
|
loop if integer_part == 0 & i > 0 break else {
|
||||||
remainder := integer_part % 10
|
remainder := integer_part % radix
|
||||||
integer_part /= 10;
|
integer_part /= radix
|
||||||
*(str + i) = @intcast(remainder + '0')
|
if remainder > 9 {
|
||||||
|
*(str + prefix_len + i) = @intcast(remainder - 10 + 'A')
|
||||||
|
} else {
|
||||||
|
*(str + prefix_len + i) = @intcast(remainder + '0')
|
||||||
|
}
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_negative {
|
if is_negative {
|
||||||
*(str + i) = '-'
|
*(str + prefix_len + i) = '-'
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@inline(string.reverse, str);
|
@inline(string.reverse, str + prefix_len);
|
||||||
*(str + i) = '.'
|
*(str + prefix_len + i) = '.'
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
tolerance := @as(T, 0.000000001)
|
|
||||||
p := precision
|
p := precision
|
||||||
|
tolerance := @as(T, 0.00000001)
|
||||||
loop if p <= 0 | fractional_part < tolerance break else {
|
loop if p <= 0 | fractional_part < tolerance break else {
|
||||||
fractional_part *= 10.0
|
fractional_part *= @itf(radix)
|
||||||
digit := @fti(fractional_part);
|
digit := @fti(fractional_part)
|
||||||
*(str + i) = @intcast(digit + '0')
|
if digit > 9 {
|
||||||
|
*(str + prefix_len + i) = @intcast(digit - 10 + 'A')
|
||||||
|
} else {
|
||||||
|
*(str + prefix_len + i) = @intcast(digit + '0')
|
||||||
|
}
|
||||||
i += 1
|
i += 1
|
||||||
fractional_part -= @itf(digit)
|
fractional_part -= @itf(digit)
|
||||||
p -= 1
|
p -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
return prefix_len + i
|
||||||
} else {
|
} else {
|
||||||
panic("Type is not a floating point\0")
|
panic("Type is not a floating point\0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_inner := fn($T: type, v: T, str: ^u8, opts: FormatOptions): uint {
|
format_inner := fn($T: type, v: T, str: ^u8, opts: FormatOptions): uint {
|
||||||
if integer(T) {
|
if integer(T) | pointer(T) {
|
||||||
return @inline(format_int, T, v, str)
|
if integer(T) {
|
||||||
|
return @inline(format_int, T, v, str, @intcast(opts.radix))
|
||||||
|
} else {
|
||||||
|
return @inline(format_int, uint, @bitcast(v), str, 16)
|
||||||
|
}
|
||||||
} else if T == bool {
|
} else if T == bool {
|
||||||
return @inline(format_bool, v, str)
|
return @inline(format_bool, v, str)
|
||||||
} else if float(T) {
|
} else if float(T) {
|
||||||
return @inline(format_float, T, v, str, opts.decimal_digits)
|
return @inline(format_float, T, v, str, opts.decimal_digits, @intcast(opts.radix))
|
||||||
} else if !primitive(T) {
|
} else if !primitive(T) {
|
||||||
i := 0
|
i := 0
|
||||||
// name := @nameof(T)
|
// name := @nameof(T)
|
||||||
// len := string.length(name)
|
// len := @inline(string.length, name)
|
||||||
// memory.copy(u8, name, str, len)
|
len := 0;
|
||||||
len := 0
|
*@as(^[u8; 2], @bitcast(str + len)) = *@bitcast(".(\0")
|
||||||
memory.copy(u8, ".(\0", str + len, 2)
|
|
||||||
len += 2
|
len += 2
|
||||||
$loop if i == @len(T) break else {
|
$loop {
|
||||||
v_sub := v[i]
|
v_sub := v[i]
|
||||||
TSub := @TypeOf(v_sub)
|
TSub := @TypeOf(v_sub)
|
||||||
len += @inline(format_inner, TSub, v_sub, str + len, opts)
|
len += @inline(format_inner, TSub, v_sub, str + len, opts)
|
||||||
if i != @len(T) - 1 {
|
|
||||||
memory.copy(u8, ", \0", str + len, 2)
|
|
||||||
len += 2
|
|
||||||
} else {
|
|
||||||
memory.copy(u8, ")\0", str + len, 1)
|
|
||||||
len += 1
|
|
||||||
}
|
|
||||||
i += 1
|
i += 1
|
||||||
}
|
if i == @len(T) break else {
|
||||||
|
*@as(^[u8; 2], @bitcast(str + len)) = *@bitcast(", \0")
|
||||||
|
len += 2
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*@as(^[u8; 1], @bitcast(str + len)) = *@bitcast(")\0")
|
||||||
|
len += 1
|
||||||
return len
|
return len
|
||||||
} else {
|
} else {
|
||||||
panic("Unsupported formatter type\0")
|
panic("Unsupported formatter type\0")
|
||||||
|
@ -121,11 +165,8 @@ format_inner := fn($T: type, v: T, str: ^u8, opts: FormatOptions): uint {
|
||||||
* Custom formatters using struct methods (T._fmt(self, str): uint),
|
* Custom formatters using struct methods (T._fmt(self, str): uint),
|
||||||
* Format struct names "Name.(x, y, z)"
|
* Format struct names "Name.(x, y, z)"
|
||||||
* Format struct fields "Name.{a: x, b: y, c: z}"
|
* Format struct fields "Name.{a: x, b: y, c: z}"
|
||||||
* Optimise (so many instructions...)
|
|
||||||
* -> Consider switching `memory.copy` to loop for comptime stuff
|
|
||||||
* Optionally tabulate
|
* Optionally tabulate
|
||||||
* Add more FormatOption fields
|
* Add more FormatOption fields
|
||||||
* Support radices for integers
|
|
||||||
* Support scientific notation for floating point
|
* Support scientific notation for floating point
|
||||||
* Support format string (impossible right now)
|
* Support format string (impossible right now)
|
||||||
* Support nullables (impossible right now)
|
* Support nullables (impossible right now)
|
||||||
|
@ -134,10 +175,14 @@ format_inner := fn($T: type, v: T, str: ^u8, opts: FormatOptions): uint {
|
||||||
|
|
||||||
FormatOptions := struct {
|
FormatOptions := struct {
|
||||||
decimal_digits: uint,
|
decimal_digits: uint,
|
||||||
|
radix: uint,
|
||||||
}
|
}
|
||||||
|
|
||||||
$DEFAULT_OPTS := FormatOptions.(2)
|
$DEFAULT_OPTS := FormatOptions.(2, 10)
|
||||||
|
|
||||||
|
/* SAFETY:
|
||||||
|
* Assumes the buffer is wide enough for the formatted text and a null char
|
||||||
|
*/
|
||||||
format := fn($T: type, v: T, str: ^u8): ^u8 return @inline(format_args, T, v, str, DEFAULT_OPTS)
|
format := fn($T: type, v: T, str: ^u8): ^u8 return @inline(format_args, T, v, str, DEFAULT_OPTS)
|
||||||
|
|
||||||
format_args := fn($T: type, v: T, str: ^u8, opts: FormatOptions): ^u8 {
|
format_args := fn($T: type, v: T, str: ^u8, opts: FormatOptions): ^u8 {
|
||||||
|
|
|
@ -24,6 +24,10 @@ panic := fn(message: ?^u8): never {
|
||||||
die
|
die
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$pointer := fn($T: type): bool {
|
||||||
|
return T != f64 & T != uint & T != int & @sizeof(T) == @sizeof(uint) & @alignof(T) == @alignof(uint)
|
||||||
|
}
|
||||||
|
|
||||||
$unsigned_int := fn($T: type): bool {
|
$unsigned_int := fn($T: type): bool {
|
||||||
return T == uint | T == u8 | T == u16 | T == u32
|
return T == uint | T == u8 | T == u16 | T == u32
|
||||||
}
|
}
|
||||||
|
@ -41,7 +45,7 @@ $float := fn($T: type): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
$primitive := fn($T: type): bool {
|
$primitive := fn($T: type): bool {
|
||||||
return integer(T) | float(T) | T == bool
|
return integer(T) | float(T) | pointer(T) | T == bool
|
||||||
}
|
}
|
||||||
|
|
||||||
$float_bytes := fn($T: type): type {
|
$float_bytes := fn($T: type): type {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.{formatters: .{format, format_args}, log, memory, math} := @use("stn");
|
.{formatters: .{format, format_args, DEFAULT_OPTS}, log, memory, math} := @use("stn");
|
||||||
.{Color} := @use("lib:render")
|
.{Color} := @use("lib:render")
|
||||||
|
|
||||||
Thingy := struct {
|
Thingy := struct {
|
||||||
|
@ -16,10 +16,14 @@ test := fn(): uint {
|
||||||
buffer := memory.request_page(1)
|
buffer := memory.request_page(1)
|
||||||
log.info(format(Thingy, .(-100, -100, .(-math.PI, true)), buffer))
|
log.info(format(Thingy, .(-100, -100, .(-math.PI, true)), buffer))
|
||||||
log.info(format(SubThingy, .(-math.E, false), buffer))
|
log.info(format(SubThingy, .(-math.E, false), buffer))
|
||||||
log.info(format(Color, .{r: 1, g: 2, b: 3, a: 4}, buffer))
|
log.info(format_args(Color, .{r: 255, g: 254, b: 253, a: 252}, buffer, .{
|
||||||
|
decimal_digits: DEFAULT_OPTS.decimal_digits,
|
||||||
|
radix: 16,
|
||||||
|
}))
|
||||||
// default value: .{decimal_digits: 2}
|
// default value: .{decimal_digits: 2}
|
||||||
log.info(format_args(f64, math.LN_2, buffer, .{decimal_digits: 1 << 32}))
|
log.info(format_args(f64, math.LN_2, buffer, .{decimal_digits: 1 << 32, radix: 16}))
|
||||||
log.info(format([u8; 3], .(1, 2, 3), buffer))
|
log.info(format([u8; 3], .(1, 2, 3), buffer))
|
||||||
|
log.info(format(^SubThingy, &.(0.0, true), buffer))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
Loading…
Reference in a new issue