Merge pull request #128 from Servostar/124-compile-exectuable-with-clang

124 compile exectuable with clang
This commit is contained in:
servostar 2024-07-21 01:46:56 +02:00 committed by GitHub
commit 20b6d269d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 1065 additions and 286 deletions

2
.env
View File

@ -1 +1 @@
SDK=0.2.5-alpine-3.19.1 SDK=0.2.6-alpine-3.19.1

View File

@ -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 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 description="docker image for setting up the build pipeline on SDK"
LABEL website="https://github.com/Servostar/gemstone" LABEL website="https://github.com/Servostar/gemstone"

106
README.md
View File

@ -1,16 +1,74 @@
<div align="center"> <div align="center">
<picture>
<img alt="gemstone logo" src="https://github.com/Servostar/gemstone/assets/72654954/fdb37c1b-81ca-4e6a-a9e9-c46effb12dae" width="75%"> <img alt="gemstone logo" src="https://github.com/Servostar/gemstone/assets/72654954/fdb37c1b-81ca-4e6a-a9e9-c46effb12dae" width="75%">
</picture>
</div>
<br> <br>
<p>
Open source programming language compiler based on LLVM, GLib and GNU Bison/Flex
<br>
capable of multi target cross compilation powered by simple build system.
</p>
<br>
<img src="https://img.shields.io/github/actions/workflow/status/Servostar/gemstone/build-check-sdk.yaml?label=Linux"/>
<img src="https://img.shields.io/github/actions/workflow/status/Servostar/gemstone/msys2-cross-compile.yml?label=Windows"/>
<img src="https://img.shields.io/github/license/Servostar/gemstone"/>
<img src="https://img.shields.io/github/languages/count/Servostar/gemstone"/>
<img src="https://img.shields.io/github/languages/top/Servostar/gemstone"/>
<br>
<img src="https://img.shields.io/badge/c-%2300599C.svg?style=flat&logo=c&logoColor=white"/>
<img src="https://img.shields.io/badge/CMake-%23008FBA.svg?&logo=cmake&color=064F8C&logoColor=white"/>
<img src="https://img.shields.io/badge/LLVM-%20?style=flat&color=262D3A&logo=llvm&logoColor=white"/>
</div>
## Gemstone ## About
Gemstone is a programming language compiler (short: GSC) written in C based on flex and GNU bison. 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. 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) ## Dependencies (build)
### Windows 11 ### 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. 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 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: The following graph visualizes the build pipeline:
``` ```mermaid
SDK (environment) flowchart LR
│ configure build environment
│ cmake, make, gcc, yacc, lex
Devkit (pipeline)
│ create build pipeline
│ create make targets
Pipeline
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
yacc (generate files) GCC (compile) Extra Source Files (src/*.c)
│ │ │
├─ parser.tab.h ─────────────►│◄────────────────────┘
│ │
└─ parser.tab.c ─────────────►│
lex (generate file) │
│ │
└─ lexer.ll.c ──────────────►│
gsc
``` ```
## Docker images ## Docker images

View File

@ -16,10 +16,16 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/../bin/std")
# add native module libraries # add native module libraries
file(GLOB_RECURSE STDLIB_IO_SOURCE_FILES src/io/*.c) 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) 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) 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})

View File

@ -2,9 +2,6 @@
// Created by servostar on 6/10/24. // Created by servostar on 6/10/24.
// //
extern void entry(void);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
entry();
return 0; return 0;
} }

View File

@ -6,7 +6,7 @@
# | Generic Input/Output | # | Generic Input/Output |
# `----------------------------------------` # `----------------------------------------`
import "def.gsc" include "def.gsc"
# platform specific handle to an I/O device # platform specific handle to an I/O device
# can be a file, buffer, window or something else # can be a file, buffer, window or something else

View File

@ -6,7 +6,7 @@
# | Memory Management | # | Memory Management |
# `----------------------------------------` # `----------------------------------------`
import "def.gsc" include "def.gsc"
# Allocate `len` bytes of heap memory # Allocate `len` bytes of heap memory
# Returns a pointer to the memory as `ptr` # Returns a pointer to the memory as `ptr`

View File

@ -6,7 +6,7 @@
# | Operating System | # | Operating System |
# `----------------------------------------` # `----------------------------------------`
import "def.gsc" include "def.gsc"
# Return a hard coded C string identifying the underlying operating system # Return a hard coded C string identifying the underlying operating system
# Will return one of the following: # Will return one of the following:

View File

@ -7,10 +7,10 @@
# `----------------------------------------` # `----------------------------------------`
# standard type definitions # standard type definitions
import "def.gsc" include "def.gsc"
# I/O operations # I/O operations
import "io.gsc" include "io.gsc"
# memory management # memory management
import "mem.gsc" include "mem.gsc"

View File

@ -1,11 +1,11 @@
FROM alpine:3.19.1 FROM alpine:3.19.1
LABEL authors="servostar" 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 description="base image for building the gemstone programming language compiler"
LABEL website="https://github.com/Servostar/gemstone" LABEL website="https://github.com/Servostar/gemstone"
# install dependencies # 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 # create user for build
RUN adduser --disabled-password lorang RUN adduser --disabled-password lorang

View File

@ -101,6 +101,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
case AST_Ident: case AST_Ident:
case AST_Macro: case AST_Macro:
case AST_Import: case AST_Import:
case AST_Include:
case AST_Storage: case AST_Storage:
case AST_Typekind: case AST_Typekind:
case AST_Sign: case AST_Sign:

View File

@ -79,6 +79,7 @@ enum AST_SyntaxElement_t {
AST_AddressOf, AST_AddressOf,
AST_Dereference, AST_Dereference,
AST_Reference, AST_Reference,
AST_Include,
AST_ELEMENT_COUNT AST_ELEMENT_COUNT
}; };

View File

@ -9,6 +9,7 @@
#include <assert.h> #include <assert.h>
#include <toml.h> #include <toml.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <link/driver.h>
static GHashTable* args = NULL; static GHashTable* args = NULL;
@ -68,7 +69,7 @@ GArray* get_non_options_after(const char* command) {
return NULL; return NULL;
} }
GArray* array = g_array_new(FALSE, FALSE, sizeof(const char*)); GArray* array = mem_new_g_array(MemoryNamespaceOpt, sizeof(const char*));
GHashTableIter iter; GHashTableIter iter;
gpointer key, value; gpointer key, value;
@ -82,7 +83,6 @@ GArray* get_non_options_after(const char* command) {
} }
if (array->len == 0) { if (array->len == 0) {
g_array_free(array, FALSE);
return NULL; return NULL;
} }
@ -98,12 +98,13 @@ TargetConfig* default_target_config() {
config->print_ast = false; config->print_ast = false;
config->print_asm = false; config->print_asm = false;
config->print_ir = false; config->print_ir = false;
config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER);
config->mode = Application; config->mode = Application;
config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive"); config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin"); config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->optimization_level = 1; config->optimization_level = 1;
config->root_module = NULL; 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->lld_fatal_warnings = FALSE;
config->gsc_fatal_warnings = FALSE; config->gsc_fatal_warnings = FALSE;
config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); 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(); 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")) { if (is_option_set("link-paths")) {
const Option* opt = get_option("link-paths"); const Option* opt = get_option("link-paths");
@ -174,7 +184,7 @@ TargetConfig* default_target_config_from_args() {
while((end = strchr(start, ',')) != NULL) { while((end = strchr(start, ',')) != NULL) {
const int len = end - start; const int len = end - start;
char* link_path = malloc(len + 1); char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len); memcpy(link_path, start, len);
link_path[len] = 0; link_path[len] = 0;
@ -185,7 +195,7 @@ TargetConfig* default_target_config_from_args() {
const int len = strlen(start); const int len = strlen(start);
if (len > 0) { if (len > 0) {
char* link_path = malloc(len + 1); char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len); memcpy(link_path, start, len);
link_path[len] = 0; 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."); print_message(Warning, "Got more than one file to compile, using first, ignoring others.");
} }
config->root_module = mem_strdup(MemoryNamespaceOpt, ((char**) files->data) [0]); config->root_module = mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0));
g_array_free(files, TRUE);
} }
char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); char* default_import_path = mem_strdup(MemoryNamespaceOpt, ".");
g_array_append_val(config->import_paths, default_import_path); 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; return config;
} }
@ -229,6 +267,7 @@ void print_help(void) {
" --print-ir print resulting LLVM-IR to a file", " --print-ir print resulting LLVM-IR to a file",
" --mode=[app|lib] set the compilation mode to either application or library", " --mode=[app|lib] set the compilation mode to either application or library",
" --output=name name of output files without extension", " --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", " --link-paths=[paths,] set a list of directories to for libraries in",
" --all-fatal-warnings treat all warnings as errors", " --all-fatal-warnings treat all warnings as errors",
" --lld-fatal-warnings treat linker 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)", " --debug print debug logs (if not disabled at compile time)",
" --version print the version", " --version print the version",
" --list-targets print a list of all available targets supported", " --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", " --help print this help dialog",
" --color-always always colorize output", " --color-always always colorize output",
" --print-gc-stats print statistics of the garbage collector" " --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) { static int parse_project_table(ProjectConfig *config, const toml_table_t *project_table) {
DEBUG("parsing project table..."); DEBUG("parsing project table...");
@ -297,7 +352,7 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec
// author names // author names
toml_array_t *authors = toml_array_in(project_table, "authors"); toml_array_t *authors = toml_array_in(project_table, "authors");
if (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++) { for (int i = 0;; i++) {
toml_datum_t author = toml_string_at(authors, 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; *mode = Library;
return PROJECT_OK; 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; 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_asm, target_table, "print_asm");
get_bool(&target_config->print_ir, target_table, "print_ir"); 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->root_module, target_table, "root");
get_str(&target_config->output_directory, target_table, "output"); get_str(&target_config->output_directory, target_table, "output");
get_str(&target_config->archive_directory, target_table, "archive"); 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) { if (err != PROJECT_OK) {
return err; 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); 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; 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); const char *key = toml_key_in(targets, i);
if (key == NULL) if (key == NULL)
break; break;
toml_table_t *target = toml_table_in(targets, key); 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; return PROJECT_OK;
@ -393,8 +458,7 @@ int load_project_config(ProjectConfig *config) {
FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r"); FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r");
if (config_file == NULL) { if (config_file == NULL) {
print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno)); print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno));
INFO("project file not found"); return PROJECT_SEMANTIC_ERR;
return PROJECT_TOML_ERR;
} }
char err_buf[TOML_ERROR_MSG_BUF]; 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)); toml_table_t *conf = toml_parse_file(config_file, err_buf, sizeof(err_buf));
fclose(config_file); fclose(config_file);
if (conf == NULL) { if (conf != NULL) {
print_message(Error, "Invalid project configuration: %s", err_buf); int status = PROJECT_SEMANTIC_ERR;
return PROJECT_SEMANTIC_ERR;
}
toml_table_t *project = toml_table_in(conf, "project"); toml_table_t *project = toml_table_in(conf, "project");
if (project == NULL) {
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."); print_message(Error, "Invalid project configuration: missing project table.");
} }
if (parse_project_table(config, project) == PROJECT_OK) { toml_free(conf);
return parse_targets(config, conf); return status;
} else {
print_message(Error, "Invalid project configuration: %s", err_buf);
} }
toml_free(conf);
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
@ -435,9 +502,8 @@ void delete_target_config(TargetConfig* config) {
} }
if (config->link_search_paths) { if (config->link_search_paths) {
for (guint i = 0; i < config->link_search_paths->len; i++) { 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); mem_free(config);
} }
@ -447,7 +513,7 @@ void delete_project_config(ProjectConfig* config) {
mem_free(config->name); mem_free(config->name);
} }
if (config->authors != NULL) { if (config->authors != NULL) {
g_array_free(config->authors, TRUE); mem_free(config->authors);
} }
if (config->desc != NULL) { if (config->desc != NULL) {
mem_free(config->desc); mem_free(config->desc);
@ -466,7 +532,7 @@ void delete_project_config(ProjectConfig* config) {
delete_target_config(val); delete_target_config(val);
} }
g_hash_table_destroy(config->targets); mem_free(config->targets);
} }
mem_free_from(MemoryNamespaceOpt, config); mem_free_from(MemoryNamespaceOpt, config);
@ -484,3 +550,16 @@ ProjectConfig* default_project_config() {
return 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);
}

View File

@ -24,6 +24,7 @@ typedef struct TargetLinkConfig_t {
// colorize linker output // colorize linker output
bool colorize; bool colorize;
char* output_file; char* output_file;
char* driver;
} TargetLinkConfig; } TargetLinkConfig;
typedef enum TargetCompilationMode_t { typedef enum TargetCompilationMode_t {
@ -50,6 +51,8 @@ typedef struct TargetConfig_t {
char* output_directory; char* output_directory;
// output directory for intermediate representations (LLVM-IR, Assembly, ...) // output directory for intermediate representations (LLVM-IR, Assembly, ...)
char* archive_directory; char* archive_directory;
// binary driver for executable generation
char* driver;
// mode of compilation // mode of compilation
TargetCompilationMode mode; TargetCompilationMode mode;
// number between 1 and 3 // number between 1 and 3
@ -183,4 +186,6 @@ const Option* get_option(const char* option);
[[nodiscard("must be freed")]] [[nodiscard("must be freed")]]
GArray* get_non_options_after(const char* command); GArray* get_non_options_after(const char* command);
void init_toml();
#endif //GEMSTONE_OPT_H #endif //GEMSTONE_OPT_H

View File

@ -165,11 +165,20 @@ static void run_backend_codegen(const Module* module, const TargetConfig* target
print_message(Info, "Compilation finished successfully"); print_message(Info, "Compilation finished successfully");
err = deinit_backend(); 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) { 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); 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++) { for (guint i = 0; i < config->import_paths->len; i++) {
const char* import_directory_path = g_array_index(config->import_paths, char*, 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 exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR); 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(path);
g_free(cwd); g_free(cwd);
g_free(canonical);
if (exists && !is_dir) { if (exists && !is_dir) {
INFO("import target found at: %s", canonical); INFO("import target found at: %s", cached_canonical);
return canonical; return cached_canonical;
} }
g_free(canonical);
} }
// file not found // 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++) { for (size_t i = 0; i < AST_get_child_count(root_module); i++) {
AST_NODE_PTR child = AST_get_node(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); const char* path = get_absolute_import_path(target, child->value);
if (path == NULL) { 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); g_hash_table_insert(imports, (gpointer) path, NULL);
gchar* directory = g_path_get_dirname(path); 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 { } else {
@ -318,7 +330,7 @@ static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *co
if (targets != NULL) { if (targets != NULL) {
for (guint i = 0; i < targets->len; i++) { 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)) { if (g_hash_table_contains(config->targets, target_name)) {
build_target(unit, g_hash_table_lookup(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 { } else {
print_message(Error, "No targets specified."); print_message(Error, "No targets specified.");
} }

View File

@ -42,7 +42,7 @@ ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
// lazy init of heap stack // lazy init of heap stack
if (stack->files == NULL) { 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)); ModuleFile* new_file = mem_alloc(MemoryNamespaceStatic, sizeof(ModuleFile));
@ -66,9 +66,10 @@ void delete_files(ModuleFileStack *stack) {
fclose(file->handle); fclose(file->handle);
} }
mem_free((void*) file);
} }
g_array_free(stack->files, TRUE); mem_free(stack->files);
DEBUG("deleted module file stack"); DEBUG("deleted module file stack");
} }
@ -330,8 +331,11 @@ const char *get_absolute_path(const char *path) {
DEBUG("resolving absolute path of: %s", path); DEBUG("resolving absolute path of: %s", path);
char* cwd = g_get_current_dir(); char* cwd = g_get_current_dir();
char* canoical = g_canonicalize_filename(path, cwd); char* canonical = g_canonicalize_filename(path, cwd);
g_free(cwd); g_free(cwd);
return canoical; char* cached_canonical = mem_strdup(MemoryNamespaceStatic, canonical);
g_free(canonical);
return cached_canonical;
} }

View File

@ -81,6 +81,7 @@
"!" {DEBUG("\"%s\" tokenized with \'OpBitnot\'", yytext); return(OpBitnot);}; "!" {DEBUG("\"%s\" tokenized with \'OpBitnot\'", yytext); return(OpBitnot);};
"^" {DEBUG("\"%s\" tokenized with \'OpBitxor\'", yytext); return(OpBitxor);}; "^" {DEBUG("\"%s\" tokenized with \'OpBitxor\'", yytext); return(OpBitxor);};
"import" {DEBUG("\"%s\" tokenized with \'KeyImport\'", yytext); return(KeyImport);}; "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);}; "silent" {DEBUG("\"%s\" tokenized with \'KeySilent\'", yytext); return(KeySilent);};
"box" {DEBUG("\"%s\" tokenized with \'KeyBox\'", yytext); return(KeyBox);}; "box" {DEBUG("\"%s\" tokenized with \'KeyBox\'", yytext); return(KeyBox);};
"typeof" {DEBUG("\"%s\" tokenized with \'FunTypeof\'", yytext); return(FunTypeof);}; "typeof" {DEBUG("\"%s\" tokenized with \'FunTypeof\'", yytext); return(FunTypeof);};

42
src/link/clang/driver.c Normal file
View File

@ -0,0 +1,42 @@
//
// Created by servostar on 18.07.24.
//
#include <link/clang/driver.h>
#include <io/files.h>
#include <mem/cache.h>
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;
}

14
src/link/clang/driver.h Normal file
View File

@ -0,0 +1,14 @@
//
// Created by servostar on 18.07.24.
//
#ifndef GEMSTONE_CLANG_DRIVER_H
#define GEMSTONE_CLANG_DRIVER_H
#include <link/driver.h>
bool clang_link(TargetLinkConfig* config);
BinaryDriver* clang_get_driver();
#endif // GEMSTONE_CLANG_DRIVER_H

20
src/link/driver.h Normal file
View File

@ -0,0 +1,20 @@
//
// Created by servostar on 18.07.24.
//
#ifndef GEMSTONE_DRIVER_H
#define GEMSTONE_DRIVER_H
#include <cfg/opt.h>
#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

42
src/link/gcc/driver.c Normal file
View File

@ -0,0 +1,42 @@
//
// Created by servostar on 18.07.24.
//
#include <link/clang/driver.h>
#include <io/files.h>
#include <mem/cache.h>
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;
}

14
src/link/gcc/driver.h Normal file
View File

@ -0,0 +1,14 @@
//
// Created by servostar on 18.07.24.
//
#ifndef GEMSTONE_GCC_DRIVER_H
#define GEMSTONE_GCC_DRIVER_H
#include <link/driver.h>
bool gcc_link(TargetLinkConfig* config);
BinaryDriver* gcc_get_driver();
#endif // GEMSTONE_GCC_DRIVER_H

72
src/link/lib.c Normal file
View File

@ -0,0 +1,72 @@
//
// Created by servostar on 18.07.24.
//
#include <link/lib.h>
#include <mem/cache.h>
#include <sys/log.h>
#include <io/files.h>
#include <link/clang/driver.h>
#include <link/gcc/driver.h>
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);
}
}

18
src/link/lib.h Normal file
View File

@ -0,0 +1,18 @@
//
// Created by servostar on 18.07.24.
//
#ifndef GEMSTONE_LIB_H
#define GEMSTONE_LIB_H
#include <link/driver.h>
typedef BinaryDriver* (*driver_init)();
void link_init();
bool link_run(TargetLinkConfig*);
void link_print_available_driver();
#endif //GEMSTONE_LIB_H

View File

@ -7,6 +7,7 @@
#include <llvm/backend.h> #include <llvm/backend.h>
#include <llvm/parser.h> #include <llvm/parser.h>
#include <sys/log.h> #include <sys/log.h>
#include <mem/cache.h>
Target create_native_target() { Target create_native_target() {
DEBUG("creating native target..."); DEBUG("creating native target...");
@ -54,7 +55,11 @@ static char* create_target_output_name(const TargetConfig* config) {
prefix = "lib"; 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) { Target create_target_from_config(const TargetConfig* config) {

View File

@ -6,6 +6,7 @@
#include <sys/log.h> #include <sys/log.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <sys/col.h> #include <sys/col.h>
#include <link/lib.h>
const char* get_absolute_link_path(const TargetConfig* config, const char* link_target_name) { 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); 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++) { 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); 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* path = g_build_filename(link_directory_path, link_target_name, NULL);
char* cwd = g_get_current_dir(); char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd); 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 exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR); const gboolean is_dir = g_file_test(canonical, G_FILE_TEST_IS_DIR);
g_free(path); g_free(path);
g_free(cwd); g_free(cwd);
g_free(canonical);
if (exists && !is_dir) { if (exists && !is_dir) {
INFO("link target found at: %s", canonical); INFO("link target found at: %s", cached_canonical);
return canonical; return cached_canonical;
} }
g_free(canonical);
} }
// file not found // file not found
@ -41,47 +44,54 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig)); TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig));
config->fatal_warnings = target_config->lld_fatal_warnings; 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->colorize = stdout_supports_ansi_esc();
config->driver = target_config->driver;
// append build object file // append build object file
char* basename = g_strjoin(".", target_config->name, "o", NULL); char* basename = g_strjoin(".", target_config->name, "o", NULL);
char* filename = g_build_filename(target_config->archive_directory, basename, 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); const char* target_object = get_absolute_link_path(target_config, (const char*) filename);
if (target_object == NULL) { if (target_object == NULL) {
ERROR("failed to resolve path to target object: %s", filename); ERROR("failed to resolve path to target object: %s", filename);
g_free(filename);
lld_delete_link_config(config); lld_delete_link_config(config);
g_free(filename);
return NULL; return NULL;
} }
g_free(filename);
{ {
// output file after linking // output file after linking
basename = g_strjoin(".", target_config->name, "out", NULL); basename = g_strjoin(".", target_config->name, "out", NULL);
filename = g_build_filename(target_config->output_directory, basename, 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); g_array_append_val(config->object_file_names, target_object);
INFO("resolved path of target object: %s", 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 // resolve absolute paths to dependent library object files
DEBUG("resolving target dependencies..."); DEBUG("resolving target dependencies...");
for (guint i = 0; i < module->imports->len; i++) { for (guint i = 0; i < module->imports->len; i++) {
const char* dependency = g_array_index(module->imports, const char*, 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) { 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); lld_delete_link_config(config);
g_free((void*) library);
return NULL; return NULL;
} }
g_free((void*) library);
g_array_append_val(config->object_file_names, dependency_object); g_array_append_val(config->object_file_names, dependency_object);
INFO("resolved path of target object: %s", 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; 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) { 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..."); return new_backend_impl_error(Implementation, NULL, "linking failed");
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;
} }
void lld_delete_link_config(TargetLinkConfig* config) { void lld_delete_link_config(TargetLinkConfig* config) {
for (guint i = 0; i < config->object_file_names->len; i++) { mem_free(config->object_file_names);
free((void*) g_array_index(config->object_file_names, const char*, i));
}
g_array_free(config->object_file_names, TRUE);
mem_free(config); mem_free(config);
} }

View File

@ -387,6 +387,49 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
return SUCCESS; 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, BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, AddressOf* addressOf, LLVMBuilderRef builder, AddressOf* addressOf,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
@ -405,7 +448,12 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMValueRef *llvm_result) { LLVMValueRef *llvm_result) {
BackendError err; 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; LLVMTypeRef llvm_deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type); err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type);
if (err.kind != Success) { if (err.kind != Success) {
@ -454,6 +502,11 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
reference, reference,
llvm_result); llvm_result);
break; break;
case ExpressionKindParameter:
err = impl_parameter_load(unit, scope, builder, expr->impl.parameter,
reference,
llvm_result);
break;
case ExpressionKindAddressOf: case ExpressionKindAddressOf:
err = impl_address_of(unit, scope, builder, &expr->impl.addressOf, err = impl_address_of(unit, scope, builder, &expr->impl.addressOf,
llvm_result); llvm_result);

View File

@ -26,7 +26,7 @@ void delete_local_scope(LLVMLocalScope* scope) {
free(scope); free(scope);
} }
static LLVMValueRef get_parameter(const LLVMFuncScope* scope, LLVMValueRef get_parameter(const LLVMFuncScope* scope,
const char* name) { const char* name) {
if (g_hash_table_contains(scope->params, name)) { if (g_hash_table_contains(scope->params, name)) {
return g_hash_table_lookup(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); 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); LLVMValueRef global_var = get_global_variable(scope->func_scope->global_scope, (char*) name);
return global_var; return global_var;
} }
@ -108,7 +103,7 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
DEBUG("implementing function declaration: %s()", func->name); DEBUG("implementing function declaration: %s()", func->name);
BackendError err = SUCCESS; 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; GArray* func_params = NULL;
if (func->kind == FunctionDeclarationKind) { 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_hash_table_insert(scope->functions, (char*) func->name, llvm_fun_type);
g_array_free(llvm_params, FALSE);
return err; return err;
} }

View File

@ -28,6 +28,8 @@ void delete_local_scope(LLVMLocalScope*);
LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name); 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); LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name);
BackendError impl_function_types(LLVMBackendCompileUnit* unit, BackendError impl_function_types(LLVMBackendCompileUnit* unit,

View File

@ -12,6 +12,27 @@
#include <assert.h> #include <assert.h>
#include <mem/cache.h> #include <mem/cache.h>
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( BackendError impl_storage_expr(
LLVMBackendCompileUnit *unit, LLVMBackendCompileUnit *unit,
LLVMBuilderRef LLVMBuilderRef
@ -27,6 +48,10 @@ BackendError impl_storage_expr(
*storage_target = *storage_target =
get_variable(scope, expr->impl.variable->name); get_variable(scope, expr->impl.variable->name);
break; break;
case StorageExprKindParameter:
*storage_target =
get_parameter(scope->func_scope, expr->impl.parameter->name);
break;
case StorageExprKindDereference: case StorageExprKindDereference:
LLVMValueRef index = NULL; LLVMValueRef index = NULL;
@ -41,16 +66,29 @@ BackendError impl_storage_expr(
return err; 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; LLVMTypeRef deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->target_type, &deref_type); err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->target_type, &deref_type);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
if (expr->target_type->kind == TypeKindReference) {
array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load"); 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;
}
*storage_target = LLVMBuildGEP2(builder, deref_type, array, &index, 1, "strg.deref"); *storage_target = LLVMBuildGEP2(builder, deref_type, array, &index, 1, "strg.deref");
break; break;
@ -73,7 +111,7 @@ BackendError impl_assign_stmt(
DEBUG("implementing assignment for variable: %p", assignment); DEBUG("implementing assignment for variable: %p", assignment);
LLVMValueRef llvm_value = NULL; 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) { if (err.kind != Success) {
return err; return err;
} }
@ -206,19 +244,24 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
param_list = call->function->impl.declaration.parameter; param_list = call->function->impl.declaration.parameter;
} }
LLVMBool reference = FALSE; Parameter param = g_array_index(param_list, Parameter, i);
Parameter parameter = g_array_index(param_list, Parameter, i);
if (is_parameter_out(&parameter)) {
reference = TRUE;
}
LLVMValueRef llvm_arg = NULL; LLVMValueRef llvm_arg = NULL;
err = impl_expr(unit, scope, builder, arg, reference, &llvm_arg); err = impl_expr(unit, scope, builder, arg, is_parameter_out(&param), &llvm_arg);
if (err.kind != Success) { if (err.kind != Success) {
break; break;
} }
if (is_parameter_out(&param)) {
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; arguments[i] = llvm_arg;
} }

View File

@ -321,7 +321,7 @@ BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
gpointer key = NULL; gpointer key = NULL;
gpointer val = NULL; gpointer val = NULL;
BackendError err; BackendError err = SUCCESS;
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) { while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
err = impl_type_define(unit, (Typedefine*) val, (const char*)key, scope); err = impl_type_define(unit, (Typedefine*) val, (const char*)key, scope);

View File

@ -90,10 +90,11 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
ERROR("failed to emit code: %s", error); ERROR("failed to emit code: %s", error);
err = err =
new_backend_impl_error(Implementation, NULL, "failed to emit code"); new_backend_impl_error(Implementation, NULL, "failed to emit code");
LLVMDisposeMessage(error);
} else { } else {
print_message(Info, "Generated code was written to: %s", filename); print_message(Info, "Generated code was written to: %s", filename);
} }
LLVMDisposeMessage(error);
g_free((void*) filename); g_free((void*) filename);
g_free((void*) basename); g_free((void*) basename);
@ -124,9 +125,9 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
ERROR("failed to create target machine: %s", error); ERROR("failed to create target machine: %s", error);
err = new_backend_impl_error(Implementation, NULL, err = new_backend_impl_error(Implementation, NULL,
"unable to create target machine"); "unable to create target machine");
LLVMDisposeMessage(error);
return err; return err;
} }
LLVMDisposeMessage(error);
DEBUG("Creating target machine..."); DEBUG("Creating target machine...");
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine( 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, err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error,
config); config);
LLVMDisposeTargetMachine(target_machine);
return err; return err;
} }
@ -223,9 +226,9 @@ static BackendError build_module(LLVMBackendCompileUnit* unit,
char* error = NULL; char* error = NULL;
if (LLVMVerifyModule(unit->module, LLVMReturnStatusAction, &error)) { if (LLVMVerifyModule(unit->module, LLVMReturnStatusAction, &error)) {
print_message(Error, "Unable to compile due to: %s", 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"); err = new_backend_impl_error(Implementation, NULL, "LLVM backend verification error, see stdout");
} }
LLVMDisposeMessage(error);
return err; return err;
} }
@ -259,9 +262,13 @@ BackendError parse_module(const Module* module, const TargetConfig* config) {
if (config->mode == Application) { if (config->mode == Application) {
TargetLinkConfig* link_config = lld_create_link_config(&target, config, module); 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");
}
} }
} }

View File

@ -7,6 +7,7 @@
#include <compiler.h> #include <compiler.h>
#include <llvm/parser.h> #include <llvm/parser.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <link/lib.h>
/** /**
* @brief Log a debug message to inform about beginning exit procedures * @brief Log a debug message to inform about beginning exit procedures
@ -38,6 +39,10 @@ void setup(int argc, char *argv[]) {
lex_init(); lex_init();
link_init();
init_toml();
DEBUG("finished starting up gemstone..."); DEBUG("finished starting up gemstone...");
} }
@ -64,6 +69,11 @@ int main(int argc, char *argv[]) {
exit(0); exit(0);
} }
if (is_option_set("list-driver")) {
link_print_available_driver();
exit(0);
}
run_compiler(); run_compiler();
if (is_option_set("print-gc-stats")) { if (is_option_set("print-gc-stats")) {

View File

@ -15,6 +15,7 @@ typedef char* MemoryNamespaceName;
#define MemoryNamespaceLex "Lexer" #define MemoryNamespaceLex "Lexer"
#define MemoryNamespaceLog "Logging" #define MemoryNamespaceLog "Logging"
#define MemoryNamespaceOpt "Options" #define MemoryNamespaceOpt "Options"
#define MemoryNamespaceTOML "TOML"
#define MemoryNamespaceSet "SET" #define MemoryNamespaceSet "SET"
#define MemoryNamespaceLlvm "LLVM" #define MemoryNamespaceLlvm "LLVM"
#define MemoryNamespaceLld "LLD" #define MemoryNamespaceLld "LLD"

View File

@ -1,7 +1,6 @@
#include <io/files.h> #include <io/files.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <set/types.h> #include <set/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/log.h> #include <sys/log.h>
#include <glib.h> #include <glib.h>
@ -335,8 +334,8 @@ int createRef(AST_NODE_PTR currentNode, Type **reftype) {
assert(currentNode->children->len == 1); assert(currentNode->children->len == 1);
assert(AST_get_node(currentNode, 0)->kind == AST_Type); assert(AST_get_node(currentNode, 0)->kind == AST_Type);
Type *type = malloc(sizeof(Type)); Type *type = mem_alloc(MemoryNamespaceSet, sizeof(Type));
Type *referenceType = malloc(sizeof(Type)); Type *referenceType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
referenceType->kind = TypeKindReference; referenceType->kind = TypeKindReference;
referenceType->nodePtr = currentNode; referenceType->nodePtr = currentNode;
@ -511,18 +510,21 @@ char* type_to_string(Type* type) {
if (type->impl.composite.scale < 1.0) { if (type->impl.composite.scale < 1.0) {
for (int i = 0; i < (int) (type->impl.composite.scale * 4); i++) { for (int i = 0; i < (int) (type->impl.composite.scale * 4); i++) {
char *concat = g_strconcat("half ", string, NULL); char *concat = g_strconcat("half ", string, NULL);
string = concat; string = mem_strdup(MemoryNamespaceSet, concat);
g_free(concat);
} }
} else if (type->impl.composite.scale > 1.0) { } else if (type->impl.composite.scale > 1.0) {
for (int i = 0; i < (int) type->impl.composite.scale; i++) { for (int i = 0; i < (int) type->impl.composite.scale; i++) {
char *concat = g_strconcat("long ", string, NULL); char *concat = g_strconcat("long ", string, NULL);
string = concat; string = mem_strdup(MemoryNamespaceSet, concat);
g_free(concat);
} }
} }
if (type->impl.composite.sign == Unsigned) { if (type->impl.composite.sign == Unsigned) {
char *concat = g_strconcat("unsigned ", string, NULL); char *concat = g_strconcat("unsigned ", string, NULL);
string = concat; string = mem_strdup(MemoryNamespaceSet, concat);
g_free(concat);
} }
break; break;
@ -530,7 +532,9 @@ char* type_to_string(Type* type) {
case TypeKindReference: { case TypeKindReference: {
char *type_string = type_to_string(type->impl.reference); char *type_string = type_to_string(type->impl.reference);
char *concat = g_strconcat("ref ", type_string, NULL); char *concat = g_strconcat("ref ", type_string, NULL);
string = concat; mem_free(type_string);
string = mem_strdup(MemoryNamespaceSet, concat);
g_free(concat);
break; break;
} }
case TypeKindBox: case TypeKindBox:
@ -541,6 +545,18 @@ char* type_to_string(Type* type) {
return string; 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) { int getVariableFromScope(const char *name, Variable **variable) {
assert(name != NULL); assert(name != NULL);
assert(variable != NULL); assert(variable != NULL);
@ -548,13 +564,6 @@ int getVariableFromScope(const char *name, Variable **variable) {
DEBUG("getting var from scope"); DEBUG("getting var from scope");
int found = 0; 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++) { for (size_t i = 0; i < Scope->len; i++) {
GHashTable *variable_table = g_array_index(Scope, GHashTable*, 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")]] [[nodiscard("type must be freed")]]
TypeValue createTypeValue(AST_NODE_PTR currentNode) { TypeValue createTypeValue(AST_NODE_PTR currentNode) {
DEBUG("create TypeValue"); DEBUG("create TypeValue");
TypeValue value; TypeValue value;
@ -726,7 +736,7 @@ int createArithOperation(Expression *ParentExpression, AST_NODE_PTR currentNode,
DEBUG("create arithmetic operation"); DEBUG("create arithmetic operation");
ParentExpression->impl.operation.kind = Arithmetic; ParentExpression->impl.operation.kind = Arithmetic;
ParentExpression->impl.operation.nodePtr = currentNode; 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); assert(expectedChildCount == currentNode->children->len);
@ -804,7 +814,7 @@ int createRelationalOperation(Expression *ParentExpression, AST_NODE_PTR current
// fill kind and Nodeptr // fill kind and Nodeptr
ParentExpression->impl.operation.kind = Relational; ParentExpression->impl.operation.kind = Relational;
ParentExpression->impl.operation.nodePtr = currentNode; 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 // fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) { 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 // fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode; 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 // fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) { 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 //fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode; 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 //fill Operand
Expression *expression = createExpression(AST_get_node(currentNode, 0)); Expression *expression = createExpression(AST_get_node(currentNode, 0));
@ -1015,7 +1025,7 @@ int createBitOperation(Expression *ParentExpression, AST_NODE_PTR currentNode) {
// fill kind and Nodeptr // fill kind and Nodeptr
ParentExpression->impl.operation.kind = Boolean; ParentExpression->impl.operation.kind = Boolean;
ParentExpression->impl.operation.nodePtr = currentNode; 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 // fill Operands
for (size_t i = 0; i < currentNode->children->len; i++) { 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 //fill kind and Nodeptr
ParentExpression->impl.operation.kind = Bitwise; ParentExpression->impl.operation.kind = Bitwise;
ParentExpression->impl.operation.nodePtr = currentNode; 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 //fill Operand
Expression *expression = createExpression(AST_get_node(currentNode, 0)); Expression *expression = createExpression(AST_get_node(currentNode, 0));
@ -1425,7 +1435,7 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
Type *resultType = malloc(sizeof(Type)); Type *resultType = mem_alloc(MemoryNamespaceSet, sizeof(Type));
resultType->nodePtr = currentNode; resultType->nodePtr = currentNode;
resultType->kind = TypeKindReference; resultType->kind = TypeKindReference;
resultType->impl.reference = address_of.variable->result; resultType->impl.reference = address_of.variable->result;
@ -1435,6 +1445,14 @@ int createAddressOf(Expression *ParentExpression, AST_NODE_PTR currentNode) {
return SEMANTIC_OK; 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) { Expression *createExpression(AST_NODE_PTR currentNode) {
DEBUG("create Expression"); DEBUG("create Expression");
Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression)); Expression *expression = mem_alloc(MemoryNamespaceSet, sizeof(Expression));
@ -1455,23 +1473,33 @@ Expression *createExpression(AST_NODE_PTR currentNode) {
case AST_Ident: case AST_Ident:
DEBUG("find var"); DEBUG("find var");
expression->kind = ExpressionKindVariable; expression->kind = ExpressionKindVariable;
int status = getVariableFromScope(currentNode->value, &(expression->impl.variable)); int status = getVariableFromScope(currentNode->value, &expression->impl.variable);
if (status == SEMANTIC_ERROR) {
expression->kind = ExpressionKindParameter;
status = getParameter(currentNode->value, &expression->impl.parameter);
if (status == SEMANTIC_ERROR) { if (status == SEMANTIC_ERROR) {
DEBUG("Identifier is not in current scope"); DEBUG("Identifier is not in current scope");
print_diagnostic(&currentNode->location, Error, "Variable not found"); print_diagnostic(&currentNode->location, Error, "Unknown identifier: `%s`", currentNode->value);
return NULL; return NULL;
} }
switch (expression->impl.variable->kind) {
case VariableKindDeclaration: if (getParameterQualifier(expression->impl.parameter) == Out) {
print_diagnostic(&currentNode->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; expression->result = expression->impl.variable->impl.declaration.type;
DEBUG("%d", expression->impl.variable->impl.declaration.type->kind); } else {
break;
case VariableKindDefinition:
expression->result = expression->impl.variable->impl.definiton.declaration.type; expression->result = expression->impl.variable->impl.definiton.declaration.type;
break; }
default:
PANIC("current Variable should not be an BoxMember");
break;
} }
break; break;
case AST_Add: case AST_Add:
@ -1611,15 +1639,33 @@ Type* getVariableType(Variable* variable) {
} }
} }
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) { int createStorageExpr(StorageExpr *expr, AST_NODE_PTR node) {
switch (node->kind) { switch (node->kind) {
case AST_Ident: case AST_Ident:
expr->kind = StorageExprKindVariable; expr->kind = StorageExprKindVariable;
int status = getVariableFromScope(node->value, &expr->impl.variable); int status = getVariableFromScope(node->value, &expr->impl.variable);
if (status == SEMANTIC_ERROR) { if (status == 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; 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; break;
case AST_Dereference: case AST_Dereference:
expr->kind = StorageExprKindDereference; expr->kind = StorageExprKindDereference;
@ -1656,17 +1702,31 @@ int createAssign(Statement *ParentStatement, AST_NODE_PTR currentNode) {
assign.nodePtr = currentNode; assign.nodePtr = currentNode;
assign.destination = mem_alloc(MemoryNamespaceSet, sizeof(StorageExpr)); 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) { if (status == SEMANTIC_ERROR) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
if (strg_expr->kind == AST_Parameter) {
if (getParameterQualifier(assign.destination->impl.parameter) == In) {
print_diagnostic(&currentNode->location, Error, "Parameter is read-only: `%s`",
assign.destination->impl.parameter->name);
return SEMANTIC_ERROR;
}
}
assign.value = createExpression(AST_get_node(currentNode, 1)); assign.value = createExpression(AST_get_node(currentNode, 1));
if (assign.value == NULL) { if (assign.value == NULL) {
return SEMANTIC_ERROR; 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; ParentStatement->impl.assignment = assign;
return SEMANTIC_OK; return SEMANTIC_OK;
@ -1677,18 +1737,19 @@ int createStatement(Block *block, AST_NODE_PTR currentNode);
int fillBlock(Block *block, AST_NODE_PTR currentNode) { int fillBlock(Block *block, AST_NODE_PTR currentNode) {
DEBUG("start filling Block"); DEBUG("start filling Block");
block->nodePtr = currentNode; block->nodePtr = currentNode;
block->statemnts = g_array_new(FALSE, FALSE, sizeof(Statement *)); block->statemnts = mem_new_g_array(MemoryNamespaceSet, sizeof(Statement *));
GHashTable *lowerScope = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *lowerScope = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
g_array_append_val(Scope, lowerScope); g_array_append_val(Scope, lowerScope);
for (size_t i = 0; i < currentNode->children->len; i++) { 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) { if (signal) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
} }
g_hash_table_destroy(lowerScope); mem_free(lowerScope);
g_array_remove_index(Scope, Scope->len - 1); g_array_remove_index(Scope, Scope->len - 1);
DEBUG("created Block successfully"); DEBUG("created Block successfully");
@ -1889,7 +1950,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
switch (currentNode->kind) { switch (currentNode->kind) {
case AST_Decl: { 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); int status = createDecl(currentNode, &variable);
if (status) { if (status) {
@ -1908,7 +1969,7 @@ int createStatement(Block *Parentblock, AST_NODE_PTR currentNode) {
break; break;
case AST_Def: { 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)) { if (createDef(currentNode, &variable)) {
return SEMANTIC_ERROR; 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))) { if (set_get_type_impl(AST_get_node(paramdecl, 0), &(decl.type))) {
return SEMANTIC_ERROR; return SEMANTIC_ERROR;
} }
Parameter param; Parameter *param = mem_alloc(MemoryNamespaceSet, sizeof(Parameter));
param.nodePtr = currentNode; param->nodePtr = currentNode;
param.kind = ParameterDeclarationKind; param->kind = ParameterDeclarationKind;
param.impl.declaration = decl; param->impl.declaration = decl;
param.name = AST_get_node(paramdecl, 1)->value; param->name = AST_get_node(paramdecl, 1)->value;
DEBUG("param name: %s", param.name); DEBUG("param name: %s", param->name);
g_array_append_val(Paramlist, param); g_array_append_val(Paramlist, *param);
DEBUG("create var for param"); if (g_hash_table_contains(functionParameter, param->name)) {
print_diagnostic(&param->nodePtr->location, Error, "Names of function parameters must be unique: %s",
Variable *paramvar = mem_alloc(MemoryNamespaceSet, sizeof(Variable)); param->name);
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(&param.nodePtr->location, Error, "Names of function parameters must be unique: %s", param.name);
return SEMANTIC_ERROR; 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"); DEBUG("created param successfully");
return SEMANTIC_OK; return SEMANTIC_OK;
@ -2043,7 +2095,7 @@ int createFunDef(Function *Parentfunction, AST_NODE_PTR currentNode) {
fundef.nodePtr = currentNode; fundef.nodePtr = currentNode;
fundef.name = nameNode->value; fundef.name = nameNode->value;
fundef.body = mem_alloc(MemoryNamespaceSet, sizeof(Block)); 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); DEBUG("paramlistlist child count: %i", paramlistlist->children->len);
for (size_t i = 0; i < paramlistlist->children->len; i++) { 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) { int addFunction(const char *name, Function *function) {
if (function->kind == FunctionDefinitionKind) { if (function->kind == FunctionDefinitionKind) {
if (g_hash_table_contains(definedFunctions, name)) { 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; return SEMANTIC_ERROR;
} }
g_hash_table_insert(declaredFunctions, (gpointer) name, function); g_hash_table_insert(declaredFunctions, (gpointer) name, function);
@ -2117,7 +2170,8 @@ int addFunction(const char *name, Function *function) {
function->impl.declaration.parameter); function->impl.declaration.parameter);
// a function can have multiple declartations but all have to be identical // a function can have multiple declartations but all have to be identical
if (result == FALSE) { 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; return SEMANTIC_ERROR;
} }
} }
@ -2175,7 +2229,7 @@ int createFunDecl(Function *Parentfunction, AST_NODE_PTR currentNode) {
int createFunction(Function *function, AST_NODE_PTR currentNode) { int createFunction(Function *function, AST_NODE_PTR currentNode) {
assert(currentNode->kind == AST_Fun); 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) { if (currentNode->children->len == 2) {
int signal = createFunDecl(function, currentNode); 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"); PANIC("function should have 2 or 3 children");
} }
g_hash_table_destroy(functionParameter); mem_free(functionParameter);
functionParameter = NULL; functionParameter = NULL;
int result = addFunction(function->name, function); 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) { Module *create_set(AST_NODE_PTR currentNode) {
DEBUG("create root Module"); DEBUG("create root Module");
//create tables for types //create tables for types
declaredComposites = g_hash_table_new(g_str_hash, g_str_equal); declaredComposites = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
declaredBoxes = g_hash_table_new(g_str_hash, g_str_equal); declaredBoxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
declaredFunctions = g_hash_table_new(g_str_hash, g_str_equal); declaredFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
definedFunctions = g_hash_table_new(g_str_hash, g_str_equal); definedFunctions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
//create scope //create scope
Scope = g_array_new(FALSE, FALSE, sizeof(GHashTable *)); Scope = mem_new_g_array(MemoryNamespaceSet, sizeof(GHashTable *));
//building current scope for module //building current scope for module
GHashTable *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 = g_hash_table_new(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); g_array_append_val(Scope, globalscope);
Module *rootModule = mem_alloc(MemoryNamespaceSet, sizeof(Module)); Module *rootModule = mem_alloc(MemoryNamespaceSet, sizeof(Module));
GHashTable *boxes = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *boxes = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
GHashTable *types = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *types = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
GHashTable *functions = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *functions = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
GHashTable *variables = g_hash_table_new(g_str_hash, g_str_equal); GHashTable *variables = mem_new_g_hash_table(MemoryNamespaceSet, g_str_hash, g_str_equal);
GArray *imports = g_array_new(FALSE, FALSE, sizeof(const char *)); GArray *imports = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *));
GArray *includes = mem_new_g_array(MemoryNamespaceSet, sizeof(const char *));
rootModule->boxes = boxes; rootModule->boxes = boxes;
rootModule->types = types; rootModule->types = types;
rootModule->functions = functions; rootModule->functions = functions;
rootModule->variables = variables; rootModule->variables = variables;
rootModule->imports = imports; rootModule->imports = imports;
rootModule->includes = includes;
DEBUG("created Module struct"); DEBUG("created Module struct");
@ -2456,6 +2512,10 @@ Module *create_set(AST_NODE_PTR currentNode) {
DEBUG("create Import"); DEBUG("create Import");
g_array_append_val(imports, AST_get_node(currentNode, i)->value); g_array_append_val(imports, AST_get_node(currentNode, i)->value);
break; break;
case AST_Include:
DEBUG("create Include");
g_array_append_val(includes, AST_get_node(currentNode, i)->value);
break;
default: default:
INFO("Provided source file could not be parsed because of semantic error."); INFO("Provided source file could not be parsed because of semantic error.");
break; break;

View File

@ -432,6 +432,7 @@ typedef enum ExpressionKind_t {
ExpressionKindTransmute, ExpressionKindTransmute,
ExpressionKindConstant, ExpressionKindConstant,
ExpressionKindVariable, ExpressionKindVariable,
ExpressionKindParameter,
ExpressionKindDereference, ExpressionKindDereference,
ExpressionKindAddressOf, ExpressionKindAddressOf,
} ExpressionKind; } ExpressionKind;
@ -446,6 +447,7 @@ typedef struct Expression_t {
Transmute transmute; Transmute transmute;
TypeValue constant; TypeValue constant;
Variable* variable; Variable* variable;
Parameter* parameter;
Dereference dereference; Dereference dereference;
AddressOf addressOf; AddressOf addressOf;
} impl; } impl;
@ -526,6 +528,7 @@ typedef struct Branch_t {
typedef enum StorageExprKind_t { typedef enum StorageExprKind_t {
StorageExprKindVariable, StorageExprKindVariable,
StorageExprKindParameter,
StorageExprKindBoxAccess, StorageExprKindBoxAccess,
StorageExprKindDereference, StorageExprKindDereference,
} StorageExprKind; } StorageExprKind;
@ -535,6 +538,7 @@ typedef struct StorageExpr_t {
Type* target_type; Type* target_type;
union StorageExprImpl { union StorageExprImpl {
Variable* variable; Variable* variable;
Parameter* parameter;
BoxAccess boxAccess; BoxAccess boxAccess;
StorageDereference dereference; StorageDereference dereference;
} impl; } impl;
@ -580,6 +584,7 @@ typedef struct Module_t {
GHashTable* variables; GHashTable* variables;
// to be resolved after the module has been parsed completely // to be resolved after the module has been parsed completely
GArray* imports; GArray* imports;
GArray* includes;
} Module; } Module;

View File

@ -53,6 +53,7 @@
%type <node_ptr> opbool %type <node_ptr> opbool
%type <node_ptr> opbit %type <node_ptr> opbit
%type <node_ptr> moduleimport %type <node_ptr> moduleimport
%type <node_ptr> moduleinclude
%type <node_ptr> programbody %type <node_ptr> programbody
%type <node_ptr> fundef %type <node_ptr> fundef
%type <node_ptr> fundecl %type <node_ptr> fundecl
@ -109,6 +110,7 @@
%token OpBitnot %token OpBitnot
%token OpBitxor %token OpBitxor
%token KeyImport %token KeyImport
%token KeyInclude
%token KeySilent %token KeySilent
%token KeyBox %token KeyBox
%token FunTypeof %token FunTypeof
@ -142,6 +144,7 @@ program: program programbody {AST_push_node(root, $2);
| programbody {AST_push_node(root, $1);}; | programbody {AST_push_node(root, $1);};
programbody: moduleimport {$$ = $1;} programbody: moduleimport {$$ = $1;}
| moduleinclude {$$ = $1;}
| fundef{$$ = $1;} | fundef{$$ = $1;}
| fundecl{$$ = $1;} | fundecl{$$ = $1;}
| box{$$ = $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); moduleimport: KeyImport ValStr {$$ = AST_new_node(new_loc(), AST_Import, $2);
DEBUG("Module-Import"); }; 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); statementlist: statementlist statement {AST_push_node($1, $2);
$$ = $1;} $$ = $1;}
| statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL); | statement {AST_NODE_PTR list = AST_new_node(new_loc(), AST_StmtList, NULL);

View File

@ -13,3 +13,5 @@ add_subdirectory(glib)
add_subdirectory(llvm) add_subdirectory(llvm)
add_subdirectory(project) add_subdirectory(project)
add_subdirectory(cache) add_subdirectory(cache)
add_subdirectory(hello_world)
add_subdirectory(driver)

View File

@ -84,6 +84,7 @@ def run_check_print_node():
53 address of 53 address of
54 deref 54 deref
55 ref 55 ref
56 value
""" == p.stdout """ == p.stdout

View File

@ -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)

View File

@ -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 <sven.vogel123@web.de>" ]
[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

View File

@ -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)
}

View File

@ -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()

View File

@ -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 <sven.vogel123@web.de>" ]
[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

28
tests/driver/gcc/main.gsc Normal file
View File

@ -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)
}

View File

@ -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()

View File

@ -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)

View File

@ -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 <sven.vogel123@web.de>" ]
[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

View File

@ -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)
}

View File

@ -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()

View File

@ -6,4 +6,4 @@ include(CTest)
add_test(NAME input_file_check add_test(NAME input_file_check
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/bin/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)

View File

@ -1,6 +0,0 @@
import "std.io"
fun main {
print("Hello, World!!!")
}

View File

@ -0,0 +1,4 @@
fun main(out int: ret) {
ret = 56 as int
}