Merge pull request #3749 from Feoramund/fix-w

Improve support for `%w`
This commit is contained in:
Jeroen van Rijn
2024-06-13 10:07:48 +02:00
committed by GitHub
3 changed files with 131 additions and 6 deletions

View File

@@ -9,6 +9,7 @@ The verbs:
General:
%v the value in a default format
%#v an expanded format of %v with newlines and indentation
%w an Odin-syntax representation of the value
%T an Odin-syntax representation of the type of the value
%% a literal percent sign; consumes no value
{{ a literal open brace; consumes no value

View File

@@ -1726,10 +1726,12 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
et := runtime.type_info_base(info.elem)
if name != "" {
io.write_string(fi.writer, name, &fi.n)
} else {
reflect.write_type(fi.writer, type_info, &fi.n)
if verb != 'w' {
if name != "" {
io.write_string(fi.writer, name, &fi.n)
} else {
reflect.write_type(fi.writer, type_info, &fi.n)
}
}
io.write_byte(fi.writer, '{', &fi.n)
defer io.write_byte(fi.writer, '}', &fi.n)
@@ -1746,9 +1748,17 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') {
}
if is_enum {
enum_name: string
if ti_named, is_named := info.elem.variant.(runtime.Type_Info_Named); is_named {
enum_name = ti_named.name
}
for ev, evi in e.values {
v := u64(ev)
if v == u64(i) {
if verb == 'w' {
io.write_string(fi.writer, enum_name, &fi.n)
io.write_byte(fi.writer, '.', &fi.n)
}
io.write_string(fi.writer, e.names[evi], &fi.n)
commas += 1
continue loop
@@ -2391,7 +2401,6 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
runtime.Type_Info_Dynamic_Array,
runtime.Type_Info_Slice,
runtime.Type_Info_Struct,
runtime.Type_Info_Union,
runtime.Type_Info_Enum,
runtime.Type_Info_Map,
runtime.Type_Info_Bit_Set,
@@ -2498,8 +2507,9 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
}
} else {
// Printed in Row-Major layout to match text layout
row_separator := ", " if verb == 'w' else "; "
for row in 0..<info.row_count {
if row > 0 { io.write_string(fi.writer, "; ", &fi.n) }
if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) }
for col in 0..<info.column_count {
if col > 0 { io.write_string(fi.writer, ", ", &fi.n) }

View File

@@ -258,6 +258,120 @@ test_pointers :: proc(t: ^testing.T) {
check(t, "0xFFFF", "%#4p", d)
}
@(test)
test_odin_value_export :: proc(t: ^testing.T) {
E :: enum u32 {
A, B, C,
}
F :: enum i16 {
A, B, F,
}
S :: struct {
j, k: int,
}
ST :: struct {
x: int `fmt:"-"`,
y: u8 `fmt:"r,0"`,
z: string `fmt:"s,0"`,
}
U :: union {
i8,
i16,
}
UEF :: union { E, F }
A :: [2]int
BSE :: distinct bit_set[E]
i : int = 64
f : f64 = 3.14
c : complex128 = 7+3i
q : quaternion256 = 1+2i+3j+4k
mat : matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
matc : #column_major matrix[2,3]f32 = {1.5, 2, 1, 0.777, 0.333, 0.8}
e : enum {A, B, C} = .B
en : E = E.C
ena : [2]E = {E.A, E.C}
s : struct { j: int, k: int } = { j = 16, k = 8 }
sn : S = S{ j = 24, k = 12 }
st : ST = { 32768, 57, "Hellope" }
str : string = "Hellope"
strc : cstring = "Hellope"
bsu : bit_set[0..<32; u32] = {0, 1}
bs : bit_set[4..<16] = {5, 7}
bse : bit_set[E] = { .B, .A }
bsE : BSE = { .A, .C }
arr : [3]int = {1, 2, 3}
ars : [3]S = {S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}
darr : [dynamic]u8 = { 128, 64, 32 }
dars : [dynamic]S = {S{j = 1, k = 2}, S{j = 3, k = 4}}
na : A = {7, 5}
may0 : Maybe(int)
may1 : Maybe(int) = 1
uz : union {i8, i16} = i8(-33)
u0 : U = U(nil)
u1 : U = i16(42)
uef0 : UEF = E.A
uefa : [3]UEF = { E.A, F.A, F.F }
map_ : map[string]u8 = {"foo" = 8, "bar" = 4}
bf : bit_field int {
a: int | 4,
b: int | 4,
e: E | 4,
} = {a = 1, b = 2, e = .A}
defer {
delete(darr)
delete(dars)
delete(map_)
}
check(t, "64", "%w", i)
check(t, "3.14", "%w", f)
check(t, "7+3i", "%w", c)
check(t, "1+2i+3j+4k", "%w", q)
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", mat)
check(t, "{1.5, 2, 1, 0.777, 0.333, 0.8}", "%w", matc)
check(t, ".B", "%w", e)
check(t, "E.C", "%w", en)
check(t, "{E.A, E.C}", "%w", ena)
check(t, "{j = 16, k = 8}", "%w", s)
check(t, "S{j = 24, k = 12}", "%w", sn)
check(t, `ST{y = 57, z = "Hellope"}`, "%w", st)
check(t, `"Hellope"`, "%w", str)
check(t, `"Hellope"`, "%w", strc)
check(t, "{0, 1}", "%w", bsu)
check(t, "{5, 7}", "%w", bs)
check(t, "{E.A, E.B}", "%w", bse)
check(t, "{E.A, E.C}", "%w", bsE)
check(t, "{1, 2, 3}", "%w", arr)
check(t, "{S{j = 3, k = 2}, S{j = 2, k = 1}, S{j = 1, k = 0}}", "%w", ars)
check(t, "{128, 64, 32}", "%w", darr)
check(t, "{S{j = 1, k = 2}, S{j = 3, k = 4}}", "%w", dars)
check(t, "{7, 5}", "%w", na)
check(t, "nil", "%w", may0)
check(t, "1", "%w", may1)
check(t, "-33", "%w", uz)
check(t, "nil", "%w", u0)
check(t, "42", "%w", u1)
check(t, "E.A", "%w", uef0)
check(t, "{E.A, F.A, F.F}", "%w", uefa)
check(t, "{a = 1, b = 2, e = E.A}", "%w", bf)
// Check this manually due to the non-deterministic ordering of map keys.
switch fmt.tprintf("%w", map_) {
case `{"foo"=8, "bar"=4}`: break
case `{"bar"=4, "foo"=8}`: break
case: testing.fail(t)
}
}
@(private)
check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) {
got := fmt.tprintf(format, ..args)