From ff22ba0c76a57b19c6bef49a8aa18c81e5c817b6 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Sun, 25 Sep 2022 15:27:02 -0500 Subject: [PATCH] added ability to inject methods on basic types --- compiler/include/astnodes.h | 2 +- compiler/src/checker.c | 59 ++++++++++++++++++++----------------- compiler/src/utils.c | 28 ++++++++++++++++-- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 2d383918..6c48a770 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -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; }; diff --git a/compiler/src/checker.c b/compiler/src/checker.c index c6ea3ae9..20d41b21 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -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) { diff --git a/compiler/src/utils.c b/compiler/src/utils.c index 33fbdea3..7c83b890 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -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; -- 2.25.1