Browse Source

Add new stuff to package reflect; fix -vet for odin_parser

gingerBill 6 years ago
parent
commit
a58c29582e
2 changed files with 98 additions and 201 deletions
  1. 1 1
      core/odin/parser/parser.odin
  2. 97 200
      core/reflect/reflect.odin

+ 1 - 1
core/odin/parser/parser.odin

@@ -1741,7 +1741,7 @@ string_to_calling_convention :: proc(s: string) -> ast.Proc_Calling_Convention {
 
 parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
 	for p.curr_tok.kind == token.Hash {
-		tok := expect_token(p, token.Hash);
+		_ = expect_token(p, token.Hash);
 		ident := expect_token(p, token.Ident);
 
 		switch ident.text {

+ 97 - 200
core/reflect/reflect.odin

@@ -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;
+}