field access bugfix and added overloading operator '[]'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 16 Jun 2021 15:56:42 +0000 (10:56 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 16 Jun 2021 15:56:42 +0000 (10:56 -0500)
bin/onyx
core/builtin.onyx
include/onyxastnodes.h
src/onyxastnodes.c
src/onyxchecker.c
src/onyxparser.c
src/onyxtypes.c

index 383ec51dbeb786693c081051b09a9d8a76a701a6..a477f85fe243502a9210704aa326df174468e1de 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 254d7d5473c531250f6ef2b2fa94fe44bb9b8c87..b7bde249e1febf3a3b9fe5bc85bc96770b4aded9 100644 (file)
@@ -179,4 +179,4 @@ CallSite :: struct {
     file   : str;
     line   : u32;
     column : u32;
-}
\ No newline at end of file
+}
index e1aaed020105dbd50bd6bb2ce5ced5bfc2170887..857778869c8b87ac910ae23120df9099ca4eb33f 100644 (file)
@@ -294,6 +294,8 @@ typedef enum BinaryOp {
     Binary_Op_Range           = 34,
     Binary_Op_Method_Call     = 35,
 
+    Binary_Op_Subscript       = 36,
+
     Binary_Op_Count
 } BinaryOp;
 
@@ -512,10 +514,22 @@ struct AstLocal         { AstTyped_base; };
 struct AstArgument      { AstTyped_base; AstTyped *value; VarArgKind va_kind; b32 is_baked : 1; };
 struct AstAddressOf     { AstTyped_base; AstTyped *expr; };
 struct AstDereference   { AstTyped_base; AstTyped *expr; };
-struct AstArrayAccess   { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 elem_size; };
-struct AstFieldAccess   { AstTyped_base; AstTyped *expr; u32 offset; u32 idx; char* field; }; // If token is null, defer to field
 struct AstSizeOf        { AstTyped_base; AstType *so_ast_type; Type *so_type; u64 size; };
 struct AstAlignOf       { AstTyped_base; AstType *ao_ast_type; Type *ao_type; u64 alignment; };
