mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
252 lines
6.6 KiB
C
252 lines
6.6 KiB
C
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by a LGPLv3.0
|
|
// a copy of which can be found in the LICENSE file.
|
|
|
|
#include "sema_internal.h"
|
|
|
|
void context_add_intrinsic(Context *context, const char *name)
|
|
{
|
|
Decl *decl = decl_calloc();
|
|
decl->module = context->module;
|
|
decl->decl_kind = DECL_FUNC;
|
|
decl->resolve_status = RESOLVE_DONE;
|
|
decl->func.is_builtin = true;
|
|
decl->name = name;
|
|
Decl *old = stable_set(&context->local_symbols, decl->name, decl);
|
|
assert(!old);
|
|
}
|
|
|
|
void sema_analysis_pass_process_imports(Module *module)
|
|
{
|
|
DEBUG_LOG("Pass: Importing dependencies for files in module '%s'.", module->name->module);
|
|
|
|
unsigned import_count = 0;
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
// 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++)
|
|
{
|
|
// 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, "No module named '%s' could be found, did you type the name right?", path->module);
|
|
decl_poison(import);
|
|
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);
|
|
}
|
|
DEBUG_LOG("Pass finished processing %d import(s) with %d error(s).", import_count, global_context.errors_found);
|
|
}
|
|
|
|
void sema_analysis_pass_register_globals(Module *module)
|
|
{
|
|
DEBUG_LOG("Pass: Register globals for module '%s'.", module->name->module);
|
|
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
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);
|
|
}
|
|
|
|
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
|
}
|
|
|
|
static inline void sema_append_decls(Context *context, Decl **decls)
|
|
{
|
|
VECEACH(decls, i)
|
|
{
|
|
context_register_global_decl(context, decls[i]);
|
|
}
|
|
}
|
|
|
|
static inline bool sema_analyse_top_level_if(Context *context, Decl *ct_if)
|
|
{
|
|
int res = sema_check_comp_time_bool(context, ct_if->ct_if_decl.expr);
|
|
if (res == -1) return false;
|
|
if (res)
|
|
{
|
|
// Append declarations
|
|
sema_append_decls(context, ct_if->ct_if_decl.then);
|
|
return true;
|
|
}
|
|
|
|
// False, so check elifs
|
|
Decl *ct_elif = ct_if->ct_if_decl.elif;
|
|
while (ct_elif)
|
|
{
|
|
if (ct_elif->decl_kind == DECL_CT_ELIF)
|
|
{
|
|
res = sema_check_comp_time_bool(context, ct_elif->ct_elif_decl.expr);
|
|
if (res == -1) return false;
|
|
if (res)
|
|
{
|
|
sema_append_decls(context, ct_elif->ct_elif_decl.then);
|
|
return true;
|
|
}
|
|
ct_elif = ct_elif->ct_elif_decl.elif;
|
|
}
|
|
else
|
|
{
|
|
assert(ct_elif->decl_kind == DECL_CT_ELSE);
|
|
sema_append_decls(context, ct_elif->ct_elif_decl.then);
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void sema_analysis_pass_conditional_compilation(Module *module)
|
|
{
|
|
|
|
DEBUG_LOG("Pass: Top level conditionals %s", module->name->module);
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
Context *context = module->contexts[index];
|
|
for (unsigned i = 0; i < vec_size(context->ct_ifs); i++)
|
|
{
|
|
// Also handle switch!
|
|
sema_analyse_top_level_if(context, context->ct_ifs[i]);
|
|
}
|
|
}
|
|
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
|
}
|
|
|
|
void sema_analysis_pass_ct_assert(Module *module)
|
|
{
|
|
DEBUG_LOG("Pass: $assert checks %s", module->name->module);
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
Context *context = module->contexts[index];
|
|
VECEACH(context->ct_asserts, i)
|
|
{
|
|
sema_analyse_ct_assert_stmt(context, context->ct_asserts[i]);
|
|
}
|
|
}
|
|
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
|
}
|
|
|
|
static inline bool analyse_func_body(Context *context, Decl *decl)
|
|
{
|
|
if (!decl->func.body) return true;
|
|
if (!sema_analyse_function_body(context, decl)) return decl_poison(decl);
|
|
return true;
|
|
}
|
|
|
|
void sema_analysis_pass_decls(Module *module)
|
|
{
|
|
DEBUG_LOG("Pass: Decl analysis %s", module->name->module);
|
|
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
Context *context = module->contexts[index];
|
|
context->current_scope = &global_context.scopes[0];
|
|
context->current_scope->scope_id = 0;
|
|
context->last_local = &global_context.locals[0];
|
|
VECEACH(context->enums, i)
|
|
{
|
|
sema_analyse_decl(context, context->enums[i]);
|
|
}
|
|
VECEACH(context->types, i)
|
|
{
|
|
sema_analyse_decl(context, context->types[i]);
|
|
}
|
|
VECEACH(context->macros, i)
|
|
{
|
|
sema_analyse_decl(context, context->macros[i]);
|
|
}
|
|
VECEACH(context->generics, i)
|
|
{
|
|
sema_analyse_decl(context, context->generics[i]);
|
|
}
|
|
VECEACH(context->methods, i)
|
|
{
|
|
sema_analyse_decl(context, context->methods[i]);
|
|
}
|
|
VECEACH(context->vars, i)
|
|
{
|
|
sema_analyse_decl(context, context->vars[i]);
|
|
}
|
|
VECEACH(context->functions, i)
|
|
{
|
|
sema_analyse_decl(context, context->functions[i]);
|
|
}
|
|
VECEACH(context->generic_defines, i)
|
|
{
|
|
sema_analyse_decl(context, context->generic_defines[i]);
|
|
}
|
|
}
|
|
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
|
}
|
|
|
|
void sema_analysis_pass_functions(Module *module)
|
|
{
|
|
DEBUG_LOG("Pass: Function analysis %s", module->name->module);
|
|
|
|
VECEACH(module->contexts, index)
|
|
{
|
|
Context *context = module->contexts[index];
|
|
VECEACH(context->methods, i)
|
|
{
|
|
analyse_func_body(context, context->methods[i]);
|
|
}
|
|
VECEACH(context->functions, i)
|
|
{
|
|
analyse_func_body(context, context->functions[i]);
|
|
}
|
|
|
|
}
|
|
|
|
DEBUG_LOG("Pass finished with %d error(s).", global_context.errors_found);
|
|
}
|