Added foreign functions (WASM imports)
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 19 Jun 2020 16:05:36 +0000 (11:05 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 19 Jun 2020 16:05:36 +0000 (11:05 -0500)
Makefile
docs/plan
include/bh.h
include/onyxwasm.h
onyx
progs/minimal.onyx
src/onyxparser.c
src/onyxwasm.c

index 32e6043f227da4530930780a2b0d1983322e84b5..54dc1cbb2b15e348eebae6b4f6c27eea58914bea 100644 (file)
--- 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
index 21597ed3db66e2c25f5e5c9e40a56af54fd53f1d..bb41161ee90762d3adfc9293d5f368a81c1ddc80 100644 (file)
--- 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
index 38b7fa118bd4261370ce6ef904524386ac117a72..85ad76997beb0ffcbfac36b1e8809dfc654f74dd 100644 (file)
@@ -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))
index c8482ada5789fdb44c534bb65b0f22d2bf38d003..3ae0f67ebdc55c762bbd85d22b41268158f17bb4 100644 (file)
@@ -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 e09523b81a2d60ab26149a45a80840c4abdf1129..be18df102da38964c6521c4c42c8cebd0f0ac8d6 100755 (executable)
Binary files a/onyx and b/onyx differ
index 83b863d61f09ef291c785befe4d72c34e5d0319e..def47486d713ee147048974c0903db0e99820def 100644 (file)
@@ -25,5 +25,6 @@ export do_stuff :: proc -> i32 {
 }
 
 export main :: proc {
-    output :: do_stuff();
+    output := do_stuff() * (0 - 2);
+    print(output);
 }
index b0ad386179f89208d110037fb9b8be81ee2fbaab..c98c1609200e87e4ab59376bedfaf19205a0258e 100644 (file)
@@ -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;
                        }
 
index f4515a4af67e87e5ee03c973d7dccc866bc64dea..e457780359b1d22101c966cc0db0499a1c74644d 100644 (file)
@@ -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, &section_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);