rework of module import
This commit is contained in:
parent
cf59e9640d
commit
76f5a0fd7f
|
@ -1,13 +0,0 @@
|
|||
[project]
|
||||
name = "gscstd"
|
||||
version = "0.1.0"
|
||||
description = "glibc build of the gemstone standard library"
|
||||
license = "GPL-2.0"
|
||||
authors = [ "Sven Vogel <sven.vogel123@web.de>" ]
|
||||
|
||||
[target.gscstd]
|
||||
import-paths = [ "glibc" ]
|
||||
root = "glibc/std.gsc"
|
||||
mode = "library"
|
||||
output = "bin"
|
||||
archive = "archive"
|
|
@ -0,0 +1,22 @@
|
|||
[project]
|
||||
name = "gscstd"
|
||||
version = "0.1.0"
|
||||
description = "Test applications for the GSC standard library."
|
||||
license = "GPL-2.0"
|
||||
authors = [ "Sven Vogel <sven.vogel123@web.de>" ]
|
||||
|
||||
[[targets]]
|
||||
name = "gsc-libc"
|
||||
import-paths = [ "libc" ]
|
||||
root = "libc/std.gsc"
|
||||
mode = "library"
|
||||
output = "bin"
|
||||
archive = "archive"
|
||||
driver = "ld.lld"
|
||||
print_asm = true
|
||||
print_ir = true
|
||||
print_ast = true
|
||||
|
||||
[[targets.dependencies]]
|
||||
# link against system default libc shared library
|
||||
libc = { shared = true }
|
|
@ -2,13 +2,13 @@
|
|||
# Bootstrap module for libgscstd-glibc
|
||||
# used on GNU/Linux operating systems
|
||||
|
||||
import "os"
|
||||
include "os"
|
||||
|
||||
# main function is to be implemented by the application source
|
||||
fun main()
|
||||
|
||||
# entrypoint function
|
||||
fun start() {
|
||||
fun _start() {
|
||||
main()
|
||||
exit(0 as i32)
|
||||
}
|
|
@ -336,6 +336,29 @@ void AST_merge_modules(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {
|
|||
AST_delete_node(src);
|
||||
}
|
||||
|
||||
void AST_import_module(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {
|
||||
assert(dst != NULL);
|
||||
assert(src != NULL);
|
||||
|
||||
size_t elements = src->children->len;
|
||||
for (size_t i = 0; i < elements; i++) {
|
||||
AST_NODE_PTR node = AST_remove_child(src, 0);
|
||||
|
||||
if (node->kind == AST_FunDef) {
|
||||
AST_NODE_PTR decl = AST_new_node(node->location, AST_FunDecl, NULL);
|
||||
|
||||
for (int u = 0; u < node->children->len - 1; u++) {
|
||||
AST_push_node(decl, AST_get_node(node, u));
|
||||
}
|
||||
|
||||
node = decl;
|
||||
}
|
||||
|
||||
AST_insert_node(dst, k + i, node);
|
||||
}
|
||||
AST_delete_node(src);
|
||||
}
|
||||
|
||||
void AST_insert_node(AST_NODE_PTR owner, size_t idx, AST_NODE_PTR child) {
|
||||
assert(owner != NULL);
|
||||
assert(child != NULL);
|
||||
|
|
|
@ -230,6 +230,9 @@ AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner,
|
|||
[[gnu::nonnull(1), gnu::nonnull(3)]]
|
||||
void AST_merge_modules(AST_NODE_PTR dst, size_t i, AST_NODE_PTR src);
|
||||
|
||||
[[gnu::nonnull(1), gnu::nonnull(3)]]
|
||||
void AST_import_module(AST_NODE_PTR dst, size_t i, AST_NODE_PTR src);
|
||||
|
||||
[[gnu::nonnull(1), gnu::nonnull(3)]]
|
||||
void AST_insert_node(AST_NODE_PTR owner, size_t idx, AST_NODE_PTR child);
|
||||
|
||||
|
|
|
@ -401,13 +401,24 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
|
|||
return PROJECT_SEMANTIC_ERR;
|
||||
}
|
||||
|
||||
static int parse_dependency(Dependency* dependency, toml_table_t* table, char* name) {
|
||||
dependency->name = mem_strdup(MemoryNamespaceOpt, name);
|
||||
|
||||
get_str(&dependency->path, table, "path");
|
||||
get_str(&dependency->target, table, "target");
|
||||
|
||||
dependency->libraries = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
|
||||
|
||||
return PROJECT_OK;
|
||||
}
|
||||
|
||||
static int parse_target(const ProjectConfig* config,
|
||||
const toml_table_t* target_table, const char* name) {
|
||||
const toml_table_t* target_table) {
|
||||
DEBUG("parsing target table...");
|
||||
|
||||
TargetConfig* target_config = default_target_config();
|
||||
|
||||
target_config->name = (char*) name;
|
||||
get_str(&target_config->name, target_table, "name");
|
||||
|
||||
get_bool(&target_config->print_ast, target_table, "print_ast");
|
||||
get_bool(&target_config->print_asm, target_table, "print_asm");
|
||||
|
@ -442,13 +453,33 @@ static int parse_target(const ProjectConfig* config,
|
|||
|
||||
g_hash_table_insert(config->targets, target_config->name, target_config);
|
||||
|
||||
toml_table_t* dependencies = toml_table_in(target_table, "dependencies");
|
||||
if (dependencies) {
|
||||
target_config->dependencies = mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal);
|
||||
for (int i = 0; i < toml_table_ntab(dependencies); i++) {
|
||||
char* key = (char*) toml_key_in(dependencies, i);
|
||||
|
||||
if (key == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
toml_table_t* dependency_table = toml_table_in(dependencies, key);
|
||||
Dependency* dependency = mem_alloc(MemoryNamespaceOpt, sizeof(Dependency));
|
||||
if (parse_dependency(dependency, dependency_table, key) == PROJECT_SEMANTIC_ERR) {
|
||||
return PROJECT_SEMANTIC_ERR;
|
||||
}
|
||||
|
||||
g_hash_table_insert(target_config->dependencies, mem_strdup(MemoryNamespaceOpt, key), dependency);
|
||||
}
|
||||
}
|
||||
|
||||
return PROJECT_OK;
|
||||
}
|
||||
|
||||
static int parse_targets(ProjectConfig* config, const toml_table_t* root) {
|
||||
DEBUG("parsing targets of project \"%s\"", config->name);
|
||||
|
||||
toml_table_t* targets = toml_table_in(root, "target");
|
||||
toml_array_t* targets = toml_array_in(root, "targets");
|
||||
if (targets == NULL) {
|
||||
print_message(Warning, "Project has no targets");
|
||||
return PROJECT_SEMANTIC_ERR;
|
||||
|
@ -457,16 +488,9 @@ static int parse_targets(ProjectConfig* config, const toml_table_t* root) {
|
|||
config->targets =
|
||||
mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal);
|
||||
|
||||
for (int i = 0; i < toml_table_ntab(targets); i++) {
|
||||
const char* key = toml_key_in(targets, i);
|
||||
|
||||
if (key == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
toml_table_t* target = toml_table_in(targets, key);
|
||||
parse_target(config, target,
|
||||
mem_strdup(MemoryNamespaceOpt, (char*) key));
|
||||
for (int i = 0; i < toml_array_nelem(targets); i++) {
|
||||
toml_table_t* target = toml_table_at(targets, i);
|
||||
parse_target(config, target);
|
||||
}
|
||||
|
||||
return PROJECT_OK;
|
||||
|
|
|
@ -34,6 +34,13 @@ typedef enum TargetCompilationMode_t {
|
|||
Library
|
||||
} TargetCompilationMode;
|
||||
|
||||
typedef struct Dependency_t {
|
||||
char* name;
|
||||
char* path;
|
||||
char* target;
|
||||
GArray* libraries;
|
||||
} Dependency;
|
||||
|
||||
/**
|
||||
* @brief A target defines a source file which is to be compiled into a specific
|
||||
* format. Additionally properties such as output folders can be set.
|
||||
|
@ -66,6 +73,7 @@ typedef struct TargetConfig_t {
|
|||
// treat parser warnings as errors
|
||||
bool gsc_fatal_warnings;
|
||||
GArray* import_paths;
|
||||
GHashTable* dependencies;
|
||||
} TargetConfig;
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <cfg/opt.h>
|
||||
#include <codegen/backend.h>
|
||||
#include <compiler.h>
|
||||
#include <glib.h>
|
||||
#include <io/files.h>
|
||||
#include <lex/util.h>
|
||||
#include <llvm/backend.h>
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include <set/set.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/log.h>
|
||||
#include <unistd.h>
|
||||
#include <yacc/parser.tab.h>
|
||||
|
||||
#define GRAPHVIZ_FILE_EXTENSION "gv"
|
||||
|
@ -21,11 +23,18 @@
|
|||
extern void yyrestart(FILE*);
|
||||
|
||||
// Module AST node used by the parser for AST construction.
|
||||
[[maybe_unused]] AST_NODE_PTR root;
|
||||
[[maybe_unused]]
|
||||
AST_NODE_PTR root;
|
||||
// Current file which gets compiled the parser.
|
||||
// NOTE: due to global state no concurrent compilation is possible
|
||||
// on parser level.
|
||||
[[maybe_unused]] ModuleFile* current_file;
|
||||
[[maybe_unused]]
|
||||
ModuleFile* current_file;
|
||||
|
||||
static int build_project_targets(ModuleFileStack* unit,
|
||||
const ProjectConfig* config);
|
||||
|
||||
static int build_target(ModuleFileStack* unit, const TargetConfig* target);
|
||||
|
||||
/**
|
||||
* @brief Compile the specified file into AST
|
||||
|
@ -230,12 +239,84 @@ static int compile_module_with_dependencies(ModuleFileStack* unit,
|
|||
for (size_t i = 0; i < AST_get_child_count(root_module); i++) {
|
||||
AST_NODE_PTR child = AST_get_node(root_module, i);
|
||||
|
||||
if (child->kind == AST_Import || child->kind == AST_Include) {
|
||||
if (child->kind == AST_Import) {
|
||||
if (g_hash_table_contains(target->dependencies, child->value)) {
|
||||
Dependency* dependency =
|
||||
g_hash_table_lookup(target->dependencies, child->value);
|
||||
|
||||
gchar* cwd = g_get_current_dir();
|
||||
chdir(dependency->path);
|
||||
|
||||
ProjectConfig* new_config = default_project_config();
|
||||
if (load_project_config(new_config)) {
|
||||
print_message(Error, "Failed to load project config: `%s`",
|
||||
child->value);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
TargetConfig* dep_target = g_hash_table_lookup(new_config->targets, dependency->target);
|
||||
if (build_target(unit, dep_target)) {
|
||||
print_message(Error, "Failed to build project config: `%s`",
|
||||
child->value);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
GPathBuf* buf = g_path_buf_new_from_path(dependency->path);
|
||||
TargetConfig* dep_conf = g_hash_table_lookup(new_config->targets, dependency->target);
|
||||
char* root_mod = dep_conf->root_module;
|
||||
g_path_buf_push(buf, root_mod);
|
||||
char* rel_path = g_path_buf_to_path(buf);
|
||||
|
||||
GPathBuf* dep_bin = g_path_buf_new();
|
||||
g_path_buf_push(dep_bin, dependency->path);
|
||||
g_path_buf_push(dep_bin, dep_conf->archive_directory);
|
||||
g_path_buf_push(dep_bin, g_strjoin(".", dep_conf->name, "o", NULL));
|
||||
char* dep_bin_path = g_path_buf_to_path(dep_bin);
|
||||
|
||||
g_array_append_val(dependency->libraries, dep_bin_path);
|
||||
|
||||
const char* path =
|
||||
get_absolute_import_path(target, rel_path);
|
||||
|
||||
if (g_hash_table_contains(imports, path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ModuleFile* imported_file = push_file(unit, path);
|
||||
AST_NODE_PTR imported_module =
|
||||
AST_new_node(empty_location(imported_file), AST_Module, NULL);
|
||||
|
||||
if (compile_file_to_ast(imported_module, imported_file)
|
||||
== EXIT_SUCCESS) {
|
||||
AST_import_module(root_module, i + 1, imported_module);
|
||||
} else {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
g_hash_table_insert(imports, (gpointer) path, NULL);
|
||||
|
||||
g_path_buf_pop(buf);
|
||||
gchar* directory = g_path_buf_to_path(buf);
|
||||
gchar* cached_directory =
|
||||
mem_strdup(MemoryNamespaceLld, directory);
|
||||
g_free(directory);
|
||||
g_array_append_val(target->import_paths, cached_directory);
|
||||
|
||||
chdir(cwd);
|
||||
|
||||
} else {
|
||||
print_message(Error, "Cannot resolve path for import: `%s`",
|
||||
child->value);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
} else if (child->kind == AST_Include) {
|
||||
|
||||
const char* path =
|
||||
get_absolute_import_path(target, child->value);
|
||||
if (path == NULL) {
|
||||
print_message(Error, "Cannot resolve path for import: `%s`",
|
||||
print_message(Error,
|
||||
"Cannot resolve path for include: `%s`",
|
||||
child->value);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -305,10 +386,6 @@ static int build_target(ModuleFileStack* unit, const TargetConfig* target) {
|
|||
}
|
||||
}
|
||||
|
||||
mem_purge_namespace(MemoryNamespaceLex);
|
||||
mem_purge_namespace(MemoryNamespaceAst);
|
||||
mem_purge_namespace(MemoryNamespaceSet);
|
||||
|
||||
print_file_statistics(file);
|
||||
|
||||
return err;
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
extern int lld_main(int Argc, const char **Argv, const char **outstr);
|
||||
|
||||
const char* FLAGS[] = {
|
||||
""
|
||||
};
|
||||
|
||||
bool lldc_link(TargetLinkConfig* config) {
|
||||
|
||||
GArray* arguments = mem_new_g_array(MemoryNamespaceLld, sizeof(char*));
|
||||
|
@ -21,6 +25,13 @@ bool lldc_link(TargetLinkConfig* config) {
|
|||
char* obj = g_array_index(config->object_file_names, char*, i);
|
||||
g_array_append_val(arguments, obj);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(FLAGS)/sizeof(char*); i++) {
|
||||
char* flag = (char*) FLAGS[i];
|
||||
|
||||
g_array_append_val(arguments, flag);
|
||||
}
|
||||
|
||||
char* output_flag = "-o";
|
||||
g_array_append_val(arguments, output_flag);
|
||||
g_array_append_val(arguments, config->output_file);
|
||||
|
@ -33,10 +44,9 @@ bool lldc_link(TargetLinkConfig* config) {
|
|||
const char* message = NULL;
|
||||
const bool code = lld_main(arguments->len, (const char**) arguments->data, &message);
|
||||
|
||||
free((void*) message);
|
||||
|
||||
if (!code) {
|
||||
print_message(Error, message);
|
||||
free((void*) message);
|
||||
}
|
||||
|
||||
return code;
|
||||
|
|
|
@ -89,26 +89,18 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused))
|
|||
|
||||
// resolve absolute paths to dependent library object files
|
||||
DEBUG("resolving target dependencies...");
|
||||
for (guint i = 0; i < module->imports->len; i++) {
|
||||
const char* dependency = g_array_index(module->imports, const char*, i);
|
||||
GHashTableIter iter;
|
||||
|
||||
const char* library = g_strjoin("", "libgsc", dependency, ".o", NULL);
|
||||
g_hash_table_iter_init(&iter, target_config->dependencies);
|
||||
char* key;
|
||||
Dependency* dep;
|
||||
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &dep)) {
|
||||
|
||||
const char* dependency_object =
|
||||
get_absolute_link_path(target_config, library);
|
||||
if (dependency_object == NULL) {
|
||||
ERROR("failed to resolve path to dependency object: %s", library);
|
||||
print_message(Warning,
|
||||
"failed to resolve path to dependency object: %s",
|
||||
dependency);
|
||||
lld_delete_link_config(config);
|
||||
lld_delete_link_config(config);
|
||||
g_free((void*) library);
|
||||
return NULL;
|
||||
for (guint k = 0; k < dep->libraries->len; k++) {
|
||||
char* lib = g_array_index(dep->libraries, char*, k);
|
||||
|
||||
g_array_append_val(config->object_file_names, lib);
|
||||
}
|
||||
g_free((void*) library);
|
||||
g_array_append_val(config->object_file_names, dependency_object);
|
||||
INFO("resolved path of target object: %s", dependency_object);
|
||||
}
|
||||
|
||||
INFO("resolved %d dependencies", config->object_file_names->len);
|
||||
|
|
|
@ -2442,7 +2442,7 @@ int addFunction(const char* name, Function* function) {
|
|||
function->name);
|
||||
return SEMANTIC_ERROR;
|
||||
}
|
||||
g_hash_table_insert(declaredFunctions, (gpointer) name, function);
|
||||
g_hash_table_insert(definedFunctions, (gpointer) name, function);
|
||||
} else if (function->kind == FunctionDeclarationKind) {
|
||||
if (g_hash_table_contains(declaredFunctions, name)) {
|
||||
Function* declaredFunction =
|
||||
|
@ -2893,16 +2893,7 @@ Module* create_set(AST_NODE_PTR currentNode) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (g_hash_table_contains(functions, function->name)) {
|
||||
print_diagnostic(
|
||||
&function->impl.definition.nodePtr->location, Error,
|
||||
"Multiple definition of function: `%s`",
|
||||
function->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_hash_table_insert(functions, (gpointer) function->name,
|
||||
function);
|
||||
g_hash_table_insert(rootModule->functions, function->name, function);
|
||||
|
||||
DEBUG("created function successfully");
|
||||
break;
|
||||
|
|
|
@ -5,12 +5,17 @@ description = "Test applications for the GSC standard library."
|
|||
license = "GPL-2.0"
|
||||
authors = [ "Sven Vogel <sven.vogel123@web.de>" ]
|
||||
|
||||
[target.prime]
|
||||
[[targets]]
|
||||
name = "prime"
|
||||
import-paths = [ "." ]
|
||||
root = "main.gsc"
|
||||
mode = "application"
|
||||
output = "bin"
|
||||
archive = "archive"
|
||||
driver = "ld.lld"
|
||||
print_asm = true
|
||||
print_ir = true
|
||||
print_ast = true
|
||||
|
||||
[dependencies]
|
||||
gscstd = { path = "../../lib" }
|
||||
[targets.dependencies]
|
||||
std = { path = "../../lib/src", target = "gsc-libc" }
|
||||
|
|
Loading…
Reference in New Issue