From: Brendan Hansen Date: Fri, 19 Jun 2020 16:05:36 +0000 (-0500) Subject: Added foreign functions (WASM imports) X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=3a13a2f95832e1905bb5086ab6bf6b5c5e49c86d;p=onyx.git Added foreign functions (WASM imports) --- diff --git a/Makefile b/Makefile index 32e6043f..54dc1cbb 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,6 @@ onyx: $(OBJ_FILES) $(CC) $(FLAGS) $(OBJ_FILES) -o $@ $(LIBS) clean: - rm $(OBJ_FILES) 2>&1 >/dev/null + rm -f $(OBJ_FILES) 2>&1 >/dev/null all: onyx diff --git a/docs/plan b/docs/plan index 21597ed3..bb41161e 100644 --- a/docs/plan +++ b/docs/plan @@ -55,7 +55,7 @@ HOW: [X] Curly braces are required for all bodies of blocks [X] Numeric literals are parsed [X] Numeric literals have the minimum type detected - [ ] Foreign imports (functions only) + [X] Foreign imports (functions only) [ ] Comparison operators [ ] Proper boolean type [ ] Conditional branching works as expected diff --git a/include/bh.h b/include/bh.h index 38b7fa11..85ad7699 100644 --- a/include/bh.h +++ b/include/bh.h @@ -582,7 +582,7 @@ typedef struct bh__table { #else #define bh_table_init(allocator_, tab, hs) bh__table_init(allocator_, (bh__table **)&(tab), hs) #define bh_table_free(tab) bh__table_free((bh__table **)&(tab)) - #define bh_table_put(T, tab, key, value) (*((T *) bh__table_put((bh__table *) tab, sizeof(T), key)) = value) + #define bh_table_put(T, tab, key, value) (*((T *) bh__table_put((bh__table *) tab, sizeof(T), key)) = (T) value) #define bh_table_has(T, tab, key) (bh__table_has((bh__table *) tab, sizeof(T), key)) #define bh_table_get(T, tab, key) (*((T *) bh__table_get((bh__table *) tab, sizeof(T), key))) #define bh_table_delete(T, tab, key) (bh__table_delete((bh__table *) tab, sizeof(T), key)) diff --git a/include/onyxwasm.h b/include/onyxwasm.h index c8482ada..3ae0f67e 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -249,18 +249,24 @@ typedef struct WasmFunc { bh_arr(WasmInstruction) code; } WasmFunc; -typedef enum WasmExportKind { - WASM_EXPORT_FUNCTION = 0x00, - WASM_EXPORT_TABLE = 0x01, - WASM_EXPORT_MEMORY = 0x02, - WASM_EXPORT_GLOBAL = 0x03, -} WasmExportKind; +typedef enum WasmForeignKind { + WASM_FOREIGN_FUNCTION = 0x00, + WASM_FOREIGN_TABLE = 0x01, + WASM_FOREIGN_MEMORY = 0x02, + WASM_FOREIGN_GLOBAL = 0x03, +} WasmForeignKind; typedef struct WasmExport { - WasmExportKind kind; + WasmForeignKind kind; i32 idx; } WasmExport; +typedef struct WasmImport { + WasmForeignKind kind; + i32 idx; + OnyxToken *mod, *name; +} WasmImport; + typedef struct OnyxWasmModule { bh_allocator allocator; @@ -271,16 +277,18 @@ typedef struct OnyxWasmModule { // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 ) // to the function type index if it has been created. bh_table(i32) type_map; - i32 next_type_idx; - // NOTE: This have to be pointers because the type is variadic in size - bh_arr(WasmFuncType*) functypes; + bh_arr(WasmFuncType*) functypes; // NOTE: This have to be pointers because the type is variadic in size bh_arr(WasmFunc) funcs; - // NOTE: Maps from ast node pointers to the function index - bh_imap func_map; - i32 next_func_idx; + bh_imap func_map; // NOTE: Maps from ast node pointers to the function index bh_table(WasmExport) exports; + + bh_arr(WasmImport) imports; + + i32 next_type_idx; + i32 next_func_idx; + i32 next_import_func_idx; i32 export_count; } OnyxWasmModule; diff --git a/onyx b/onyx index e09523b8..be18df10 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 83b863d6..def47486 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -25,5 +25,6 @@ export do_stuff :: proc -> i32 { } export main :: proc { - output :: do_stuff(); + output := do_stuff() * (0 - 2); + print(output); } diff --git a/src/onyxparser.c b/src/onyxparser.c index b0ad3861..c98c1609 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -249,6 +249,8 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) { ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL, sym_token->pos, sym_token->token); onyx_token_null_toggle(*sym_token); + + return sym_node; } if (parser->curr_token->type != TOKEN_TYPE_OPEN_PAREN) { @@ -709,6 +711,26 @@ static OnyxAstNode* parse_top_level_symbol(OnyxParser* parser) { } } +static b32 define_function(OnyxParser* parser, OnyxAstNodeFuncDef* func) { + onyx_token_null_toggle(*func->token); + + if (!bh_table_has(OnyxAstNode *, parser->identifiers, func->token->token)) { + bh_table_put(OnyxAstNode *, parser->identifiers, func->token->token, func); + } else { + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, + func->token->pos, + func->token->token); + + // NOTE: I really wish C had defer... + onyx_token_null_toggle(*func->token); + return 0; + } + + onyx_token_null_toggle(*func->token); + return 1; +} + static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) { switch (parser->curr_token->type) { case TOKEN_TYPE_KEYWORD_USE: @@ -744,23 +766,22 @@ static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) { if (node->kind == ONYX_AST_NODE_KIND_FUNCDEF) { node->token = symbol; - onyx_token_null_toggle(*symbol); - - if (!bh_table_has(OnyxAstNode *, parser->identifiers, symbol->token)) { - bh_table_put(OnyxAstNode *, parser->identifiers, symbol->token, node); - } else { - onyx_message_add(parser->msgs, - ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, - symbol->pos, - symbol->token); - - // NOTE: I really wish C had defer... - onyx_token_null_toggle(*symbol); + if (!define_function(parser, &node->as_funcdef)) { return NULL; } + } - onyx_token_null_toggle(*symbol); + if (node->kind == ONYX_AST_NODE_KIND_FOREIGN) { + OnyxAstNodeForeign* foreign = &node->as_foreign; + + foreign->import->token = symbol; + if (foreign->import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + if (!define_function(parser, &foreign->import->as_funcdef)) { + return NULL; + } + } } + return node; } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index f4515a4a..e4577803 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -440,7 +440,7 @@ static void process_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret bh_arr_push(func->code, ((WasmInstruction){ WI_RETURN, 0x00 })); } -static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* fd) { +static i32 generate_type_idx(OnyxWasmModule* mod, OnyxAstNodeFuncDef* fd) { static char type_repr_buf[128]; char* t = type_repr_buf; @@ -479,6 +479,12 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* mod->next_type_idx++; } + return type_idx; +} + +static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* fd) { + i32 type_idx = generate_type_idx(mod, fd); + WasmFunc wasm_func = { .type_idx = type_idx, .locals = { @@ -496,7 +502,7 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* onyx_token_null_toggle(*fd->token); WasmExport wasm_export = { - .kind = WASM_EXPORT_FUNCTION, + .kind = WASM_FOREIGN_FUNCTION, .idx = func_idx, }; bh_table_put(WasmExport, mod->exports, fd->token->token, wasm_export); @@ -543,8 +549,24 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* bh_imap_clear(&mod->local_map); } -void process_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign) { - +static void process_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign) { + if (foreign->import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + i32 type_idx = generate_type_idx(module, &foreign->import->as_funcdef); + + WasmImport import = { + .kind = WASM_FOREIGN_FUNCTION, + .idx = type_idx, + .mod = foreign->mod_token, + .name = foreign->name_token, + }; + + bh_arr_push(module->imports, import); + + } else { + DEBUG_HERE; + // NOTE: Invalid foreign + assert(0); + } } OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* program) { @@ -560,10 +582,14 @@ OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* progra .exports = NULL, .export_count = 0, + + .imports = NULL, + .next_import_func_idx = 0, }; bh_arr_new(alloc, module.functypes, 4); bh_arr_new(alloc, module.funcs, 4); + bh_arr_new(alloc, module.imports, 4); bh_table_init(bh_heap_allocator(), module.type_map, 61); bh_table_init(bh_heap_allocator(), module.exports, 61); @@ -571,7 +597,18 @@ OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* progra bh_imap_init(&module.local_map, bh_heap_allocator()); bh_imap_init(&module.func_map, bh_heap_allocator()); + // NOTE: Count number of import functions OnyxAstNode* walker = program; + while (walker) { + if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN + && walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + module.next_func_idx++; + } + + walker = walker->next; + } + + walker = program; while (walker) { switch (walker->kind) { case ONYX_AST_NODE_KIND_FUNCDEF: @@ -637,6 +674,14 @@ static i32 output_vector(void** arr, i32 stride, i32 arrlen, vector_func elem, b return vec_buff->length; } +static i32 output_name(const char* start, i32 length, bh_buffer* buff) { + i32 leb_len, prev_len = buff->length; + u8* leb = uint_to_uleb128((u64) length, &leb_len); + bh_buffer_append(buff, leb, leb_len); + bh_buffer_append(buff, start, length); + return buff->length - prev_len; +} + static i32 output_functype(WasmFuncType* type, bh_buffer* buff) { i32 prev_len = buff->length; @@ -706,6 +751,35 @@ static i32 output_funcsection(OnyxWasmModule* module, bh_buffer* buff) { return buff->length - prev_len; } +static i32 output_importsection(OnyxWasmModule* module, bh_buffer* buff) { + i32 prev_len = buff->length; + bh_buffer_write_byte(buff, WASM_SECTION_ID_IMPORT); + + bh_buffer vec_buff; + bh_buffer_init(&vec_buff, buff->allocator, 128); + + i32 leb_len; + u8* leb = uint_to_uleb128((u64) (bh_arr_length(module->imports)), &leb_len); + bh_buffer_append(&vec_buff, leb, leb_len); + + bh_arr_each(WasmImport, import, module->imports) { + output_name(import->mod->token, import->mod->length, &vec_buff); + output_name(import->name->token, import->name->length, &vec_buff); + bh_buffer_write_byte(&vec_buff, (u8) import->kind); + + leb = uint_to_uleb128((u64) import->idx, &leb_len); + bh_buffer_append(&vec_buff, leb, leb_len); + } + + leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len); + bh_buffer_append(buff, leb, leb_len); + + bh_buffer_concat(buff, vec_buff); + bh_buffer_free(&vec_buff); + + return buff->length - prev_len; +} + static i32 output_exportsection(OnyxWasmModule* module, bh_buffer* buff) { i32 prev_len = buff->length; bh_buffer_write_byte(buff, WASM_SECTION_ID_EXPORT); @@ -720,9 +794,7 @@ static i32 output_exportsection(OnyxWasmModule* module, bh_buffer* buff) { i32 key_len = 0; bh_table_each_start(WasmExport, module->exports); key_len = strlen(key); - leb = uint_to_uleb128((u64) key_len, &leb_len); - bh_buffer_append(&vec_buff, leb, leb_len); - bh_buffer_append(&vec_buff, key, key_len); + output_name(key, key_len, &vec_buff); bh_buffer_write_byte(&vec_buff, (u8) (value.kind)); leb = uint_to_uleb128((u64) value.idx, &leb_len); @@ -743,7 +815,7 @@ static i32 output_startsection(OnyxWasmModule* module, bh_buffer* buff) { i32 start_idx = -1; bh_table_each_start(WasmExport, module->exports) { - if (value.kind == WASM_EXPORT_FUNCTION) { + if (value.kind == WASM_FOREIGN_FUNCTION) { if (strncmp("main", key, 5) == 0) { start_idx = value.idx; break; @@ -755,11 +827,11 @@ static i32 output_startsection(OnyxWasmModule* module, bh_buffer* buff) { bh_buffer_write_byte(buff, WASM_SECTION_ID_START); i32 start_leb_len, section_leb_len; - u8* start_leb = uint_to_uleb128((u64) start_idx, &start_leb_len); + uint_to_uleb128((u64) start_idx, &start_leb_len); u8* section_leb = uint_to_uleb128((u64) start_leb_len, §ion_leb_len); bh_buffer_append(buff, section_leb, section_leb_len); - start_leb = uint_to_uleb128((u64) start_idx, &start_leb_len); + u8* start_leb = uint_to_uleb128((u64) start_idx, &start_leb_len); bh_buffer_append(buff, start_leb, start_leb_len); } @@ -893,6 +965,7 @@ void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file) { bh_buffer_append(&master_buffer, WASM_VERSION, 4); output_typesection(module, &master_buffer); + output_importsection(module, &master_buffer); output_funcsection(module, &master_buffer); output_exportsection(module, &master_buffer); output_startsection(module, &master_buffer);