diff options
| author | gingerBill <bill@gingerbill.org> | 2024-03-07 13:39:44 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2024-03-07 13:39:44 +0000 |
| commit | 573402c97e4d3a49e870af077e189fbbf2736efd (patch) | |
| tree | 3ccb15b20c5f88d3a12b04d2802b2247e643af07 | |
| parent | e01701ce0eed3f9491f531e5a38e36ad403eaa05 (diff) | |
Begin work on `%w` - 'w'rite as valid Odin literals
| -rw-r--r-- | core/fmt/fmt.odin | 387 |
1 files changed, 217 insertions, 170 deletions
diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index cadc9f1dd..6ec495500 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -972,7 +972,7 @@ fmt_bad_verb :: proc(fi: ^Info, verb: rune) { // fmt_bool :: proc(fi: ^Info, b: bool, verb: rune) { switch verb { - case 't', 'v': + case 't', 'v', 'w': fmt_string(fi, b ? "true" : "false", 's') case: fmt_bad_verb(fi, verb) @@ -1209,7 +1209,7 @@ fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) { switch verb { case 'c', 'r', 'v': io.write_rune(fi.writer, r, &fi.n) - case 'q': + case 'q', 'w': fi.n += io.write_quoted_rune(fi.writer, r) case: fmt_int(fi, u64(r), false, 32, verb) @@ -1226,7 +1226,8 @@ fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) { // fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) { switch verb { - case 'v': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) + case 'v', 'w': + _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) case 'b': _fmt_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER) case 'o': _fmt_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER) case 'i', 'd': _fmt_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) @@ -1261,7 +1262,8 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) { // fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: rune) { switch verb { - case 'v': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) + case 'v', 'w': + _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) case 'b': _fmt_int_128(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER) case 'o': _fmt_int_128(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER) case 'i', 'd': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER) @@ -1351,7 +1353,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b // fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { switch verb { - case 'g', 'G', 'v': + case 'g', 'G', 'v', 'w': _fmt_float_as(fi, v, bit_size, verb, 'g', -1) case 'f', 'F': _fmt_float_as(fi, v, bit_size, verb, 'f', 3) @@ -1424,7 +1426,7 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) { io.write_string(fi.writer, s, &fi.n) } - case 'q': // quoted string + case 'q', 'w': // quoted string io.write_quoted_string(fi.writer, s, '"', &fi.n) case 'x', 'X': @@ -1467,7 +1469,7 @@ fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) { fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) { u := u64(uintptr(p)) switch verb { - case 'p', 'v': + case 'p', 'v', 'w': if !fi.hash && verb == 'v' { io.write_string(fi.writer, "0x", &fi.n) } @@ -1535,7 +1537,7 @@ string_to_enum_value :: proc($T: typeid, s: string) -> (T, bool) { // Inputs: // - fi: Pointer to the Info struct containing format settings. // - v: The enum value to format. -// - verb: The format specifier character (e.g. 'i','d','f','s','v','q'). +// - verb: The format specifier character (e.g. 'i','d','f','s','v','q','w'). // fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { if v.id == nil || v.data == nil { @@ -1559,6 +1561,15 @@ fmt_enum :: proc(fi: ^Info, v: any, verb: rune) { fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, 'i') io.write_string(fi.writer, ")", &fi.n) } + case 'w': + if str, ok := enum_value_to_string(v); ok { + io.write_byte(fi.writer, '.', &fi.n) + io.write_string(fi.writer, str, &fi.n) + } else { + io.write_string(fi.writer, "%!(BAD ENUM VALUE=", &fi.n) + fmt_arg(fi, any{v.data, runtime.type_info_base(e.base).id}, 'i') + io.write_string(fi.writer, ")", &fi.n) + } } } } @@ -1747,8 +1758,8 @@ fmt_write_indent :: proc(fi: ^Info) { // - verb: The formatting verb to be used for the array elements. // fmt_write_array :: proc(fi: ^Info, array_data: rawptr, count: int, elem_size: int, elem_id: typeid, verb: rune) { - io.write_byte(fi.writer, '[', &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) if count <= 0 { return @@ -1821,6 +1832,13 @@ handle_tag :: proc(data: rawptr, info: reflect.Type_Info_Struct, idx: int, verb: r, w := utf8.decode_rune_in_string(value) value = value[w:] if value == "" || value[0] == ',' { + if verb^ == 'w' { + // TODO(bill): is this a good idea overriding that field tags if 'w' is used? + switch r { + case 's': r = 'q' + case: r = 'w' + } + } verb^ = r if len(value) > 0 && value[0] == ',' { field_name := value[1:] @@ -1832,7 +1850,7 @@ handle_tag :: proc(data: rawptr, info: reflect.Type_Info_Struct, idx: int, verb: switch r { case 's', 'q': handle_optional_len(data, info, field_name, optional_len) - case 'v': + case 'v', 'w': #partial switch reflect.type_kind(info.types[idx].id) { case .String, .Multi_Pointer, .Array, .Slice, .Dynamic_Array: handle_optional_len(data, info, field_name, optional_len) @@ -1854,7 +1872,7 @@ handle_tag :: proc(data: rawptr, info: reflect.Type_Info_Struct, idx: int, verb: // - type_name: The name of the type being formatted // fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_Struct, type_name: string) { - if the_verb != 'v' { + if the_verb != 'v' && the_verb != 'w' { fmt_bad_verb(fi, the_verb) return } @@ -1871,7 +1889,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St is_soa := info.soa_kind != .None io.write_string(fi.writer, type_name, &fi.n) - io.write_byte(fi.writer, '[' if is_soa else '{', &fi.n) + io.write_byte(fi.writer, '[' if is_soa && the_verb == 'v' else '{', &fi.n) fi.record_level += 1 defer fi.record_level -= 1 @@ -1889,7 +1907,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St if hash { for _ in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) } } - io.write_byte(fi.writer, ']' if is_soa else '}', &fi.n) + io.write_byte(fi.writer, ']' if is_soa && the_verb == 'v' else '}', &fi.n) } if is_soa { @@ -1972,7 +1990,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St for name, i in info.names { optional_len: int = -1 use_nul_termination: bool = false - verb := 'v' + verb := the_verb if the_verb == 'w' else 'v' if handle_tag(v.data, info, i, &verb, &optional_len, &use_nul_termination) { continue } @@ -2051,7 +2069,7 @@ fmt_array_nul_terminated :: proc(fi: ^Info, data: rawptr, max_n: int, elem_size: // - n: The number of elements in the array. // - elem_size: The size of each element in the array. // - elem: Pointer to the type information of the array element. -// - verb: The formatting verb (e.g. 's','q','p'). +// - verb: The formatting verb (e.g. 's','q','p','w'). // fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflect.Type_Info, verb: rune) { if data == nil && n > 0 { @@ -2130,141 +2148,143 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named) } // Built-in Custom Formatters for core library types - switch a in v { - case runtime.Source_Code_Location: - io.write_string(fi.writer, a.file_path, &fi.n) - - when ODIN_ERROR_POS_STYLE == .Default { - io.write_byte(fi.writer, '(', &fi.n) - io.write_int(fi.writer, int(a.line), 10, &fi.n) - io.write_byte(fi.writer, ':', &fi.n) - io.write_int(fi.writer, int(a.column), 10, &fi.n) - io.write_byte(fi.writer, ')', &fi.n) - } else when ODIN_ERROR_POS_STYLE == .Unix { - io.write_byte(fi.writer, ':', &fi.n) - io.write_int(fi.writer, int(a.line), 10, &fi.n) - io.write_byte(fi.writer, ':', &fi.n) - io.write_int(fi.writer, int(a.column), 10, &fi.n) - io.write_byte(fi.writer, ':', &fi.n) - } else { - #panic("Unhandled ODIN_ERROR_POS_STYLE") - } - return + if verb != 'w' { + switch a in v { + case runtime.Source_Code_Location: + io.write_string(fi.writer, a.file_path, &fi.n) + + when ODIN_ERROR_POS_STYLE == .Default { + io.write_byte(fi.writer, '(', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + io.write_byte(fi.writer, ')', &fi.n) + } else when ODIN_ERROR_POS_STYLE == .Unix { + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.line), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + io.write_int(fi.writer, int(a.column), 10, &fi.n) + io.write_byte(fi.writer, ':', &fi.n) + } else { + #panic("Unhandled ODIN_ERROR_POS_STYLE") + } + return - case time.Duration: - ffrac :: proc(buf: []byte, v: u64, prec: int) -> (nw: int, nv: u64) { - v := v - w := len(buf) - print := false - for _ in 0..<prec { - digit := v % 10 - print = print || digit != 0 + case time.Duration: + ffrac :: proc(buf: []byte, v: u64, prec: int) -> (nw: int, nv: u64) { + v := v + w := len(buf) + print := false + for _ in 0..<prec { + digit := v % 10 + print = print || digit != 0 + if print { + w -= 1 + buf[w] = byte(digit) + '0' + } + v /= 10 + } if print { w -= 1 - buf[w] = byte(digit) + '0' + buf[w] = '.' } - v /= 10 - } - if print { - w -= 1 - buf[w] = '.' + return w, v } - return w, v - } - fint :: proc(buf: []byte, v: u64) -> int { - v := v - w := len(buf) - if v == 0 { - w -= 1 - buf[w] = '0' - } else { - for v > 0 { + fint :: proc(buf: []byte, v: u64) -> int { + v := v + w := len(buf) + if v == 0 { w -= 1 - buf[w] = byte(v%10) + '0' - v /= 10 + buf[w] = '0' + } else { + for v > 0 { + w -= 1 + buf[w] = byte(v%10) + '0' + v /= 10 + } } + return w } - return w - } - - buf: [32]byte - w := len(buf) - u := u64(a) - neg := a < 0 - if neg { - u = -u - } - if u < u64(time.Second) { - prec: int - w -= 1 - buf[w] = 's' - w -= 1 - switch { - case u == 0: - io.write_string(fi.writer, "0s", &fi.n) - return - case u < u64(time.Microsecond): - prec = 0 - buf[w] = 'n' - case u < u64(time.Millisecond): - prec = 3 - // U+00B5 'µ' micro sign == 0xC2 0xB5 - w -= 1 // Need room for two bytes - copy(buf[w:], "µ") - case: - prec = 6 - buf[w] = 'm' + buf: [32]byte + w := len(buf) + u := u64(a) + neg := a < 0 + if neg { + u = -u } - w, u = ffrac(buf[:w], u, prec) - w = fint(buf[:w], u) - } else { - w -= 1 - buf[w] = 's' - w, u = ffrac(buf[:w], u, 9) - w = fint(buf[:w], u%60) - u /= 60 - if u > 0 { + + if u < u64(time.Second) { + prec: int + w -= 1 + buf[w] = 's' + w -= 1 + switch { + case u == 0: + io.write_string(fi.writer, "0s", &fi.n) + return + case u < u64(time.Microsecond): + prec = 0 + buf[w] = 'n' + case u < u64(time.Millisecond): + prec = 3 + // U+00B5 'µ' micro sign == 0xC2 0xB5 + w -= 1 // Need room for two bytes + copy(buf[w:], "µ") + case: + prec = 6 + buf[w] = 'm' + } + w, u = ffrac(buf[:w], u, prec) + w = fint(buf[:w], u) + } else { w -= 1 - buf[w] = 'm' + buf[w] = 's' + w, u = ffrac(buf[:w], u, 9) w = fint(buf[:w], u%60) u /= 60 if u > 0 { w -= 1 - buf[w] = 'h' - w = fint(buf[:w], u) + buf[w] = 'm' + w = fint(buf[:w], u%60) + u /= 60 + if u > 0 { + w -= 1 + buf[w] = 'h' + w = fint(buf[:w], u) + } } } - } - if neg { - w -= 1 - buf[w] = '-' - } - io.write_string(fi.writer, string(buf[w:]), &fi.n) - return + if neg { + w -= 1 + buf[w] = '-' + } + io.write_string(fi.writer, string(buf[w:]), &fi.n) + return - case time.Time: - t := a - y, mon, d := time.date(t) - h, min, s := time.clock(t) - ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 - write_padded_number(fi, i64(y), 4) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(mon), 2) - io.write_byte(fi.writer, '-', &fi.n) - write_padded_number(fi, i64(d), 2) - io.write_byte(fi.writer, ' ', &fi.n) - - write_padded_number(fi, i64(h), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(min), 2) - io.write_byte(fi.writer, ':', &fi.n) - write_padded_number(fi, i64(s), 2) - io.write_byte(fi.writer, '.', &fi.n) - write_padded_number(fi, (ns), 9) - io.write_string(fi.writer, " +0000 UTC", &fi.n) - return + case time.Time: + t := a + y, mon, d := time.date(t) + h, min, s := time.clock(t) + ns := (t._nsec - (t._nsec/1e9 + time.UNIX_TO_ABSOLUTE)*1e9) % 1e9 + write_padded_number(fi, i64(y), 4) + io.write_byte(fi.writer, '-', &fi.n) + write_padded_number(fi, i64(mon), 2) + io.write_byte(fi.writer, '-', &fi.n) + write_padded_number(fi, i64(d), 2) + io.write_byte(fi.writer, ' ', &fi.n) + + write_padded_number(fi, i64(h), 2) + io.write_byte(fi.writer, ':', &fi.n) + write_padded_number(fi, i64(min), 2) + io.write_byte(fi.writer, ':', &fi.n) + write_padded_number(fi, i64(s), 2) + io.write_byte(fi.writer, '.', &fi.n) + write_padded_number(fi, (ns), 9) + io.write_string(fi.writer, " +0000 UTC", &fi.n) + return + } } #partial switch b in info.base.variant { @@ -2275,6 +2295,23 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named) case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v, verb = verb) case: + if verb == 'w' { + #partial switch b in info.base.variant { + case runtime.Type_Info_Array, + runtime.Type_Info_Enumerated_Array, + 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, + runtime.Type_Info_Simd_Vector, + runtime.Type_Info_Matrix, + runtime.Type_Info_Bit_Field: + io.write_string(fi.writer, info.name, &fi.n) + } + } fmt_value(fi, any{v.data, info.base.id}, verb) } } @@ -2341,8 +2378,13 @@ fmt_union :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Union, // - info: A runtime.Type_Info_Matrix struct containing matrix type information. // fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix) { - io.write_string(fi.writer, "matrix[", &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) + if verb == 'w' { + io.write_byte(fi.writer, '{', &fi.n) + } else { + io.write_string(fi.writer, "matrix", &fi.n) + io.write_byte(fi.writer, '[', &fi.n) + } + defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) fi.indent += 1 @@ -2413,8 +2455,8 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit return false } - io.write_string(fi.writer, type_name if len(type_name) != 0 else "bit_field", &fi.n) - io.write_string(fi.writer, "{", &fi.n) + io.write_string(fi.writer, type_name if len(type_name) != 0 || verb == 'w' else "bit_field", &fi.n) + io.write_byte(fi.writer, '{', &fi.n) hash := fi.hash; defer fi.hash = hash indent := fi.indent; defer fi.indent -= 1 @@ -2631,11 +2673,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { defer fi.record_level -= 1 if fi.hash { - io.write_string(fi.writer, "[\n", &fi.n) + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + io.write_byte(fi.writer, '\n', &fi.n) defer { io.write_byte(fi.writer, '\n', &fi.n) fmt_write_indent(fi) - io.write_byte(fi.writer, ']', &fi.n) + io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) } indent := fi.indent fi.indent += 1 @@ -2659,8 +2702,8 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { io.write_string(fi.writer, ",\n", &fi.n) } } else { - io.write_byte(fi.writer, '[', &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) for i in 0..<info.count { if i > 0 { io.write_string(fi.writer, ", ", &fi.n) } @@ -2725,38 +2768,42 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Map: - if verb != 'v' { + switch verb { + case: fmt_bad_verb(fi, verb) - return - } - - io.write_string(fi.writer, "map[", &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) - fi.record_level += 1 - defer fi.record_level -= 1 - - m := (^mem.Raw_Map)(v.data) - if m != nil { - if info.map_info == nil { - return + case 'v', 'w': + if verb == 'v' { + io.write_string(fi.writer, "map", &fi.n) } - map_cap := uintptr(runtime.map_cap(m^)) - ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info) - j := 0 - for bucket_index in 0..<map_cap { - runtime.map_hash_is_valid(hs[bucket_index]) or_continue + io.write_byte(fi.writer, '[' if verb != 'w' else '{', &fi.n) + defer io.write_byte(fi.writer, ']' if verb != 'w' else '}', &fi.n) + + fi.record_level += 1 + defer fi.record_level -= 1 - if j > 0 { - io.write_string(fi.writer, ", ", &fi.n) + m := (^mem.Raw_Map)(v.data) + if m != nil { + if info.map_info == nil { + return } - j += 1 + map_cap := uintptr(runtime.map_cap(m^)) + ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info) + j := 0 + for bucket_index in 0..<map_cap { + runtime.map_hash_is_valid(hs[bucket_index]) or_continue + + if j > 0 { + io.write_string(fi.writer, ", ", &fi.n) + } + j += 1 - key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) - value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) + key := runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index) + value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) - fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v') - io.write_string(fi.writer, "=", &fi.n) - fmt_arg(fi, any{rawptr(value), info.value.id}, 'v') + fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) + io.write_string(fi.writer, "=", &fi.n) + fmt_arg(fi, any{rawptr(value), info.value.id}, verb) + } } } @@ -2811,11 +2858,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { // - fi: A pointer to an Info struct containing formatting information. // - c: The complex128 value to be formatted. // - bits: The number of bits in the complex number (32 or 64). -// - verb: The formatting verb rune ('f', 'F', 'v', 'h', 'H'). +// - verb: The formatting verb rune ('f', 'F', 'v', 'h', 'H', 'w'). // fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { switch verb { - case 'f', 'F', 'v', 'h', 'H': + case 'f', 'F', 'v', 'h', 'H', 'w': r, i := real(c), imag(c) fmt_float(fi, r, bits/2, verb) if !fi.plus && i >= 0 { @@ -2835,11 +2882,11 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { // - fi: A pointer to an Info struct containing formatting information. // - q: The quaternion256 value to be formatted. // - bits: The number of bits in the quaternion number (64, 128, or 256). -// - verb: The formatting verb rune ('f', 'F', 'v', 'h', 'H'). +// - verb: The formatting verb rune ('f', 'F', 'v', 'h', 'H', 'w'). // fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) { switch verb { - case 'f', 'F', 'v', 'h', 'H': + case 'f', 'F', 'v', 'h', 'H', 'w': r, i, j, k := real(q), imag(q), jmag(q), kmag(q) fmt_float(fi, r, bits/4, verb) |