added '#with' clause to interfaces
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 26 Sep 2022 01:32:28 +0000 (20:32 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 26 Sep 2022 01:32:28 +0000 (20:32 -0500)
compiler/include/astnodes.h
compiler/src/checker.c
compiler/src/parser.c
compiler/src/symres.c

index 6c48a770740520ab1f62ed473dca50af5ce0155f..66f0a2b778fa5a606db3ce46e7b36a9adc4ada66 100644 (file)
@@ -1097,12 +1097,18 @@ typedef struct InterfaceConstraint {
     b32 invert_condition: 1;
 } InterfaceConstraint;
 
+typedef struct InterfaceVariable {
+    OnyxToken *symbol;
+    AstType   *type;
+} InterfaceVariable;
+
 struct AstInterface {
     AstTyped_base;
     char *name;
 
     bh_arr(InterfaceParam)      params;
     bh_arr(InterfaceConstraint) exprs;
+    bh_arr(InterfaceVariable)   vars;
 };
 
 typedef enum ConstraintPhase {
index 64f794403de98f6f70ea65ac979f7a2061c633c4..b574ff8cfc3a76af0f29b2f61ce4707ea9799ba6 100644 (file)
@@ -1985,6 +1985,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
             CHECK(directive_first, (AstDirectiveFirst *) expr);
             break;
 
+        case Ast_Kind_Constraint_Sentinel:
+            if (expr->type == NULL) YIELD(expr->token->pos, "Waiting to know constraint sentinel's type.");
+            break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
@@ -1993,7 +1997,6 @@ CheckStatus check_expression(AstTyped** pexpr) {
         case Ast_Kind_Package: break;
         case Ast_Kind_Error: break;
         case Ast_Kind_Unary_Field_Access: break;
-        case Ast_Kind_Constraint_Sentinel: break;
         case Ast_Kind_Switch_Case: break;
         case Ast_Kind_Foreign_Block: break;
         case Ast_Kind_Zero_Value: break;
@@ -2846,6 +2849,16 @@ CheckStatus check_constraint(AstConstraint *constraint) {
                 symbol_introduce(constraint->scope, ip->type_token, (AstNode *) type_alias);
             }
 
+            fori (i, 0, bh_arr_length(constraint->interface->vars)) {
+                InterfaceVariable *iv = &constraint->interface->vars[i];
+
+                AstTyped *sentinel = onyx_ast_node_new(context.ast_alloc, sizeof(AstTyped), Ast_Kind_Constraint_Sentinel);
+                sentinel->token = iv->symbol;
+                sentinel->type_node = iv->type;
+
+                symbol_introduce(constraint->scope, iv->symbol, (AstNode *) sentinel);
+            }
+
             assert(constraint->entity);
             constraint->entity->scope = constraint->scope;
 
index ea4ef81d69b84d134afb110ca5801a317d5ac70d..7ffd0912fa305a28c632a0f70bffef39ac5c2d8c 100644 (file)
@@ -2168,11 +2168,24 @@ static AstInterface* parse_interface(OnyxParser* parser) {
     }
 
     bh_arr_new(global_heap_allocator, interface->exprs, 2);
+    bh_arr_new(global_heap_allocator, interface->vars, 2);
 
     expect_token(parser, '{');
     while (!consume_token_if_next(parser, '}')) {
         if (parser->hit_unexpected_token) return interface;
 
+        if (parse_possible_directive(parser, "with")) {
+            InterfaceVariable v;
+            v.symbol = expect_token(parser, Token_Type_Symbol);
+            expect_token(parser, ':');
+
+            v.type = parse_type(parser);
+            expect_token(parser, ';');
+
+            bh_arr_push(interface->vars, v);
+            continue;
+        }
+
         InterfaceConstraint ic = {0};
         if (parse_possible_directive(parser, "not")) {
             ic.invert_condition = 1;
index b5044fac465d0b7a2afbc3bbf11b1b23b45f475c..7042740ffe1ac707896ca60d43e17d9d23d1aad9 100644 (file)
@@ -519,7 +519,21 @@ static SymresStatus symres_expression(AstTyped** expr) {
     }
 
     switch ((*expr)->kind) {
-        case Ast_Kind_Symbol: SYMRES(symbol, (AstNode **) expr); break;
+        case Ast_Kind_Symbol:
+            SYMRES(symbol, (AstNode **) expr);
+
+            // HACK?
+            // I don't know how I never ran into this problem before,
+            // but when a symbol is resolved, there is never a "double
+            // check" that its type node is symbol resolved as well.
+            // This only proved to be an issue when using constraint
+            // sentinels, so I only added that case here. This should
+            // maybe be considered in the future because I think this
+            // lack of double checking could be causing other bugs.
+            if ((*expr)->kind == Ast_Kind_Constraint_Sentinel) {
+                SYMRES(type, &(*expr)->type_node);
+            }
+            break;
 
         case Ast_Kind_Binary_Op:
             SYMRES(expression, &((AstBinaryOp *)(*expr))->left);
@@ -623,6 +637,12 @@ static SymresStatus symres_expression(AstTyped** expr) {
             }
             break;
 
+        case Ast_Kind_Constraint_Sentinel: {
+            AstTyped *sentinel = (AstTyped *) *expr;
+            SYMRES(type, &sentinel->type_node);
+            break;
+        }
+
         default: break;
     }