From 04227061e2667df791cc23067a07d9ccc9997e2f Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 7 Nov 2022 18:33:49 -0600 Subject: [PATCH] distinct types have a scope; added aoc-2021 day 21 --- compiler/include/astnodes.h | 1 + compiler/src/checker.c | 17 ++ compiler/src/symres.c | 1 + compiler/src/types.c | 1 + compiler/src/utils.c | 10 + core/hash/hash.onyx | 1 + tests/aoc-2021/day21 | 1 + tests/aoc-2021/day21.onyx | 227 ++++++++++++++++++++++ tests/aoc-2021/input/day21.txt | 2 + tests/bugs/method_call_source_double.onyx | 7 +- 10 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 tests/aoc-2021/day21 create mode 100644 tests/aoc-2021/day21.onyx create mode 100644 tests/aoc-2021/input/day21.txt diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 6258625a..ca1d9389 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1020,6 +1020,7 @@ struct AstDistinctType { char *name; AstType *base_type; Type *dtcache; + Scope *scope; }; // Top level nodes diff --git a/compiler/src/checker.c b/compiler/src/checker.c index f879a45c..720342c3 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -1314,6 +1314,23 @@ CheckStatus check_struct_literal(AstStructLiteral* sl) { return Check_Success; } + if (bh_arr_length(sl->args.values) == 1) { + CHECK(expression, &sl->args.values[0]); + + Type* type_to_match = sl->type; + if (sl->type->kind == Type_Kind_Distinct) { + type_to_match = sl->type->Distinct.base_type; + } + + TYPE_CHECK(&sl->args.values[0], type_to_match) { + ERROR(sl->token->pos, + "Mismatched type in initialized type. FIX ME"); + } + + sl->flags |= Ast_Flag_Has_Been_Checked; + return Check_Success; + } + if ((sl->flags & Ast_Flag_Has_Been_Checked) != 0) { assert(sl->args.values); assert(sl->args.values[0]); diff --git a/compiler/src/symres.c b/compiler/src/symres.c index f3763353..4ba8554a 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -458,6 +458,7 @@ static SymresStatus symres_method_call(AstBinaryOp** mcall) { SYMRES(expression, (AstTyped **) &(*mcall)->right); + // TODO: This doesn't look right? Does this ever happen? Check this... if ((*mcall)->right->kind != Ast_Kind_Call) { *mcall = (AstBinaryOp *) (*mcall)->right; } diff --git a/compiler/src/types.c b/compiler/src/types.c index c5e22243..1d9acf14 100644 --- a/compiler/src/types.c +++ b/compiler/src/types.c @@ -621,6 +621,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) { Type *distinct_type = type_create(Type_Kind_Distinct, alloc, 0); distinct_type->Distinct.base_type = base_type; distinct_type->Distinct.name = distinct->name; + distinct_type->ast_type = type_node; distinct->dtcache = distinct_type; type_register(distinct_type); diff --git a/compiler/src/utils.c b/compiler/src/utils.c index d73ab5c8..b8e12832 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -301,6 +301,11 @@ all_types_peeled_off: AstNode* callee = (AstNode *) ((AstPolyCallType *) node)->callee; return try_symbol_raw_resolve_from_node(callee, symbol); } + + case Ast_Kind_Distinct_Type: { + AstDistinctType* dtype = (AstDistinctType *) node; + return symbol_raw_resolve(dtype->scope, symbol); + } } return NULL; @@ -1124,6 +1129,11 @@ all_types_peeled_off: AstStructType* stype = pstype->base_struct; return &stype->scope; } + + case Ast_Kind_Distinct_Type: { + AstDistinctType* dtype = (AstDistinctType *) node; + return &dtype->scope; + } } return NULL; diff --git a/core/hash/hash.onyx b/core/hash/hash.onyx index 364ef6ae..433f553b 100644 --- a/core/hash/hash.onyx +++ b/core/hash/hash.onyx @@ -12,6 +12,7 @@ to_u32 :: #match { return hash; }, (key: type_expr) -> u32 { return to_u32(cast(u32) key); }, + (key: bool) -> u32 { return 1 if key else 0; }, #precedence 10000 macro (key: $T/HasHashMethod) => key->hash() diff --git a/tests/aoc-2021/day21 b/tests/aoc-2021/day21 new file mode 100644 index 00000000..d6db649b --- /dev/null +++ b/tests/aoc-2021/day21 @@ -0,0 +1 @@ +995904 diff --git a/tests/aoc-2021/day21.onyx b/tests/aoc-2021/day21.onyx new file mode 100644 index 00000000..1ae72403 --- /dev/null +++ b/tests/aoc-2021/day21.onyx @@ -0,0 +1,227 @@ +use core + +PART :: 1 + +#if PART == 1 { + +Die :: struct { + value: u32; + rolls: u32; +} + +#inject Die { + make :: () -> Die { + return .{ 1, 0 }; + } + + roll :: (d: ^Die) -> u32 { + defer d.value += 1; + defer d.rolls += 1; + return d.value; + } +} + +Player :: struct { + square: u32; + score: u32; +} + +#inject Player { + move :: (p: ^Player, squares: u32) { + p.square += squares; + p.square %= 10; + + p.score += (p.square + 1); + } +} + +main :: () { + p1, p2: Player; + + for os.with_file("./tests/aoc-2021/input/day21.txt") { + r := io.reader_make(it); + + l1 := r->read_line(consume_newline=true); + l2 := r->read_line(consume_newline=true); + + _, s1 := string.bisect(l1, #char ":"); + _, s2 := string.bisect(l2, #char ":"); + + string.strip_whitespace(^s1); + string.strip_whitespace(^s2); + + p1.square = ~~ (conv.str_to_i64(s1) - 1); + p2.square = ~~ (conv.str_to_i64(s2) - 1); + } + + die := Die.make(); + losing_score: u32; + + while true { + play :: macro (player, opponent: ^Player) { + r1 := die->roll(); + r2 := die->roll(); + r3 := die->roll(); + + player->move(r1 + r2 + r3); + + if player.score >= 1000 { + losing_score = opponent.score; + break; + } + } + + play(^p1, ^p2); + play(^p2, ^p1); + } + + println(losing_score * die.rolls); +} + +} // End of part 1 + + +#if PART == 2 { + +Player :: struct { + square: u32; + score: u64; +} + +#inject Player { + hash :: (p: Player) -> u32 { + h := 7; + h += h << 5 + hash.to_u32(p.square); + h += h << 5 + hash.to_u32(p.score); + return h; + } + + move :: (p: Player, m: u32) -> Player { + n := p; + n.square += m; + n.square %= 10; + + n.score += ~~(n.square + 1); + return n; + } +} + +#operator == (p1, p2: Player) => p1.square == p2.square && p1.score == p2.score; + + +Case :: struct { + multiplier: u32; + spaces: u32; +} + +cases := Case.[ + Case.{ 1, 3 }, + Case.{ 3, 4 }, + Case.{ 6, 5 }, + Case.{ 7, 6 }, + Case.{ 6, 7 }, + Case.{ 3, 8 }, + Case.{ 1, 9 }, +] + +calc_wins_memo :: (p1, p2: Player, player_1_turn: bool) -> (u64, u64) { + #persist memo: Map(Pair(Pair(Player, Player), bool), Pair(u64, u64)); + + if memo->has(.{.{p1, p2}, player_1_turn}) { + v := memo->get(.{.{p1, p2}, player_1_turn}); + return v.first, v.second; + } + + v1, v2 := calc_wins(p1, p2, player_1_turn); + memo[.{.{p1, p2}, player_1_turn}] = .{v1, v2}; + return v1, v2; +} + +calc_wins :: (p1, p2: Player, player_1_turn := true) -> (u64, u64) { + if p1.score >= 21 { + return 1, 0; + } + + elseif p2.score >= 21 { + return 0, 1; + } + + else { + w1, w2: u64; + + if player_1_turn { + for^ cases { + n1, n2 := calc_wins_memo( + p1->move(it.spaces), + p2, + false + ); + + w1 += n1 * ~~it.multiplier; + w2 += n2 * ~~it.multiplier; + } + + } else { + for^ cases { + n1, n2 := calc_wins_memo( + p1, + p2->move(it.spaces), + true + ); + + w1 += n1 * ~~it.multiplier; + w2 += n2 * ~~it.multiplier; + } + } + + return w1, w2; + } +} + +main :: () { + p1, p2: Player; + + for os.with_file("./tests/aoc-2021/input/day21.txt") { + r := io.reader_make(it); + + l1 := r->read_line(consume_newline=true); + l2 := r->read_line(consume_newline=true); + + _, s1 := string.bisect(l1, #char ":"); + _, s2 := string.bisect(l2, #char ":"); + + string.strip_whitespace(^s1); + string.strip_whitespace(^s2); + + p1.square = cast(i32) (conv.str_to_i64(s1) - 1); + p2.square = cast(i32) (conv.str_to_i64(s2) - 1); + } + + w1, w2 := calc_wins(p1, p2); + println(w1); + println(w2); + println(math.max(w1, w2)); + +} + +} + + + +Pair :: struct (T1: type_expr, T2: type_expr) { + first: T1; + second: T2; +} + +#inject Pair { + hash :: (p: Pair($T/hash.Hashable, $R/hash.Hashable)) -> u32 { + h := 7; + h += h << 5 + hash.to_u32(p.first); + h += h << 5 + hash.to_u32(p.second); + return h; + } +} + +#operator == (p1: Pair, p2: typeof p1) => + p1.first == p2.first && p1.second == p2.second; + diff --git a/tests/aoc-2021/input/day21.txt b/tests/aoc-2021/input/day21.txt new file mode 100644 index 00000000..9a4346e6 --- /dev/null +++ b/tests/aoc-2021/input/day21.txt @@ -0,0 +1,2 @@ +Player 1 starting position: 3 +Player 2 starting position: 4 \ No newline at end of file diff --git a/tests/bugs/method_call_source_double.onyx b/tests/bugs/method_call_source_double.onyx index 8ec3db60..bf2a2d38 100644 --- a/tests/bugs/method_call_source_double.onyx +++ b/tests/bugs/method_call_source_double.onyx @@ -18,8 +18,8 @@ good_foo := Foo.VTable.{ } } -make_foo :: () -> Foo { - foo : Foo; +make_foo :: () -> ^Foo { + foo := new(Foo); foo.vtable = ^good_foo; foo.x = 1234; @@ -28,8 +28,7 @@ make_foo :: () -> Foo { } main :: () { - foo := make_foo(); - foo->f(); + make_foo()->f(); Foo.{^good_foo, 5678}->f(); } -- 2.25.1