From: Brendan Hansen Date: Fri, 30 Sep 2022 02:20:08 +0000 (-0500) Subject: aoc-2021 day 18; experimented with "trait interfaces" X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=a03a82fd89b51c4339e9cdb9bf83af76442e3049;p=onyx.git aoc-2021 day 18; experimented with "trait interfaces" --- diff --git a/compiler/src/checker.c b/compiler/src/checker.c index ba04efe9..67b88746 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -781,10 +781,12 @@ static void report_bad_binaryop(AstBinaryOp* binop) { static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop, AstTyped* third_argument) { if (bh_arr_length(operator_overloads[binop->operation]) == 0) return NULL; - if (binop->overload_args == NULL) { - binop->overload_args = bh_alloc_item(context.ast_alloc, Arguments); - bh_arr_new(context.ast_alloc, binop->overload_args->values, 3); - bh_arr_set_length(binop->overload_args->values, third_argument ? 3 : 2); + if (binop->overload_args == NULL || binop->overload_args->values[1] == NULL) { + if (binop->overload_args == NULL) { + binop->overload_args = bh_alloc_item(context.ast_alloc, Arguments); + bh_arr_new(context.ast_alloc, binop->overload_args->values, 3); + bh_arr_set_length(binop->overload_args->values, third_argument ? 3 : 2); + } if (binop_is_assignment(binop->operation)) { binop->overload_args->values[0] = (AstTyped *) make_address_of(context.ast_alloc, binop->left); diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 78ba5cc2..54a14cf4 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -357,7 +357,7 @@ static SymresStatus symres_field_access(AstFieldAccess** fa) { } } else if (force_a_lookup) { - if (context.cycle_detected) { + if (context.cycle_detected || context.cycle_almost_detected) { onyx_report_error((*fa)->token->pos, Error_Critical, "'%b' does not exist here. This is a bad error message.", (*fa)->token->text, (*fa)->token->length); @@ -1565,14 +1565,46 @@ static SymresStatus symres_constraint(AstConstraint* constraint) { } case Constraint_Phase_Checking_Expressions: { + SymresStatus ss; + onyx_errors_disable(); + fori (i, constraint->expr_idx, bh_arr_length(constraint->exprs)) { - SYMRES(expression, &constraint->exprs[i].expr); + InterfaceConstraint* ic = &constraint->exprs[i]; + + // Most of this logic was directly copied from the + // check_constraint code. There might be a better + // way to factor this? + ss = symres_expression(&ic->expr); + if (ss == Symres_Yield_Macro) { + onyx_errors_enable(); + return ss; + } + + if (ss == Symres_Error && !ic->invert_condition) { + goto constraint_error; + } + + if (ss == Symres_Success && ic->invert_condition) { + goto constraint_error; + } - if (constraint->exprs[i].expected_type_expr) { - SYMRES(type, &constraint->exprs[i].expected_type_expr); + if (ic->expected_type_expr) { + ss = symres_type(&ic->expected_type_expr); + if (ss == Symres_Yield_Macro) { + onyx_errors_enable(); + return ss; + } } + + continue; + + constraint_error: + onyx_errors_enable(); + *constraint->report_status = Constraint_Check_Status_Failed; + return Symres_Error; } + onyx_errors_enable(); return Symres_Success; } } @@ -1762,6 +1794,7 @@ void symres_entity(Entity* ent) { if (ss == Symres_Yield_Micro) ent->micro_attempts++; if (ss == Symres_Complete) ent->state = Entity_State_Finalized; if (ss == Symres_Goto_Parse) ent->state = Entity_State_Parse; + if (ss == Symres_Error) ent->state = Entity_State_Failed; if (ss == Symres_Success) { ent->macro_attempts = 0; ent->micro_attempts = 0; diff --git a/core/conv.onyx b/core/conv.onyx index 8a8d0c01..4470c7e6 100644 --- a/core/conv.onyx +++ b/core/conv.onyx @@ -54,61 +54,82 @@ Custom_Parse :: struct { parse: (rawptr, str, Allocator) -> bool; } -str_to_i64 :: (s: str, base: u32 = 10) -> i64 { +str_to_i64 :: #match #local {} + +#overload +str_to_i64 :: macro (s: str, base: u32 = 10) -> i64 { + str_to_i64 :: str_to_i64; + s_ := s; + return str_to_i64(^s_, base); +} + +#overload +str_to_i64 :: (s: ^str, base: u32 = 10) -> i64 { use package core value: i64 = 0; mul := 1; - if s[0] == #char "-" { + if s.data[0] == #char "-" { mul = -1; - s = string.advance(s, 1); + string.advance(s, 1); } - if s[0] == #char "+" { - s = string.advance(s, 1); + if s.data[0] == #char "+" { + string.advance(s, 1); } - for c: s do switch c { - case #char "0" .. #char "9" { - value *= ~~base; - value += ~~(c - #char "0"); - } + while !string.empty(*s) { + switch c := s.data[0]; c { + case #char "0" .. #char "9" { + value *= ~~base; + value += ~~(c - #char "0"); + } - case #char "A" .. #char "Z" { - if base <= 10 do fallthrough; + case #char "A" .. #char "Z" { + if base <= 10 do fallthrough; - value *= ~~base; - value += ~~((c - #char "A") + 10); - } - - case #char "a" .. #char "z" { - if base <= 10 do fallthrough; + value *= ~~base; + value += ~~((c - #char "A") + 10); + } + + case #char "a" .. #char "z" { + if base <= 10 do fallthrough; + + value *= ~~base; + value += ~~((c - #char "a") + 10); + } - value *= ~~base; - value += ~~((c - #char "a") + 10); + case #default do break break; } - case #default do break break; + string.advance(s); } return value * ~~mul; } -str_to_f64 :: (s_: str) -> f64 { +str_to_f64 :: #match #local {} + +#overload +str_to_f64 :: macro (s: str) -> f64 { + str_to_f64 :: str_to_f64; + s_ := s; + return str_to_f64(^s_); +} + +#overload +str_to_f64 :: (s: ^str) -> f64 { use package core - // 's' needs to live on the stack to take its address. Stupid optimization - // that simple structs turn into registers for parameters. - s := s_; - string.strip_leading_whitespace(^s); + string.strip_leading_whitespace(s); - sign := parse_sign(^s); - value, _ := parse_digits(^s); + sign := parse_sign(s); + value, _ := parse_digits(s); - if s[0] == #char "." { - string.advance(^s, 1); - fraction, fraction_digits := parse_digits(^s); + if s.data[0] == #char "." { + string.advance(s, 1); + fraction, fraction_digits := parse_digits(s); while fraction_digits > 0 { fraction_digits -= 1; fraction /= 10; @@ -118,11 +139,11 @@ str_to_f64 :: (s_: str) -> f64 { value *= sign; - if s[0] != #char "e" && s[0] != #char "E" do return value; - string.advance(^s, 1); + if s.data[0] != #char "e" && s.data[0] != #char "E" do return value; + string.advance(s, 1); - exponent_sign := parse_sign(^s); - exponent, _ := parse_digits(^s); + exponent_sign := parse_sign(s); + exponent, _ := parse_digits(s); if exponent_sign > 0 { while exponent > 0 { value *= 10; diff --git a/core/hash.onyx b/core/hash.onyx index baa67125..fa4a30dc 100644 --- a/core/hash.onyx +++ b/core/hash.onyx @@ -11,9 +11,16 @@ to_u32 :: #match { for ch: key do hash += (hash << 5) + ~~ch; return hash; }, - (key: type_expr) -> u32 do return to_u32(cast(u32) key); + (key: type_expr) -> u32 { return to_u32(cast(u32) key); }, + + #precedence 10000 macro (key: $T/HasHashMethod) => key->hash() } Hashable :: interface (t: $T) { { to_u32(t) } -> u32; } + +HasHashMethod :: interface (t: $T) { + { t->hash() } -> u32; +} + diff --git a/tests/aoc-2020/day17.onyx b/tests/aoc-2020/day17.onyx index af534ca8..916bb576 100644 --- a/tests/aoc-2020/day17.onyx +++ b/tests/aoc-2020/day17.onyx @@ -1,26 +1,41 @@ #load "core/std" -use package core -reader :: package core.string.reader +use core +use core.string {reader} + +OverloadsEqual :: interface (t: $T) { + { T.equals(t, t) } -> bool; +} + +#operator == macro (t: $T/OverloadsEqual, s: T) => t->equals(s); + CubePos :: struct { x, y, z, w : i32; } -CubeState :: struct { - alive := false; - next := false; -} +#inject CubePos { + hash :: (c: CubePos) => { + hash: u32 = 7; + hash += hash << 5 + core.hash.to_u32(c.x); + hash += hash << 5 + core.hash.to_u32(c.y); + hash += hash << 5 + core.hash.to_u32(c.z); + hash += hash << 5 + core.hash.to_u32(c.w); + return hash; + } -#match hash.to_u32 (c: CubePos) -> u32 { - return 17 * c.x + 13 * c.y + 11 * c.z + 21 * c.w; + equals :: (a, b: CubePos) => { + return (a.x == b.x) + && (a.y == b.y) + && (a.z == b.z) + && (a.w == b.w); + } } -#operator == (a: CubePos, b: CubePos) -> bool { - return (a.x == b.x) - && (a.y == b.y) - && (a.z == b.z) - && (a.w == b.w); + +CubeState :: struct { + alive := false; + next := false; } get_neighbor_count :: (cubes: ^Map(CubePos, CubeState), pos: CubePos) -> u32 { diff --git a/tests/aoc-2021/day18 b/tests/aoc-2021/day18 new file mode 100644 index 00000000..48106eec --- /dev/null +++ b/tests/aoc-2021/day18 @@ -0,0 +1,3 @@ +4864 +i: [[[[2,9],6],[[2,8],9]],[[[0,5],6],[[6,1],7]]] +j: [[[[9,6],[5,8]],[6,2]],[[[8,0],[7,0]],[[5,6],4]]] diff --git a/tests/aoc-2021/day18.onyx b/tests/aoc-2021/day18.onyx new file mode 100644 index 00000000..09f08a02 --- /dev/null +++ b/tests/aoc-2021/day18.onyx @@ -0,0 +1,273 @@ +#load "core/std" + +PART :: 2 + +use core +use core.alloc {arena} + +num_allocator: Allocator; + +SnailNum :: struct { + parent: ^SnailNum; + left, right: ^SnailNum; + + left_val, right_val: u32; +} + + +#inject SnailNum { + allocator: Allocator; + + make :: () => { + return make(SnailNum, SnailNum.allocator); + } + + make_pair :: (left, right: u32) => { + n := SnailNum.make(); + n.left_val = left; + n.right_val = right; + return n; + } + + clone :: (n: ^SnailNum) -> ^SnailNum { + if n == null do return null; + + new_num := SnailNum.make(); + new_num->set_left(SnailNum.clone(n.left)); + new_num->set_right(SnailNum.clone(n.right)); + new_num.left_val = n.left_val; + new_num.right_val = n.right_val; + + return new_num; + } + + add :: (a, b: ^SnailNum) => { + if a == null do return b; + if b == null do return a; + + new_root := SnailNum.make(); + new_root->set_left(a); + new_root->set_right(b); + + while new_root->reduce() --- + + return new_root; + } + + reduce :: (use n: ^SnailNum) -> (reduced_something: bool) { + if r, _ := n->reduce_explodes(); r do return true; + if r := n->reduce_splits(); r do return true; + return false; + } + + reduce_explodes :: (use n: ^SnailNum, depth := 0) -> (reduced_something: bool, zero_node: bool) { + if depth <= 3 { + did_reduce, zero_node := false, false; + + if left != null { + if did_reduce, zero_node = left->reduce_explodes(depth + 1); zero_node { + left = null; + } + } + + if right != null && !did_reduce { + if did_reduce, zero_node = right->reduce_explodes(depth + 1); zero_node { + right = null; + } + } + + return did_reduce, false; + } + + pleft := n->pair_to_left(); + pright := n->pair_to_right(); + if pleft != null do *pleft += left_val; + if pright != null do *pright += right_val; + + left_val = 0; + right_val = 0; + + return true, true; + } + + reduce_splits :: (use n: ^SnailNum) -> (reduced_something: bool) { + if left != null { + if left->reduce_splits() { + return true; + } + + } elseif left_val >= 10 { + l1, l2 := split_number(left_val); + n->set_left(SnailNum.make_pair(l1, l2)); + left_val = 0; + return true; + } + + if right != null { + if right->reduce_splits() { + return true; + } + + } elseif right_val >= 10 { + r1, r2 := split_number(right_val); + n->set_right(SnailNum.make_pair(r1, r2)); + right_val = 0; + return true; + } + + return false; + + split_number :: (n: u32) -> (u32, u32) { + h := n / 2; + return h, h + (0 if n % 2 == 0 else 1); + } + } + + set_left :: (parent, new_left: ^SnailNum) { + parent.left_val = 0; + parent.left = new_left; + if new_left != null do new_left.parent = parent; + } + + set_right :: (parent, new_right: ^SnailNum) { + parent.right_val = 0; + parent.right = new_right; + if new_right != null do new_right.parent = parent; + } + + pair_to_left :: (n: ^SnailNum) -> ^u32 { + while n.parent != null && n.parent.left == n { + n = n.parent; + } + + if n.parent == null do return null; + + if n.parent.left == null do return ^n.parent.left_val; + + n = n.parent.left; + + while n.right != null { + n = n.right; + } + + return ^n.right_val; + } + + pair_to_right :: (n: ^SnailNum) -> ^u32 { + while n.parent != null && n.parent.right == n { + n = n.parent; + } + + if n.parent == null do return null; + + if n.parent.right == null do return ^n.parent.right_val; + + n = n.parent.right; + + while n.left != null { + n = n.left; + } + + return ^n.left_val; + } + + magnitude :: (use n: ^SnailNum) => { + if n == null { + return 0; + } + + return 3 * (left_val + left->magnitude()) + + 2 * (right_val + right->magnitude()); + } + + parse :: (line: ^str) -> ^SnailNum { + string.advance(line); // [ + + root := SnailNum.make(); + if line.data[0] == #char "[" { + root->set_left(SnailNum.parse(line)); + } else { + root.left_val = ~~ conv.str_to_i64(line); + } + + string.advance(line); // , + + if line.data[0] == #char "[" { + root->set_right(SnailNum.parse(line)); + } else { + root.right_val = ~~ conv.str_to_i64(line); + } + + string.advance(line); // ] + + return root; + } + + format :: (output: ^conv.Format_Output, s: ^conv.Format, use n: ^SnailNum) { + if left == null && right == null { + conv.format(output, "[{},{}]", left_val, right_val); + } + elseif left == null && right != null { + conv.format(output, "[{},{*}]", left_val, right); + } + elseif left != null && right == null { + conv.format(output, "[{*},{}]", left, right_val); + } + elseif left != null && right != null { + conv.format(output, "[{*},{*}]", left, right); + } + } +} + + + +main :: () { + num_arena := arena.make(context.allocator, 64 * 1024); + SnailNum.allocator = alloc.as_allocator(^num_arena); + + conv.register_custom_formatter(SnailNum.format); + + for file: os.with_file("./tests/aoc-2021/input/day18.txt") { + r := io.reader_make(file); + + #if PART == 1 { + s: ^SnailNum = null; + + for line: r->lines() { + n := SnailNum.parse(^line); + s = s->add(n); + } + + printf("{*}\n", s->magnitude()); + } + + #if PART == 2 { + nums := make([..] ^SnailNum); + for line: r->lines() { + nums << SnailNum.parse(^line); + } + + maximum := 0; + max_i, max_j : i32; + + for i: nums.count { + for j: nums.count { + if i == j do continue; + + n1 := nums[i]->clone(); + n2 := nums[j]->clone(); + + mag := n1->add(n2)->magnitude(); + if mag >= maximum { + maximum = mag; + max_i, max_j = i, j; + } + } + } + + println(maximum); + printf("i: {*}\n", nums[max_i]); + printf("j: {*}\n", nums[max_j]); + } + } +} diff --git a/tests/aoc-2021/input/day18.txt b/tests/aoc-2021/input/day18.txt new file mode 100644 index 00000000..9b65fac7 --- /dev/null +++ b/tests/aoc-2021/input/day18.txt @@ -0,0 +1,100 @@ +[[[[7,1],[0,0]],[6,[8,2]]],[8,[3,8]]] +[[[3,6],[9,4]],[[[5,9],5],[8,0]]] +[[[2,2],2],[1,[[1,6],7]]] +[[[[0,9],7],[[3,2],8]],[6,[7,9]]] +[[[[4,1],6],[[7,6],[2,2]]],[[[1,1],9],4]] +[[[8,[3,7]],3],[[4,4],[[9,1],[3,5]]]] +[[4,[8,2]],[1,[0,5]]] +[8,[8,7]] +[[[[2,2],7],[3,[4,5]]],[[4,6],[[2,5],4]]] +[[[5,5],[[5,1],3]],[[2,[8,2]],[[6,9],[1,5]]]] +[0,7] +[[[[5,1],3],[8,[5,3]]],7] +[[5,[2,[0,6]]],[[[5,5],2],[9,[8,0]]]] +[[[[3,4],2],0],4] +[[[[5,3],[2,7]],6],[[4,0],[9,[7,2]]]] +[[[3,[2,5]],[3,3]],7] +[[[[5,1],1],[4,8]],[[5,[8,3]],2]] +[[4,[[8,1],[8,5]]],[[[4,1],0],6]] +[[[5,5],[5,9]],[0,[[6,8],[0,1]]]] +[4,[[[7,9],4],0]] +[[[[0,1],7],[[3,6],5]],[8,[5,[6,1]]]] +[[[7,7],[8,0]],[6,[8,[7,9]]]] +[[[9,2],1],6] +[[[4,4],[2,[5,0]]],[[[2,6],6],[5,[4,3]]]] +[[2,[[4,7],5]],1] +[[8,7],[[[2,0],7],[1,[0,3]]]] +[[9,[[9,3],[9,5]]],[[8,7],[[4,1],[6,5]]]] +[[3,4],[[9,4],5]] +[[5,[[8,3],5]],1] +[[0,[[9,0],[3,2]]],[2,[7,[5,1]]]] +[[9,[[9,5],[8,6]]],[[4,4],[[3,8],[1,6]]]] +[[[1,[5,2]],9],[[4,6],[3,[8,0]]]] +[[1,7],[[1,7],9]] +[[[[3,4],3],[[7,5],[9,1]]],[[[5,0],[3,0]],[[7,9],6]]] +[[[7,2],[[1,0],[5,6]]],[[[3,7],[8,9]],6]] +[[[[1,1],1],[[8,6],[9,8]]],[[[1,8],4],[8,9]]] +[[[8,9],0],3] +[[[1,7],[1,[3,9]]],[6,[0,[8,5]]]] +[[0,5],[6,5]] +[[[[6,8],[4,5]],[[7,4],6]],[[3,6],5]] +[[8,[[0,9],8]],[9,[7,[7,9]]]] +[0,[[[7,1],2],[[0,4],4]]] +[[0,[[9,1],5]],[1,4]] +[3,4] +[[[9,3],[1,3]],[[[4,8],3],[[1,3],[9,0]]]] +[[[[5,1],7],[[9,2],8]],[[[6,8],[5,4]],[0,1]]] +[8,[[1,[3,0]],[[7,9],4]]] +[[[6,4],[[2,9],[9,0]]],[7,[[0,0],3]]] +[[3,[[9,6],6]],2] +[[5,[[3,1],[7,5]]],[[[6,7],9],[[4,6],[5,2]]]] +[[[4,[6,5]],8],[[6,[8,0]],[[9,3],3]]] +[[[[4,9],[2,8]],9],[[[5,0],0],[[3,4],[2,8]]]] +[[3,[7,1]],[9,[[1,8],7]]] +[[9,1],[0,[[0,7],[7,1]]]] +[[7,[0,[7,6]]],[[[5,3],1],[6,[4,5]]]] +[8,[[[2,1],[6,9]],[[3,3],[4,6]]]] +[0,[7,[3,0]]] +[[[[1,6],3],[5,[8,0]]],[[[6,6],7],1]] +[[[7,[8,3]],3],[[[2,8],5],[0,[9,5]]]] +[[[[5,1],4],[[1,2],1]],7] +[[[3,[7,5]],7],3] +[[9,[6,[1,1]]],[[[4,1],[2,2]],[[9,5],[7,7]]]] +[2,7] +[[[9,[8,6]],[[9,0],[6,5]]],[[[6,7],5],[[7,7],[2,3]]]] +[[[0,[6,4]],2],[4,[7,[7,5]]]] +[[[[6,1],[9,1]],[[6,1],9]],[[2,6],0]] +[[0,[[1,8],[3,5]]],[4,[[8,2],[4,2]]]] +[[[[9,3],[4,2]],2],[[[2,1],[7,1]],[4,8]]] +[[[3,[0,2]],3],8] +[[[4,[4,9]],9],[[[4,4],5],9]] +[[[[8,2],7],9],[[[1,0],[3,8]],[[7,7],0]]] +[[[3,2],[9,7]],[[9,[8,2]],[[5,5],3]]] +[[[7,[3,1]],[[8,3],1]],[[[8,6],[7,0]],4]] +[[9,[[9,1],5]],[[4,[1,1]],2]] +[[[[7,4],[0,3]],7],[8,[6,[3,3]]]] +[5,5] +[[6,7],[1,[7,[8,1]]]] +[[1,[0,4]],7] +[[[4,0],[[0,1],[2,2]]],[9,[[9,9],[3,0]]]] +[[[6,0],[[8,6],3]],[[5,1],[[8,1],[2,7]]]] +[[[[8,3],7],5],[9,[[5,1],8]]] +[[[[4,0],[5,2]],[[0,0],7]],2] +[[[[0,1],6],2],[[8,2],6]] +[[[[2,4],1],[[6,7],9]],[[[1,6],9],3]] +[[5,5],[[8,[7,7]],[5,8]]] +[[6,[[9,2],[9,7]]],[[[8,5],[4,4]],7]] +[[[9,[7,7]],[6,0]],[7,[[8,7],[1,2]]]] +[[7,[6,2]],[[9,[5,2]],[1,4]]] +[[[7,[5,9]],[[3,9],[4,5]]],[0,6]] +[[9,[8,[2,2]]],[[9,7],[1,1]]] +[[[[2,3],4],[[4,8],9]],[[9,[8,6]],[[0,9],0]]] +[[0,[[9,3],0]],[8,8]] +[[[[2,9],6],[[2,8],9]],[[[0,5],6],[[6,1],7]]] +[[9,[[8,3],[5,8]]],[[7,[3,0]],3]] +[[[4,[4,2]],0],1] +[[[[9,6],[5,8]],[6,2]],[[[8,0],[7,0]],[[5,6],4]]] +[[[8,0],[[4,3],[7,4]]],[[3,[7,9]],[[7,3],6]]] +[[3,[5,[0,3]]],[5,4]] +[[[[1,2],[6,3]],1],[[7,[5,2]],[[8,8],7]]] +[[4,[[8,0],[7,1]]],[[8,[8,0]],[[1,5],3]]]