diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f143d55c..7edd98501 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,6 +109,7 @@ add_executable(c3c src/compiler/llvm_codegen.c src/utils/stringutils.c src/compiler/dwarf.h + src/compiler/copying.c src/compiler/llvm_codegen_stmt.c src/compiler/llvm_codegen_expr.c src/compiler/llvm_codegen_debug_info.c diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index e13965749..cec5122f4 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -17,12 +17,21 @@ Vmem tokdata_arena; Vmem decl_arena; Vmem type_info_arena; +static void global_context_clear_errors(void) +{ + global_context.in_panic_mode = false; + global_context.errors_found = 0; + global_context.warnings_found = 0; +} + void compiler_init(const char *std_lib_dir) { // Skip library detection. //compiler.lib_dir = find_lib_dir(); //DEBUG_LOG("Found std library: %s", compiler.lib_dir); stable_init(&global_context.modules, 64); + global_context.module_list = NULL; + global_context.generic_module_list = NULL; stable_init(&global_context.global_symbols, 0x1000); vmem_init(&ast_arena, 4 * 1024); vmem_init(&expr_arena, 4 * 1024); @@ -73,7 +82,8 @@ void compiler_parse(void) bool loaded = false; File *file = source_file_load(global_context.sources[i], &loaded); if (loaded) continue; - diag_setup(active_target.test_output); + + global_context_clear_errors(); Context *context = context_create(file); parse_file(context); context_print_ast(context, stdout); @@ -81,10 +91,17 @@ void compiler_parse(void) exit(EXIT_SUCCESS); } +static inline void halt_on_error(void) +{ + if (global_context.errors_found > 0) exit(EXIT_FAILURE); +} + void compiler_compile(void) { Context **contexts = NULL; - diag_setup(active_target.test_output); + + global_context_clear_errors(); + if (global_context.lib_dir) { vec_add(global_context.sources, strformat("%s/std/runtime.c3", global_context.lib_dir)); @@ -101,7 +118,7 @@ void compiler_compile(void) if (loaded) continue; Context *context = context_create(file); vec_add(contexts, context); - parse_file(context); + if (!parse_file(context)) continue; } unsigned source_count = vec_size(contexts); if (!source_count) @@ -109,47 +126,57 @@ void compiler_compile(void) error_exit("No source files to compile."); } assert(contexts); - for (unsigned i = 0; i < source_count; i++) - { - sema_analysis_pass_process_imports(contexts[i]); - } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + Module **modules = global_context.module_list; - for (unsigned i = 0; i < source_count; i++) + unsigned module_count = vec_size(modules); + for (unsigned i = 0; i < module_count; i++) { - sema_analysis_pass_register_globals(contexts[i]); + sema_analysis_pass_process_imports(modules[i]); } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + + 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]); } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + + halt_on_error(); for (unsigned i = 0; i < source_count; i++) { sema_analysis_pass_decls(contexts[i]); } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + + halt_on_error(); for (unsigned i = 0; i < source_count; i++) { sema_analysis_pass_ct_assert(contexts[i]); } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + + halt_on_error(); for (unsigned i = 0; i < source_count; i++) { sema_analysis_pass_functions(contexts[i]); } - if (diagnostics.errors > 0) exit(EXIT_FAILURE); + + halt_on_error(); if (active_target.output_headers) { for (unsigned i = 0; i < source_count; i++) { Context *context = contexts[i]; + if (context->module->parameters) break; header_gen(context); } return; @@ -162,6 +189,11 @@ void compiler_compile(void) for (unsigned i = 0; i < source_count; i++) { Context *context = contexts[i]; + if (context->module->parameters) + { + gen_contexts[i] = NULL; + continue; + } gen_contexts[i] = llvm_gen(context); } @@ -190,6 +222,7 @@ void compiler_compile(void) for (unsigned i = 0; i < source_count; i++) { + if (!gen_contexts[i]) continue; const char *file_name = llvm_codegen(gen_contexts[i]); assert(file_name || !create_exe); vec_add(obj_files, file_name); @@ -199,11 +232,12 @@ void compiler_compile(void) { if (active_target.arch_os_target == ARCH_OS_TARGET_DEFAULT) { - platform_linker(active_target.name, obj_files, source_count); + platform_linker(active_target.name, obj_files, vec_size(obj_files)); } else { - if (!obj_format_linking_supported(platform_target.object_format) || !linker(active_target.name, obj_files, source_count)) + if (!obj_format_linking_supported(platform_target.object_format) || !linker(active_target.name, obj_files, + vec_size(obj_files))) { printf("No linking is performed due to missing linker support."); active_target.run_after_compile = false; @@ -304,10 +338,14 @@ void global_context_add_type(Type *type) VECADD(global_context.type, type); } -Module *compiler_find_or_create_module(Path *module_name) +Module *global_context_find_module(const char *name) { - Module *module = stable_get(&global_context.modules, module_name->module); + return stable_get(&global_context.modules, name); +} +Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters) +{ + Module *module = global_context_find_module(module_name->module); if (module) { // We might have gotten an auto-generated module, if so @@ -315,6 +353,7 @@ Module *compiler_find_or_create_module(Path *module_name) if (module->name->span.loc.index == INVALID_TOKEN_ID.index && module_name->span.loc.index != INVALID_TOKEN_ID.index) { module->name = module_name; + module->parameters = parameters; } return module; } @@ -323,15 +362,24 @@ Module *compiler_find_or_create_module(Path *module_name) // Set up the module. module = CALLOCS(Module); module->name = module_name; + module->parameters = parameters; stable_init(&module->symbols, 0x10000); stable_set(&global_context.modules, module_name->module, module); + if (parameters) + { + vec_add(global_context.generic_module_list, module); + } + else + { + vec_add(global_context.module_list, module); + } + // Now find the possible parent array: Path *parent_path = path_find_parent_path(NULL, module_name); if (parent_path) { // Get the parent - Module *parent_module = compiler_find_or_create_module(parent_path); - vec_add(parent_module->sub_modules, module); + compiler_find_or_create_module(parent_path, NULL); } return module; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 964b56e0b..09fb1076e 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -136,13 +136,6 @@ typedef struct TokenType type : 8; } Token; -typedef struct _Diagnostics -{ - bool panic_mode; - unsigned errors; - unsigned warnings; - bool test_mode; -} Diagnostics; typedef struct { @@ -272,6 +265,7 @@ typedef struct { Path *path; TokenId symbol; + bool private; bool aliased; } ImportDecl; @@ -291,6 +285,7 @@ typedef struct _VarDecl bool failable : 1; bool unwrap : 1; bool vararg : 1; + bool is_static : 1; TypeInfo *type_info; union { @@ -379,8 +374,6 @@ typedef struct FunctionSignature function_signature; Ast *body; FuncAnnotations *annotations; - Decl **locals; - Ast **labels; } FuncDecl; typedef struct @@ -440,7 +433,7 @@ typedef struct { Path *path; Expr **params; - Token alias; + TokenId name; } DefineDecl; typedef struct @@ -492,10 +485,7 @@ typedef struct _Decl { struct { - union - { - Decl** methods; - }; + Decl** methods; union { // Unions, Errtype and Struct use strukt @@ -1148,17 +1138,19 @@ typedef struct _Ast typedef struct _Module { Path *name; + TokenId *parameters; - bool is_external; - bool is_c_library; - bool is_exported; + bool is_external : 1; + bool is_c_library : 1; + bool is_exported : 1; + bool is_generic : 1; Ast **files; // Asts Decl** functions; STable symbols; STable public_symbols; - Module **sub_modules; + struct _Context **contexts; } Module; @@ -1213,7 +1205,6 @@ typedef struct typedef struct _Context { Path *module_name; - TokenId* module_parameters; File* file; Decl** imports; Module *module; @@ -1262,9 +1253,7 @@ typedef struct _Context int macro_counter; int macro_nesting; }; - Decl* locals[MAX_LOCALS]; Decl **last_local; - DynamicScope scopes[MAX_SCOPE_DEPTH]; char path_scratch[MAX_PATH]; struct { STable external_symbols; @@ -1277,23 +1266,30 @@ typedef struct _Context Token next_tok; TokenId docs_start; TokenId docs_end; + Decl* locals[MAX_LOCALS]; + DynamicScope scopes[MAX_SCOPE_DEPTH]; } Context; typedef struct { STable modules; + Module **module_list; + Module **generic_module_list; STable global_symbols; STable qualified_symbols; Type **type; const char *lib_dir; const char **sources; + bool in_panic_mode : 1; + bool in_test_mode : 1; + unsigned errors_found; + unsigned warnings_found; } GlobalContext; typedef enum { MODULE_SYMBOL_SEARCH_EXTERNAL, - MODULE_SYMBOL_SEARCH_PARENT, - MODULE_SYMBOL_SEARCH_THIS + MODULE_SYMBOL_SEARCH_MODULE } ModuleSymbolSearch; typedef enum @@ -1383,7 +1379,6 @@ extern Decl *poisoned_decl; extern Expr *poisoned_expr; extern Type *poisoned_type; extern TypeInfo *poisoned_type_info; -extern Diagnostics diagnostics; extern Type *type_bool, *type_void, *type_compstr, *type_voidptr; @@ -1491,13 +1486,14 @@ void header_gen(Context *context); void global_context_add_type(Type *type); Decl *compiler_find_symbol(const char *name); -Module *compiler_find_or_create_module(Path *module_name); +Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters); +Module *global_context_find_module(const char *name); void compiler_register_public_symbol(Decl *decl); Context *context_create(File *file); void context_register_global_decl(Context *context, Decl *decl); void context_register_external_symbol(Context *context, Decl *decl); -bool context_add_import(Context *context, Path *path, Token symbol, Token alias); +bool context_add_import(Context *context, Path *path, Token symbol, Token alias, bool private_import); bool context_set_module_from_filename(Context *context); bool context_set_module(Context *context, Path *path, TokenId *generic_parameters); void context_print_ast(Context *context, FILE *file); @@ -1520,7 +1516,6 @@ static inline DeclKind decl_from_token(TokenType type); #pragma mark --- Diag functions -void diag_setup(bool test_output); void diag_verror_range(SourceLocation *location, const char *message, va_list args); @@ -1588,21 +1583,21 @@ static inline TokenType token_type(Token token) { return toktypeptr(token.id.ind #define TOKLEN(T) TOKLOC(T)->length #define TOKVALID(_tok) (_tok.index != 0) -Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch search, Decl **private_decl); +Decl *module_find_symbol(Module *module, const char *symbol); -void parse_file(Context *context); +bool parse_file(Context *context); Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span); Path *path_find_parent_path(Context *context, Path *path); const char *resolve_status_to_string(ResolveStatus status); -#define SEMA_TOKEN_ERROR(_tok, ...) sema_error_range3(source_span_from_token_id(_tok.id), __VA_ARGS__) -#define SEMA_TOKID_ERROR(_tok_id, ...) sema_error_range3(source_span_from_token_id(_tok_id), __VA_ARGS__) -#define SEMA_ERROR(_node, ...) sema_error_range3((_node)->span, __VA_ARGS__) +#define SEMA_TOKEN_ERROR(_tok, ...) sema_error_range(source_span_from_token_id(_tok.id), __VA_ARGS__) +#define SEMA_TOKID_ERROR(_tok_id, ...) sema_error_range(source_span_from_token_id(_tok_id), __VA_ARGS__) +#define SEMA_ERROR(_node, ...) sema_error_range((_node)->span, __VA_ARGS__) #define SEMA_PREV(_node, ...) sema_prev_at_range3((_node)->span, __VA_ARGS__) -void sema_analysis_pass_process_imports(Context *context); -void sema_analysis_pass_register_globals(Context *context); +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); @@ -1630,7 +1625,7 @@ Type *sema_type_lower_by_size(Type *type, ByteSize element_size); void sema_error_at_prev_end(Token token, const char *message, ...); -void sema_error_range3(SourceSpan span, const char *message, ...); +void sema_error_range(SourceSpan span, const char *message, ...); void sema_verror_range(SourceLocation *location, const char *message, va_list args); void sema_error(Context *context, const char *message, ...); @@ -2002,6 +1997,24 @@ 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) + +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); + /** * Minimum alignment, values are either offsets or alignments. * @return diff --git a/src/compiler/context.c b/src/compiler/context.c index 976b27bd2..0a0e15ff4 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -16,12 +16,12 @@ Context *context_create(File *file) } -static inline bool create_module_or_check_name(Context *context, Path *module_name) +static inline bool create_module_or_check_name(Context *context, Path *module_name, TokenId *parameters) { context->module_name = module_name; if (context->module == NULL) { - context->module = compiler_find_or_create_module(module_name); + context->module = compiler_find_or_create_module(module_name, parameters); return true; } @@ -56,12 +56,11 @@ bool context_set_module_from_filename(Context *context) path->span = INVALID_RANGE; path->module = module_name; path->len = len; - return create_module_or_check_name(context, path); + return create_module_or_check_name(context, path, NULL); } bool context_set_module(Context *context, Path *path, TokenId *generic_parameters) { - DEBUG_LOG("CONTEXT: Setting module to '%s'.", path->module); // Note that we allow the illegal name for now, to be able to parse further. context->module_name = path; if (!is_all_lower(path->module)) @@ -69,9 +68,8 @@ bool context_set_module(Context *context, Path *path, TokenId *generic_parameter SEMA_ERROR(path, "A module name may not have any upper case characters."); return false; } - context->module_parameters = generic_parameters; - return create_module_or_check_name(context, path); + return create_module_or_check_name(context, path, generic_parameters); } @@ -159,7 +157,7 @@ void context_register_global_decl(Context *context, Decl *decl) DEBUG_LOG("Registering symbol '%s'.", decl->name); Decl *old = stable_set(&context->local_symbols, decl->name, decl); - if (!old && decl->visibility != VISIBLE_LOCAL) + if (!old) { old = stable_set(&context->module->symbols, decl->name, decl); } @@ -176,10 +174,11 @@ void context_register_global_decl(Context *context, Decl *decl) } } -bool context_add_import(Context *context, Path *path, Token token, Token alias) +bool context_add_import(Context *context, Path *path, Token token, Token alias, bool private_import) { DEBUG_LOG("SEMA: Add import of '%s'.", path->module); + if (!is_all_lower(path->module)) { SEMA_ERROR(path, "A module is not expected to have any upper case characters, please change it."); @@ -191,6 +190,7 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias) import->decl_kind = DECL_IMPORT; import->visibility = VISIBLE_LOCAL; import->import.path = path; + import->import.private = private_import; import->import.symbol = token.id; if (alias.type != TOKEN_INVALID_TOKEN) { diff --git a/src/compiler/copying.c b/src/compiler/copying.c new file mode 100644 index 000000000..ec6095ccc --- /dev/null +++ b/src/compiler/copying.c @@ -0,0 +1,523 @@ +#include "compiler_internal.h" + +Expr **copy_expr_list(Context *context, Expr **expr_list) +{ + Expr **result = NULL; + VECEACH(expr_list, i) + { + vec_add(result, copy_expr(context, expr_list[i])); + } + return result; +} + +static inline Decl *decl_copy_label_from_macro(Context *context, Decl *to_copy, Ast *ast) +{ + if (!to_copy) return NULL; + to_copy = decl_copy_local_from_macro(context, to_copy); + to_copy->label.parent = astid(ast); + return to_copy; +} + + +static inline void copy_flow(Context *context, Ast *ast) +{ + ast->flow.label = decl_copy_label_from_macro(context, ast->flow.label, ast); +} + +static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to_copy) +{ + TypeInfo **result = NULL; + VECEACH(to_copy, i) + { + vec_add(result, copy_type_info(context, to_copy[i])); + } + return result; +} + + +static DesignatorElement** macro_copy_designator_list(Context *context, DesignatorElement **list) +{ + DesignatorElement **result = NULL; + VECEACH(list, i) + { + DesignatorElement *element = MALLOC(sizeof(DesignatorElement)); + DesignatorElement *to_copy = list[i]; + *element = *to_copy; + switch (to_copy->kind) + { + case DESIGNATOR_FIELD: + // Nothing needed + break; + case DESIGNATOR_RANGE: + MACRO_COPY_EXPR(element->index_end_expr); + FALLTHROUGH; + case DESIGNATOR_ARRAY: + MACRO_COPY_EXPR(element->index_expr); + break; + default: + UNREACHABLE + } + vec_add(result, element); + } + return result; +} + + +Expr *copy_expr(Context *context, Expr *source_expr) +{ + if (!source_expr) return NULL; + Expr *expr = COPY(source_expr); + switch (source_expr->expr_kind) + { + case EXPR_ENUM_CONSTANT: + case EXPR_MEMBER_ACCESS: + UNREACHABLE + case EXPR_UNDEF: + return expr; + case EXPR_CONST_IDENTIFIER: + case EXPR_MACRO_IDENTIFIER: + case EXPR_CT_IDENT: + case EXPR_MACRO_CT_IDENTIFIER: + case EXPR_HASH_IDENT: + // TODO + return expr; + case EXPR_DESIGNATOR: + expr->designator_expr.path = macro_copy_designator_list(context, expr->designator_expr.path); + MACRO_COPY_EXPR(expr->designator_expr.value); + return expr; + case EXPR_TYPEINFO: + MACRO_COPY_TYPE(expr->type_expr); + return expr; + case EXPR_SLICE_ASSIGN: + MACRO_COPY_EXPR(expr->slice_assign_expr.left); + MACRO_COPY_EXPR(expr->slice_assign_expr.right); + return expr; + case EXPR_SLICE: + MACRO_COPY_EXPR(expr->slice_expr.expr); + MACRO_COPY_EXPR(expr->slice_expr.start); + MACRO_COPY_EXPR(expr->slice_expr.end); + return expr; + case EXPR_LEN: + MACRO_COPY_EXPR(expr->len_expr.inner); + return expr; + case EXPR_CATCH: + case EXPR_TRY: + MACRO_COPY_EXPR(expr->trycatch_expr); + return expr; + case EXPR_DECL_LIST: + MACRO_COPY_AST_LIST(expr->dexpr_list_expr); + return expr; + case EXPR_FAILABLE: + MACRO_COPY_EXPR(expr->failable_expr); + return expr; + case EXPR_ELSE: + MACRO_COPY_EXPR(expr->else_expr.expr); + if (expr->else_expr.is_jump) + { + MACRO_COPY_EXPR(expr->else_expr.else_expr); + } + else + { + MACRO_COPY_AST(expr->else_expr.else_stmt); + } + return expr; + case EXPR_MACRO_BLOCK: + UNREACHABLE + case EXPR_TYPEOF: + MACRO_COPY_EXPR(expr->typeof_expr); + return expr; + case EXPR_COMPOUND_LITERAL: + MACRO_COPY_EXPR(expr->expr_compound_literal.initializer); + MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); + return expr; + case EXPR_EXPR_BLOCK: + MACRO_COPY_AST_LIST(expr->expr_block.stmts); + return expr; + case EXPR_POISONED: + return source_expr; + case EXPR_GUARD: + MACRO_COPY_EXPR(expr->guard_expr.inner); + return expr; + case EXPR_CONST: + return expr; + case EXPR_BINARY: + MACRO_COPY_EXPR(expr->binary_expr.left); + MACRO_COPY_EXPR(expr->binary_expr.right); + return expr; + case EXPR_TERNARY: + MACRO_COPY_EXPR(expr->ternary_expr.cond); + MACRO_COPY_EXPR(expr->ternary_expr.then_expr); + MACRO_COPY_EXPR(expr->ternary_expr.else_expr); + return expr; + case EXPR_UNARY: + MACRO_COPY_EXPR(expr->unary_expr.expr); + return expr; + case EXPR_POST_UNARY: + MACRO_COPY_EXPR(expr->post_expr.expr); + return expr; + case EXPR_TYPEID: + MACRO_COPY_TYPE(expr->typeid_expr); + return expr; + case EXPR_IDENTIFIER: + return expr; + case EXPR_CALL: + MACRO_COPY_EXPR(expr->call_expr.function); + MACRO_COPY_EXPR_LIST(expr->call_expr.arguments); + return expr; + case EXPR_SUBSCRIPT: + MACRO_COPY_EXPR(expr->subscript_expr.expr); + MACRO_COPY_EXPR(expr->subscript_expr.index); + return expr; + case EXPR_GROUP: + MACRO_COPY_EXPR(expr->group_expr->group_expr); + return expr; + case EXPR_ACCESS: + MACRO_COPY_EXPR(expr->access_expr.parent); + return expr; + case EXPR_INITIALIZER_LIST: + MACRO_COPY_EXPR_LIST(expr->initializer_expr.initializer_expr); + return expr; + case EXPR_EXPRESSION_LIST: + MACRO_COPY_EXPR_LIST(expr->expression_list); + return expr; + case EXPR_CAST: + MACRO_COPY_EXPR(expr->cast_expr.expr); + MACRO_COPY_TYPE(expr->cast_expr.type_info); + return expr; + case EXPR_SCOPED_EXPR: + MACRO_COPY_EXPR(expr->expr_scope.expr); + return expr; + } + UNREACHABLE +} + +Ast *copy_ast(Context *context, Ast *source) +{ + if (!source) return NULL; + Ast *ast = COPY(source); + switch (source->ast_kind) + { + case AST_DOCS: + MACRO_COPY_AST_LIST(ast->directives); + return ast; + case AST_DOC_DIRECTIVE: + switch (ast->doc_directive.kind) + { + case DOC_DIRECTIVE_REQUIRE: + case DOC_DIRECTIVE_ENSURE: + MACRO_COPY_EXPR(ast->doc_directive.contract.decl_exprs); + MACRO_COPY_EXPR(ast->doc_directive.contract.comment); + break; + case DOC_DIRECTIVE_PARAM: + case DOC_DIRECTIVE_ERRORS: + case DOC_DIRECTIVE_PURE: + case DOC_DIRECTIVE_UNKNOWN: + break; + } + return ast; + case AST_POISONED: + return ast; + case AST_ASM_STMT: + TODO + case AST_ASSERT_STMT: + MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); + MACRO_COPY_EXPR(ast->ct_assert_stmt.message); + return ast; + case AST_BREAK_STMT: + return ast; + case AST_CASE_STMT: + MACRO_COPY_AST(ast->case_stmt.body); + if (ast->case_stmt.is_type) + { + MACRO_COPY_TYPE(ast->case_stmt.type_info); + } + else + { + MACRO_COPY_EXPR(ast->case_stmt.expr); + } + return ast; + case AST_CATCH_STMT: + copy_flow(context, ast); + if (ast->catch_stmt.has_err_var) + { + MACRO_COPY_DECL(ast->catch_stmt.err_var); + } + else + { + MACRO_COPY_EXPR(ast->catch_stmt.catchable); + } + if (ast->catch_stmt.is_switch) + { + MACRO_COPY_AST_LIST(ast->catch_stmt.cases); + } + else + { + MACRO_COPY_AST(ast->catch_stmt.body); + } + return ast; + case AST_COMPOUND_STMT: + MACRO_COPY_AST_LIST(ast->compound_stmt.stmts); + return ast; + case AST_CT_COMPOUND_STMT: + MACRO_COPY_AST_LIST(ast->ct_compound_stmt); + return ast; + case AST_CONTINUE_STMT: + TODO + return ast; + case AST_CT_ASSERT: + MACRO_COPY_EXPR(ast->ct_assert_stmt.message); + MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); + return ast; + case AST_CT_IF_STMT: + MACRO_COPY_EXPR(ast->ct_if_stmt.expr); + MACRO_COPY_AST(ast->ct_if_stmt.elif); + MACRO_COPY_AST(ast->ct_if_stmt.then); + return ast; + case AST_CT_ELIF_STMT: + MACRO_COPY_EXPR(ast->ct_elif_stmt.expr); + MACRO_COPY_AST(ast->ct_elif_stmt.then); + MACRO_COPY_AST(ast->ct_elif_stmt.elif); + return ast; + case AST_CT_ELSE_STMT: + MACRO_COPY_AST(ast->ct_else_stmt); + return ast; + case AST_CT_FOR_STMT: + MACRO_COPY_AST(ast->ct_for_stmt.body); + MACRO_COPY_EXPR(ast->ct_for_stmt.expr); + return ast; + case AST_CT_SWITCH_STMT: + MACRO_COPY_EXPR(ast->ct_switch_stmt.cond); + MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body); + return ast; + case AST_DECLARE_STMT: + MACRO_COPY_DECL(ast->declare_stmt); + return ast; + case AST_DEFAULT_STMT: + MACRO_COPY_AST(ast->case_stmt.body); + return ast; + case AST_DEFINE_STMT: + ast->define_stmt = copy_decl(context, 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); + MACRO_COPY_AST(ast->do_stmt.body); + MACRO_COPY_EXPR(ast->do_stmt.expr); + return ast; + case AST_EXPR_STMT: + MACRO_COPY_EXPR(ast->expr_stmt); + return ast; + case AST_FOR_STMT: + copy_flow(context, 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); + 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); + MACRO_COPY_EXPR(ast->if_stmt.cond); + MACRO_COPY_AST(ast->if_stmt.else_body); + MACRO_COPY_AST(ast->if_stmt.then_body); + return ast; + case AST_NEXT_STMT: + MACRO_COPY_EXPR(ast->next_stmt.switch_expr); + TODO + return ast; + case AST_NOP_STMT: + return ast; + case AST_RETURN_STMT: + MACRO_COPY_EXPR(ast->return_stmt.expr); + return ast; + case AST_SWITCH_STMT: + copy_flow(context, ast); + MACRO_COPY_EXPR(ast->switch_stmt.cond); + MACRO_COPY_AST_LIST(ast->switch_stmt.cases); + return ast; + case AST_TRY_STMT: + MACRO_COPY_EXPR(ast->try_stmt.decl_expr); + MACRO_COPY_AST(ast->try_stmt.body); + return ast; + case AST_UNREACHABLE_STMT: + return ast; + case AST_VOLATILE_STMT: + TODO + return ast; + case AST_WHILE_STMT: + copy_flow(context, ast); + MACRO_COPY_EXPR(ast->while_stmt.cond); + MACRO_COPY_AST(ast->while_stmt.body); + return ast; + case AST_SCOPED_STMT: + MACRO_COPY_AST(ast->scoped_stmt.stmt); + return ast; + } + UNREACHABLE; +} + + +Ast** copy_ast_list(Context *context, Ast **to_copy) +{ + Ast **result = NULL; + VECEACH(to_copy, i) + { + vec_add(result, copy_ast(context, to_copy[i])); + } + return result; +} + +Decl** copy_decl_list(Context *context, Decl **to_copy) +{ + Decl **result = NULL; + VECEACH(to_copy, i) + { + vec_add(result, copy_decl(context, to_copy[i])); + } + return result; +} + +Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy) +{ + if (!to_copy) return NULL; + assert(to_copy->decl_kind == DECL_VAR); + Decl *copy = COPY(to_copy); + MACRO_COPY_TYPE(copy->var.type_info); + MACRO_COPY_EXPR(copy->var.init_expr); + return copy; +} + + +TypeInfo *copy_type_info(Context *context, TypeInfo *source) +{ + if (!source) return NULL; + TypeInfo *copy = malloc_arena(sizeof(TypeInfo)); + memcpy(copy, source, sizeof(TypeInfo)); + switch (source->kind) + { + case TYPE_INFO_POISON: + return copy; + case TYPE_INFO_IDENTIFIER: + return copy; + case TYPE_INFO_EXPRESSION: + assert(source->resolve_status == RESOLVE_NOT_DONE); + copy->unresolved_type_expr = copy_expr(context, 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); + 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); + return copy; + case TYPE_INFO_POINTER: + assert(source->resolve_status == RESOLVE_NOT_DONE); + copy->pointer = copy_type_info(context, source->pointer); + return copy; + } + UNREACHABLE +} + +static void copy_function_signature_deep(Context *context, 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) +{ + if (!decl) return NULL; + Decl *copy = COPY(decl); + MACRO_COPY_AST(copy->docs); + // Copy attributes? Yes! + switch (decl->decl_kind) + { + case DECL_POISONED: + break; + case DECL_UNION: + case DECL_STRUCT: + MACRO_COPY_DECL_LIST(copy->strukt.members); + MACRO_COPY_DECL_LIST(copy->methods); + break; + case DECL_ENUM: + 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: + 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); + MACRO_COPY_AST(copy->func.body); + break; + case DECL_VAR: + MACRO_COPY_TYPE(copy->var.type_info); + if (copy->var.kind == VARDECL_ALIAS) + { + MACRO_COPY_DECL(copy->var.alias); + } + else + { + MACRO_COPY_EXPR(copy->var.init_expr); + } + break; + case DECL_LABEL: + TODO + break; + case DECL_ENUM_CONSTANT: + MACRO_COPY_EXPR(copy->enum_constant.expr); + MACRO_COPY_EXPR_LIST(copy->enum_constant.args); + break; + case DECL_TYPEDEF: + if (copy->typedef_decl.is_func) + { + copy_function_signature_deep(context, ©->typedef_decl.function_signature); + break; + } + MACRO_COPY_TYPE(copy->typedef_decl.type_info); + break; + case DECL_DISTINCT: + 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); + 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: + case DECL_CT_ELSE: + case DECL_CT_ELIF: + case DECL_CT_SWITCH: + case DECL_CT_CASE: + case DECL_ATTRIBUTE: + case DECL_DEFINE: + TODO + } + return copy; +} + diff --git a/src/compiler/diagnostics.c b/src/compiler/diagnostics.c index d516b8710..7f0601e40 100644 --- a/src/compiler/diagnostics.c +++ b/src/compiler/diagnostics.c @@ -5,15 +5,7 @@ #include "compiler_internal.h" #include -Diagnostics diagnostics; -void diag_setup(bool test_output) -{ - diagnostics.panic_mode = false; - diagnostics.errors = 0; - diagnostics.warnings = 0; - diagnostics.test_mode = test_output; -} typedef enum { @@ -24,7 +16,7 @@ typedef enum static void print_error2(SourceLocation *location, const char *message, PrintType print_type) { - if (diagnostics.test_mode) + if (active_target.test_output) { switch (print_type) { @@ -119,17 +111,17 @@ static void vprint_error(SourceLocation *location, const char *message, va_list void diag_verror_range(SourceLocation *location, const char *message, va_list args) { - if (diagnostics.panic_mode) return; - diagnostics.panic_mode = true; + if (global_context.in_panic_mode) return; + global_context.in_panic_mode = true; vprint_error(location, message, args); - diagnostics.errors++; + global_context.errors_found++; } void sema_verror_range(SourceLocation *location, const char *message, va_list args) { vprint_error(location, message, args); - diagnostics.errors++; + global_context.errors_found++; } @@ -147,7 +139,7 @@ void sema_prev_at_range3(SourceSpan span, const char *message, ...) va_end(args); } -void sema_error_range3(SourceSpan span, const char *message, ...) +void sema_error_range(SourceSpan span, const char *message, ...) { SourceLocation *start = TOKLOC(span.loc); SourceLocation *end = TOKLOC(span.end_loc); @@ -190,7 +182,7 @@ void sema_error_at_prev_end(Token token, const char *message, ...) void sema_error(Context *context, const char *message, ...) { - diagnostics.errors++; + global_context.errors_found++; File *file = lexer_current_file(&context->lexer); va_list list; va_start(list, message); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index f9db93c48..9612f648a 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -423,13 +423,13 @@ typedef enum TOKEN_IF, TOKEN_IMPORT, TOKEN_INTERFACE, - TOKEN_LOCAL, TOKEN_MACRO, TOKEN_MODULE, TOKEN_NEXTCASE, TOKEN_NULL, TOKEN_PUBLIC, TOKEN_RETURN, + TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, TOKEN_TRUE, @@ -562,8 +562,8 @@ typedef enum typedef enum { - VISIBLE_MODULE, VISIBLE_LOCAL, + VISIBLE_MODULE, VISIBLE_PUBLIC, VISIBLE_EXTERN, } Visibility; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 7f0842a90..313849e78 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -984,7 +984,7 @@ void *llvm_gen(Context *context) if (llvm_use_debug(gen_context)) LLVMDIBuilderFinalize(gen_context->debug.builder); // If it's in test, then we want to serialize the IR before it is optimized. - if (diagnostics.test_mode) + if (active_target.test_output) { gencontext_print_llvm_ir(gen_context); gencontext_verify_ir(gen_context); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 82233c06e..1c5b233be 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1141,6 +1141,26 @@ void gencontext_emit_catch_stmt(GenContext *c, Ast *ast) llvm_emit_block(c, after_catch); } +void llvm_emit_puts_output(GenContext *c, const char *message) +{ + LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char); + LLVMTypeRef type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), &char_ptr_type, 1, false); + LLVMValueRef puts_func = LLVMGetNamedFunction(c->module, "puts"); + if (!puts_func) + { + puts_func = LLVMAddFunction(c->module, "puts", type); + } + LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), strlen(message) + 1), ""); + LLVMSetLinkage(global_name, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_name, 1); + LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context, message, strlen(message), 0)); + + LLVMValueRef zero = llvm_get_zero(c, type_usize); + LLVMValueRef string = LLVMBuildInBoundsGEP2(c->builder, LLVMTypeOf(global_name), global_name, &zero, 1, ""); + string = LLVMBuildBitCast(c->builder, string, char_ptr_type, ""); + LLVMBuildCall(c->builder, puts_func, &string, 1, ""); + +} void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *panic_name) { LLVMBasicBlockRef panic_block = llvm_basic_block_new(c, "panic"); @@ -1149,22 +1169,7 @@ void llvm_emit_panic_on_true(GenContext *c, LLVMValueRef value, const char *pani llvm_value_set_bool(&be_value, value); llvm_emit_cond_br(c, &be_value, panic_block, ok_block); llvm_emit_block(c, panic_block); - LLVMTypeRef char_ptr_type = llvm_get_ptr_type(c, type_char); - LLVMTypeRef type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), &char_ptr_type, 1, false); - LLVMValueRef puts_func = LLVMGetNamedFunction(c->module, "puts"); - if (!puts_func) - { - puts_func = LLVMAddFunction(c->module, "puts", type); - } - LLVMValueRef global_name = LLVMAddGlobal(c->module, LLVMArrayType(llvm_get_type(c, type_char), strlen(panic_name) + 1), ""); - LLVMSetLinkage(global_name, LLVMInternalLinkage); - LLVMSetGlobalConstant(global_name, 1); - LLVMSetInitializer(global_name, LLVMConstStringInContext(c->context, panic_name, strlen(panic_name), 0)); - - LLVMValueRef zero = llvm_get_zero(c, type_usize); - LLVMValueRef string = LLVMBuildInBoundsGEP2(c->builder, LLVMTypeOf(global_name), global_name, &zero, 1, ""); - string = LLVMBuildBitCast(c->builder, string, char_ptr_type, ""); - LLVMBuildCall(c->builder, puts_func, &string, 1, ""); + llvm_emit_puts_output(c, panic_name); llvm_emit_call_intrinsic(c, intrinsic_id_trap, NULL, 0, NULL, 0); llvm_emit_br(c, ok_block); llvm_emit_block(c, ok_block); diff --git a/src/compiler/module.c b/src/compiler/module.c index 12379d007..03d2aadee 100644 --- a/src/compiler/module.c +++ b/src/compiler/module.c @@ -4,40 +4,9 @@ #include "compiler_internal.h" -Decl *module_find_symbol(Module *module, const char *symbol, ModuleSymbolSearch search, Decl **private_decl) +Decl *module_find_symbol(Module *module, const char *symbol) { - Decl *decl = stable_get(&module->symbols, symbol); - if (decl) - { - switch (decl->visibility) - { - case VISIBLE_LOCAL: - *private_decl = decl; - decl = NULL; - break; - case VISIBLE_EXTERN: - decl = NULL; - break; - case VISIBLE_MODULE: - if (search == MODULE_SYMBOL_SEARCH_EXTERNAL) - { - *private_decl = decl; - decl = NULL; - } - break; - case VISIBLE_PUBLIC: - break; - } - } - if (!decl) - { - if (search == MODULE_SYMBOL_SEARCH_THIS) search = MODULE_SYMBOL_SEARCH_PARENT; - VECEACH (module->sub_modules, i) - { - if ((decl = module_find_symbol(module->sub_modules[i], symbol, search, private_decl))) break; - } - } - return decl; + return stable_get(&module->symbols, symbol); } Path *path_create_from_string(Context *context, const char *string, size_t len, SourceSpan span) diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index c834eec22..fab885105 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -66,7 +66,7 @@ static bool context_next_is_type_and_not_ident(Context *context) * are *always* sync points. * * func, any type, CT_IDENT, CT_TYPE_IDENT, $if, $for, $switch, generic, - * doc comment start, asm, typeof, TYPE_IDENT, local, const, IDENT + * doc comment start, asm, typeof, TYPE_IDENT, const, IDENT * - are sync points only if they appear in the first column. */ void recover_top_level(Context *context) @@ -89,7 +89,6 @@ void recover_top_level(Context *context) case TOKEN_DEFINE: return; case TOKEN_IDENT: // Incr arrays only - case TOKEN_LOCAL: case TOKEN_CONST: case TOKEN_ASM: case TOKEN_TYPEOF: @@ -324,7 +323,7 @@ static inline bool parse_optional_module_params(Context *context, TokenId **toke { case TOKEN_IDENT: case TOKEN_TYPE_IDENT: - return false; + break; case TOKEN_COMMA: SEMA_TOKEN_ERROR(context->tok, "Unexpected ','"); return false; @@ -343,6 +342,7 @@ static inline bool parse_optional_module_params(Context *context, TokenId **toke return consume(context, TOKEN_RPAREN, "Expected ')'."); } } + } /** * module ::= MODULE module_path ('(' module_params ')')? EOS @@ -378,7 +378,7 @@ bool parse_module(Context *context) TokenId *generic_parameters = NULL; if (!parse_optional_module_params(context, &generic_parameters)) { - context_set_module(context, path, generic_parameters); + context_set_module(context, path, NULL); recover_top_level(context); return true; } @@ -406,7 +406,7 @@ static inline bool parse_specified_import(Context *context, Path *path) // Alias? if (!try_consume(context, TOKEN_AS)) { - return context_add_import(context, path, symbol, NO_TOKEN); + return context_add_import(context, path, symbol, NO_TOKEN, false); } if (context->tok.type != symbol.type) { @@ -420,7 +420,7 @@ static inline bool parse_specified_import(Context *context, Path *path) } Token alias = context->tok; advance(context); - return context_add_import(context, path, symbol, alias); + return context_add_import(context, path, symbol, alias, false); } @@ -765,11 +765,11 @@ TypeInfo *parse_type(Context *context) /** * Parse ident ('=' expr)? - * @param local + * @param is_static * @param type * @return */ -Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) +Decl *parse_decl_after_type(Context *context, TypeInfo *type) { if (TOKEN_IS(TOKEN_LPAREN)) { @@ -783,8 +783,7 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) TokenId name = context->tok.id; advance(context); - Visibility visibility = local ? VISIBLE_LOCAL : VISIBLE_MODULE; - Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, visibility); + Decl *decl = decl_new_var(name, type, VARDECL_LOCAL, VISIBLE_LOCAL); if (TOKEN_IS(TOKEN_EQ)) { if (!decl) @@ -800,21 +799,14 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type) /** - * declaration ::= ('local' | 'const')? type variable ('=' expr)? + * declaration ::= ('static' | 'const')? type variable ('=' expr)? * * @return Decl* (poisoned on error) */ Decl *parse_decl(Context *context) { - bool local = try_consume(context, TOKEN_LOCAL); - if (TOKEN_IS(TOKEN_CONST)) { - if (local) - { - SEMA_TOKID_ERROR(context->prev_tok, "A 'local' variable cannot also be declared 'constant'."); - return poisoned_decl; - } return parse_const_declaration(context, VISIBLE_LOCAL); } @@ -822,7 +814,7 @@ Decl *parse_decl(Context *context) bool failable = try_consume(context, TOKEN_BANG); - Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, local, type), poisoned_decl); + Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, type), poisoned_decl); if (failable && decl->var.unwrap) { SEMA_ERROR(decl, "You cannot use unwrap with a failable variable."); @@ -1453,16 +1445,17 @@ static inline Decl *parse_define(Context *context, Visibility visibility) 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; - Decl *decl = decl_new(DECL_DEFINE, context->tok.id, visibility); 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); Expr **exprs = NULL; @@ -1475,16 +1468,19 @@ static inline Decl *parse_define(Context *context, Visibility visibility) TRY_CONSUME_OR(TOKEN_COMMA, "Expected ',' after argument.", poisoned_decl); } } - decl->define_decl.path = path; - decl->define_decl.params = exprs; TRY_CONSUME_OR(TOKEN_AS, "Expected 'as' after generic declaration.", poisoned_decl); if (!token_is_symbol(context->tok.type)) { SEMA_TOKEN_ERROR(context->tok, "The aliased name must follow after 'as'."); return poisoned_decl; } - decl->define_decl.alias = context->tok; + 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); return decl; } @@ -1930,9 +1926,7 @@ static inline bool check_no_visibility_before(Context *context, Visibility visib /** * - * import ::= IMPORT import_path (':' specified_import_list)? ';' - * - * specified_import_list ::= specified_import (',' specified_import)* + * import ::= IMPORT import_path (AS MODULE)? ';' * * @return true if import succeeded */ @@ -1957,7 +1951,12 @@ static inline bool parse_import(Context *context) } else { - context_add_import(context, path, NO_TOKEN, NO_TOKEN); + bool private = try_consume(context, TOKEN_AS); + if (private) + { + CONSUME_OR(TOKEN_MODULE, false); + } + context_add_import(context, path, NO_TOKEN, NO_TOKEN, private); } TRY_CONSUME_EOS_OR(false); return true; @@ -2125,10 +2124,6 @@ Decl *parse_top_level_statement(Context *context) visibility = VISIBLE_PUBLIC; advance(context); break; - case TOKEN_LOCAL: - visibility = VISIBLE_LOCAL; - advance(context); - break; case TOKEN_EXTERN: visibility = VISIBLE_EXTERN; advance(context); diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 292293515..11f5b5333 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -19,6 +19,7 @@ static inline Ast *parse_declaration_stmt(Context *context) { Ast *decl_stmt = AST_NEW_TOKEN(AST_DECLARE_STMT, context->tok); decl_stmt->declare_stmt = TRY_DECL_OR(parse_decl(context), poisoned_ast); + decl_stmt->declare_stmt->var.is_static = try_consume(context, TOKEN_STATIC); CONSUME_OR(TOKEN_EOS, poisoned_ast); return decl_stmt; } @@ -667,7 +668,7 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context) if (expr->expr_kind == EXPR_TYPEINFO) { ast->ast_kind = AST_DECLARE_STMT; - ast->declare_stmt = TRY_DECL_OR(parse_decl_after_type(context, true, expr->type_expr), poisoned_ast); + ast->declare_stmt = TRY_DECL_OR(parse_decl_after_type(context, expr->type_expr), poisoned_ast); ast->declare_stmt->var.failable = failable; } else @@ -1009,7 +1010,7 @@ Ast *parse_stmt(Context *context) return parse_try_stmt(context); case TOKEN_DEFINE: return parse_define_stmt(context); - case TOKEN_LOCAL: // Local means declaration! + case TOKEN_STATIC: // Static means declaration! case TOKEN_CONST: // Const means declaration! return parse_declaration_stmt(context); case TOKEN_AT: diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 936b71e69..6481b6735 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -132,11 +132,14 @@ static inline void parse_translation_unit(Context *context) } } -void parse_file(Context *context) +bool parse_file(Context *context) { lexer_init_with_file(&context->lexer, context->file); - if (diagnostics.errors) return; + if (global_context.errors_found) return false; parse_translation_unit(context); + if (!context->module) return false; + vec_add(context->module->contexts, context); + return true; } diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index b5bce5a90..9692817d6 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -51,7 +51,7 @@ Ast *parse_jump_stmt_no_eos(Context *context); bool parse_switch_body(Context *context, Ast ***cases, TokenType case_type, TokenType default_type, bool allow_multiple_values); Expr *parse_expression_list(Context *context); -Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type); +Decl *parse_decl_after_type(Context *context, TypeInfo *type); bool parse_param_list(Context *context, Expr ***result, TokenType param_end, bool *unsplat); Expr *parse_type_compound_literal_expr_after_type(Context *context, TypeInfo *type_info); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 10f6c5942..0b44eaf29 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1020,11 +1020,107 @@ static inline bool sema_analyse_generic(Context *context, Decl *decl) } -static inline bool sema_analyse_define(Context *context, Decl *decl) +static bool sema_analyse_plain_define(Context *c, Decl *decl, Decl *symbol) { - Path *path = decl->generic_decl.path; + unsigned parameter_count = vec_size(symbol->module->parameters); + if (parameter_count > 0) + { + SEMA_ERROR(decl, "Using 'define' with parameterized modules, requires parameters - did you forget them?"); + return false; + } TODO - return true; +} + +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 +} +static bool sema_analyse_parameterized_define(Context *c, Decl *decl, Module *module) +{ + Expr **params = decl->define_decl.params; + unsigned parameter_count = vec_size(module->parameters); + assert(parameter_count > 0); + if (parameter_count != vec_size(params)) + { + 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; + } + char *param_path = c->path_scratch; + memcpy(param_path, module->name->module, module->name->len); + unsigned offset = module->name->len; + param_path[offset++] = '('; + 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; + } + if (!sema_resolve_type_info(c, expr->type_expr)) return false; + if (i != 0) param_path[offset++] = ','; + const char *type_name = expr->type_expr->type->canonical->name; + unsigned len = strlen(type_name); + memcpy(param_path + offset, type_name, len); + offset += len; + } + 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); + 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; + instantiated_module = sema_instantiate_module(c, module, path, decl->define_decl.params); + TODO + } + TODO +} +static inline bool sema_analyse_define(Context *c, Decl *decl) +{ + Path *path = decl->define_decl.path; + if (path) + { + VECEACH(c->imports, i) + { + Decl *import = c->imports[i]; + if (path->module == import->import.path->module) + { + return sema_analyse_parameterized_define(c, decl, import->module); + } + } + } + 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) + { + 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; + } + 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); } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index d5430adf9..fb930c762 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -10,21 +10,8 @@ * - Disallow jumping in and out of an expression block. */ -static Expr **expr_copy_expr_list_from_macro(Context *context, Expr **expr_list); -static Expr *expr_copy_from_macro(Context *context, Expr *source_expr); -static Ast *ast_copy_from_macro(Context *context, Ast *source); -static Ast **ast_copy_list_from_macro(Context *context, Ast **to_copy); -static Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy); -static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source); static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr); -#define MACRO_COPY_DECL(x) x = decl_copy_local_from_macro(context, x) -#define MACRO_COPY_EXPR(x) x = expr_copy_from_macro(context, x) -#define MACRO_COPY_TYPE(x) x = type_info_copy_from_macro(context, x) -#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(context, x) -#define MACRO_COPY_EXPR_LIST(x) x = expr_copy_expr_list_from_macro(context, x) -#define MACRO_COPY_AST_LIST(x) x = ast_copy_list_from_macro(context, x) -#define MACRO_COPY_AST(x) x = ast_copy_from_macro(context, x) static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl) { @@ -231,16 +218,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, expr_copy_from_macro(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(context, decl->var.init_expr)); return sema_analyse_expr(context, to, expr); case VARDECL_PARAM_EXPR: - expr_replace(expr, expr_copy_from_macro(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(context, 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, expr_copy_from_macro(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(context, decl->var.init_expr)); return sema_cast_rvalue(context, to, expr); case VARDECL_PARAM: case VARDECL_GLOBAL: @@ -382,23 +369,7 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e return true; } -static inline Decl *decl_copy_local_from_macro(Context *context, Decl *to_copy) -{ - if (!to_copy) return NULL; - assert(to_copy->decl_kind == DECL_VAR); - Decl *copy = COPY(to_copy); - MACRO_COPY_TYPE(copy->var.type_info); - MACRO_COPY_EXPR(copy->var.init_expr); - return copy; -} -static inline Decl *decl_copy_label_from_macro(Context *context, Decl *to_copy, Ast *ast) -{ - if (!to_copy) return NULL; - to_copy = decl_copy_local_from_macro(context, to_copy); - to_copy->label.parent = astid(ast); - return to_copy; -} static inline Decl *decl_find_enum_constant(const char *name, Decl *decl) { @@ -648,7 +619,7 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr case VARDECL_CONST: if (!decl->type) { - Expr *copy = expr_copy_from_macro(context, decl->var.init_expr); + Expr *copy = copy_expr(context, decl->var.init_expr); if (!sema_analyse_expr(context, to, copy)) return false; if (!expr_is_constant_eval(copy)) { @@ -745,7 +716,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, expr_copy_from_macro(context, decl->var.init_expr)); + expr_replace(expr, copy_expr(context, decl->var.init_expr)); return sema_analyse_expr(context, to, expr); } @@ -1214,7 +1185,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 = decl_copy_local_from_macro(context, func_params[i]); + Decl *param = copy_decl(context, func_params[i]); vec_add(params, param); assert(param->decl_kind == DECL_VAR); assert(param->resolve_status == RESOLVE_NOT_DONE); @@ -1303,7 +1274,7 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr bool ok = true; - Ast *body = ast_copy_from_macro(context, decl->macro_decl.body); + Ast *body = copy_ast(context, decl->macro_decl.body); TypeInfo *foo = decl->macro_decl.rtype; @@ -4660,419 +4631,6 @@ static inline bool sema_expr_analyse_const(Type *to, Expr *expr) return true; } -static Ast *ast_shallow_copy(Ast *source) -{ - return COPY(source); -} - -static Expr *expr_shallow_copy(Expr *source) -{ - return COPY(source); -} - - - -static TypeInfo *type_info_copy_from_macro(Context *context, TypeInfo *source) -{ - if (!source) return NULL; - TypeInfo *copy = malloc_arena(sizeof(TypeInfo)); - memcpy(copy, source, sizeof(TypeInfo)); - switch (source->kind) - { - case TYPE_INFO_POISON: - return copy; - case TYPE_INFO_IDENTIFIER: - return copy; - case TYPE_INFO_EXPRESSION: - assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->unresolved_type_expr = expr_copy_from_macro(context, source->unresolved_type_expr); - return copy; - case TYPE_INFO_ARRAY: - assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.len = expr_copy_from_macro(context, source->array.len); - copy->array.base = type_info_copy_from_macro(context, 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 = type_info_copy_from_macro(context, source->array.base); - return copy; - case TYPE_INFO_POINTER: - assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->pointer = type_info_copy_from_macro(context, source->pointer); - return copy; - } - UNREACHABLE -} - - -static Ast** ast_copy_list_from_macro(Context *context, Ast **to_copy) -{ - Ast **result = NULL; - VECEACH(to_copy, i) - { - vec_add(result, ast_copy_from_macro(context, to_copy[i])); - } - return result; -} - -static DesignatorElement** macro_copy_designator_list(Context *context, DesignatorElement **list) -{ - DesignatorElement **result = NULL; - VECEACH(list, i) - { - DesignatorElement *element = MALLOC(sizeof(DesignatorElement)); - DesignatorElement *to_copy = list[i]; - *element = *to_copy; - switch (to_copy->kind) - { - case DESIGNATOR_FIELD: - // Nothing needed - break; - case DESIGNATOR_RANGE: - MACRO_COPY_EXPR(element->index_end_expr); - FALLTHROUGH; - case DESIGNATOR_ARRAY: - MACRO_COPY_EXPR(element->index_expr); - break; - default: - UNREACHABLE - } - vec_add(result, element); - } - return result; -} - -static Expr *expr_copy_from_macro(Context *context, Expr *source_expr) -{ - if (!source_expr) return NULL; - Expr *expr = expr_shallow_copy(source_expr); - switch (source_expr->expr_kind) - { - case EXPR_ENUM_CONSTANT: - case EXPR_MEMBER_ACCESS: - UNREACHABLE - case EXPR_UNDEF: - return expr; - case EXPR_CONST_IDENTIFIER: - case EXPR_MACRO_IDENTIFIER: - case EXPR_CT_IDENT: - case EXPR_MACRO_CT_IDENTIFIER: - case EXPR_HASH_IDENT: - // TODO - return expr; - case EXPR_DESIGNATOR: - expr->designator_expr.path = macro_copy_designator_list(context, expr->designator_expr.path); - MACRO_COPY_EXPR(expr->designator_expr.value); - return expr; - case EXPR_TYPEINFO: - MACRO_COPY_TYPE(expr->type_expr); - return expr; - case EXPR_SLICE_ASSIGN: - MACRO_COPY_EXPR(expr->slice_assign_expr.left); - MACRO_COPY_EXPR(expr->slice_assign_expr.right); - return expr; - case EXPR_SLICE: - MACRO_COPY_EXPR(expr->slice_expr.expr); - MACRO_COPY_EXPR(expr->slice_expr.start); - MACRO_COPY_EXPR(expr->slice_expr.end); - return expr; - case EXPR_LEN: - MACRO_COPY_EXPR(expr->len_expr.inner); - return expr; - case EXPR_CATCH: - case EXPR_TRY: - MACRO_COPY_EXPR(expr->trycatch_expr); - return expr; - case EXPR_DECL_LIST: - MACRO_COPY_AST_LIST(expr->dexpr_list_expr); - return expr; - case EXPR_FAILABLE: - MACRO_COPY_EXPR(expr->failable_expr); - return expr; - case EXPR_ELSE: - MACRO_COPY_EXPR(expr->else_expr.expr); - if (expr->else_expr.is_jump) - { - MACRO_COPY_EXPR(expr->else_expr.else_expr); - } - else - { - MACRO_COPY_AST(expr->else_expr.else_stmt); - } - return expr; - case EXPR_MACRO_BLOCK: - UNREACHABLE - case EXPR_TYPEOF: - MACRO_COPY_EXPR(expr->typeof_expr); - return expr; - case EXPR_COMPOUND_LITERAL: - MACRO_COPY_EXPR(expr->expr_compound_literal.initializer); - MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); - return expr; - case EXPR_EXPR_BLOCK: - MACRO_COPY_AST_LIST(expr->expr_block.stmts); - return expr; - case EXPR_POISONED: - return source_expr; - case EXPR_GUARD: - MACRO_COPY_EXPR(expr->guard_expr.inner); - return expr; - case EXPR_CONST: - return expr; - case EXPR_BINARY: - MACRO_COPY_EXPR(expr->binary_expr.left); - MACRO_COPY_EXPR(expr->binary_expr.right); - return expr; - case EXPR_TERNARY: - MACRO_COPY_EXPR(expr->ternary_expr.cond); - MACRO_COPY_EXPR(expr->ternary_expr.then_expr); - MACRO_COPY_EXPR(expr->ternary_expr.else_expr); - return expr; - case EXPR_UNARY: - MACRO_COPY_EXPR(expr->unary_expr.expr); - return expr; - case EXPR_POST_UNARY: - MACRO_COPY_EXPR(expr->post_expr.expr); - return expr; - case EXPR_TYPEID: - MACRO_COPY_TYPE(expr->typeid_expr); - return expr; - case EXPR_IDENTIFIER: - return expr; - case EXPR_CALL: - MACRO_COPY_EXPR(expr->call_expr.function); - MACRO_COPY_EXPR_LIST(expr->call_expr.arguments); - return expr; - case EXPR_SUBSCRIPT: - MACRO_COPY_EXPR(expr->subscript_expr.expr); - MACRO_COPY_EXPR(expr->subscript_expr.index); - return expr; - case EXPR_GROUP: - MACRO_COPY_EXPR(expr->group_expr->group_expr); - return expr; - case EXPR_ACCESS: - MACRO_COPY_EXPR(expr->access_expr.parent); - return expr; - case EXPR_INITIALIZER_LIST: - MACRO_COPY_EXPR_LIST(expr->initializer_expr.initializer_expr); - return expr; - case EXPR_EXPRESSION_LIST: - MACRO_COPY_EXPR_LIST(expr->expression_list); - return expr; - case EXPR_CAST: - MACRO_COPY_EXPR(expr->cast_expr.expr); - MACRO_COPY_TYPE(expr->cast_expr.type_info); - return expr; - case EXPR_SCOPED_EXPR: - MACRO_COPY_EXPR(expr->expr_scope.expr); - return expr; - } - UNREACHABLE -} - -static Expr **expr_copy_expr_list_from_macro(Context *context, Expr **expr_list) -{ - Expr **result = NULL; - VECEACH(expr_list, i) - { - vec_add(result, expr_copy_from_macro(context, expr_list[i])); - } - return result; -} - - -static inline void copy_flow(Context *context, Ast *ast) -{ - ast->flow.label = decl_copy_label_from_macro(context, ast->flow.label, ast); -} - -static TypeInfo** type_info_copy_list_from_macro(Context *context, TypeInfo **to_copy) -{ - TypeInfo **result = NULL; - VECEACH(to_copy, i) - { - vec_add(result, type_info_copy_from_macro(context, to_copy[i])); - } - return result; -} - -static Ast *ast_copy_from_macro(Context *context, Ast *source) -{ - if (!source) return NULL; - Ast *ast = ast_shallow_copy(source); - switch (source->ast_kind) - { - case AST_DOCS: - ast->directives = ast_copy_list_from_macro(context, ast->directives); - return ast; - case AST_DOC_DIRECTIVE: - switch (ast->doc_directive.kind) - { - case DOC_DIRECTIVE_REQUIRE: - case DOC_DIRECTIVE_ENSURE: - MACRO_COPY_EXPR(ast->doc_directive.contract.decl_exprs); - MACRO_COPY_EXPR(ast->doc_directive.contract.comment); - break; - case DOC_DIRECTIVE_PARAM: - case DOC_DIRECTIVE_ERRORS: - case DOC_DIRECTIVE_PURE: - case DOC_DIRECTIVE_UNKNOWN: - break; - } - return ast; - case AST_POISONED: - return ast; - case AST_ASM_STMT: - TODO - case AST_ASSERT_STMT: - MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); - MACRO_COPY_EXPR(ast->ct_assert_stmt.message); - return ast; - case AST_BREAK_STMT: - return ast; - case AST_CASE_STMT: - MACRO_COPY_AST(ast->case_stmt.body); - if (ast->case_stmt.is_type) - { - MACRO_COPY_TYPE(ast->case_stmt.type_info); - } - else - { - MACRO_COPY_EXPR(ast->case_stmt.expr); - } - return ast; - break; - case AST_CATCH_STMT: - copy_flow(context, ast); - if (ast->catch_stmt.has_err_var) - { - MACRO_COPY_DECL(ast->catch_stmt.err_var); - } - else - { - MACRO_COPY_EXPR(ast->catch_stmt.catchable); - } - if (ast->catch_stmt.is_switch) - { - MACRO_COPY_AST_LIST(ast->catch_stmt.cases); - } - else - { - MACRO_COPY_AST(ast->catch_stmt.body); - } - return ast; - case AST_COMPOUND_STMT: - MACRO_COPY_AST_LIST(ast->compound_stmt.stmts); - return ast; - case AST_CT_COMPOUND_STMT: - MACRO_COPY_AST_LIST(ast->ct_compound_stmt); - return ast; - case AST_CONTINUE_STMT: - TODO - return ast; - case AST_CT_ASSERT: - MACRO_COPY_EXPR(ast->ct_assert_stmt.message); - MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); - return ast; - case AST_CT_IF_STMT: - MACRO_COPY_EXPR(ast->ct_if_stmt.expr); - MACRO_COPY_AST(ast->ct_if_stmt.elif); - MACRO_COPY_AST(ast->ct_if_stmt.then); - return ast; - case AST_CT_ELIF_STMT: - MACRO_COPY_EXPR(ast->ct_elif_stmt.expr); - MACRO_COPY_AST(ast->ct_elif_stmt.then); - MACRO_COPY_AST(ast->ct_elif_stmt.elif); - return ast; - case AST_CT_ELSE_STMT: - MACRO_COPY_AST(ast->ct_else_stmt); - return ast; - case AST_CT_FOR_STMT: - MACRO_COPY_AST(ast->ct_for_stmt.body); - MACRO_COPY_EXPR(ast->ct_for_stmt.expr); - return ast; - case AST_CT_SWITCH_STMT: - MACRO_COPY_EXPR(ast->ct_switch_stmt.cond); - MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body); - return ast; - case AST_DECLARE_STMT: - MACRO_COPY_DECL(ast->declare_stmt); - return ast; - case AST_DEFAULT_STMT: - MACRO_COPY_AST(ast->case_stmt.body); - return ast; - case AST_DEFINE_STMT: - ast->define_stmt = decl_copy_local_from_macro(context, 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); - MACRO_COPY_AST(ast->do_stmt.body); - MACRO_COPY_EXPR(ast->do_stmt.expr); - return ast; - case AST_EXPR_STMT: - MACRO_COPY_EXPR(ast->expr_stmt); - return ast; - case AST_FOR_STMT: - copy_flow(context, 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); - 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); - MACRO_COPY_EXPR(ast->if_stmt.cond); - MACRO_COPY_AST(ast->if_stmt.else_body); - MACRO_COPY_AST(ast->if_stmt.then_body); - return ast; - case AST_NEXT_STMT: - MACRO_COPY_EXPR(ast->next_stmt.switch_expr); - TODO - return ast; - case AST_NOP_STMT: - return ast; - case AST_RETURN_STMT: - MACRO_COPY_EXPR(ast->return_stmt.expr); - return ast; - case AST_SWITCH_STMT: - copy_flow(context, ast); - MACRO_COPY_EXPR(ast->switch_stmt.cond); - MACRO_COPY_AST_LIST(ast->switch_stmt.cases); - return ast; - case AST_TRY_STMT: - MACRO_COPY_EXPR(ast->try_stmt.decl_expr); - MACRO_COPY_AST(ast->try_stmt.body); - return ast; - case AST_UNREACHABLE_STMT: - return ast; - case AST_VOLATILE_STMT: - TODO - return ast; - case AST_WHILE_STMT: - copy_flow(context, ast); - MACRO_COPY_EXPR(ast->while_stmt.cond); - MACRO_COPY_AST(ast->while_stmt.body); - return ast; - case AST_SCOPED_STMT: - MACRO_COPY_AST(ast->scoped_stmt.stmt); - return ast; - } - UNREACHABLE; -} @@ -5088,10 +4646,6 @@ static inline bool sema_expr_analyse_type(Context *context, Expr *expr) } - - - - static inline bool sema_expr_analyse_expr_block(Context *context, Type *to, Expr *expr) { bool success = true; @@ -5311,7 +4865,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 = expr_copy_from_macro(context, decl->var.init_expr); + Expr *copy = copy_expr(context, 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_name_resolution.c b/src/compiler/sema_name_resolution.c index 896f1e4df..1c542f9df 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -33,37 +33,68 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path *ambiguous_other_decl = NULL; Decl *decl = NULL; bool path_found = false; + + // 1. Do we match our own path? if (matches_subpath(context->module->name, path)) { - return stable_get(&context->module->symbols, symbol); + // 2. If so just get the symbol. + return module_find_symbol(context->module, symbol); } + // 3. Loop over imports. VECEACH(context->imports, i) { Decl *import = context->imports[i]; - // Partial imports - if (TOKVALID(import->import.symbol) && TOKSTR(import->import.symbol) != symbol) continue; - // Full import, first match the subpath. + // 4. Don't look through parameterized modules. + if (import->module->parameters) continue; + + // TODO handle partial imports. + + // 5. Can we match a subpath? if (path->len > import->import.path->len) continue; if (!matches_subpath(import->import.path, path)) continue; + + // 6. We have a sub path match at least. path_found = true; - Decl *found = module_find_symbol(import->module, symbol, MODULE_SYMBOL_SEARCH_EXTERNAL, private_decl); + + // 7. Find the symbol + Decl *found = module_find_symbol(import->module, symbol); + + // 8. No match, so continue if (!found) continue; + + // 9. If we found something private and we don't import privately? + if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) + { + // 10. Register this as a possible private decl. + *private_decl = found; + continue; + } + + // 11. Did we already have a match? if (decl) { + // 12. Then set an ambiguous match. *ambiguous_other_decl = found; continue; } + + // 13. We've found a match. decl = found; + *private_decl = NULL; } + // 14. If we didn't find one. if (!decl) { + // 15. If the path wasn't found, then let's say that. if (!path_found) { SEMA_ERROR(path, "Unknown module '%.*s', did you forget to import it?", path->len, path->module); return poisoned_decl; } + // 16. Otherwise return null. return NULL; } + // 17. Store that this external symbol is used and return. context_register_external_symbol(context, decl); return decl; } @@ -110,8 +141,8 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl if (decl) return decl; - // Search in the module and child modules. - decl = module_find_symbol(context->module, symbol, MODULE_SYMBOL_SEARCH_THIS, private_decl); + // Search in the module. + decl = module_find_symbol(context->module, symbol); if (decl) { @@ -124,14 +155,22 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl { Decl *import = context->imports[i]; if (!decl_ok(import)) continue; - Decl *found = module_find_symbol(import->module, symbol, MODULE_SYMBOL_SEARCH_EXTERNAL, private_decl); + Decl *found = module_find_symbol(import->module, symbol); if (!found) continue; + // If we found something private and we don't import privately? + if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) + { + // 10. Register this as a possible private decl. + *private_decl = found; + continue; + } if (decl) { *ambiguous_other_decl = found; continue; } decl = found; + *private_decl = found; } if (!decl) return NULL; context_register_external_symbol(context, decl); diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index ac8a1ee22..84df69c25 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -16,51 +16,87 @@ void context_add_intrinsic(Context *context, const char *name) assert(!old); } -void sema_analysis_pass_process_imports(Context *context) +void sema_analysis_pass_process_imports(Module *module) { - DEBUG_LOG("Pass: Importing dependencies for %s", context->file->name); - unsigned imports = vec_size(context->imports); - for (unsigned i = 0; i < imports; i++) + DEBUG_LOG("Pass: Importing dependencies for files in module '%s'.", module->name->module); + unsigned import_count = 0; + VECEACH(module->contexts, index) { - Decl *import = context->imports[i]; - import->resolve_status = RESOLVE_RUNNING; - Path *path = import->import.path; - Module *module = stable_get(&global_context.modules, path->module); - DEBUG_LOG("- Import of %s.", path->module); - if (!module) + // 1. Loop through each context in the module. + Context *context = module->contexts[index]; + DEBUG_LOG("Checking imports for %s.", context->file->name); + + // 2. Loop through imports + unsigned imports = vec_size(context->imports); + for (unsigned i = 0; i < imports; i++) { - SEMA_ERROR(import, "No module named '%s' could be found.", path->module); - decl_poison(import); - continue; - } - import->module = module; - for (unsigned j = 0; j < i; j++) - { - if (import->module == context->imports[j]->module) + // 3. Begin analysis + Decl *import = context->imports[i]; + assert(import->resolve_status == RESOLVE_NOT_DONE); + import->resolve_status = RESOLVE_RUNNING; + + // 4. Find the module. + Path *path = import->import.path; + Module *import_module = global_context_find_module(path->module); + + // 5. Do we find it? + if (!import_module) { - SEMA_ERROR(import, "Module '%s' imported more than once.", path->module); - SEMA_PREV(context->imports[i], "Previous import was here"); + SEMA_ERROR(import, "No module named '%s' could be found, did you type the name right?", path->module); decl_poison(import); - break; + continue; + } + + // 6. Importing itself is not allowed. + if (import_module == module) + { + SEMA_ERROR(import, "Importing the current module is not allowed, you need to remove it."); + decl_poison(import); + continue; + } + + // 6. Assign the module. + DEBUG_LOG("* Import of %s.", path->module); + import->module = import_module; + for (unsigned j = 0; j < i; j++) + { + // 7. We might run into multiple imports of the same package. + if (import->module == context->imports[j]->module) + { + SEMA_ERROR(import, "Module '%s' was imported more than once, please remove the duplicates.", path->module); + SEMA_PREV(context->imports[j], "Previous import was here"); + decl_poison(import); + break; + } } } + import_count += imports; + // TODO probably remove this: + context_add_intrinsic(context, kw___round); + context_add_intrinsic(context, kw___trunc); + context_add_intrinsic(context, kw___ceil); + context_add_intrinsic(context, kw___sqrt); } - context_add_intrinsic(context, kw___round); - context_add_intrinsic(context, kw___trunc); - context_add_intrinsic(context, kw___ceil); - context_add_intrinsic(context, kw___sqrt); - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + DEBUG_LOG("Pass finished processing %d import(s) with %d error(s).", import_count, global_context.errors_found); } -void sema_analysis_pass_register_globals(Context *context) +void sema_analysis_pass_register_globals(Module *module) { - DEBUG_LOG("Pass: Register globals for %s", context->file->name); - VECEACH(context->global_decls, i) + DEBUG_LOG("Pass: Register globals for module '%s'.", module->name->module); + + VECEACH(module->contexts, index) { - context_register_global_decl(context, context->global_decls[i]); + Context *context = module->contexts[index]; + DEBUG_LOG("Processing %s.", context->file->name); + Decl **decls = context->global_decls; + VECEACH(decls, i) + { + context_register_global_decl(context, decls[i]); + } + vec_resize(context->global_decls, 0); } - vec_resize(context->global_decls, 0); - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } static inline void sema_append_decls(Context *context, Decl **decls) @@ -110,23 +146,28 @@ static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if) void sema_analysis_pass_conditional_compilation(Context *context) { + // 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++) { // Also handle switch! sema_analyse_top_level_if(context, context->ct_ifs[i]); } - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } void sema_analysis_pass_ct_assert(Context *context) { + if (context->module->parameters) return; + DEBUG_LOG("Pass: $assert checks %s", context->file->name); VECEACH(context->ct_asserts, i) { sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]); } - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } static inline bool analyse_func_body(Context *context, Decl *decl) @@ -138,6 +179,8 @@ static inline bool analyse_func_body(Context *context, Decl *decl) void sema_analysis_pass_decls(Context *context) { + if (context->module->parameters) return; + DEBUG_LOG("Pass: Decl analysis %s", context->file->name); context->current_scope = &context->scopes[0]; context->current_scope->scope_id = 0; @@ -174,13 +217,15 @@ void sema_analysis_pass_decls(Context *context) { sema_analyse_decl(context, context->generic_defines[i]); } - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } void sema_analysis_pass_functions(Context *context) { DEBUG_LOG("Pass: Function analysis %s", context->file->name); + if (context->module->parameters) return; + VECEACH(context->methods, i) { analyse_func_body(context, context->methods[i]); @@ -190,5 +235,5 @@ void sema_analysis_pass_functions(Context *context) analyse_func_body(context, context->functions[i]); } - DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors); + DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found); } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 0357112ba..0b1ee90f7 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1384,7 +1384,7 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa if (switch_type_flattened->array.base->type_kind == TYPE_U8) break; FALLTHROUGH; default: - sema_error_range3(expr_span, "It is not possible to switch over '%s'.", type_to_error_string(switch_type)); + sema_error_range(expr_span, "It is not possible to switch over '%s'.", type_to_error_string(switch_type)); return false; } Ast *default_case = NULL; diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index 51907297a..9b95752a0 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -226,8 +226,6 @@ const char *token_type_to_string(TokenType type) return "import"; case TOKEN_INTERFACE: return "interface"; - case TOKEN_LOCAL: - return "local"; case TOKEN_MACRO: return "macro"; case TOKEN_MODULE: @@ -240,6 +238,8 @@ const char *token_type_to_string(TokenType type) return "public"; case TOKEN_RETURN: return "return"; + case TOKEN_STATIC: + return "static"; case TOKEN_STRUCT: return "struct"; case TOKEN_SWITCH: @@ -306,7 +306,6 @@ const char *token_type_to_string(TokenType type) return "uptrdiff"; case TOKEN_HALF: return "half"; - case TOKEN_DOCS_EOL: return "EOL"; case TOKEN_DOCS_START: diff --git a/src/utils/lib.h b/src/utils/lib.h index 97754a7ea..815628ac8 100644 --- a/src/utils/lib.h +++ b/src/utils/lib.h @@ -326,8 +326,11 @@ static inline void* _expand(void *vec, size_t element_size) return vec; } + +#define CONCAT_INNER(a, b) a ## b +#define CONCAT(a, b) CONCAT_INNER(a, b) #define VECEACH(_vec, _index) \ - for (unsigned _index = 0, __vecsize = vec_size(_vec); _index < __vecsize; _index++) + for (unsigned _index = 0, CONCAT(__vecsize_, __LINE__) = vec_size(_vec); _index < CONCAT(__vecsize_, __LINE__); _index++) #define VECNEW(_type, _capacity) ((_type *)(_vec_new(sizeof(_type), _capacity) + 1)) diff --git a/test/test_suite/functions/assorted_tests.c3t b/test/test_suite/functions/assorted_tests.c3t index 187914a71..479823689 100644 --- a/test/test_suite/functions/assorted_tests.c3t +++ b/test/test_suite/functions/assorted_tests.c3t @@ -37,7 +37,7 @@ struct InternalFPF char type; } -local func void setInternalFPFZero(InternalFPF* dest) @noinline +func void setInternalFPFZero(InternalFPF* dest) @noinline { dest.type = 0; } diff --git a/test/test_suite/globals/recursive_locals.c3 b/test/test_suite/globals/recursive_locals.c3 index 2cac48fa2..1709dbf9f 100644 --- a/test/test_suite/globals/recursive_locals.c3 +++ b/test/test_suite/globals/recursive_locals.c3 @@ -1,11 +1,12 @@ + struct List { int x; List* next; } -local const List A = { 7, &B }; -local const List B = { 8, &A }; +const List A = { 7, &B }; +const List B = { 8, &A }; extern List d; diff --git a/test/test_suite/import/import_error.c3 b/test/test_suite/import/import_error.c3 new file mode 100644 index 000000000..00d88652f --- /dev/null +++ b/test/test_suite/import/import_error.c3 @@ -0,0 +1,7 @@ +module test; +import std::mem; +import std::mem; // #error: was imported more +import hello_world; // #error: No module named +import test; // #error: Importing the current + +func void hello() { } \ No newline at end of file diff --git a/test/test_suite/module/unknown_modules.c3 b/test/test_suite/module/unknown_modules.c3 index 42c12d96c..a800c0fc8 100644 --- a/test/test_suite/module/unknown_modules.c3 +++ b/test/test_suite/module/unknown_modules.c3 @@ -1,4 +1,4 @@ module test; -import foo; // #error: No module named 'foo' could be found. -import bar; // #error: No module named 'bar' could be found. \ No newline at end of file +import foo; // #error: No module named 'foo' could be found +import bar; // #error: No module named 'bar' could be found \ No newline at end of file diff --git a/test/test_suite/visibility/local_global_func.c3t b/test/test_suite/visibility/local_global_func.c3t deleted file mode 100644 index 81157292d..000000000 --- a/test/test_suite/visibility/local_global_func.c3t +++ /dev/null @@ -1,31 +0,0 @@ -module test; - -int x; -local int y = 12; - -local func void foo(int z) @noinline -{ - y = z; -} - -func void* test() -{ - foo(12); - return &y; -} - -// #expect: local_global_func.ll - -@x = protected global i32 0, align 4 -@y = hidden global i32 12, align 4 - -define internal void @test.foo(i32 %0) - - %z = alloca i32, align 4 - store i32 %0, i32* %z, align 4 - %1 = load i32, i32* %z, align 4 - store i32 %1, i32* @y, align 4 - ret void -define i8* @test.test() - call void @test.foo(i32 12) - ret i8* bitcast (i32* @y to i8*)