From 8c34d89df3034f8193c0c57b3ec256fe8fc999b0 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sat, 26 Feb 2022 15:55:13 -0600 Subject: [PATCH] struct method in type data; bug fixes --- core/string.onyx | 2 +- core/type_info/helper.onyx | 31 +++++++++++++++- core/type_info/type_info.onyx | 6 ++++ src/checker.c | 9 +++++ src/wasm_type_table.h | 64 +++++++++++++++++++++++++++++++++ tests/struct_use_pointer_member | 2 +- 6 files changed, 111 insertions(+), 3 deletions(-) diff --git a/core/string.onyx b/core/string.onyx index 80ba0b90..9da43aaa 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -192,7 +192,7 @@ strip_whitespace :: #match { strip_leading_whitespace :: #match { (s: ^str) { - while true do switch s.data[0] { + while s.count > 0 do switch s.data[0] { case #char " ", #char "\t", #char "\n", #char "\r" { s.data += 1; s.count -= 1; diff --git a/core/type_info/helper.onyx b/core/type_info/helper.onyx index 70328dde..358aeeb7 100644 --- a/core/type_info/helper.onyx +++ b/core/type_info/helper.onyx @@ -223,4 +223,33 @@ get_struct_by_name :: (name: str) -> type_expr { } return void; -} \ No newline at end of file +} + +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; + } +} diff --git a/core/type_info/type_info.onyx b/core/type_info/type_info.onyx index 2a256c5f..254753c1 100644 --- a/core/type_info/type_info.onyx +++ b/core/type_info/type_info.onyx @@ -152,6 +152,12 @@ Type_Info_Struct :: struct { members: [] Member; parameters: [] any; tags: [] any; + + Method :: struct { + name: str; + func: any; + } + methods: [] Method; } Type_Info_Polymorphic_Struct :: struct { diff --git a/src/checker.c b/src/checker.c index eea13f55..ca9afa83 100644 --- a/src/checker.c +++ b/src/checker.c @@ -2133,6 +2133,15 @@ CheckStatus check_struct(AstStructType* s_node) { CHECK(constraint_context, &s_node->constraints, s_node->scope, pos); } + if (s_node->scope) { + fori (i, 0, shlen(s_node->scope->symbols)) { + AstNode* node = s_node->scope->symbols[i].value; + if (node->kind == Ast_Kind_Function) { + node->flags |= Ast_Flag_Function_Used; + } + } + } + bh_arr_each(AstStructMember *, smem, s_node->members) { if ((*smem)->type_node != NULL) { CHECK(type, &(*smem)->type_node); diff --git a/src/wasm_type_table.h b/src/wasm_type_table.h index b32e8551..9fc5aa03 100644 --- a/src/wasm_type_table.h +++ b/src/wasm_type_table.h @@ -1,6 +1,12 @@ // This file is directly included in src/onxywasm.c // It is here purely to decrease the amount of clutter in the main file. +typedef struct StructMethodData { + u32 name_loc; + u32 name_len; + u32 type; + u32 data_loc; +} StructMethodData; u64 build_type_table(OnyxWasmModule* module) { @@ -186,6 +192,7 @@ u64 build_type_table(OnyxWasmModule* module) { memset(meta_locations, 0, s->mem_count * sizeof(u32)); memset(struct_tag_locations, 0, bh_arr_length(s->meta_tags) * sizeof(u32)); + // Member names u32 i = 0; bh_arr_each(StructMember*, pmem, s->memarr) { StructMember* mem = *pmem; @@ -196,6 +203,7 @@ u64 build_type_table(OnyxWasmModule* module) { bh_buffer_align(&table_buffer, 8); + // Polymorphic solutions i = 0; bh_arr_each(AstPolySolution, sln, s->poly_sln) { bh_buffer_align(&table_buffer, 8); @@ -229,6 +237,7 @@ u64 build_type_table(OnyxWasmModule* module) { bh_buffer_align(&table_buffer, 8); + // Member default values i = 0; bh_arr_each(StructMember*, pmem, s->memarr) { StructMember* mem = *pmem; @@ -265,6 +274,7 @@ u64 build_type_table(OnyxWasmModule* module) { } } + // Member tags i = 0; bh_arr_each(StructMember*, pmem, s->memarr) { StructMember* mem = *pmem; @@ -313,6 +323,7 @@ u64 build_type_table(OnyxWasmModule* module) { bh_buffer_align(&table_buffer, 8); u32 members_base = table_buffer.length; + // Member array i = 0; bh_arr_each(StructMember*, pmem, s->memarr) { StructMember* mem = *pmem; @@ -334,6 +345,7 @@ u64 build_type_table(OnyxWasmModule* module) { bh_buffer_align(&table_buffer, 8); u32 params_base = table_buffer.length; + // Polymorphic solution any array i = 0; bh_arr_each(AstPolySolution, sln, s->poly_sln) { WRITE_PTR(param_locations[i++]); @@ -342,6 +354,7 @@ u64 build_type_table(OnyxWasmModule* module) { else bh_buffer_write_u32(&table_buffer, sln->value->type->id); } + // Struct tag array i = 0; bh_arr_each(AstTyped *, tag, s->meta_tags) { AstTyped* value = *tag; @@ -361,6 +374,54 @@ u64 build_type_table(OnyxWasmModule* module) { i += 1; } + // Struct methods + bh_arr(StructMethodData) method_data=NULL; + AstType *ast_type = type->ast_type; + if (ast_type->kind == Ast_Kind_Struct_Type) { + AstStructType *struct_type = (AstStructType *) ast_type; + Scope* struct_scope = struct_type->scope; + + if (struct_scope == NULL) goto no_methods; + + fori (i, 0, shlen(struct_scope->symbols)) { + AstFunction* node = (AstFunction *) struct_scope->symbols[i].value; + if (node->kind != Ast_Kind_Function) continue; + assert(node->entity); + assert(node->entity->function == node); + + // Name + char *name = struct_scope->symbols[i].key; + u32 name_loc = table_buffer.length; + u32 name_len = strlen(name); + bh_buffer_append(&table_buffer, name, name_len); + + // any data member + bh_buffer_align(&table_buffer, 4); + u32 data_loc = table_buffer.length; + u32 func_idx = get_element_idx(module, node); + bh_buffer_write_u32(&table_buffer, func_idx); + + bh_arr_push(method_data, ((StructMethodData) { + .name_loc = name_loc, + .name_len = name_len, + .type = node->type->id, + .data_loc = data_loc, + })); + } + } + + no_methods: + + bh_buffer_align(&table_buffer, 4); + u32 method_data_base = table_buffer.length; + + i = 0; + bh_arr_each(StructMethodData, method, method_data) { + WRITE_SLICE(method->name_loc, method->name_len); + WRITE_PTR(method->data_loc); + bh_buffer_write_u32(&table_buffer, method->type); + } + bh_buffer_align(&table_buffer, 8); u32 struct_tag_base = table_buffer.length; @@ -368,6 +429,7 @@ u64 build_type_table(OnyxWasmModule* module) { WRITE_SLICE(struct_tag_locations[i], s->meta_tags[i]->type->id); } + // Struct name u32 name_base = 0; u32 name_length = 0; if (s->name) { @@ -392,7 +454,9 @@ u64 build_type_table(OnyxWasmModule* module) { WRITE_SLICE(members_base, s->mem_count); WRITE_SLICE(params_base, bh_arr_length(s->poly_sln)); WRITE_SLICE(struct_tag_base, bh_arr_length(s->meta_tags)); + WRITE_SLICE(method_data_base, bh_arr_length(method_data)); + bh_arr_free(method_data); break; } diff --git a/tests/struct_use_pointer_member b/tests/struct_use_pointer_member index 96429d6f..a8fbd546 100644 --- a/tests/struct_use_pointer_member +++ b/tests/struct_use_pointer_member @@ -1,2 +1,2 @@ Hello, I am Billy! -Go away!! func[6] +Go away!! func[9] -- 2.25.1