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:
Christoffer Lerno
2021-05-06 15:57:00 +02:00
committed by Christoffer Lerno
parent 3bd638bf77
commit f7919edb35
26 changed files with 972 additions and 709 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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
View 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, &copy->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, &copy->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, &copy->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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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:

View File

@@ -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))

View File

@@ -37,7 +37,7 @@ struct InternalFPF
char type;
}
local func void setInternalFPFZero(InternalFPF* dest) @noinline
func void setInternalFPFZero(InternalFPF* dest) @noinline
{
dest.type = 0;
}

View File

@@ -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;

View 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() { }

View File

@@ -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

View File

@@ -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*)