distinct types have a scope; added aoc-2021 day 21
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 8 Nov 2022 00:33:49 +0000 (18:33 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 8 Nov 2022 00:33:49 +0000 (18:33 -0600)
compiler/include/astnodes.h
compiler/src/checker.c
compiler/src/symres.c
compiler/src/types.c
compiler/src/utils.c
core/hash/hash.onyx
tests/aoc-2021/day21 [new file with mode: 0644]
tests/aoc-2021/day21.onyx [new file with mode: 0644]
tests/aoc-2021/input/day21.txt [new file with mode: 0644]
tests/bugs/method_call_source_double.onyx

index 6258625a94bff6d533e93257f42c0f20615189d7..ca1d9389bebb51e1e7a613394b7079842a452457 100644 (file)
@@ -1020,6 +1020,7 @@ struct AstDistinctType {
     char *name;
     AstType *base_type;
     Type *dtcache;
+    Scope *scope;
 };
 
 // Top level nodes
index f879a45c9ed183629672e70f970949ee2e8e99e5..720342c3f57686b6805510d358970d43d20bec33 100644 (file)
@@ -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]);
index f37633531e48ba856cb4efed90377aeda31b6c95..4ba8554a8e29b4d9cd7bc3ab18bfbd9a8a3c8cd4 100644 (file)
@@ -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;
     }
index c5e22243c4c651bbbff705194635d6236bc51e8a..1d9acf14fc46f66523dcf36dfda9e5a8f9f705c6 100644 (file)
@@ -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);
index d73ab5c81f32b9f4ba28cf2c049318405de89dd4..b8e1283261fe994858949cff04f767c10f37a64c 100644 (file)
@@ -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;
index 364ef6ae0f9849a40741d46d960c33b72ace5452..433f553b93b856c5a547054db9059b4d38c218db 100644 (file)
@@ -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 (file)
index 0000000..d6db649
--- /dev/null
@@ -0,0 +1 @@
+995904
diff --git a/tests/aoc-2021/day21.onyx b/tests/aoc-2021/day21.onyx
new file mode 100644 (file)
index 0000000..1ae7240
--- /dev/null
@@ -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 (file)
index 0000000..9a4346e
--- /dev/null
@@ -0,0 +1,2 @@
+Player 1 starting position: 3
+Player 2 starting position: 4
\ No newline at end of file
index 8ec3db60dcd4868f958e46269c6c7a72af311981..bf2a2d3839dfb170c35c96d3a51707852e507469 100644 (file)
@@ -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();
 }