From: Brendan Hansen Date: Wed, 6 Jan 2021 05:24:49 +0000 (-0600) Subject: changed cast logic; a test case is not correct at the moment X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=adebe8a159e8331766f1cd80fab68288d9124482;p=onyx.git changed cast logic; a test case is not correct at the moment --- diff --git a/bin/onyx b/bin/onyx index ab00105d..c30ab5a1 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/core/map.onyx b/core/map.onyx index a6e6b76e..ceae9041 100644 --- a/core/map.onyx +++ b/core/map.onyx @@ -7,6 +7,9 @@ use package core.string as string Map :: struct ($K, $V) { hashes : [..] i32; entries : [..] MapEntry(K, V); + + // The value provided by `map.get`, if nothing was found. + default_value : V; } MapEntry :: struct ($K, $T) { @@ -15,10 +18,12 @@ MapEntry :: struct ($K, $T) { value : T; } -init :: proc (use map: ^Map($K, $V), hash_count: i32 = 16) { +init :: proc (use map: ^Map($K, $V), dv: V, hash_count: i32 = 16) { array.init(^hashes, hash_count); array.init(^entries, 4); + default_value = dv; + for i: 0 .. hash_count do array.push(^hashes, -1); } @@ -50,11 +55,11 @@ has :: proc (use map: ^Map($K, $V), key: K) -> bool { return lr.entry_index >= 0; } -get :: proc (use map: ^Map($K, $V), key: K, default := cast(V) 0) -> V { +get :: proc (use map: ^Map($K, $V), key: K) -> V { lr := lookup(map, key); if lr.entry_index >= 0 do return entries[lr.entry_index].value; - return default; + return default_value; } delete :: proc (use map: ^Map($K, $V), key: K) { diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index a8cdc664..90daef4e 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -930,6 +930,7 @@ void promote_numlit_to_larger(AstNumLit* num); b32 convert_numlit_to_type(AstNumLit* num, Type* type); b32 type_check_or_auto_cast(AstTyped** pnode, Type* type); Type* resolve_expression_type(AstTyped* node); +b32 cast_is_legal(Type* from_, Type* to_, char** err_msg); char* get_function_name(AstFunction* func); typedef enum PolyProcLookupMethod { diff --git a/onyx.exe b/onyx.exe index 0ea5726e..e47275a8 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyxchecker.c b/src/onyxchecker.c index ab6b8aba..707e7546 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -893,7 +893,14 @@ CheckStatus check_unaryop(AstUnaryOp** punop) { CHECK(expression, &unaryop->expr); resolve_expression_type(unaryop->expr); - if (unaryop->operation != Unary_Op_Cast) { + if (unaryop->operation == Unary_Op_Cast) { + char* err; + if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) { + onyx_report_error(unaryop->token->pos, "Cast Error: %s", err); + return Check_Error; + } + + } else { unaryop->type = unaryop->expr->type; } diff --git a/src/onyxutils.c b/src/onyxutils.c index 3edd10e1..00ccec2a 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -953,9 +953,14 @@ b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) { if (types_are_compatible(node->type, type)) return 1; if (node_is_auto_cast((AstNode *) node)) { - // HACK: Check that this cast is legal! - ((AstUnaryOp *) node)->type = type; - return 1; + char* dummy; + if (!cast_is_legal(((AstUnaryOp *) node)->expr->type, type, &dummy)) { + return 0; + + } else { + ((AstUnaryOp *) node)->type = type; + return 1; + } } else if (node->kind == Ast_Kind_NumLit) { if (convert_numlit_to_type((AstNumLit *) node, type)) return 1; @@ -983,6 +988,95 @@ Type* resolve_expression_type(AstTyped* node) { return node->type; } +static const b32 cast_legality[][11] = { + /* I8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* U8 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }, + /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, + /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 }, + /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1 }, +}; + +b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) { + Type* from = from_; + Type* to = to_; + + if (from->kind == Type_Kind_Enum) from = from->Enum.backing; + if (to->kind == Type_Kind_Enum) to = to->Enum.backing; + + if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) { + *err_msg = "Cannot cast to or from a struct."; + return 0; + } + + if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) { + *err_msg = "Cannot cast to or from a slice."; + return 0; + } + + if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) { + *err_msg = "Cannot cast to or from a dynamic array."; + return 0; + } + + if (to->kind == Type_Kind_Function) { + *err_msg = "Cannot cast to a function."; + return 0; + } + + if ( (type_is_simd(to) && !type_is_simd(from)) + || (!type_is_simd(to) && type_is_simd(from))) { + *err_msg = "Can only perform a SIMD cast between SIMD types."; + return 0; + } + + if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) { + *err_msg = "Cannot cast from void."; + return 0; + } + i32 fromidx = -1, toidx = -1; + if (from->Basic.flags & Basic_Flag_Pointer || from->kind == Type_Kind_Array) { + fromidx = 10; + } + else if (from->Basic.flags & Basic_Flag_Integer) { + b32 unsign = (from->Basic.flags & Basic_Flag_Unsigned) != 0; + + fromidx = log2_dumb(from->Basic.size) * 2 + unsign; + } + else if (from->Basic.flags & Basic_Flag_Float) { + if (from->Basic.size == 4) fromidx = 8; + else if (from->Basic.size == 8) fromidx = 9; + } + + if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) { + toidx = 10; + } + else if (to->Basic.flags & Basic_Flag_Integer) { + b32 unsign = (to->Basic.flags & Basic_Flag_Unsigned) != 0; + + toidx = log2_dumb(to->Basic.size) * 2 + unsign; + } + else if (to->Basic.flags & Basic_Flag_Float) { + if (to->Basic.size == 4) toidx = 8; + else if (to->Basic.size == 8) toidx = 9; + } + + if (fromidx != -1 && toidx != -1) { + if (!cast_legality[fromidx][toidx]) { + *err_msg = bh_aprintf(global_heap_allocator, "Cast from '%s' to '%s' is not allowed.", type_get_name(from_), type_get_name(to_)); + return 0; + } + } + + *err_msg = NULL; + return 1; +} + char* get_function_name(AstFunction* func) { if (func->name != NULL) { return bh_aprintf(global_scratch_allocator, "%b", func->name->text, func->name->length); diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 1a9ede09..fdd4b842 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -2346,56 +2346,10 @@ EMIT_FUNC(cast, AstUnaryOp* cast) { Type* from = cast->expr->type; Type* to = cast->type; - - if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) { - onyx_report_error(cast->token->pos, "Cannot cast to or from a struct."); - WI(WI_DROP); - *pcode = code; - return; - } - - if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) { - onyx_report_error(cast->token->pos, "Cannot cast to or from a slice."); - WI(WI_DROP); - *pcode = code; - return; - } - - if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) { - onyx_report_error(cast->token->pos, "Cannot cast to or from a dynamic array."); - WI(WI_DROP); - *pcode = code; - return; - } - - if (to->kind == Type_Kind_Function) { - onyx_report_error(cast->token->pos, "Cannot cast to a function."); - WI(WI_DROP); - *pcode = code; - return; - } - - if (type_is_simd(to) && !type_is_simd(from)) { - onyx_report_error(cast->token->pos, "Can only perform a SIMD cast between SIMD types."); - return; - } - - if (type_is_simd(from) && !type_is_simd(to)) { - onyx_report_error(cast->token->pos, "Can only perform a SIMD cast between SIMD types."); - return; - } - - if (type_is_simd(from) && type_is_simd(to)) { - *pcode = code; - return; - } - if (from->kind == Type_Kind_Enum) from = from->Enum.backing; if (to->kind == Type_Kind_Enum) to = to->Enum.backing; - if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) { - onyx_report_error(cast->token->pos, "Cannot cast from void."); - WI(WI_DROP); + if (type_is_simd(from) && type_is_simd(to)) { *pcode = code; return; } @@ -2435,11 +2389,9 @@ EMIT_FUNC(cast, AstUnaryOp* cast) { if (fromidx != -1 && toidx != -1) { WasmInstructionType cast_op = cast_map[fromidx][toidx]; - if (cast_op == WI_UNREACHABLE) { - bh_printf("%d %d\n", fromidx, toidx); - onyx_report_error(cast->token->pos, "Bad cast."); - } - else if (cast_op != WI_NOP) { + assert(cast_op != WI_UNREACHABLE); + + if (cast_op != WI_NOP) { WI(cast_op); } } diff --git a/tests/aoc-2020/day14.onyx b/tests/aoc-2020/day14.onyx index 4e1651c1..9d23a103 100644 --- a/tests/aoc-2020/day14.onyx +++ b/tests/aoc-2020/day14.onyx @@ -71,6 +71,7 @@ bitmask_iter_next :: proc (use bmi: ^BitmaskIter) -> u64 { done = true; } + printf("val is %l\n", val); return val; } @@ -80,7 +81,7 @@ main :: proc (args: [] cstr) { file := reader.make(contents); mem : map.Map(u64, u64); - map.init(^mem, 257); + map.init(^mem, 0, 257); defer map.free(^mem); mask : Bitmask; diff --git a/tests/aoc-2020/day15.onyx b/tests/aoc-2020/day15.onyx index 2cc74023..804e1e9f 100644 --- a/tests/aoc-2020/day15.onyx +++ b/tests/aoc-2020/day15.onyx @@ -15,7 +15,7 @@ main :: proc (args: [] cstr) { // Any changes to the implementation of Map should be tested on this // file to validate if they 1) work and 2) are faster. nums : map.Map(u32, spoken_times); - map.init(^nums, 32767); + map.init(^nums, spoken_times.{}, 32767); defer map.free(^nums); turn := 1; @@ -28,12 +28,12 @@ main :: proc (args: [] cstr) { } while turn != 2021 { - st := map.get(^nums, last_num, spoken_times.{}); + st := map.get(^nums, last_num); if st.previous == 0 do last_num = 0; else do last_num = st.recent - st.previous; - st = map.get(^nums, last_num, spoken_times.{}); + st = map.get(^nums, last_num); st.previous = st.recent; st.recent = turn; map.put(^nums, last_num, st); diff --git a/tests/aoc-2020/day17.onyx b/tests/aoc-2020/day17.onyx index 61cee9b4..4cc8f304 100644 --- a/tests/aoc-2020/day17.onyx +++ b/tests/aoc-2020/day17.onyx @@ -32,7 +32,7 @@ get_neighbor_count :: proc (cubes: ^map.Map(CubePos, CubeState), pos: CubePos) - for x: -1 .. 2 do for y: -1 .. 2 do for z: -1 .. 2 do for w: -1 .. 2 { if x == 0 && y == 0 && z == 0 && w == 0 do continue; key := CubePos.{ pos.x + x, pos.y + y, pos.z + z, pos.w + w }; - state := map.get(cubes, key, CubeState.{}); + state := map.get(cubes, key); if state.alive do count += 1; } @@ -45,7 +45,7 @@ main :: proc (args: [] cstr) { file := reader.make(contents); cubes : map.Map(CubePos, CubeState); - map.init(^cubes, 1021); + map.init(^cubes, CubeState.{}, 1021); defer map.free(^cubes); z := 0; @@ -81,7 +81,7 @@ main :: proc (args: [] cstr) { } for ^cube: cubes_to_consider { - state := map.get(^cubes, *cube, CubeState.{}); + state := map.get(^cubes, *cube); ncount := get_neighbor_count(^cubes, *cube); if state.alive { @@ -94,7 +94,7 @@ main :: proc (args: [] cstr) { } for ^cube: cubes_to_consider { - state := map.get(^cubes, *cube, CubeState.{}); + state := map.get(^cubes, *cube); state.alive = state.next; map.put(^cubes, *cube, state); } diff --git a/tests/aoc-2020/day20.onyx b/tests/aoc-2020/day20.onyx index 988e5a81..b4fca178 100644 --- a/tests/aoc-2020/day20.onyx +++ b/tests/aoc-2020/day20.onyx @@ -257,7 +257,7 @@ main :: proc (args: [] cstr) { defer array.free(^tiles); tile_map : map.Map(u32, ^Tile); - map.init(^tile_map, 67); + map.init(^tile_map, null, 67); defer map.free(^tile_map); tile_data := calloc(200 * sizeof TileData); diff --git a/tests/aoc-2020/day21.onyx b/tests/aoc-2020/day21.onyx index d092ab98..dfe862c8 100644 --- a/tests/aoc-2020/day21.onyx +++ b/tests/aoc-2020/day21.onyx @@ -36,8 +36,8 @@ main :: proc (args: [] cstr) { file := reader.make(contents); - map.init(^ingredient_map, 127); - map.init(^allergen_map); + map.init(^ingredient_map, Ingredient.{}, 127); + map.init(^allergen_map, Allergen.{}); defer { map.free(^ingredient_map); map.free(^allergen_map); @@ -59,7 +59,7 @@ main :: proc (args: [] cstr) { array.push(^food.ingredients, ingredient_name); - ingredient := map.get(^ingredient_map, ingredient_name, Ingredient.{}); + ingredient := map.get(^ingredient_map, ingredient_name); if ingredient.name.data == null { ingredient.name = ingredient_name; array.init(^ingredient.appears_on, 4); @@ -78,7 +78,7 @@ main :: proc (args: [] cstr) { array.push(^food.allergens, allergen_name); - allergen := map.get(^allergen_map, allergen_name, Allergen.{}); + allergen := map.get(^allergen_map, allergen_name); if allergen.name.data == null { allergen.name = allergen_name; array.init(^allergen.appears_on, 4); @@ -113,7 +113,7 @@ main :: proc (args: [] cstr) { potential_allergen_count := 0; for ^allergen_name: potential_allergens { c := array_count_contains(^potential_allergens, *allergen_name, string.equal); - allergen := map.get(^allergen_map, *allergen_name, Allergen.{}); + allergen := map.get(^allergen_map, *allergen_name); if c == allergen.appears_on.count { potential_allergen_count += 1; } @@ -126,7 +126,7 @@ main :: proc (args: [] cstr) { total_safe := 0; for safe: definitely_safe { - ingredient := map.get(^ingredient_map, safe, Ingredient.{}); + ingredient := map.get(^ingredient_map, safe); total_safe += ingredient.appears_on.count; map.delete(^ingredient_map, safe); @@ -157,7 +157,7 @@ main :: proc (args: [] cstr) { } if match_count == 1 { - ingredient := map.get(^ingredient_map, matching_ingredient_name, Ingredient.{}); + ingredient := map.get(^ingredient_map, matching_ingredient_name); map.delete(^ingredient_map, matching_ingredient_name); ingredient.allergen = allergen_entry.key; diff --git a/tests/aoc-2020/day22.onyx b/tests/aoc-2020/day22.onyx index c4c1622b..7786c40c 100644 --- a/tests/aoc-2020/day22.onyx +++ b/tests/aoc-2020/day22.onyx @@ -61,7 +61,7 @@ encode_hands :: proc (alloc: Allocator, p1: ^[..] u32, p2: ^[..] u32) -> str { recursive_combat :: proc (player1: ^[..] u32, player2: ^[..] u32) -> u32 { hand_seen : map.Map(str, bool); - map.init(^hand_seen, 31); + map.init(^hand_seen, false, 31); defer map.free(^hand_seen); while player1.count > 0 && player2.count > 0 { diff --git a/tests/aoc-2020/day24.onyx b/tests/aoc-2020/day24.onyx index 61b6320f..7d9cb5cd 100644 --- a/tests/aoc-2020/day24.onyx +++ b/tests/aoc-2020/day24.onyx @@ -33,7 +33,7 @@ main :: proc (args: [] cstr) { file := reader.make(contents); grid : map.Map(Vec2, Cell); // `true` is black - map.init(^grid, 1021); + map.init(^grid, Cell.{}, 1021); defer map.free(^grid); while !reader.empty(^file) { @@ -67,7 +67,7 @@ main :: proc (args: [] cstr) { } - curr := map.get(^grid, loc, Cell.{}); + curr := map.get(^grid, loc); map.put(^grid, loc, Cell.{ alive = !curr.alive }); } @@ -98,7 +98,7 @@ main :: proc (args: [] cstr) { } for ^cell: cells_to_consider { - state := map.get(^grid, *cell, Cell.{}); + state := map.get(^grid, *cell); ncount := get_neighbor_count(^grid, *cell); if state.alive { @@ -128,7 +128,7 @@ get_neighbor_count :: proc (grid: ^map.Map(Vec2, Cell), pos: Vec2) -> u32 { count := 0; for ^dir: Hex_Directions { - cell := map.get(grid, Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y }, Cell.{}); + cell := map.get(grid, Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y }); if cell.alive do count += 1; } diff --git a/tests/aoc-2020/day25.onyx b/tests/aoc-2020/day25.onyx index 09d89941..2f20fc22 100644 --- a/tests/aoc-2020/day25.onyx +++ b/tests/aoc-2020/day25.onyx @@ -25,7 +25,7 @@ dlp_bsgs :: proc (n: u32, a: u32, b: u32) -> u32 { m := cast(u32) ceil_f64(sqrt_f64(~~n)); t : map.Map(u32, u32); - map.init(^t, m / 2); + map.init(^t, 0, m / 2); defer map.free(^t); tmp: u64 = 1; @@ -39,7 +39,7 @@ dlp_bsgs :: proc (n: u32, a: u32, b: u32) -> u32 { tmp = ~~b; for i: 0 .. m { if map.has(^t, cast(u32) tmp) { - v := map.get(^t, cast(u32) tmp, 0); + v := map.get(^t, cast(u32) tmp); return i * m + v; } diff --git a/tests/aoc-2020/day7.onyx b/tests/aoc-2020/day7.onyx index 08dceae3..3282b976 100644 --- a/tests/aoc-2020/day7.onyx +++ b/tests/aoc-2020/day7.onyx @@ -24,7 +24,7 @@ BagContainment :: struct { bg_init :: proc (use graph: ^BagGraph) { array.init(^nodes, 16); - map.init(^node_map); + map.init(^node_map, null); } bg_free :: proc (use graph: ^BagGraph) { diff --git a/tests/aoc-2020/day8.onyx b/tests/aoc-2020/day8.onyx index e197fa7c..6a0a3f93 100644 --- a/tests/aoc-2020/day8.onyx +++ b/tests/aoc-2020/day8.onyx @@ -15,7 +15,7 @@ Instruction :: struct { // Returns if the program successfully exited. get_acc_value :: proc (instrs: [..] Instruction, ret_acc: ^i32) -> bool { already_been: map.Map(i32, bool); - map.init(^already_been); + map.init(^already_been, false); defer map.free(^already_been); ip := 0; diff --git a/tests/general1.onyx b/tests/general1.onyx index d5d870e1..8e25d1f8 100644 --- a/tests/general1.onyx +++ b/tests/general1.onyx @@ -234,7 +234,7 @@ main :: proc (args: [] cstr) { print("\n"); pmap : map.Map(rawptr, rawptr); - map.init(^pmap, 50); + map.init(^pmap, null, 50); defer map.free(^pmap); for i: 0 .. 100 do map.put(^pmap, ^s.a[i], ^s.b[i]); diff --git a/tests/i32map.onyx b/tests/i32map.onyx index d8cf721f..d43a198f 100644 --- a/tests/i32map.onyx +++ b/tests/i32map.onyx @@ -6,7 +6,7 @@ use package core main :: proc (args: [] cstr) { imap : map.Map(i32, str); - map.init(^imap); + map.init(^imap, ""); defer { print("Freeing map\n"); map.free(^imap); @@ -17,7 +17,7 @@ main :: proc (args: [] cstr) { println(map.has(^imap, 50)); println(map.has(^imap, 51)); - printf("%s%s\n", map.get(^imap, 50, ""), map.get(^imap, 1234, "")); + printf("%s%s\n", map.get(^imap, 50), map.get(^imap, 1234)); map.delete(^imap, 50); println(map.has(^imap, 50)); diff --git a/tests/overload_with_autocast.onyx b/tests/overload_with_autocast.onyx index 9c427e59..9048be22 100644 --- a/tests/overload_with_autocast.onyx +++ b/tests/overload_with_autocast.onyx @@ -3,6 +3,7 @@ use package core overloaded :: proc { + proc (x: str, y: i32) do println("Called str, i32"); , proc (x: f32, y: str) do println("Called f32, str"); , proc (x: i32, y: i32) do println("Called i32, i32"); , }