diff --git a/README.md b/README.md index bfaed6969..ef6cd3509 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ C3 is a C-like language trying to be "an incremental improvement over C" rather C3 owes a lot to the ideas of the [C2 language](http://c2lang.org): to iterate on top of C without trying to be a whole new language. -C3 tries to be an alternative in the the C/C++ niche: fast and close to the metal. +C3 tries to be an alternative in the C/C++ niche: fast and close to the metal. ### Design Principles - Procedural "get things done"-type of language. -- Try to stay close to C - only change where truly needed. +- Try to stay close to C - only change what's really necessary. - C ABI compatibility and excellent C integration. - Learning C3 should be easy for a C programmer. - Data is inert. @@ -31,12 +31,12 @@ func void main() - No mandatory header files - New semantic macro system -- Generic modules -- Module based -- Subarrays (slices) and vararrays built in +- Module based name spacing +- Subarrays (slices) and dynamic arrays built in - Compile time reflection - Enhanced compile time execution -- "Result" based zero overhead error handling +- Generics based on generic modules +- "Result"-based zero overhead error handling - Defer - Value methods - Associated enum data @@ -53,6 +53,8 @@ developer of Judge0. Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have any suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue] (https://github.com/c3lang/c3c/issues) or discuss C3 on its dedicated Discord: https://discord.gg/qN76R87 +The compiler should compile on Linux and MacOS, but needs some development love to +work on Windows. Also, parts of the code is still rough and needs to be made solid. #### Todo / done @@ -85,39 +87,41 @@ C3 on its dedicated Discord: https://discord.gg/qN76R87 - [x] `typeof` - [x] 2s complement wrapping operators - [x] Labelled break / continue -- [x] `next` statement +- [x] `nextcase` statement - [x] Expression blocks - [x] Do-without-while - [x] Foreach statement +- [x] Generic modules +- [x] Distinct types +- [x] Built-in linking +- [x] CT only macros evaluating to constants +- [x] range initializers e.g. `{ [1..2] = 2 }` +- [ ] Anonymous structs +- [ ] Complete C ABI conformance *in progress* +- [ ] Debug info *in progress* +- [ ] Virtual type +- [ ] Enum associated data support +- [ ] Windows support - [ ] All attributes - [ ] Associative array literals - [ ] CT type constants - [ ] Reflection methods -- [ ] Anonymous structs -- [x] Distinct types - [ ] LTO/ThinLTO setup -- [x] Built-in linking - [ ] `global` / `shared` for globals - [ ] Complex macros -- [x] CT only macros evaluating to constants - [ ] Escape macros - [ ] Implicit capturing macros - [ ] Trailing body macros - [ ] Subarray initializers -- [x] range initializers e.g. `{ [1..2] = 2 }` - [ ] Bitstructs - [ ] `asm` section - [ ] `$switch` - [ ] `$for` - [ ] Pre-post conditions - [ ] Stdlib inclusion -- [ ] Generic modules - [ ] String functions -- [ ] Vararrays e.g. `int[*]` - [ ] Compile time incremental arrays -- [ ] Complete C ABI conformance *in progress* -- [ ] Generic functions -- [ ] Debug info *in progress* +- [ ] Vararrays e.g. `int[*]` - [ ] Simd vector types - [ ] Complex types @@ -125,8 +129,9 @@ C3 on its dedicated Discord: https://discord.gg/qN76R87 - If you wish to contribute with ideas, please file issues on the c3docs: https://github.com/c3lang/c3docs instead of the compiler. - Discuss the language on discord to help iron out syntax. -- Stdlib work will soon start, do you want to help out building the C3 std lib? -- Do you want to do real compiler work? Everyone is welcome to contribute. +- Interested in contributing to the stdlib? Please get in touch on Discord. +- Are you a Windows dev? Please help make the compiler work on Windows! +- Install instructions for other Linux and Unix variants are appreciated. #### Installing on Ubuntu diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 8e0c8084c..eddb38fd2 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -109,6 +109,48 @@ void* compile_on_pthread(void *gencontext) return (void *)llvm_codegen(gencontext); } #endif + +void sema_analyze_stage(Module *module, AnalysisStage stage) +{ + while (module->stage < stage) + { + module->stage++; + switch (module->stage) + { + case ANALYSIS_NOT_BEGUN: + UNREACHABLE + case ANALYSIS_IMPORTS: + sema_analysis_pass_process_imports(module); + break; + case ANALYSIS_REGISTER_GLOBALS: + sema_analysis_pass_register_globals(module); + break; + case ANALYSIS_CONDITIONAL_COMPILATION: + sema_analysis_pass_conditional_compilation(module); + break; + case ANALYSIS_DECLS: + sema_analysis_pass_decls(module); + break; + case ANALYSIS_CT_ASSERT: + sema_analysis_pass_ct_assert(module); + break; + case ANALYSIS_FUNCTIONS: + sema_analysis_pass_functions(module); + break; + } + if (global_context.errors_found) return; + } +} + +static void analyze_to_stage(AnalysisStage stage) +{ + for (unsigned i = 0; i < vec_size(global_context.module_list); i++) + { + sema_analyze_stage(global_context.module_list[i], stage); + } + halt_on_error(); +} + void compiler_compile(void) { Context **contexts = NULL; @@ -139,74 +181,29 @@ void compiler_compile(void) error_exit("No source files to compile."); } assert(contexts); + for (AnalysisStage stage = ANALYSIS_NOT_BEGUN + 1; stage <= ANALYSIS_LAST; stage++) + { + analyze_to_stage(stage); + } + Module **modules = global_context.module_list; - unsigned module_count = vec_size(modules); - for (unsigned i = 0; i < module_count; i++) - { - sema_analysis_pass_process_imports(modules[i]); - } - - halt_on_error(); - - for (unsigned i = 0; i < module_count; i++) - { - sema_analysis_pass_register_globals(modules[i]); - } - - halt_on_error(); - - for (unsigned i = 0; i < source_count; i++) - { - sema_analysis_pass_conditional_compilation(contexts[i]); - } - - halt_on_error(); - - for (unsigned i = 0; i < source_count; i++) - { - sema_analysis_pass_decls(contexts[i]); - } - - halt_on_error(); - - for (unsigned i = 0; i < source_count; i++) - { - sema_analysis_pass_ct_assert(contexts[i]); - } - - halt_on_error(); - - for (unsigned i = 0; i < source_count; i++) - { - sema_analysis_pass_functions(contexts[i]); - } - - halt_on_error(); if (active_target.output_headers) { - for (unsigned i = 0; i < source_count; i++) + for (unsigned i = 0; i < module_count; i++) { - Context *context = contexts[i]; - if (context->module->parameters) break; - header_gen(context); + header_gen(modules[i]); } return; } - llvm_codegen_setup(); void **gen_contexts = malloc(module_count * sizeof(void *)); for (unsigned i = 0; i < module_count; i++) { - if (!modules[i]->contexts) - { - gen_contexts[i] = NULL; - continue; - } gen_contexts[i] = llvm_gen(modules[i]); } @@ -241,7 +238,7 @@ void compiler_compile(void) if (!gen_contexts[i]) continue; pthread_create(&threads[i], NULL, &compile_on_pthread, gen_contexts[i]); } - for (unsigned i = 0; i < source_count; i++) + for (unsigned i = 0; i < module_count; i++) { void *file_name; pthread_join(threads[i], &file_name); @@ -392,6 +389,7 @@ Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters) // Set up the module. module = CALLOCS(Module); module->name = module_name; + module->stage = ANALYSIS_NOT_BEGUN; module->parameters = parameters; stable_init(&module->symbols, 0x10000); stable_set(&global_context.modules, module_name->module, module); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index e91210fca..6cbeb4f55 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -429,11 +429,30 @@ typedef struct Path *path; // For redefinition } GenericDecl; +typedef enum +{ + DEFINE_FUNC, + DEFINE_DISTINCT_TYPE, + DEFINE_TYPE_ALIAS, + DEFINE_IDENT_ALIAS, +} DefineType; + typedef struct { - Path *path; + DefineType define_kind: 5; + bool is_parameterized : 1; + union + { + FunctionSignature function_signature; + TypeInfo *type_info; + struct + { + Path *path; + TokenId identifier; + }; + Decl *alias; + }; Expr **params; - TokenId name; } DefineDecl; typedef struct @@ -1144,6 +1163,7 @@ typedef struct _Module bool is_c_library : 1; bool is_exported : 1; bool is_generic : 1; + AnalysisStage stage : 6; Ast **files; // Asts @@ -1480,7 +1500,7 @@ const char *llvm_codegen(void *context); void *llvm_gen(Module *module); void llvm_codegen_setup(); -void header_gen(Context *context); +void header_gen(Module *module); void global_context_add_type(Type *type); Decl *compiler_find_symbol(const char *name); @@ -1511,6 +1531,14 @@ static inline bool decl_ok(Decl *decl) { return !decl || decl->decl_kind != DECL static inline bool decl_poison(Decl *decl) { decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false; } static inline bool decl_is_struct_type(Decl *decl); static inline DeclKind decl_from_token(TokenType type); +static inline Decl *decl_flatten(Decl *decl) +{ + if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind == DEFINE_IDENT_ALIAS) + { + return decl->define_decl.alias; + } + return decl; +} #pragma mark --- Diag functions @@ -1596,10 +1624,11 @@ const char *resolve_status_to_string(ResolveStatus status); void sema_analysis_pass_process_imports(Module *module); void sema_analysis_pass_register_globals(Module *module); -void sema_analysis_pass_conditional_compilation(Context *context); -void sema_analysis_pass_decls(Context *context); -void sema_analysis_pass_ct_assert(Context *context); -void sema_analysis_pass_functions(Context *context); +void sema_analysis_pass_conditional_compilation(Module *module); +void sema_analysis_pass_decls(Module *module); +void sema_analysis_pass_ct_assert(Module *module); +void sema_analysis_pass_functions(Module *module); +void sema_analyze_stage(Module *module, AnalysisStage stage); bool sema_add_member(Context *context, Decl *decl); bool sema_add_local(Context *context, Decl *decl); @@ -1890,7 +1919,7 @@ static inline Type *type_flatten_distinct(Type *type) type = type->canonical; while (type->type_kind == TYPE_DISTINCT) { - type = type->decl->distinct_decl.base_type->canonical; + type = type->decl->define_decl.type_info->type->canonical; } return type; } @@ -1999,23 +2028,23 @@ static inline bool type_is_promotable_float(Type *type) return type_is_float(type->canonical) && type->builtin.bytesize < type_double->builtin.bytesize; } -#define MACRO_COPY_DECL(x) x = copy_decl(context, x) -#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(context, x) -#define MACRO_COPY_EXPR(x) x = copy_expr(context, x) -#define MACRO_COPY_TYPE(x) x = copy_type_info(context, x) -#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(context, x) -#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(context, x) -#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(context, x) -#define MACRO_COPY_AST(x) x = copy_ast(context, x) +#define MACRO_COPY_DECL(x) x = copy_decl(x) +#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(x) +#define MACRO_COPY_EXPR(x) x = copy_expr(x) +#define MACRO_COPY_TYPE(x) x = copy_type_info(x) +#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(x) +#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(x) +#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(x) +#define MACRO_COPY_AST(x) x = copy_ast(x) -Expr **copy_expr_list(Context *context, Expr **expr_list); -Expr *copy_expr(Context *context, Expr *source_expr); -Ast *copy_ast(Context *context, Ast *source); -Ast **copy_ast_list(Context *context, Ast **to_copy); -Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy); -Decl *copy_decl(Context *context, Decl *decl); -Decl **copy_decl_list(Context *context, Decl **decl_list); -TypeInfo *copy_type_info(Context *context, TypeInfo *source); +Expr **copy_expr_list(Expr **expr_list); +Expr *copy_expr(Expr *source_expr); +Ast *copy_ast(Ast *source); +Ast **copy_ast_list(Ast **to_copy); +Decl *decl_copy_local_from_macro(Decl *to_copy); +Decl *copy_decl(Decl *decl); +Decl **copy_decl_list(Decl **decl_list); +TypeInfo *copy_type_info(TypeInfo *source); /** * Minimum alignment, values are either offsets or alignments. diff --git a/src/compiler/copying.c b/src/compiler/copying.c index ec6095ccc..555ea58b5 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -1,27 +1,27 @@ #include "compiler_internal.h" -Expr **copy_expr_list(Context *context, Expr **expr_list) +Expr **copy_expr_list(Expr **expr_list) { Expr **result = NULL; VECEACH(expr_list, i) { - vec_add(result, copy_expr(context, expr_list[i])); + vec_add(result, copy_expr(expr_list[i])); } return result; } -static inline Decl *decl_copy_label_from_macro(Context *context, Decl *to_copy, Ast *ast) +static inline Decl *decl_copy_label_from_macro(Decl *to_copy, Ast *ast) { if (!to_copy) return NULL; - to_copy = decl_copy_local_from_macro(context, to_copy); + to_copy = decl_copy_local_from_macro(to_copy); to_copy->label.parent = astid(ast); return to_copy; } -static inline void copy_flow(Context *context, Ast *ast) +static inline void copy_flow(Ast *ast) { - ast->flow.label = decl_copy_label_from_macro(context, ast->flow.label, ast); + ast->flow.label = decl_copy_label_from_macro(ast->flow.label, ast); } static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to_copy) @@ -29,13 +29,13 @@ static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to TypeInfo **result = NULL; VECEACH(to_copy, i) { - vec_add(result, copy_type_info(context, to_copy[i])); + vec_add(result, copy_type_info(to_copy[i])); } return result; } -static DesignatorElement** macro_copy_designator_list(Context *context, DesignatorElement **list) +static DesignatorElement **macro_copy_designator_list(DesignatorElement **list) { DesignatorElement **result = NULL; VECEACH(list, i) @@ -63,7 +63,7 @@ static DesignatorElement** macro_copy_designator_list(Context *context, Designat } -Expr *copy_expr(Context *context, Expr *source_expr) +Expr *copy_expr(Expr *source_expr) { if (!source_expr) return NULL; Expr *expr = COPY(source_expr); @@ -82,7 +82,7 @@ Expr *copy_expr(Context *context, Expr *source_expr) // TODO return expr; case EXPR_DESIGNATOR: - expr->designator_expr.path = macro_copy_designator_list(context, expr->designator_expr.path); + expr->designator_expr.path = macro_copy_designator_list(expr->designator_expr.path); MACRO_COPY_EXPR(expr->designator_expr.value); return expr; case EXPR_TYPEINFO: @@ -191,7 +191,7 @@ Expr *copy_expr(Context *context, Expr *source_expr) UNREACHABLE } -Ast *copy_ast(Context *context, Ast *source) +Ast *copy_ast(Ast *source) { if (!source) return NULL; Ast *ast = COPY(source); @@ -237,7 +237,7 @@ Ast *copy_ast(Context *context, Ast *source) } return ast; case AST_CATCH_STMT: - copy_flow(context, ast); + copy_flow(ast); if (ast->catch_stmt.has_err_var) { MACRO_COPY_DECL(ast->catch_stmt.err_var); @@ -296,14 +296,14 @@ Ast *copy_ast(Context *context, Ast *source) MACRO_COPY_AST(ast->case_stmt.body); return ast; case AST_DEFINE_STMT: - ast->define_stmt = copy_decl(context, ast->define_stmt); + ast->define_stmt = copy_decl(ast->define_stmt); return ast; case AST_DEFER_STMT: assert(!ast->defer_stmt.prev_defer); MACRO_COPY_AST(ast->defer_stmt.body); return ast; case AST_DO_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_AST(ast->do_stmt.body); MACRO_COPY_EXPR(ast->do_stmt.expr); return ast; @@ -311,21 +311,21 @@ Ast *copy_ast(Context *context, Ast *source) MACRO_COPY_EXPR(ast->expr_stmt); return ast; case AST_FOR_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_EXPR(ast->for_stmt.cond); MACRO_COPY_EXPR(ast->for_stmt.incr); MACRO_COPY_AST(ast->for_stmt.body); MACRO_COPY_EXPR(ast->for_stmt.init); return ast; case AST_FOREACH_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_DECL(ast->foreach_stmt.index); MACRO_COPY_DECL(ast->foreach_stmt.variable); MACRO_COPY_EXPR(ast->foreach_stmt.enumeration); MACRO_COPY_AST(ast->for_stmt.body); return ast; case AST_IF_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_EXPR(ast->if_stmt.cond); MACRO_COPY_AST(ast->if_stmt.else_body); MACRO_COPY_AST(ast->if_stmt.then_body); @@ -340,7 +340,7 @@ Ast *copy_ast(Context *context, Ast *source) MACRO_COPY_EXPR(ast->return_stmt.expr); return ast; case AST_SWITCH_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_EXPR(ast->switch_stmt.cond); MACRO_COPY_AST_LIST(ast->switch_stmt.cases); return ast; @@ -354,7 +354,7 @@ Ast *copy_ast(Context *context, Ast *source) TODO return ast; case AST_WHILE_STMT: - copy_flow(context, ast); + copy_flow(ast); MACRO_COPY_EXPR(ast->while_stmt.cond); MACRO_COPY_AST(ast->while_stmt.body); return ast; @@ -366,27 +366,27 @@ Ast *copy_ast(Context *context, Ast *source) } -Ast** copy_ast_list(Context *context, Ast **to_copy) +Ast **copy_ast_list(Ast **to_copy) { Ast **result = NULL; VECEACH(to_copy, i) { - vec_add(result, copy_ast(context, to_copy[i])); + vec_add(result, copy_ast(to_copy[i])); } return result; } -Decl** copy_decl_list(Context *context, Decl **to_copy) +Decl **copy_decl_list(Decl **decl_list) { Decl **result = NULL; - VECEACH(to_copy, i) + VECEACH(decl_list, i) { - vec_add(result, copy_decl(context, to_copy[i])); + vec_add(result, copy_decl(decl_list[i])); } return result; } -Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy) +Decl *decl_copy_local_from_macro(Decl *to_copy) { if (!to_copy) return NULL; assert(to_copy->decl_kind == DECL_VAR); @@ -396,8 +396,7 @@ Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy) return copy; } - -TypeInfo *copy_type_info(Context *context, TypeInfo *source) +TypeInfo *copy_type_info(TypeInfo *source) { if (!source) return NULL; TypeInfo *copy = malloc_arena(sizeof(TypeInfo)); @@ -410,63 +409,92 @@ TypeInfo *copy_type_info(Context *context, TypeInfo *source) return copy; case TYPE_INFO_EXPRESSION: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->unresolved_type_expr = copy_expr(context, source->unresolved_type_expr); + copy->unresolved_type_expr = copy_expr(source->unresolved_type_expr); return copy; case TYPE_INFO_ARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.len = copy_expr(context, source->array.len); - copy->array.base = copy_type_info(context, source->array.base); + copy->array.len = copy_expr(source->array.len); + copy->array.base = copy_type_info(source->array.base); return copy; case TYPE_INFO_INC_ARRAY: case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_VARARRAY: case TYPE_INFO_SUBARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.base = copy_type_info(context, source->array.base); + copy->array.base = copy_type_info(source->array.base); return copy; case TYPE_INFO_POINTER: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->pointer = copy_type_info(context, source->pointer); + copy->pointer = copy_type_info(source->pointer); return copy; } UNREACHABLE } -static void copy_function_signature_deep(Context *context, FunctionSignature *signature) +static void copy_function_signature_deep(FunctionSignature *signature) { MACRO_COPY_DECL_LIST(signature->params); MACRO_COPY_TYPE(signature->rtype); assert(!signature->failable_abi_info); assert(!signature->ret_abi_info); } -Decl *copy_decl(Context *context, Decl *decl) +void copy_decl_type(Decl *decl) +{ + Type *type = decl->type; + Type *copy = type_new(type->type_kind, type->name); + *copy = *type; + copy->type_cache = NULL; + copy->decl = decl; + copy->canonical = copy; + decl->type = copy; +} + +static Attr **copy_attributes(Attr** attr_list) +{ + if (!attr_list) return attr_list; + Attr** list = NULL; + VECEACH(attr_list, i) + { + Attr *attribute = attr_list[i]; + Attr *copy = MALLOC(sizeof(Attr)); + *copy = *attribute; + MACRO_COPY_EXPR(copy->expr); + vec_add(list, copy); + } + return list; +} +Decl *copy_decl(Decl *decl) { if (!decl) return NULL; Decl *copy = COPY(decl); MACRO_COPY_AST(copy->docs); - // Copy attributes? Yes! + copy->attributes = copy_attributes(copy->attributes); switch (decl->decl_kind) { case DECL_POISONED: break; case DECL_UNION: case DECL_STRUCT: + case DECL_ERR: + copy_decl_type(copy); MACRO_COPY_DECL_LIST(copy->strukt.members); MACRO_COPY_DECL_LIST(copy->methods); break; case DECL_ENUM: + copy_decl_type(copy); MACRO_COPY_DECL_LIST(copy->methods); MACRO_COPY_DECL_LIST(copy->enums.parameters); MACRO_COPY_TYPE(copy->enums.type_info); MACRO_COPY_DECL_LIST(copy->enums.values); break; case DECL_INTERFACE: + copy_decl_type(copy); MACRO_COPY_DECL_LIST(copy->interface_decl.functions); break; case DECL_FUNC: MACRO_COPY_TYPE(copy->func.type_parent); copy->func.annotations = NULL; - copy_function_signature_deep(context, ©->func.function_signature); + copy_function_signature_deep(©->func.function_signature); MACRO_COPY_AST(copy->func.body); break; case DECL_VAR: @@ -490,7 +518,7 @@ Decl *copy_decl(Context *context, Decl *decl) case DECL_TYPEDEF: if (copy->typedef_decl.is_func) { - copy_function_signature_deep(context, ©->typedef_decl.function_signature); + copy_function_signature_deep(©->typedef_decl.function_signature); break; } MACRO_COPY_TYPE(copy->typedef_decl.type_info); @@ -499,24 +527,54 @@ Decl *copy_decl(Context *context, Decl *decl) MACRO_COPY_DECL_LIST(copy->distinct_decl.methods); if (copy->distinct_decl.typedef_decl.is_func) { - copy_function_signature_deep(context, ©->distinct_decl.typedef_decl.function_signature); + copy_function_signature_deep(©->distinct_decl.typedef_decl.function_signature); break; } MACRO_COPY_TYPE(copy->distinct_decl.typedef_decl.type_info); break; - case DECL_ERR: - case DECL_ARRAY_VALUE: - case DECL_IMPORT: - case DECL_MACRO: - case DECL_GENERIC: case DECL_CT_IF: + MACRO_COPY_EXPR(decl->ct_if_decl.expr); + MACRO_COPY_DECL(decl->ct_if_decl.elif); + MACRO_COPY_DECL_LIST(decl->ct_if_decl.then); + break; case DECL_CT_ELSE: + MACRO_COPY_DECL_LIST(decl->ct_else_decl); + break; case DECL_CT_ELIF: + MACRO_COPY_EXPR(decl->ct_elif_decl.expr); + MACRO_COPY_DECL(decl->ct_elif_decl.elif); + MACRO_COPY_DECL_LIST(decl->ct_elif_decl.then); + break; + case DECL_IMPORT: + break; + case DECL_ARRAY_VALUE: + TODO + case DECL_MACRO: + MACRO_COPY_DECL_LIST(decl->macro_decl.parameters); + MACRO_COPY_AST(decl->macro_decl.body); + MACRO_COPY_TYPE(decl->macro_decl.rtype); + break; + case DECL_GENERIC: + TODO case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: - case DECL_DEFINE: TODO + case DECL_DEFINE: + MACRO_COPY_EXPR_LIST(decl->define_decl.params); + switch (decl->define_decl.define_kind) + { + case DEFINE_FUNC: + copy_function_signature_deep(&decl->define_decl.function_signature); + break; + case DEFINE_DISTINCT_TYPE: + case DEFINE_TYPE_ALIAS: + MACRO_COPY_TYPE(decl->define_decl.type_info); + break; + case DEFINE_IDENT_ALIAS: + break; + } + break; } return copy; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 9612f648a..a7ebc4f09 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -629,3 +629,14 @@ typedef enum CALL_AARCH64_VECTOR, } CallABI; +typedef enum +{ + ANALYSIS_NOT_BEGUN, + ANALYSIS_IMPORTS, + ANALYSIS_REGISTER_GLOBALS, + ANALYSIS_CONDITIONAL_COMPILATION, + ANALYSIS_DECLS, + ANALYSIS_CT_ASSERT, + ANALYSIS_FUNCTIONS, + ANALYSIS_LAST = ANALYSIS_FUNCTIONS +} AnalysisStage; \ No newline at end of file diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 099cb87b3..8170765ab 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -239,8 +239,10 @@ static void header_gen_var(FILE *file, Context *c, Decl *decl) fprintf(file, "/* vars */\n"); } -void header_gen(Context *context) +void header_gen(Module *module) { + TODO + Context *context = module->contexts[0]; const char *filename = strcat_arena(context->file->name, ".h"); FILE *file = fopen(filename, "w"); OUTPUT("#include \n"); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 26ec0686d..f8d187098 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -372,7 +372,7 @@ static void gencontext_emit_global_variable_init(GenContext *c, Decl *decl) // TODO fix name LLVMValueRef old = decl->backend_ref; - decl->backend_ref = LLVMAddGlobal(c->module, LLVMTypeOf(init_value), decl->name); + decl->backend_ref = LLVMAddGlobal(c->module, LLVMTypeOf(init_value), decl->external_name); llvm_set_alignment(decl->backend_ref, alignment); if (decl->visibility != VISIBLE_EXTERN) { @@ -403,6 +403,7 @@ static void gencontext_emit_global_variable_init(GenContext *c, Decl *decl) decl->backend_ref = LLVMConstBitCast(decl->backend_ref, llvm_get_ptr_type(c, decl->type)); } LLVMReplaceAllUsesWith(old, decl->backend_ref); + LLVMDeleteGlobal(old); // Should we set linkage here? if (llvm_use_debug(c)) @@ -750,6 +751,7 @@ void llvm_value_set_address_align(BEValue *value, LLVMValueRef llvm_value, Type } void llvm_value_set_decl_address(BEValue *value, Decl *decl) { + decl = decl_flatten(decl); llvm_value_set_address(value, decl_ref(decl), decl->type); value->alignment = decl->alignment; @@ -943,6 +945,7 @@ const char *llvm_codegen(void *context) void *llvm_gen(Module *module) { + if (!vec_size(module->contexts)) return NULL; assert(intrinsics_setup); GenContext *gen_context = calloc(sizeof(GenContext), 1); gencontext_init(gen_context, module); diff --git a/src/compiler/llvm_codegen_c_abi_x64.c b/src/compiler/llvm_codegen_c_abi_x64.c index ec3a4061d..d36a04e03 100644 --- a/src/compiler/llvm_codegen_c_abi_x64.c +++ b/src/compiler/llvm_codegen_c_abi_x64.c @@ -576,6 +576,7 @@ AbiType *x64_get_sse_type_at_offset(Type *type, unsigned ir_offset, Type *source AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_type, unsigned source_offset) { + type = type_flatten(type); switch (type->type_kind) { case TYPE_U64: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 67a66367c..f88d8fb4f 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2424,6 +2424,7 @@ static void llvm_emit_fp_intrinsic_expr(GenContext *c, unsigned intrinsic_id, BE void gencontext_emit_call_intrinsic_expr(GenContext *c, BEValue *be_value, Expr *expr) { Decl *function_decl = expr->call_expr.function->identifier_expr.decl; + function_decl = decl_flatten(function_decl); if (function_decl->name == kw___round) { llvm_emit_fp_intrinsic_expr(c, intrinsic_id_rint, be_value, expr); @@ -2634,6 +2635,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr) { // 3. Call a regular function. Decl *function_decl = expr->call_expr.function->identifier_expr.decl; + function_decl = decl_flatten(function_decl); // 3a. This may be an intrinsic, if so generate an intrinsic call instead. if (function_decl->func.is_builtin) diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index d01254dac..ed24a39ab 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -975,6 +975,38 @@ bool parse_next_is_decl(Context *context) } } +bool parse_next_is_type(Context *context) +{ + TokenType next_tok = context->next_tok.type; + switch (context->tok.type) + { + case TOKEN_VOID: + case TOKEN_CHAR: + case TOKEN_BOOL: + case TOKEN_ICHAR: + case TOKEN_DOUBLE: + case TOKEN_FLOAT: + case TOKEN_INT: + case TOKEN_ISIZE: + case TOKEN_LONG: + case TOKEN_SHORT: + case TOKEN_UINT: + case TOKEN_ULONG: + case TOKEN_USHORT: + case TOKEN_USIZE: + case TOKEN_QUAD: + case TOKEN_TYPE_IDENT: + case TOKEN_CT_TYPE_IDENT: + case TOKEN_ERR: + case TOKEN_TYPEID: + return true; + case TOKEN_IDENT: + if (next_tok != TOKEN_SCOPE) return false; + return context_next_is_type_with_path_prefix(context); + default: + return false; + } +} bool parse_next_is_case_type(Context *context) @@ -1431,53 +1463,127 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi } /** - * define_decl ::= DEFINE path? (IDENT | TYPE_IDENT | CONST_IDENT) '(' expr (',' expr)* ')' as (IDENT | TYPE_IDENT | CONST_IDENT) + * define_parameters ::= '(' expr (',' expr)* ')' + * + * @return NULL if parsing failed, otherwise a list of Expr* */ -static inline Decl *parse_define(Context *context, Visibility visibility) +static inline Expr **parse_parameterized_define(Context *context, Visibility visibility) { - if (context->next_tok.type == TOKEN_CT_TYPE_IDENT || context->next_tok.type == TOKEN_CT_IDENT) - { - SEMA_TOKEN_ERROR(context->next_tok, "Compile time variables cannot be defined at the global level."); - return poisoned_decl; - } - TokenId first = context->tok.id; - advance_and_verify(context, TOKEN_DEFINE); - bool had_error = false; - Path *path = parse_path_prefix(context, &had_error); - if (had_error) return poisoned_decl; - if (!token_is_symbol(context->tok.type)) - { - SEMA_TOKEN_ERROR(context->tok, "Expected an identifier here."); - return poisoned_decl; - } - TokenId name = context->tok.id; - advance(context); - CONSUME_OR(TOKEN_LPAREN, poisoned_decl); + CONSUME_OR(TOKEN_LPAREN, NULL); Expr **exprs = NULL; while (!try_consume(context, TOKEN_RPAREN)) { - Expr *expr = TRY_EXPR_OR(parse_constant_expr(context), poisoned_decl); + Expr *expr = TRY_EXPR_OR(parse_constant_expr(context), NULL); vec_add(exprs, expr); if (context->tok.type != TOKEN_RPAREN) { - TRY_CONSUME_OR(TOKEN_COMMA, "Expected ',' after argument.", poisoned_decl); + TRY_CONSUME_OR(TOKEN_COMMA, "Expected ',' after argument.", NULL); } } - TRY_CONSUME_OR(TOKEN_AS, "Expected 'as' after generic declaration.", poisoned_decl); + return exprs; +} + +/** + * func_define ::= failable_type opt_parameter_type_list + */ +static inline bool parse_func_define(Context *context, Decl *decl, Visibility visibility) +{ + decl->define_decl.define_kind = DEFINE_FUNC; + advance_and_verify(context, TOKEN_FUNC); + TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), false); + if (try_consume(context, TOKEN_BANG)) + { + decl->define_decl.function_signature.failable = true; + } + decl->define_decl.function_signature.rtype = type_info; + if (!parse_opt_parameter_type_list(context, visibility, &(decl->typedef_decl.function_signature), true)) + { + return false; + } + return true; +} + +/** + * define_decl ::= DEFINE path? (IDENT | TYPE_IDENT | CONST_IDENT) define_parameters? as (IDENT | TYPE_IDENT | CONST_IDENT) + */ +static inline Decl *parse_define(Context *context, Visibility visibility) +{ + advance_and_verify(context, TOKEN_DEFINE); + Decl *decl = decl_new(DECL_DEFINE, context->tok.id, visibility); + if (try_consume(context, TOKEN_FUNC)) + { + if (!parse_func_define(context, decl, visibility)) return poisoned_decl; + } + else if (parse_next_is_type(context)) + { + decl->define_decl.define_kind = DEFINE_TYPE_ALIAS; + decl->define_decl.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); + } + else if (TOKEN_IS(TOKEN_IDENT) || TOKEN_IS(TOKEN_CONST_IDENT)) + { + decl->define_decl.path = NULL; + if (context->next_tok.type == TOKEN_SCOPE) + { + bool error; + decl->define_decl.path = parse_path_prefix(context, &error); + if (error) return poisoned_decl; + } + decl->define_decl.identifier = context->tok.id; + if (try_consume(context, TOKEN_CONST_IDENT) || try_consume(context, TOKEN_IDENT)) + { + decl->define_decl.define_kind = DEFINE_IDENT_ALIAS; + } + else + { + SEMA_TOKEN_ERROR(context->tok, "Expected an identifier, constant or type."); + return poisoned_decl; + } + } + else + { + SEMA_TOKEN_ERROR(context->tok, "Expected a constant, type or identifier here."); + return poisoned_decl; + } + + Expr **exprs = NULL; + if (TOKEN_IS(TOKEN_LPAREN)) + { + exprs = parse_parameterized_define(context, visibility); + if (!exprs) return poisoned_decl; + TRY_CONSUME_OR(TOKEN_AS, "Expected 'as' after the generic declaration, did you forget it", poisoned_decl); + decl->define_decl.is_parameterized = true; + decl->define_decl.params = exprs; + } + else + { + TRY_CONSUME_OR(TOKEN_AS, "Expected 'as' after the name, did you forget it?", poisoned_decl); + } + + // Parse optional "distinct" + if (context->tok.type == TOKEN_IDENT && TOKSTR(context->tok) == kw_distinct) + { + if (decl->define_decl.define_kind != DEFINE_TYPE_ALIAS || decl->define_decl.is_parameterized) + { + SEMA_TOKID_ERROR(context->tok.id, "'distinct' can only be used for regular types."); + return poisoned_decl; + } + advance(context); + decl->define_decl.define_kind = DEFINE_DISTINCT_TYPE; + } + + decl->name = TOKSTR(context->tok); + decl->name_token = context->tok.id; + if (!token_is_symbol(context->tok.type)) { SEMA_TOKEN_ERROR(context->tok, "The aliased name must follow after 'as'."); return poisoned_decl; } - Decl *decl = decl_new(DECL_DEFINE, context->tok.id, visibility); - decl->define_decl.path = path; - decl->define_decl.params = exprs; - decl->define_decl.name = name; - decl->span = (SourceSpan){ first, context->tok.id }; - advance(context); - TRY_CONSUME_EOS_OR(poisoned_decl); + advance(context); + CONSUME_OR(TOKEN_EOS, poisoned_decl); return decl; + } @@ -1569,7 +1675,6 @@ static inline bool parse_func_typedef(Context *context, Decl *decl, Visibility v return false; } return true; - } /** diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 9692817d6..bbc15e8a3 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -58,6 +58,7 @@ Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *ty Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info); bool parse_next_is_decl(Context *context); bool parse_next_is_case_type(Context *context); +bool parse_next_is_type(Context *context); bool parse_module(Context *context); Decl *parse_define_compile_time_variable(Context *context, bool global); bool try_consume(Context *context, TokenType type); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index c68f05917..82948d526 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -723,6 +723,11 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib return type; case ATTRIBUTE_SECTION: case ATTRIBUTE_CNAME: + if (context->module->is_generic) + { + SEMA_TOKID_ERROR(attr->name, "'cname' attributes are not allowed in generic modules."); + return false; + } if (!attr->expr) { SEMA_TOKID_ERROR(attr->name, "'%s' requires a string argument, e.g. %s(\"foo\").", TOKSTR(attr->name), TOKSTR(attr->name)); @@ -1031,14 +1036,100 @@ static bool sema_analyse_plain_define(Context *c, Decl *decl, Decl *symbol) TODO } +static Context *copy_context(Module *module, Context *c) +{ + Context *copy = context_create(c->file); + copy->imports = copy_decl_list(c->imports); + copy->global_decls = copy_decl_list(c->global_decls); + copy->module = module; + assert(!c->functions && !c->methods && !c->enums && !c->ct_ifs && !c->types && !c->interfaces && !c->external_symbol_list); + return copy; +} + static Module *sema_instantiate_module(Context *context, Module *module, Path *path, Expr **parms) { Module *new_module = compiler_find_or_create_module(path, NULL); - new_module->functions = copy_decl_list(context, module->functions); - TODO + new_module->is_generic = true; + Context **contexts = module->contexts; + VECEACH(contexts, i) + { + vec_add(new_module->contexts, copy_context(new_module, contexts[i])); + } + Context *first_context = new_module->contexts[0]; + VECEACH(module->parameters, i) + { + TokenId param = module->parameters[i]; + Decl *decl = decl_new_with_type(param, DECL_TYPEDEF, VISIBLE_PUBLIC); + decl->resolve_status = RESOLVE_DONE; + Expr *type_info_expr = parms[i]; + assert(type_info_expr->expr_kind == EXPR_TYPEINFO); + assert(type_info_expr->type_expr->resolve_status == RESOLVE_DONE); + decl->typedef_decl.type_info = type_info_expr->type_expr; + decl->type->name = decl->name; + decl->type->canonical = type_info_expr->type_expr->type->canonical; + vec_add(first_context->global_decls, decl); + } + return new_module; } -static bool sema_analyse_parameterized_define(Context *c, Decl *decl, Module *module) + +static Decl *sema_analyse_parameterized_define(Context *c, Decl *decl) { + TokenId define_ident;; + TypeInfo *define_type; + if (decl->define_decl.define_kind == DEFINE_TYPE_ALIAS) + { + define_type = decl->define_decl.type_info; + } + else + { + define_ident = decl->define_decl.identifier; + } + Path *decl_path; + bool mismatch = false; + const char *name; + SourceSpan mismatch_span = INVALID_RANGE; + switch (decl->define_decl.define_kind) + { + case DEFINE_IDENT_ALIAS: + decl_path = decl->define_decl.path; + name = TOKSTR(define_ident); + break; + case DEFINE_TYPE_ALIAS: + mismatch_span = define_type->span; + decl_path = define_type->unresolved.path; + name = TOKSTR(define_type->unresolved.name_loc); + mismatch = define_type->kind != TYPE_INFO_IDENTIFIER; + break; + default: + UNREACHABLE + } + if (mismatch) + { + sema_error_range(mismatch_span, "A variable, type or constant was expected here."); + return poisoned_decl; + } + if (!decl_path) + { + sema_error_range(mismatch_span, "Parameterization requires the full path, please add it."); + return poisoned_decl; + } + Decl *import_found = NULL; + VECEACH(c->imports, i) + { + Decl *import = c->imports[i]; + if (decl_path->module == import->import.path->module) + { + import_found = import; + break; + } + } + if (!import_found) + { + sema_error_range(mismatch_span, "It was not possible to find a matching module, did you use the full path?"); + return poisoned_decl; + } + + Module *module = import_found->module; Expr **params = decl->define_decl.params; unsigned parameter_count = vec_size(module->parameters); assert(parameter_count > 0); @@ -1046,81 +1137,119 @@ static bool sema_analyse_parameterized_define(Context *c, Decl *decl, Module *mo { sema_error_range((SourceSpan) { params[0]->span.loc, VECLAST(params)->span.end_loc }, "The generic module expected %d arguments, but you only supplied %d, did you make a mistake?", parameter_count, vec_size(decl->define_decl.params)); - return false; + return poisoned_decl; } - char *param_path = global_context.scratch_buffer; - memcpy(param_path, module->name->module, module->name->len); - unsigned offset = module->name->len; - param_path[offset++] = '('; + scratch_buffer_clear(); + scratch_buffer_append_len(module->name->module, module->name->len); + scratch_buffer_append_char('.'); VECEACH(decl->define_decl.params, i) { Expr *expr = decl->define_decl.params[i]; if (expr->expr_kind != EXPR_TYPEINFO) { SEMA_ERROR(expr, "A generic module can only take plain types as arguments."); - return false; + return poisoned_decl; } - if (!sema_resolve_type_info(c, expr->type_expr)) return false; - if (i != 0) param_path[offset++] = ','; + if (!sema_resolve_type_info(c, expr->type_expr)) return poisoned_decl; + if (i != 0) scratch_buffer_append_char('.'); const char *type_name = expr->type_expr->type->canonical->name; - unsigned len = strlen(type_name); - memcpy(param_path + offset, type_name, len); - offset += len; + scratch_buffer_append(type_name); } - param_path[offset++] = ')'; - param_path[offset] = '\0'; TokenType ident_type = TOKEN_IDENT; - const char *path_string = symtab_add(param_path, offset, fnv1a(param_path, offset), &ident_type); + const char *res = scratch_buffer_to_string(); + size_t len = global_context.scratch_buffer_len; + const char *path_string = symtab_add(res, len, fnv1a(res, len), &ident_type); Module *instantiated_module = global_context_find_module(path_string); if (!instantiated_module) { Path *path = CALLOCS(Path); path->module = path_string; path->span = module->name->span; - path->len = offset; + path->len = len; instantiated_module = sema_instantiate_module(c, module, path, decl->define_decl.params); - TODO + sema_analyze_stage(instantiated_module, c->module->stage - 1); } - TODO + Decl *symbol = module_find_symbol(instantiated_module, name); + if (!symbol) + { + SEMA_ERROR(decl, "Identifier '%s' could not be found.", name); + return poisoned_decl; + } + if (symbol->visibility <= VISIBLE_MODULE && !import_found->import.private) + { + SEMA_TOKID_ERROR(decl->name_token, "'%s' is not visible from this module.", symbol->name); + return poisoned_decl; + } + context_register_external_symbol(c, symbol); + return symbol; } +static void decl_define_type(Decl *decl, Type *actual_type) +{ + Type *type = type_new(TYPE_TYPEDEF, decl->name); + type->decl = decl; + type->canonical = actual_type->canonical; + decl->type = type; +} + static inline bool sema_analyse_define(Context *c, Decl *decl) { - Path *path = decl->define_decl.path; - if (path) + Decl *symbol; + if (decl->define_decl.is_parameterized) { - VECEACH(c->imports, i) + symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), poisoned_decl); + } + else + { + switch (decl->define_decl.define_kind) { - Decl *import = c->imports[i]; - if (path->module == import->import.path->module) + case DEFINE_FUNC: { - return sema_analyse_parameterized_define(c, decl, import->module); + Type *func_type = sema_analyse_function_signature(c, &decl->define_decl.function_signature, false); + if (!func_type) return false; + decl_define_type(decl, type_get_ptr(func_type)); + return true; + } + case DEFINE_TYPE_ALIAS: + if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false; + decl_define_type(decl, decl->define_decl.type_info->type); + return true; + case DEFINE_DISTINCT_TYPE: + { + if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false; + Type *type = type_new(TYPE_DISTINCT, decl->name); + type->decl = decl; + type->canonical = type; + decl->type = type; + return true; + } + case DEFINE_IDENT_ALIAS: + { + Decl *ambiguous_decl = NULL; + Decl *private_symbol = NULL; + symbol = sema_resolve_symbol(c, + TOKSTR(decl->define_decl.identifier), + decl->define_decl.path, + &ambiguous_decl, + &private_symbol); + if (!symbol) TODO; + break; } } } - Decl *ambiguous_decl = NULL; - Decl *private_decl = NULL; - Decl *symbol = sema_resolve_symbol(c, TOKSTR(decl->define_decl.name), decl->define_decl.path, &ambiguous_decl, &private_decl); - if (!symbol) + switch (decl->define_decl.define_kind) { - if (private_decl) - { - SEMA_TOKID_ERROR(decl->define_decl.name, "'%s' is not visible from this module.", private_decl->name); - } - else if (ambiguous_decl) - { - SEMA_TOKID_ERROR(decl->define_decl.name, "The name '%s' ambiguous, please add a path.", ambiguous_decl->name); - } - else - { - SEMA_TOKID_ERROR(decl->define_decl.name, "Identifier '%s' could not be found.", TOKSTR(decl->define_decl.name)); - } - return false; + case DEFINE_FUNC: + case DEFINE_DISTINCT_TYPE: + UNREACHABLE + case DEFINE_TYPE_ALIAS: + decl_define_type(decl, symbol->type); + break; + case DEFINE_IDENT_ALIAS: + decl->type = symbol->type; + decl->define_decl.alias = symbol; + break; } - if (vec_size(decl->define_decl.params) > 0) - { - sema_error_range((SourceSpan) { decl->define_decl.params[0]->span.loc, VECLAST(decl->define_decl.params)->span.end_loc }, "Using 'define' with arguments is only for generic modules, did you add arguments by accident?"); - } - return sema_analyse_plain_define(c, decl, symbol); + return true; } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index fb930c762..8db0e51af 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -162,6 +162,7 @@ static bool expr_is_ltype(Expr *expr) static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr) { Decl *decl = expr->identifier_expr.decl; + decl = decl_flatten(decl); expr->identifier_expr.is_rvalue = true; switch (decl->decl_kind) @@ -218,16 +219,16 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr { case VARDECL_CONST: if (!type_is_builtin(decl->type->type_kind)) break; - expr_replace(expr, copy_expr(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(decl->var.init_expr)); return sema_analyse_expr(context, to, expr); case VARDECL_PARAM_EXPR: - expr_replace(expr, copy_expr(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(decl->var.init_expr)); assert(decl->var.init_expr->resolve_status == RESOLVE_DONE); return true; case VARDECL_PARAM_CT_TYPE: TODO case VARDECL_PARAM_REF: - expr_replace(expr, copy_expr(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(decl->var.init_expr)); return sema_cast_rvalue(context, to, expr); case VARDECL_PARAM: case VARDECL_GLOBAL: @@ -619,7 +620,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr case VARDECL_CONST: if (!decl->type) { - Expr *copy = copy_expr(context, decl->var.init_expr); + Expr *copy = copy_expr(decl->var.init_expr); if (!sema_analyse_expr(context, to, copy)) return false; if (!expr_is_constant_eval(copy)) { @@ -716,7 +717,7 @@ static inline bool sema_expr_analyse_hash_identifier(Context *context, Type *to, assert(decl->resolve_status == RESOLVE_DONE); assert(decl->var.init_expr->resolve_status == RESOLVE_DONE); - expr_replace(expr, copy_expr(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(decl->var.init_expr)); return sema_analyse_expr(context, to, expr); } @@ -1185,7 +1186,7 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr for (unsigned i = 0; i < num_args; i++) { Expr *arg = args[i]; - Decl *param = copy_decl(context, func_params[i]); + Decl *param = copy_decl(func_params[i]); vec_add(params, param); assert(param->decl_kind == DECL_VAR); assert(param->resolve_status == RESOLVE_NOT_DONE); @@ -1274,7 +1275,7 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr bool ok = true; - Ast *body = copy_ast(context, decl->macro_decl.body); + Ast *body = copy_ast(decl->macro_decl.body); TypeInfo *foo = decl->macro_decl.rtype; @@ -1341,6 +1342,8 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr return ok; } + + static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr) { expr->constant = false; @@ -1386,6 +1389,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr SEMA_ERROR(expr, "This value cannot be invoked, did you accidentally add ()?"); return false; } + decl = decl_flatten(decl); switch (decl->decl_kind) { case DECL_VAR: @@ -1399,9 +1403,10 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr case DECL_POISONED: return false; default: - SEMA_ERROR(expr, "The expression cannot be called."); - return false; + break; } + SEMA_ERROR(expr, "The expression cannot be called."); + return false; } static inline bool sema_expr_analyse_range(Context *context, Type *to, Expr *expr) @@ -4865,7 +4870,7 @@ bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, static inline bool sema_cast_ct_ident_rvalue(Context *context, Type *to, Expr *expr) { Decl *decl = expr->ct_ident_expr.decl; - Expr *copy = copy_expr(context, decl->var.init_expr); + Expr *copy = copy_expr(decl->var.init_expr); if (!sema_analyse_expr(context, to, copy)) return false; expr_replace(expr, copy); return true; diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 1f28e6e5d..1c68045af 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -19,6 +19,7 @@ void context_add_intrinsic(Context *context, const char *name) void sema_analysis_pass_process_imports(Module *module) { DEBUG_LOG("Pass: Importing dependencies for files in module '%s'.", module->name->module); + unsigned import_count = 0; VECEACH(module->contexts, index) { @@ -144,28 +145,32 @@ static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if) } -void sema_analysis_pass_conditional_compilation(Context *context) +void sema_analysis_pass_conditional_compilation(Module *module) { - // We never look at conditional compilation. - if (context->module->parameters) return; - DEBUG_LOG("Pass: Top level conditionals %s", context->file->name); - for (unsigned i = 0; i < vec_size(context->ct_ifs); i++) + DEBUG_LOG("Pass: Top level conditionals %s", module->name->module); + VECEACH(module->contexts, index) { - // Also handle switch! - sema_analyse_top_level_if(context, context->ct_ifs[i]); + Context *context = module->contexts[index]; + for (unsigned i = 0; i < vec_size(context->ct_ifs); i++) + { + // Also handle switch! + sema_analyse_top_level_if(context, context->ct_ifs[i]); + } } DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } -void sema_analysis_pass_ct_assert(Context *context) +void sema_analysis_pass_ct_assert(Module *module) { - if (context->module->parameters) return; - - DEBUG_LOG("Pass: $assert checks %s", context->file->name); - VECEACH(context->ct_asserts, i) + DEBUG_LOG("Pass: $assert checks %s", module->name->module); + VECEACH(module->contexts, index) { - sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]); + Context *context = module->contexts[index]; + VECEACH(context->ct_asserts, i) + { + sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]); + } } DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } @@ -177,62 +182,68 @@ static inline bool analyse_func_body(Context *context, Decl *decl) return true; } -void sema_analysis_pass_decls(Context *context) +void sema_analysis_pass_decls(Module *module) { - if (context->module->parameters) return; + DEBUG_LOG("Pass: Decl analysis %s", module->name->module); - DEBUG_LOG("Pass: Decl analysis %s", context->file->name); - context->current_scope = &global_context.scopes[0]; - context->current_scope->scope_id = 0; - context->last_local = &global_context.locals[0]; - VECEACH(context->enums, i) + VECEACH(module->contexts, index) { - sema_analyse_decl(context, context->enums[i]); - } - VECEACH(context->types, i) - { - sema_analyse_decl(context, context->types[i]); - } - VECEACH(context->macros, i) - { - sema_analyse_decl(context, context->macros[i]); - } - VECEACH(context->generics, i) - { - sema_analyse_decl(context, context->generics[i]); - } - VECEACH(context->methods, i) - { - sema_analyse_decl(context, context->methods[i]); - } - VECEACH(context->vars, i) - { - sema_analyse_decl(context, context->vars[i]); - } - VECEACH(context->functions, i) - { - sema_analyse_decl(context, context->functions[i]); - } - VECEACH(context->generic_defines, i) - { - sema_analyse_decl(context, context->generic_defines[i]); + Context *context = module->contexts[index]; + context->current_scope = &global_context.scopes[0]; + context->current_scope->scope_id = 0; + context->last_local = &global_context.locals[0]; + VECEACH(context->enums, i) + { + sema_analyse_decl(context, context->enums[i]); + } + VECEACH(context->types, i) + { + sema_analyse_decl(context, context->types[i]); + } + VECEACH(context->macros, i) + { + sema_analyse_decl(context, context->macros[i]); + } + VECEACH(context->generics, i) + { + sema_analyse_decl(context, context->generics[i]); + } + VECEACH(context->methods, i) + { + sema_analyse_decl(context, context->methods[i]); + } + VECEACH(context->vars, i) + { + sema_analyse_decl(context, context->vars[i]); + } + VECEACH(context->functions, i) + { + sema_analyse_decl(context, context->functions[i]); + } + VECEACH(context->generic_defines, i) + { + sema_analyse_decl(context, context->generic_defines[i]); + } } DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } -void sema_analysis_pass_functions(Context *context) +void sema_analysis_pass_functions(Module *module) { - DEBUG_LOG("Pass: Function analysis %s", context->file->name); + DEBUG_LOG("Pass: Function analysis %s", module->name->module); - if (context->module->parameters) return; + VECEACH(module->contexts, index) + { + Context *context = module->contexts[index]; + VECEACH(context->methods, i) + { + analyse_func_body(context, context->methods[i]); + } + VECEACH(context->functions, i) + { + analyse_func_body(context, context->functions[i]); + } - VECEACH(context->methods, i) - { - analyse_func_body(context, context->methods[i]); - } - VECEACH(context->functions, i) - { - analyse_func_body(context, context->functions[i]); } DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 9f235019b..fa32a417f 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -119,6 +119,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ERR: case DECL_ENUM: case DECL_TYPEDEF: + case DECL_DEFINE: case DECL_DISTINCT: case DECL_INTERFACE: type_info->type = decl->type; @@ -151,7 +152,6 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ATTRIBUTE: case DECL_CT_SWITCH: case DECL_CT_CASE: - case DECL_DEFINE: UNREACHABLE } UNREACHABLE diff --git a/test/test_suite/arrays/array_struct.c3t b/test/test_suite/arrays/array_struct.c3t index d765fac87..556e084a0 100644 --- a/test/test_suite/arrays/array_struct.c3t +++ b/test/test_suite/arrays/array_struct.c3t @@ -10,4 +10,4 @@ Foo[10] array; // #expect: test.ll -@array = protected global [10 x %test.Foo] zeroinitializer, align 16 \ No newline at end of file +@test.array = protected global [10 x %test.Foo] zeroinitializer, align 16 \ No newline at end of file diff --git a/test/test_suite/arrays/complex_array_const.c3t b/test/test_suite/arrays/complex_array_const.c3t index 381e6ff0c..8a50ea175 100644 --- a/test/test_suite/arrays/complex_array_const.c3t +++ b/test/test_suite/arrays/complex_array_const.c3t @@ -15,7 +15,7 @@ Connection[3] link // #expect: test.ll -@.str = private constant [6 x i8] c"link1\00" -@.str.1 = private constant [6 x i8] c"link2\00" -@.str.2 = private constant [6 x i8] c"link3\00" -@link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16 +@.str = private constant [6 x i8] c"link1\00", align 1 +@.str.1 = private constant [6 x i8] c"link2\00", align 1 +@.str.2 = private constant [6 x i8] c"link3\00", align 1 +@test.link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16 diff --git a/test/test_suite/constants/char_literals.c3t b/test/test_suite/constants/char_literals.c3t index d843c7b5a..cc63b7a73 100644 --- a/test/test_suite/constants/char_literals.c3t +++ b/test/test_suite/constants/char_literals.c3t @@ -13,12 +13,12 @@ public char i = '\e'; // #expect: test.ll -@a = global i8 32 -@b = global i8 13 -@c = global i8 9 -@d = global i8 10 -@e = global i8 0 -@f = global i8 39 -@g = global i8 34 -@h = global i8 92 -@i = global i8 27 +@test.a = global i8 32, align 1 +@test.b = global i8 13, align 1 +@test.c = global i8 9, align 1 +@test.d = global i8 10, align 1 +@test.e = global i8 0, align 1 +@test.f = global i8 39, align 1 +@test.g = global i8 34, align 1 +@test.h = global i8 92, align 1 +@test.i = global i8 27, align 1 diff --git a/test/test_suite/constants/constants.c3t b/test/test_suite/constants/constants.c3t index 177bba937..49dc6a3f7 100644 --- a/test/test_suite/constants/constants.c3t +++ b/test/test_suite/constants/constants.c3t @@ -19,15 +19,15 @@ func void test() // #expect: constants.ll -@AA = protected constant i8 -1 -@BB = protected constant i8 -56 -@CC = protected constant i32 -1 -@DD = protected constant i32 -1 -@x = protected global i32 255 -@z = protected global i32 -1 -@w = protected global i8 -1 -@v = protected global i16 -1 -@z2 = protected global i32 -1 +@constants.AA = protected constant i8 -1, align 1 +@constants.BB = protected constant i8 -56, align 1 +@constants.CC = protected constant i32 -1, align 4 +@constants.DD = protected constant i32 -1, align 4 +@constants.x = protected global i32 255, align 4 +@constants.z = protected global i32 -1, align 4 +@constants.w = protected global i8 -1, align 1 +@constants.v = protected global i16 -1, align 2 +@constants.z2 = protected global i32 -1, align 4 entry: %xx = alloca i32 diff --git a/test/test_suite/pointers/const_pointer.c3t b/test/test_suite/pointers/const_pointer.c3t index a1f02cd56..efce8a9ed 100644 --- a/test/test_suite/pointers/const_pointer.c3t +++ b/test/test_suite/pointers/const_pointer.c3t @@ -10,7 +10,7 @@ void*[3] data = { &foo, &bar, &xx }; // #expect: const_pointer.ll -@foo = protected global double 1.700000e+01, align 8 -@bar = protected global double 1.200000e+01, align 8 -@xx = protected global float 1.200000e+01, align 4 -@data = protected global [3 x i8*] [i8* bitcast (double* @foo to i8*), i8* bitcast (double* @bar to i8*), i8* bitcast (float* @xx to i8*)], align 16 +@const_pointer.foo = protected global double 1.700000e+01, align 8 +@const_pointer.bar = protected global double 1.200000e+01, align 8 +@const_pointer.xx = protected global float 1.200000e+01, align 4 +@const_pointer.data = protected global [3 x i8*] [i8* bitcast (double* @const_pointer.foo to i8*), i8* bitcast (double* @const_pointer.bar to i8*), i8* bitcast (float* @const_pointer.xx to i8*)], align 16 diff --git a/test/test_suite/struct/simple_struct.c3t b/test/test_suite/struct/simple_struct.c3t index 7208ae0f6..5eb49eb47 100644 --- a/test/test_suite/struct/simple_struct.c3t +++ b/test/test_suite/struct/simple_struct.c3t @@ -11,4 +11,4 @@ struct Foo // #expect: test.ll %test.Foo = type { i32, double } -@a = protected global %test.Foo zeroinitializer, align 8 \ No newline at end of file +@test.a = protected global %test.Foo zeroinitializer, align 8 \ No newline at end of file diff --git a/test/test_suite/struct/struct_const_construct_simple.c3t b/test/test_suite/struct/struct_const_construct_simple.c3t index 2938a8615..acd19eff2 100644 --- a/test/test_suite/struct/struct_const_construct_simple.c3t +++ b/test/test_suite/struct/struct_const_construct_simple.c3t @@ -22,12 +22,12 @@ Foo foo8 = FOO7; %structo.Foo = type { i32, i64 } @Foo = linkonce_odr constant i8 1 -@x = protected global i64 16, align 8 -@foo1 = protected global %structo.Foo { i32 1, i64 2 }, align 8 -@foo2 = protected global %structo.Foo { i32 2, i64 0 }, align 8 -@foo3 = protected global %structo.Foo { i32 0, i64 3 }, align 8 -@foo4 = protected global %structo.Foo { i32 4, i64 1 }, align 8 -@foo5 = protected global %structo.Foo zeroinitializer, align 8 -@foo6 = protected global %structo.Foo zeroinitializer, align 8 -@FOO7 = protected constant %structo.Foo { i32 1, i64 2 }, align 8 -@foo8 = protected global %structo.Foo { i32 1, i64 2 }, align 8 +@structo.x = protected global i64 16, align 8 +@structo.foo1 = protected global %structo.Foo { i32 1, i64 2 }, align 8 +@structo.foo2 = protected global %structo.Foo { i32 2, i64 0 }, align 8 +@structo.foo3 = protected global %structo.Foo { i32 0, i64 3 }, align 8 +@structo.foo4 = protected global %structo.Foo { i32 4, i64 1 }, align 8 +@structo.foo5 = protected global %structo.Foo zeroinitializer, align 8 +@structo.foo6 = protected global %structo.Foo zeroinitializer, align 8 +@structo.FOO7 = protected constant %structo.Foo { i32 1, i64 2 }, align 8 +@structo.foo8 = protected global %structo.Foo { i32 1, i64 2 }, align 8 diff --git a/test/test_suite/struct/struct_pack_and_align.c3t b/test/test_suite/struct/struct_pack_and_align.c3t index 1866ea728..b52be0c01 100644 --- a/test/test_suite/struct/struct_pack_and_align.c3t +++ b/test/test_suite/struct/struct_pack_and_align.c3t @@ -76,12 +76,12 @@ public Foo6 foo6 = { 1, 2, 3 }; %struct2.Foo5 = type { i32, [12 x i8], i8, [15 x i8] } %struct2.Foo6 = type { i32, i16, i16 } -@foo1 = global %struct2.Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4 -@foo2 = global %struct2.Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4 -@foo3 = global %struct2.Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8 -@foo4 = global %struct2.Foo4 <{ i8 1, i64 2 }>, align 1 -@foo5 = global %struct2.Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16 -@foo6 = global %struct2.Foo6 { i32 1, i16 2, i16 3 }, align 1 +@struct2.foo1 = global %struct2.Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4 +@struct2.foo2 = global %struct2.Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4 +@struct2.foo3 = global %struct2.Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8 +@struct2.foo4 = global %struct2.Foo4 <{ i8 1, i64 2 }>, align 1 +@struct2.foo5 = global %struct2.Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16 +@struct2.foo6 = global %struct2.Foo6 { i32 1, i16 2, i16 3 }, align 1 @struct2.test5 entry: diff --git a/test/test_suite/union/union_codegen_const.c3t b/test/test_suite/union/union_codegen_const.c3t index 0704d9f03..574664bc1 100644 --- a/test/test_suite/union/union_codegen_const.c3t +++ b/test/test_suite/union/union_codegen_const.c3t @@ -13,8 +13,8 @@ Foo i = { .b = 2.3, .a = 23 }; // #expect: test.ll -@f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 -@g = protected global %test.Foo { double 2.300000e+00 }, align 8 -@h = protected global %test.Foo { double 2.300000e+00 }, align 8 -@i = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 +@test.f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 +@test.g = protected global %test.Foo { double 2.300000e+00 }, align 8 +@test.h = protected global %test.Foo { double 2.300000e+00 }, align 8 +@test.i = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 diff --git a/test/test_suite/union/union_in_struct.c3t b/test/test_suite/union/union_in_struct.c3t index 59e5e0286..3da70fa11 100644 --- a/test/test_suite/union/union_in_struct.c3t +++ b/test/test_suite/union/union_in_struct.c3t @@ -23,7 +23,7 @@ func void test(Blend_Map_Entry* foo) %test.Blend_Map_Entry = type { %test.vals } %test.vals = type { [2 x double], [8 x i8] } -@a = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8 -@b = protected global %test.Blend_Map_Entry { %test.vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8 -@c = protected global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8 -@d = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8 +@test.a = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8 +@test.b = protected global %test.Blend_Map_Entry { %test.vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8 +@test.c = protected global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8 +@test.d = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8