|> iter.map((x) => string.from_cstr(*x));
defer arg_iter.close(arg_iter.data);
- use type_info;
+ use package runtime.info;
ptr_type := cast(^Type_Info_Pointer) get_type_info(output.type);
if ptr_type.kind != .Pointer do return false;
(T: type_expr, allocator := context.allocator) -> rawptr {
memory :: package core.memory
+ type_info :: package runtime.info
info := type_info.get_type_info(T);
size := type_info.size_of(T);
--- /dev/null
+package core.avl_tree
+
+AVL_Tree :: struct (T: type_expr) {
+ data: T;
+ left, right: ^AVL_Tree(T);
+
+ insert :: (tree: ^AVL_Tree, data: tree.T) {
+ node := new(typeof *tree);
+ node.data = data;
+ node.left = null;
+ node.right = null;
+ }
+}
+
map.init(^custom_parsers, default=null_proc);
#if Enable_Custom_Formatters {
- use type_info;
+ use package runtime.info;
for type_idx: type_table.count {
type := type_table[type_idx];
}
format_any :: (output: ^Format_Output, formatting: ^Format, v: any) {
- use package builtin.type_info
+ use package runtime.info
array :: package core.array;
if formatting.dereference {
// 256 bytes is enough for the name of a type but I'm not entirely sure...
stream := io.string_stream_make(~~buf);
writer := io.writer_make(^stream);
- type_info.write_type_name(^writer, value);
+ write_type_name(^writer, value);
output->write(io.string_stream_to_str(^stream));
}
// parse_any(^x, "12.34");
parse_any :: #match {}
#match parse_any (v: any, to_parse: str, string_allocator := context.allocator) -> bool {
- use type_info;
+ use package runtime.info;
info := get_type_info(v.type);
if info.kind != .Pointer do return false;
return custom_parsers[data_type](target, to_parse, string_allocator);
}
- use type_info;
+ use package runtime.info;
info := get_type_info(data_type);
switch data_type {
--- /dev/null
+
+package runtime.info
+
+//
+// Foreign Blocks
+// Because foreign blocks can generate a lot of data, and their data is only
+// really helpful in a handful of cases, you need to pass "--generate-foreign-bindings"
+// to have these arrays filled out.
+//
+
+foreign_block :: #distinct u32
+
+foreign_blocks: [] ^Foreign_Block;
+
+Foreign_Block :: struct {
+ module_name: str;
+ funcs: [] Foreign_Function;
+
+ Foreign_Function :: struct {
+ name: str;
+ type: type_expr;
+ }
+}
+
+get_foreign_block :: (f: foreign_block) -> ^Foreign_Block {
+ if ~~f < cast(i32) 0 || ~~f >= cast(i32) foreign_blocks.count do return null;
+
+ return foreign_blocks[cast(i32) f];
+}
\ No newline at end of file
--- /dev/null
+package runtime.info
+
+#local io :: package core.io
+
+write_type_name :: (writer: ^io.Writer, t: type_expr) {
+ info := get_type_info(t);
+ if info == null do return;
+
+ switch info.kind {
+ case .Basic {
+ basic := cast(^Type_Info_Basic) info;
+
+ switch basic.basic_kind {
+ case .Void do io.write_str(writer, "void");
+ case .Bool do io.write_str(writer, "bool");
+ case .U8 do io.write_str(writer, "u8");
+ case .I8 do io.write_str(writer, "i8");
+ case .U16 do io.write_str(writer, "u16");
+ case .I16 do io.write_str(writer, "i16");
+ case .U32 do io.write_str(writer, "u32");
+ case .I32 do io.write_str(writer, "i32");
+ case .U64 do io.write_str(writer, "u64");
+ case .I64 do io.write_str(writer, "i64");
+
+ case .F32 do io.write_str(writer, "f32");
+ case .F64 do io.write_str(writer, "f64");
+
+ case .Rawptr do return io.write_str(writer, "rawptr");
+
+ case .I8X16 do return io.write_str(writer, "i8x16");
+ case .I16X8 do return io.write_str(writer, "i16x8");
+ case .I32X4 do return io.write_str(writer, "i32x4");
+ case .I64X2 do return io.write_str(writer, "i64x2");
+ case .F32X4 do return io.write_str(writer, "f32x4");
+ case .F64X2 do return io.write_str(writer, "f64x2");
+ case .V128 do return io.write_str(writer, "v128");
+
+ case .Type_Index do io.write_str(writer, "type_expr");
+ case .Unsized_Int do io.write_str(writer, "<unsized int>");
+ case .Unsized_Float do io.write_str(writer, "<unsized float>");
+ }
+ }
+
+ case .Pointer {
+ pointer := cast(^Type_Info_Pointer) info;
+ io.write_str(writer, "^");
+ write_type_name(writer, pointer.to);
+ }
+
+ case .Array {
+ arr := cast(^Type_Info_Array) info;
+ io.write_format(writer, "[{}] ", arr.count);
+ write_type_name(writer, arr.of);
+ }
+
+ case .Slice {
+ slice := cast(^Type_Info_Slice) info;
+ io.write_str(writer, "[] ");
+ write_type_name(writer, slice.of);
+ }
+
+ case .Dynamic_Array {
+ dyn := cast(^Type_Info_Dynamic_Array) info;
+ io.write_str(writer, "[..] ");
+ write_type_name(writer, dyn.of);
+ }
+
+ case .Variadic_Argument {
+ va := cast(^Type_Info_Variadic_Argument) info;
+ io.write_str(writer, "..");
+ write_type_name(writer, va.of);
+ }
+
+ case .Enum {
+ e := cast(^Type_Info_Enum) info;
+ io.write_str(writer, e.name);
+ }
+
+ case .Struct {
+ s := cast(^Type_Info_Struct) info;
+ if s.name.count > 0 do io.write_str(writer, s.name);
+ else do io.write_str(writer, "<anonymous struct>");
+ }
+
+ case .Polymorphic_Struct {
+ s := cast(^Type_Info_Polymorphic_Struct) info;
+ if s.name.count > 0 do io.write_str(writer, s.name);
+ else do io.write_str(writer, "<anonymous polymorphic struct>");
+ }
+
+ case .Compound {
+ comp := cast(^Type_Info_Compound) info;
+ io.write_str(writer, "(");
+
+ i := 0;
+ for type: comp.components {
+ if i != 0 do io.write_str(writer, ", ");
+
+ write_type_name(writer, type);
+ i += 1;
+ }
+ io.write_str(writer, ")");
+ }
+
+ case .Function {
+ f := cast(^Type_Info_Function) info;
+ io.write_str(writer, "(");
+
+ i := 0;
+ for type: f.parameter_types {
+ if i != 0 do io.write_str(writer, ", ");
+
+ write_type_name(writer, type);
+ i += 1;
+ }
+ io.write_str(writer, ") -> ");
+
+ write_type_name(writer, f.return_type);
+ }
+
+ case .Distinct {
+ d := cast(^Type_Info_Distinct) info;
+ io.write_str(writer, d.name);
+ }
+ }
+}
+
+is_pointer :: (t: type_expr) -> bool {
+ if t == rawptr do return true;
+ info := get_type_info(t);
+ return info.kind == .Pointer;
+}
+
+size_of :: (t: type_expr) -> u32 {
+ info := get_type_info(t);
+ if info == null do return 0;
+
+ switch info.kind {
+ case .Basic {
+ basic := cast(^Type_Info_Basic) info;
+
+ switch basic.basic_kind {
+ case .Void do return 0;
+ case .Bool, .U8, .I8 do return 1;
+ case .U16, .I16 do return 2;
+ case .U32, .I32, .F32, .Type_Index do return 4;
+ case .U64, .I64, .F64 do return 8;
+ case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 do return 16;
+ case .Rawptr do return sizeof rawptr;
+
+ case .Unsized_Int do return 0;
+ case .Unsized_Float do return 0;
+ }
+ }
+
+ case .Pointer do return sizeof rawptr;
+
+ case .Array {
+ arr := cast(^Type_Info_Array) info;
+ return size_of(arr.of) * arr.count;
+ }
+
+ case .Slice do return sizeof str;
+ case .Dynamic_Array do return sizeof [..] void;
+ case .Variadic_Argument do return sizeof str;
+ case .Enum {
+ e := cast(^Type_Info_Enum) info;
+ return e.size;
+ }
+
+ case .Struct {
+ s := cast(^Type_Info_Struct) info;
+ return s.size;
+ }
+
+ case .Polymorphic_Struct do return 0;
+
+ case .Compound do return 0;
+
+ case .Function do return 4;
+
+ case .Distinct {
+ d := cast(^Type_Info_Distinct) info;
+ return size_of(d.base_type);
+ }
+ }
+
+ return 0;
+}
+
+offset_of :: (T: type_expr, member: str) -> u32 {
+ info := get_type_info(T);
+ if info == null do return 0;
+ if info.kind != .Struct do return 0;
+
+ struct_info := cast(^Type_Info_Struct) info;
+ for ^m: struct_info.members {
+ if m.name == member do return m.offset;
+ }
+
+ // Should this return something else if the member was not found?
+ return 0;
+}
+
+get_tags_for_member :: (S: type_expr, member_name: str) -> [] any {
+ ti := get_type_info(S);
+ if ti.kind != .Struct do return .[];
+
+ for ^ (cast(^Type_Info_Struct) ti).members {
+ if it.name == member_name {
+ return it.tags;
+ }
+ }
+
+ return .[];
+}
+
+struct_constructed_from :: (struct_type: type_expr, base_type: type_expr) -> bool {
+ struct_info := get_type_info(struct_type);
+ if struct_info.kind != .Struct do return false;
+
+ return (cast(^Type_Info_Struct) struct_info).constructed_from == base_type;
+}
+
+struct_inherits :: (struct_type: type_expr, base_type: type_expr) -> bool {
+ struct_info := cast(^Type_Info_Struct) get_type_info(struct_type);
+ if struct_info.kind != .Struct do return false;
+
+ first_member := ^struct_info.members[0];
+ return first_member.used && first_member.type == base_type;
+}
+
+#operator == (t1: Type_Info_Function, t2: Type_Info_Function) -> bool {
+ if t1.parameter_types.count != t2.parameter_types.count do return false;
+ if t1.return_type != t2.return_type do return false;
+ if t1.is_variadic != t2.is_variadic do return false;
+
+ while i := 0; i < t1.parameter_types.count {
+ @Robustness // This does not handle nested procedure types
+ if t1.parameter_types[i] != t2.parameter_types[i] do return false;
+ }
+
+ return true;
+}
+
+enum_name :: (value: $Backing_Type) -> str {
+ info := get_type_info(Backing_Type);
+ if info.kind != .Enum do return null_str;
+
+ etype := cast(^Type_Info_Enum) info;
+ for ^member: etype.members {
+ if member.value == ~~value do return member.name;
+ }
+
+ return null_str;
+}
+
+enum_value :: ($E: type_expr, name: str) -> E {
+ info := get_type_info(E);
+ if info.kind != .Enum do return ~~0;
+
+ etype := cast(^Type_Info_Enum) info;
+ for ^member: etype.members {
+ if member.name == name do return ~~member.value;
+ }
+
+ return ~~0;
+}
+
+enum_values :: (E: type_expr) -> [] Type_Info_Enum.Member {
+ info := cast(^Type_Info_Enum) get_type_info(E);
+ if info.kind != .Enum do return .[];
+
+ return info.members;
+}
+
+get_struct_by_name :: (name: str) -> type_expr {
+ index := 0;
+ for type_table {
+ defer index += 1;
+ if it.kind != .Struct do continue;
+
+ if (cast(^Type_Info_Struct) it).name == name do return cast(type_expr) index;
+ }
+
+ return void;
+}
+
+get_struct_method :: (type: type_expr, method_name: str) -> ^any {
+ info := cast(^Type_Info_Struct) get_type_info(type);
+ if info.kind != .Struct do return null;
+
+ for ^method: info.methods {
+ if method.name == method_name {
+ return ^method.func;
+ }
+ }
+
+ return null;
+}
+
+populate_struct_vtable :: (table: ^$Table_Type, struct_type: type_expr, safe := true) {
+ v_info := cast(^Type_Info_Struct) get_type_info(Table_Type);
+ if v_info.kind != .Struct do return;
+
+ for^ member: v_info.members {
+ if get_type_info(member.type).kind != .Function do continue;
+
+ struct_method := get_struct_method(struct_type, member.name);
+ if struct_method == null do continue;
+ if safe && struct_method.type != member.type do continue;
+
+ dest := cast(^()->void) (cast(^u8) table + member.offset);
+ *dest = *cast(^()->void) struct_method.data;
+ }
+}
+
+for_all_types :: macro (body: Code) {
+ for (package runtime.info).type_table.count {
+ type_info := (package runtime.info).type_table[it];
+ type_idx : type_expr = ~~ it;
+
+ #unquote body;
+ }
+}
--- /dev/null
+// A lot of these names have been copied from JAI's introspection system. This is just because
+// I don't want to mentally bike-shed about the names; I just want to get something working.
+
+package runtime.info
+
+type_table : [] ^Type_Info;
+
+Type_Info :: struct {
+ // This must match the order of the elements in onyxtypes.h
+ Kind :: enum {
+ Invalid :: 0x00; // Unused
+ Basic :: 0x01;
+ Pointer :: 0x02;
+ Function :: 0x03;
+ Struct :: 0x04;
+ Polymorphic_Struct :: 0x05;
+ Compound :: 0x06;
+ Array :: 0x07;
+ Slice :: 0x08;
+ Dynamic_Array :: 0x09;
+ Variadic_Argument :: 0x0a;
+ Enum :: 0x0b;
+ Distinct :: 0x0c;
+ }
+
+ kind := Kind.Invalid;
+ size: u32;
+
+ // Does this need to know alignment? Probably?
+ alignment: u32;
+}
+
+Type_Info_Basic :: struct {
+ use base : Type_Info;
+
+ // This must match the order of the elements in BasicKind in onyxtypes.h
+ Kind :: enum {
+ Void :: 0x00;
+ Bool :: 0x01;
+
+ Unsized_Int :: 0x02;
+ I8 :: 0x03;
+ U8 :: 0x04;
+ I16 :: 0x05;
+ U16 :: 0x06;
+ I32 :: 0x07;
+ U32 :: 0x08;
+ I64 :: 0x09;
+ U64 :: 0x0a;
+
+ Unsized_Float :: 0x0b;
+ F32 :: 0x0c;
+ F64 :: 0x0d;
+
+ Rawptr :: 0x0e;
+
+ I8X16 :: 0x0f;
+ I16X8 :: 0x10;
+ I32X4 :: 0x11;
+ I64X2 :: 0x12;
+ F32X4 :: 0x13;
+ F64X2 :: 0x14;
+ V128 :: 0x15;
+
+ Type_Index :: 0x16;
+ }
+
+ basic_kind: Kind;
+}
+
+Type_Info_Pointer :: struct {
+ use base : Type_Info;
+
+ @Rename
+ to: type_expr;
+}
+
+Type_Info_Function :: struct {
+ use base : Type_Info;
+
+ return_type: type_expr;
+ parameter_types: [] type_expr;
+
+ is_variadic: bool;
+}
+
+Type_Info_Array :: struct {
+ use base : Type_Info;
+
+ @Rename
+ of: type_expr;
+ count: u32;
+}
+
+Type_Info_Slice :: struct {
+ use base : Type_Info;
+
+ @Rename
+ of: type_expr;
+}
+
+Type_Info_Dynamic_Array :: struct {
+ use base : Type_Info;
+
+ @Rename
+ of: type_expr;
+}
+
+Type_Info_Variadic_Argument :: struct {
+ use base : Type_Info;
+
+ @Rename
+ of: type_expr;
+}
+
+Type_Info_Enum :: struct {
+ use base : Type_Info;
+
+ Member :: struct {
+ name: str;
+ value: u64; // This assumes enums are always represented as ints.
+ }
+
+ // This is first for better alignment
+ backing_type: type_expr;
+ name: str;
+ members: [] Member;
+
+ is_flags: bool;
+}
+
+Type_Info_Struct :: struct {
+ use base : Type_Info;
+
+ Member :: struct {
+ name: str;
+ offset: u32;
+ type: type_expr;
+
+ used: bool;
+ default: rawptr; // Pointer to the initial value of the same type as the member.
+ // null if no default value is given, or if it is not compile time known.
+
+ // As another thought. This could become a thunk that get the default value
+ // at runtime or returns the value.
+
+ tags: [] any;
+ }
+
+ constructed_from: type_expr;
+ name: str;
+ members: [] Member;
+ parameters: [] any;
+ tags: [] any;
+
+ Method :: struct {
+ name: str;
+ func: any;
+ }
+ methods: [] Method;
+}
+
+Type_Info_Polymorphic_Struct :: struct {
+ use base : Type_Info;
+
+ name: str;
+ tags: [] any;
+}
+
+Type_Info_Compound :: struct {
+ use base : Type_Info;
+
+ components : [] type_expr;
+}
+
+Type_Info_Distinct :: struct {
+ use base : Type_Info;
+
+ base_type: type_expr;
+ name: str;
+}
+
+get_type_info :: (t: type_expr) -> ^Type_Info {
+ // Grossness to get around the fact that type_exprs are not technically comparable, because in most
+ // cases you should not compare them as the number assigned to them is arbitrary.
+ if ~~t < cast(i32) 0 || ~~t >= cast(i32) type_table.count do return null;
+
+ return type_table[cast(i32) t];
+}
+
+
#load "./runtime/build_opts"
#load "./runtime/common"
-#load "./type_info/helper"
+#load "./runtime/info/helper"
+#load "./runtime/info/types"
+#load "./runtime/info/foreign_blocks"
#load "./arg_parse"
+++ /dev/null
-package builtin.type_info
-
-#local io :: package core.io
-
-write_type_name :: (writer: ^io.Writer, t: type_expr) {
- info := get_type_info(t);
- if info == null do return;
-
- switch info.kind {
- case .Basic {
- basic := cast(^Type_Info_Basic) info;
-
- switch basic.basic_kind {
- case .Void do io.write_str(writer, "void");
- case .Bool do io.write_str(writer, "bool");
- case .U8 do io.write_str(writer, "u8");
- case .I8 do io.write_str(writer, "i8");
- case .U16 do io.write_str(writer, "u16");
- case .I16 do io.write_str(writer, "i16");
- case .U32 do io.write_str(writer, "u32");
- case .I32 do io.write_str(writer, "i32");
- case .U64 do io.write_str(writer, "u64");
- case .I64 do io.write_str(writer, "i64");
-
- case .F32 do io.write_str(writer, "f32");
- case .F64 do io.write_str(writer, "f64");
-
- case .Rawptr do return io.write_str(writer, "rawptr");
-
- case .I8X16 do return io.write_str(writer, "i8x16");
- case .I16X8 do return io.write_str(writer, "i16x8");
- case .I32X4 do return io.write_str(writer, "i32x4");
- case .I64X2 do return io.write_str(writer, "i64x2");
- case .F32X4 do return io.write_str(writer, "f32x4");
- case .F64X2 do return io.write_str(writer, "f64x2");
- case .V128 do return io.write_str(writer, "v128");
-
- case .Type_Index do io.write_str(writer, "type_expr");
- case .Unsized_Int do io.write_str(writer, "<unsized int>");
- case .Unsized_Float do io.write_str(writer, "<unsized float>");
- }
- }
-
- case .Pointer {
- pointer := cast(^Type_Info_Pointer) info;
- io.write_str(writer, "^");
- write_type_name(writer, pointer.to);
- }
-
- case .Array {
- arr := cast(^Type_Info_Array) info;
- io.write_format(writer, "[{}] ", arr.count);
- write_type_name(writer, arr.of);
- }
-
- case .Slice {
- slice := cast(^Type_Info_Slice) info;
- io.write_str(writer, "[] ");
- write_type_name(writer, slice.of);
- }
-
- case .Dynamic_Array {
- dyn := cast(^Type_Info_Dynamic_Array) info;
- io.write_str(writer, "[..] ");
- write_type_name(writer, dyn.of);
- }
-
- case .Variadic_Argument {
- va := cast(^Type_Info_Variadic_Argument) info;
- io.write_str(writer, "..");
- write_type_name(writer, va.of);
- }
-
- case .Enum {
- e := cast(^Type_Info_Enum) info;
- io.write_str(writer, e.name);
- }
-
- case .Struct {
- s := cast(^Type_Info_Struct) info;
- if s.name.count > 0 do io.write_str(writer, s.name);
- else do io.write_str(writer, "<anonymous struct>");
- }
-
- case .Polymorphic_Struct {
- s := cast(^Type_Info_Polymorphic_Struct) info;
- if s.name.count > 0 do io.write_str(writer, s.name);
- else do io.write_str(writer, "<anonymous polymorphic struct>");
- }
-
- case .Compound {
- comp := cast(^Type_Info_Compound) info;
- io.write_str(writer, "(");
-
- i := 0;
- for type: comp.components {
- if i != 0 do io.write_str(writer, ", ");
-
- write_type_name(writer, type);
- i += 1;
- }
- io.write_str(writer, ")");
- }
-
- case .Function {
- f := cast(^Type_Info_Function) info;
- io.write_str(writer, "(");
-
- i := 0;
- for type: f.parameter_types {
- if i != 0 do io.write_str(writer, ", ");
-
- write_type_name(writer, type);
- i += 1;
- }
- io.write_str(writer, ") -> ");
-
- write_type_name(writer, f.return_type);
- }
-
- case .Distinct {
- d := cast(^Type_Info_Distinct) info;
- io.write_str(writer, d.name);
- }
- }
-}
-
-is_pointer :: (t: type_expr) -> bool {
- if t == rawptr do return true;
- info := get_type_info(t);
- return info.kind == .Pointer;
-}
-
-size_of :: (t: type_expr) -> u32 {
- info := get_type_info(t);
- if info == null do return 0;
-
- switch info.kind {
- case .Basic {
- basic := cast(^Type_Info_Basic) info;
-
- switch basic.basic_kind {
- case .Void do return 0;
- case .Bool, .U8, .I8 do return 1;
- case .U16, .I16 do return 2;
- case .U32, .I32, .F32, .Type_Index do return 4;
- case .U64, .I64, .F64 do return 8;
- case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 do return 16;
- case .Rawptr do return sizeof rawptr;
-
- case .Unsized_Int do return 0;
- case .Unsized_Float do return 0;
- }
- }
-
- case .Pointer do return sizeof rawptr;
-
- case .Array {
- arr := cast(^Type_Info_Array) info;
- return size_of(arr.of) * arr.count;
- }
-
- case .Slice do return sizeof str;
- case .Dynamic_Array do return sizeof [..] void;
- case .Variadic_Argument do return sizeof str;
- case .Enum {
- e := cast(^Type_Info_Enum) info;
- return e.size;
- }
-
- case .Struct {
- s := cast(^Type_Info_Struct) info;
- return s.size;
- }
-
- case .Polymorphic_Struct do return 0;
-
- case .Compound do return 0;
-
- case .Function do return 4;
-
- case .Distinct {
- d := cast(^Type_Info_Distinct) info;
- return size_of(d.base_type);
- }
- }
-
- return 0;
-}
-
-offset_of :: (T: type_expr, member: str) -> u32 {
- info := get_type_info(T);
- if info == null do return 0;
- if info.kind != .Struct do return 0;
-
- struct_info := cast(^Type_Info_Struct) info;
- for ^m: struct_info.members {
- if m.name == member do return m.offset;
- }
-
- // Should this return something else if the member was not found?
- return 0;
-}
-
-get_tags_for_member :: (S: type_expr, member_name: str) -> [] any {
- use type_info;
-
- ti := get_type_info(S);
- if ti.kind != .Struct do return .[];
-
- for ^ (cast(^Type_Info_Struct) ti).members {
- if it.name == member_name {
- return it.tags;
- }
- }
-
- return .[];
-}
-
-struct_constructed_from :: (struct_type: type_expr, base_type: type_expr) -> bool {
- struct_info := get_type_info(struct_type);
- if struct_info.kind != .Struct do return false;
-
- return (cast(^Type_Info_Struct) struct_info).constructed_from == base_type;
-}
-
-struct_inherits :: (struct_type: type_expr, base_type: type_expr) -> bool {
- struct_info := cast(^Type_Info_Struct) get_type_info(struct_type);
- if struct_info.kind != .Struct do return false;
-
- first_member := ^struct_info.members[0];
- return first_member.used && first_member.type == base_type;
-}
-
-#operator == (t1: Type_Info_Function, t2: Type_Info_Function) -> bool {
- if t1.parameter_types.count != t2.parameter_types.count do return false;
- if t1.return_type != t2.return_type do return false;
- if t1.is_variadic != t2.is_variadic do return false;
-
- while i := 0; i < t1.parameter_types.count {
- @Robustness // This does not handle nested procedure types
- if t1.parameter_types[i] != t2.parameter_types[i] do return false;
- }
-
- return true;
-}
-
-enum_name :: (value: $Backing_Type) -> str {
- info := get_type_info(Backing_Type);
- if info.kind != .Enum do return null_str;
-
- etype := cast(^Type_Info_Enum) info;
- for ^member: etype.members {
- if member.value == ~~value do return member.name;
- }
-
- return null_str;
-}
-
-enum_value :: ($E: type_expr, name: str) -> E {
- info := get_type_info(E);
- if info.kind != .Enum do return ~~0;
-
- etype := cast(^Type_Info_Enum) info;
- for ^member: etype.members {
- if member.name == name do return ~~member.value;
- }
-
- return ~~0;
-}
-
-enum_values :: (E: type_expr) -> [] Type_Info_Enum.Member {
- info := cast(^Type_Info_Enum) get_type_info(E);
- if info.kind != .Enum do return .[];
-
- return info.members;
-}
-
-get_struct_by_name :: (name: str) -> type_expr {
- index := 0;
- for type_table {
- defer index += 1;
- if it.kind != .Struct do continue;
-
- if (cast(^Type_Info_Struct) it).name == name do return cast(type_expr) index;
- }
-
- return void;
-}
-
-get_struct_method :: (type: type_expr, method_name: str) -> ^any {
- info := cast(^Type_Info_Struct) get_type_info(type);
- if info.kind != .Struct do return null;
-
- for ^method: info.methods {
- if method.name == method_name {
- return ^method.func;
- }
- }
-
- return null;
-}
-
-populate_struct_vtable :: (table: ^$Table_Type, struct_type: type_expr, safe := true) {
- v_info := cast(^Type_Info_Struct) get_type_info(Table_Type);
- if v_info.kind != .Struct do return;
-
- for^ member: v_info.members {
- if get_type_info(member.type).kind != .Function do continue;
-
- struct_method := get_struct_method(struct_type, member.name);
- if struct_method == null do continue;
- if safe && struct_method.type != member.type do continue;
-
- dest := cast(^()->void) (cast(^u8) table + member.offset);
- *dest = *cast(^()->void) struct_method.data;
- }
-}
-
-for_all_types :: macro (body: Code) {
- for (package builtin.type_info).type_table.count {
- type_info := (package builtin.type_info).type_table[it];
- type_idx : type_expr = ~~ it;
-
- #unquote body;
- }
-}
+++ /dev/null
-// A lot of these names have been copied from JAI's introspection system. This is just because
-// I don't want to mentally bike-shed about the names; I just want to get something working.
-
-package builtin.type_info
-
-type_table : [] ^Type_Info;
-
-Type_Info :: struct {
- // This must match the order of the elements in onyxtypes.h
- Kind :: enum {
- Invalid :: 0x00; // Unused
- Basic :: 0x01;
- Pointer :: 0x02;
- Function :: 0x03;
- Struct :: 0x04;
- Polymorphic_Struct :: 0x05;
- Compound :: 0x06;
- Array :: 0x07;
- Slice :: 0x08;
- Dynamic_Array :: 0x09;
- Variadic_Argument :: 0x0a;
- Enum :: 0x0b;
- Distinct :: 0x0c;
- }
-
- kind := Kind.Invalid;
- size: u32;
-
- // Does this need to know alignment? Probably?
- alignment: u32;
-}
-
-Type_Info_Basic :: struct {
- use base : Type_Info;
-
- // This must match the order of the elements in BasicKind in onyxtypes.h
- Kind :: enum {
- Void :: 0x00;
- Bool :: 0x01;
-
- Unsized_Int :: 0x02;
- I8 :: 0x03;
- U8 :: 0x04;
- I16 :: 0x05;
- U16 :: 0x06;
- I32 :: 0x07;
- U32 :: 0x08;
- I64 :: 0x09;
- U64 :: 0x0a;
-
- Unsized_Float :: 0x0b;
- F32 :: 0x0c;
- F64 :: 0x0d;
-
- Rawptr :: 0x0e;
-
- I8X16 :: 0x0f;
- I16X8 :: 0x10;
- I32X4 :: 0x11;
- I64X2 :: 0x12;
- F32X4 :: 0x13;
- F64X2 :: 0x14;
- V128 :: 0x15;
-
- Type_Index :: 0x16;
- }
-
- basic_kind: Kind;
-}
-
-Type_Info_Pointer :: struct {
- use base : Type_Info;
-
- @Rename
- to: type_expr;
-}
-
-Type_Info_Function :: struct {
- use base : Type_Info;
-
- return_type: type_expr;
- parameter_types: [] type_expr;
-
- is_variadic: bool;
-}
-
-Type_Info_Array :: struct {
- use base : Type_Info;
-
- @Rename
- of: type_expr;
- count: u32;
-}
-
-Type_Info_Slice :: struct {
- use base : Type_Info;
-
- @Rename
- of: type_expr;
-}
-
-Type_Info_Dynamic_Array :: struct {
- use base : Type_Info;
-
- @Rename
- of: type_expr;
-}
-
-Type_Info_Variadic_Argument :: struct {
- use base : Type_Info;
-
- @Rename
- of: type_expr;
-}
-
-Type_Info_Enum :: struct {
- use base : Type_Info;
-
- Member :: struct {
- name: str;
- value: u64; // This assumes enums are always represented as ints.
- }
-
- // This is first for better alignment
- backing_type: type_expr;
- name: str;
- members: [] Member;
-
- is_flags: bool;
-}
-
-Type_Info_Struct :: struct {
- use base : Type_Info;
-
- Member :: struct {
- name: str;
- offset: u32;
- type: type_expr;
-
- used: bool;
- default: rawptr; // Pointer to the initial value of the same type as the member.
- // null if no default value is given, or if it is not compile time known.
-
- // As another thought. This could become a thunk that get the default value
- // at runtime or returns the value.
-
- tags: [] any;
- }
-
- constructed_from: type_expr;
- name: str;
- members: [] Member;
- parameters: [] any;
- tags: [] any;
-
- Method :: struct {
- name: str;
- func: any;
- }
- methods: [] Method;
-}
-
-Type_Info_Polymorphic_Struct :: struct {
- use base : Type_Info;
-
- name: str;
- tags: [] any;
-}
-
-Type_Info_Compound :: struct {
- use base : Type_Info;
-
- components : [] type_expr;
-}
-
-Type_Info_Distinct :: struct {
- use base : Type_Info;
-
- base_type: type_expr;
- name: str;
-}
-
-get_type_info :: (t: type_expr) -> ^Type_Info {
- // Grossness to get around the fact that type_exprs are not technically comparable, because in most
- // cases you should not compare them as the number assigned to them is arbitrary.
- if ~~t < cast(i32) 0 || ~~t >= cast(i32) type_table.count do return null;
-
- return type_table[cast(i32) t];
-}
-
-
-
-
-//
-// I have a small feeling I am going to rename "type_info" at some point soon,
-// which makes including this here make even more sense.
-//
-// Alternate names for "type_info" could be:
-//
-// - reflect
-// - introspect
-// - runtime.info I kind of like this so then things are in the runtime package.
-// runtime can be for things defined in the language, whil core
-// core can be for standard library like functionality.
-
-
-//
-// Foreign Blocks
-// Because foreign blocks can generate a lot of data, and their data is only
-// really helpful in a handful of cases, you need to pass "--generate-foreign-bindings"
-// to have these arrays filled out.
-//
-
-foreign_block :: #distinct u32
-
-foreign_blocks: [] ^Foreign_Block;
-
-Foreign_Block :: struct {
- module_name: str;
- funcs: [] Foreign_Function;
-
- Foreign_Function :: struct {
- name: str;
- type: type_expr;
- }
-}
-
-get_foreign_block :: (f: foreign_block) -> ^Foreign_Block {
- if ~~f < cast(i32) 0 || ~~f >= cast(i32) foreign_blocks.count do return null;
-
- return foreign_blocks[cast(i32) f];
-}
\ No newline at end of file
This type represents the value given by the `#callsite` expression. In practice, you will never use this type because you will just do something like: `f :: (site := #callsite)`
- `any` -
-This type represents any value. It does this by using a data pointer and a type expression. Using the `builtin.type_info` package, you can introspect that type expression to retrieve data about the type, and from there reconstruct how to use the data pointer. See `conv.onyx` for how this works with `printf`.
+This type represents any value. It does this by using a data pointer and a type expression. Using the `runtime.info` package, you can introspect that type expression to retrieve data about the type, and from there reconstruct how to use the data pointer. See `conv.onyx` for how this works with `printf`.
- `Code` -
This is a dummy type that represents the type of a `#unquote {}` block. It is used when passing code around to macros or procedures, i.e. `f :: macro (body: Code)`
\ No newline at end of file
NODE(DirectiveOperator) \
NODE(DirectiveExport) \
NODE(DirectiveDefined) \
- NODE(DirectiveTag) \
NODE(DirectiveInit) \
NODE(DirectiveLibrary) \
NODE(DirectiveRemove) \
Ast_Kind_Directive_Operator,
Ast_Kind_Directive_Export,
Ast_Kind_Directive_Defined,
- Ast_Kind_Directive_Tag,
Ast_Kind_Directive_Init,
Ast_Kind_Directive_Library,
Ast_Kind_Directive_Remove,
b32 is_defined: 1;
};
-struct AstDirectiveTag {
- AstNode_base;
-
- AstTyped* expr;
- AstTyped* tag;
-};
-
struct AstDirectiveRemove {
AstNode_base;
};
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
- offset_of :: (package builtin.type_info).offset_of;
+ offset_of :: (package runtime.info).offset_of;
IV :: Immediate_Vertex;
// Position
use package core
use package simd
+#local info :: package runtime.info
#if !#defined((package runtime).Generated_Foreign_Info) {
#error "Please run this script with the '--generate-foreign-info' flag."
}
Binding_Config :: struct {
- foreign_block: type_info.foreign_block;
+ foreign_block: info.foreign_block;
preamble: [] str;
output_file: str;
cast_map: [] Cast_Mapping;
build_c_binding :: (use binding_config: Binding_Config) -> bool {
for file: os.with_file(output_file, .Write) {
writer := io.writer_make(file);
- fb := type_info.get_foreign_block(foreign_block);
+ fb := info.get_foreign_block(foreign_block);
write_file_introduction(^writer, preamble, fb.module_name);
}
write_function_body :: (writer, ff, cast_map) => {
- use type_info;
+ use info;
method_type := ff.type;
method_info := cast (^Type_Info_Function) get_type_info(method_type);
}
print_body :: (writer, method_name, method_info, cast_map) => {
- use type_info;
+ use info;
call := io.dynamic_string_stream_make();
defer io.dynamic_string_stream_free(^call);
callw := io.writer_make(^call);
}
type_to_wasm_type :: (t: type_expr) -> str {
- use type_info;
+ use info;
param_info := get_type_info(t);
switch param_info.kind {
}
type_encoding :: (t: type_expr) -> str {
- use type_info;
+ use info;
param_info := get_type_info(t);
switch param_info.kind {
bh_arr_new(global_heap_allocator, init_procedures, 4);
- p = package_lookup("builtin.type_info");
+ p = package_lookup("runtime.info");
if (p != NULL) {
type_table_node = (AstTyped *) symbol_raw_resolve(p->scope, "type_table");
foreign_blocks_node = (AstTyped *) symbol_raw_resolve(p->scope, "foreign_blocks");
export->export_name = export->export_name_expr->token;
}
- if (directive->kind == Ast_Kind_Directive_Tag) {
- AstDirectiveTag *tag = (AstDirectiveTag *) directive;
-
- CHECK(expression, &tag->tag);
-
- switch (tag->expr->kind) {
- case Ast_Kind_Struct_Type: {
- AstStructType* st = (AstStructType *) tag->expr;
-
- bh_arr(AstTyped *) tags = st->meta_tags;
-
- if (tags == NULL) bh_arr_new(global_heap_allocator, tags, 1);
- bh_arr_push(tags, tag->tag);
-
- st->meta_tags = tags;
-
- return Check_Complete;
- }
-
- case Ast_Kind_Field_Access: {
- AstFieldAccess* fa = (AstFieldAccess *) tag->expr;
-
- if (fa->expr->kind == Ast_Kind_Struct_Type) {
- // CLEANUP: Everything in this case is handled very poorly.
- AstStructType* st = (AstStructType *) fa->expr;
- Type* s_type = type_build_from_ast(context.ast_alloc, (AstType *) st);
-
- bh_arr_each(AstStructMember *, smem, st->members) {
- if (token_equals((*smem)->token, fa->token)) {
- bh_arr(AstTyped *) tags = (*smem)->meta_tags;
-
- if (tags == NULL) bh_arr_new(global_heap_allocator, tags, 1);
- bh_arr_push(tags, tag->tag);
-
- (*smem)->meta_tags = tags;
-
- bh_arr_each(StructMember *, smem_type, s_type->Struct.memarr) {
- if (token_text_equals((*smem)->token, (*smem_type)->name)) {
- (*smem_type)->meta_tags = tags;
- break;
- }
- }
-
- return Check_Complete;
- }
- }
-
- onyx_report_error(fa->token->pos, Error_Critical, "'%b' is not a member of '%s'.",
- fa->token->text, fa->token->length,
- st->name);
- return Check_Error;
- }
- }
-
- default: {
- onyx_report_error(tag->token->pos, Error_Critical, "Cannot tag this.");
- return Check_Error;
- }
- }
- }
-
if (directive->kind == Ast_Kind_Directive_Init) {
AstDirectiveInit *init = (AstDirectiveInit *) directive;
if ((init->flags & Ast_Flag_Has_Been_Checked) == 0) {
case Ast_Kind_Directive_Export:
case Ast_Kind_Directive_Add_Overload:
- case Ast_Kind_Directive_Tag:
case Ast_Kind_Directive_Operator:
case Ast_Kind_Directive_Init:
case Ast_Kind_Directive_Library: {
.state = Entity_State_Parse_Builtin,
.type = Entity_Type_Load_File,
.package = NULL,
- .include = create_load(context.ast_alloc, "core/type_info/type_info"),
+ .include = create_load(context.ast_alloc, "core/runtime/info/types"),
+ }));
+ entity_heap_insert(&context.entities, ((Entity) {
+ .state = Entity_State_Parse_Builtin,
+ .type = Entity_Type_Load_File,
+ .package = NULL,
+ .include = create_load(context.ast_alloc, "core/runtime/info/foreign_blocks"),
}));
entity_heap_insert(&context.entities, ((Entity) {
ENTITY_SUBMIT(export);
return;
}
- else if (parse_possible_directive(parser, "tag")) {
- AstDirectiveTag *tag = make_node(AstDirectiveTag, Ast_Kind_Directive_Tag);
- tag->token = dir_token;
-
- tag->expr = parse_expression(parser, 0);
- expect_token(parser, ',');
- tag->tag = parse_expression(parser, 0);
-
- ENTITY_SUBMIT(tag);
- return;
- }
else if (parse_possible_directive(parser, "thread_local")) {
OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
AstMemRes* memres = parse_memory_reservation(parser, symbol, 1);
break;
}
- case Ast_Kind_Directive_Tag: {
- AstDirectiveTag *tag = (AstDirectiveTag *) directive;
- SYMRES(expression, &tag->tag);
- SYMRES(expression, &tag->expr);
- break;
- }
-
case Ast_Kind_Directive_Init: {
AstDirectiveInit *init = (AstDirectiveInit *) directive;
SYMRES(expression, &init->init_proc);
if (POINTER_SIZE == 4) bh_buffer_write_u32(&table_buffer, count); \
if (POINTER_SIZE == 8) bh_buffer_write_u64(&table_buffer, count);
- // This is the data behind the "type_table" slice in type_info.onyx
+ // This is the data behind the "type_table" slice in runtime/info/types.onyx
#if (POINTER_SIZE == 4)
#define Table_Info_Type u32
#else
#load "core/std"
use package core
+info :: package runtime.info
Base :: struct (T: type_expr) {
const: i32;
x := Base(str).{ 10, "Hello" };
printf("{}\n", x);
- printf("{}\n", type_info.struct_constructed_from(typeof x, Base));
+ printf("{}\n", info.struct_constructed_from(typeof x, Base));
y: Allocator;
- printf("{}\n", type_info.struct_constructed_from(typeof y, Base));
+ printf("{}\n", info.struct_constructed_from(typeof y, Base));
}
\ No newline at end of file