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