From 0c9f487783227a894fe08fdf51bbef0dc2f0dbc3 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 18:48:01 -0400 Subject: [PATCH 1/2] Fix and document `%w` verb for `core:fmt` --- core/fmt/doc.odin | 1 + core/fmt/fmt.odin | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/core/fmt/doc.odin b/core/fmt/doc.odin index be666dcc4..d45e6c796 100644 --- a/core/fmt/doc.odin +++ b/core/fmt/doc.odin @@ -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 diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index f9113a7a7..4c65dd01f 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -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.. 0 { io.write_string(fi.writer, "; ", &fi.n) } + if row > 0 { io.write_string(fi.writer, row_separator, &fi.n) } for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } From abe5c2ca83c8c893fa98626448d43c63d9d23a6f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:04:47 -0400 Subject: [PATCH 2/2] Add test for `%w` --- tests/core/fmt/test_core_fmt.odin | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 507e0f433..49142e24d 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -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)