casts X to type T
[X] Curly braces are required for all bodies of blocks
- [ ] Numeric literals are parsed
- [ ] Numeric literals have the minimum type detected (automatically upcasts)
+ [X] Numeric literals are parsed
+ [X] Numeric literals have the minimum type detected
[ ] Comparison operators
[ ] Proper boolean type
[ ] Conditional branching works as expected
This could be slow but it would be easier than creating a graph
scheduling algorithm.
+ [ ] Consequence of the above, recursion works
+
[ ] Devise and implement a simple set of implicit type casting rules.
- Numeric literals always type cast to whatever type is needed (very flexible).
// Converts an unsigned integer to the unsigned LEB128 format
u8* uint_to_uleb128(u64 n, i32* output_length);
u8* int_to_leb128(i64 n, i32* output_length);
-u8* float_to_ieee754(f32 f);
-u8* double_to_ieee754(f64 f);
+u8* float_to_ieee754(f32 f, b32 reverse);
+u8* double_to_ieee754(f64 f, b32 reverse);
//-------------------------------------------------------------------------------
#ifndef BH_NO_IMAP
-typedef u64 bh_imap_key_t;
+typedef u64 bh_imap_entry_t;
typedef struct bh__imap_entry {
- bh_imap_key_t key, value;
+ bh_imap_entry_t key, value;
} bh__imap_entry;
typedef struct bh_imap {
bh_allocator allocator;
- bh_arr(bh__imap_entry) keys;
+ bh_arr(bh__imap_entry) entries;
} bh_imap;
void bh_imap_init(bh_imap* imap, bh_allocator alloc);
void bh_imap_free(bh_imap* imap);
-void bh_imap_put(bh_imap* imap, bh_imap_key_t key, bh_imap_key_t value);
-b32 bh_imap_has(bh_imap* imap, bh_imap_key_t key);
-bh_imap_key_t bh_imap_get(bh_imap* imap, bh_imap_key_t key);
-void bh_imap_delete(bh_imap* imap, bh_imap_key_t key);
+void bh_imap_put(bh_imap* imap, bh_imap_entry_t key, bh_imap_entry_t value);
+b32 bh_imap_has(bh_imap* imap, bh_imap_entry_t key);
+bh_imap_entry_t bh_imap_get(bh_imap* imap, bh_imap_entry_t key);
+void bh_imap_delete(bh_imap* imap, bh_imap_entry_t key);
+void bh_imap_clear(bh_imap* imap);
#ifdef BH_DEFINE
#endif // BH_DEFINE
// NOTE: This assumes the underlying implementation of float on the host
// system is already IEEE-754. This is safe to assume in most cases.
-u8* float_to_ieee754(f32 f) {
+u8* float_to_ieee754(f32 f, b32 reverse) {
static u8 buffer[4];
u8* fmem = (u8*) &f;
- buffer[0] = fmem[3];
- buffer[1] = fmem[2];
- buffer[2] = fmem[1];
- buffer[3] = fmem[0];
+ if (reverse) {
+ buffer[0] = fmem[3];
+ buffer[1] = fmem[2];
+ buffer[2] = fmem[1];
+ buffer[3] = fmem[0];
+ } else {
+ buffer[0] = fmem[0];
+ buffer[1] = fmem[1];
+ buffer[2] = fmem[2];
+ buffer[3] = fmem[3];
+ }
return buffer;
}
-u8* double_to_ieee754(f64 f) {
+u8* double_to_ieee754(f64 f, b32 reverse) {
static u8 buffer[8];
u8* fmem = (u8*) &f;
- buffer[0] = fmem[7];
- buffer[1] = fmem[6];
- buffer[2] = fmem[5];
- buffer[3] = fmem[4];
- buffer[4] = fmem[3];
- buffer[5] = fmem[2];
- buffer[6] = fmem[1];
- buffer[7] = fmem[0];
+ if (reverse) {
+ buffer[0] = fmem[7];
+ buffer[1] = fmem[6];
+ buffer[2] = fmem[5];
+ buffer[3] = fmem[4];
+ buffer[4] = fmem[3];
+ buffer[5] = fmem[2];
+ buffer[6] = fmem[1];
+ buffer[7] = fmem[0];
+ } else {
+ buffer[0] = fmem[0];
+ buffer[1] = fmem[1];
+ buffer[2] = fmem[2];
+ buffer[3] = fmem[3];
+ buffer[4] = fmem[4];
+ buffer[5] = fmem[5];
+ buffer[6] = fmem[6];
+ buffer[7] = fmem[7];
+ }
return buffer;
}
#ifndef BH_NO_IMAP
void bh_imap_init(bh_imap* imap, bh_allocator alloc) {
imap->allocator = alloc;
- imap->keys = NULL;
+ imap->entries = NULL;
- bh_arr_new(alloc, imap->keys, 4);
+ bh_arr_new(alloc, imap->entries, 4);
}
void bh_imap_free(bh_imap* imap) {
- bh_arr_free(imap->keys);
- imap->keys = NULL;
+ bh_arr_free(imap->entries);
+ imap->entries = NULL;
}
-b32 bh__imap_get_index(bh_imap* imap, bh_imap_key_t key, i32* pos) {
+b32 bh__imap_get_index(bh_imap* imap, bh_imap_entry_t key, i32* pos) {
i32 low = 0;
- i32 high = bh_arr_length(imap->keys);
+ i32 high = bh_arr_length(imap->entries);
i32 middle = 0;
bh__imap_entry tmp;
while (high > low) {
middle = (high + low) / 2;
- tmp = imap->keys[middle];
+ tmp = imap->entries[middle];
if (tmp.key == key) {
if (pos) *pos = middle;
return 0;
}
-void bh_imap_put(bh_imap* imap, bh_imap_key_t key, bh_imap_key_t value) {
+void bh_imap_put(bh_imap* imap, bh_imap_entry_t key, bh_imap_entry_t value) {
i32 middle = 0;
b32 found_existing = bh__imap_get_index(imap, key, &middle);
if (found_existing) {
- imap->keys[middle].value = value;
+ imap->entries[middle].value = value;
} else {
- bh_arr_insertn(imap->keys, middle, 1);
- imap->keys[middle].key = key;
- imap->keys[middle].value = value;
+ bh_arr_insertn(imap->entries, middle, 1);
+ imap->entries[middle].key = key;
+ imap->entries[middle].value = value;
}
}
-b32 bh_imap_has(bh_imap* imap, bh_imap_key_t key) {
+b32 bh_imap_has(bh_imap* imap, bh_imap_entry_t key) {
return bh__imap_get_index(imap, key, NULL);
}
-bh_imap_key_t bh_imap_get(bh_imap* imap, bh_imap_key_t key) {
+bh_imap_entry_t bh_imap_get(bh_imap* imap, bh_imap_entry_t key) {
i32 middle = 0;
b32 found_existing = bh__imap_get_index(imap, key, &middle);
if (found_existing) {
- return imap->keys[middle].value;
+ return imap->entries[middle].value;
} else {
return 0;
}
}
-void bh_imap_delete(bh_imap* imap, bh_imap_key_t key) {
+void bh_imap_delete(bh_imap* imap, bh_imap_entry_t key) {
i32 middle = 0;
b32 found_existing = bh__imap_get_index(imap, key, &middle);
if (found_existing) {
- bh_arr_deleten(imap->keys, middle, 1);
+ bh_arr_deleten(imap->entries, middle, 1);
}
}
+void bh_imap_clear(bh_imap* imap) {
+ // NOTE: Does not clear out an of the data that was in the map
+ bh_arr_set_length(imap->entries, 0);
+}
+
#endif // ifndef BH_NO_IMAP
#endif // ifdef BH_DEFINE
typedef struct OnyxToken {
OnyxTokenType type;
- isize length;
+ i32 length;
char* token;
OnyxFilePos pos;
} OnyxToken;
#include "onyxmsgs.h"
typedef union OnyxAstNode OnyxAstNode;
+typedef struct OnyxAstNodeNumLit OnyxAstNodeNumLit;
typedef struct OnyxAstNodeLocal OnyxAstNodeLocal;
typedef struct OnyxAstNodeScope OnyxAstNodeScope;
typedef struct OnyxAstNodeBlock OnyxAstNodeBlock;
ONYX_AST_FLAG_COMPTIME = BH_BIT(3),
} OnyxAstFlags;
+struct OnyxAstNodeNumLit {
+ OnyxAstNodeKind kind;
+ u32 flags;
+ OnyxToken *token;
+ OnyxTypeInfo *type;
+ OnyxAstNode *next;
+ union { i32 i; i64 l; f32 f; f64 d; } value;
+ ptr unused;
+};
+
struct OnyxAstNodeLocal {
OnyxAstNodeKind kind;
u32 flags;
OnyxAstNodeLocal as_local;
OnyxAstNodeScope as_scope;
OnyxAstNodeCall as_call;
+ OnyxAstNodeNumLit as_numlit;
};
const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind);
typedef struct OnyxWasmModule {
bh_allocator allocator;
- // NOTE: Mapping to local indicies currently in scope.
- bh_table(i32) local_map;
+ // NOTE: Mapping from local ast node ptrs to indicies
+ bh_imap local_map;
// NOTE: Used internally as a map from strings that represent function types,
// 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
return (c * d) as i32;
}
-export do_stuff :: proc () -> i32 {
- res := diff_square((2 + 3) as i32, (4 + 5) as i32);
+export do_stuff :: proc -> i32 {
+ res := diff_square((4 + 5) as i32, (2 + 3) as i32);
res = res + foo();
return res;
}
-export main :: proc () {
+export main :: proc {
output :: do_stuff();
}
INCREMENT_CURR_TOKEN(tokenizer);
}
+ if (*(tokenizer->curr + 1) == 'f') {
+ len++;
+ INCREMENT_CURR_TOKEN(tokenizer);
+ }
+
tk.type = TOKEN_TYPE_LITERAL_NUMERIC;
tk.length = len;
}
static OnyxAstNodeScope* leave_scope(OnyxParser* parser);
static void insert_identifier(OnyxParser* parser, OnyxAstNode* ident, b32 is_local);
static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident);
+static OnyxAstNodeNumLit* parse_numeric_literal(OnyxParser* parser);
static OnyxAstNode* parse_factor(OnyxParser* parser);
static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left);
static OnyxAstNode* parse_expression(OnyxParser* parser);
onyx_token_null_toggle(*local->token);
}
+static OnyxAstNodeNumLit* parse_numeric_literal(OnyxParser* parser) {
+ OnyxAstNodeNumLit* lit_node = (OnyxAstNodeNumLit *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);
+ lit_node->token = expect(parser, TOKEN_TYPE_LITERAL_NUMERIC);
+ lit_node->flags |= ONYX_AST_FLAG_COMPTIME;
+ lit_node->value.l = 0ll;
+
+ onyx_token_null_toggle(*lit_node->token);
+
+ OnyxTypeInfo* type;
+ char* tok = lit_node->token->token;
+
+ // NOTE: charset_contains() behaves more like string_contains()
+ // so I'm using it in this case
+ if (charset_contains(tok, '.')) {
+ if (tok[lit_node->token->length - 1] == 'f') {
+ type = &builtin_types[ONYX_TYPE_INFO_KIND_FLOAT32];
+ lit_node->value.f = strtof(tok, NULL);
+ } else {
+ type = &builtin_types[ONYX_TYPE_INFO_KIND_FLOAT64];
+ lit_node->value.d = strtod(tok, NULL);
+ }
+ } else {
+ i64 value = strtoll(tok, NULL, 0);
+ if (bh_abs(value) < ((u64) 1 << 32)) {
+ type = &builtin_types[ONYX_TYPE_INFO_KIND_INT32];
+ } else {
+ type = &builtin_types[ONYX_TYPE_INFO_KIND_INT64];
+ }
+
+ lit_node->value.l = value;
+ }
+
+ lit_node->type = type;
+ onyx_token_null_toggle(*lit_node->token);
+ return lit_node;
+}
+
static OnyxAstNode* parse_factor(OnyxParser* parser) {
switch (parser->curr_token->type) {
case TOKEN_TYPE_OPEN_PAREN:
return (OnyxAstNode *) call_node;
}
- case TOKEN_TYPE_LITERAL_NUMERIC:
- {
- OnyxAstNode* lit_node = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_LITERAL);
- lit_node->type = &builtin_types[ONYX_TYPE_INFO_KIND_INT64];
- lit_node->token = expect(parser, TOKEN_TYPE_LITERAL_NUMERIC);
- lit_node->flags |= ONYX_AST_FLAG_COMPTIME;
- return lit_node;
- }
+ case TOKEN_TYPE_LITERAL_NUMERIC: return (OnyxAstNode *) parse_numeric_literal(parser);
default:
onyx_message_add(parser->msgs,
}
static OnyxAstNodeParam* parse_function_params(OnyxParser* parser) {
+ if (parser->curr_token->type != TOKEN_TYPE_OPEN_PAREN)
+ return NULL;
+
expect(parser, TOKEN_TYPE_OPEN_PAREN);
if (parser->curr_token->type == TOKEN_TYPE_CLOSE_PAREN) {
}
case ONYX_AST_NODE_KIND_LITERAL: {
- bh_printf("%b", node->token->token, node->token->length);
+ bh_printf("(%s) %b", node->type->name, node->token->token, node->token->length);
if (node->next) {
onyx_ast_print(node->next, indent);
}
static void process_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval) {
if (lval->kind == ONYX_AST_NODE_KIND_LOCAL || lval->kind == ONYX_AST_NODE_KIND_PARAM) {
- onyx_token_null_toggle(*lval->token);
- i32 localidx = bh_table_get(i32, mod->local_map, lval->token->token);
- onyx_token_null_toggle(*lval->token);
+ i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) lval);
bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_SET, localidx }));
} else {
case ONYX_AST_NODE_KIND_LOCAL:
case ONYX_AST_NODE_KIND_PARAM:
{
- onyx_token_null_toggle(*expr->token);
- i32 localidx = bh_table_get(i32, mod->local_map, expr->token->token);
- onyx_token_null_toggle(*expr->token);
+ i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) expr);
bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_GET, localidx }));
break;
case ONYX_AST_NODE_KIND_CAST: process_cast(mod, func, expr); break;
case ONYX_AST_NODE_KIND_LITERAL:
{
- // TODO: Implement proper literal type detection and parsing
- i64 value = 0;
-
- bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, value }));
+ OnyxAstNodeNumLit* lit = &expr->as_numlit;
+ WasmType lit_type = onyx_type_to_wasm_type(lit->type);
+ WasmInstruction instr = { WI_NOP, 0 };
+
+ if (lit_type == WASM_TYPE_INT32) {
+ instr.type = WI_I32_CONST;
+ instr.data.i1 = lit->value.i;
+ } else if (lit_type == WASM_TYPE_INT64) {
+ instr.type = WI_I64_CONST;
+ instr.data.l = lit->value.l;
+ } else if (lit_type == WASM_TYPE_FLOAT32) {
+ instr.type = WI_F32_CONST;
+ instr.data.f = lit->value.f;
+ } else if (lit_type == WASM_TYPE_FLOAT64) {
+ instr.type = WI_F64_CONST;
+ instr.data.d = lit->value.d;
+ }
+
+ bh_arr_push(func->code, instr);
break;
}
// NOTE: Generate the local map
i32 localidx = 0;
forll (OnyxAstNodeParam, param, fd->params, next) {
- onyx_token_null_toggle(*param->token);
- bh_table_put(i32, mod->local_map, param->token->token, localidx++);
- onyx_token_null_toggle(*param->token);
+ 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 };
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]) {
- onyx_token_null_toggle(*local->token);
- bh_table_put(i32, mod->local_map, local->token->token, localidx++);
- onyx_token_null_toggle(*local->token);
+ bh_imap_put(&mod->local_map, (u64) local, localidx++);
(*count)++;
}
bh_arr_push(mod->funcs, wasm_func);
// NOTE: Clear the local map on exit of generating this function
- bh_table_clear(mod->local_map);
+ bh_imap_clear(&mod->local_map);
}
OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* program) {
bh_arr_new(alloc, module.functypes, 4);
bh_arr_new(alloc, module.funcs, 4);
- bh_table_init(bh_heap_allocator(), module.local_map, 61);
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());
OnyxAstNode* walker = program;
void onyx_wasm_module_free(OnyxWasmModule* module) {
bh_arr_free(module->functypes);
bh_arr_free(module->funcs);
- bh_table_free(module->local_map);
+ bh_imap_free(&module->local_map);
+ bh_imap_free(&module->func_map);
bh_table_free(module->type_map);
bh_table_free(module->exports);
}
static void output_instruction(WasmInstruction* instr, bh_buffer* buff) {
i32 leb_len;
u8* leb;
+
+ bh_buffer_write_byte(buff, (u8) instr->type);
+
switch (instr->type) {
case WI_LOCAL_GET:
case WI_LOCAL_SET:
- bh_buffer_write_byte(buff, (u8) instr->type);
+ 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:
- bh_buffer_write_byte(buff, (u8) instr->type);
leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
bh_buffer_append(buff, leb, leb_len);
break;
case WI_I32_CONST:
+ leb = int_to_leb128((i64) instr->data.i1, &leb_len);
+ bh_buffer_append(buff, leb, leb_len);
+ break;
case WI_I64_CONST:
- bh_buffer_write_byte(buff, (u8) instr->type);
- bh_buffer_write_byte(buff, 0); // TODO: Actually output the literal
- break;
-
- case WI_CALL:
- bh_buffer_write_byte(buff, (u8) instr->type);
- leb = uint_to_uleb128((u64) instr->data.i1, &leb_len);
+ leb = int_to_leb128((i64) instr->data.l, &leb_len);
bh_buffer_append(buff, leb, leb_len);
+ break;
+ case WI_F32_CONST:
+ leb = float_to_ieee754(instr->data.f, 0);
+ bh_buffer_append(buff, leb, 4);
+ break;
+ case WI_F64_CONST:
+ leb = double_to_ieee754(instr->data.d, 0);
+ bh_buffer_append(buff, leb, 8);
break;
- default:
- bh_buffer_write_byte(buff, (u8) instr->type);
+ default: break;
}
}