|
@@ -2,7 +2,6 @@ package reflect
|
|
|
|
|
|
import "core:runtime"
|
|
|
import "core:mem"
|
|
|
-import "core:strings"
|
|
|
|
|
|
|
|
|
Type_Kind :: enum {
|
|
@@ -116,6 +115,31 @@ is_nil :: proc(v: any) -> bool {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+length :: proc(val: any) -> int {
|
|
|
+ if val == nil do return 0;
|
|
|
+
|
|
|
+ v := val;
|
|
|
+ v.id = runtime.typeid_base(v.id);
|
|
|
+ switch a in v {
|
|
|
+ case runtime.Type_Info_Array:
|
|
|
+ return a.count;
|
|
|
+
|
|
|
+ case runtime.Type_Info_Slice:
|
|
|
+ return (^mem.Raw_Slice)(v.data).len;
|
|
|
+
|
|
|
+ case runtime.Type_Info_Dynamic_Array:
|
|
|
+ return (^mem.Raw_Dynamic_Array)(v.data).len;
|
|
|
+
|
|
|
+ case runtime.Type_Info_String:
|
|
|
+ if a.is_cstring {
|
|
|
+ return len((^cstring)(v.data)^);
|
|
|
+ } else {
|
|
|
+ return (^mem.Raw_String)(v.data).len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
|
|
if val == nil do return nil;
|
|
@@ -196,6 +220,35 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+struct_field_value_by_name :: proc(a: any, field: string, recurse := false) -> any {
|
|
|
+ if a == nil do return nil;
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+
|
|
|
+ if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
|
|
+ for name, i in s.names {
|
|
|
+ if name == field {
|
|
|
+ return any{
|
|
|
+ rawptr(uintptr(a.data) + s.offsets[i]),
|
|
|
+ s.types[i].id,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ if recurse && s.usings[i] {
|
|
|
+ f := any{
|
|
|
+ rawptr(uintptr(a.data) + s.offsets[i]),
|
|
|
+ s.types[i].id,
|
|
|
+ };
|
|
|
+
|
|
|
+ if res := struct_field_value_by_name(f, field, recurse); res != nil {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
|
|
|
struct_field_names :: proc(T: typeid) -> []string {
|
|
@@ -286,212 +339,56 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: b
|
|
|
}
|
|
|
|
|
|
|
|
|
-write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
|
|
|
- write_type(buf, type_info_of(id));
|
|
|
-}
|
|
|
-
|
|
|
-write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
|
|
|
- using strings;
|
|
|
- if ti == nil {
|
|
|
- write_string(buf, "nil");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- switch info in ti.variant {
|
|
|
- case runtime.Type_Info_Named:
|
|
|
- write_string(buf, info.name);
|
|
|
- case runtime.Type_Info_Integer:
|
|
|
- switch ti.id {
|
|
|
- case int: write_string(buf, "int");
|
|
|
- case uint: write_string(buf, "uint");
|
|
|
- case uintptr: write_string(buf, "uintptr");
|
|
|
- case:
|
|
|
- write_byte(buf, info.signed ? 'i' : 'u');
|
|
|
- write_i64(buf, i64(8*ti.size), 10);
|
|
|
- switch info.endianness {
|
|
|
- case runtime.Type_Info_Endianness.Little:
|
|
|
- write_string(buf, "le");
|
|
|
- case runtime.Type_Info_Endianness.Big:
|
|
|
- write_string(buf, "be");
|
|
|
- }
|
|
|
- }
|
|
|
- case runtime.Type_Info_Rune:
|
|
|
- write_string(buf, "rune");
|
|
|
- case runtime.Type_Info_Float:
|
|
|
- write_byte(buf, 'f');
|
|
|
- write_i64(buf, i64(8*ti.size), 10);
|
|
|
- case runtime.Type_Info_Complex:
|
|
|
- write_string(buf, "complex");
|
|
|
- write_i64(buf, i64(8*ti.size), 10);
|
|
|
- case runtime.Type_Info_String:
|
|
|
- if info.is_cstring {
|
|
|
- write_string(buf, "cstring");
|
|
|
- } else {
|
|
|
- write_string(buf, "string");
|
|
|
- }
|
|
|
- case runtime.Type_Info_Boolean:
|
|
|
- switch ti.id {
|
|
|
- case bool: write_string(buf, "bool");
|
|
|
- case:
|
|
|
- write_byte(buf, 'b');
|
|
|
- write_i64(buf, i64(8*ti.size), 10);
|
|
|
- }
|
|
|
- case runtime.Type_Info_Any:
|
|
|
- write_string(buf, "any");
|
|
|
-
|
|
|
- case runtime.Type_Info_Type_Id:
|
|
|
- write_string(buf, "typeid");
|
|
|
-
|
|
|
- case runtime.Type_Info_Pointer:
|
|
|
- if info.elem == nil {
|
|
|
- write_string(buf, "rawptr");
|
|
|
- } else {
|
|
|
- write_string(buf, "^");
|
|
|
- write_type(buf, info.elem);
|
|
|
- }
|
|
|
- case runtime.Type_Info_Procedure:
|
|
|
- write_string(buf, "proc");
|
|
|
- if info.params == nil {
|
|
|
- write_string(buf, "()");
|
|
|
- } else {
|
|
|
- t := info.params.variant.(runtime.Type_Info_Tuple);
|
|
|
- write_string(buf, "(");
|
|
|
- for t, i in t.types {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
- write_type(buf, t);
|
|
|
+enum_string :: proc(a: any) -> string {
|
|
|
+ if a == nil do return "";
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if e, ok := ti.variant.(runtime.Type_Info_Enum); ok {
|
|
|
+ for _, i in e.values {
|
|
|
+ value := &e.values[i];
|
|
|
+ n := mem.compare_byte_ptrs((^byte)(a.data), (^byte)(value), ti.size);
|
|
|
+ if n == 0 {
|
|
|
+ return e.names[i];
|
|
|
}
|
|
|
- write_string(buf, ")");
|
|
|
}
|
|
|
- if info.results != nil {
|
|
|
- write_string(buf, " -> ");
|
|
|
- write_type(buf, info.results);
|
|
|
- }
|
|
|
- case runtime.Type_Info_Tuple:
|
|
|
- count := len(info.names);
|
|
|
- if count != 1 do write_string(buf, "(");
|
|
|
- for name, i in info.names {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
+ } else {
|
|
|
+ panic("expected an enum to reflect.enum_string");
|
|
|
+ }
|
|
|
|
|
|
- t := info.types[i];
|
|
|
+ return "";
|
|
|
+}
|
|
|
|
|
|
- if len(name) > 0 {
|
|
|
- write_string(buf, name);
|
|
|
- write_string(buf, ": ");
|
|
|
- }
|
|
|
- write_type(buf, t);
|
|
|
- }
|
|
|
- if count != 1 do write_string(buf, ")");
|
|
|
+union_variant_type_info :: proc(a: any) -> ^runtime.Type_Info {
|
|
|
+ id := union_variant_typeid(a);
|
|
|
+ return type_info_of(id);
|
|
|
+}
|
|
|
|
|
|
- case runtime.Type_Info_Array:
|
|
|
- write_string(buf, "[");
|
|
|
- write_i64(buf, i64(info.count), 10);
|
|
|
- write_string(buf, "]");
|
|
|
- write_type(buf, info.elem);
|
|
|
- case runtime.Type_Info_Dynamic_Array:
|
|
|
- write_string(buf, "[dynamic]");
|
|
|
- write_type(buf, info.elem);
|
|
|
- case runtime.Type_Info_Slice:
|
|
|
- write_string(buf, "[]");
|
|
|
- write_type(buf, info.elem);
|
|
|
-
|
|
|
- case runtime.Type_Info_Map:
|
|
|
- write_string(buf, "map[");
|
|
|
- write_type(buf, info.key);
|
|
|
- write_byte(buf, ']');
|
|
|
- write_type(buf, info.value);
|
|
|
-
|
|
|
- case runtime.Type_Info_Struct:
|
|
|
- write_string(buf, "struct ");
|
|
|
- if info.is_packed do write_string(buf, "#packed ");
|
|
|
- if info.is_raw_union do write_string(buf, "#raw_union ");
|
|
|
- if info.custom_align {
|
|
|
- write_string(buf, "#align ");
|
|
|
- write_i64(buf, i64(ti.align), 10);
|
|
|
- write_byte(buf, ' ');
|
|
|
- }
|
|
|
- write_byte(buf, '{');
|
|
|
- for name, i in info.names {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
- write_string(buf, name);
|
|
|
- write_string(buf, ": ");
|
|
|
- write_type(buf, info.types[i]);
|
|
|
- }
|
|
|
- write_byte(buf, '}');
|
|
|
-
|
|
|
- case runtime.Type_Info_Union:
|
|
|
- write_string(buf, "union ");
|
|
|
- if info.custom_align {
|
|
|
- write_string(buf, "#align ");
|
|
|
- write_i64(buf, i64(ti.align), 10);
|
|
|
- write_byte(buf, ' ');
|
|
|
- }
|
|
|
- write_byte(buf, '{');
|
|
|
- for variant, i in info.variants {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
- write_type(buf, variant);
|
|
|
- }
|
|
|
- write_byte(buf, '}');
|
|
|
-
|
|
|
- case runtime.Type_Info_Enum:
|
|
|
- write_string(buf, "enum ");
|
|
|
- write_type(buf, info.base);
|
|
|
- write_string(buf, " {");
|
|
|
- for name, i in info.names {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
- write_string(buf, name);
|
|
|
- }
|
|
|
- write_byte(buf, '}');
|
|
|
-
|
|
|
- case runtime.Type_Info_Bit_Field:
|
|
|
- write_string(buf, "bit_field ");
|
|
|
- if ti.align != 1 {
|
|
|
- write_string(buf, "#align ");
|
|
|
- write_i64(buf, i64(ti.align), 10);
|
|
|
- write_byte(buf, ' ');
|
|
|
+union_variant_typeid :: proc(a: any) -> typeid {
|
|
|
+ if a == nil do return nil;
|
|
|
+
|
|
|
+ ti := runtime.type_info_base(type_info_of(a.id));
|
|
|
+ if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
|
|
|
+ tag_ptr := uintptr(a.data) + info.tag_offset;
|
|
|
+ tag_any := any{rawptr(tag_ptr), info.tag_type.id};
|
|
|
+
|
|
|
+ tag: i64 = ---;
|
|
|
+ switch i in tag_any {
|
|
|
+ case u8: tag = i64(i);
|
|
|
+ case i8: tag = i64(i);
|
|
|
+ case u16: tag = i64(i);
|
|
|
+ case i16: tag = i64(i);
|
|
|
+ case u32: tag = i64(i);
|
|
|
+ case i32: tag = i64(i);
|
|
|
+ case u64: tag = i64(i);
|
|
|
+ case i64: tag = i64(i);
|
|
|
+ case: unimplemented();
|
|
|
}
|
|
|
- write_string(buf, " {");
|
|
|
- for name, i in info.names {
|
|
|
- if i > 0 do write_string(buf, ", ");
|
|
|
- write_string(buf, name);
|
|
|
- write_string(buf, ": ");
|
|
|
- write_i64(buf, i64(info.bits[i]), 10);
|
|
|
- }
|
|
|
- write_byte(buf, '}');
|
|
|
-
|
|
|
- case runtime.Type_Info_Bit_Set:
|
|
|
- write_string(buf, "bit_set[");
|
|
|
- switch {
|
|
|
- case is_enum(info.elem):
|
|
|
- write_type(buf, info.elem);
|
|
|
- case is_rune(info.elem):
|
|
|
- write_encoded_rune(buf, rune(info.lower));
|
|
|
- write_string(buf, "..");
|
|
|
- write_encoded_rune(buf, rune(info.upper));
|
|
|
- case:
|
|
|
- write_i64(buf, info.lower, 10);
|
|
|
- write_string(buf, "..");
|
|
|
- write_i64(buf, info.upper, 10);
|
|
|
- }
|
|
|
- if info.underlying != nil {
|
|
|
- write_string(buf, "; ");
|
|
|
- write_type(buf, info.underlying);
|
|
|
- }
|
|
|
- write_byte(buf, ']');
|
|
|
-
|
|
|
- case runtime.Type_Info_Opaque:
|
|
|
- write_string(buf, "opaque ");
|
|
|
- write_type(buf, info.elem);
|
|
|
|
|
|
- case runtime.Type_Info_Simd_Vector:
|
|
|
- if info.is_x86_mmx {
|
|
|
- write_string(buf, "intrinsics.x86_mmx");
|
|
|
- } else {
|
|
|
- write_string(buf, "intrinsics.vector(");
|
|
|
- write_i64(buf, i64(info.count));
|
|
|
- write_string(buf, ", ");
|
|
|
- write_type(buf, info.elem);
|
|
|
- write_byte(buf, ')');
|
|
|
+ if a.data != nil && tag != 0 {
|
|
|
+ return info.variants[tag-1].id;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ panic("expected a union to reflect.union_variant_typeid");
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
+ return nil;
|
|
|
+}
|