Created
May 5, 2020 09:27
-
-
Save JoshuaManton/c5f9fb87047cbcdda8f0cf6e1c47eed7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import "core:fmt" | |
import "core:mem" | |
import "core:reflect" | |
import "core:strings" | |
import rt "core:runtime" | |
pretty_print :: proc(thing: any) { | |
sb: strings.Builder; | |
defer strings.destroy_builder(&sb); | |
print_value(&sb, thing.data, type_info_of(thing.id), 0); | |
println(strings.to_string(sb)); | |
print_value :: proc(sb: ^strings.Builder, data: rawptr, ti: ^rt.Type_Info, indent_level: int) { | |
do_indent :: proc(sb: ^strings.Builder, indent_level: int) { | |
for i in 0..<indent_level do sbprint(sb, " "); | |
} | |
indent_level := indent_level; | |
switch kind in ti.variant { | |
case rt.Type_Info_Named: print_value(sb, data, kind.base, indent_level); | |
case rt.Type_Info_Integer: { | |
if kind.signed { | |
switch kind.endianness { | |
case .Little: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^i8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^i16le)data)^); | |
case 4: fmt.sbprint(sb, (cast(^i32le)data)^); | |
case 8: fmt.sbprint(sb, (cast(^i64le)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case .Big: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^i8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^i16be)data)^); | |
case 4: fmt.sbprint(sb, (cast(^i32be)data)^); | |
case 8: fmt.sbprint(sb, (cast(^i64be)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case .Platform: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^i8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^i16)data)^); | |
case 4: fmt.sbprint(sb, (cast(^i32)data)^); | |
case 8: fmt.sbprint(sb, (cast(^i64)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case: panic(tprint(kind.endianness)); | |
} | |
} | |
else { | |
switch kind.endianness { | |
case .Little: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^u8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^u16le)data)^); | |
case 4: fmt.sbprint(sb, (cast(^u32le)data)^); | |
case 8: fmt.sbprint(sb, (cast(^u64le)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case .Big: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^u8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^u16be)data)^); | |
case 4: fmt.sbprint(sb, (cast(^u32be)data)^); | |
case 8: fmt.sbprint(sb, (cast(^u64be)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case .Platform: { | |
switch ti.size { | |
case 1: fmt.sbprint(sb, (cast(^u8 )data)^); | |
case 2: fmt.sbprint(sb, (cast(^u16)data)^); | |
case 4: fmt.sbprint(sb, (cast(^u32)data)^); | |
case 8: fmt.sbprint(sb, (cast(^u64)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case: panic(tprint(kind.endianness)); | |
} | |
} | |
} | |
case rt.Type_Info_Rune: fmt.sbprint(sb, (cast(^rune)data)^); | |
case rt.Type_Info_Float: { | |
switch ti.size { | |
case 4: sbprint(sb, (cast(^f32)data)^); | |
case 8: sbprint(sb, (cast(^f64)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case rt.Type_Info_Struct: { | |
sbprint(sb, "{\n"); | |
indent_level += 1; | |
for name, idx in kind.names { | |
type := kind.types[idx]; | |
offset := kind.offsets[idx]; | |
do_indent(sb, indent_level); | |
sbprint(sb, name, ": ", type, " = "); | |
print_value(sb, mem.ptr_offset(cast(^byte)data, cast(int)offset), type, indent_level); | |
sbprint(sb, ",\n"); | |
} | |
indent_level -= 1; | |
do_indent(sb, indent_level); | |
sbprint(sb, "}"); | |
} | |
case rt.Type_Info_Boolean: { | |
switch ti.size { | |
case 1: sbprint(sb, (cast(^b8 )data)^); | |
case 2: sbprint(sb, (cast(^b16)data)^); | |
case 4: sbprint(sb, (cast(^b32)data)^); | |
case 8: sbprint(sb, (cast(^b64)data)^); | |
case: panic(tprint(ti.size)); | |
} | |
} | |
case rt.Type_Info_String: { | |
if kind.is_cstring do sbprint(sb, '"', (cast(^cstring)data)^, '"'); | |
else do sbprint(sb, '"', (cast(^string )data)^, '"'); | |
} | |
case rt.Type_Info_Pointer: { | |
// todo(josh): do we want to recurse maybe just once? | |
sbprint(sb, (cast(^rawptr)data)^); | |
} | |
case rt.Type_Info_Procedure: sbprint(sb, (cast(^rawptr)data)^); | |
case rt.Type_Info_Type_Id: sbprint(sb, (cast(^typeid)data)^); | |
case rt.Type_Info_Array: { | |
sbprint(sb, "[\n"); | |
indent_level += 1; | |
for idx in 0..<kind.count { | |
offset := idx * kind.elem.size; | |
do_indent(sb, indent_level); | |
sbprint(sb, "[", idx, "]", " = "); | |
print_value(sb, mem.ptr_offset(cast(^byte)data, offset), kind.elem, indent_level); | |
sbprint(sb, ",\n"); | |
} | |
indent_level -= 1; | |
do_indent(sb, indent_level); | |
sbprint(sb, "]"); | |
} | |
case rt.Type_Info_Slice: { | |
sbprint(sb, "[\n"); | |
indent_level += 1; | |
raw_slice := cast(^mem.Raw_Slice)data; | |
for idx in 0..<raw_slice.len { | |
offset := idx * kind.elem.size; | |
do_indent(sb, indent_level); | |
sbprint(sb, "[", idx, "]", " = "); | |
print_value(sb, mem.ptr_offset(cast(^byte)raw_slice.data, offset), kind.elem, indent_level); | |
sbprint(sb, ",\n"); | |
} | |
indent_level -= 1; | |
do_indent(sb, indent_level); | |
sbprint(sb, "]"); | |
} | |
case rt.Type_Info_Enumerated_Array: { | |
sbprint(sb, "[\n"); | |
indent_level += 1; | |
for idx in 0..<kind.count { | |
offset := idx * kind.elem.size; | |
do_indent(sb, indent_level); | |
// todo(josh): the enum string thing doesn't work | |
sbprint(sb, "[", reflect.enum_string(any{data, kind.index.id}), "]", " = "); | |
print_value(sb, mem.ptr_offset(cast(^byte)data, offset), kind.elem, indent_level); | |
sbprint(sb, ",\n"); | |
} | |
indent_level -= 1; | |
do_indent(sb, indent_level); | |
sbprint(sb, "]"); | |
} | |
case rt.Type_Info_Dynamic_Array: { | |
sbprint(sb, "[\n"); | |
indent_level += 1; | |
raw_dyn := cast(^mem.Raw_Dynamic_Array)data; | |
for idx in 0..<raw_dyn.len { | |
offset := idx * kind.elem.size; | |
do_indent(sb, indent_level); | |
sbprint(sb, "[", idx, "]", " = "); | |
print_value(sb, mem.ptr_offset(cast(^byte)raw_dyn.data, offset), kind.elem, indent_level); | |
sbprint(sb, ",\n"); | |
} | |
indent_level -= 1; | |
do_indent(sb, indent_level); | |
sbprint(sb, "]"); | |
} | |
case rt.Type_Info_Union: { | |
// todo(josh): union types get printed wrong | |
tag_ti := get_union_type_info(any{data, ti.id}); | |
print_value(sb, data, tag_ti, indent_level); | |
} | |
case rt.Type_Info_Enum: sbprint(sb, reflect.enum_string(any{data, ti.id})); | |
case rt.Type_Info_Any: sbprint(sb, "(", (cast(^any)data)^.id, ") ", (cast(^any)data)^); | |
case rt.Type_Info_Map: panic("Type_Info_Map"); | |
case rt.Type_Info_Bit_Field: panic("Type_Info_Bit_Field"); | |
case rt.Type_Info_Bit_Set: panic("Type_Info_Bit_Set"); | |
case rt.Type_Info_Complex: panic("Type_Info_Complex"); | |
case rt.Type_Info_Quaternion: panic("Type_Info_Quaternion"); | |
case rt.Type_Info_Opaque: panic("Type_Info_Opaque"); | |
case rt.Type_Info_Simd_Vector: panic("Type_Info_Simd_Vector"); | |
case rt.Type_Info_Tuple: panic("Type_Info_Tuple"); | |
} | |
get_union_type_info :: proc(v : any) -> ^rt.Type_Info { | |
if tag := get_union_tag(v); tag > 0 { | |
info := rt.type_info_base(type_info_of(v.id)).variant.(rt.Type_Info_Union); | |
return info.variants[tag - 1]; | |
} | |
return nil; | |
} | |
get_union_tag :: proc(v : any) -> i64 { | |
info, ok := rt.type_info_base(type_info_of(v.id)).variant.(rt.Type_Info_Union); | |
assert(ok, tprint(v)); | |
tag_ptr := uintptr(v.data) + info.tag_offset; | |
tag_any := any{rawptr(tag_ptr), info.tag_type.id}; | |
tag: i64 = -1; | |
switch i in tag_any { | |
case u8: tag = i64(i); | |
case u16: tag = i64(i); | |
case u32: tag = i64(i); | |
case u64: tag = i64(i); | |
case i8: tag = i64(i); | |
case i16: tag = i64(i); | |
case i32: tag = i64(i); | |
case i64: tag = i64(i); | |
case: panic(fmt.tprint("Invalid union tag type: ", i)); | |
} | |
assert(tag >= 0); | |
return tag; | |
} | |
} | |
} | |
Foo :: struct { | |
i: int, | |
str: string, | |
tagged_union: union { | |
string, | |
int, | |
Foo_Enum, | |
}, | |
nested: Nested, | |
ptr: ^int, | |
procedure: proc(int) -> f32, | |
empty: Empty, | |
}; | |
Nested :: struct { | |
aaa: any, | |
things: [3]string, | |
blahblah: []int, | |
dyn_blah: [dynamic]f32, | |
foo: Foo_Enum, | |
enumerated: [Foo_Enum]bool, | |
wow_so_nested: string, | |
booooooool: bool, | |
}; | |
Empty :: struct { | |
}; | |
Foo_Enum :: enum { | |
Bar, Baz, Qux, | |
}; | |
the_procedure :: proc(x: int) -> f32 { return 1337; } | |
foozle: int = 4289; | |
afoozle : any = foozle; | |
pretty_print(Foo{149, "Henlo", .Qux, Nested{afoozle, {"oh", "my", "wowzers"}, {1, 4, 9}, {9, 3, 2, 4}, .Baz, {.Bar = true, .Baz = false, .Qux = true}, "pachooooo", true}, &foozle, the_procedure, {}}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment