file : str;
line : u32;
column : u32;
-}
\ No newline at end of file
+}
Binary_Op_Range = 34,
Binary_Op_Method_Call = 35,
+ Binary_Op_Subscript = 36,
+
Binary_Op_Count
} BinaryOp;
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;
"&=", "|=", "^=", "<<=", ">>=", ">>>=",
"NONE",
- "|>", "..",
+ "|>", "..", "->",
+
+ "[]",
};
const char* entity_state_strings[Entity_State_Count] = {
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);
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'.",
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,
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);
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;
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, ']');
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;
}
}
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);
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.");
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;
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;