Files
c3c/src/compiler/compiler.c

282 lines
7.5 KiB
C

// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
#include "compiler_internal.h"
#include "../build/build_options.h"
Compiler compiler;
Vmem ast_arena;
Vmem expr_arena;
Vmem sourceloc_arena;
Vmem toktype_arena;
Vmem tokdata_arena;
Vmem decl_arena;
Vmem type_info_arena;
void compiler_init(void)
{
// Skip library detection.
//compiler.lib_dir = find_lib_dir();
//DEBUG_LOG("Found std library: %s", compiler.lib_dir);
stable_init(&compiler.modules, 64);
stable_init(&compiler.global_symbols, 0x1000);
vmem_init(&ast_arena, 4 * 1024);
vmem_init(&expr_arena, 4 * 1024);
vmem_init(&decl_arena, 1024);
vmem_init(&sourceloc_arena, 4 * 1024);
vmem_init(&toktype_arena, 4 * 1024);
vmem_init(&tokdata_arena, 4 * 1024);
vmem_init(&type_info_arena, 1024);
// Create zero index value.
SourceLocation *loc = sourceloc_calloc();
char *token_type = toktype_calloc();
TokenData *data = tokdata_calloc();
}
static void compiler_lex(BuildTarget *target)
{
VECEACH(target->sources, i)
{
bool loaded = false;
File *file = source_file_load(target->sources[i], &loaded);
if (loaded) continue;
Lexer lexer;
lexer_init_with_file(&lexer, file);
printf("# %s\n", file->full_path);
while (1)
{
Token token = lexer_advance(&lexer);
printf("%s ", token_type_to_string(token.type));
if (token.type == TOKEN_EOF) break;
}
printf("\n");
}
exit(EXIT_SUCCESS);
}
void compiler_parse(BuildTarget *target)
{
VECEACH(target->sources, i)
{
bool loaded = false;
File *file = source_file_load(target->sources[i], &loaded);
if (loaded) continue;
diag_reset();
Context *context = context_create(file, target);
parse_file(context);
context_print_ast(context, stdout);
}
exit(EXIT_SUCCESS);
}
void compiler_compile(BuildTarget *target)
{
Context **contexts = NULL;
diag_reset();
//vec_add(target->sources, strformat("%s/std/builtin.c3", compiler.lib_dir));
//vec_add(target->sources, strformat("%s/std/io.c3", compiler.lib_dir));
VECEACH(target->sources, i)
{
bool loaded = false;
File *file = source_file_load(target->sources[i], &loaded);
if (loaded) continue;
Context *context = context_create(file, target);
vec_add(contexts, context);
parse_file(context);
}
assert(contexts);
VECEACH(contexts, i)
{
sema_analysis_pass_process_imports(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
{
sema_analysis_pass_register_globals(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
{
sema_analysis_pass_conditional_compilation(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
{
sema_analysis_pass_decls(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
{
sema_analysis_pass_ct_assert(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
VECEACH(contexts, i)
{
sema_analysis_pass_functions(contexts[i]);
}
if (diagnostics.errors > 0) exit(EXIT_FAILURE);
if (build_options.command == COMMAND_GENERATE_HEADERS)
{
VECEACH(contexts, i)
{
Context *context = contexts[i];
header_gen(context);
}
return;
}
llvm_codegen_setup();
VECEACH(contexts, i)
{
Context *context = contexts[i];
llvm_codegen(context);
}
printf("-- AST/EXPR INFO -- \n");
printf(" * Ast memory use: %llukb\n", (unsigned long long)ast_arena.allocated / 1024);
printf(" * Decl memory use: %llukb\n", (unsigned long long)decl_arena.allocated / 1024);
printf(" * Expr memory use: %llukb\n", (unsigned long long)expr_arena.allocated / 1024);
printf(" * TypeInfo memory use: %llukb\n", (unsigned long long)type_info_arena.allocated / 1024);
printf(" * Token memory use: %llukb\n", (unsigned long long)(toktype_arena.allocated) / 1024);
printf(" * Sourceloc memory use: %llukb\n", (unsigned long long)(sourceloc_arena.allocated) / 1024);
printf(" * Token data memory use: %llukb\n", (unsigned long long)(tokdata_arena.allocated) / 1024);
print_arena_status();
exit(EXIT_SUCCESS);
}
static void target_expand_source_names(BuildTarget *target)
{
const char **files = NULL;
VECEACH(target->sources, i)
{
const char *name = target->sources[i];
size_t name_len = strlen(name);
if (name_len < 1) goto INVALID_NAME;
if (name[name_len - 1] == '*')
{
if (name_len == 1 || name[name_len - 2] == '/')
{
char *path = strdup(name);
path[name_len - 1] = '\0';
file_add_wildcard_files(&files, path, false);
free(path);
continue;
}
if (name[name_len - 2] != '*') goto INVALID_NAME;
if (name_len == 2 || name[name_len - 3] == '/')
{
char *path = strdup(name);
path[name_len - 2] = '\0';
file_add_wildcard_files(&files, path, true);
free(path);
continue;
}
goto INVALID_NAME;
}
if (name_len < 4) goto INVALID_NAME;
if (strcmp(&name[name_len - 3], ".c3") != 0) goto INVALID_NAME;
vec_add(files, name);
continue;
INVALID_NAME:
error_exit("File names must end with .c3 or they cannot be compiled: '%s' is invalid.", name);
}
target->sources = files;
}
void compile_files(BuildTarget *target)
{
if (!target)
{
target = CALLOCS(BuildTarget);
target->type = TARGET_TYPE_EXECUTABLE;
target->sources = build_options.files;
target->name = "a.out";
}
target_expand_source_names(target);
target_setup();
if (!vec_size(target->sources)) error_exit("No files to compile.");
switch (build_options.compile_option)
{
case COMPILE_LEX_ONLY:
compiler_lex(target);
break;
case COMPILE_LEX_PARSE_ONLY:
compiler_parse(target);
break;
case COMPILE_OUTPUT_HEADERS:
default:
compiler_compile(target);
break;
}
}
Decl *compiler_find_symbol(const char *string)
{
return stable_get(&compiler.global_symbols, string);
}
void compiler_add_type(Type *type)
{
DEBUG_LOG("Created type %s.", type->name);
assert(type_ok(type));
VECADD(compiler.type, type);
}
Module *compiler_find_or_create_module(Path *module_name)
{
Module *module = stable_get(&compiler.modules, module_name->module);
if (module)
{
// We might have gotten an auto-generated module, if so
// update the path here.
if (module->name->span.loc.index == INVALID_TOKEN_ID.index && module_name->span.loc.index != INVALID_TOKEN_ID.index)
{
module->name = module_name;
}
return module;
}
DEBUG_LOG("Creating module %s.", module_name->module);
// Set up the module.
module = CALLOCS(Module);
module->name = module_name;
stable_init(&module->symbols, 0x10000);
stable_set(&compiler.modules, module_name->module, 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);
}
return module;
}
void compiler_register_public_symbol(Decl *decl)
{
assert(decl->name);
Decl *prev = stable_get(&compiler.global_symbols, decl->name);
// If the previous symbol was already declared globally, remove it.
stable_set(&compiler.global_symbols, decl->name, prev ? poisoned_decl : decl);
STable *sub_module_space = stable_get(&compiler.qualified_symbols, decl->module->name->module);
if (!sub_module_space)
{
sub_module_space = malloc_arena(sizeof(*sub_module_space));
stable_init(sub_module_space, 0x100);
stable_set(&compiler.qualified_symbols, decl->module->name->module, sub_module_space);
}
prev = stable_get(sub_module_space, decl->name);
stable_set(sub_module_space, decl->name, prev ? poisoned_decl : decl);
}