diff --git a/.env b/.env
index 6eb74fb..b31e782 100644
--- a/.env
+++ b/.env
@@ -1 +1 @@
-SDK=0.2.5-alpine-3.19.1
+SDK=0.2.6-alpine-3.19.1
diff --git a/Dockerfile b/Dockerfile
index a68c334..6674f53 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
-FROM servostar/gemstone:sdk-0.2.5-alpine-3.19.1
+FROM servostar/gemstone:sdk-0.2.6-alpine-3.19.1
LABEL authors="servostar"
-LABEL version="0.2.5"
+LABEL version="0.2.6"
LABEL description="docker image for setting up the build pipeline on SDK"
LABEL website="https://github.com/Servostar/gemstone"
diff --git a/README.md b/README.md
index daaaf32..70d8240 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,74 @@
-
-
+
+
+ Open source programming language compiler based on LLVM, GLib and GNU Bison/Flex
+
+ capable of multi target cross compilation powered by simple build system.
+
+
+
+
+
+
+
+
+
+
+
-
-## Gemstone
+## About
Gemstone is a programming language compiler (short: GSC) written in C based on flex and GNU bison.
It uses LLVM to produce optimized native binaries for many platforms and uses its own builtin build system for more complex project management.
+## Architecture
+
+Gemstone is a LALR enabled non-reentrant compiler utilizing a linear flow of components. The compiler has multiple stages of operation, each representing a crucial step in compilation.
+
+```mermaid
+---
+title: GSC Architecture Overview
+---
+flowchart LR
+ lex["`**Lexical Analysis**
+ tokenization via flex`"]
+ bison["`**Syntax Analysis**
+ parsing via bison`"]
+ set["`**Semantic Analysis**
+ parse tree generation`"]
+ llvm["`**Codegen**
+ code generation via LLVM`"]
+ driver["`**Linking**
+ Linkage via Clang/GCC`"]
+
+ start(("Start")) --> lex
+
+ subgraph compile AST
+ lex --> bison
+ end
+
+ subgraph Validation
+ bison --> import{"Import/Include?"}
+ import --> |yes| ast[[compile AST]] --> merge["Merge AST"] --> import
+ import --> |no| set
+ set --> llvm
+ end
+
+ stop(("End"))
+
+ subgraph Codegen
+ llvm --> lib{"Produce Library?"}
+ lib -->|no| driver --> executable(["Executable"])
+ lib -->|yes| library(["Library"])
+ end
+
+ library --> stop
+ executable --> stop
+```
+
## Dependencies (build)
### Windows 11
@@ -78,33 +136,23 @@ For creating the build pipeline build the Dockerfile in the root folder of this
Then the make targets are generated. Running `make release` will build gemstone from source in release mode.
The generated binaries can be found either in `bin/release/gsc` or `bin/debug/gsc` depending on the chosen target.
The following graph visualizes the build pipeline:
-```
- SDK (environment)
- │
- │ configure build environment
- │ cmake, make, gcc, yacc, lex
- │
- ▼
- Devkit (pipeline)
- │
- │ create build pipeline
- │ create make targets
- ▼
- Pipeline
-
-
-yacc (generate files) GCC (compile) Extra Source Files (src/*.c)
-│ │ │
-├─ parser.tab.h ─────────────►│◄────────────────────┘
-│ │
-└─ parser.tab.c ─────────────►│
- │
-lex (generate file) │
-│ │
-└─ lexer.ll.c ──────────────►│
- │
- ▼
- gsc
+```mermaid
+flowchart LR
+
+ subgraph Docker
+ alpine[Alpine Linux] --> sdk[SDK] --> dev[Devkit]
+ end
+
+ subgraph Build
+ dev --> |generate parser| bison[Bison]
+ dev --> |generate lexer| flex[Flex]
+ bison --> cc[GCC/Clang/MSVC]
+ flex --> cc
+ cc --> debug
+ cc --> release
+ cc --> check
+ end
+
```
## Docker images
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 8be6998..097546c 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -16,10 +16,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/../bin/std")
# add native module libraries
file(GLOB_RECURSE STDLIB_IO_SOURCE_FILES src/io/*.c)
-add_library(io ${STDLIB_IO_SOURCE_FILES})
+add_library(gscio ${STDLIB_IO_SOURCE_FILES})
file(GLOB_RECURSE STDLIB_MEM_SOURCE_FILES src/mem/*.c)
-add_library(mem ${STDLIB_MEM_SOURCE_FILES})
+add_library(gscmem ${STDLIB_MEM_SOURCE_FILES})
file(GLOB_RECURSE STDLIB_OS_SOURCE_FILES src/os/*.c)
-add_library(os ${STDLIB_OS_SOURCE_FILES})
+add_library(gscos ${STDLIB_OS_SOURCE_FILES})
+
+# Complete standard library
+add_library(gscstd
+ ${STDLIB_IO_SOURCE_FILES}
+ ${STDLIB_MEM_SOURCE_FILES}
+ ${STDLIB_OS_SOURCE_FILES})
diff --git a/lib/src/entry/entrypoint.c b/lib/src/entry/entrypoint.c
index c41e482..75cf927 100644
--- a/lib/src/entry/entrypoint.c
+++ b/lib/src/entry/entrypoint.c
@@ -2,9 +2,6 @@
// Created by servostar on 6/10/24.
//
-extern void entry(void);
-
int main(int argc, char* argv[]) {
- entry();
return 0;
}
diff --git a/lib/src/io.gsc b/lib/src/io.gsc
index db8de9b..c729644 100644
--- a/lib/src/io.gsc
+++ b/lib/src/io.gsc
@@ -6,7 +6,7 @@
# | Generic Input/Output |
# `----------------------------------------`
-import "def.gsc"
+include "def.gsc"
# platform specific handle to an I/O device
# can be a file, buffer, window or something else
diff --git a/lib/src/mem.gsc b/lib/src/mem.gsc
index 0307666..b9df686 100644
--- a/lib/src/mem.gsc
+++ b/lib/src/mem.gsc
@@ -6,7 +6,7 @@
# | Memory Management |
# `----------------------------------------`
-import "def.gsc"
+include "def.gsc"
# Allocate `len` bytes of heap memory
# Returns a pointer to the memory as `ptr`
diff --git a/lib/src/os.gsc b/lib/src/os.gsc
index bfd6958..5f7a190 100644
--- a/lib/src/os.gsc
+++ b/lib/src/os.gsc
@@ -6,7 +6,7 @@
# | Operating System |
# `----------------------------------------`
-import "def.gsc"
+include "def.gsc"
# Return a hard coded C string identifying the underlying operating system
# Will return one of the following:
diff --git a/lib/src/std.gsc b/lib/src/std.gsc
index cf690e3..36d6a75 100644
--- a/lib/src/std.gsc
+++ b/lib/src/std.gsc
@@ -7,10 +7,10 @@
# `----------------------------------------`
# standard type definitions
-import "def.gsc"
+include "def.gsc"
# I/O operations
-import "io.gsc"
+include "io.gsc"
# memory management
-import "mem.gsc"
+include "mem.gsc"
diff --git a/sdk/Dockerfile b/sdk/Dockerfile
index 1cba1d3..5bfaf89 100644
--- a/sdk/Dockerfile
+++ b/sdk/Dockerfile
@@ -1,11 +1,11 @@
FROM alpine:3.19.1
LABEL authors="servostar"
-LABEL version="0.2.5"
+LABEL version="0.2.6"
LABEL description="base image for building the gemstone programming language compiler"
LABEL website="https://github.com/Servostar/gemstone"
# install dependencies
-RUN apk add build-base gcc make cmake bison flex git python3 graphviz glib glib-dev llvm17-libs llvm17-dev
+RUN apk add build-base gcc clang make cmake bison flex git python3 graphviz glib glib-dev llvm17-libs llvm17-dev
# create user for build
RUN adduser --disabled-password lorang
diff --git a/src/ast/ast.c b/src/ast/ast.c
index 7da6bf5..9f00f56 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -101,6 +101,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
case AST_Ident:
case AST_Macro:
case AST_Import:
+ case AST_Include:
case AST_Storage:
case AST_Typekind:
case AST_Sign:
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 5c71d2c..a7be0be 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -79,6 +79,7 @@ enum AST_SyntaxElement_t {
AST_AddressOf,
AST_Dereference,
AST_Reference,
+ AST_Include,
AST_ELEMENT_COUNT
};
diff --git a/src/cfg/opt.c b/src/cfg/opt.c
index 57ed113..8a946b6 100644
--- a/src/cfg/opt.c
+++ b/src/cfg/opt.c
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
static GHashTable* args = NULL;
@@ -68,7 +69,7 @@ GArray* get_non_options_after(const char* command) {
return NULL;
}
- GArray* array = g_array_new(FALSE, FALSE, sizeof(const char*));
+ GArray* array = mem_new_g_array(MemoryNamespaceOpt, sizeof(const char*));
GHashTableIter iter;
gpointer key, value;
@@ -82,7 +83,6 @@ GArray* get_non_options_after(const char* command) {
}
if (array->len == 0) {
- g_array_free(array, FALSE);
return NULL;
}
@@ -98,12 +98,13 @@ TargetConfig* default_target_config() {
config->print_ast = false;
config->print_asm = false;
config->print_ir = false;
+ config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER);
config->mode = Application;
config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->optimization_level = 1;
config->root_module = NULL;
- config->link_search_paths = g_array_new(FALSE, FALSE, sizeof(char*));
+ config->link_search_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
config->lld_fatal_warnings = FALSE;
config->gsc_fatal_warnings = FALSE;
config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
@@ -160,9 +161,18 @@ TargetConfig* default_target_config_from_args() {
}
}
- // TODO: free vvvvvvvvvvvvv
+ if (is_option_set("driver")) {
+ const Option* opt = get_option("driver");
+
+ if (opt->value != NULL) {
+ config->driver = mem_strdup(MemoryNamespaceOpt, (char*) opt->value);
+ }
+ }
+
char* cwd = g_get_current_dir();
- g_array_append_val(config->link_search_paths, cwd);
+ char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
+ g_array_append_val(config->link_search_paths, cached_cwd);
+ free(cwd);
if (is_option_set("link-paths")) {
const Option* opt = get_option("link-paths");
@@ -174,7 +184,7 @@ TargetConfig* default_target_config_from_args() {
while((end = strchr(start, ',')) != NULL) {
const int len = end - start;
- char* link_path = malloc(len + 1);
+ char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len);
link_path[len] = 0;
@@ -185,7 +195,7 @@ TargetConfig* default_target_config_from_args() {
const int len = strlen(start);
if (len > 0) {
- char* link_path = malloc(len + 1);
+ char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len);
link_path[len] = 0;
@@ -204,14 +214,42 @@ TargetConfig* default_target_config_from_args() {
print_message(Warning, "Got more than one file to compile, using first, ignoring others.");
}
- config->root_module = mem_strdup(MemoryNamespaceOpt, ((char**) files->data) [0]);
-
- g_array_free(files, TRUE);
+ config->root_module = mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0));
}
char* default_import_path = mem_strdup(MemoryNamespaceOpt, ".");
g_array_append_val(config->import_paths, default_import_path);
+ if (is_option_set("import-paths")) {
+ const Option* opt = get_option("import-paths");
+
+ if (opt->value != NULL) {
+
+ const char* start = opt->value;
+ const char* end = NULL;
+ while((end = strchr(start, ',')) != NULL) {
+
+ const int len = end - start;
+ char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1);
+ memcpy(import_path, start, len);
+ import_path[len] = 0;
+
+ g_array_append_val(config->import_paths, import_path);
+
+ start = end;
+ }
+
+ const int len = strlen(start);
+ if (len > 0) {
+ char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1);
+ memcpy(import_path, start, len);
+ import_path[len] = 0;
+
+ g_array_append_val(config->import_paths, import_path);
+ }
+ }
+ }
+
return config;
}
@@ -229,6 +267,7 @@ void print_help(void) {
" --print-ir print resulting LLVM-IR to a file",
" --mode=[app|lib] set the compilation mode to either application or library",
" --output=name name of output files without extension",
+ " --driver set binary driver to use",
" --link-paths=[paths,] set a list of directories to for libraries in",
" --all-fatal-warnings treat all warnings as errors",
" --lld-fatal-warnings treat linker warnings as errors",
@@ -238,6 +277,7 @@ void print_help(void) {
" --debug print debug logs (if not disabled at compile time)",
" --version print the version",
" --list-targets print a list of all available targets supported",
+ " --list-driver print a list of all available binary driver",
" --help print this help dialog",
" --color-always always colorize output",
" --print-gc-stats print statistics of the garbage collector"
@@ -281,6 +321,21 @@ static void get_int(int* integer, const toml_table_t *table, const char* name) {
}
}
+static void get_array(GArray* array, const toml_table_t *table, const char* name) {
+ const toml_array_t* toml_array = toml_array_in(table, name);
+
+ if (toml_array) {
+ for (int i = 0; i < toml_array_nelem(toml_array); i++) {
+ toml_datum_t value = toml_string_at(toml_array, i);
+
+ if (value.ok) {
+ char* copy = mem_strdup(MemoryNamespaceOpt, value.u.s);
+ g_array_append_val(array, copy);
+ }
+ }
+ }
+}
+
static int parse_project_table(ProjectConfig *config, const toml_table_t *project_table) {
DEBUG("parsing project table...");
@@ -297,7 +352,7 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec
// author names
toml_array_t *authors = toml_array_in(project_table, "authors");
if (authors) {
- config->authors = g_array_new(FALSE, FALSE, sizeof(char *));
+ config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char *));
for (int i = 0;; i++) {
toml_datum_t author = toml_string_at(authors, i);
@@ -328,7 +383,7 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
*mode = Library;
return PROJECT_OK;
}
- printf("Invalid project configuration, mode is invalid: %s\n\n", name);
+ print_message(Error, "Invalid project configuration, mode is invalid: %s", name);
return PROJECT_SEMANTIC_ERR;
}
@@ -343,6 +398,7 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
get_bool(&target_config->print_asm, target_table, "print_asm");
get_bool(&target_config->print_ir, target_table, "print_ir");
+ get_str(&target_config->driver, target_table, "driver");
get_str(&target_config->root_module, target_table, "root");
get_str(&target_config->output_directory, target_table, "output");
get_str(&target_config->archive_directory, target_table, "archive");
@@ -357,6 +413,15 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
if (err != PROJECT_OK) {
return err;
}
+ char* cwd = g_get_current_dir();
+ char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
+ free(cwd);
+
+ g_array_append_val(target_config->link_search_paths, cached_cwd);
+ get_array(target_config->link_search_paths, target_table, "link-paths");
+
+ g_array_append_val(target_config->import_paths, cached_cwd);
+ get_array(target_config->import_paths, target_table, "import-paths");
g_hash_table_insert(config->targets, target_config->name, target_config);
@@ -372,16 +437,16 @@ static int parse_targets(ProjectConfig *config, const toml_table_t *root) {
return PROJECT_SEMANTIC_ERR;
}
- config->targets = g_hash_table_new(g_str_hash, g_str_equal);
+ config->targets = mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal);
- for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) {
+ 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, key);
+ parse_target(config, target, mem_strdup(MemoryNamespaceOpt, (char*) key));
}
return PROJECT_OK;
@@ -393,8 +458,7 @@ int load_project_config(ProjectConfig *config) {
FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r");
if (config_file == NULL) {
print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno));
- INFO("project file not found");
- return PROJECT_TOML_ERR;
+ return PROJECT_SEMANTIC_ERR;
}
char err_buf[TOML_ERROR_MSG_BUF];
@@ -402,21 +466,24 @@ int load_project_config(ProjectConfig *config) {
toml_table_t *conf = toml_parse_file(config_file, err_buf, sizeof(err_buf));
fclose(config_file);
- if (conf == NULL) {
+ if (conf != NULL) {
+ int status = PROJECT_SEMANTIC_ERR;
+ toml_table_t *project = toml_table_in(conf, "project");
+
+ if (project != NULL) {
+ if (parse_project_table(config, project) == PROJECT_OK) {
+ status = parse_targets(config, conf);
+ }
+ } else {
+ print_message(Error, "Invalid project configuration: missing project table.");
+ }
+
+ toml_free(conf);
+ return status;
+ } else {
print_message(Error, "Invalid project configuration: %s", err_buf);
- return PROJECT_SEMANTIC_ERR;
}
- toml_table_t *project = toml_table_in(conf, "project");
- if (project == NULL) {
- print_message(Error, "Invalid project configuration: missing project table.");
- }
-
- if (parse_project_table(config, project) == PROJECT_OK) {
- return parse_targets(config, conf);
- }
-
- toml_free(conf);
return PROJECT_SEMANTIC_ERR;
}
@@ -435,9 +502,8 @@ void delete_target_config(TargetConfig* config) {
}
if (config->link_search_paths) {
for (guint i = 0; i < config->link_search_paths->len; i++) {
- free(g_array_index(config->link_search_paths, char*, i));
+ mem_free(g_array_index(config->link_search_paths, char*, i));
}
- g_array_free(config->link_search_paths, TRUE);
}
mem_free(config);
}
@@ -447,7 +513,7 @@ void delete_project_config(ProjectConfig* config) {
mem_free(config->name);
}
if (config->authors != NULL) {
- g_array_free(config->authors, TRUE);
+ mem_free(config->authors);
}
if (config->desc != NULL) {
mem_free(config->desc);
@@ -466,7 +532,7 @@ void delete_project_config(ProjectConfig* config) {
delete_target_config(val);
}
- g_hash_table_destroy(config->targets);
+ mem_free(config->targets);
}
mem_free_from(MemoryNamespaceOpt, config);
@@ -484,3 +550,16 @@ ProjectConfig* default_project_config() {
return config;
}
+
+static void* toml_cached_malloc(size_t bytes) {
+ return mem_alloc(MemoryNamespaceTOML, bytes);
+}
+
+static void toml_cached_free(void* ptr) {
+ mem_free(ptr);
+}
+
+void init_toml() {
+ INFO("setting up cached memory for TOML C99...");
+ toml_set_memutil(toml_cached_malloc, toml_cached_free);
+}
diff --git a/src/cfg/opt.h b/src/cfg/opt.h
index 9b61def..06e6f1d 100644
--- a/src/cfg/opt.h
+++ b/src/cfg/opt.h
@@ -24,6 +24,7 @@ typedef struct TargetLinkConfig_t {
// colorize linker output
bool colorize;
char* output_file;
+ char* driver;
} TargetLinkConfig;
typedef enum TargetCompilationMode_t {
@@ -50,6 +51,8 @@ typedef struct TargetConfig_t {
char* output_directory;
// output directory for intermediate representations (LLVM-IR, Assembly, ...)
char* archive_directory;
+ // binary driver for executable generation
+ char* driver;
// mode of compilation
TargetCompilationMode mode;
// number between 1 and 3
@@ -183,4 +186,6 @@ const Option* get_option(const char* option);
[[nodiscard("must be freed")]]
GArray* get_non_options_after(const char* command);
+void init_toml();
+
#endif //GEMSTONE_OPT_H
diff --git a/src/compiler.c b/src/compiler.c
index 289daf7..a515009 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -165,11 +165,20 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target
print_message(Info, "Compilation finished successfully");
err = deinit_backend();
+ if (err.kind != Success) {
+ ERROR("Unable to deinit backend: %s", err.impl.message);
+ }
}
const char* get_absolute_import_path(const TargetConfig* config, const char* import_target_name) {
INFO("resolving absolute path for import target: %s", import_target_name);
+ if (!g_str_has_suffix(import_target_name, ".gsc")) {
+ char* full_filename = g_strjoin("", import_target_name, ".gsc", NULL);
+ import_target_name = mem_strdup(MemoryNamespaceLld, full_filename);
+ g_free(full_filename);
+ }
+
for (guint i = 0; i < config->import_paths->len; i++) {
const char* import_directory_path = g_array_index(config->import_paths, char*, i);
@@ -180,15 +189,16 @@ const char* get_absolute_import_path(const TargetConfig* config, const char* imp
const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR);
+ char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical);
+
g_free(path);
g_free(cwd);
+ g_free(canonical);
if (exists && !is_dir) {
- INFO("import target found at: %s", canonical);
- return canonical;
+ INFO("import target found at: %s", cached_canonical);
+ return cached_canonical;
}
-
- g_free(canonical);
}
// file not found
@@ -204,7 +214,7 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
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) {
+ if (child->kind == AST_Import || child->kind == AST_Include) {
const char* path = get_absolute_import_path(target, child->value);
if (path == NULL) {
@@ -228,7 +238,9 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
g_hash_table_insert(imports, (gpointer) path, NULL);
gchar* directory = g_path_get_dirname(path);
- g_array_append_val(target->import_paths, directory);
+ gchar* cached_directory = mem_strdup(MemoryNamespaceLld, directory);
+ g_free(directory);
+ g_array_append_val(target->import_paths, cached_directory);
}
}
} else {
@@ -318,7 +330,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co
if (targets != NULL) {
for (guint i = 0; i < targets->len; i++) {
- const char *target_name = (((Option*) targets->data) + i)->string;
+ const char *target_name = g_array_index(targets, const char*, i);
if (g_hash_table_contains(config->targets, target_name)) {
build_target(unit, g_hash_table_lookup(config->targets, target_name));
@@ -327,7 +339,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co
}
}
- g_array_free(targets, FALSE);
+ mem_free(targets);
} else {
print_message(Error, "No targets specified.");
}
diff --git a/src/io/files.c b/src/io/files.c
index dc4d044..ddd018c 100644
--- a/src/io/files.c
+++ b/src/io/files.c
@@ -42,7 +42,7 @@ ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
// lazy init of heap stack
if (stack->files == NULL) {
- stack->files = g_array_new(FALSE, FALSE, sizeof(ModuleFile*));
+ stack->files = mem_new_g_array(MemoryNamespaceStatic, sizeof(ModuleFile*));
}
ModuleFile* new_file = mem_alloc(MemoryNamespaceStatic, sizeof(ModuleFile));
@@ -66,9 +66,10 @@ void delete_files(ModuleFileStack *stack) {
fclose(file->handle);
}
+ mem_free((void*) file);
}
- g_array_free(stack->files, TRUE);
+ mem_free(stack->files);
DEBUG("deleted module file stack");
}
@@ -330,8 +331,11 @@ const char *get_absolute_path(const char *path) {
DEBUG("resolving absolute path of: %s", path);
char* cwd = g_get_current_dir();
- char* canoical = g_canonicalize_filename(path, cwd);
+ char* canonical = g_canonicalize_filename(path, cwd);
g_free(cwd);
- return canoical;
+ char* cached_canonical = mem_strdup(MemoryNamespaceStatic, canonical);
+ g_free(canonical);
+
+ return cached_canonical;
}
diff --git a/src/lex/lexer.l b/src/lex/lexer.l
index bfde8ff..e955b0e 100644
--- a/src/lex/lexer.l
+++ b/src/lex/lexer.l
@@ -81,6 +81,7 @@
"!" {DEBUG("\"%s\" tokenized with \'OpBitnot\'", yytext); return(OpBitnot);};
"^" {DEBUG("\"%s\" tokenized with \'OpBitxor\'", yytext); return(OpBitxor);};
"import" {DEBUG("\"%s\" tokenized with \'KeyImport\'", yytext); return(KeyImport);};
+"include" {DEBUG("\"%s\" tokenized with \'KeyInclude\'", yytext); return(KeyInclude);};
"silent" {DEBUG("\"%s\" tokenized with \'KeySilent\'", yytext); return(KeySilent);};
"box" {DEBUG("\"%s\" tokenized with \'KeyBox\'", yytext); return(KeyBox);};
"typeof" {DEBUG("\"%s\" tokenized with \'FunTypeof\'", yytext); return(FunTypeof);};
diff --git a/src/link/clang/driver.c b/src/link/clang/driver.c
new file mode 100644
index 0000000..6d4e0cf
--- /dev/null
+++ b/src/link/clang/driver.c
@@ -0,0 +1,42 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#include
+#include
+#include
+
+bool clang_link(TargetLinkConfig* config) {
+
+ GString* commandString = g_string_new("");
+
+ g_string_append(commandString, "clang");
+
+ for (guint i = 0; i < config->object_file_names->len; i++) {
+ g_string_append(commandString, " ");
+ g_string_append(commandString, g_array_index(config->object_file_names, char*, i));
+ }
+
+ g_string_append(commandString, " -o ");
+ g_string_append(commandString, config->output_file);
+
+ print_message(Info, "invoking binary link with: %s", commandString->str);
+
+ if (system(commandString->str)) {
+ return false;
+ }
+
+ g_string_free(commandString, true);
+
+ return true;
+}
+
+BinaryDriver* clang_get_driver() {
+
+ BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver));
+
+ driver->name = "clang";
+ driver->link_func = &clang_link;
+
+ return driver;
+}
diff --git a/src/link/clang/driver.h b/src/link/clang/driver.h
new file mode 100644
index 0000000..e8f15da
--- /dev/null
+++ b/src/link/clang/driver.h
@@ -0,0 +1,14 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#ifndef GEMSTONE_CLANG_DRIVER_H
+#define GEMSTONE_CLANG_DRIVER_H
+
+#include
+
+bool clang_link(TargetLinkConfig* config);
+
+BinaryDriver* clang_get_driver();
+
+#endif // GEMSTONE_CLANG_DRIVER_H
diff --git a/src/link/driver.h b/src/link/driver.h
new file mode 100644
index 0000000..9eba996
--- /dev/null
+++ b/src/link/driver.h
@@ -0,0 +1,20 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#ifndef GEMSTONE_DRIVER_H
+#define GEMSTONE_DRIVER_H
+
+#include
+
+#define DEFAULT_DRIVER "clang"
+
+//! @brief Function a binary driver used to link files
+typedef bool (*driver_link)(TargetLinkConfig*);
+
+typedef struct BinaryDriver_t {
+ const char* name;
+ driver_link link_func;
+} BinaryDriver;
+
+#endif //GEMSTONE_DRIVER_H
diff --git a/src/link/gcc/driver.c b/src/link/gcc/driver.c
new file mode 100644
index 0000000..854bf0c
--- /dev/null
+++ b/src/link/gcc/driver.c
@@ -0,0 +1,42 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#include
+#include
+#include
+
+bool gcc_link(TargetLinkConfig* config) {
+
+ GString* commandString = g_string_new("");
+
+ g_string_append(commandString, "gcc");
+
+ for (guint i = 0; i < config->object_file_names->len; i++) {
+ g_string_append(commandString, " ");
+ g_string_append(commandString, g_array_index(config->object_file_names, char*, i));
+ }
+
+ g_string_append(commandString, " -o ");
+ g_string_append(commandString, config->output_file);
+
+ print_message(Info, "invoking binary link with: %s", commandString->str);
+
+ if (system(commandString->str)) {
+ return false;
+ }
+
+ g_string_free(commandString, true);
+
+ return true;
+}
+
+BinaryDriver* gcc_get_driver() {
+
+ BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver));
+
+ driver->name = "gcc";
+ driver->link_func = &gcc_link;
+
+ return driver;
+}
diff --git a/src/link/gcc/driver.h b/src/link/gcc/driver.h
new file mode 100644
index 0000000..8227353
--- /dev/null
+++ b/src/link/gcc/driver.h
@@ -0,0 +1,14 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#ifndef GEMSTONE_GCC_DRIVER_H
+#define GEMSTONE_GCC_DRIVER_H
+
+#include
+
+bool gcc_link(TargetLinkConfig* config);
+
+BinaryDriver* gcc_get_driver();
+
+#endif // GEMSTONE_GCC_DRIVER_H
diff --git a/src/link/lib.c b/src/link/lib.c
new file mode 100644
index 0000000..6e4aaf1
--- /dev/null
+++ b/src/link/lib.c
@@ -0,0 +1,72 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+static driver_init AVAILABLE_DRIVER[] = {
+ clang_get_driver,
+ gcc_get_driver
+};
+
+static GHashTable* binary_driver = NULL;
+
+void link_init() {
+ INFO("initializing binary driver...");
+
+ if (binary_driver == NULL) {
+ binary_driver = mem_new_g_hash_table(MemoryNamespaceLld, g_str_hash, g_str_equal);
+
+ for (unsigned long int i = 0; i < sizeof(AVAILABLE_DRIVER)/sizeof(driver_init); i++) {
+ BinaryDriver* driver = AVAILABLE_DRIVER[i]();
+
+ if (driver == NULL) {
+ ERROR("failed to init driver by index: %d", i);
+ continue;
+ }
+
+ g_hash_table_insert(binary_driver, (gpointer) driver->name, driver);
+ INFO("initialized `%s` driver", driver->name);
+ }
+ } else {
+ PANIC("binary driver already initialized");
+ }
+}
+
+bool link_run(TargetLinkConfig* config) {
+
+ if (g_hash_table_contains(binary_driver, config->driver)) {
+ print_message(Info, "Invoking binary driver: %s", config->driver);
+
+ BinaryDriver* driver = g_hash_table_lookup(binary_driver, config->driver);
+
+ if (!driver->link_func(config)) {
+ print_message(Error, "Driver %s failed", config->driver);
+ return false;
+ }
+ return true;
+
+ } else {
+ print_message(Error, "Binary driver not available: `%s`", config->driver);
+ return false;
+ }
+}
+
+void link_print_available_driver() {
+ printf("Available binary driver:\n");
+
+ GHashTableIter iter;
+ gpointer key, value;
+ g_hash_table_iter_init(&iter, binary_driver);
+
+ while (g_hash_table_iter_next(&iter, &key, &value)) {
+
+ printf(" - %s\n", (char*) key);
+ }
+}
diff --git a/src/link/lib.h b/src/link/lib.h
new file mode 100644
index 0000000..74ac352
--- /dev/null
+++ b/src/link/lib.h
@@ -0,0 +1,18 @@
+//
+// Created by servostar on 18.07.24.
+//
+
+#ifndef GEMSTONE_LIB_H
+#define GEMSTONE_LIB_H
+
+#include
+
+typedef BinaryDriver* (*driver_init)();
+
+void link_init();
+
+bool link_run(TargetLinkConfig*);
+
+void link_print_available_driver();
+
+#endif //GEMSTONE_LIB_H
diff --git a/src/llvm/backend.c b/src/llvm/backend.c
index 870987d..07f4954 100644
--- a/src/llvm/backend.c
+++ b/src/llvm/backend.c
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
Target create_native_target() {
DEBUG("creating native target...");
@@ -54,7 +55,11 @@ static char* create_target_output_name(const TargetConfig* config) {
prefix = "lib";
}
- return g_strjoin("", prefix, config->name, NULL);
+ char* name = g_strjoin("", prefix, config->name, NULL);
+ char* cached_name = mem_strdup(MemoryNamespaceLlvm, name);
+ g_free(name);
+
+ return cached_name;
}
Target create_target_from_config(const TargetConfig* config) {
diff --git a/src/llvm/link/lld.c b/src/llvm/link/lld.c
index e1a2175..79eec2a 100644
--- a/src/llvm/link/lld.c
+++ b/src/llvm/link/lld.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
const char* get_absolute_link_path(const TargetConfig* config, const char* link_target_name) {
INFO("resolving absolute path for link target: %s", link_target_name);
@@ -13,22 +14,24 @@ const char* get_absolute_link_path(const TargetConfig* config, const char* link_
for (guint i = 0; i < config->link_search_paths->len; i++) {
const char* link_directory_path = g_array_index(config->link_search_paths, char*, i);
+ INFO("searching at: %s", link_directory_path);
+
char* path = g_build_filename(link_directory_path, link_target_name, NULL);
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
+ char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical);
const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR);
g_free(path);
g_free(cwd);
+ g_free(canonical);
if (exists && !is_dir) {
- INFO("link target found at: %s", canonical);
- return canonical;
+ INFO("link target found at: %s", cached_canonical);
+ return cached_canonical;
}
-
- g_free(canonical);
}
// file not found
@@ -41,47 +44,54 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig));
config->fatal_warnings = target_config->lld_fatal_warnings;
- config->object_file_names = g_array_new(FALSE, FALSE, sizeof(char*));
+ config->object_file_names = mem_new_g_array(MemoryNamespaceLld, sizeof(char*));
config->colorize = stdout_supports_ansi_esc();
+ config->driver = target_config->driver;
// append build object file
char* basename = g_strjoin(".", target_config->name, "o", NULL);
char* filename = g_build_filename(target_config->archive_directory, basename, NULL);
+ g_free(basename);
const char* target_object = get_absolute_link_path(target_config, (const char*) filename);
if (target_object == NULL) {
ERROR("failed to resolve path to target object: %s", filename);
+ g_free(filename);
lld_delete_link_config(config);
+ g_free(filename);
return NULL;
}
+ g_free(filename);
{
// output file after linking
basename = g_strjoin(".", target_config->name, "out", NULL);
filename = g_build_filename(target_config->output_directory, basename, NULL);
- config->output_file = filename;
+ config->output_file = mem_strdup(MemoryNamespaceLld, filename);
+
+ g_free(basename);
+ g_free(filename);
}
g_array_append_val(config->object_file_names, target_object);
INFO("resolved path of target object: %s", target_object);
- // if it is an app, add entrypoint library
- if (target_config->mode == Application) {
- char* entrypoint = g_strdup("libentrypoint.a");
- g_array_append_val(module->imports, entrypoint);
- }
-
// 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);
- const char* dependency_object = get_absolute_link_path(target_config, dependency);
+ const char* library = g_strjoin("", "libgsc", dependency, ".a", NULL);
+
+ const char* dependency_object = get_absolute_link_path(target_config, library);
if (dependency_object == NULL) {
- ERROR("failed to resolve path to dependency object: %s", dependency);
+ 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;
}
+ g_free((void*) library);
g_array_append_val(config->object_file_names, dependency_object);
INFO("resolved path of target object: %s", dependency_object);
}
@@ -91,59 +101,16 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
return config;
}
-GArray* lld_create_lld_arguments(TargetLinkConfig* config) {
- GArray* argv = g_array_new(TRUE, FALSE, sizeof(char*));
-
- gchar* arg = g_strdup("ld.lld");
- g_array_append_val(argv, arg);
-
- if (config->fatal_warnings) {
- arg = g_strdup("--fatal-warnings");
- g_array_append_val(argv, arg);
- }
-
- if (config->colorize) {
- arg = g_strdup("--color-diagnostics=always");
- g_array_append_val(argv, arg);
- }
-
- {
- arg = g_strjoin("", "-o", config->output_file, NULL);
- g_array_append_val(argv, arg);
- }
-
- for (guint i = 0; i < config->object_file_names->len; i++) {
- char* object_file_path = g_array_index(config->object_file_names, char*, i);
- arg = g_strjoin("", object_file_path, NULL);
- g_array_append_val(argv, arg);
- }
-
- return argv;
-}
-
BackendError lld_link_target(TargetLinkConfig* config) {
- DEBUG("linking target...");
- BackendError err = SUCCESS;
- GArray* argv = lld_create_lld_arguments(config);
+ if (link_run(config)) {
+ return SUCCESS;
+ }
- INFO("Linking target...");
-
- char* arguments = g_strjoinv(" ", (char**) argv->data);
- print_message(Info, "%s", arguments);
- g_free(arguments);
-
- INFO("done linking target...");
-
- g_array_free(argv, TRUE);
-
- return err;
+ return new_backend_impl_error(Implementation, NULL, "linking failed");
}
void lld_delete_link_config(TargetLinkConfig* config) {
- for (guint i = 0; i < config->object_file_names->len; i++) {
- free((void*) g_array_index(config->object_file_names, const char*, i));
- }
- g_array_free(config->object_file_names, TRUE);
+ mem_free(config->object_file_names);
mem_free(config);
}
diff --git a/src/llvm/llvm-ir/expr.c b/src/llvm/llvm-ir/expr.c
index 254a969..d3a3c66 100644
--- a/src/llvm/llvm-ir/expr.c
+++ b/src/llvm/llvm-ir/expr.c
@@ -387,6 +387,49 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
return SUCCESS;
}
+BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
+ LLVMBuilderRef builder, Parameter *parameter,
+ LLVMBool reference,
+ LLVMValueRef *llvm_result) {
+
+ LLVMValueRef llvm_variable = NULL;
+ if (g_hash_table_contains(scope->func_scope->params, parameter->name)) {
+ llvm_variable = g_hash_table_lookup(scope->func_scope->params, parameter->name);
+ }
+
+ Type* type;
+
+ ParameterDeclaration decl;
+
+ if (parameter->kind == ParameterDeclarationKind) {
+ decl = parameter->impl.definiton.declaration;
+ } else {
+ decl = parameter->impl.declaration;
+ }
+ type = decl.type;
+
+ if (llvm_variable == NULL) {
+ return new_backend_impl_error(Implementation, NULL, "Variable not found");
+ }
+
+ if (decl.qualifier == In || reference) {
+ *llvm_result = llvm_variable;
+ } else {
+ // no referencing, load value
+ LLVMTypeRef llvm_type;
+
+ get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
+
+ if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
+ *llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
+ } else {
+ *llvm_result = llvm_variable;
+ }
+ }
+
+ return SUCCESS;
+}
+
BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, AddressOf* addressOf,
LLVMValueRef *llvm_result) {
@@ -405,7 +448,12 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMValueRef *llvm_result) {
BackendError err;
- LLVMValueRef llvm_pointer = get_variable(scope, dereference->variable->impl.variable->name);
+ LLVMValueRef llvm_pointer = NULL;
+ err = impl_expr(unit, scope, builder, dereference->variable, TRUE, &llvm_pointer);
+ if (err.kind != Success) {
+ return err;
+ }
+
LLVMTypeRef llvm_deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type);
if (err.kind != Success) {
@@ -454,6 +502,11 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
reference,
llvm_result);
break;
+ case ExpressionKindParameter:
+ err = impl_parameter_load(unit, scope, builder, expr->impl.parameter,
+ reference,
+ llvm_result);
+ break;
case ExpressionKindAddressOf:
err = impl_address_of(unit, scope, builder, &expr->impl.addressOf,
llvm_result);
diff --git a/src/llvm/llvm-ir/func.c b/src/llvm/llvm-ir/func.c
index 473d6ad..032aa3b 100644
--- a/src/llvm/llvm-ir/func.c
+++ b/src/llvm/llvm-ir/func.c
@@ -26,7 +26,7 @@ void delete_local_scope(LLVMLocalScope* scope) {
free(scope);
}
-static LLVMValueRef get_parameter(const LLVMFuncScope* scope,
+LLVMValueRef get_parameter(const LLVMFuncScope* scope,
const char* name) {
if (g_hash_table_contains(scope->params, name)) {
return g_hash_table_lookup(scope->params, name);
@@ -44,11 +44,6 @@ LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name) {
return get_variable(scope->parent_scope, name);
}
- LLVMValueRef param = get_parameter(scope->func_scope, name);
- if (param != NULL) {
- return param;
- }
-
LLVMValueRef global_var = get_global_variable(scope->func_scope->global_scope, (char*) name);
return global_var;
}
@@ -108,7 +103,7 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
DEBUG("implementing function declaration: %s()", func->name);
BackendError err = SUCCESS;
- GArray* llvm_params = g_array_new(FALSE, FALSE, sizeof(LLVMTypeRef));
+ GArray* llvm_params = mem_new_g_array(MemoryNamespaceLlvm, sizeof(LLVMTypeRef));
GArray* func_params = NULL;
if (func->kind == FunctionDeclarationKind) {
@@ -140,8 +135,6 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
g_hash_table_insert(scope->functions, (char*) func->name, llvm_fun_type);
- g_array_free(llvm_params, FALSE);
-
return err;
}
diff --git a/src/llvm/llvm-ir/func.h b/src/llvm/llvm-ir/func.h
index 5ab4621..349135a 100644
--- a/src/llvm/llvm-ir/func.h
+++ b/src/llvm/llvm-ir/func.h
@@ -28,6 +28,8 @@ void delete_local_scope(LLVMLocalScope*);
LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name);
+LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name);
+
LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name);
BackendError impl_function_types(LLVMBackendCompileUnit* unit,
diff --git a/src/llvm/llvm-ir/stmt.c b/src/llvm/llvm-ir/stmt.c
index 6a3f41a..9f20c20 100644
--- a/src/llvm/llvm-ir/stmt.c
+++ b/src/llvm/llvm-ir/stmt.c
@@ -12,6 +12,27 @@
#include
#include
+BackendError impl_param_load(
+ LLVMBackendCompileUnit *unit,
+ LLVMBuilderRef builder,
+ LLVMLocalScope *scope,
+ const StorageExpr *expr,
+ LLVMValueRef* storage_target) {
+ BackendError err = SUCCESS;
+
+ if (expr->impl.parameter->impl.declaration.qualifier == Out || expr->impl.parameter->impl.declaration.qualifier == InOut) {
+ LLVMTypeRef llvm_type = NULL;
+ err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.parameter->impl.declaration.type, &llvm_type);
+ if (err.kind != Success) {
+ return err;
+ }
+
+ *storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target, "strg.param.out.load");
+ }
+
+ return err;
+}
+
BackendError impl_storage_expr(
LLVMBackendCompileUnit *unit,
LLVMBuilderRef
@@ -27,6 +48,10 @@ BackendError impl_storage_expr(
*storage_target =
get_variable(scope, expr->impl.variable->name);
break;
+ case StorageExprKindParameter:
+ *storage_target =
+ get_parameter(scope->func_scope, expr->impl.parameter->name);
+ break;
case StorageExprKindDereference:
LLVMValueRef index = NULL;
@@ -41,16 +66,29 @@ BackendError impl_storage_expr(
return err;
}
+ if (expr->impl.dereference.array->kind == StorageExprKindParameter) {
+ err = impl_param_load(unit, builder, scope, expr->impl.dereference.array, &array);
+ if (err.kind != Success) {
+ return err;
+ }
+ }
+
+ if (expr->impl.dereference.array->kind == StorageExprKindDereference) {
+ LLVMTypeRef deref_type = NULL;
+ err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type);
+ if (err.kind != Success) {
+ return err;
+ }
+
+ array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load");
+ }
+
LLVMTypeRef deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->target_type, &deref_type);
if (err.kind != Success) {
return err;
}
- if (expr->target_type->kind == TypeKindReference) {
- array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load");
- }
-
*storage_target = LLVMBuildGEP2(builder, deref_type, array, &index, 1, "strg.deref");
break;
@@ -73,7 +111,7 @@ BackendError impl_assign_stmt(
DEBUG("implementing assignment for variable: %p", assignment);
LLVMValueRef llvm_value = NULL;
- err = impl_expr(unit, scope, builder, assignment->value, TRUE, &llvm_value);
+ err = impl_expr(unit, scope, builder, assignment->value, false, &llvm_value);
if (err.kind != Success) {
return err;
}
@@ -206,19 +244,24 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
param_list = call->function->impl.declaration.parameter;
}
- LLVMBool reference = FALSE;
- Parameter parameter = g_array_index(param_list, Parameter, i);
- if (is_parameter_out(¶meter)) {
- reference = TRUE;
- }
+ Parameter param = g_array_index(param_list, Parameter, i);
LLVMValueRef llvm_arg = NULL;
- err = impl_expr(unit, scope, builder, arg, reference, &llvm_arg);
+ err = impl_expr(unit, scope, builder, arg, is_parameter_out(¶m), &llvm_arg);
if (err.kind != Success) {
break;
}
+ if (is_parameter_out(¶m)) {
+ if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) {
+ LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false);
+ LLVMTypeRef llvm_type = NULL;
+ get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type);
+ llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, "");
+ }
+ }
+
arguments[i] = llvm_arg;
}
diff --git a/src/llvm/llvm-ir/types.c b/src/llvm/llvm-ir/types.c
index f699e97..c64ed6e 100644
--- a/src/llvm/llvm-ir/types.c
+++ b/src/llvm/llvm-ir/types.c
@@ -321,7 +321,7 @@ BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
gpointer key = NULL;
gpointer val = NULL;
- BackendError err;
+ BackendError err = SUCCESS;
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
err = impl_type_define(unit, (Typedefine*) val, (const char*)key, scope);
diff --git a/src/llvm/parser.c b/src/llvm/parser.c
index 9f07ae8..be7ae7c 100644
--- a/src/llvm/parser.c
+++ b/src/llvm/parser.c
@@ -90,10 +90,11 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
ERROR("failed to emit code: %s", error);
err =
new_backend_impl_error(Implementation, NULL, "failed to emit code");
- LLVMDisposeMessage(error);
+
} else {
print_message(Info, "Generated code was written to: %s", filename);
}
+ LLVMDisposeMessage(error);
g_free((void*) filename);
g_free((void*) basename);
@@ -124,9 +125,9 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
ERROR("failed to create target machine: %s", error);
err = new_backend_impl_error(Implementation, NULL,
"unable to create target machine");
- LLVMDisposeMessage(error);
return err;
}
+ LLVMDisposeMessage(error);
DEBUG("Creating target machine...");
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
@@ -147,6 +148,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error,
config);
+ LLVMDisposeTargetMachine(target_machine);
+
return err;
}
@@ -223,9 +226,9 @@ static BackendError build_module(LLVMBackendCompileUnit* unit,
char* error = NULL;
if (LLVMVerifyModule(unit->module, LLVMReturnStatusAction, &error)) {
print_message(Error, "Unable to compile due to: %s", error);
- LLVMDisposeMessage(error);
err = new_backend_impl_error(Implementation, NULL, "LLVM backend verification error, see stdout");
}
+ LLVMDisposeMessage(error);
return err;
}
@@ -259,9 +262,13 @@ BackendError parse_module(const Module* module, const TargetConfig* config) {
if (config->mode == Application) {
TargetLinkConfig* link_config = lld_create_link_config(&target, config, module);
- lld_link_target(link_config);
+ if (link_config != NULL) {
+ err = lld_link_target(link_config);
- lld_delete_link_config(link_config);
+ lld_delete_link_config(link_config);
+ } else {
+ err = new_backend_impl_error(Implementation, NULL, "libclang error");
+ }
}
}
diff --git a/src/main.c b/src/main.c
index 5b222a4..0367f8b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
/**
* @brief Log a debug message to inform about beginning exit procedures
@@ -38,6 +39,10 @@ void setup(int argc, char *argv[]) {
lex_init();
+ link_init();
+
+ init_toml();
+
DEBUG("finished starting up gemstone...");
}
@@ -64,6 +69,11 @@ int main(int argc, char *argv[]) {
exit(0);
}
+ if (is_option_set("list-driver")) {
+ link_print_available_driver();
+ exit(0);
+ }
+
run_compiler();
if (is_option_set("print-gc-stats")) {
diff --git a/src/mem/cache.h b/src/mem/cache.h
index 486e84c..cb47d06 100644
--- a/src/mem/cache.h
+++ b/src/mem/cache.h
@@ -15,6 +15,7 @@ typedef char* MemoryNamespaceName;
#define MemoryNamespaceLex "Lexer"
#define MemoryNamespaceLog "Logging"
#define MemoryNamespaceOpt "Options"
+#define MemoryNamespaceTOML "TOML"
#define MemoryNamespaceSet "SET"
#define MemoryNamespaceLlvm "LLVM"
#define MemoryNamespaceLld "LLD"
diff --git a/src/set/set.c b/src/set/set.c
index 1ad9652..0d41b2e 100644
--- a/src/set/set.c
+++ b/src/set/set.c
@@ -1,7 +1,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -20,7 +19,7 @@ int createTypeCastFromExpression(Expression *expression, Type *resultType, Expre
bool compareTypes(Type *leftType, Type *rightType);
-char* type_to_string(Type* type);
+char *type_to_string(Type *type);
const Type ShortShortUnsingedIntType = {
.kind = TypeKindComposite,
@@ -335,8 +334,8 @@ int createRef(AST_NODE_PTR currentNode, Type **reftype) {
assert(currentNode->children->len == 1);
assert(AST_get_node(currentNode, 0)->kind == AST_Type);
- Type *type = malloc(sizeof(Type));
- Type *referenceType = malloc(sizeof(Type));
+ Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type));
+ Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
referenceType->kind = TypeKindReference;
referenceType->nodePtr = currentNode;
@@ -459,8 +458,8 @@ int createDef(AST_NODE_PTR currentNode, GArray **variables) {
}
if (!compareTypes(def.declaration.type, name->result)) {
- char* expected_type = type_to_string(def.declaration.type);
- char* gotten_type = type_to_string(name->result);
+ char *expected_type = type_to_string(def.declaration.type);
+ char *gotten_type = type_to_string(name->result);
print_diagnostic(&name->nodePtr->location, Warning, "expected `%s` got `%s`", expected_type, gotten_type);
@@ -490,8 +489,8 @@ int createDef(AST_NODE_PTR currentNode, GArray **variables) {
return status;
}
-char* type_to_string(Type* type) {
- char* string = NULL;
+char *type_to_string(Type *type) {
+ char *string = NULL;
switch (type->kind) {
case TypeKindPrimitive:
@@ -510,27 +509,32 @@ char* type_to_string(Type* type) {
if (type->impl.composite.scale < 1.0) {
for (int i = 0; i < (int) (type->impl.composite.scale * 4); i++) {
- char* concat = g_strconcat("half ", string, NULL);
- string = concat;
+ char *concat = g_strconcat("half ", string, NULL);
+ string = mem_strdup(MemoryNamespaceSet, concat);
+ g_free(concat);
}
} else if (type->impl.composite.scale > 1.0) {
for (int i = 0; i < (int) type->impl.composite.scale; i++) {
- char* concat = g_strconcat("long ", string, NULL);
- string = concat;
+ char *concat = g_strconcat("long ", string, NULL);
+ string = mem_strdup(MemoryNamespaceSet, concat);
+ g_free(concat);
}
}
if (type->impl.composite.sign == Unsigned) {
- char* concat = g_strconcat("unsigned ", string, NULL);
- string = concat;
+ char *concat = g_strconcat("unsigned ", string, NULL);
+ string = mem_strdup(MemoryNamespaceSet, concat);
+ g_free(concat);
}
break;
}
case TypeKindReference: {
- char* type_string = type_to_string(type->impl.reference);
- char* concat = g_strconcat("ref ", type_string, NULL);
- string = concat;
+ char *type_string = type_to_string(type->impl.reference);
+ char *concat = g_strconcat("ref ", type_string, NULL);
+ mem_free(type_string);
+ string = mem_strdup(MemoryNamespaceSet, concat);
+ g_free(concat);
break;
}
case TypeKindBox:
@@ -541,6 +545,18 @@ char* type_to_string(Type* type) {
return string;
}
+int getParameter(const char *name, Parameter **parameter) {
+ // loop through all variable scope and find a variable
+ if (functionParameter != NULL) {
+ if (g_hash_table_contains(functionParameter, name)) {
+ *parameter = g_hash_table_lookup(functionParameter, name);
+ return SEMANTIC_OK;
+ }
+ }
+
+ return SEMANTIC_ERROR;
+}
+
int getVariableFromScope(const char *name, Variable **variable) {
assert(name != NULL);
assert(variable != NULL);
@@ -548,13 +564,6 @@ int getVariableFromScope(const char *name, Variable **variable) {
DEBUG("getting var from scope");
int found = 0;
- // loop through all variable scope and find a variable
- if (functionParameter != NULL) {
- if (g_hash_table_contains(functionParameter, name)) {
- *variable = g_hash_table_lookup(functionParameter, name);
- found += 1;
- }
- }
for (size_t i = 0; i < Scope->len; i++) {
GHashTable *variable_table = g_array_index(Scope, GHashTable*, i);
@@ -612,6 +621,7 @@ int fillTablesWithVars(GHashTable *variableTable, const GArray *variables) {
}
[[nodiscard("type must be freed")]]
+
TypeValue createTypeValue(AST_NODE_PTR currentNode) {
DEBUG("create TypeValue");
TypeValue value;
@@ -726,7 +736,7 @@ int createArithOperation(Expression *ParentExpression, AST_NODE_PTR currentNode,
DEBUG("create arithmetic operation");
ParentExpression->impl.operation.kind = Arithmetic;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
assert(expectedChildCount == currentNode->children->len);
@@ -804,7 +814,7 @@ int createRelationalOperation(Expression *ParentExpression, AST_NODE_PTR current
// fill kind and Nodeptr
ParentExpression->impl.operation.kind = Relational;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
// fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) {
@@ -863,7 +873,7 @@ int createBoolOperation(Expression *ParentExpression, AST_NODE_PTR currentNode)
// fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
// fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) {
@@ -947,7 +957,7 @@ int createBoolNotOperation(Expression *ParentExpression, AST_NODE_PTR currentNod
//fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
//fill Operand
Expression *expression = createExpression(AST_get_node(currentNode, 0));
@@ -1015,7 +1025,7 @@ int createBitOperation(Expression *ParentExpression, AST_NODE_PTR currentNode) {
// fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
// fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) {
@@ -1152,7 +1162,7 @@ int createBitNotOperation(Expression *ParentExpression, AST_NODE_PTR currentNode
//fill kind and Nodeptr
ParentExpression->impl.operation.kind = Bitwise;
ParentExpression->impl.operation.nodePtr = currentNode;
- ParentExpression->impl.operation.operands = g_array_new(FALSE, FALSE, sizeof(Expression *));
+ ParentExpression->impl.operation.operands = mem_new_g_array(MemoryNamespaceSet, sizeof(Expression *));
//fill Operand
Expression *expression = createExpression(AST_get_node(currentNode, 0));
@@ -1425,7 +1435,7 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) {
return SEMANTIC_ERROR;
}
- Type *resultType = malloc(sizeof(Type));
+ Type *resultType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
resultType->nodePtr = currentNode;
resultType->kind = TypeKindReference;
resultType->impl.reference = address_of.variable->result;
@@ -1435,6 +1445,14 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) {
return SEMANTIC_OK;
}
+IO_Qualifier getParameterQualifier(Parameter *parameter) {
+ if (parameter->kind == ParameterDeclarationKind) {
+ return parameter->impl.declaration.qualifier;
+ } else {
+ return parameter->impl.definiton.declaration.qualifier;
+ }
+}
+
Expression *createExpression(AST_NODE_PTR currentNode) {
DEBUG("create Expression");
Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression));
@@ -1455,23 +1473,33 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
case AST_Ident:
DEBUG("find var");
expression->kind = ExpressionKindVariable;
- int status = getVariableFromScope(currentNode->value, &(expression->impl.variable));
+ int status = getVariableFromScope(currentNode->value, &expression->impl.variable);
if (status == SEMANTIC_ERROR) {
- DEBUG("Identifier is not in current scope");
- print_diagnostic(¤tNode->location, Error, "Variable not found");
- return NULL;
- }
- switch (expression->impl.variable->kind) {
- case VariableKindDeclaration:
+ expression->kind = ExpressionKindParameter;
+ status = getParameter(currentNode->value, &expression->impl.parameter);
+ if (status == SEMANTIC_ERROR) {
+ DEBUG("Identifier is not in current scope");
+ print_diagnostic(¤tNode->location, Error, "Unknown identifier: `%s`", currentNode->value);
+ return NULL;
+ }
+
+ if (getParameterQualifier(expression->impl.parameter) == Out) {
+ print_diagnostic(¤tNode->location, Error, "Parameter is write-only: `%s`",
+ currentNode->value);
+ return NULL;
+ }
+
+ if (expression->impl.parameter->kind == ParameterDeclarationKind) {
+ expression->result = expression->impl.parameter->impl.declaration.type;
+ } else {
+ expression->result = expression->impl.parameter->impl.definiton.declaration.type;
+ }
+ } else {
+ if (expression->impl.variable->kind == VariableKindDeclaration) {
expression->result = expression->impl.variable->impl.declaration.type;
- DEBUG("%d", expression->impl.variable->impl.declaration.type->kind);
- break;
- case VariableKindDefinition:
+ } else {
expression->result = expression->impl.variable->impl.definiton.declaration.type;
- break;
- default:
- PANIC("current Variable should not be an BoxMember");
- break;
+ }
}
break;
case AST_Add:
@@ -1603,7 +1631,7 @@ bool compareTypes(Type *leftType, Type *rightType) {
return FALSE;
}
-Type* getVariableType(Variable* variable) {
+Type *getVariableType(Variable *variable) {
if (variable->kind == VariableKindDeclaration) {
return variable->impl.declaration.type;
} else {
@@ -1611,15 +1639,33 @@ Type* getVariableType(Variable* variable) {
}
}
-int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) {
+Type *getParameterType(Parameter *parameter) {
+ if (parameter->kind == ParameterDeclarationKind) {
+ return parameter->impl.declaration.type;
+ } else {
+ return parameter->impl.definiton.declaration.type;
+ }
+}
+
+int createStorageExpr(StorageExpr *expr, AST_NODE_PTR node) {
switch (node->kind) {
case AST_Ident:
expr->kind = StorageExprKindVariable;
int status = getVariableFromScope(node->value, &expr->impl.variable);
if (status == SEMANTIC_ERROR) {
- return SEMANTIC_ERROR;
+
+ expr->kind = StorageExprKindParameter;
+ status = getParameter(node->value, &expr->impl.parameter);
+ if (status == SEMANTIC_ERROR) {
+ print_diagnostic(&node->location, Error, "Unknown token: `%s`", node->value);
+ return SEMANTIC_ERROR;
+ } else {
+ expr->target_type = getParameterType(expr->impl.parameter);
+ }
+
+ } else {
+ expr->target_type = getVariableType(expr->impl.variable);
}
- expr->target_type = getVariableType(expr->impl.variable);
break;
case AST_Dereference:
expr->kind = StorageExprKindDereference;
@@ -1629,7 +1675,7 @@ int createStorageExpr(StorageExpr* expr, AST_NODE_PTR node) {
expr->impl.dereference.index = createExpression(index_node);
expr->impl.dereference.array = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr));
- if (createStorageExpr(expr->impl.dereference.array, array_node) == SEMANTIC_ERROR){
+ if (createStorageExpr(expr->impl.dereference.array, array_node) == SEMANTIC_ERROR) {
return SEMANTIC_ERROR;
}
@@ -1656,17 +1702,31 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) {
assign.nodePtr = currentNode;
assign.destination = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr));
- int status = createStorageExpr(assign.destination, AST_get_node(currentNode, 0));
+ AST_NODE_PTR strg_expr = AST_get_node(currentNode, 0);
+ int status = createStorageExpr(assign.destination, strg_expr);
if (status == SEMANTIC_ERROR) {
return SEMANTIC_ERROR;
}
+ if (strg_expr->kind == AST_Parameter) {
+ if (getParameterQualifier(assign.destination->impl.parameter) == In) {
+ print_diagnostic(¤tNode->location, Error, "Parameter is read-only: `%s`",
+ assign.destination->impl.parameter->name);
+ return SEMANTIC_ERROR;
+ }
+ }
+
assign.value = createExpression(AST_get_node(currentNode, 1));
if (assign.value == NULL) {
return SEMANTIC_ERROR;
}
- // TODO: check assignment type compatability
+ if (!compareTypes(assign.destination->target_type, assign.value->result)) {
+ print_diagnostic(&assign.value->nodePtr->location, Error, "assignment requires `%s` but got `%s`",
+ type_to_string(assign.destination->target_type),
+ type_to_string(assign.value->result));
+ return SEMANTIC_ERROR;
+ }
ParentStatement->impl.assignment = assign;
return SEMANTIC_OK;
@@ -1677,18 +1737,19 @@ int createStatement(Block *block, AST_NODE_PTR currentNode);
int fillBlock(Block *block, AST_NODE_PTR currentNode) {
DEBUG("start filling Block");
block->nodePtr = currentNode;
- block->statemnts = g_array_new(FALSE, FALSE, sizeof(Statement *));
- GHashTable *lowerScope = g_hash_table_new(g_str_hash, g_str_equal);
+ block->statemnts = mem_new_g_array(MemoryNamespaceSet, sizeof(Statement *));
+ GHashTable *lowerScope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
g_array_append_val(Scope, lowerScope);
for (size_t i = 0; i < currentNode->children->len; i++) {
- int signal = createStatement(block, AST_get_node(currentNode, i));
+ AST_NODE_PTR stmt_node = AST_get_node(currentNode, i);
+ int signal = createStatement(block, stmt_node);
if (signal) {
return SEMANTIC_ERROR;
}
}
- g_hash_table_destroy(lowerScope);
+ mem_free(lowerScope);
g_array_remove_index(Scope, Scope->len - 1);
DEBUG("created Block successfully");
@@ -1867,7 +1928,7 @@ int createfuncall(Statement *parentStatement, AST_NODE_PTR currentNode) {
for (size_t i = 0; i < argsListNode->children->len; i++) {
AST_NODE_PTR currentExprList = AST_get_node(argsListNode, i);
- for (int j = ((int) currentExprList->children->len) -1; j >= 0; j--) {
+ for (int j = ((int) currentExprList->children->len) - 1; j >= 0; j--) {
AST_NODE_PTR expr_node = AST_get_node(currentExprList, j);
Expression *expr = createExpression(expr_node);
if (expr == NULL) {
@@ -1889,7 +1950,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
switch (currentNode->kind) {
case AST_Decl: {
- GArray *variable = g_array_new(FALSE, FALSE, sizeof(Variable *));
+ GArray *variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable *));
int status = createDecl(currentNode, &variable);
if (status) {
@@ -1908,7 +1969,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
break;
case AST_Def: {
- GArray *variable = g_array_new(FALSE, FALSE, sizeof(Variable *));
+ GArray *variable = mem_new_g_array(MemoryNamespaceSet, sizeof(Variable *));
if (createDef(currentNode, &variable)) {
return SEMANTIC_ERROR;
@@ -2003,30 +2064,21 @@ int createParam(GArray *Paramlist, AST_NODE_PTR currentNode) {
if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) {
return SEMANTIC_ERROR;
}
- Parameter param;
- param.nodePtr = currentNode;
- param.kind = ParameterDeclarationKind;
- param.impl.declaration = decl;
- param.name = AST_get_node(paramdecl, 1)->value;
+ Parameter *param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter));
+ param->nodePtr = currentNode;
+ param->kind = ParameterDeclarationKind;
+ param->impl.declaration = decl;
+ param->name = AST_get_node(paramdecl, 1)->value;
- DEBUG("param name: %s", param.name);
- g_array_append_val(Paramlist, param);
+ DEBUG("param name: %s", param->name);
+ g_array_append_val(Paramlist, *param);
- DEBUG("create var for param");
-
- Variable *paramvar = mem_alloc(MemoryNamespaceSet, sizeof(Variable));
- paramvar->kind = VariableKindDeclaration;
- paramvar->name = param.name;
- paramvar->nodePtr = currentNode;
- paramvar->impl.declaration.nodePtr = currentNode;
- paramvar->impl.declaration.qualifier = Local;
- paramvar->impl.declaration.type = param.impl.declaration.type;
-
- if (g_hash_table_contains(functionParameter, param.name)) {
- print_diagnostic(¶m.nodePtr->location, Error, "Names of function parameters must be unique: %s", param.name);
+ if (g_hash_table_contains(functionParameter, param->name)) {
+ print_diagnostic(¶m->nodePtr->location, Error, "Names of function parameters must be unique: %s",
+ param->name);
return SEMANTIC_ERROR;
}
- g_hash_table_insert(functionParameter, (gpointer) param.name, paramvar);
+ g_hash_table_insert(functionParameter, (gpointer) param->name, param);
DEBUG("created param successfully");
return SEMANTIC_OK;
@@ -2043,7 +2095,7 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
fundef.nodePtr = currentNode;
fundef.name = nameNode->value;
fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block));
- fundef.parameter = g_array_new(FALSE, FALSE, sizeof(Parameter));
+ fundef.parameter = mem_new_g_array(MemoryNamespaceSet, sizeof(Parameter));
DEBUG("paramlistlist child count: %i", paramlistlist->children->len);
for (size_t i = 0; i < paramlistlist->children->len; i++) {
@@ -2106,7 +2158,8 @@ bool compareParameter(GArray *leftParameter, GArray *rightParameter) {
int addFunction(const char *name, Function *function) {
if (function->kind == FunctionDefinitionKind) {
if (g_hash_table_contains(definedFunctions, name)) {
- print_diagnostic(&function->nodePtr->location, Error, "Multiple definition of function: `%s`", function->name);
+ print_diagnostic(&function->nodePtr->location, Error, "Multiple definition of function: `%s`",
+ function->name);
return SEMANTIC_ERROR;
}
g_hash_table_insert(declaredFunctions, (gpointer) name, function);
@@ -2117,7 +2170,8 @@ int addFunction(const char *name, Function *function) {
function->impl.declaration.parameter);
// a function can have multiple declartations but all have to be identical
if (result == FALSE) {
- print_diagnostic(&function->nodePtr->location, Error, "Divergent declaration of function: `%s`", function->name);
+ print_diagnostic(&function->nodePtr->location, Error, "Divergent declaration of function: `%s`",
+ function->name);
return SEMANTIC_ERROR;
}
}
@@ -2175,7 +2229,7 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
int createFunction(Function *function, AST_NODE_PTR currentNode) {
assert(currentNode->kind == AST_Fun);
- functionParameter = g_hash_table_new(g_str_hash, g_str_equal);
+ functionParameter = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
if (currentNode->children->len == 2) {
int signal = createFunDecl(function, currentNode);
@@ -2191,7 +2245,7 @@ int createFunction(Function *function, AST_NODE_PTR currentNode) {
PANIC("function should have 2 or 3 children");
}
- g_hash_table_destroy(functionParameter);
+ mem_free(functionParameter);
functionParameter = NULL;
int result = addFunction(function->name, function);
@@ -2359,32 +2413,34 @@ int createTypeDef(GHashTable *types, AST_NODE_PTR currentNode) {
Module *create_set(AST_NODE_PTR currentNode) {
DEBUG("create root Module");
//create tables for types
- declaredComposites = g_hash_table_new(g_str_hash, g_str_equal);
- declaredBoxes = g_hash_table_new(g_str_hash, g_str_equal);
- declaredFunctions = g_hash_table_new(g_str_hash, g_str_equal);
- definedFunctions = g_hash_table_new(g_str_hash, g_str_equal);
+ declaredComposites = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ declaredBoxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ declaredFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ definedFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
//create scope
- Scope = g_array_new(FALSE, FALSE, sizeof(GHashTable *));
+ Scope = mem_new_g_array(MemoryNamespaceSet, sizeof(GHashTable *));
//building current scope for module
- GHashTable *globalscope = g_hash_table_new(g_str_hash, g_str_equal);
- globalscope = g_hash_table_new(g_str_hash, g_str_equal);
+ GHashTable *globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ globalscope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
g_array_append_val(Scope, globalscope);
Module *rootModule = mem_alloc(MemoryNamespaceSet, sizeof(Module));
- GHashTable *boxes = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *types = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *functions = g_hash_table_new(g_str_hash, g_str_equal);
- GHashTable *variables = g_hash_table_new(g_str_hash, g_str_equal);
- GArray *imports = g_array_new(FALSE, FALSE, sizeof(const char *));
+ GHashTable *boxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ GHashTable *types = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ GHashTable *functions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ GHashTable *variables = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
+ GArray *imports = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *));
+ GArray *includes = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *));
rootModule->boxes = boxes;
rootModule->types = types;
rootModule->functions = functions;
rootModule->variables = variables;
rootModule->imports = imports;
+ rootModule->includes = includes;
DEBUG("created Module struct");
@@ -2456,6 +2512,10 @@ Module *create_set(AST_NODE_PTR currentNode) {
DEBUG("create Import");
g_array_append_val(imports, AST_get_node(currentNode, i)->value);
break;
+ case AST_Include:
+ DEBUG("create Include");
+ g_array_append_val(includes, AST_get_node(currentNode, i)->value);
+ break;
default:
INFO("Provided source file could not be parsed because of semantic error.");
break;
diff --git a/src/set/types.h b/src/set/types.h
index 2eb6e44..828f14e 100644
--- a/src/set/types.h
+++ b/src/set/types.h
@@ -432,6 +432,7 @@ typedef enum ExpressionKind_t {
ExpressionKindTransmute,
ExpressionKindConstant,
ExpressionKindVariable,
+ ExpressionKindParameter,
ExpressionKindDereference,
ExpressionKindAddressOf,
} ExpressionKind;
@@ -446,6 +447,7 @@ typedef struct Expression_t {
Transmute transmute;
TypeValue constant;
Variable* variable;
+ Parameter* parameter;
Dereference dereference;
AddressOf addressOf;
} impl;
@@ -526,6 +528,7 @@ typedef struct Branch_t {
typedef enum StorageExprKind_t {
StorageExprKindVariable,
+ StorageExprKindParameter,
StorageExprKindBoxAccess,
StorageExprKindDereference,
} StorageExprKind;
@@ -535,6 +538,7 @@ typedef struct StorageExpr_t {
Type* target_type;
union StorageExprImpl {
Variable* variable;
+ Parameter* parameter;
BoxAccess boxAccess;
StorageDereference dereference;
} impl;
@@ -580,6 +584,7 @@ typedef struct Module_t {
GHashTable* variables;
// to be resolved after the module has been parsed completely
GArray* imports;
+ GArray* includes;
} Module;
diff --git a/src/yacc/parser.y b/src/yacc/parser.y
index 70f3069..29dd70c 100644
--- a/src/yacc/parser.y
+++ b/src/yacc/parser.y
@@ -53,6 +53,7 @@
%type opbool
%type opbit
%type moduleimport
+%type moduleinclude
%type programbody
%type fundef
%type fundecl
@@ -109,6 +110,7 @@
%token OpBitnot
%token OpBitxor
%token KeyImport
+%token KeyInclude
%token KeySilent
%token KeyBox
%token FunTypeof
@@ -142,6 +144,7 @@ program: program programbody {AST_push_node(root, $2);
| programbody {AST_push_node(root, $1);};
programbody: moduleimport {$$ = $1;}
+ | moduleinclude {$$ = $1;}
| fundef{$$ = $1;}
| fundecl{$$ = $1;}
| box{$$ = $1;}
@@ -328,6 +331,9 @@ funcall: Ident argumentlist {AST_NODE_PTR funcall = AST_new_node(new_loc(), AST_
moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2);
DEBUG("Module-Import"); };
+moduleinclude: KeyInclude ValStr {$$ = AST_new_node(new_loc(), AST_Include, $2);
+ DEBUG("Module-Include"); };
+
statementlist: statementlist statement {AST_push_node($1, $2);
$$ = $1;}
| statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3ce0770..456af55 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,3 +13,5 @@ add_subdirectory(glib)
add_subdirectory(llvm)
add_subdirectory(project)
add_subdirectory(cache)
+add_subdirectory(hello_world)
+add_subdirectory(driver)
diff --git a/tests/ast/test_ast.py b/tests/ast/test_ast.py
index d7f9665..b153c33 100644
--- a/tests/ast/test_ast.py
+++ b/tests/ast/test_ast.py
@@ -84,6 +84,7 @@ def run_check_print_node():
53 address of
54 deref
55 ref
+56 value
""" == p.stdout
diff --git a/tests/driver/CMakeLists.txt b/tests/driver/CMakeLists.txt
new file mode 100644
index 0000000..85fd68c
--- /dev/null
+++ b/tests/driver/CMakeLists.txt
@@ -0,0 +1,13 @@
+include(CTest)
+
+# ------------------------------------------------------- #
+# CTEST 1
+# test compilation and execution with GCC driver
+
+add_test(NAME driver_gcc
+ WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/driver/gcc
+ COMMAND python ${GEMSTONE_TEST_DIR}/driver/gcc/test_driver_gcc.py)
+
+add_test(NAME driver_clang
+ WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/driver/clang
+ COMMAND python ${GEMSTONE_TEST_DIR}/driver/clang/test_driver_clang.py)
diff --git a/tests/driver/clang/build.toml b/tests/driver/clang/build.toml
new file mode 100644
index 0000000..f200572
--- /dev/null
+++ b/tests/driver/clang/build.toml
@@ -0,0 +1,19 @@
+[project]
+name = "driver compilation test"
+version = "0.1.0"
+description = "Print a string to stdout"
+license = "GPL-2.0"
+authors = [ "Sven Vogel " ]
+
+[target.release]
+link-paths = [ "../../../bin/std" ]
+import-paths = [ "../../../lib/src" ]
+driver = "clang"
+root = "main.gsc"
+mode = "application"
+output = "bin"
+archive = "archive"
+print_ast = false
+print_asm = false
+print_ir = false
+opt = 3
diff --git a/tests/driver/clang/main.gsc b/tests/driver/clang/main.gsc
new file mode 100644
index 0000000..70314a2
--- /dev/null
+++ b/tests/driver/clang/main.gsc
@@ -0,0 +1,28 @@
+
+import "std"
+
+fun cstrlen(in cstr: str)(out u32: len) {
+ u32: idx = 0 as u32
+
+ while !(str[idx] == 0) {
+ idx = idx + 1
+ }
+
+ len = idx
+}
+
+fun printcstr(in cstr: msg) {
+ u32: len = 0
+ cstrlen(msg)(len)
+
+ handle: stdout = 0
+ getStdoutHandle()(stdout)
+
+ u32: written = 0
+ writeBytes(stdout, msg, len)(written)
+}
+
+fun main() {
+ cstr: msg = "Hello, world!\n"
+ printcstr(msg)
+}
diff --git a/tests/driver/clang/test_driver_clang.py b/tests/driver/clang/test_driver_clang.py
new file mode 100644
index 0000000..ae8f2b1
--- /dev/null
+++ b/tests/driver/clang/test_driver_clang.py
@@ -0,0 +1,29 @@
+import os.path
+import subprocess
+import logging
+from logging import info
+
+
+def check_clang():
+ info("testing Clang driver...")
+
+ logging.basicConfig(level=logging.INFO)
+
+ p = subprocess.run(["../../../bin/check/gsc", "build", "release", "--verbose", "--driver=clang"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert p.returncode == 0
+
+ p = subprocess.run(["bin/release.out"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert "Hello, world!" in p.stdout
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ info("check if binary exists...")
+ assert os.path.exists("../../../bin/check/gsc")
+
+ check_clang()
diff --git a/tests/driver/gcc/build.toml b/tests/driver/gcc/build.toml
new file mode 100644
index 0000000..85e76d9
--- /dev/null
+++ b/tests/driver/gcc/build.toml
@@ -0,0 +1,19 @@
+[project]
+name = "driver compilation test"
+version = "0.1.0"
+description = "Print a string to stdout"
+license = "GPL-2.0"
+authors = [ "Sven Vogel " ]
+
+[target.release]
+link-paths = [ "../../../bin/std" ]
+import-paths = [ "../../../lib/src" ]
+driver = "gcc"
+root = "main.gsc"
+mode = "application"
+output = "bin"
+archive = "archive"
+print_ast = false
+print_asm = false
+print_ir = false
+opt = 3
diff --git a/tests/driver/gcc/main.gsc b/tests/driver/gcc/main.gsc
new file mode 100644
index 0000000..70314a2
--- /dev/null
+++ b/tests/driver/gcc/main.gsc
@@ -0,0 +1,28 @@
+
+import "std"
+
+fun cstrlen(in cstr: str)(out u32: len) {
+ u32: idx = 0 as u32
+
+ while !(str[idx] == 0) {
+ idx = idx + 1
+ }
+
+ len = idx
+}
+
+fun printcstr(in cstr: msg) {
+ u32: len = 0
+ cstrlen(msg)(len)
+
+ handle: stdout = 0
+ getStdoutHandle()(stdout)
+
+ u32: written = 0
+ writeBytes(stdout, msg, len)(written)
+}
+
+fun main() {
+ cstr: msg = "Hello, world!\n"
+ printcstr(msg)
+}
diff --git a/tests/driver/gcc/test_driver_gcc.py b/tests/driver/gcc/test_driver_gcc.py
new file mode 100644
index 0000000..a081961
--- /dev/null
+++ b/tests/driver/gcc/test_driver_gcc.py
@@ -0,0 +1,29 @@
+import os.path
+import subprocess
+import logging
+from logging import info
+
+
+def check_gcc():
+ info("testing GCC driver...")
+
+ logging.basicConfig(level=logging.INFO)
+
+ p = subprocess.run(["../../../bin/check/gsc", "build", "release", "--verbose", "--driver=gcc"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert p.returncode == 0
+
+ p = subprocess.run(["bin/release.out"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert "Hello, world!" in p.stdout
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ info("check if binary exists...")
+ assert os.path.exists("../../../bin/check/gsc")
+
+ check_gcc()
diff --git a/tests/hello_world/CMakeLists.txt b/tests/hello_world/CMakeLists.txt
new file mode 100644
index 0000000..6ca46a7
--- /dev/null
+++ b/tests/hello_world/CMakeLists.txt
@@ -0,0 +1,9 @@
+include(CTest)
+
+# ------------------------------------------------------- #
+# CTEST 1
+# test a simple project
+
+add_test(NAME hello_world
+ WORKING_DIRECTORY ${GEMSTONE_TEST_DIR}/hello_world
+ COMMAND python ${GEMSTONE_TEST_DIR}/hello_world/test_hello_world.py)
diff --git a/tests/hello_world/build.toml b/tests/hello_world/build.toml
new file mode 100644
index 0000000..71fbfd3
--- /dev/null
+++ b/tests/hello_world/build.toml
@@ -0,0 +1,19 @@
+[project]
+name = "print C string test"
+version = "0.1.0"
+description = "Print a string to stdout"
+license = "GPL-2.0"
+authors = [ "Sven Vogel " ]
+
+[target.release]
+link-paths = [ "../../bin/std" ]
+import-paths = [ "../../lib/src" ]
+driver = "gcc"
+root = "main.gsc"
+mode = "application"
+output = "bin"
+archive = "archive"
+print_ast = false
+print_asm = false
+print_ir = false
+opt = 3
diff --git a/tests/hello_world/main.gsc b/tests/hello_world/main.gsc
new file mode 100644
index 0000000..70314a2
--- /dev/null
+++ b/tests/hello_world/main.gsc
@@ -0,0 +1,28 @@
+
+import "std"
+
+fun cstrlen(in cstr: str)(out u32: len) {
+ u32: idx = 0 as u32
+
+ while !(str[idx] == 0) {
+ idx = idx + 1
+ }
+
+ len = idx
+}
+
+fun printcstr(in cstr: msg) {
+ u32: len = 0
+ cstrlen(msg)(len)
+
+ handle: stdout = 0
+ getStdoutHandle()(stdout)
+
+ u32: written = 0
+ writeBytes(stdout, msg, len)(written)
+}
+
+fun main() {
+ cstr: msg = "Hello, world!\n"
+ printcstr(msg)
+}
diff --git a/tests/hello_world/test_hello_world.py b/tests/hello_world/test_hello_world.py
new file mode 100644
index 0000000..a9f801d
--- /dev/null
+++ b/tests/hello_world/test_hello_world.py
@@ -0,0 +1,29 @@
+import os.path
+import subprocess
+import logging
+from logging import info
+
+
+def check_build_and_run():
+ info("testing compilation of hello world...")
+
+ logging.basicConfig(level=logging.INFO)
+
+ p = subprocess.run(["../../bin/check/gsc", "build", "release", "--verbose"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert p.returncode == 0
+
+ p = subprocess.run(["bin/release.out"], capture_output=True, text=True)
+
+ print(p.stdout)
+
+ assert "Hello, world!" in p.stdout
+
+if __name__ == "__main__":
+ logging.basicConfig(level=logging.INFO)
+ info("check if binary exists...")
+ assert os.path.exists("../../bin/check/gsc")
+
+ check_build_and_run()
diff --git a/tests/input_file/CMakeLists.txt b/tests/input_file/CMakeLists.txt
index 263e769..23244fb 100644
--- a/tests/input_file/CMakeLists.txt
+++ b/tests/input_file/CMakeLists.txt
@@ -6,4 +6,4 @@ include(CTest)
add_test(NAME input_file_check
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/check
- COMMAND python ${GEMSTONE_TEST_DIR}/input_file/test_input_file.py ${GEMSTONE_TEST_DIR}/input_file/test.gem)
+ COMMAND python ${GEMSTONE_TEST_DIR}/input_file/test_input_file.py ${GEMSTONE_TEST_DIR}/input_file/test.gsc)
diff --git a/tests/input_file/test.gem b/tests/input_file/test.gem
deleted file mode 100644
index 991288d..0000000
--- a/tests/input_file/test.gem
+++ /dev/null
@@ -1,6 +0,0 @@
-
-import "std.io"
-
-fun main {
- print("Hello, World!!!")
-}
\ No newline at end of file
diff --git a/tests/input_file/test.gsc b/tests/input_file/test.gsc
new file mode 100644
index 0000000..3479ad3
--- /dev/null
+++ b/tests/input_file/test.gsc
@@ -0,0 +1,4 @@
+
+fun main(out int: ret) {
+ ret = 56 as int
+}