mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Split modules into generic and normal modules on the top level. Prepare for static. Change local -> static as keyword. Add private include. Remove old sub module search.
This commit is contained in:
committed by
Christoffer Lerno
parent
3bd638bf77
commit
f7919edb35
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
523
src/compiler/copying.c
Normal file
523
src/compiler/copying.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,7 @@
|
||||
#include "compiler_internal.h"
|
||||
#include <math.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -37,7 +37,7 @@ struct InternalFPF
|
||||
char type;
|
||||
}
|
||||
|
||||
local func void setInternalFPFZero(InternalFPF* dest) @noinline
|
||||
func void setInternalFPFZero(InternalFPF* dest) @noinline
|
||||
{
|
||||
dest.type = 0;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
7
test/test_suite/import/import_error.c3
Normal file
7
test/test_suite/import/import_error.c3
Normal file
@@ -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() { }
|
||||
@@ -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.
|
||||
import foo; // #error: No module named 'foo' could be found
|
||||
import bar; // #error: No module named 'bar' could be found
|
||||
@@ -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*)
|
||||
Reference in New Issue
Block a user