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;
// 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;
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) {
}
}
+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:
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;
}
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;
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 = {
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);
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) {
.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);
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:
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;
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);
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);
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;
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);
}
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);