+struct AstArrayAccess   {
+    AstTyped_base;
+    BinaryOp __unused_operation; // This will be set to Binary_Op_Subscript
+    AstTyped *addr;
+    AstTyped *expr;
+    u64 elem_size;
+};
+struct AstFieldAccess   {
+    AstTyped_base;
+    AstTyped *expr;
+    u32 offset;
+    u32 idx;
+    char* field; // If token is null, defer to field
+};
 struct AstFileContents  {
     AstTyped_base;
 
index 531090b28414eeba7930b83f464802d562a77bad..09ed6cc24b33a6cdf32c43153c148176d8a2acce 100644 (file)
@@ -105,7 +105,9 @@ const char *binaryop_string[Binary_Op_Count] = {
     "&=", "|=", "^=", "<<=", ">>=", ">>>=",
     "NONE",
 
-    "|>", "..",
+    "|>", "..", "->",
+
+    "[]",
 };
 
 const char* entity_state_strings[Entity_State_Count] = {
index fbc4c6be8c50ca07eecce621209570fc6c9ab24f..9829b1d030725f1b31f5d3dcd0ae8e1369e79e5c 100644 (file)
@@ -38,7 +38,7 @@ CheckStatus check_compound(AstCompound* compound);
 CheckStatus check_expression(AstTyped** expr);
 CheckStatus check_address_of(AstAddressOf* aof);
 CheckStatus check_dereference(AstDereference* deref);
-CheckStatus check_array_access(AstArrayAccess* expr);
+CheckStatus check_array_access(AstArrayAccess** paa);
 CheckStatus check_field_access(AstFieldAccess** pfield);
 CheckStatus check_method_call(AstBinaryOp** mcall);
 CheckStatus check_size_of(AstSizeOf* so);
@@ -1288,10 +1288,27 @@ CheckStatus check_dereference(AstDereference* deref) {
     return Check_Success;
 }
 
-CheckStatus check_array_access(AstArrayAccess* aa) {
+CheckStatus check_array_access(AstArrayAccess** paa) {
+    AstArrayAccess* aa = *paa;
     CHECK(expression, &aa->addr);
     CHECK(expression, &aa->expr);
 
+    // NOTE: Try operator overloading before checking everything else.
+    if ((aa->addr->type != NULL && aa->expr->type != NULL) &&
+        (aa->addr->type->kind != Type_Kind_Basic || aa->expr->type->kind != Type_Kind_Basic)) {
+        // AstArrayAccess is the same as AstBinaryOp for the first sizeof(AstBinaryOp) bytes
+        AstBinaryOp* binop = (AstBinaryOp *) aa;
+        AstCall *implicit_call = binaryop_try_operator_overload(binop);
+
+        if (implicit_call != NULL) {
+            CHECK(call, implicit_call);
+
+            // NOTE: Not an array access
+            *paa = (AstArrayAccess *) implicit_call;
+            return Check_Success;
+        }
+    }
+
     if (!type_is_array_accessible(aa->addr->type)) {
         onyx_report_error(aa->token->pos,
                 "Expected pointer or array type for left of array access, got '%s'.",
@@ -1374,7 +1391,7 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
         return Check_Error;
     }
 
-    if (!is_lval((AstNode *) field->expr)) {
+    if (field->expr->type->kind != Type_Kind_Pointer && !is_lval((AstNode *) field->expr)) {
         onyx_report_error(field->token->pos,
             "Cannot access field '%b'. Expression is not an lval.",
             field->token->text,
@@ -1382,6 +1399,11 @@ CheckStatus check_field_access(AstFieldAccess** pfield) {
         return Check_Error;
     }
 
+    // HACK: (*foo).bar does not work without this.
+    if (field->expr->kind == Ast_Kind_Dereference) {
+        field->expr = ((AstDereference *) field->expr)->expr;
+    }
+
     StructMember smem;
     if (field->token != NULL && field->field == NULL) {
         token_toggle_end(field->token);
@@ -1512,7 +1534,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
         case Ast_Kind_Address_Of:    retval = check_address_of((AstAddressOf *) expr); break;
         case Ast_Kind_Dereference:   retval = check_dereference((AstDereference *) expr); break;
         case Ast_Kind_Slice:
-        case Ast_Kind_Array_Access:  retval = check_array_access((AstArrayAccess *expr); break;
+        case Ast_Kind_Array_Access:  retval = check_array_access((AstArrayAccess **) pexpr); break;
         case Ast_Kind_Field_Access:  retval = check_field_access((AstFieldAccess **) pexpr); break;
         case Ast_Kind_Method_Call:   retval = check_method_call((AstBinaryOp **) pexpr); break;
         case Ast_Kind_Size_Of:       retval = check_size_of((AstSizeOf *) expr); break;
index 9199115205bfbff19049d8563a5acaffe1ea7d92..44347d15a6aa1d165e700257f32e3a1894a7d715 100644 (file)
@@ -615,6 +615,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 aa_node->token = open_bracket;
                 aa_node->addr = retval;
                 aa_node->expr = expr;
+                aa_node->__unused_operation = Binary_Op_Subscript;
 
                 retval = (AstTyped *) aa_node;
                 expect_token(parser, ']');
@@ -765,6 +766,7 @@ static BinaryOp binary_op_from_token_type(TokenType t) {
 
         case Token_Type_Pipe:              return Binary_Op_Pipe;
         case Token_Type_Dot_Dot:           return Binary_Op_Range;
+        case '[':                          return Binary_Op_Subscript;
         default: return Binary_Op_Count;
     }
 }
@@ -827,6 +829,7 @@ static AstTyped* parse_expression(OnyxParser* parser, b32 assignment_allowed) {
         bin_op_kind = binary_op_from_token_type(parser->curr->type);
         if (bin_op_kind == Binary_Op_Count) goto expression_done;
         if (binop_is_assignment(bin_op_kind) && !assignment_allowed) goto expression_done;
+        if (bin_op_kind == Binary_Op_Subscript) goto expression_done;
 
         bin_op_tok = parser->curr;
         consume_token(parser);
@@ -2331,6 +2334,7 @@ static void parse_top_level_statement(OnyxParser* parser) {
 
                 BinaryOp op = binary_op_from_token_type(parser->curr->type);
                 consume_token(parser);
+                if (op == Binary_Op_Subscript) expect_token(parser, ']');    // #operator [] ... needs to consume the other ']'
                 
                 if (op == Binary_Op_Count) {
                     onyx_report_error(parser->curr->pos, "Invalid binary operator.");
index 6bdb5c896f152081bb520c7784b7cbe22566ec8f..0e307106ca01da24433ad81f3b72eb08370bf22b 100644 (file)
@@ -332,13 +332,13 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
                 mem_alignment = type_alignment_of((*member)->type);
                 if (mem_alignment <= 0) {
-                    if ((*member)->type->kind == Type_Kind_Struct) {
-                        AstStructType* member_node = (AstStructType *) (*member)->type->ast_type;
-                        if (member_node->stcache_is_valid) {
-                            s_node->stcache_is_valid = 0;
-                            return NULL;
-                        }
-                    }
+                    // if ((*member)->type->kind == Type_Kind_Struct) {
+                    //     AstStructType* member_node = (AstStructType *) (*member)->type->ast_type;
+                    //     if (member_node->stcache_is_valid) {
+                    //         s_node->stcache_is_valid = 0;
+                    //         return NULL;
+                    //     }
+                    // }
 
                     onyx_report_error((*member)->token->pos, "Invalid member type: %s", type_get_name((*member)->type)); 
                     return NULL;
@@ -427,6 +427,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
         case Ast_Kind_Enum_Type: {
             AstEnumType* enum_node = (AstEnumType *) type_node;
             if (enum_node->etcache) return enum_node->etcache;
+            if (enum_node->backing_type == NULL) return NULL;
 
             Type* enum_type = bh_alloc(alloc, sizeof(Type));
             enum_node->etcache = enum_type;