diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 04184c591..a9c6b41db 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -435,7 +435,7 @@ func void testAnonStruct() if (s.a != 1) printf("Error s.a\n"); if (s.x != 0) printf("Error s.x\n"); if (s.xx.b != 0) printf("Error s.xx.b = %d\n", s.xx.b); - if (s.xx.c != 2) printf("Error s.xx.c\n"); + if (s.xx.c != 0) printf("Error s.xx.c\n"); if (s.b1 != 0) printf("Error s.b1\n"); if (s.c1 != 0) printf("Error s.c1\n"); if (s.b2 != 123) printf("Error s.b2\n"); @@ -1080,13 +1080,13 @@ union TestUnionSize } func void testTypeValues() { -// TestUnionSize.a.sizeof; printf("Enum size: %d = 2\n", TestEnumSize.sizeof); printf("Enum size: %d = 4\n", TestEnumSizeDefault.sizeof); printf("Struct size: %d = 12\n", TestStructInt.sizeof); printf("Struct size: %d = 16\n", TestStructSize.sizeof); printf("Union size: %d = 5\n", TestUnionSize.sizeof); printf("Error size: %d = 4\n", Err.sizeof); + printf("Testunion.a sizeof: %d = 2\n", TestUnionSize.a.sizeof); } func int main(int x) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 52fc8a843..280f664c1 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1053,6 +1053,7 @@ extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; extern const char *kw_main; extern const char *kw_sizeof; +extern const char *kw_offsetof; #define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, _token.span) #define AST_NEW(_kind, _loc) new_ast(_kind, _loc) @@ -1311,7 +1312,7 @@ static inline bool type_is_signed(Type *type) { return type->type_kind >= TYPE_I static inline bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U64; } static inline bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; } static inline bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; } -bool type_may_have_method(Type *type); +bool type_may_have_sub_elements(Type *type); static inline Type *type_reduced(Type *type) { diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index ee249a085..321f03eac 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -62,8 +62,8 @@ inline Expr* parse_constant_expr(Context *context) * ; * * parameter - * : type - * | expr + * : expr + * | '[' expr ']' '=' expr * ; * */ @@ -87,17 +87,7 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type) } else { - if (!parse_type_or_expr(context, &expr, &type)) return false; - } - if (!expr) - { - if (!allow_type) - { - sema_error_range(start, "Did not expect a type here, only expressions."); - return false; - } - expr = expr_new(EXPR_TYPEID, type->span); - RANGE_EXTEND_PREV(expr); + expr = parse_expr(context); } vec_add(*result, expr); if (!try_consume(context, TOKEN_COMMA)) @@ -781,7 +771,7 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info) expr->type_access.name = context->tok; advance(context); RANGE_EXTEND_PREV(expr); - return expr; + return parse_precedence_with_left_side(context, expr, PREC_CALL - 1); } diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index a0dfb0a69..eebbb5e0b 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -494,28 +494,7 @@ static inline bool is_valid_try_statement(TokenType type) } } -static inline Ast *parse_decl_or_expr_stmt(Context *context) -{ - Expr *expr = NULL; - TypeInfo *type = NULL; - if (!parse_type_or_expr(context, &expr, &type)) return poisoned_ast; - - Ast *ast; - if (expr) - { - ast = AST_NEW(AST_EXPR_STMT, expr->span); - ast->expr_stmt = expr; - } - else - { - Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, false, type), poisoned_ast); - ast = AST_NEW(AST_DECLARE_STMT, decl->span); - ast->declare_stmt = decl; - } - CONSUME_OR(TOKEN_EOS, poisoned_ast); - return ast; -} /** * ct_for_stmt @@ -644,11 +623,15 @@ Ast *parse_stmt(Context *context) case TOKEN_CT_TYPE_IDENT: case TOKEN_TYPE_IDENT: case TOKEN_ERROR_TYPE: - if (context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LBRACE) + case TOKEN_IDENT: + if (parse_next_is_decl(context)) + { + return parse_declaration_stmt(context); + } + else { return parse_expr_stmt(context); } - return parse_declaration_stmt(context); case TOKEN_TYPEOF: TODO case TOKEN_LOCAL: // Local means declaration! @@ -662,12 +645,6 @@ Ast *parse_stmt(Context *context) return parse_expr_stmt(context); case TOKEN_AT: return parse_expr_stmt(context); - case TOKEN_IDENT: - if (context->next_tok.type == TOKEN_SCOPE) - { - return parse_decl_or_expr_stmt(context); - } - return parse_expr_stmt(context); case TOKEN_RETURN: { Ast *ast = TRY_AST(parse_return(context)); diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 94cccdfc5..c60e329e6 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -660,20 +660,18 @@ Ast *parse_decl_expr_list(Context *context) decl_expr->decl_expr_stmt = NULL; while (1) { - Expr *expr = NULL; - TypeInfo *type = NULL; - if (!parse_type_or_expr(context, &expr, &type)) return false; - if (expr) + if (parse_next_is_decl(context)) { - Ast *stmt = AST_NEW(AST_EXPR_STMT, expr->span); - stmt->expr_stmt = expr; + Decl *decl = TRY_DECL_OR(parse_decl(context), poisoned_ast); + Ast *stmt = AST_NEW(AST_DECLARE_STMT, decl->span); + stmt->declare_stmt = decl; vec_add(decl_expr->decl_expr_stmt, stmt); } else { - Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, false, type), poisoned_ast); - Ast *stmt = AST_NEW(AST_DECLARE_STMT, decl->span); - stmt->declare_stmt = decl; + Expr *expr = TRY_EXPR_OR(parse_expr(context), poisoned_ast); + Ast *stmt = AST_NEW(AST_EXPR_STMT, expr->span); + stmt->expr_stmt = expr; vec_add(decl_expr->decl_expr_stmt, stmt); } if (!try_consume(context, TOKEN_COMMA)) break; @@ -682,27 +680,7 @@ Ast *parse_decl_expr_list(Context *context) } -static inline bool is_expr_after_type_ident(Context *context) -{ - return context->next_tok.type == TOKEN_DOT || context->next_tok.type == TOKEN_LPAREN; -} - -bool parse_type_or_expr_after_type(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) -{ - if (!type_info_ok(*type_ptr)) return false; - if (try_consume(context, TOKEN_DOT)) - { - *expr_ptr = parse_type_access_expr_after_type(context, *type_ptr); - *type_ptr = NULL; - return expr_ok(*expr_ptr); - } - if (context->tok.type == TOKEN_LBRACE) - { - return parse_type_compound_literal_expr_after_type(context, *type_ptr); - } - return true; -} -bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) +bool parse_next_is_decl(Context *context) { switch (context->tok.type) { @@ -732,33 +710,22 @@ bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr) case TOKEN_TYPE_IDENT: case TOKEN_CT_TYPE_IDENT: case TOKEN_ERROR_TYPE: - *type_ptr = parse_type(context); - return parse_type_or_expr_after_type(context, expr_ptr, type_ptr); - return true; + case TOKEN_TYPEID: + return context->next_tok.type == TOKEN_STAR || context->next_tok.type == TOKEN_LBRACKET || context->next_tok.type == TOKEN_IDENT; case TOKEN_IDENT: - if (context->next_tok.type == TOKEN_SCOPE) + if (context->next_tok.type != TOKEN_SCOPE) return false; + // We need a little lookahead to see if this is type or expression. + context_store_lexer_state(context); + do { - // We need a little lookahead to see if this is type or expression. - context_store_lexer_state(context); - do - { - advance(context); advance(context); - } while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); - if (context->tok.type == TOKEN_TYPE_IDENT) - { - context_restore_lexer_state(context); - *type_ptr = parse_type(context); - return parse_type_or_expr_after_type(context, expr_ptr, type_ptr); - } - context_restore_lexer_state(context); - } - break; + advance(context); advance(context); + } while (context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); + bool is_type = context->tok.type == TOKEN_TYPE_IDENT; + context_restore_lexer_state(context); + return is_type; default: - break; + return false; } - *expr_ptr = parse_expr(context); - return expr_ok(*expr_ptr); - } @@ -961,6 +928,7 @@ void add_struct_member(Decl *parent, Decl *parent_struct, Decl *member, TypeInfo vec_add(parent_struct->strukt.members, member); member->member_decl.index = index; member->member_decl.reference_type = type_new(TYPE_MEMBER, member->name); + member->member_decl.reference_type->canonical = member->member_decl.reference_type; member->member_decl.reference_type->decl = member; member->member_decl.type_info = type; member->member_decl.parent = parent; @@ -1961,38 +1929,6 @@ void parse_file(Context *context) -/** - * method_ref - * : '.' IDENT - * ; - * - * @param type - * @return Expr - */ -static Expr *parse_type_access(Context *context, TypeInfo *type) -{ - Expr *expr = EXPR_NEW_TOKEN(EXPR_TYPE_ACCESS, context->tok); - expr->span = type->span; - expr->type_access.type = type; - - advance_and_verify(context, TOKEN_DOT); - expr->type_access.name = context->tok; - - switch (context->tok.type) - { - case TOKEN_MACRO: - case TOKEN_IDENT: - case TOKEN_CONST_IDENT: - advance(context); - RANGE_EXTEND_PREV(expr); - return expr; - default: - SEMA_TOKEN_ERROR(context->tok, "Expected a function name, macro, or constant."); - return poisoned_expr; - } -} - - diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index cd253a6e8..5d0ad3efd 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -42,18 +42,17 @@ Ast *parse_decl_expr_list(Context *context); Ast* parse_compound_stmt(Context *context); Ast *parse_jump_stmt_no_eos(Context *context); Expr *parse_expression_list(Context *context); -bool parse_type_or_expr(Context *context, Expr **expr_ptr, TypeInfo **type_ptr); Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type); bool parse_param_list(Context *context, Expr ***result, bool allow_type); Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *type_info); Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info); +bool parse_next_is_decl(Context *context); void error_at_current(Context *context, const char* message, ...); bool try_consume(Context *context, TokenType type); bool consume(Context *context, TokenType type, const char *message, ...); bool consume_const_name(Context *context, const char* type); Expr *parse_precedence_with_left_side(Context *context, Expr *left_side, Precedence precedence); - static inline bool expect(Context *context, TokenType token_type) { if (token_type == context->tok.type) return true; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 371fe84b0..004016072 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -375,7 +375,7 @@ static inline bool sema_analyse_method(Context *context, Decl *decl) { TypeInfo *parent_type = decl->func.type_parent; if (!sema_resolve_type_info(context, parent_type)) return false; - if (!type_may_have_method(parent_type->type)) + if (!type_may_have_sub_elements(parent_type->type)) { SEMA_ERROR(decl, "Methods can not be associated with '%s'", diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 9ba5ae4b7..5eacc256a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -15,6 +15,7 @@ static Expr **expr_copy_expr_list_from_macro(Context *context, Expr *macro, Expr static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_expr); static Ast *ast_copy_from_macro(Context *context, Expr *macro, Ast *source); static Ast **ast_copy_list_from_macro(Context *context, Expr *macro, Ast **to_copy); +static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr); #define MACRO_COPY_EXPR(x) x = expr_copy_from_macro(context, macro, x) #define MACRO_COPY_TYPE(x) x = type_info_copy_from_macro(context, macro, x) @@ -695,56 +696,6 @@ static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *exp return true; } -static inline bool sema_expr_analyse_access(Context *context, Expr *expr) -{ - if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false; - - assert(expr->expr_kind == EXPR_ACCESS); - assert(expr->access_expr.parent->resolve_status == RESOLVE_DONE); - - Type *parent_type = expr->access_expr.parent->type; - Type *type = parent_type->canonical; - bool is_pointer = type->type_kind == TYPE_POINTER; - if (is_pointer) - { - type = type->pointer; - } - if (!type_may_have_method(type)) - { - SEMA_ERROR(expr, "Cannot access '%s' on '%s'", expr->access_expr.sub_element.string, type_to_error_string(parent_type)); - return false; - } - Decl *decl = type->decl; - switch (decl->decl_kind) - { - case DECL_ENUM: - case DECL_ERROR: - return sema_expr_analyse_method(context, expr, decl, is_pointer); - case DECL_STRUCT: - case DECL_UNION: - break; - default: - UNREACHABLE - } - Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); - if (!member) - { - return sema_expr_analyse_method(context, expr, decl, is_pointer); - return false; - } - if (is_pointer) - { - Expr *deref = expr_new(EXPR_UNARY, expr->span); - deref->unary_expr.operator = UNARYOP_DEREF; - deref->unary_expr.expr = expr->access_expr.parent; - deref->resolve_status = RESOLVE_DONE; - deref->type = type; - expr->access_expr.parent = deref; - } - expr->type = member->type; - expr->access_expr.ref = member; - return true; -} static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value) { @@ -754,7 +705,7 @@ static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, expr_to_rewrite->resolve_status = true; } -static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr) +static bool sema_expr_analyse_type_access(Context *context, Type *to, Expr *expr) { TypeInfo *type_info = expr->type_access.type; if (!sema_resolve_type_info(context, type_info)) return false; @@ -767,7 +718,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp expr->resolve_status = RESOLVE_DONE; return true; } - if (!type_may_have_method(canonical)) + if (!type_may_have_sub_elements(canonical)) { SEMA_ERROR(expr, "'%s' does not have methods.", type_to_error_string(type_info->type)); return false; @@ -838,7 +789,7 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp if (expr->type_access.name.string == member->name) { expr->type_access.decl = member; - expr->type = member->type; + expr->type = member->member_decl.reference_type; return true; } } @@ -846,6 +797,151 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp return false; } +static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr) +{ + Type *type = expr->access_expr.parent->type->decl->member_decl.type_info->type; + Type *canonical = type->canonical; + Token token = expr->access_expr.sub_element; + const char *sub_element = token.string; + if (sub_element == kw_sizeof) + { + expr_rewrite_to_int_const(expr, type_usize, type_size(canonical)); + return true; + } + if (sub_element == kw_offsetof) + { + TODO // calculate offset. + } + // Possibly alignof + if (!type_may_have_sub_elements(type)) + { + SEMA_ERROR(expr, "'%s' does not have a member '%s'.", type_to_error_string(type), sub_element); + return false; + } + Decl *decl = canonical->decl; + + switch (decl->decl_kind) + { + case DECL_ENUM: + if (token.type == TOKEN_CONST_IDENT) + { + if (!sema_expr_analyse_enum_constant(expr, sub_element, decl)) + { + SEMA_ERROR(expr, + "'%s' has no enumeration value '%s'.", + decl->name, + sub_element); + return false; + } + return true; + } + break; + case DECL_ERROR: + if (expr->type_access.name.type == TOKEN_CONST_IDENT) + { + if (!sema_expr_analyse_error_constant(expr, sub_element, decl)) + { + SEMA_ERROR(expr, "'%s' has no error type '%s'.", decl->name, sub_element); + return false; + } + return true; + } + break; + case DECL_UNION: + case DECL_STRUCT: + break; + default: + UNREACHABLE + } + + VECEACH(decl->methods, i) + { + Decl *function = decl->methods[i]; + if (sub_element == function->name) + { + expr->access_expr.ref = function; + expr->type = function->type; + return true; + } + } + + if (decl_is_struct_type(decl)) + { + VECEACH(decl->strukt.members, i) + { + Decl *member = decl->strukt.members[i]; + if (sub_element == member->name) + { + expr->access_expr.ref = member; + expr->type = member->member_decl.reference_type; + return true; + } + } + } + SEMA_ERROR(expr, + "No function or member '%s.%s' found.", + type_to_error_string(type), + sub_element); + return false; +} + + +static inline bool sema_expr_analyse_access(Context *context, Expr *expr) +{ + if (!sema_analyse_expr(context, NULL, expr->access_expr.parent)) return false; + + assert(expr->expr_kind == EXPR_ACCESS); + assert(expr->access_expr.parent->resolve_status == RESOLVE_DONE); + + Type *parent_type = expr->access_expr.parent->type; + Type *type = parent_type->canonical; + + if (type->type_kind == TYPE_MEMBER) + { + return sema_expr_analyse_member_access(context, expr); + } + bool is_pointer = type->type_kind == TYPE_POINTER; + if (is_pointer) + { + type = type->pointer; + } + if (!type_may_have_sub_elements(type)) + { + SEMA_ERROR(expr, "Cannot access '%s' on '%s'", expr->access_expr.sub_element.string, type_to_error_string(parent_type)); + return false; + } + Decl *decl = type->decl; + switch (decl->decl_kind) + { + case DECL_ENUM: + case DECL_ERROR: + return sema_expr_analyse_method(context, expr, decl, is_pointer); + case DECL_STRUCT: + case DECL_UNION: + break; + default: + UNREACHABLE + } + Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); + if (!member) + { + return sema_expr_analyse_method(context, expr, decl, is_pointer); + return false; + } + if (is_pointer) + { + Expr *deref = expr_new(EXPR_UNARY, expr->span); + deref->unary_expr.operator = UNARYOP_DEREF; + deref->unary_expr.expr = expr->access_expr.parent; + deref->resolve_status = RESOLVE_DONE; + deref->type = type; + expr->access_expr.parent = deref; + } + expr->type = member->type; + expr->access_expr.ref = member; + return true; +} + static DesignatedPath *sema_analyse_init_path(Context *context, DesignatedPath *parent, Expr *expr, bool *has_found_match, bool *has_reported_error); static DesignatedPath *sema_analyse_init_identifier_string(Context *context, DesignatedPath *parent_path, const char *string, bool *has_found_match, bool *has_reported_error) diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index e1108bcdc..61af11a82 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -38,6 +38,7 @@ const char *attribute_list[NUMBER_OF_ATTRIBUTES]; const char *kw_main; const char *kw_sizeof; +const char *kw_offsetof; void symtab_init(uint32_t capacity) { @@ -73,6 +74,7 @@ void symtab_init(uint32_t capacity) #define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type) kw_main = KW_DEF("main"); kw_sizeof = KW_DEF("sizeof"); + kw_offsetof = KW_DEF("offsetof"); attribute_list[ATTRIBUTE_INLINE] = KW_DEF("inline"); attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline"); attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall"); diff --git a/src/compiler/types.c b/src/compiler/types.c index c8b036081..93eac5bf0 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -560,7 +560,7 @@ bool type_is_subtype(Type *type, Type *possible_subtype) } -bool type_may_have_method(Type *type) +bool type_may_have_sub_elements(Type *type) { // An alias is not ok. switch (type->type_kind)