diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 50262c3ff..34164b79a 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -974,6 +974,46 @@ func void testMethodFunctions() printf("%d %d %d\n", x.x.x, x.x.y, x.x.z); } +enum TestEnumSize : ushort +{ + BLURB +} + +enum TestEnumSizeDefault +{ + BLURB +} + +struct TestStructSize +{ + char x; + long y; +} + +struct TestStructInt +{ + int a; + int b; + int c; +} + +union TestUnionSize +{ + short a; + int b; + char[5] c; +} +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); +} + func int main(int x) { printf("Helo!\n"); @@ -990,6 +1030,7 @@ func int main(int x) testExprBlock(); testFuncPointer(); testMethodFunctions(); + testTypeValues(); int efd = 9; uint fefoek = 1; printf("Helo: %d\n", efd + cast(fefoek, int)); diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 52159f7b1..251e3f861 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -335,6 +335,10 @@ void fprint_type_recursive(FILE *file, Type *type, int indent) case TYPE_ERROR: DUMPF("(error %s)", type->name); return; + case TYPE_MEMBER: + DUMPF("(member %s", type->name); + DUMPTYPE(type->decl->parent_struct->type); + DUMPEND(); case TYPE_TYPEDEF: DUMPF("(typedef %s", type->name); DUMPTYPE(type->canonical); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index caccabdda..27ccbbb72 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -189,7 +189,7 @@ struct _Type void *backend_debug_type; union { - // Error, Struct, Union, Typedef + // Error, Struct, Union, Typedef, Member Decl *decl; // int, float, bool TypeBuiltin builtin; @@ -415,7 +415,7 @@ typedef struct _Decl union { Decl* parent_struct; - Decl** method_functions; + Decl** methods; }; union { @@ -471,7 +471,7 @@ typedef struct union { Token name; - Decl *method; + Decl *decl; }; } ExprTypeAccess; @@ -949,7 +949,7 @@ typedef struct _Context Decl **error_types; Decl **types; Decl **functions; - Decl **method_functions; + Decl **methods; Decl **vars; Decl **ct_ifs; Ast **defers; @@ -1021,6 +1021,13 @@ typedef struct Type **type; } Compiler; +typedef enum +{ + MODULE_SYMBOL_SEARCH_EXTERNAL, + MODULE_SYMBOL_SEARCH_PARENT, + MODULE_SYMBOL_SEARCH_THIS +} ModuleSymbolSearch; + extern Compiler compiler; extern Ast *poisoned_ast; extern Decl *poisoned_decl; @@ -1041,7 +1048,8 @@ extern Type *type_typeid, *type_error_union, *type_error_base; extern const char *attribute_list[NUMBER_OF_ATTRIBUTES]; -extern const char *main_kw; +extern const char *kw_main; +extern const char *kw_sizeof; #define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, _token.span) #define AST_NEW(_kind, _loc) new_ast(_kind, _loc) @@ -1202,12 +1210,6 @@ void lexer_init_with_file(Lexer *lexer, File *file); File* lexer_current_file(Lexer *lexer); -typedef enum -{ - MODULE_SYMBOL_SEARCH_EXTERNAL, - MODULE_SYMBOL_SEARCH_PARENT, - MODULE_SYMBOL_SEARCH_THIS -} ModuleSymbolSearch; Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch search); @@ -1306,7 +1308,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_functions(Type *type); +bool type_may_have_method(Type *type); static inline Type *type_reduced(Type *type) { diff --git a/src/compiler/context.c b/src/compiler/context.c index 82bfba3eb..51f688007 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -96,7 +96,7 @@ void context_register_global_decl(Context *context, Decl *decl) case DECL_FUNC: if (decl->func.type_parent) { - vec_add(context->method_functions, decl); + vec_add(context->methods, decl); // TODO set name return; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 681c4ca61..03842bd41 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -507,6 +507,7 @@ typedef enum TYPE_VARARRAY, TYPE_SUBARRAY, TYPE_TYPEID, + TYPE_MEMBER, TYPE_LAST = TYPE_TYPEID } TypeKind; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 3168b1b41..4edb2afc6 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -358,9 +358,9 @@ void llvm_codegen(Context *context) { gencontext_emit_extern_decl(&gen_context, context->external_symbol_list[i]); } - VECEACH(context->method_functions, i) + VECEACH(context->methods, i) { - gencontext_emit_function_decl(&gen_context, context->method_functions[i]); + gencontext_emit_function_decl(&gen_context, context->methods[i]); } VECEACH(context->functions, i) { @@ -383,9 +383,9 @@ void llvm_codegen(Context *context) Decl *decl = context->functions[i]; if (decl->func.body) gencontext_emit_function_body(&gen_context, decl); } - VECEACH(context->method_functions, i) + VECEACH(context->methods, i) { - Decl *decl = context->method_functions[i]; + Decl *decl = context->methods[i]; if (decl->func.body) gencontext_emit_function_body(&gen_context, decl); } diff --git a/src/compiler/llvm_codegen_debug_info.c b/src/compiler/llvm_codegen_debug_info.c index 542d4d176..ff54ad4bb 100644 --- a/src/compiler/llvm_codegen_debug_info.c +++ b/src/compiler/llvm_codegen_debug_info.c @@ -108,6 +108,7 @@ LLVMMetadataRef gencontext_get_debug_type(GenContext *context, Type *type) case TYPE_IXX: case TYPE_FXX: case TYPE_TYPEID: + case TYPE_MEMBER: UNREACHABLE case TYPE_BOOL: return gencontext_simple_debug_type(context, type, DW_ATE_boolean); diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 53e992723..4e286bb10 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -165,7 +165,9 @@ LLVMTypeRef llvm_get_type(LLVMContextRef context, Type *type) DEBUG_LOG("Generating type %s", type->name); switch (type->type_kind) { + case TYPE_MEMBER: case TYPE_POISONED: + UNREACHABLE case TYPE_TYPEID: return type->backend_type = LLVMIntTypeInContext(context, type->builtin.bitsize); case TYPE_ERROR: diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 6deb8349f..9b4f74f58 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -1528,7 +1528,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit func->func.type_parent = type; advance_and_verify(context, TOKEN_TYPE_IDENT); - TRY_CONSUME_OR(TOKEN_DOT, "Expected '.' after the type in a method function.", poisoned_decl); + TRY_CONSUME_OR(TOKEN_DOT, "Expected '.' after the type in a method declaration.", poisoned_decl); } EXPECT_IDENT_FOR_OR("function name", poisoned_decl); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 5765c4766..c84e54dd4 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -796,6 +796,7 @@ CastKind cast_to_bool_kind(Type *type) case TYPE_ERROR: case TYPE_ENUM: case TYPE_FUNC: + case TYPE_MEMBER: case TYPE_ARRAY: case TYPE_VARARRAY: case TYPE_SUBARRAY: @@ -835,6 +836,7 @@ bool cast(Expr *expr, Type *to_type, CastType cast_type) case TYPE_POISONED: case TYPE_VOID: case TYPE_TYPEID: + case TYPE_MEMBER: break; case TYPE_BOOL: // Bool may convert into integers and floats but only explicitly. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index bc12898a6..a9ebfb911 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -410,30 +410,30 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl) -static inline bool sema_analyse_method_function(Context *context, Decl *decl) +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_functions(parent_type->type)) + if (!type_may_have_method(parent_type->type)) { SEMA_ERROR(decl, - "Method functions can not be associated with '%s'", + "Methods can not be associated with '%s'", type_to_error_string(decl->func.type_parent->type)); return false; } Decl *parent = parent_type->type->decl; - VECEACH(parent->method_functions, i) + VECEACH(parent->methods, i) { - Decl *function = parent->method_functions[i]; + Decl *function = parent->methods[i]; if (function->name == decl->name) { - SEMA_ERROR(decl, "Duplicate name '%s' for method function.", function->name); + SEMA_ERROR(decl, "Duplicate name '%s' for method.", function->name); SEMA_PREV(function, "Previous definition here."); return false; } } - DEBUG_LOG("Method function '%s.%s' analysed.", parent->name, decl->name); - vec_add(parent->method_functions, decl); + DEBUG_LOG("Method '%s.%s' analysed.", parent->name, decl->name); + vec_add(parent->methods, decl); return true; } @@ -563,7 +563,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) if (!func_type) return decl_poison(decl); if (decl->func.type_parent) { - if (!sema_analyse_method_function(context, decl)) return decl_poison(decl); + if (!sema_analyse_method(context, decl)) return decl_poison(decl); } VECEACH(decl->attributes, i) { @@ -608,7 +608,7 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) return decl_poison(decl); } } - if (decl->name == main_kw) + if (decl->name == kw_main) { if (decl->visibility == VISIBLE_LOCAL) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 108d8f18a..693fe07e3 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -480,7 +480,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr switch (func_expr->expr_kind) { case EXPR_TYPE_ACCESS: - decl = func_expr->type_access.method; + decl = func_expr->type_access.decl; break; case EXPR_IDENTIFIER: decl = func_expr->identifier_expr.decl; @@ -641,12 +641,12 @@ static inline bool sema_expr_analyse_subscript(Context *context, Type *to, Expr return sema_expr_analyse_subscript_after_parent_resolution(context, NULL, expr); } -static inline bool sema_expr_analyse_method_function(Context *context, Expr *expr, Decl *decl, bool is_pointer) +static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *decl, bool is_pointer) { const char *name = expr->access_expr.sub_element.string; - VECEACH(decl->method_functions, i) + VECEACH(decl->methods, i) { - Decl *function = decl->method_functions[i]; + Decl *function = decl->methods[i]; if (function->name == name) { expr->access_expr.ref = function; @@ -657,11 +657,11 @@ static inline bool sema_expr_analyse_method_function(Context *context, Expr *exp if (decl_is_struct_type(decl)) { - SEMA_ERROR(expr, "There is no element nor method function '%s.%s'.", decl->name, name); + SEMA_ERROR(expr, "There is no element nor method '%s.%s'.", decl->name, name); } else { - SEMA_ERROR(expr, "Cannot find method function '%s.%s'", decl->name, name); + SEMA_ERROR(expr, "Cannot find method '%s.%s'", decl->name, name); } return false; } @@ -706,7 +706,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) { type = type->pointer; } - if (!type_may_have_method_functions(type)) + 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; @@ -716,7 +716,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) { case DECL_ENUM: case DECL_ERROR: - return sema_expr_analyse_method_function(context, expr, decl, is_pointer); + return sema_expr_analyse_method(context, expr, decl, is_pointer); case DECL_STRUCT: case DECL_UNION: break; @@ -726,7 +726,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) Decl *member = strukt_recursive_search_member(decl, expr->access_expr.sub_element.string); if (!member) { - return sema_expr_analyse_method_function(context, expr, decl, is_pointer); + return sema_expr_analyse_method(context, expr, decl, is_pointer); return false; } if (is_pointer) @@ -743,6 +743,13 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr) return true; } +static inline void expr_rewrite_to_int_const(Expr *expr_to_rewrite, Type *type, uint64_t value) +{ + expr_to_rewrite->expr_kind = EXPR_CONST; + expr_const_set_int(&expr_to_rewrite->const_expr, value, type->canonical->type_kind); + 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) { @@ -757,9 +764,9 @@ 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_functions(canonical)) + if (!type_may_have_method(canonical)) { - SEMA_ERROR(expr, "'%s' does not have method functions.", type_to_error_string(type_info->type)); + SEMA_ERROR(expr, "'%s' does not have methods.", type_to_error_string(type_info->type)); return false; } Decl *decl = canonical->decl; @@ -777,6 +784,11 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp } return true; } + if (expr->type_access.name.start == kw_sizeof) + { + expr_rewrite_to_int_const(expr, type_usize, type_size(decl->enums.type_info->type)); + return true; + } break; case DECL_ERROR: if (expr->type_access.name.type == TOKEN_CONST_IDENT) @@ -788,24 +800,46 @@ static inline bool sema_expr_analyse_type_access(Context *context, Type *to, Exp } return true; } + if (expr->type_access.name.start == kw_sizeof) + { + expr_rewrite_to_int_const(expr, type_usize, type_size(type_error_base->canonical)); + return true; + } break; case DECL_UNION: case DECL_STRUCT: + if (expr->type_access.name.start == kw_sizeof) + { + expr_rewrite_to_int_const(expr, type_usize, type_size(decl->type)); + return true; + } break; default: UNREACHABLE } - VECEACH(type_info->type->decl->method_functions, i) + + + VECEACH(decl->methods, i) { - Decl *function = type_info->type->decl->method_functions[i]; + Decl *function = decl->methods[i]; if (expr->type_access.name.string == function->name) { - expr->type_access.method = function; - expr->type = function->func.function_signature.rtype->type; + expr->type_access.decl = function; + expr->type = function->type; return true; } } - SEMA_ERROR(expr, "No function '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string); + VECEACH(decl->strukt.members, i) + { + Decl *member = decl->strukt.members[i]; + if (expr->type_access.name.string == member->name) + { + expr->type_access.decl = member; + expr->type = member->type; + return true; + } + } + SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(type_info->type), expr->type_access.name.string); return false; } @@ -2018,6 +2052,7 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp case TYPE_VARARRAY: case TYPE_SUBARRAY: case TYPE_TYPEID: + case TYPE_MEMBER: // Only != and == allowed. goto ERR; case ALL_INTS: @@ -2259,6 +2294,7 @@ static bool sema_expr_analyse_not(Context *context, Type *to, Expr *expr, Expr * case TYPE_ENUM: case TYPE_ERROR: case TYPE_TYPEID: + case TYPE_MEMBER: SEMA_ERROR(expr, "Cannot use 'not' on %s", type_to_error_string(inner->type)); return false; } diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 719b82b73..0568e4c6f 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -114,9 +114,9 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->error_types[i]); } - VECEACH(context->method_functions, i) + VECEACH(context->methods, i) { - sema_analyse_decl(context, context->method_functions[i]); + sema_analyse_decl(context, context->methods[i]); } VECEACH(context->vars, i) { @@ -126,9 +126,9 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->functions[i]); } - VECEACH(context->method_functions, i) + VECEACH(context->methods, i) { - analyse_func_body(context, context->method_functions[i]); + analyse_func_body(context, context->methods[i]); } VECEACH(context->functions, i) { diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 21dcb8148..e1108bcdc 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -36,7 +36,8 @@ static SymTab symtab; const char *attribute_list[NUMBER_OF_ATTRIBUTES]; -const char *main_kw; +const char *kw_main; +const char *kw_sizeof; void symtab_init(uint32_t capacity) { @@ -70,7 +71,8 @@ void symtab_init(uint32_t capacity) // Init some constant idents TokenType type = TOKEN_IDENT; #define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type) - main_kw = KW_DEF("main"); + kw_main = KW_DEF("main"); + kw_sizeof = KW_DEF("sizeof"); 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 4ba5e390f..d3213346d 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -133,6 +133,8 @@ const char *type_to_error_string(Type *type) } asprintf(&buffer, "%s*", type_to_error_string(type->pointer)); return buffer; + case TYPE_MEMBER: + return "member"; case TYPE_STRING: return "string"; case TYPE_ARRAY: @@ -236,6 +238,8 @@ size_t type_size(Type *canonical) case ALL_INTS: case ALL_FLOATS: return canonical->builtin.bytesize; + case TYPE_MEMBER: + return type_size(canonical->decl->var.type_info->type); case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: @@ -272,6 +276,8 @@ unsigned int type_abi_alignment(Type *canonical) case ALL_FLOATS: case TYPE_ERROR_UNION: return canonical->builtin.abi_alignment; + case TYPE_MEMBER: + return type_abi_alignment(canonical->decl->var.type_info->type); case TYPE_FUNC: case TYPE_POINTER: case TYPE_VARARRAY: @@ -552,7 +558,7 @@ bool type_is_subtype(Type *type, Type *possible_subtype) } -bool type_may_have_method_functions(Type *type) +bool type_may_have_method(Type *type) { // An alias is not ok. switch (type->type_kind) @@ -737,6 +743,7 @@ Type *type_find_max_type(Type *type, Type *other) case TYPE_ERROR: if (other->type_kind == TYPE_ERROR) return type_error_union; return NULL; + case TYPE_MEMBER: case TYPE_FUNC: case TYPE_UNION: case TYPE_ERROR_UNION: