Merge pull request #128 from Servostar/124-compile-exectuable-with-clang
124 compile exectuable with clang
This commit is contained in:
commit
20b6d269d8
|
@ -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
106
README.md
|
@ -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
|
||||||
|
|
|
@ -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})
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
139
src/cfg/opt.c
139
src/cfg/opt.c
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(¶meter)) {
|
|
||||||
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(¶m), &llvm_arg);
|
||||||
|
|
||||||
if (err.kind != Success) {
|
if (err.kind != Success) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_parameter_out(¶m)) {
|
||||||
|
if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) {
|
||||||
|
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false);
|
||||||
|
LLVMTypeRef llvm_type = NULL;
|
||||||
|
get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type);
|
||||||
|
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
arguments[i] = llvm_arg;
|
arguments[i] = llvm_arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
src/main.c
10
src/main.c
|
@ -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")) {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
214
src/set/set.c
214
src/set/set.c
|
@ -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(¤tNode->location, Error, "Variable not found");
|
print_diagnostic(¤tNode->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(¤tNode->location, Error, "Parameter is write-only: `%s`",
|
||||||
|
currentNode->value);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression->impl.parameter->kind == ParameterDeclarationKind) {
|
||||||
|
expression->result = expression->impl.parameter->impl.declaration.type;
|
||||||
|
} else {
|
||||||
|
expression->result = expression->impl.parameter->impl.definiton.declaration.type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (expression->impl.variable->kind == VariableKindDeclaration) {
|
||||||
expression->result = expression->impl.variable->impl.declaration.type;
|
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(¤tNode->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(¶m->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(¶m.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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
||||||
|
}
|
|
@ -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()
|
|
@ -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
|
|
@ -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)
|
||||||
|
}
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
|
@ -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)
|
||||||
|
}
|
|
@ -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()
|
|
@ -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)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
import "std.io"
|
|
||||||
|
|
||||||
fun main {
|
|
||||||
print("Hello, World!!!")
|
|
||||||
}
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
fun main(out int: ret) {
|
||||||
|
ret = 56 as int
|
||||||
|
}
|
Loading…
Reference in New Issue