[X] Numeric literals have the minimum type detected
[X] Foreign imports (functions only)
[X] Comparison operators
- [ ] Proper boolean type
+ [X] Proper boolean type
[X] Conditional branching works as expected
[ ] Simple while loop is functioning as expected
[ ] break and continue semantics
- Changing output location
- Viewing help screen
+ [ ] 'use' statements work
+ - Adds '.onyx' to the end of the file name list
+ - Only searches in current directory for now
+
+ [ ] Output 'drop' instruction for functions whose return value isn't used
+
[ ] Devise and implement a simple set of implicit type casting rules.
- Numeric literals always type cast to whatever type is needed (very flexible).
TOKEN_TYPE_KEYWORD_PROC,
TOKEN_TYPE_KEYWORD_GLOBAL,
TOKEN_TYPE_KEYWORD_CAST,
+ TOKEN_TYPE_KEYWORD_WHILE,
TOKEN_TYPE_RIGHT_ARROW,
TOKEN_TYPE_LEFT_ARROW,
TOKEN_TYPE_SYMBOL,
TOKEN_TYPE_LITERAL_STRING,
TOKEN_TYPE_LITERAL_NUMERIC,
+ TOKEN_TYPE_LITERAL_BOOL_TRUE,
+ TOKEN_TYPE_LITERAL_BOOL_FALSE,
TOKEN_TYPE_COUNT
} OnyxTokenType;
typedef struct OnyxAstNodeScope OnyxAstNodeScope;
typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
typedef struct OnyxAstNodeIf OnyxAstNodeIf;
+typedef struct OnyxAstNodeWhile OnyxAstNodeWhile;
typedef struct OnyxAstNodeParam OnyxAstNodeParam;
typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef;
typedef struct OnyxAstNodeForeign OnyxAstNodeForeign;
ONYX_AST_NODE_KIND_EQUAL,
ONYX_AST_NODE_KIND_NOT_EQUAL,
- ONYX_AST_NODE_KIND_GREATER,
- ONYX_AST_NODE_KIND_GREATER_EQUAL,
ONYX_AST_NODE_KIND_LESS,
ONYX_AST_NODE_KIND_LESS_EQUAL,
+ ONYX_AST_NODE_KIND_GREATER,
+ ONYX_AST_NODE_KIND_GREATER_EQUAL,
ONYX_AST_NODE_KIND_NOT,
ONYX_AST_NODE_KIND_IF,
- ONYX_AST_NODE_KIND_LOOP,
+ ONYX_AST_NODE_KIND_WHILE,
ONYX_AST_NODE_KIND_COUNT
} OnyxAstNodeKind;
OnyxAstNode *true_block;
};
+struct OnyxAstNodeWhile {
+ OnyxAstNodeKind kind;
+ u32 flags;
+ OnyxToken *token; // NOTE: UNUSED
+ OnyxTypeInfo *type;
+ OnyxAstNode *next;
+ OnyxAstNode *cond;
+ OnyxAstNodeBlock *body;
+};
+
struct OnyxAstNodeFuncDef {
OnyxAstNodeKind kind;
u32 flags;
OnyxAstNodeNumLit as_numlit;
OnyxAstNodeForeign as_foreign;
OnyxAstNodeIf as_if;
+ OnyxAstNodeWhile as_while;
OnyxAstNodeFile as_file;
};
-other_value :: proc -> i32 {
- return 8675309 + something_else();
+other_value :: proc (n i32) -> i32 {
+ return 8675309 + something_else(n);
+}
+
+export fib :: proc (n i32) -> i32 {
+ if n == 0 { return 1; }
+ if n == 1 { return 1; }
+
+ a := 0;
+ b := 1;
+
+ count := n;
+
+ while count >= 0 {
+ count = count - 1;
+
+ c :: a + b;
+ b = a;
+ a = c;
+ }
+
+ return a;
+}
+
+export factorial :: proc (n i32) -> i32 {
+ if n <= 1 { return 1; }
+
+ f := 1;
+ i := 2;
+
+ while i <= n {
+ f = f * i;
+ i = i + 1;
+ }
+
+ return f;
}
// Foreign functions are included this way:
// sym_name :: foreign "module" "name" proc ...
-print :: foreign "host" "print" proc (value i32) ---
+// TODO: Make this work
+// use "progs/other";
-something_else :: proc -> i32 {
- return 100;
+print_i32 :: foreign "host" "print" proc (value i32) ---
+print_f32 :: foreign "host" "print" proc (value f32) ---
+print_i64 :: foreign "host" "print" proc (value i64) ---
+print_f64 :: foreign "host" "print" proc (value f64) ---
+
+something_else :: proc (n i32) -> i32 {
+ return 100 * n;
}
// This is the entry point
export main :: proc {
- nineteen :: 5 * 3 + 4;
- thirty_five :: 5 * (3 + 4);
+ i := 0;
+ while i < 10 {
+ print_i32(fib(i));
+ i = i + 1;
+ }
+
+ i = 0;
+ while i < 10 {
+ print_i32(factorial(i));
+ i = i + 1;
+ }
+
+ x : i32;
+ y := 0;
+ while y < 10 {
+
+ x = 0;
+ while x < 10 {
+ print_i32(x + y * 10);
+ x = x + 1;
+ }
+
+ y = y + 1;
+ }
+}
+
+export main2 :: proc {
+ big_num := fib(factorial(4));
+ something :: other_value(3);
- something :: other_value();
+ condition := big_num < something;
- print(nineteen);
- print(thirty_five);
- print(something);
+ if condition {
+ print_i32(big_num);
+ print_i32(something);
+ }
}
static const char* docstring = "Onyx compiler version " VERSION "\n"
"\n"
- "The standard compiler for the Onyx programming language.\n";
+ "The standard compiler for the Onyx programming language.\n"
+ "\n"
+ " $ onyx [-o <target file>] [--help] <input files>\n"
+ "\n"
+ " -o <target_file> Specify the target file\n"
+ " --help Print this help message\n";
typedef enum CompileAction {
ONYX_COMPILE_ACTION_COMPILE,
} CompilerProgress;
typedef struct CompilerState {
- bh_arena token_arena, ast_arena, msg_arena, sp_arena;
+ bh_arena ast_arena, msg_arena, sp_arena;
bh_allocator token_alloc, ast_alloc, msg_alloc, sp_alloc;
bh_table(bh_file_contents) loaded_files;
OnyxAstNodeFile* parse_source_file(bh_file_contents* file_contents, CompilerState* compiler_state) {
// NOTE: Maybe don't want to recreate the tokenizer and parser for every file
OnyxTokenizer tokenizer = onyx_tokenizer_create(compiler_state->token_alloc, file_contents);
+ bh_printf("Lexing %s\n", file_contents->filename);
onyx_lex_tokens(&tokenizer);
+ bh_printf("Parsing %s\n", file_contents->filename);
OnyxParser parser = onyx_parser_create(compiler_state->ast_alloc, &tokenizer, &compiler_state->msgs);
return onyx_parse(&parser);
}
onyx_message_create(compiler_state->msg_alloc, &compiler_state->msgs);
- // NOTE: Create the arena for tokens from the lexer
- bh_arena_init(&compiler_state->token_arena, opts->allocator, 16 * 1024 * 1024); // 16 MB
- compiler_state->token_alloc = bh_arena_allocator(&compiler_state->token_arena);
+ compiler_state->token_alloc = opts->allocator;
// NOTE: Create the arena where AST nodes will exist
// Prevents nodes from being scattered across memory due to fragmentation
bh_file_error err = bh_file_open(&file, *filename);
if (err != BH_FILE_ERROR_NONE) {
- bh_printf_err("Failed to open file %s\n", filename);
+ bh_printf_err("Failed to open file %s\n", *filename);
return ONYX_COMPILER_PROGRESS_FAILED_READ;
}
+ bh_printf("Reading %s\n", file.filename);
bh_file_contents fc = bh_file_read_contents(compiler_state->token_alloc, &file);
bh_file_close(&file);
return ONYX_COMPILER_PROGRESS_FAILED_PARSE;
}
+ bh_printf("Checking semantics and types\n");
OnyxSemPassState sp_state = onyx_sempass_create( compiler_state->sp_alloc, compiler_state->ast_alloc, &compiler_state->msgs);
onyx_sempass(&sp_state, root_file);
return ONYX_COMPILER_PROGRESS_FAILED_SEMPASS;
}
+ bh_printf("Creating WASM code\n");
compiler_state->wasm_mod = onyx_wasm_module_create(opts->allocator);
onyx_wasm_module_compile(&compiler_state->wasm_mod, root_file);
return ONYX_COMPILER_PROGRESS_FAILED_OUTPUT;
}
+ bh_printf("Writing WASM to %s\n", output_file.filename);
onyx_wasm_module_write_to_file(&compiler_state->wasm_mod, output_file);
return ONYX_COMPILER_PROGRESS_SUCCESS;
}
void compiler_state_free(CompilerState* cs) {
+ // NOTE: There is a memory leak here because the token's aren't freed
+
bh_arena_free(&cs->ast_arena);
bh_arena_free(&cs->msg_arena);
- bh_arena_free(&cs->token_arena);
bh_arena_free(&cs->sp_arena);
bh_table_free(cs->loaded_files);
onyx_wasm_module_free(&cs->wasm_mod);
"proc", //"TOKEN_TYPE_KEYWORD_PROC",
"global", //"TOKEN_TYPE_KEYWORD_GLOBAL",
"as", //"TOKEN_TYPE_KEYWORD_CAST",
+ "while", //"TOKEN_TYPE_KEYWORD_WHILE",
"->", //"TOKEN_TYPE_RIGHT_ARROW",
"<-", //"TOKEN_TYPE_LEFT_ARROW",
"TOKEN_TYPE_SYMBOL",
"TOKEN_TYPE_LITERAL_STRING",
"TOKEN_TYPE_LITERAL_NUMERIC",
+ "true",
+ "false",
"TOKEN_TYPE_COUNT"
};
LITERAL_TOKEN("export", 1, TOKEN_TYPE_KEYWORD_EXPORT);
LITERAL_TOKEN("use", 1, TOKEN_TYPE_KEYWORD_USE);
LITERAL_TOKEN("if", 1, TOKEN_TYPE_KEYWORD_IF);
- LITERAL_TOKEN("elseif", 1, TOKEN_TYPE_KEYWORD_ELSEIF);
+ LITERAL_TOKEN("elseif", 1, TOKEN_TYPE_KEYWORD_ELSEIF);
LITERAL_TOKEN("else", 1, TOKEN_TYPE_KEYWORD_ELSE);
LITERAL_TOKEN("foreign", 1, TOKEN_TYPE_KEYWORD_FOREIGN);
LITERAL_TOKEN("for", 1, TOKEN_TYPE_KEYWORD_FOR);
LITERAL_TOKEN("proc", 1, TOKEN_TYPE_KEYWORD_PROC);
LITERAL_TOKEN("global", 1, TOKEN_TYPE_KEYWORD_GLOBAL);
LITERAL_TOKEN("as", 1, TOKEN_TYPE_KEYWORD_CAST);
+ LITERAL_TOKEN("while", 1, TOKEN_TYPE_KEYWORD_WHILE);
+ LITERAL_TOKEN("true", 1, TOKEN_TYPE_LITERAL_BOOL_TRUE);
+ LITERAL_TOKEN("false", 1, TOKEN_TYPE_LITERAL_BOOL_FALSE);
LITERAL_TOKEN("->", 0, TOKEN_TYPE_RIGHT_ARROW);
LITERAL_TOKEN("<-", 0, TOKEN_TYPE_RIGHT_ARROW);
LITERAL_TOKEN("<=", 0, TOKEN_TYPE_SYM_LESS_EQUAL);
"NOT",
"IF",
- "LOOP",
+ "WHILE",
"ONYX_AST_NODE_KIND_COUNT",
};
{ ONYX_TYPE_INFO_KIND_UNKNOWN, 0, "unknown" },
{ ONYX_TYPE_INFO_KIND_VOID, 0, "void", 0, 0, 0, 0, 1 },
- { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 0, 0, 1, 1 },
+ { ONYX_TYPE_INFO_KIND_BOOL, 1, "bool", 0, 1, 0, 1, 1 },
{ ONYX_TYPE_INFO_KIND_UINT32, 4, "u32", 1, 1, 0, 0, 1 },
{ ONYX_TYPE_INFO_KIND_UINT64, 8, "u64", 1, 1, 0, 0, 1 },
static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left);
static OnyxAstNode* parse_expression(OnyxParser* parser);
static OnyxAstNodeIf* parse_if_stmt(OnyxParser* parser);
+static OnyxAstNodeWhile* parse_while_stmt(OnyxParser* parser);
static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret);
static OnyxAstNode* parse_return_statement(OnyxParser* parser);
static OnyxAstNodeBlock* parse_block(OnyxParser* parser);
case TOKEN_TYPE_LITERAL_NUMERIC: return (OnyxAstNode *) parse_numeric_literal(parser);
+ case TOKEN_TYPE_LITERAL_BOOL_TRUE:
+ {
+ OnyxAstNodeNumLit* bool_node = (OnyxAstNodeNumLit *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);
+ bool_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
+ bool_node->token = expect(parser, TOKEN_TYPE_LITERAL_BOOL_TRUE);
+ bool_node->value.i = 1;
+ return (OnyxAstNode *) bool_node;
+ }
+
+ case TOKEN_TYPE_LITERAL_BOOL_FALSE:
+ {
+ OnyxAstNodeNumLit* bool_node = (OnyxAstNodeNumLit *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);
+ bool_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
+ bool_node->token = expect(parser, TOKEN_TYPE_LITERAL_BOOL_FALSE);
+ bool_node->value.i = 0;
+ return (OnyxAstNode *) bool_node;
+ }
+
default:
onyx_message_add(parser->msgs,
ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
return root_if;
}
+static OnyxAstNodeWhile* parse_while_stmt(OnyxParser* parser) {
+ OnyxToken* while_token = expect(parser, TOKEN_TYPE_KEYWORD_WHILE);
+
+ OnyxAstNode* cond = parse_expression(parser);
+ OnyxAstNodeBlock* body = parse_block(parser);
+
+ OnyxAstNodeWhile* while_node = (OnyxAstNodeWhile *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_WHILE);
+ while_node->token = while_token;
+ while_node->cond = cond;
+ while_node->body = body;
+
+ return while_node;
+}
+
// Returns 1 if the symbol was consumed. Returns 0 otherwise
// ret is set to the statement to insert
static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret) {
retval = (OnyxAstNode *) parse_if_stmt(parser);
break;
+ case TOKEN_TYPE_KEYWORD_WHILE:
+ needs_semicolon = 0;
+ retval = (OnyxAstNode *) parse_while_stmt(parser);
+ break;
+
default:
break;
}
curr_param = (OnyxAstNodeParam *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PARAM);
curr_param->token = symbol;
curr_param->type = parse_type(parser);
+ curr_param->flags |= ONYX_AST_FLAG_CONST;
if (first_param == NULL) first_param = curr_param;
if (walker->kind == ONYX_AST_NODE_KIND_BLOCK) {
bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker);
+ } else if (walker->kind == ONYX_AST_NODE_KIND_WHILE) {
+ bh_arr_push(traversal_queue, walker->as_while.body);
+
} else if (walker->kind == ONYX_AST_NODE_KIND_IF) {
if (walker->as_if.true_block)
bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker->as_if.true_block);
static void symres_assignment(OnyxSemPassState* state, OnyxAstNode* assign);
static void symres_return(OnyxSemPassState* state, OnyxAstNode* ret);
static void symres_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode);
+static void symres_while(OnyxSemPassState* state, OnyxAstNodeWhile* whilenode);
static void symres_statement_chain(OnyxSemPassState* state, OnyxAstNode* walker, OnyxAstNode** trailer);
static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt);
static void symres_block(OnyxSemPassState* state, OnyxAstNodeBlock* block);
}
}
+static void symres_while(OnyxSemPassState* state, OnyxAstNodeWhile* whilenode) {
+ symres_expression(state, &whilenode->cond);
+ symres_block(state, whilenode->body);
+}
+
// NOTE: Returns 1 if the statment should be removed
static b32 symres_statement(OnyxSemPassState* state, OnyxAstNode* stmt) {
switch (stmt->kind) {
case ONYX_AST_NODE_KIND_ASSIGNMENT: symres_assignment(state, stmt); return 0;
case ONYX_AST_NODE_KIND_RETURN: symres_return(state, stmt); return 0;
case ONYX_AST_NODE_KIND_IF: symres_if(state, &stmt->as_if); return 0;
+ case ONYX_AST_NODE_KIND_WHILE: symres_while(state, &stmt->as_while); return 0;
case ONYX_AST_NODE_KIND_CALL: symres_call(state, stmt); return 0;
case ONYX_AST_NODE_KIND_ARGUMENT: symres_expression(state, (OnyxAstNode **) &stmt->left); return 0;
case ONYX_AST_NODE_KIND_BLOCK: symres_block(state, &stmt->as_block); return 0;
static void typecheck_assignment(OnyxSemPassState* state, OnyxAstNode* assign);
static void typecheck_return(OnyxSemPassState* state, OnyxAstNode* retnode);
static void typecheck_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode);
+static void typecheck_while(OnyxSemPassState* state, OnyxAstNodeWhile* whilenode);
static void typecheck_call(OnyxSemPassState* state, OnyxAstNodeCall* call);
static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr);
static void typecheck_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode) {
typecheck_expression(state, ifnode->cond);
- if (ifnode->cond->type != &builtin_types[ONYX_TYPE_INFO_KIND_INT32]) {
+ if (ifnode->cond->type != &builtin_types[ONYX_TYPE_INFO_KIND_BOOL]) {
onyx_message_add(state->msgs,
ONYX_MESSAGE_TYPE_LITERAL,
ifnode->cond->token->pos,
- "expected integer type for condition");
+ "expected boolean type for condition");
return;
}
if (ifnode->false_block) typecheck_statement(state, ifnode->false_block);
}
+static void typecheck_while(OnyxSemPassState* state, OnyxAstNodeWhile* whilenode) {
+ typecheck_expression(state, whilenode->cond);
+ if (whilenode->cond->type != &builtin_types[ONYX_TYPE_INFO_KIND_BOOL]) {
+ onyx_message_add(state->msgs,
+ ONYX_MESSAGE_TYPE_LITERAL,
+ whilenode->cond->token->pos,
+ "expected boolean type for condition");
+ return;
+ }
+
+ typecheck_block(state, whilenode->body);
+}
+
static void typecheck_call(OnyxSemPassState* state, OnyxAstNodeCall* call) {
OnyxAstNodeFuncDef* callee = (OnyxAstNodeFuncDef *) call->callee;
return;
}
- expr->type = expr->left->type;
+ if (expr->kind >= ONYX_AST_NODE_KIND_EQUAL
+ && expr->kind <= ONYX_AST_NODE_KIND_GREATER_EQUAL) {
+ expr->type = &builtin_types[ONYX_TYPE_INFO_KIND_BOOL];
+ } else {
+ expr->type = expr->left->type;
+ }
+
break;
case ONYX_AST_NODE_KIND_NEGATE:
case ONYX_AST_NODE_KIND_ASSIGNMENT: typecheck_assignment(state, stmt); break;
case ONYX_AST_NODE_KIND_RETURN: typecheck_return(state, stmt); break;
case ONYX_AST_NODE_KIND_IF: typecheck_if(state, &stmt->as_if); break;
+ case ONYX_AST_NODE_KIND_WHILE: typecheck_while(state, &stmt->as_while); break;
case ONYX_AST_NODE_KIND_CALL: typecheck_call(state, &stmt->as_call); break;
case ONYX_AST_NODE_KIND_BLOCK: typecheck_block(state, &stmt->as_block); break;
static void compile_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval);
static void compile_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign);
static void compile_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node);
+static void compile_while(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeWhile* while_node);
static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr);
static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* cast);
static void compile_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret);
case ONYX_AST_NODE_KIND_RETURN: compile_return(mod, func, stmt); break;
case ONYX_AST_NODE_KIND_ASSIGNMENT: compile_assignment(mod, func, stmt); break;
case ONYX_AST_NODE_KIND_IF: compile_if(mod, func, (OnyxAstNodeIf *) stmt); break;
+ case ONYX_AST_NODE_KIND_WHILE: compile_while(mod, func, (OnyxAstNodeWhile *) stmt); break;
case ONYX_AST_NODE_KIND_CALL: compile_expression(mod, func, stmt); break;
case ONYX_AST_NODE_KIND_BLOCK: compile_block(mod, func, (OnyxAstNodeBlock *) stmt); break;
+
default: break;
}
}
bh_arr_push(func->code, ((WasmInstruction){ WI_IF_END, 0x00 }));
}
+static void compile_while(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeWhile* while_node) {
+ bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
+ bh_arr_push(func->code, ((WasmInstruction){ WI_LOOP_START, 0x40 }));
+
+ compile_expression(mod, func, while_node->cond);
+ bh_arr_push(func->code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
+ bh_arr_push(func->code, ((WasmInstruction){ WI_COND_JUMP, 0x01 }));
+
+ forll (OnyxAstNode, stmt, while_node->body->body, next) {
+ compile_statement(mod, func, stmt);
+ }
+
+ bh_arr_push(func->code, ((WasmInstruction){ WI_JUMP, 0x00 }));
+
+ bh_arr_push(func->code, ((WasmInstruction){ WI_LOOP_END, 0x00 }));
+ bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+}
+
static void compile_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign) {
compile_expression(mod, func, assign->right);
compile_assign_lval(mod, func, assign->left);
case ONYX_AST_NODE_KIND_##ast_binop: \
{ \
WasmInstructionType instr_type; \
- switch (expr->type->kind) { \
+ switch (expr->left->type->kind) { \
+ case ONYX_TYPE_INFO_KIND_BOOL: \
case ONYX_TYPE_INFO_KIND_UINT32: \
case ONYX_TYPE_INFO_KIND_INT32: instr_type = WI_I32_##wasm_binop; break; \
case ONYX_TYPE_INFO_KIND_UINT64: \
case ONYX_AST_NODE_KIND_##ast_binop: \
{ \
WasmInstructionType instr_type; \
- switch (expr->type->kind) { \
+ switch (expr->left->type->kind) { \
+ case ONYX_TYPE_INFO_KIND_BOOL: \
case ONYX_TYPE_INFO_KIND_UINT32: \
case ONYX_TYPE_INFO_KIND_INT32: \
- if (expr->type->is_unsigned) instr_type = WI_I32_##wasm_binop##_U; \
+ if (expr->left->type->is_unsigned) instr_type = WI_I32_##wasm_binop##_U; \
else instr_type = WI_I32_##wasm_binop##_S; \
break; \
case ONYX_TYPE_INFO_KIND_UINT64: \
case ONYX_TYPE_INFO_KIND_INT64: \
- if (expr->type->is_unsigned) instr_type = WI_I64_##wasm_binop##_U; \
+ if (expr->left->type->is_unsigned) instr_type = WI_I64_##wasm_binop##_U; \
else instr_type = WI_I64_##wasm_binop##_S; \
break; \
case ONYX_TYPE_INFO_KIND_FLOAT32: instr_type = WI_F32_##wasm_binop; break; \
case WI_LOCAL_SET:
case WI_CALL:
case WI_BLOCK_START:
+ case WI_LOOP_START:
+ case WI_JUMP:
+ case WI_COND_JUMP:
case WI_IF_START:
leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
bh_buffer_append(buff, leb, leb_len);