From: Brendan Hansen Date: Thu, 18 Jun 2020 20:13:24 +0000 (-0500) Subject: Added numeric literals and changes to bh_imap X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=3a6002b5b7efd05e637bd0c7ac45ea910cd458fc;p=onyx.git Added numeric literals and changes to bh_imap --- diff --git a/docs/plan b/docs/plan index b297a650..66c9d3f8 100644 --- a/docs/plan +++ b/docs/plan @@ -53,8 +53,8 @@ HOW: 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 @@ -75,6 +75,8 @@ HOW: 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). diff --git a/include/bh.h b/include/bh.h index 687b51ab..38b7fa11 100644 --- a/include/bh.h +++ b/include/bh.h @@ -112,8 +112,8 @@ inline i64 chars_match(char* ptr1, char* ptr2) { // 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); @@ -625,24 +625,25 @@ b32 bh_table_iter_next(bh_table_iterator* it); //------------------------------------------------------------------------------- #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 @@ -983,30 +984,48 @@ u8* int_to_leb128(i64 n, i32* output_length) { // 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; } @@ -1920,25 +1939,25 @@ step_to_next: #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; @@ -1955,43 +1974,48 @@ b32 bh__imap_get_index(bh_imap* imap, bh_imap_key_t key, i32* pos) { 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 diff --git a/include/onyxlex.h b/include/onyxlex.h index 366465ab..97754648 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -65,7 +65,7 @@ typedef struct OnyxFilePos { typedef struct OnyxToken { OnyxTokenType type; - isize length; + i32 length; char* token; OnyxFilePos pos; } OnyxToken; diff --git a/include/onyxparser.h b/include/onyxparser.h index 47786d40..80690f2f 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -7,6 +7,7 @@ #include "onyxmsgs.h" typedef union OnyxAstNode OnyxAstNode; +typedef struct OnyxAstNodeNumLit OnyxAstNodeNumLit; typedef struct OnyxAstNodeLocal OnyxAstNodeLocal; typedef struct OnyxAstNodeScope OnyxAstNodeScope; typedef struct OnyxAstNodeBlock OnyxAstNodeBlock; @@ -111,6 +112,16 @@ typedef enum OnyxAstFlags { 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; @@ -193,6 +204,7 @@ union OnyxAstNode { OnyxAstNodeLocal as_local; OnyxAstNodeScope as_scope; OnyxAstNodeCall as_call; + OnyxAstNodeNumLit as_numlit; }; const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind); diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 52e0c74a..c8482ada 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -264,8 +264,8 @@ typedef struct WasmExport { 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 ) diff --git a/onyx b/onyx index cbaebf60..944178d4 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/minimal.onyx b/progs/minimal.onyx index e19b7ed2..8b153fc7 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -14,12 +14,12 @@ diff_square :: proc (a i32, b 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(); } diff --git a/src/onyxlex.c b/src/onyxlex.c index 9e9a0104..d0069690 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -223,6 +223,11 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) { INCREMENT_CURR_TOKEN(tokenizer); } + if (*(tokenizer->curr + 1) == 'f') { + len++; + INCREMENT_CURR_TOKEN(tokenizer); + } + tk.type = TOKEN_TYPE_LITERAL_NUMERIC; tk.length = len; } diff --git a/src/onyxparser.c b/src/onyxparser.c index b2fa3684..0c5d5dae 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -70,6 +70,7 @@ static OnyxAstNodeScope* enter_scope(OnyxParser* parser); 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); @@ -190,6 +191,43 @@ static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident) { 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: @@ -254,14 +292,7 @@ static OnyxAstNode* parse_factor(OnyxParser* parser) { 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, @@ -585,6 +616,9 @@ static OnyxTypeInfo* parse_type(OnyxParser* parser) { } 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) { diff --git a/src/onyxutils.c b/src/onyxutils.c index 74aecf9d..055932fd 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -97,7 +97,7 @@ void onyx_ast_print(OnyxAstNode* node, i32 indent) { } 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); } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index e30fae20..4d768fba 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -248,9 +248,7 @@ static void process_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* 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 { @@ -338,9 +336,7 @@ static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* 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; @@ -349,10 +345,25 @@ static void process_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* 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; } @@ -500,9 +511,7 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* // 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 }; @@ -513,9 +522,7 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* 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)++; } @@ -530,7 +537,7 @@ static void process_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef* 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) { @@ -551,10 +558,10 @@ OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* progra 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; @@ -575,7 +582,8 @@ OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* progra 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); } @@ -789,34 +797,40 @@ static i32 output_locals(WasmFunc* func, bh_buffer* buff) { 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; } }