[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)
[ ] Comparison operators
[ ] Proper boolean type
[ ] Conditional branching works as expected
typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
typedef struct OnyxAstNodeParam OnyxAstNodeParam;
typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;
+typedef struct OnyxAstNodeForeign OnyxAstNodeForeign;
typedef struct OnyxAstNodeCall OnyxAstNodeCall;
typedef struct OnyxParser {
ONYX_AST_NODE_KIND_PROGRAM,
ONYX_AST_NODE_KIND_FUNCDEF,
+ ONYX_AST_NODE_KIND_FOREIGN,
ONYX_AST_NODE_KIND_BLOCK,
ONYX_AST_NODE_KIND_SCOPE,
ONYX_AST_NODE_KIND_LOCAL,
OnyxAstNodeParam *params;
};
+struct OnyxAstNodeForeign {
+ OnyxAstNodeKind kind;
+ u32 flags;
+ OnyxToken *mod_token;
+ OnyxTypeInfo *type;
+ OnyxAstNode *next;
+ OnyxToken *name_token;
+ OnyxAstNode *import;
+};
+
struct OnyxAstNodeCall {
OnyxAstNodeKind kind;
u32 flags;
OnyxAstNodeScope as_scope;
OnyxAstNodeCall as_call;
OnyxAstNodeNumLit as_numlit;
+ OnyxAstNodeForeign as_foreign;
};
const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);
--- /dev/null
+
+gfx_draw_rect :: foreign "gfx" "draw_rect" proc (x i32, y i32, w i32, h i32) ---
+
+update :: proc ---
+
+draw :: proc {
+ draw_rect(0, 0, 100, 100);
+}
+
+export main :: proc {
+
+ while true {
+ update();
+ draw();
+ }
+}
-foo :: proc () -> i32 {
+
+print :: foreign "host" "print" proc (value i32) ---
+
+foo :: proc -> i32 {
return 10 as i32;
}
export do_stuff :: proc -> i32 {
res := diff_square((4 + 5) as i32, (2 + 3) as i32);
res = res + foo();
+ // res should be 66
return res;
}
"PROGRAM",
"FUNCDEF",
+ "FOREIGN",
"BLOCK",
"SCOPE",
"LOCAL",
return func_def;
}
+static OnyxAstNode* parse_top_level_symbol(OnyxParser* parser) {
+ if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {
+ OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);
+ return (OnyxAstNode *) func_def;
+
+ } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {
+ // Handle struct case
+ assert(0);
+ } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_FOREIGN) {
+ parser_next_token(parser);
+
+ OnyxAstNodeForeign* foreign = (OnyxAstNodeForeign *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_FOREIGN);
+ foreign->mod_token = expect(parser, TOKEN_TYPE_LITERAL_STRING);
+ foreign->name_token = expect(parser, TOKEN_TYPE_LITERAL_STRING);
+ foreign->import = parse_top_level_symbol(parser);
+
+ return (OnyxAstNode *) foreign;
+ } else {
+ onyx_message_add(parser->msgs,
+ ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
+ parser->curr_token->pos,
+ onyx_get_token_type_name(parser->curr_token->type));
+ return &error_node;
+ }
+}
+
static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) {
switch (parser->curr_token->type) {
case TOKEN_TYPE_KEYWORD_USE:
expect(parser, TOKEN_TYPE_SYM_COLON);
expect(parser, TOKEN_TYPE_SYM_COLON);
- if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) {
- OnyxAstNodeFuncDef* func_def = parse_function_definition(parser);
- func_def->token = symbol;
+ OnyxAstNode* node = parse_top_level_symbol(parser);
+ if (node->kind == ONYX_AST_NODE_KIND_FUNCDEF) {
+ node->token = symbol;
- onyx_token_null_toggle(*symbol);
+ onyx_token_null_toggle(*symbol);
- if (!bh_table_has(OnyxAstNode *, parser->identifiers, symbol->token)) {
- bh_table_put(OnyxAstNode *, parser->identifiers, symbol->token, (OnyxAstNode *) func_def);
- } else {
- onyx_message_add(parser->msgs,
- ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
- symbol->pos,
- symbol->token);
+ 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);
- return NULL;
- }
-
- onyx_token_null_toggle(*symbol);
- return (OnyxAstNode *) func_def;
+ // NOTE: I really wish C had defer...
+ onyx_token_null_toggle(*symbol);
+ return NULL;
+ }
- } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) {
- // Handle struct case
- assert(0);
- } else {
- onyx_message_add(parser->msgs,
- ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
- parser->curr_token->pos,
- onyx_get_token_type_name(parser->curr_token->type));
- break;
- }
+ onyx_token_null_toggle(*symbol);
+ }
+ return node;
}
default: break;
}
case ONYX_AST_NODE_KIND_FUNCDEF: {
- bh_printf("(%b) ", node->token->token, node->token->length);
+ if (node->token)
+ bh_printf("(%b) ", node->token->token, node->token->length);
OnyxAstNodeFuncDef* fd = &node->as_funcdef;
print_indent;
break;
}
+ case ONYX_AST_NODE_KIND_FOREIGN: {
+ OnyxAstNodeForeign* foreign = &node->as_foreign;
+ bh_printf("%b:%b",
+ foreign->mod_token->token, foreign->mod_token->length,
+ foreign->name_token->token, foreign->name_token->length);
+
+ if (foreign->import) {
+ onyx_ast_print(foreign->import, indent + 1);
+ }
+
+ if (foreign->next) {
+ onyx_ast_print(foreign->next, indent);
+ }
+ break;
+ }
+
default: {
onyx_ast_print(node->left, indent + 1);
onyx_ast_print(node->right, indent + 1);
}
// If there is no body then don't process the code
- if (fd->body == NULL) return;
-
- // NOTE: Generate the local map
- i32 localidx = 0;
- forll (OnyxAstNodeParam, param, fd->params, next) {
- bh_imap_put(&mod->local_map, (u64) param, localidx++);
- }
-
- static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
-
- // HACK: This assumes that the order of the count members
- // is the same as the order of the local_types above
- u8* count = &wasm_func.locals.i32_count;
- fori (ti, 0, 3) {
- forll (OnyxAstNodeLocal, local, fd->body->scope->last_local, prev_local) {
- if (onyx_type_to_wasm_type(local->type) == local_types[ti]) {
- bh_imap_put(&mod->local_map, (u64) local, localidx++);
-
- (*count)++;
- }
- }
+ if (fd->body != NULL) {
+ // NOTE: Generate the local map
+ i32 localidx = 0;
+ forll (OnyxAstNodeParam, param, fd->params, next) {
+ bh_imap_put(&mod->local_map, (u64) param, localidx++);
+ }
+
+ static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
+
+ // HACK: This assumes that the order of the count members
+ // is the same as the order of the local_types above
+ u8* count = &wasm_func.locals.i32_count;
+ fori (ti, 0, 3) {
+ forll (OnyxAstNodeLocal, local, fd->body->scope->last_local, prev_local) {
+ if (onyx_type_to_wasm_type(local->type) == local_types[ti]) {
+ bh_imap_put(&mod->local_map, (u64) local, localidx++);
+
+ (*count)++;
+ }
+ }
- count++;
- }
+ count++;
+ }
- // Generate code
- process_function_body(mod, &wasm_func, fd);
+ // Generate code
+ process_function_body(mod, &wasm_func, fd);
+ } else {
+ // NOTE: Empty bodies still need a block end instruction
+ bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+ }
bh_arr_push(mod->funcs, wasm_func);
bh_imap_clear(&mod->local_map);
}
+void process_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign) {
+
+}
+
OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* program) {
OnyxWasmModule module = {
.allocator = alloc,
case ONYX_AST_NODE_KIND_FUNCDEF:
process_function_definition(&module, &walker->as_funcdef);
break;
+ case ONYX_AST_NODE_KIND_FOREIGN:
+ process_foreign(&module, &walker->as_foreign);
+ break;
default: break;
}
case WI_LOCAL_GET:
case WI_LOCAL_SET:
case WI_CALL:
- leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
- bh_buffer_append(buff, leb, leb_len);
- break;
-
case WI_BLOCK_START:
leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
bh_buffer_append(buff, leb, leb_len);