added ability to inject methods on basic types
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 25 Sep 2022 20:27:02 +0000 (15:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 25 Sep 2022 20:27:02 +0000 (15:27 -0500)
compiler/include/astnodes.h
compiler/src/checker.c
compiler/src/utils.c

index 2d383918659b0c3f52e64691f77a4d5725a680ac..6c48a770740520ab1f62ed473dca50af5ce0155f 100644 (file)
@@ -897,7 +897,7 @@ struct AstSwitch {
     Type* type
 struct AstType { AstType_base; };
 
-struct AstBasicType     { AstType_base; Type* basic_type; };
+struct AstBasicType     { AstType_base; Type* basic_type; Scope *scope; };
 struct AstPointerType   { AstType_base; AstType* elem; };
 struct AstArrayType     { AstType_base; AstType* elem; AstTyped *count_expr; };
 struct AstSliceType     { AstType_base; AstType* elem; };
index c6ea3ae90d0b1014b22ca9100f6f6c62df0a49f2..20d41b2149a4a1485f6094d30954accc236604d1 100644 (file)
@@ -1671,14 +1671,6 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
         return Check_Return_To_Symres;
     }
 
-    if (!type_is_structlike(field->expr->type)) {
-        ERROR_(field->token->pos,
-            "Cannot access field '%b' on '%s'. Type is not a struct.",
-            field->token->text,
-            field->token->length,
-            node_get_type_name(field->expr));
-    }
-
     // Optimization for (*foo).member.
     if (field->expr->kind == Ast_Kind_Dereference) {
         field->expr = ((AstDereference *) field->expr)->expr;
@@ -1696,6 +1688,15 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
         }
     }
 
+    if (!type_is_structlike(field->expr->type)) {
+        /*ERROR_(field->token->pos,
+            "Cannot access field '%b' on '%s'. Type is not a struct.",
+            field->token->text,
+            field->token->length,
+            node_get_type_name(field->expr));*/
+        goto try_resolve_from_type;
+    }
+
     StructMember smem;
     if (!type_lookup_member(field->expr->type, field->field, &smem)) {
         if (field->expr->type->kind == Type_Kind_Array) {
@@ -1705,25 +1706,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
             }
         }
 
-        AstNode* n = try_symbol_raw_resolve_from_type(field->expr->type, field->field);
-
-        AstType* type_node = field->expr->type->ast_type;
-        if (!n) n = try_symbol_raw_resolve_from_node((AstNode *) type_node, field->field);
-
-        if (n) {
-            *pfield = (AstFieldAccess *) n;
-            return Check_Success;
-        }
-
-        if (!type_node) goto closest_not_found;
-
-        char* closest = find_closest_symbol_in_node((AstNode *) type_node, field->field);
-        if (closest) {
-            ERROR_(field->token->pos, "Field '%s' does not exists on '%s'. Did you mean '%s'?", field->field, node_get_type_name(field->expr), closest);
-        }
-
-      closest_not_found:
-        ERROR_(field->token->pos, "Field '%s' does not exists on '%s'.", field->field, node_get_type_name(field->expr));
+        goto try_resolve_from_type;
     }
 
     // NOTE: If this member was included into the structure through a "use x: ^T" kind of statement,
@@ -1748,6 +1731,28 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
     field->type = smem.type;
     field->flags |= Ast_Flag_Has_Been_Checked;
     return Check_Success;
+
+    // TODO: DOCUMENT THIS WEIRD CASE
+  try_resolve_from_type:
+    AstNode* n = try_symbol_raw_resolve_from_type(field->expr->type, field->field);
+
+    AstType* type_node = field->expr->type->ast_type;
+    if (!n) n = try_symbol_raw_resolve_from_node((AstNode *) type_node, field->field);
+
+    if (n) {
+        *pfield = (AstFieldAccess *) n;
+        return Check_Success;
+    }
+
+    if (!type_node) goto closest_not_found;
+
+    char* closest = find_closest_symbol_in_node((AstNode *) type_node, field->field);
+    if (closest) {
+        ERROR_(field->token->pos, "Field '%s' does not exists on '%s'. Did you mean '%s'?", field->field, node_get_type_name(field->expr), closest);
+    }
+
+  closest_not_found:
+    ERROR_(field->token->pos, "Field '%s' does not exists on '%s'.", field->field, node_get_type_name(field->expr));
 }
 
 CheckStatus check_method_call(AstBinaryOp** pmcall) {
index 33fbdea362083d6ef98965fbfdabf714a3a40694..7c83b89023e5e338292abc2ac81a5d1a65aabd11 100644 (file)
@@ -191,6 +191,10 @@ AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn) {
 }
 
 AstNode* try_symbol_raw_resolve_from_node(AstNode* node, char* symbol) {
+    // CLEANUP: I think this has a lot of duplication from get_scope_from_node.
+    // There are some additional cases handled here, but I think the majority
+    // of this code could be rewritten in terms of get_scope_from_node.
+
     b32 used_pointer = 0;
 
     while (1) {
@@ -240,6 +244,15 @@ all_types_peeled_off:
             return symbol_raw_resolve(fb->scope, symbol);
         }
 
+        case Ast_Kind_Basic_Type: {
+            AstBasicType *bt = (AstBasicType *) node;
+
+            if (bt->scope == NULL)
+                return NULL;
+
+            return symbol_raw_resolve(bt->scope, symbol);
+        }
+
         case Ast_Kind_Enum_Type: {
             AstEnumType* etype = (AstEnumType *) node;
             return symbol_raw_resolve(etype->scope, symbol);
@@ -455,6 +468,8 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads,
 
             // return and not continue because if the overload that didn't have a type will
             // work in the future, then it has to take precedence over the other options available.
+            bh_imap_free(&all_overloads);
+            bh_arr_free(args.values);
             return (AstTyped *) &node_that_signals_a_yield;
         }
         assert(overload->type->kind == Type_Kind_Function);
@@ -473,6 +488,8 @@ AstTyped* find_matching_overload_by_arguments(bh_arr(OverloadOption) overloads,
         }
 
         if (tm == TYPE_MATCH_YIELD) {
+            bh_imap_free(&all_overloads);
+            bh_arr_free(args.values);
             return (AstTyped *) &node_that_signals_a_yield;
         }
     }
@@ -1087,6 +1104,11 @@ all_types_peeled_off:
             return &package->package->scope;
         } 
 
+        case Ast_Kind_Basic_Type: {
+            AstBasicType* btype = (AstBasicType *) node;
+            return &btype->scope;
+        }
+
         case Ast_Kind_Enum_Type: {
             AstEnumType* etype = (AstEnumType *) node;
             return &etype->scope;
@@ -1126,8 +1148,10 @@ Scope *get_scope_from_node_or_create(AstNode *node) {
     // is used in other parts of the compiler for struct/enum
     // scopes?
     if (!*pscope) {
-        assert(node->token);
-        *pscope = scope_create(context.ast_alloc, NULL, node->token->pos);
+        OnyxFilePos pos = {0};
+        if (node->token) pos = node->token->pos;
+
+        *pscope = scope_create(context.ast_alloc, NULL, pos);
     }
 
     return *pscope;