added: scopes for interfaces
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 27 Sep 2023 03:29:23 +0000 (22:29 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 27 Sep 2023 03:29:23 +0000 (22:29 -0500)
compiler/include/astnodes.h
compiler/src/checker.c
compiler/src/parser.c
compiler/src/symres.c
compiler/src/utils.c
tests/interface_scopes [new file with mode: 0644]
tests/interface_scopes.onyx [new file with mode: 0644]

index d93fa1b09a747e9ef17abf569b9341d809079ada..c88f5bdf3a244ca5ff4e37dddf2e9d873ed210e0 100644 (file)
@@ -1213,6 +1213,8 @@ struct AstInterface {
     bh_arr(InterfaceParam)      params;
     bh_arr(InterfaceConstraint) exprs;
 
+    Scope *scope;
+
     b32 is_intrinsic: 1;
 };
 
index 61d6e24cf7a11ad5e7566ee94e39076d0c76fb90..6c8aff4293560cf3e028efa832af6062c2b284ed 100644 (file)
@@ -3567,8 +3567,10 @@ CheckStatus check_constraint(AstConstraint *constraint) {
             }
 
             assert(constraint->interface->entity && constraint->interface->entity->scope);
+            assert(constraint->interface->scope);
+            assert(constraint->interface->scope->parent == constraint->interface->entity->scope);
 
-            constraint->scope = scope_create(context.ast_alloc, constraint->interface->entity->scope, constraint->token->pos);
+            constraint->scope = scope_create(context.ast_alloc, constraint->interface->scope, constraint->token->pos);
 
             if (bh_arr_length(constraint->type_args) != bh_arr_length(constraint->interface->params)) {
                 ERROR_(constraint->token->pos, "Wrong number of arguments given to interface. Expected %d, got %d.",
index 82d4d7082d1f8a806260e228406184dfb9c8f49a..c06c2ac9635e19696883b74d19fdcdaba0504ab7 100644 (file)
@@ -2484,10 +2484,24 @@ static AstInterface* parse_interface(OnyxParser* parser) {
 
     bh_arr_new(global_heap_allocator, interface->exprs, 2);
 
+    type_create_scope(parser, &interface->scope, interface->token);
+    parser->current_scope = interface->scope;
+
     expect_token(parser, '{');
     while (!consume_token_if_next(parser, '}')) {
         if (parser->hit_unexpected_token) return interface;
 
+        if (next_tokens_are(parser, 3, Token_Type_Symbol, ':', ':')) {
+            OnyxToken* binding_name = expect_token(parser, Token_Type_Symbol);
+            consume_token(parser);
+
+            AstBinding* binding = parse_top_level_binding(parser, binding_name);
+            if (binding) ENTITY_SUBMIT(binding);
+
+            consume_token_if_next(parser, ';');
+            continue;
+        }
+
         InterfaceConstraint ic = {0};
         if (parse_possible_directive(parser, "not")) {
             ic.invert_condition = 1;
@@ -2510,6 +2524,7 @@ static AstInterface* parse_interface(OnyxParser* parser) {
         expect_token(parser, ';');
     }
 
+    parser->current_scope = parser->current_scope->parent;
     return interface;
 }
 
index af8ff885238780edc284e600800286a338f1f037..6f934039e067828e88ab05cb7c6f7635e337dbc3 100644 (file)
@@ -376,8 +376,8 @@ static SymresStatus symres_field_access(AstFieldAccess** fa) {
         expr->kind == Ast_Kind_Enum_Type ||
         expr->kind == Ast_Kind_Type_Raw_Alias ||
         expr->kind == Ast_Kind_Union_Type ||
-        expr->kind == Ast_Kind_Poly_Union_Type) {
-
+        expr->kind == Ast_Kind_Poly_Union_Type ||
+        expr->kind == Ast_Kind_Interface) {
         force_a_lookup = 1;
     }
 
index abff4de0c602c575b08ef9ccc166564546429aab..e027a52af98f3048e7ff30dbcaec1cb4de7b115d 100644 (file)
@@ -383,6 +383,11 @@ all_types_peeled_off:
             AstDistinctType* dtype = (AstDistinctType *) node;
             return symbol_raw_resolve(dtype->scope, symbol);
         }
+
+        case Ast_Kind_Interface: {
+            AstInterface* inter = (AstInterface *) node;
+            return symbol_raw_resolve(inter->scope, symbol);
+        }
     }
 
     return NULL;
@@ -1411,6 +1416,11 @@ all_types_peeled_off:
             AstDistinctType* dtype = (AstDistinctType *) node;
             return &dtype->scope;
         }
+
+        case Ast_Kind_Interface: {
+            AstInterface* inter = (AstInterface *) node;
+            return &inter->scope;
+        }
     }
 
     return NULL;
diff --git a/tests/interface_scopes b/tests/interface_scopes
new file mode 100644 (file)
index 0000000..c9da063
--- /dev/null
@@ -0,0 +1,8 @@
+Woof!  Message 1
+Woof!  Another message!
+Woof!  Such cool message!
+WOOF!  YELL THIS.
+Meow!  Message 1
+Meow!  Another message!
+Meow!  Such cool message!
+MEOW!  Yell this.
diff --git a/tests/interface_scopes.onyx b/tests/interface_scopes.onyx
new file mode 100644 (file)
index 0000000..b63bfb3
--- /dev/null
@@ -0,0 +1,54 @@
+use core {*}
+
+Speak :: interface (t: $T) {
+    { speak(t, str.{}) } -> void;
+    { yell(t, str.{}) } -> void;
+
+    speak :: #match {}
+}
+
+#inject Speak {
+    yell  :: #match {}
+}
+
+Dog :: struct {_: i32}
+
+#overload
+Speak.speak :: (d: Dog, msg: str) {
+    printf("Woof!  {}\n", msg);
+}
+
+#overload
+Speak.yell :: (d: Dog, msg: str) {
+    printf("WOOF!  {}\n", string.temp_copy(msg) |> string.to_uppercase());
+}
+
+Cat :: struct {_: i32}
+
+#overload
+Speak.speak :: (d: Cat, msg: str) {
+    printf("Meow!  {}\n", msg);
+}
+
+#overload
+Speak.yell :: (d: Cat, msg: str) {
+    printf("MEOW!  {}\n", msg);
+}
+
+
+speak_things :: (thing: $T/Speak) {
+    Speak.speak(thing, "Message 1");
+    Speak.speak(thing, "Another message!");
+    Speak.speak(thing, "Such cool message!");
+    
+    Speak.yell(thing, "Yell this.");
+}
+
+
+main :: () {
+    dog := Dog.{};
+    cat := Cat.{};
+
+    speak_things(dog);
+    speak_things(cat);
+}
\ No newline at end of file