Created
May 7, 2020 22:30
-
-
Save JoshuaManton/10a3977ad4af73ee31eb66dafd1fcdeb 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
Foozle :: 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; } | |
tester: int = 4289; | |
tester_any : any = tester; | |
foozler := Foozle{149, "Henlo", .Qux, Nested{tester_any, {"oh", "my", "wowzers"}, {1, 4, 9}, {9, 3, 2, 4}, .Baz, {.Bar = true, .Baz = false, .Qux = true}, "pachooooo", true}, &tester, the_procedure, {}}; | |
logging.pretty_print(foozler); | |
// prints | |
{ | |
i: int = 149, | |
str: string = "Henlo", | |
tagged_union: union {string, int, Foo_Enum} = (Foo_Enum) Qux, | |
nested: Nested = { | |
aaa: any = (int) 4289, | |
things: [3]string = [ | |
[0] = "oh", | |
[1] = "my", | |
[2] = "wowzers", | |
], | |
blahblah: []int = [ | |
[0] = 1, | |
[1] = 4, | |
[2] = 9, | |
], | |
dyn_blah: [dynamic]f32 = [ | |
[0] = 9.000, | |
[1] = 3.000, | |
[2] = 2.000, | |
[3] = 4.000, | |
], | |
foo: Foo_Enum = Baz, | |
enumerated: [Foo_Enum]bool = [ | |
[] = true, | |
[] = false, | |
[] = true, | |
], | |
wow_so_nested: string = "pachooooo", | |
booooooool: bool = true, | |
}, | |
ptr: ^int = 0xAB1ADAF630, | |
procedure: proc(int) -> f32 = 0x7FF6E7B41AB0, | |
empty: Empty = { | |
}, | |
} | |
// source | |
pretty_print :: proc(thing: any) { | |
sb: strings.Builder; | |
defer strings.destroy_builder(&sb); | |
pretty_sbprint(&sb, thing); | |
println(strings.to_string(sb)); | |
} | |
pretty_sbprint :: proc(sb: ^strings.Builder, thing: any) { | |
print_value(sb, thing.data, type_info_of(thing.id), 0); | |
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]; | |
// print name | |
do_indent(sb, indent_level); | |
sbprint(sb, name, ": "); | |
// print type | |
sbprint(sb, type); | |
// print value | |
sbprint(sb, " = "); | |
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: { | |
tag_ti := get_union_type_info(any{data, ti.id}); | |
sbprint(sb, "(", tag_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: sbprint(sb, "{{Type_Info_Map not supported}}"); | |
case rt.Type_Info_Bit_Field: sbprint(sb, "{{Type_Info_Bit_Field not supported}}"); | |
case rt.Type_Info_Bit_Set: sbprint(sb, "{{Type_Info_Bit_Set not supported}}"); | |
case rt.Type_Info_Complex: sbprint(sb, "{{Type_Info_Complex not supported}}"); | |
case rt.Type_Info_Quaternion: sbprint(sb, "{{Type_Info_Quaternion not supported}}"); | |
case rt.Type_Info_Opaque: sbprint(sb, "{{Type_Info_Opaque not supported}}"); | |
case rt.Type_Info_Simd_Vector: sbprint(sb, "{{Type_Info_Simd_Vector not supported}}"); | |
case rt.Type_Info_Tuple: sbprint(sb, "{{Type_Info_Tuple not supported}}"); | |
} | |
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); | |
if !ok do panic(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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment