From ab73703e644c7e3372087247e2cbb13d003bd51d Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 26 Sep 2023 22:29:23 -0500 Subject: [PATCH] added: scopes for interfaces --- compiler/include/astnodes.h | 2 ++ compiler/src/checker.c | 4 ++- compiler/src/parser.c | 15 +++++++++++ compiler/src/symres.c | 4 +-- compiler/src/utils.c | 10 +++++++ tests/interface_scopes | 8 ++++++ tests/interface_scopes.onyx | 54 +++++++++++++++++++++++++++++++++++++ 7 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 tests/interface_scopes create mode 100644 tests/interface_scopes.onyx diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index d93fa1b0..c88f5bdf 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1213,6 +1213,8 @@ struct AstInterface { bh_arr(InterfaceParam) params; bh_arr(InterfaceConstraint) exprs; + Scope *scope; + b32 is_intrinsic: 1; }; diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 61d6e24c..6c8aff42 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -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.", diff --git a/compiler/src/parser.c b/compiler/src/parser.c index 82d4d708..c06c2ac9 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -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; } diff --git a/compiler/src/symres.c b/compiler/src/symres.c index af8ff885..6f934039 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -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; } diff --git a/compiler/src/utils.c b/compiler/src/utils.c index abff4de0..e027a52a 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -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 index 00000000..c9da063a --- /dev/null +++ b/tests/interface_scopes @@ -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 index 00000000..b63bfb33 --- /dev/null +++ b/tests/interface_scopes.onyx @@ -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 -- 2.25.1