formatted source with clangd

This commit is contained in:
Sven Vogel 2024-08-05 22:47:12 +02:00
parent ed728c8042
commit e1649657fd
45 changed files with 2431 additions and 1936 deletions

View File

@ -1,3 +1,45 @@
BasedOnStyle: Google
IndentWidth: 4 IndentWidth: 4
PointerAlignment: Left PointerAlignment: Left
BreakAfterAttributes: Always
BreakStringLiterals: true
SpaceAfterCStyleCast: true
SortIncludes: CaseSensitive
UseTab: Never
ReflowComments: false
EmptyLineAfterAccessModifier: Never
TabWidth: 4
SpaceAroundPointerQualifiers: Default
InsertNewlineAtEOF: true
InsertBraces: true
IndentCaseLabels: true
IncludeBlocks: Regroup
ContinuationIndentWidth: 2
ColumnLimit: 80
BreakBeforeBraces: Attach
BinPackParameters: true
BinPackArguments: true
AllowAllArgumentsOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AlignOperands: Align
BreakBeforeBinaryOperators: NonAssignment
AlignConsecutiveMacros: Consecutive
AlignEscapedNewlines: Left
AlignConsecutiveDeclarations: false
AlignConsecutiveAssignments: Consecutive
IndentCaseBlocks: true
AlignArrayOfStructures: Left
AlignAfterOpenBracket: Align
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortLoopsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AlwaysBreakAfterReturnType: None
BracedInitializerIndentWidth: 4
BreakConstructorInitializers: AfterColon
DerivePointerAlignment: false
IndentWrappedFunctionNames: true
Language: Cpp
SpaceAfterLogicalNot: false
LineEnding: LF

19
run-clang-format.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
# Define the target directory
directory="./src"
# Check if the target is not a directory
if [ ! -d "$directory" ]; then
echo "Error: $directory is not a valid directory"
exit 1
fi
# Use find to iterate over all files in the directory and subdirectories
find "$directory" -type f | while read -r file; do
if [[ "${file##*/}" =~ ^[a-z_]+\.c|h$ ]]; then
echo "Formatting file: $file..."
clang-format -i "$file"
fi
done

View File

@ -1,15 +1,18 @@
#include <assert.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <mem/cache.h>
#include <stdio.h> #include <stdio.h>
#include <sys/log.h> #include <sys/log.h>
#include <assert.h>
#include <mem/cache.h>
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) { struct AST_Node_t* AST_new_node(TokenLocation location,
enum AST_SyntaxElement_t kind,
const char* value) {
DEBUG("creating new AST node: %d \"%s\"", kind, value); DEBUG("creating new AST node: %d \"%s\"", kind, value);
assert(kind < AST_ELEMENT_COUNT); assert(kind < AST_ELEMENT_COUNT);
struct AST_Node_t *node = mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t)); struct AST_Node_t* node =
mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t));
if (node == NULL) { if (node == NULL) {
PANIC("failed to allocate AST node"); PANIC("failed to allocate AST node");
@ -140,11 +143,15 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
PANIC("failed to allocate children array of AST node"); PANIC("failed to allocate children array of AST node");
} }
owner->location.col_end = max(owner->location.col_end, child->location.col_end); owner->location.col_end =
owner->location.line_end = max(owner->location.line_end, child->location.line_end); max(owner->location.col_end, child->location.col_end);
owner->location.line_end =
max(owner->location.line_end, child->location.line_end);
owner->location.col_start = min(owner->location.col_start, child->location.col_start); owner->location.col_start =
owner->location.line_start = min(owner->location.line_start, child->location.line_start); min(owner->location.col_start, child->location.col_start);
owner->location.line_start =
min(owner->location.line_start, child->location.line_start);
if (owner->location.file == NULL) { if (owner->location.file == NULL) {
owner->location.file = child->location.file; owner->location.file = child->location.file;
@ -174,7 +181,8 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
return child; return child;
} }
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) { struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner,
const size_t idx) {
assert(owner != NULL); assert(owner != NULL);
assert(owner->children != NULL); assert(owner->children != NULL);
assert(idx < owner->children->len); assert(idx < owner->children->len);
@ -187,7 +195,8 @@ struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx)
return child; return child;
} }
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) { struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner,
const struct AST_Node_t* child) {
assert(owner != NULL); assert(owner != NULL);
assert(child != NULL); assert(child != NULL);
assert(owner->children != NULL); assert(owner->children != NULL);
@ -207,8 +216,8 @@ void AST_delete_node(struct AST_Node_t *node) {
DEBUG("Deleting AST node: %p", node); DEBUG("Deleting AST node: %p", node);
if (node->parent != NULL) { if (node->parent != NULL) {
[[maybe_unused]] [[maybe_unused]] const struct AST_Node_t* child =
const struct AST_Node_t* child = AST_detach_child(node->parent, node); AST_detach_child(node->parent, node);
assert(child == node); assert(child == node);
} }
@ -235,7 +244,8 @@ static void AST_visit_nodes_recurse2(struct AST_Node_t *root,
(for_each)(root, depth); (for_each)(root, depth);
for (size_t i = 0; i < root->children->len; i++) { for (size_t i = 0; i < root->children->len; i++) {
AST_visit_nodes_recurse2(g_array_index(root->children, AST_NODE_PTR, i), for_each, depth + 1); AST_visit_nodes_recurse2(g_array_index(root->children, AST_NODE_PTR, i),
for_each, depth + 1);
} }
} }
@ -250,24 +260,28 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
AST_visit_nodes_recurse2(root, for_each, 0); AST_visit_nodes_recurse2(root, for_each, 0);
} }
static void AST_fprint_graphviz_node_definition(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_definition(FILE* stream,
const struct AST_Node_t* node) {
DEBUG("Printing graphviz definition of %p", node); DEBUG("Printing graphviz definition of %p", node);
assert(stream != NULL); assert(stream != NULL);
assert(node != NULL); assert(node != NULL);
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node)); fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node,
AST_node_to_string(node));
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
for (size_t i = 0; i < node->children->len; i++) { for (size_t i = 0; i < node->children->len; i++) {
AST_fprint_graphviz_node_definition(stream, g_array_index(node->children, AST_NODE_PTR, i)); AST_fprint_graphviz_node_definition(
stream, g_array_index(node->children, AST_NODE_PTR, i));
} }
} }
static void AST_fprint_graphviz_node_connection(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_connection(FILE* stream,
const struct AST_Node_t* node) {
DEBUG("Printing graphviz connection of %p", node); DEBUG("Printing graphviz connection of %p", node);
assert(stream != NULL); assert(stream != NULL);
@ -298,7 +312,8 @@ void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) {
fprintf(stream, "}\n"); fprintf(stream, "}\n");
} }
AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner, enum AST_SyntaxElement_t kind) { AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner,
enum AST_SyntaxElement_t kind) {
for (size_t i = 0; i < owner->children->len; i++) { for (size_t i = 0; i < owner->children->len; i++) {
AST_NODE_PTR child = AST_get_node(owner, i); AST_NODE_PTR child = AST_get_node(owner, i);

View File

@ -2,8 +2,8 @@
#ifndef _AST_H_ #ifndef _AST_H_
#define _AST_H_ #define _AST_H_
#include <stdio.h>
#include <io/files.h> #include <io/files.h>
#include <stdio.h>
/** /**
* @brief The type of a AST node * @brief The type of a AST node
@ -93,7 +93,8 @@ enum AST_SyntaxElement_t {
* Every node can have one ancestor (parent) but multiple (also none) children. * Every node can have one ancestor (parent) but multiple (also none) children.
* Nodes have two properties: * Nodes have two properties:
* - kind: The type of the node. Such as AST_Expr, AST_Add, ... * - kind: The type of the node. Such as AST_Expr, AST_Add, ...
* - value: A string representing an optional value. Can be a integer literal for kind AST_int * - value: A string representing an optional value. Can be a integer literal
* for kind AST_int
*/ */
typedef struct AST_Node_t { typedef struct AST_Node_t {
// parent node that owns this node // parent node that owns this node
@ -116,42 +117,43 @@ typedef struct AST_Node_t {
typedef struct AST_Node_t* AST_NODE_PTR; typedef struct AST_Node_t* AST_NODE_PTR;
/** /**
* @brief Initalize the global state of this module. Required for some functionality to work correctly. * @brief Initalize the global state of this module. Required for some
* functionality to work correctly.
*/ */
void AST_init(void); void AST_init(void);
/** /**
* @brief Returns the string representation of the supplied node * @brief Returns the string representation of the supplied node
* @attention The retuned pointer is not to be freed as it may either be a statically stored string or * @attention The retuned pointer is not to be freed as it may either be a
* used by the node after this function call. * statically stored string or used by the node after this function call.
* @param node to return string representation of * @param node to return string representation of
* @return string represenation of the node * @return string represenation of the node
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1)]]
[[gnu::nonnull(1)]]
const char* AST_node_to_string(const struct AST_Node_t* node); const char* AST_node_to_string(const struct AST_Node_t* node);
/** /**
* @brief Create a new node struct on the system heap. Initializes the struct with the given values. * @brief Create a new node struct on the system heap. Initializes the struct
* All other fields are set to either NULL or 0. No allocation for children array is preformed. * with the given values. All other fields are set to either NULL or 0. No
* @attention parameter value can be NULL in case no value can be provided for the node * allocation for children array is preformed.
* @attention parameter value can be NULL in case no value can be provided for
* the node
* @param kind the type of this node * @param kind the type of this node
* @param value an optional value for this node * @param value an optional value for this node
* @return * @return
*/ */
[[maybe_unused]] [[maybe_unused]] [[nodiscard("pointer must be freed")]] [[gnu::returns_nonnull]]
[[nodiscard("pointer must be freed")]] struct AST_Node_t* AST_new_node(TokenLocation location,
[[gnu::returns_nonnull]] enum AST_SyntaxElement_t kind,
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value); const char* value);
/** /**
* @brief Deallocate this node and all of its children. * @brief Deallocate this node and all of its children.
* @attention This function will detach this node from its parent if one is present * @attention This function will detach this node from its parent if one is
* Use of the supplied node after this call is undefined behavior * present Use of the supplied node after this call is undefined behavior
* @param node The node to deallocate * @param node The node to deallocate
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1)]]
[[gnu::nonnull(1)]]
void AST_delete_node(struct AST_Node_t* node); void AST_delete_node(struct AST_Node_t* node);
/** /**
@ -160,57 +162,56 @@ void AST_delete_node(struct AST_Node_t * node);
* @param owner node to add a child to * @param owner node to add a child to
* @param child node to be added as a child * @param child node to be added as a child
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_push_node(struct AST_Node_t* owner, struct AST_Node_t* child); void AST_push_node(struct AST_Node_t* owner, struct AST_Node_t* child);
/** /**
* @brief Remove the specified child from the owner. * @brief Remove the specified child from the owner.
* @attention The parent of the removed node is set to NULL. * @attention The parent of the removed node is set to NULL.
* The returned pointer is still valid. It must be freed at some pointer later. * The returned pointer is still valid. It must be freed at some
* pointer later.
* @param owner Node to remove the child from * @param owner Node to remove the child from
* @param idx the index of the child to remove * @param idx the index of the child to remove
* @return a pointer to the child which was removed * @return a pointer to the child which was removed
*/ */
[[maybe_unused]] [[maybe_unused]] [[nodiscard("pointer must be freed")]] [[gnu::nonnull(1)]]
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1)]]
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx); struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, size_t idx);
/** /**
* @brief Detach a child from its parent. This involves removing the child from its parent * @brief Detach a child from its parent. This involves removing the child from
* and marking the parent of the child as NULL. * its parent and marking the parent of the child as NULL.
* @attention The returned pointer is still valid. It must be freed at some pointer later. * @attention The returned pointer is still valid. It must be freed at some
* pointer later.
* @param owner the owner to remove the child from * @param owner the owner to remove the child from
* @param child the child to detach * @param child the child to detach
* @return a pointer to child detached * @return a pointer to child detached
*/ */
[[nodiscard("pointer must be freed")]] [[nodiscard("pointer must be freed")]] [[gnu::nonnull(1), gnu::nonnull(1)]]
[[gnu::nonnull(1), gnu::nonnull(1)]] struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner,
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child); const struct AST_Node_t* child);
/** /**
* @brief Return a pointer to the n-th child of a node * @brief Return a pointer to the n-th child of a node
* @attention Pointer to childen nodes will never change. * @attention Pointer to childen nodes will never change.
* However, the index a node is stored within a parent can change * However, the index a node is stored within a parent can change
* if a child of lower index is removed, thus reducing the childrens index by one. * if a child of lower index is removed, thus reducing the childrens
* index by one.
* @param owner the parent node which owns the children * @param owner the parent node which owns the children
* @param idx the index of the child to get a pointer to * @param idx the index of the child to get a pointer to
* @return a pointer to the n-th child of the owner node * @return a pointer to the n-th child of the owner node
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1)]]
[[gnu::nonnull(1)]]
struct AST_Node_t* AST_get_node(struct AST_Node_t* owner, size_t idx); struct AST_Node_t* AST_get_node(struct AST_Node_t* owner, size_t idx);
AST_NODE_PTR AST_get_last_node(AST_NODE_PTR node); AST_NODE_PTR AST_get_last_node(AST_NODE_PTR node);
/** /**
* @brief Execute a function for every child, grandchild, ... and the supplied node as topmost ancestor * @brief Execute a function for every child, grandchild, ... and the supplied
* node as topmost ancestor
* @param root the root to recursively execute a function for * @param root the root to recursively execute a function for
* @param for_each the function to execute * @param for_each the function to execute
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_visit_nodes_recurse(struct AST_Node_t* root, void AST_visit_nodes_recurse(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t* node, void (*for_each)(struct AST_Node_t* node,
size_t depth)); size_t depth));
@ -220,11 +221,11 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
* @param stream The stream to print to. Can be a file, stdout, ... * @param stream The stream to print to. Can be a file, stdout, ...
* @param node the topmost ancestor * @param node the topmost ancestor
*/ */
[[maybe_unused]] [[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* node); void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* node);
AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner, enum AST_SyntaxElement_t kind); AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner,
enum AST_SyntaxElement_t kind);
[[gnu::nonnull(1), gnu::nonnull(3)]] [[gnu::nonnull(1), gnu::nonnull(3)]]
void AST_merge_modules(AST_NODE_PTR dst, size_t i, AST_NODE_PTR src); void AST_merge_modules(AST_NODE_PTR dst, size_t i, AST_NODE_PTR src);

View File

@ -2,14 +2,14 @@
// Created by servostar on 5/31/24. // Created by servostar on 5/31/24.
// //
#include <assert.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <io/files.h>
#include <link/driver.h>
#include <mem/cache.h>
#include <string.h> #include <string.h>
#include <sys/log.h> #include <sys/log.h>
#include <io/files.h>
#include <assert.h>
#include <toml.h> #include <toml.h>
#include <mem/cache.h>
#include <link/driver.h>
static GHashTable* args = NULL; static GHashTable* args = NULL;
@ -34,7 +34,8 @@ void parse_options(int argc, char* argv[]) {
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option)); Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option));
option->is_opt = g_str_has_prefix(argv[i], "--"); option->is_opt = g_str_has_prefix(argv[i], "--");
option->string = mem_strdup(MemoryNamespaceOpt, argv[i] + (option->is_opt ? 2 : 0)); option->string =
mem_strdup(MemoryNamespaceOpt, argv[i] + (option->is_opt ? 2 : 0));
option->index = i; option->index = i;
option->value = NULL; option->value = NULL;
@ -104,7 +105,8 @@ TargetConfig* default_target_config() {
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 = mem_new_g_array(MemoryNamespaceOpt, 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*));
@ -148,7 +150,8 @@ TargetConfig* default_target_config_from_args() {
} else if (strcmp(opt->value, "lib") == 0) { } else if (strcmp(opt->value, "lib") == 0) {
config->mode = Library; config->mode = Library;
} else { } else {
print_message(Warning, "Invalid compilation mode: %s", opt->value); print_message(Warning, "Invalid compilation mode: %s",
opt->value);
} }
} }
} }
@ -211,10 +214,12 @@ TargetConfig* default_target_config_from_args() {
} else { } else {
if (files->len > 1) { if (files->len > 1) {
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, g_array_index(files, char*, 0)); config->root_module =
mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0));
} }
char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); char* default_import_path = mem_strdup(MemoryNamespaceOpt, ".");
@ -262,33 +267,37 @@ void print_help(void) {
"Compile non-project file: gsc compile <target-options> [file]", "Compile non-project file: gsc compile <target-options> [file]",
"Output information: gsc <option>", "Output information: gsc <option>",
"Target options:", "Target options:",
" --print-ast print resulting abstract syntax tree to a file", " --print-ast print resulting abstract syntax tree to a "
"file",
" --print-asm print resulting assembly language to a file", " --print-asm print resulting assembly language to a file",
" --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", " --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",
" --gsc-fatal-warnings treat parser warnings as errors", " --gsc-fatal-warnings treat parser warnings as errors",
"Options:", "Options:",
" --verbose print logs with level information or higher", " --verbose print logs with level information or higher",
" --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", " --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"};
};
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char*); i++) { for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char*); i++) {
printf("%s\n", lines[i]); printf("%s\n", lines[i]);
} }
} }
static void get_bool(bool* boolean, const toml_table_t *table, const char* name) { static void get_bool(bool* boolean, const toml_table_t* table,
const char* name) {
DEBUG("retrieving boolean %s", name); DEBUG("retrieving boolean %s", name);
const toml_datum_t datum = toml_bool_in(table, name); const toml_datum_t datum = toml_bool_in(table, name);
@ -299,7 +308,8 @@ static void get_bool(bool* boolean, const toml_table_t *table, const char* name)
} }
} }
static void get_str(char** string, const toml_table_t *table, const char* name) { static void get_str(char** string, const toml_table_t* table,
const char* name) {
DEBUG("retrieving string %s", name); DEBUG("retrieving string %s", name);
const toml_datum_t datum = toml_string_in(table, name); const toml_datum_t datum = toml_string_in(table, name);
@ -321,7 +331,8 @@ 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) { 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); const toml_array_t* toml_array = toml_array_in(table, name);
if (toml_array) { if (toml_array) {
@ -336,7 +347,8 @@ static void get_array(GArray* array, const toml_table_t *table, const char* name
} }
} }
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...");
// project name // project name
@ -356,8 +368,9 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec
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);
if (!author.ok) if (!author.ok) {
break; break;
}
g_array_append_val(config->authors, author.u.s); g_array_append_val(config->authors, author.u.s);
} }
@ -383,11 +396,13 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
*mode = Library; *mode = Library;
return PROJECT_OK; return PROJECT_OK;
} }
print_message(Error, "Invalid project configuration, mode is invalid: %s", name); print_message(Error, "Invalid project configuration, mode is invalid: %s",
name);
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
static int parse_target(const ProjectConfig *config, const toml_table_t *target_table, const char* name) { static int parse_target(const ProjectConfig* config,
const toml_table_t* target_table, const char* name) {
DEBUG("parsing target table..."); DEBUG("parsing target table...");
TargetConfig* target_config = default_target_config(); TargetConfig* target_config = default_target_config();
@ -402,8 +417,10 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
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");
get_bool(&target_config->lld_fatal_warnings, target_table, "lld_fatal_warnings"); get_bool(&target_config->lld_fatal_warnings, target_table,
get_bool(&target_config->gsc_fatal_warnings, target_table, "gsc_fatal_warnings"); "lld_fatal_warnings");
get_bool(&target_config->gsc_fatal_warnings, target_table,
"gsc_fatal_warnings");
get_int(&target_config->optimization_level, target_table, "opt"); get_int(&target_config->optimization_level, target_table, "opt");
@ -437,16 +454,19 @@ static int parse_targets(ProjectConfig *config, const toml_table_t *root) {
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
config->targets = mem_new_g_hash_table(MemoryNamespaceOpt, 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 < toml_table_ntab(targets); 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, mem_strdup(MemoryNamespaceOpt, (char*) key)); parse_target(config, target,
mem_strdup(MemoryNamespaceOpt, (char*) key));
} }
return PROJECT_OK; return PROJECT_OK;
@ -457,7 +477,8 @@ 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));
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
@ -475,7 +496,8 @@ int load_project_config(ProjectConfig *config) {
status = parse_targets(config, conf); status = parse_targets(config, conf);
} }
} else { } else {
print_message(Error, "Invalid project configuration: missing project table."); print_message(
Error, "Invalid project configuration: missing project table.");
} }
toml_free(conf); toml_free(conf);
@ -528,7 +550,8 @@ void delete_project_config(ProjectConfig* config) {
char* key; char* key;
TargetConfig* val; TargetConfig* val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) { while (
g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
delete_target_config(val); delete_target_config(val);
} }
@ -539,7 +562,8 @@ void delete_project_config(ProjectConfig* config) {
} }
ProjectConfig* default_project_config() { ProjectConfig* default_project_config() {
ProjectConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig)); ProjectConfig* config =
mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig));
config->authors = NULL; config->authors = NULL;
config->name = NULL; config->name = NULL;

View File

@ -49,7 +49,8 @@ typedef struct TargetConfig_t {
char* root_module; char* root_module;
// output directory for binaries // output directory for binaries
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 // binary driver for executable generation
char* driver; char* driver;
@ -182,8 +183,7 @@ const Option* get_option(const char* option);
* @param command * @param command
* @return an array of options that followed command. * @return an array of options that followed command.
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]] [[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(); void init_toml();

View File

@ -1,5 +1,6 @@
#include "set/types.h" #include "set/types.h"
#include <codegen/backend.h> #include <codegen/backend.h>
#include <sys/log.h> #include <sys/log.h>
@ -19,7 +20,8 @@ BackendError new_backend_error(BackendErrorKind kind) {
return error; return error;
} }
BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message) { BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node,
const char* message) {
BackendError error; BackendError error;
error.kind = kind; error.kind = kind;
error.impl.ast_node = node; error.impl.ast_node = node;
@ -39,7 +41,8 @@ BackendError init_backend(void) {
BackendError code = CodegenBackend.init_func(); BackendError code = CodegenBackend.init_func();
if (code.kind != Success) { if (code.kind != Success) {
ERROR("failed to initialize backend: %s with code: %ld", CodegenBackend.name, code); ERROR("failed to initialize backend: %s with code: %ld",
CodegenBackend.name, code);
return code; return code;
} }
@ -57,14 +60,17 @@ BackendError deinit_backend(void) {
BackendError code = CodegenBackend.deinit_func(); BackendError code = CodegenBackend.deinit_func();
if (code.kind != Success) { if (code.kind != Success) {
ERROR("failed to undo initialization of backend: %s with code: %ld", CodegenBackend.name, code); ERROR("failed to undo initialization of backend: %s with code: %ld",
CodegenBackend.name, code);
return code; return code;
} }
return new_backend_error(Success); return new_backend_error(Success);
} }
BackendError set_backend(const codegen_init init_func, const codegen_deinit deinit_func, const codegen codegen_func, const char* name) { BackendError set_backend(const codegen_init init_func,
const codegen_deinit deinit_func,
const codegen codegen_func, const char* name) {
CodegenBackend.init_func = init_func; CodegenBackend.init_func = init_func;
CodegenBackend.deinit_func = deinit_func; CodegenBackend.deinit_func = deinit_func;
CodegenBackend.codegen_func = codegen_func; CodegenBackend.codegen_func = codegen_func;
@ -83,7 +89,8 @@ BackendError generate_code(const Module* root, const TargetConfig* target) {
BackendError code = CodegenBackend.codegen_func(root, target); BackendError code = CodegenBackend.codegen_func(root, target);
if (code.kind) { if (code.kind) {
ERROR("code generation of backend: %s failed with code: %ld `%s`", CodegenBackend.name, code, code.impl.message); ERROR("code generation of backend: %s failed with code: %ld `%s`",
CodegenBackend.name, code, code.impl.message);
return code; return code;
} }

View File

@ -2,9 +2,9 @@
#ifndef CODEGN_BACKEND_H_ #ifndef CODEGN_BACKEND_H_
#define CODEGN_BACKEND_H_ #define CODEGN_BACKEND_H_
#include <set/types.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <set/types.h>
typedef struct BackendImplError_t { typedef struct BackendImplError_t {
// faulty AST node // faulty AST node
@ -28,8 +28,8 @@ typedef struct BackendError_t {
} BackendError; } BackendError;
/** /**
* @brief Function called by the compiler backend to generate an intermediate format * @brief Function called by the compiler backend to generate an intermediate
* from AST. Returns a custom container for its intermediate language. * format from AST. Returns a custom container for its intermediate language.
*/ */
typedef BackendError (*codegen)(const Module*, const TargetConfig* target); typedef BackendError (*codegen)(const Module*, const TargetConfig* target);
@ -47,13 +47,16 @@ typedef BackendError (*codegen_deinit)(void);
* @brief Set the backend functions to use * @brief Set the backend functions to use
* *
* @param init_func the function to call for initializing the backend * @param init_func the function to call for initializing the backend
* @param deinit_func the function to call for undoing the initialization of the backend * @param deinit_func the function to call for undoing the initialization of the
* backend
* @param codegen_func the function to call when generating code * @param codegen_func the function to call when generating code
* @param name name of the backend * @param name name of the backend
*/ */
[[nodiscard]] [[nodiscard]] [[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(3),
[[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(3), gnu::nonnull(3)]] gnu::nonnull(3)]]
BackendError set_backend(const codegen_init init_func, const codegen_deinit deinit_func, const codegen codegen_func, const char* name); BackendError set_backend(const codegen_init init_func,
const codegen_deinit deinit_func,
const codegen codegen_func, const char* name);
/** /**
* @brief Call the initialization function of the backend * @brief Call the initialization function of the backend
@ -89,7 +92,8 @@ BackendError generate_code(const Module* root, const TargetConfig* target);
*/ */
BackendError new_backend_error(BackendErrorKind kind); BackendError new_backend_error(BackendErrorKind kind);
BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message); BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node,
const char* message);
#define SUCCESS new_backend_error(Success) #define SUCCESS new_backend_error(Success)

View File

@ -2,41 +2,40 @@
// Created by servostar on 6/2/24. // Created by servostar on 6/2/24.
// //
#include <compiler.h>
#include <ast/ast.h>
#include <stdlib.h>
#include <sys/log.h>
#include <yacc/parser.tab.h>
#include <lex/util.h>
#include <io/files.h>
#include <assert.h> #include <assert.h>
#include <ast/ast.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <codegen/backend.h> #include <codegen/backend.h>
#include <compiler.h>
#include <io/files.h>
#include <lex/util.h>
#include <llvm/backend.h> #include <llvm/backend.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <set/set.h> #include <set/set.h>
#include <stdlib.h>
#include <sys/log.h>
#include <yacc/parser.tab.h>
#define GRAPHVIZ_FILE_EXTENSION "gv" #define GRAPHVIZ_FILE_EXTENSION "gv"
extern void yyrestart(FILE*); extern void yyrestart(FILE*);
// Module AST node used by the parser for AST construction. // Module AST node used by the parser for AST construction.
[[maybe_unused]] [[maybe_unused]] AST_NODE_PTR root;
AST_NODE_PTR root;
// Current file which gets compiled the parser. // Current file which gets compiled the parser.
// NOTE: due to global state no concurrent compilation is possible // NOTE: due to global state no concurrent compilation is possible
// on parser level. // on parser level.
[[maybe_unused]] [[maybe_unused]] ModuleFile* current_file;
ModuleFile *current_file;
/** /**
* @brief Compile the specified file into AST * @brief Compile the specified file into AST
* @param ast Initialized AST module node to build program rules * @param ast Initialized AST module node to build program rules
* @param file The file to be processed * @param file The file to be processed
* @return EXIT_SUCCESS in case the parsing was success full anything lese if not * @return EXIT_SUCCESS in case the parsing was success full anything lese if
* not
*/ */
[[nodiscard("AST may be in invalid state")]] [[nodiscard("AST may be in invalid state")]] [[gnu::nonnull(1),
[[gnu::nonnull(1), gnu::nonnull(1)]] gnu::nonnull(1)]]
static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile* file) { static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile* file) {
assert(file->path != NULL); assert(file->path != NULL);
assert(ast != NULL); assert(ast != NULL);
@ -45,7 +44,8 @@ static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
if (file->handle == NULL) { if (file->handle == NULL) {
INFO("unable to open file: %s", file->path); INFO("unable to open file: %s", file->path);
print_message(Error, "Cannot open file %s: %s", file->path, strerror(errno)); print_message(Error, "Cannot open file %s: %s", file->path,
strerror(errno));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -83,7 +83,8 @@ static int setup_target_environment(const TargetConfig *target) {
const char* message = get_last_error(); const char* message = get_last_error();
assert(message != NULL); assert(message != NULL);
print_message(Error, "Unable to create directory: %s: %s", target->archive_directory, message); print_message(Error, "Unable to create directory: %s: %s",
target->archive_directory, message);
free((void*) message); free((void*) message);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -93,7 +94,8 @@ static int setup_target_environment(const TargetConfig *target) {
const char* message = get_last_error(); const char* message = get_last_error();
assert(message != NULL); assert(message != NULL);
print_message(Error, "Unable to create directory: %s: %s", target->output_directory, message); print_message(Error, "Unable to create directory: %s: %s",
target->output_directory, message);
free((void*) message); free((void*) message);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -104,7 +106,8 @@ static int setup_target_environment(const TargetConfig *target) {
} }
/** /**
* @brief Print the supplied AST of the specified target to a graphviz ".gv" file * @brief Print the supplied AST of the specified target to a graphviz ".gv"
* file
* @param ast * @param ast
* @param target * @param target
*/ */
@ -120,7 +123,8 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
// create file path to write graphviz to // create file path to write graphviz to
// basename of ile // basename of ile
char* filename = g_strjoin(".", target->name, GRAPHVIZ_FILE_EXTENSION, NULL); char* filename =
g_strjoin(".", target->name, GRAPHVIZ_FILE_EXTENSION, NULL);
// relative path to file // relative path to file
char* path = g_build_filename(target->archive_directory, filename, NULL); char* path = g_build_filename(target->archive_directory, filename, NULL);
@ -129,7 +133,8 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
FILE* output = fopen(path, "w"); FILE* output = fopen(path, "w");
if (output == NULL) { if (output == NULL) {
char* message = (char*) get_last_error(); char* message = (char*) get_last_error();
print_message(Error, "Unable to open file for syntax tree at: %s: %s", path, message); print_message(Error, "Unable to open file for syntax tree at: %s: %s",
path, message);
free(message); free(message);
} else { } else {
DEBUG("writing graph to file..."); DEBUG("writing graph to file...");
@ -145,7 +150,8 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
g_free(path); g_free(path);
} }
static int run_backend_codegen(const Module* module, const TargetConfig* target) { static int run_backend_codegen(const Module* module,
const TargetConfig* target) {
DEBUG("initializing LLVM codegen backend..."); DEBUG("initializing LLVM codegen backend...");
llvm_backend_init(); llvm_backend_init();
@ -173,7 +179,8 @@ static int run_backend_codegen(const Module* module, const TargetConfig* target)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
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")) { if (!g_str_has_suffix(import_target_name, ".gsc")) {
@ -183,9 +190,11 @@ const char* get_absolute_import_path(const TargetConfig* config, const char* imp
} }
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);
char* path = g_build_filename(import_directory_path, import_target_name, NULL); char* path =
g_build_filename(import_directory_path, import_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);
@ -208,9 +217,13 @@ const char* get_absolute_import_path(const TargetConfig* config, const char* imp
return NULL; return NULL;
} }
static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* file, const TargetConfig *target, AST_NODE_PTR root_module) { static int compile_module_with_dependencies(ModuleFileStack* unit,
ModuleFile* file,
const TargetConfig* target,
AST_NODE_PTR root_module) {
GHashTable* imports = mem_new_g_hash_table(MemoryNamespaceAst, g_str_hash, g_str_equal); GHashTable* imports =
mem_new_g_hash_table(MemoryNamespaceAst, g_str_hash, g_str_equal);
if (compile_file_to_ast(root_module, file) == EXIT_SUCCESS) { if (compile_file_to_ast(root_module, file) == EXIT_SUCCESS) {
@ -219,9 +232,11 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
if (child->kind == AST_Import || child->kind == AST_Include) { 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) {
print_message(Error, "Cannot resolve path for import: `%s`", child->value); print_message(Error, "Cannot resolve path for import: `%s`",
child->value);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -230,9 +245,11 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
} }
ModuleFile* imported_file = push_file(unit, path); ModuleFile* imported_file = push_file(unit, path);
AST_NODE_PTR imported_module = AST_new_node(empty_location(imported_file), AST_Module, NULL); AST_NODE_PTR imported_module =
AST_new_node(empty_location(imported_file), AST_Module, NULL);
if (compile_file_to_ast(imported_module, imported_file) == EXIT_SUCCESS) { if (compile_file_to_ast(imported_module, imported_file)
== EXIT_SUCCESS) {
AST_merge_modules(root_module, i + 1, imported_module); AST_merge_modules(root_module, i + 1, imported_module);
} else { } else {
return EXIT_FAILURE; return EXIT_FAILURE;
@ -241,7 +258,8 @@ 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);
gchar* cached_directory = mem_strdup(MemoryNamespaceLld, directory); gchar* cached_directory =
mem_strdup(MemoryNamespaceLld, directory);
g_free(directory); g_free(directory);
g_array_append_val(target->import_paths, cached_directory); g_array_append_val(target->import_paths, cached_directory);
} }
@ -264,7 +282,8 @@ static int build_target(ModuleFileStack *unit, const TargetConfig *target) {
print_message(Info, "Building target: %s", target->name); print_message(Info, "Building target: %s", target->name);
ModuleFile* file = push_file(unit, target->root_module); ModuleFile* file = push_file(unit, target->root_module);
AST_NODE_PTR root_module = AST_new_node(empty_location(file), AST_Module, NULL); AST_NODE_PTR root_module =
AST_new_node(empty_location(file), AST_Module, NULL);
err = compile_module_with_dependencies(unit, file, target, root_module); err = compile_module_with_dependencies(unit, file, target, root_module);
if (err == EXIT_SUCCESS) { if (err == EXIT_SUCCESS) {
@ -323,7 +342,8 @@ static int compile_file(ModuleFileStack *unit) {
* @param unit * @param unit
* @param config * @param config
*/ */
static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *config) { static int build_project_targets(ModuleFileStack* unit,
const ProjectConfig* config) {
int err = EXIT_SUCCESS; int err = EXIT_SUCCESS;
if (is_option_set("all")) { if (is_option_set("all")) {
@ -334,7 +354,8 @@ static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *con
char* key; char* key;
TargetConfig* val; TargetConfig* val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) { while (
g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
err = build_target(unit, val); err = build_target(unit, val);
} }
return err; return err;
@ -348,7 +369,8 @@ static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *con
const char* target_name = g_array_index(targets, const char*, i); 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)) {
err = build_target(unit, g_hash_table_lookup(config->targets, target_name)); err = build_target(
unit, g_hash_table_lookup(config->targets, target_name));
} else { } else {
print_message(Error, "Unknown target: %s", target_name); print_message(Error, "Unknown target: %s", target_name);
} }
@ -363,7 +385,8 @@ static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *con
} }
/** /**
* @brief Build targets from project. Configuration is provided by command line arguments. * @brief Build targets from project. Configuration is provided by command line
* arguments.
* @param unit File storage * @param unit File storage
*/ */
static int build_project(ModuleFileStack* unit) { static int build_project(ModuleFileStack* unit) {

View File

@ -2,13 +2,13 @@
// Created by servostar on 5/30/24. // Created by servostar on 5/30/24.
// //
#include <assert.h>
#include <io/files.h> #include <io/files.h>
#include <mem/cache.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <sys/log.h>
#include <assert.h>
#include <sys/col.h> #include <sys/col.h>
#include <mem/cache.h> #include <sys/log.h>
#ifdef __unix__ #ifdef __unix__
@ -42,7 +42,8 @@ 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 = mem_new_g_array(MemoryNamespaceStatic, 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));
@ -92,7 +93,8 @@ static void custom_fgets(char *buffer, size_t n, FILE *stream) {
} }
} }
void print_diagnostic(TokenLocation *location, Message kind, const char *message, ...) { void print_diagnostic(TokenLocation* location, Message kind,
const char* message, ...) {
assert(location->file != NULL); assert(location->file != NULL);
assert(location->file->handle != NULL); assert(location->file->handle != NULL);
assert(location != NULL); assert(location != NULL);
@ -105,7 +107,8 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
unsigned long int line_count = 1; unsigned long int line_count = 1;
// seek to first line // seek to first line
while (line_count < location->line_start && fgets(buffer, SEEK_BUF_BYTES, location->file->handle) != NULL) { while (line_count < location->line_start
&& fgets(buffer, SEEK_BUF_BYTES, location->file->handle) != NULL) {
line_count += strchr(buffer, '\n') != NULL; line_count += strchr(buffer, '\n') != NULL;
} }
@ -131,7 +134,8 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
const char* absolute_path = get_absolute_path(location->file->path); const char* absolute_path = get_absolute_path(location->file->path);
printf("%s%s:%ld:%s %s%s:%s ", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET); printf("%s%s:%ld:%s %s%s:%s ", BOLD, absolute_path, location->line_start,
RESET, accent_color, kind_text, RESET);
va_list args; va_list args;
va_start(args, message); va_start(args, message);
@ -144,7 +148,8 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
mem_free((void*) absolute_path); mem_free((void*) absolute_path);
const unsigned long int lines = location->line_end - location->line_start + 1; const unsigned long int lines =
location->line_end - location->line_start + 1;
for (unsigned long int l = 0; l < lines; l++) { for (unsigned long int l = 0; l < lines; l++) {
printf(" %4ld | ", location->line_start + l); printf(" %4ld | ", location->line_start + l);
@ -166,11 +171,13 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("%s", accent_color); printf("%s", accent_color);
chars = 0; chars = 0;
limit = min(location->col_end - location->col_start + 1, SEEK_BUF_BYTES); limit =
min(location->col_end - location->col_start + 1, SEEK_BUF_BYTES);
while (limit > 0) { while (limit > 0) {
custom_fgets(buffer, (int) limit, location->file->handle); custom_fgets(buffer, (int) limit, location->file->handle);
chars += printf("%s", buffer); chars += printf("%s", buffer);
limit = min(location->col_end - location->col_start + 1 - chars, SEEK_BUF_BYTES); limit = min(location->col_end - location->col_start + 1 - chars,
SEEK_BUF_BYTES);
if (strchr(buffer, '\n') != NULL) { if (strchr(buffer, '\n') != NULL) {
goto cont; goto cont;
@ -196,14 +203,17 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("%s", accent_color); printf("%s", accent_color);
printf("^"); printf("^");
for (unsigned long int i = 0; i < location->col_end - location->col_start; i++) { for (unsigned long int i = 0; i < location->col_end - location->col_start;
i++) {
printf("~"); printf("~");
} }
printf("%s\n\n", RESET); printf("%s\n\n", RESET);
} }
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end, TokenLocation new_location(unsigned long int line_start,
unsigned long int col_start,
unsigned long int line_end,
unsigned long int col_end, ModuleFile* file) { unsigned long int col_end, ModuleFile* file) {
TokenLocation location; TokenLocation location;
@ -229,7 +239,9 @@ TokenLocation empty_location(ModuleFile* file) {
} }
void print_file_statistics(ModuleFile* file) { void print_file_statistics(ModuleFile* file) {
if (file->statistics.info_count + file->statistics.warning_count + file->statistics.error_count < 1) { if (file->statistics.info_count + file->statistics.warning_count
+ file->statistics.error_count
< 1) {
return; return;
} }

View File

@ -5,8 +5,8 @@
#ifndef GEMSTONE_FILES_H #ifndef GEMSTONE_FILES_H
#define GEMSTONE_FILES_H #define GEMSTONE_FILES_H
#include <stdio.h>
#include <glib.h> #include <glib.h>
#include <stdio.h>
#if defined(WIN32) || defined(_WIN32) #if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR "\\" #define PATH_SEPARATOR "\\"
@ -30,11 +30,7 @@ typedef struct ModuleFileStack_t {
GArray* files; GArray* files;
} ModuleFileStack; } ModuleFileStack;
typedef enum Message_t { typedef enum Message_t { Info, Warning, Error } Message;
Info,
Warning,
Error
} Message;
typedef struct TokenLocation_t { typedef struct TokenLocation_t {
unsigned long int line_start; unsigned long int line_start;
@ -75,7 +71,9 @@ void delete_files(ModuleFileStack *stack);
* @param col_end * @param col_end
* @return * @return
*/ */
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end, TokenLocation new_location(unsigned long int line_start,
unsigned long int col_start,
unsigned long int line_end,
unsigned long int col_end, ModuleFile* file); unsigned long int col_end, ModuleFile* file);
/** /**
@ -92,7 +90,8 @@ TokenLocation empty_location(ModuleFile* file);
* @param message * @param message
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
void print_diagnostic(TokenLocation *location, Message kind, const char *message, ...); void print_diagnostic(TokenLocation* location, Message kind,
const char* message, ...);
[[gnu::nonnull(2)]] [[gnu::nonnull(2)]]
/** /**
@ -105,7 +104,8 @@ void print_message(Message kind, const char *fmt, ...);
/** /**
* @brief Print statistics about a specific file. * @brief Print statistics about a specific file.
* Will print the amount of infos, warning and errors emitted during compilation. * Will print the amount of infos, warning and errors emitted during
* compilation.
* @param file * @param file
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]]
@ -119,7 +119,8 @@ void print_file_statistics(ModuleFile *file);
void print_unit_statistics(ModuleFileStack* file_stack); void print_unit_statistics(ModuleFileStack* file_stack);
/** /**
* @brief Create a new directory. Will return EEXISTS in case the directory already exists. * @brief Create a new directory. Will return EEXISTS in case the directory
* already exists.
* @param path * @param path
* @return 0 if successful, anything else otherwise * @return 0 if successful, anything else otherwise
*/ */
@ -138,8 +139,7 @@ const char* get_last_error();
* @param path * @param path
* @return * @return
*/ */
[[gnu::nonnull(1)]] [[gnu::nonnull(1)]] [[nodiscard("pointer must be freed")]]
[[nodiscard("pointer must be freed")]]
const char* get_absolute_path(const char* path); const char* get_absolute_path(const char* path);
#endif // GEMSTONE_FILES_H #endif // GEMSTONE_FILES_H

View File

@ -1,9 +1,9 @@
#include <lex/util.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h> #include <glib.h>
#include <lex/util.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <stdlib.h>
#include <string.h>
// implementation based on: // implementation based on:
// https://github.com/sunxfancy/flex-bison-examples/blob/master/error-handling/ccalc.c // https://github.com/sunxfancy/flex-bison-examples/blob/master/error-handling/ccalc.c
@ -46,8 +46,9 @@ void beginToken(char *t) {
int nextChar(char* dst) { int nextChar(char* dst) {
int frc; int frc;
if (eof) if (eof) {
return 0; return 0;
}
while (nBuffer >= lBuffer) { while (nBuffer >= lBuffer) {
frc = getNextLine(); frc = getNextLine();
@ -91,22 +92,10 @@ struct ConstEscSeq {
}; };
static struct ConstEscSeq sequences[] = { static struct ConstEscSeq sequences[] = {
{ {"\\n", "\n"},
"\\n", {"\\\\", "\\"},
"\n" {"\\t", "\t"},
}, {"\\r", "\r"}
{
"\\\\",
"\\"
},
{
"\\t",
"\t"
},
{
"\\r",
"\r"
}
}; };
char* collapse_escape_sequences(char* string) { char* collapse_escape_sequences(char* string) {

View File

@ -2,8 +2,8 @@
#ifndef LEX_UTIL_H_ #ifndef LEX_UTIL_H_
#define LEX_UTIL_H_ #define LEX_UTIL_H_
#include <yacc/parser.tab.h>
#include <stdio.h> #include <stdio.h>
#include <yacc/parser.tab.h>
#define MAX_READ_BUFFER_SIZE 1000 #define MAX_READ_BUFFER_SIZE 1000

View File

@ -2,8 +2,8 @@
// Created by servostar on 18.07.24. // Created by servostar on 18.07.24.
// //
#include <link/clang/driver.h>
#include <io/files.h> #include <io/files.h>
#include <link/clang/driver.h>
#include <mem/cache.h> #include <mem/cache.h>
bool clang_link(TargetLinkConfig* config) { bool clang_link(TargetLinkConfig* config) {
@ -14,7 +14,8 @@ bool clang_link(TargetLinkConfig* config) {
for (guint i = 0; i < config->object_file_names->len; i++) { for (guint i = 0; i < config->object_file_names->len; i++) {
g_string_append(commandString, " "); g_string_append(commandString, " ");
g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); g_string_append(commandString,
g_array_index(config->object_file_names, char*, i));
} }
g_string_append(commandString, " -o "); g_string_append(commandString, " -o ");

View File

@ -2,8 +2,8 @@
// Created by servostar on 18.07.24. // Created by servostar on 18.07.24.
// //
#include <link/clang/driver.h>
#include <io/files.h> #include <io/files.h>
#include <link/clang/driver.h>
#include <mem/cache.h> #include <mem/cache.h>
bool gcc_link(TargetLinkConfig* config) { bool gcc_link(TargetLinkConfig* config) {
@ -14,7 +14,8 @@ bool gcc_link(TargetLinkConfig* config) {
for (guint i = 0; i < config->object_file_names->len; i++) { for (guint i = 0; i < config->object_file_names->len; i++) {
g_string_append(commandString, " "); g_string_append(commandString, " ");
g_string_append(commandString, g_array_index(config->object_file_names, char*, i)); g_string_append(commandString,
g_array_index(config->object_file_names, char*, i));
} }
g_string_append(commandString, " -o "); g_string_append(commandString, " -o ");

View File

@ -2,18 +2,14 @@
// Created by servostar on 18.07.24. // Created by servostar on 18.07.24.
// //
#include <io/files.h>
#include <link/clang/driver.h>
#include <link/gcc/driver.h>
#include <link/lib.h> #include <link/lib.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <sys/log.h> #include <sys/log.h>
#include <io/files.h>
#include <link/clang/driver.h> static driver_init AVAILABLE_DRIVER[] = {clang_get_driver, gcc_get_driver};
#include <link/gcc/driver.h>
static driver_init AVAILABLE_DRIVER[] = {
clang_get_driver,
gcc_get_driver
};
static GHashTable* binary_driver = NULL; static GHashTable* binary_driver = NULL;
@ -21,9 +17,11 @@ void link_init() {
INFO("initializing binary driver..."); INFO("initializing binary driver...");
if (binary_driver == NULL) { if (binary_driver == NULL) {
binary_driver = mem_new_g_hash_table(MemoryNamespaceLld, g_str_hash, g_str_equal); 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++) { for (unsigned long int i = 0;
i < sizeof(AVAILABLE_DRIVER) / sizeof(driver_init); i++) {
BinaryDriver* driver = AVAILABLE_DRIVER[i](); BinaryDriver* driver = AVAILABLE_DRIVER[i]();
if (driver == NULL) { if (driver == NULL) {
@ -44,7 +42,8 @@ bool link_run(TargetLinkConfig* config) {
if (g_hash_table_contains(binary_driver, config->driver)) { if (g_hash_table_contains(binary_driver, config->driver)) {
print_message(Info, "Invoking binary driver: %s", config->driver); print_message(Info, "Invoking binary driver: %s", config->driver);
BinaryDriver* driver = g_hash_table_lookup(binary_driver, config->driver); BinaryDriver* driver =
g_hash_table_lookup(binary_driver, config->driver);
if (!driver->link_func(config)) { if (!driver->link_func(config)) {
print_message(Error, "Driver %s failed", config->driver); print_message(Error, "Driver %s failed", config->driver);
@ -53,7 +52,8 @@ bool link_run(TargetLinkConfig* config) {
return true; return true;
} else { } else {
print_message(Error, "Binary driver not available: `%s`", config->driver); print_message(Error, "Binary driver not available: `%s`",
config->driver);
return false; return false;
} }
} }

View File

@ -6,8 +6,8 @@
#include <llvm-c/TargetMachine.h> #include <llvm-c/TargetMachine.h>
#include <llvm/backend.h> #include <llvm/backend.h>
#include <llvm/parser.h> #include <llvm/parser.h>
#include <sys/log.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <sys/log.h>
Target create_native_target() { Target create_native_target() {
DEBUG("creating native target..."); DEBUG("creating native target...");
@ -72,8 +72,8 @@ Target create_target_from_config(const TargetConfig* config) {
target.opt = llvm_opt_from_int(config->optimization_level); target.opt = llvm_opt_from_int(config->optimization_level);
INFO("Configured target: %s/%d: (%s) on %s { %s }", target.name.str, target.opt, INFO("Configured target: %s/%d: (%s) on %s { %s }", target.name.str,
target.triple.str, target.cpu.str, target.features.str); target.opt, target.triple.str, target.cpu.str, target.features.str);
return target; return target;
} }

View File

@ -4,11 +4,7 @@
#include <llvm-c/TargetMachine.h> #include <llvm-c/TargetMachine.h>
enum StringAllocation_t { enum StringAllocation_t { LLVM, LIBC, NONE };
LLVM,
LIBC,
NONE
};
typedef struct String_t { typedef struct String_t {
enum StringAllocation_t allocation; enum StringAllocation_t allocation;

View File

@ -2,21 +2,24 @@
// Created by servostar on 6/4/24. // Created by servostar on 6/4/24.
// //
#include <link/lib.h>
#include <llvm/link/lld.h> #include <llvm/link/lld.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> #include <sys/log.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);
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); 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); char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical);
@ -38,21 +41,28 @@ const char* get_absolute_link_path(const TargetConfig* config, const char* link_
return NULL; return NULL;
} }
TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* target, const TargetConfig* target_config, const Module* module) { TargetLinkConfig* lld_create_link_config(__attribute__((unused))
const Target* target,
const TargetConfig* target_config,
const Module* module) {
DEBUG("generating link configuration"); DEBUG("generating link configuration");
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 = mem_new_g_array(MemoryNamespaceLld, 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; 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); 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); g_free(filename);
@ -65,7 +75,8 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
{ {
// 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 = mem_strdup(MemoryNamespaceLld, filename); config->output_file = mem_strdup(MemoryNamespaceLld, filename);
@ -83,10 +94,14 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
const char* library = g_strjoin("", "libgsc", dependency, ".a", NULL); const char* library = g_strjoin("", "libgsc", dependency, ".a", NULL);
const char* dependency_object = get_absolute_link_path(target_config, library); 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", library); 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); 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); g_free((void*) library);
return NULL; return NULL;

View File

@ -8,7 +8,10 @@
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm/backend.h> #include <llvm/backend.h>
TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target * target, const TargetConfig* target_config, const Module* module); TargetLinkConfig* lld_create_link_config(__attribute__((unused))
const Target* target,
const TargetConfig* target_config,
const Module* module);
BackendError lld_link_target(TargetLinkConfig* config); BackendError lld_link_target(TargetLinkConfig* config);

View File

@ -4,8 +4,8 @@
#include <llvm/llvm-ir/expr.h> #include <llvm/llvm-ir/expr.h>
#include <llvm/llvm-ir/types.h> #include <llvm/llvm-ir/types.h>
#include <sys/log.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <sys/log.h>
BackendError impl_bitwise_operation(LLVMBackendCompileUnit* unit, BackendError impl_bitwise_operation(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope, LLVMLocalScope* scope,
@ -32,13 +32,16 @@ BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.bitwise) { switch (operation->impl.bitwise) {
case BitwiseAnd: case BitwiseAnd:
*llvm_result = LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "bitwise and"); *llvm_result =
LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "bitwise and");
break; break;
case BitwiseOr: case BitwiseOr:
*llvm_result = LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "bitwise or"); *llvm_result =
LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "bitwise or");
break; break;
case BitwiseXor: case BitwiseXor:
*llvm_result = LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "bitwise xor"); *llvm_result =
LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "bitwise xor");
break; break;
case BitwiseNot: case BitwiseNot:
*llvm_result = LLVMBuildNot(builder, llvm_rhs, "bitwise not"); *llvm_result = LLVMBuildNot(builder, llvm_rhs, "bitwise not");
@ -50,15 +53,15 @@ BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit,
/** /**
* @brief Convert any integral type (integer) to a boolean value. * @brief Convert any integral type (integer) to a boolean value.
* A boolean value hereby meaning an integer of the same type as the input * A boolean value hereby meaning an integer of the same type as the
* value but with the value of either 0 or one. * input value but with the value of either 0 or one.
* @param builder * @param builder
* @param integral * @param integral
* @return * @return
*/ */
[[maybe_unused]] [[maybe_unused]]
static LLVMValueRef convert_integral_to_boolean( static LLVMValueRef convert_integral_to_boolean(LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMValueRef integral) { LLVMValueRef integral) {
// type of input // type of input
LLVMTypeRef valueType = LLVMTypeOf(integral); LLVMTypeRef valueType = LLVMTypeOf(integral);
// zero value of same type as integral // zero value of same type as integral
@ -92,13 +95,16 @@ BackendError impl_logical_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.logical) { switch (operation->impl.logical) {
case LogicalAnd: case LogicalAnd:
*llvm_result = LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "logical and"); *llvm_result =
LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "logical and");
break; break;
case LogicalOr: case LogicalOr:
*llvm_result = LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "logical or"); *llvm_result =
LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "logical or");
break; break;
case LogicalXor: case LogicalXor:
*llvm_result = LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "logical xor"); *llvm_result =
LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "logical xor");
break; break;
case LogicalNot: case LogicalNot:
*llvm_result = LLVMBuildNot(builder, llvm_rhs, "logical not"); *llvm_result = LLVMBuildNot(builder, llvm_rhs, "logical not");
@ -165,7 +171,8 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
break; break;
} }
*llvm_result = LLVMBuildICmp(builder, operator, llvm_lhs, llvm_rhs, "integral comparison"); *llvm_result = LLVMBuildICmp(builder, operator, llvm_lhs, llvm_rhs,
"integral comparison");
} else if (is_floating_point(rhs->result)) { } else if (is_floating_point(rhs->result)) {
// integral type // integral type
@ -183,7 +190,8 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
break; break;
} }
*llvm_result = LLVMBuildFCmp(builder, operator, llvm_lhs, llvm_rhs, "floating point comparison"); *llvm_result = LLVMBuildFCmp(builder, operator, llvm_lhs, llvm_rhs,
"floating point comparison");
} else { } else {
PANIC("invalid type for relational operator"); PANIC("invalid type for relational operator");
} }
@ -220,19 +228,24 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.arithmetic) { switch (operation->impl.arithmetic) {
case Add: case Add:
*llvm_result = LLVMBuildNSWAdd(builder, llvm_lhs, llvm_rhs, "signed integer addition"); *llvm_result = LLVMBuildNSWAdd(builder, llvm_lhs, llvm_rhs,
"signed integer addition");
break; break;
case Sub: case Sub:
*llvm_result = LLVMBuildNSWSub(builder, llvm_lhs, llvm_rhs, "signed integer subtraction"); *llvm_result = LLVMBuildNSWSub(builder, llvm_lhs, llvm_rhs,
"signed integer subtraction");
break; break;
case Mul: case Mul:
*llvm_result = LLVMBuildNSWMul(builder, llvm_lhs, llvm_rhs, "signed integer multiply"); *llvm_result = LLVMBuildNSWMul(builder, llvm_lhs, llvm_rhs,
"signed integer multiply");
break; break;
case Div: case Div:
*llvm_result = LLVMBuildSDiv(builder, llvm_lhs, llvm_rhs, "signed integer divide"); *llvm_result = LLVMBuildSDiv(builder, llvm_lhs, llvm_rhs,
"signed integer divide");
break; break;
case Negate: case Negate:
*llvm_result = LLVMBuildNeg(builder, llvm_rhs, "signed integer negate"); *llvm_result =
LLVMBuildNeg(builder, llvm_rhs, "signed integer negate");
break; break;
} }
@ -240,19 +253,24 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.arithmetic) { switch (operation->impl.arithmetic) {
case Add: case Add:
*llvm_result = LLVMBuildFAdd(builder, llvm_lhs, llvm_rhs, "floating point addition"); *llvm_result = LLVMBuildFAdd(builder, llvm_lhs, llvm_rhs,
"floating point addition");
break; break;
case Sub: case Sub:
*llvm_result = LLVMBuildFSub(builder, llvm_lhs, llvm_rhs, "floating point subtraction"); *llvm_result = LLVMBuildFSub(builder, llvm_lhs, llvm_rhs,
"floating point subtraction");
break; break;
case Mul: case Mul:
*llvm_result = LLVMBuildFMul(builder, llvm_lhs, llvm_rhs, "floating point multiply"); *llvm_result = LLVMBuildFMul(builder, llvm_lhs, llvm_rhs,
"floating point multiply");
break; break;
case Div: case Div:
*llvm_result = LLVMBuildFDiv(builder, llvm_lhs, llvm_rhs, "floating point divide"); *llvm_result = LLVMBuildFDiv(builder, llvm_lhs, llvm_rhs,
"floating point divide");
break; break;
case Negate: case Negate:
*llvm_result = LLVMBuildFNeg(builder, llvm_rhs, "floating point negate"); *llvm_result =
LLVMBuildFNeg(builder, llvm_rhs, "floating point negate");
break; break;
} }
@ -324,8 +342,7 @@ static LLVMBool is_type_signed(const Type *type) {
BackendError impl_typecast(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope, BackendError impl_typecast(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, TypeCast* typecast, LLVMBuilderRef builder, TypeCast* typecast,
bool reference, bool reference, LLVMValueRef* llvm_result) {
LLVMValueRef *llvm_result) {
LLVMValueRef operand = NULL; LLVMValueRef operand = NULL;
impl_expr(unit, scope, builder, typecast->operand, reference, 0, &operand); impl_expr(unit, scope, builder, typecast->operand, reference, 0, &operand);
@ -347,9 +364,9 @@ BackendError impl_typecast(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
return err; return err;
} }
BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_variable_load(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, Variable *variable, LLVMLocalScope* scope, LLVMBuilderRef builder,
LLVMBool reference, Variable* variable, LLVMBool reference,
LLVMValueRef* llvm_result) { LLVMValueRef* llvm_result) {
LLVMValueRef llvm_variable = get_variable(scope, variable->name); LLVMValueRef llvm_variable = get_variable(scope, variable->name);
@ -363,7 +380,8 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
} }
if (llvm_variable == NULL) { if (llvm_variable == NULL) {
return new_backend_impl_error(Implementation, NULL, "Variable not found"); return new_backend_impl_error(Implementation, NULL,
"Variable not found");
} }
if (reference) { if (reference) {
@ -379,7 +397,8 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type); get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) { if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
*llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, ""); *llvm_result =
LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
} else { } else {
*llvm_result = llvm_variable; *llvm_result = llvm_variable;
} }
@ -388,14 +407,15 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
return SUCCESS; return SUCCESS;
} }
BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_parameter_load(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, Parameter *parameter, LLVMLocalScope* scope, LLVMBuilderRef builder,
LLVMBool reference, Parameter* parameter, LLVMBool reference,
LLVMValueRef* llvm_result) { LLVMValueRef* llvm_result) {
LLVMValueRef llvm_variable = NULL; LLVMValueRef llvm_variable = NULL;
if (g_hash_table_contains(scope->func_scope->params, parameter->name)) { if (g_hash_table_contains(scope->func_scope->params, parameter->name)) {
llvm_variable = g_hash_table_lookup(scope->func_scope->params, parameter->name); llvm_variable =
g_hash_table_lookup(scope->func_scope->params, parameter->name);
} }
Type* type; Type* type;
@ -410,7 +430,8 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
type = decl.type; type = decl.type;
if (llvm_variable == NULL) { if (llvm_variable == NULL) {
return new_backend_impl_error(Implementation, NULL, "Variable not found"); return new_backend_impl_error(Implementation, NULL,
"Variable not found");
} }
if (decl.qualifier == In || reference) { if (decl.qualifier == In || reference) {
@ -422,7 +443,8 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type); get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) { if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
*llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, ""); *llvm_result =
LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
} else { } else {
*llvm_result = llvm_variable; *llvm_result = llvm_variable;
} }
@ -431,11 +453,12 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
return SUCCESS; return SUCCESS;
} }
BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope, BackendError impl_address_of(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, AddressOf* addressOf, LLVMLocalScope* scope, LLVMBuilderRef builder,
LLVMValueRef *llvm_result) { AddressOf* addressOf, LLVMValueRef* llvm_result) {
BackendError err = impl_expr(unit, scope, builder, addressOf->variable, TRUE, 0, llvm_result); BackendError err = impl_expr(unit, scope, builder, addressOf->variable,
TRUE, 0, llvm_result);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
@ -446,33 +469,38 @@ BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope
BackendError impl_deref(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope, BackendError impl_deref(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Dereference* dereference, LLVMBuilderRef builder, Dereference* dereference,
bool reference, bool reference, uint32_t deref_depth,
uint32_t deref_depth,
LLVMValueRef* llvm_result) { LLVMValueRef* llvm_result) {
BackendError err; BackendError err;
LLVMValueRef llvm_pointer = NULL; LLVMValueRef llvm_pointer = NULL;
err = impl_expr(unit, scope, builder, dereference->variable, false, deref_depth + 1, &llvm_pointer); err = impl_expr(unit, scope, builder, dereference->variable, false,
deref_depth + 1, &llvm_pointer);
if (err.kind != Success) { if (err.kind != Success) {
return err; 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) {
return err; return err;
} }
LLVMValueRef* index = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef)); LLVMValueRef* index = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef));
err = impl_expr(unit, scope, builder, dereference->index, FALSE, deref_depth + 1, index); err = impl_expr(unit, scope, builder, dereference->index, FALSE,
deref_depth + 1, index);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
*llvm_result = LLVMBuildGEP2(builder, llvm_deref_type, llvm_pointer, index, 1, "expr.deref.gep2"); *llvm_result = LLVMBuildGEP2(builder, llvm_deref_type, llvm_pointer, index,
1, "expr.deref.gep2");
if (!reference || deref_depth > 0) { if (!reference || deref_depth > 0) {
*llvm_result = LLVMBuildLoad2(builder, llvm_deref_type, *llvm_result, "expr.deref.load"); *llvm_result = LLVMBuildLoad2(builder, llvm_deref_type, *llvm_result,
"expr.deref.load");
} }
return err; return err;
@ -480,8 +508,7 @@ BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope, BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Expression* expr, LLVMBuilderRef builder, Expression* expr,
LLVMBool reference, LLVMBool reference, uint32_t deref_depth,
uint32_t deref_depth,
LLVMValueRef* llvm_result) { LLVMValueRef* llvm_result) {
DEBUG("implementing expression: %ld", expr->kind); DEBUG("implementing expression: %ld", expr->kind);
BackendError err = SUCCESS; BackendError err = SUCCESS;
@ -497,8 +524,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break; break;
case ExpressionKindTypeCast: case ExpressionKindTypeCast:
err = impl_typecast(unit, scope, builder, &expr->impl.typecast, err = impl_typecast(unit, scope, builder, &expr->impl.typecast,
reference, reference, llvm_result);
llvm_result);
break; break;
case ExpressionKindOperation: case ExpressionKindOperation:
err = impl_operation(unit, scope, builder, &expr->impl.operation, err = impl_operation(unit, scope, builder, &expr->impl.operation,
@ -506,13 +532,12 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break; break;
case ExpressionKindVariable: case ExpressionKindVariable:
err = impl_variable_load(unit, scope, builder, expr->impl.variable, err = impl_variable_load(unit, scope, builder, expr->impl.variable,
reference, reference, llvm_result);
llvm_result);
break; break;
case ExpressionKindParameter: case ExpressionKindParameter:
err = impl_parameter_load(unit, scope, builder, expr->impl.parameter, err =
reference, impl_parameter_load(unit, scope, builder, expr->impl.parameter,
llvm_result); reference, llvm_result);
break; 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,
@ -520,15 +545,15 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break; break;
case ExpressionKindDereference: case ExpressionKindDereference:
err = impl_deref(unit, scope, builder, &expr->impl.dereference, err = impl_deref(unit, scope, builder, &expr->impl.dereference,
reference, reference, deref_depth, llvm_result);
deref_depth,
llvm_result);
break; break;
case ExpressionKindFunctionCall: case ExpressionKindFunctionCall:
err = impl_func_call(unit, builder, scope, expr->impl.call, llvm_result); err = impl_func_call(unit, builder, scope, expr->impl.call,
llvm_result);
break; break;
default: default:
err = new_backend_impl_error(Implementation, NULL, "unknown expression"); err = new_backend_impl_error(Implementation, NULL,
"unknown expression");
break; break;
} }

View File

@ -12,8 +12,7 @@
BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope, BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Expression* expr, LLVMBuilderRef builder, Expression* expr,
LLVMBool reference, LLVMBool reference, uint32_t deref_depth,
uint32_t deref_depth,
LLVMValueRef* llvm_result); LLVMValueRef* llvm_result);
#endif // LLVM_BACKEND_EXPR_H #endif // LLVM_BACKEND_EXPR_H

View File

@ -2,15 +2,15 @@
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Types.h> #include <llvm-c/Types.h>
#include <llvm/llvm-ir/expr.h>
#include <llvm/llvm-ir/func.h> #include <llvm/llvm-ir/func.h>
#include <llvm/parser.h>
#include <llvm/llvm-ir/types.h>
#include <llvm/llvm-ir/stmt.h> #include <llvm/llvm-ir/stmt.h>
#include <llvm/llvm-ir/types.h>
#include <llvm/llvm-ir/variables.h> #include <llvm/llvm-ir/variables.h>
#include <llvm/parser.h>
#include <mem/cache.h>
#include <set/types.h> #include <set/types.h>
#include <sys/log.h> #include <sys/log.h>
#include <mem/cache.h>
#include <llvm/llvm-ir/expr.h>
LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) { LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) {
LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope)); LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope));
@ -27,8 +27,7 @@ void delete_local_scope(LLVMLocalScope* scope) {
free(scope); free(scope);
} }
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);
} }
@ -45,7 +44,8 @@ LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* name) {
return get_variable(scope->parent_scope, name); return get_variable(scope->parent_scope, name);
} }
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;
} }
@ -63,7 +63,8 @@ LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name) {
return TRUE; return TRUE;
} }
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 != NULL; return global_var != NULL;
} }
@ -104,7 +105,8 @@ 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 = mem_new_g_array(MemoryNamespaceLlvm, 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) {
@ -131,17 +133,19 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
LLVMTypeRef llvm_return_type = LLVMVoidTypeInContext(unit->context); LLVMTypeRef llvm_return_type = LLVMVoidTypeInContext(unit->context);
if (func->kind == FunctionDeclarationKind) { if (func->kind == FunctionDeclarationKind) {
if (func->impl.declaration.return_value != NULL) { if (func->impl.declaration.return_value != NULL) {
err = get_type_impl(unit, scope, func->impl.declaration.return_value, &llvm_return_type); err =
get_type_impl(unit, scope, func->impl.declaration.return_value,
&llvm_return_type);
} }
} else { } else {
if (func->impl.definition.return_value != NULL) { if (func->impl.definition.return_value != NULL) {
err = get_type_impl(unit, scope, func->impl.definition.return_value, &llvm_return_type); err = get_type_impl(unit, scope, func->impl.definition.return_value,
&llvm_return_type);
} }
} }
LLVMTypeRef llvm_fun_type = LLVMTypeRef llvm_fun_type = LLVMFunctionType(
LLVMFunctionType(llvm_return_type, llvm_return_type, (LLVMTypeRef*) llvm_params->data, llvm_params->len, 0);
(LLVMTypeRef*)llvm_params->data, llvm_params->len, 0);
*llvm_fun = LLVMAddFunction(unit->module, func->name, llvm_fun_type); *llvm_fun = LLVMAddFunction(unit->module, func->name, llvm_fun_type);
@ -151,8 +155,8 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
} }
BackendError impl_func_def(LLVMBackendCompileUnit* unit, BackendError impl_func_def(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* global_scope, LLVMGlobalScope* global_scope, Function* func,
Function* func, const char* name) { const char* name) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, name); LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, name);
@ -174,35 +178,42 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
// create value references for parameter // create value references for parameter
for (guint i = 0; i < func->impl.definition.parameter->len; i++) { for (guint i = 0; i < func->impl.definition.parameter->len; i++) {
Parameter* param = &g_array_index(func->impl.definition.parameter, Parameter, i); Parameter* param =
&g_array_index(func->impl.definition.parameter, Parameter, i);
LLVMValueRef llvm_param = LLVMGetParam(llvm_func, i); LLVMValueRef llvm_param = LLVMGetParam(llvm_func, i);
if (llvm_param == NULL) { if (llvm_param == NULL) {
return new_backend_impl_error(Implementation, NULL, "invalid parameter"); return new_backend_impl_error(Implementation, NULL,
"invalid parameter");
} }
g_hash_table_insert(func_scope->params, (gpointer)param->name, llvm_param); g_hash_table_insert(func_scope->params, (gpointer) param->name,
llvm_param);
} }
LLVMBasicBlockRef llvm_start_body_block = NULL; LLVMBasicBlockRef llvm_start_body_block = NULL;
LLVMBasicBlockRef llvm_end_body_block = NULL; LLVMBasicBlockRef llvm_end_body_block = NULL;
err = impl_block(unit, builder, func_scope, &llvm_start_body_block, &llvm_end_body_block, func->impl.definition.body); err = impl_block(unit, builder, func_scope, &llvm_start_body_block,
&llvm_end_body_block, func->impl.definition.body);
if (err.kind == Success) { if (err.kind == Success) {
LLVMPositionBuilderAtEnd(builder, entry); LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuildBr(builder, llvm_start_body_block); LLVMBuildBr(builder, llvm_start_body_block);
LLVMValueRef terminator = LLVMGetBasicBlockTerminator(llvm_end_body_block); LLVMValueRef terminator =
LLVMGetBasicBlockTerminator(llvm_end_body_block);
if (terminator == NULL) { if (terminator == NULL) {
// insert returning end block // insert returning end block
LLVMBasicBlockRef end_block = LLVMBasicBlockRef end_block = LLVMAppendBasicBlockInContext(
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end"); unit->context, llvm_func, "func.end");
LLVMPositionBuilderAtEnd(builder, end_block); LLVMPositionBuilderAtEnd(builder, end_block);
LLVMValueRef llvm_return = NULL; LLVMValueRef llvm_return = NULL;
if (func->kind == FunctionDeclarationKind) { if (func->kind == FunctionDeclarationKind) {
if (func->impl.declaration.return_value != NULL) { if (func->impl.declaration.return_value != NULL) {
err = get_type_default_value(unit, global_scope, func->impl.declaration.return_value, &llvm_return); err = get_type_default_value(
unit, global_scope,
func->impl.declaration.return_value, &llvm_return);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -212,7 +223,9 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
} }
} else { } else {
if (func->impl.definition.return_value != NULL) { if (func->impl.definition.return_value != NULL) {
err = get_type_default_value(unit, global_scope, func->impl.definition.return_value, &llvm_return); err = get_type_default_value(
unit, global_scope,
func->impl.definition.return_value, &llvm_return);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -237,7 +250,8 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
} }
BackendError impl_function_types(LLVMBackendCompileUnit* unit, BackendError impl_function_types(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, GHashTable* functions) { LLVMGlobalScope* scope,
GHashTable* functions) {
DEBUG("implementing functions..."); DEBUG("implementing functions...");
GHashTableIter iterator; GHashTableIter iterator;
g_hash_table_iter_init(&iterator, functions); g_hash_table_iter_init(&iterator, functions);
@ -289,10 +303,11 @@ gboolean is_parameter_out(Parameter *param) {
gboolean is_out = FALSE; gboolean is_out = FALSE;
if (param->kind == ParameterDeclarationKind) { if (param->kind == ParameterDeclarationKind) {
is_out = param->impl.declaration.qualifier == Out || param->impl.declaration.qualifier == InOut; is_out = param->impl.declaration.qualifier == Out
|| param->impl.declaration.qualifier == InOut;
} else { } else {
is_out = param->impl.definiton.declaration.qualifier == Out || is_out = param->impl.definiton.declaration.qualifier == Out
param->impl.definiton.declaration.qualifier == InOut; || param->impl.definiton.declaration.qualifier == InOut;
} }
return is_out; return is_out;
@ -310,7 +325,8 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
// prevent memory allocation when number of bytes would be zero // prevent memory allocation when number of bytes would be zero
// avoid going of assertion in memory cache // avoid going of assertion in memory cache
if (call->expressions->len > 0) { if (call->expressions->len > 0) {
arguments = mem_alloc(MemoryNamespaceLlvm, sizeof(LLVMValueRef) * call->expressions->len); arguments = mem_alloc(MemoryNamespaceLlvm,
sizeof(LLVMValueRef) * call->expressions->len);
for (size_t i = 0; i < call->expressions->len; i++) { for (size_t i = 0; i < call->expressions->len; i++) {
Expression* arg = g_array_index(call->expressions, Expression*, i); Expression* arg = g_array_index(call->expressions, Expression*, i);
@ -325,18 +341,24 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
Parameter param = g_array_index(param_list, Parameter, i); Parameter param = g_array_index(param_list, Parameter, i);
LLVMValueRef llvm_arg = NULL; LLVMValueRef llvm_arg = NULL;
err = impl_expr(unit, scope, builder, arg, is_parameter_out(&param), 0, &llvm_arg); err = impl_expr(unit, scope, builder, arg, is_parameter_out(&param),
0, &llvm_arg);
if (err.kind != Success) { if (err.kind != Success) {
break; break;
} }
if (is_parameter_out(&param)) { if (is_parameter_out(&param)) {
if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) { if ((arg->kind == ExpressionKindParameter
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false); && !is_parameter_out(arg->impl.parameter))
|| arg->kind != ExpressionKindParameter) {
LLVMValueRef index =
LLVMConstInt(LLVMInt32Type(), 0, false);
LLVMTypeRef llvm_type = NULL; LLVMTypeRef llvm_type = NULL;
get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type); get_type_impl(unit, scope->func_scope->global_scope,
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, ""); param.impl.declaration.type, &llvm_type);
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg,
&index, 1, "");
} }
} }
@ -345,16 +367,20 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
} }
if (err.kind == Success) { if (err.kind == Success) {
LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, call->function->name); LLVMValueRef llvm_func =
LLVMGetNamedFunction(unit->module, call->function->name);
if (llvm_func == NULL) { if (llvm_func == NULL) {
return new_backend_impl_error(Implementation, NULL, "no declared function"); return new_backend_impl_error(Implementation, NULL,
"no declared function");
} }
LLVMTypeRef llvm_func_type = g_hash_table_lookup(scope->func_scope->global_scope->functions, call->function->name); LLVMTypeRef llvm_func_type = g_hash_table_lookup(
scope->func_scope->global_scope->functions, call->function->name);
LLVMValueRef value = LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments, call->expressions->len, LLVMValueRef value =
""); LLVMBuildCall2(builder, llvm_func_type, llvm_func, arguments,
call->expressions->len, "");
if (NULL != return_value) { if (NULL != return_value) {
*return_value = value; *return_value = value;
@ -363,4 +389,3 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
return err; return err;
} }

View File

@ -2,9 +2,8 @@
#ifndef LLVM_BACKEND_FUNC_H_ #ifndef LLVM_BACKEND_FUNC_H_
#define LLVM_BACKEND_FUNC_H_ #define LLVM_BACKEND_FUNC_H_
#include <llvm/parser.h>
#include <glib.h> #include <glib.h>
#include <llvm/parser.h>
typedef struct LLVMFuncScope_t { typedef struct LLVMFuncScope_t {
LLVMGlobalScope* global_scope; LLVMGlobalScope* global_scope;
@ -33,12 +32,10 @@ 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,
LLVMGlobalScope* scope, LLVMGlobalScope* scope, GHashTable* variables);
GHashTable* variables);
BackendError impl_functions(LLVMBackendCompileUnit* unit, BackendError impl_functions(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, LLVMGlobalScope* scope, GHashTable* variables);
GHashTable* variables);
BackendError impl_func_call(LLVMBackendCompileUnit* unit, BackendError impl_func_call(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope, LLVMBuilderRef builder, LLVMLocalScope* scope,

View File

@ -2,42 +2,41 @@
// Created by servostar on 5/28/24. // Created by servostar on 5/28/24.
// //
#include <assert.h>
#include <codegen/backend.h> #include <codegen/backend.h>
#include <sys/log.h>
#include <llvm/parser.h>
#include <llvm/llvm-ir/stmt.h>
#include <llvm/llvm-ir/expr.h> #include <llvm/llvm-ir/expr.h>
#include <llvm/llvm-ir/func.h> #include <llvm/llvm-ir/func.h>
#include <llvm/llvm-ir/stmt.h>
#include <llvm/llvm-ir/types.h> #include <llvm/llvm-ir/types.h>
#include <assert.h> #include <llvm/parser.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <sys/log.h>
BackendError impl_param_load( BackendError impl_param_load(LLVMBackendCompileUnit* unit,
LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope* scope,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
const StorageExpr* expr, const StorageExpr* expr,
LLVMValueRef* storage_target) { LLVMValueRef* storage_target) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
if (expr->impl.parameter->impl.declaration.qualifier == Out || expr->impl.parameter->impl.declaration.qualifier == InOut) { if (expr->impl.parameter->impl.declaration.qualifier == Out
|| expr->impl.parameter->impl.declaration.qualifier == InOut) {
LLVMTypeRef llvm_type = NULL; LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.parameter->impl.declaration.type, &llvm_type); err = get_type_impl(unit, scope->func_scope->global_scope,
expr->impl.parameter->impl.declaration.type,
&llvm_type);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
*storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target, "strg.param.out.load"); *storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target,
"strg.param.out.load");
} }
return err; return err;
} }
BackendError impl_storage_expr( BackendError impl_storage_expr(LLVMBackendCompileUnit* unit,
LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope* scope,
LLVMBuilderRef
builder,
LLVMLocalScope *scope,
const StorageExpr* expr, const StorageExpr* expr,
LLVMValueRef* storage_target) { LLVMValueRef* storage_target) {
@ -45,8 +44,7 @@ BackendError impl_storage_expr(
switch (expr->kind) { switch (expr->kind) {
case StorageExprKindVariable: case StorageExprKindVariable:
*storage_target = *storage_target = get_variable(scope, expr->impl.variable->name);
get_variable(scope, expr->impl.variable->name);
break; break;
case StorageExprKindParameter: case StorageExprKindParameter:
*storage_target = *storage_target =
@ -55,19 +53,23 @@ BackendError impl_storage_expr(
case StorageExprKindDereference: case StorageExprKindDereference:
LLVMValueRef index = NULL; LLVMValueRef index = NULL;
err = impl_expr(unit, scope, builder, expr->impl.dereference.index, false, 0, &index); err = impl_expr(unit, scope, builder, expr->impl.dereference.index,
false, 0, &index);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
LLVMValueRef array = NULL; LLVMValueRef array = NULL;
err = impl_storage_expr(unit, builder, scope, expr->impl.dereference.array, &array); err = impl_storage_expr(unit, builder, scope,
expr->impl.dereference.array, &array);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
if (expr->impl.dereference.array->kind == StorageExprKindParameter) { if (expr->impl.dereference.array->kind
err = impl_param_load(unit, builder, scope, expr->impl.dereference.array, &array); == StorageExprKindParameter) {
err = impl_param_load(unit, builder, scope,
expr->impl.dereference.array, &array);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -75,21 +77,26 @@ BackendError impl_storage_expr(
if (true) { if (true) {
LLVMTypeRef deref_type = NULL; LLVMTypeRef deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.dereference.array->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;
} }
array = LLVMBuildLoad2(builder, deref_type, array, "strg.deref.indirect-load"); array = LLVMBuildLoad2(builder, deref_type, array,
"strg.deref.indirect-load");
} }
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->target_type, &deref_type);
if (err.kind != Success) { if (err.kind != Success) {
return err; 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;
case StorageExprKindBoxAccess: case StorageExprKindBoxAccess:
@ -100,24 +107,22 @@ BackendError impl_storage_expr(
return err; return err;
} }
BackendError impl_assign_stmt( BackendError impl_assign_stmt(LLVMBackendCompileUnit* unit,
LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope* scope,
LLVMBuilderRef const Assignment* assignment) {
builder,
LLVMLocalScope *scope,
const Assignment *assignment
) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
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, false, 0, &llvm_value); err =
impl_expr(unit, scope, builder, assignment->value, false, 0, &llvm_value);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
LLVMValueRef llvm_array = NULL; LLVMValueRef llvm_array = NULL;
err = impl_storage_expr(unit, builder, scope, assignment->destination, &llvm_array); err = impl_storage_expr(unit, builder, scope, assignment->destination,
&llvm_array);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -129,14 +134,16 @@ BackendError impl_assign_stmt(
BackendError impl_basic_block(LLVMBackendCompileUnit* unit, BackendError impl_basic_block(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope, LLVMBuilderRef builder, LLVMLocalScope* scope,
const Block *block, LLVMBasicBlockRef *llvm_start_block, LLVMBasicBlockRef *llvm_end_block) { const Block* block,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block) {
DEBUG("implementing basic block..."); DEBUG("implementing basic block...");
BackendError err = SUCCESS; BackendError err = SUCCESS;
LLVMLocalScope* block_scope = new_local_scope(scope); LLVMLocalScope* block_scope = new_local_scope(scope);
// append a new LLVM basic block // append a new LLVM basic block
*llvm_start_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, *llvm_start_block = LLVMAppendBasicBlockInContext(
"stmt.block.start"); unit->context, scope->func_scope->llvm_func, "stmt.block.start");
LLVMPositionBuilderAtEnd(builder, *llvm_start_block); LLVMPositionBuilderAtEnd(builder, *llvm_start_block);
LLVMBasicBlockRef end_previous_block = *llvm_start_block; LLVMBasicBlockRef end_previous_block = *llvm_start_block;
@ -149,7 +156,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
LLVMBasicBlockRef llvm_next_start_block = NULL; LLVMBasicBlockRef llvm_next_start_block = NULL;
LLVMBasicBlockRef llvm_next_end_block = NULL; LLVMBasicBlockRef llvm_next_end_block = NULL;
err = impl_stmt(unit, builder, scope, stmt, &llvm_next_start_block, &llvm_next_end_block); err = impl_stmt(unit, builder, scope, stmt, &llvm_next_start_block,
&llvm_next_end_block);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -164,8 +172,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
} }
if (terminated) { if (terminated) {
end_previous_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, end_previous_block = LLVMAppendBasicBlockInContext(
"ret.after"); unit->context, scope->func_scope->llvm_func, "ret.after");
LLVMPositionBuilderAtEnd(builder, end_previous_block); LLVMPositionBuilderAtEnd(builder, end_previous_block);
} }
} }
@ -177,8 +185,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError impl_while(LLVMBackendCompileUnit *unit, BackendError impl_while(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope *scope, LLVMLocalScope* scope,
LLVMBasicBlockRef* llvm_start_block, LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block, LLVMBasicBlockRef* llvm_end_block,
const While* while_stmt) { const While* while_stmt) {
@ -186,13 +194,14 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
BackendError err; BackendError err;
// Create condition block // Create condition block
LLVMBasicBlockRef while_cond_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, LLVMBasicBlockRef while_cond_block = LLVMAppendBasicBlockInContext(
"loop.while.cond"); unit->context, scope->func_scope->llvm_func, "loop.while.cond");
*llvm_start_block = while_cond_block; *llvm_start_block = while_cond_block;
LLVMPositionBuilderAtEnd(builder, while_cond_block); LLVMPositionBuilderAtEnd(builder, while_cond_block);
// Resolve condition in block to a variable // Resolve condition in block to a variable
LLVMValueRef cond_result = NULL; LLVMValueRef cond_result = NULL;
err = impl_expr(unit, scope, builder, (Expression *) while_stmt->conditon, FALSE, 0, &cond_result); err = impl_expr(unit, scope, builder, (Expression*) while_stmt->conditon,
FALSE, 0, &cond_result);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -200,7 +209,8 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
// build body of loop // build body of loop
LLVMBasicBlockRef while_start_body_block = NULL; LLVMBasicBlockRef while_start_body_block = NULL;
LLVMBasicBlockRef while_end_body_block = NULL; LLVMBasicBlockRef while_end_body_block = NULL;
err = impl_basic_block(unit, builder, scope, &while_stmt->block, &while_start_body_block, &while_end_body_block); err = impl_basic_block(unit, builder, scope, &while_stmt->block,
&while_start_body_block, &while_end_body_block);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -210,11 +220,12 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
LLVMBuildBr(builder, while_cond_block); LLVMBuildBr(builder, while_cond_block);
// builder will continue after the loop // builder will continue after the loop
LLVMBasicBlockRef while_after_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, LLVMBasicBlockRef while_after_block = LLVMAppendBasicBlockInContext(
"loop.while.after"); unit->context, scope->func_scope->llvm_func, "loop.while.after");
// build conditional branch at end of condition block // build conditional branch at end of condition block
LLVMPositionBuilderAtEnd(builder, while_cond_block); LLVMPositionBuilderAtEnd(builder, while_cond_block);
LLVMBuildCondBr(builder, cond_result, while_start_body_block, while_after_block); LLVMBuildCondBr(builder, cond_result, while_start_body_block,
while_after_block);
LLVMPositionBuilderAtEnd(builder, while_after_block); LLVMPositionBuilderAtEnd(builder, while_after_block);
@ -223,35 +234,41 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError BackendError impl_cond_block(LLVMBackendCompileUnit* unit,
impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Expression *cond, LLVMBuilderRef builder, LLVMLocalScope* scope,
const Block *block, LLVMBasicBlockRef *cond_block, LLVMBasicBlockRef *start_body_block, LLVMBasicBlockRef *end_body_block, Expression* cond, const Block* block,
LLVMBasicBlockRef* cond_block,
LLVMBasicBlockRef* start_body_block,
LLVMBasicBlockRef* end_body_block,
LLVMValueRef* llvm_cond) { LLVMValueRef* llvm_cond) {
BackendError err; BackendError err;
*cond_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, *cond_block = LLVMAppendBasicBlockInContext(
"stmt.branch.cond"); unit->context, scope->func_scope->llvm_func, "stmt.branch.cond");
LLVMPositionBuilderAtEnd(builder, *cond_block); LLVMPositionBuilderAtEnd(builder, *cond_block);
// Resolve condition in block to a variable // Resolve condition in block to a variable
err = impl_expr(unit, scope, builder, cond, FALSE, 0, llvm_cond); err = impl_expr(unit, scope, builder, cond, FALSE, 0, llvm_cond);
if (err.kind == Success) { if (err.kind == Success) {
// build body of loop // build body of loop
err = impl_basic_block(unit, builder, scope, block, start_body_block, end_body_block); err = impl_basic_block(unit, builder, scope, block, start_body_block,
end_body_block);
} }
return err; return err;
} }
BackendError impl_branch(LLVMBackendCompileUnit *unit, BackendError impl_branch(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope *scope, LLVMLocalScope* scope,
LLVMBasicBlockRef* branch_start_block, LLVMBasicBlockRef* branch_start_block,
LLVMBasicBlockRef* branch_end_block, LLVMBasicBlockRef* branch_end_block,
const Branch* branch) { const Branch* branch) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
GArray* cond_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef)); GArray* cond_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef));
GArray *start_body_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef)); GArray* start_body_blocks =
GArray *end_body_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef)); g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef));
GArray* end_body_blocks =
g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef));
GArray* cond_values = g_array_new(FALSE, FALSE, sizeof(LLVMValueRef)); GArray* cond_values = g_array_new(FALSE, FALSE, sizeof(LLVMValueRef));
// add If to arrays // add If to arrays
@ -261,8 +278,8 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
LLVMBasicBlockRef end_body_block = NULL; LLVMBasicBlockRef end_body_block = NULL;
LLVMValueRef cond_value = NULL; LLVMValueRef cond_value = NULL;
err = impl_cond_block(unit, builder, scope, branch->ifBranch.conditon, &branch->ifBranch.block, err = impl_cond_block(unit, builder, scope, branch->ifBranch.conditon,
&cond_block, &branch->ifBranch.block, &cond_block,
&start_body_block, &end_body_block, &cond_value); &start_body_block, &end_body_block, &cond_value);
g_array_append_val(cond_blocks, cond_block); g_array_append_val(cond_blocks, cond_block);
@ -281,8 +298,9 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
ElseIf* elseIf = ((ElseIf*) branch->elseIfBranches->data) + i; ElseIf* elseIf = ((ElseIf*) branch->elseIfBranches->data) + i;
err = impl_cond_block(unit, builder, scope, elseIf->conditon, &elseIf->block, &cond_block, err = impl_cond_block(
&start_body_block, &end_body_block, &cond_value); unit, builder, scope, elseIf->conditon, &elseIf->block,
&cond_block, &start_body_block, &end_body_block, &cond_value);
g_array_append_val(cond_blocks, cond_block); g_array_append_val(cond_blocks, cond_block);
g_array_append_val(start_body_blocks, start_body_block); g_array_append_val(start_body_blocks, start_body_block);
@ -296,13 +314,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
// else block // else block
if (branch->elseBranch.block.statemnts != NULL) { if (branch->elseBranch.block.statemnts != NULL) {
LLVMBasicBlockRef start_else_block = NULL; LLVMBasicBlockRef start_else_block = NULL;
err = impl_basic_block(unit, builder, scope, &branch->elseBranch.block, &start_else_block, &after_block); err = impl_basic_block(unit, builder, scope, &branch->elseBranch.block,
&start_else_block, &after_block);
g_array_append_val(cond_blocks, start_else_block); g_array_append_val(cond_blocks, start_else_block);
} }
if (after_block == NULL) { if (after_block == NULL) {
after_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func, after_block = LLVMAppendBasicBlockInContext(
"stmt.branch.after"); unit->context, scope->func_scope->llvm_func, "stmt.branch.after");
} }
LLVMPositionBuilderAtEnd(builder, after_block); LLVMPositionBuilderAtEnd(builder, after_block);
@ -313,10 +332,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
} }
for (size_t i = 0; i < cond_blocks->len - 1; i++) { for (size_t i = 0; i < cond_blocks->len - 1; i++) {
LLVMBasicBlockRef next_block = g_array_index(cond_blocks, LLVMBasicBlockRef, i + 1); LLVMBasicBlockRef next_block =
LLVMBasicBlockRef cond_block = g_array_index(cond_blocks, LLVMBasicBlockRef, i); g_array_index(cond_blocks, LLVMBasicBlockRef, i + 1);
LLVMBasicBlockRef start_body_block = g_array_index(start_body_blocks, LLVMBasicBlockRef, i); LLVMBasicBlockRef cond_block =
LLVMBasicBlockRef end_body_block = g_array_index(end_body_blocks, LLVMBasicBlockRef, i); g_array_index(cond_blocks, LLVMBasicBlockRef, i);
LLVMBasicBlockRef start_body_block =
g_array_index(start_body_blocks, LLVMBasicBlockRef, i);
LLVMBasicBlockRef end_body_block =
g_array_index(end_body_blocks, LLVMBasicBlockRef, i);
LLVMValueRef cond_value = g_array_index(cond_values, LLVMValueRef, i); LLVMValueRef cond_value = g_array_index(cond_values, LLVMValueRef, i);
LLVMPositionBuilderAtEnd(builder, cond_block); LLVMPositionBuilderAtEnd(builder, cond_block);
@ -337,15 +360,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError impl_decl(LLVMBackendCompileUnit *unit, BackendError impl_decl(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope* scope, VariableDeclaration* decl,
LLVMLocalScope *scope,
VariableDeclaration *decl,
const char* name) { const char* name) {
DEBUG("implementing local declaration: %s", name); DEBUG("implementing local declaration: %s", name);
BackendError err = SUCCESS; BackendError err = SUCCESS;
LLVMTypeRef llvm_type = NULL; LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, decl->type, &llvm_type); err = get_type_impl(unit, scope->func_scope->global_scope, decl->type,
&llvm_type);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
@ -355,7 +377,8 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit,
LLVMValueRef local = LLVMBuildAlloca(builder, llvm_type, name); LLVMValueRef local = LLVMBuildAlloca(builder, llvm_type, name);
LLVMValueRef initial_value = NULL; LLVMValueRef initial_value = NULL;
err = get_type_default_value(unit, scope->func_scope->global_scope, decl->type, &initial_value); err = get_type_default_value(unit, scope->func_scope->global_scope,
decl->type, &initial_value);
if (err.kind == Success) { if (err.kind == Success) {
DEBUG("setting default value..."); DEBUG("setting default value...");
@ -368,10 +391,8 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError impl_return(LLVMBackendCompileUnit *unit, BackendError impl_return(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope* scope, Return* returnStmt) {
LLVMLocalScope *scope,
Return *returnStmt) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
LLVMValueRef expr = NULL; LLVMValueRef expr = NULL;
@ -385,22 +406,22 @@ BackendError impl_return(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError impl_def(LLVMBackendCompileUnit *unit, BackendError impl_def(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope* scope, VariableDefiniton* def,
LLVMLocalScope *scope,
VariableDefiniton *def,
const char* name) { const char* name) {
DEBUG("implementing local definition: %s", name); DEBUG("implementing local definition: %s", name);
BackendError err = SUCCESS; BackendError err = SUCCESS;
LLVMTypeRef llvm_type = NULL; LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, def->declaration.type, &llvm_type); err = get_type_impl(unit, scope->func_scope->global_scope,
def->declaration.type, &llvm_type);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
LLVMValueRef initial_value = NULL; LLVMValueRef initial_value = NULL;
err = impl_expr(unit, scope, builder, def->initializer, FALSE, 0, &initial_value); err = impl_expr(unit, scope, builder, def->initializer, FALSE, 0,
&initial_value);
if (err.kind != Success) { if (err.kind != Success) {
return err; return err;
} }
@ -414,45 +435,52 @@ BackendError impl_def(LLVMBackendCompileUnit *unit,
return err; return err;
} }
BackendError impl_var(LLVMBackendCompileUnit *unit, BackendError impl_var(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMLocalScope* scope, Variable* var) {
LLVMLocalScope *scope,
Variable *var) {
BackendError err; BackendError err;
switch (var->kind) { switch (var->kind) {
case VariableKindDeclaration: case VariableKindDeclaration:
err = impl_decl(unit, builder, scope, &var->impl.declaration, var->name); err = impl_decl(unit, builder, scope, &var->impl.declaration,
var->name);
break; break;
case VariableKindDefinition: case VariableKindDefinition:
err = impl_def(unit, builder, scope, &var->impl.definiton, var->name); err =
impl_def(unit, builder, scope, &var->impl.definiton, var->name);
break; break;
default: default:
err = new_backend_impl_error(Implementation, NULL, "Unexpected variable kind in statement"); err = new_backend_impl_error(
Implementation, NULL, "Unexpected variable kind in statement");
break; break;
} }
return err; return err;
} }
BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Statement *stmt, LLVMBasicBlockRef* llvm_start_block, LLVMBasicBlockRef* llvm_end_block) { BackendError impl_stmt(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope, Statement* stmt,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block) {
assert(stmt != NULL); assert(stmt != NULL);
DEBUG("implementing statement: %ld", stmt->kind); DEBUG("implementing statement: %ld", stmt->kind);
BackendError err; BackendError err;
switch (stmt->kind) { switch (stmt->kind) {
case StatementKindAssignment: case StatementKindAssignment:
err = impl_assign_stmt(unit, builder, scope, &stmt->impl.assignment); err =
impl_assign_stmt(unit, builder, scope, &stmt->impl.assignment);
break; break;
case StatementKindBranch: case StatementKindBranch:
err = impl_branch(unit, builder, scope, llvm_start_block, llvm_end_block, &stmt->impl.branch); err = impl_branch(unit, builder, scope, llvm_start_block,
llvm_end_block, &stmt->impl.branch);
break; break;
case StatementKindDeclaration: case StatementKindDeclaration:
case StatementKindDefinition: case StatementKindDefinition:
err = impl_var(unit, builder, scope, stmt->impl.variable); err = impl_var(unit, builder, scope, stmt->impl.variable);
break; break;
case StatementKindWhile: case StatementKindWhile:
err = impl_while(unit, builder, scope, llvm_start_block, llvm_end_block, &stmt->impl.whileLoop); err = impl_while(unit, builder, scope, llvm_start_block,
llvm_end_block, &stmt->impl.whileLoop);
break; break;
case StatementKindFunctionCall: case StatementKindFunctionCall:
err = impl_func_call(unit, builder, scope, &stmt->impl.call, NULL); err = impl_func_call(unit, builder, scope, &stmt->impl.call, NULL);
@ -461,18 +489,18 @@ BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLV
err = impl_return(unit, builder, scope, &stmt->impl.returnStmt); err = impl_return(unit, builder, scope, &stmt->impl.returnStmt);
break; break;
default: default:
err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind"); err = new_backend_impl_error(Implementation, NULL,
"Unexpected statement kind");
break; break;
} }
return err; return err;
} }
BackendError impl_block(LLVMBackendCompileUnit *unit, BackendError impl_block(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMFuncScope *scope, LLVMFuncScope* scope,
LLVMBasicBlockRef* llvm_start_block, LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block, LLVMBasicBlockRef* llvm_end_block, const Block* block) {
const Block *block) {
DEBUG("Implementing function block..."); DEBUG("Implementing function block...");
BackendError err = SUCCESS; BackendError err = SUCCESS;
@ -481,7 +509,8 @@ BackendError impl_block(LLVMBackendCompileUnit *unit,
function_entry_scope->vars = g_hash_table_new(g_str_hash, g_str_equal); function_entry_scope->vars = g_hash_table_new(g_str_hash, g_str_equal);
function_entry_scope->parent_scope = NULL; function_entry_scope->parent_scope = NULL;
err = impl_basic_block(unit, builder, function_entry_scope, block, llvm_start_block, llvm_end_block); err = impl_basic_block(unit, builder, function_entry_scope, block,
llvm_start_block, llvm_end_block);
delete_local_scope(function_entry_scope); delete_local_scope(function_entry_scope);

View File

@ -7,13 +7,14 @@
#include <llvm/llvm-ir/func.h> #include <llvm/llvm-ir/func.h>
BackendError impl_block(LLVMBackendCompileUnit *unit, BackendError impl_block(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBuilderRef builder, LLVMFuncScope *scope, LLVMFuncScope* scope,
LLVMBasicBlockRef* llvm_start_block, LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block, LLVMBasicBlockRef* llvm_end_block, const Block* block);
const Block *block);
BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Statement *stmt, BackendError impl_stmt(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMBasicBlockRef *llvm_start_block, LLVMBasicBlockRef *llvm_end_block); LLVMLocalScope* scope, Statement* stmt,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block);
#endif // LLVM_BACKEND_STMT_H #endif // LLVM_BACKEND_STMT_H

View File

@ -3,10 +3,10 @@
#include <llvm-c/Types.h> #include <llvm-c/Types.h>
#include <llvm/llvm-ir/types.h> #include <llvm/llvm-ir/types.h>
#include <llvm/parser.h> #include <llvm/parser.h>
#include <mem/cache.h>
#include <set/set.h>
#include <set/types.h> #include <set/types.h>
#include <sys/log.h> #include <sys/log.h>
#include <set/set.h>
#include <mem/cache.h>
#define BASE_BYTES 4 #define BASE_BYTES 4
#define BITS_PER_BYTE 8 #define BITS_PER_BYTE 8
@ -39,28 +39,35 @@ static BackendError get_const_composite_value(CompositeType composite,
llvm_value); llvm_value);
} }
BackendError impl_reference_const(LLVMBackendCompileUnit* unit, TypeValue* value, LLVMValueRef* llvm_value) { BackendError impl_reference_const(LLVMBackendCompileUnit* unit,
TypeValue* value, LLVMValueRef* llvm_value) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
if (compareTypes(value->type, (Type*) &StringLiteralType)) { if (compareTypes(value->type, (Type*) &StringLiteralType)) {
// is string literal // is string literal
LLVMValueRef string_value = LLVMConstString(value->value, strlen(value->value), false); LLVMValueRef string_value =
LLVMConstString(value->value, strlen(value->value), false);
char uuid[9]; char uuid[9];
sprintf(uuid, "%08x", g_str_hash(value->value)); sprintf(uuid, "%08x", g_str_hash(value->value));
LLVMValueRef string_global = LLVMAddGlobal(unit->module, LLVMTypeOf(string_value), uuid); LLVMValueRef string_global =
LLVMAddGlobal(unit->module, LLVMTypeOf(string_value), uuid);
LLVMSetInitializer(string_global, string_value); LLVMSetInitializer(string_global, string_value);
LLVMSetGlobalConstant(string_global, true); LLVMSetGlobalConstant(string_global, true);
LLVMSetUnnamedAddress(string_global, LLVMGlobalUnnamedAddr); LLVMSetUnnamedAddress(string_global, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(string_global, 1); LLVMSetAlignment(string_global, 1);
// Cast the global variable to a pointer type if needed // Cast the global variable to a pointer type if needed
LLVMTypeRef i8_ptr_type = LLVMPointerType(LLVMInt8TypeInContext(unit->context), 0); LLVMTypeRef i8_ptr_type =
LLVMValueRef global_str_ptr = LLVMConstBitCast(string_global, i8_ptr_type); LLVMPointerType(LLVMInt8TypeInContext(unit->context), 0);
LLVMValueRef global_str_ptr =
LLVMConstBitCast(string_global, i8_ptr_type);
*llvm_value = global_str_ptr; *llvm_value = global_str_ptr;
} else { } else {
err = new_backend_impl_error(Implementation, value->nodePtr, "reference initializer can only be string literals"); err = new_backend_impl_error(
Implementation, value->nodePtr,
"reference initializer can only be string literals");
} }
return err; return err;
} }
@ -79,14 +86,14 @@ BackendError get_const_type_value(LLVMBackendCompileUnit* unit,
switch (gemstone_value->type->kind) { switch (gemstone_value->type->kind) {
case TypeKindPrimitive: case TypeKindPrimitive:
err = get_const_primitive_value(gemstone_value->type->impl.primitive, err = get_const_primitive_value(
llvm_type, gemstone_value->value, gemstone_value->type->impl.primitive, llvm_type,
llvm_value); gemstone_value->value, llvm_value);
break; break;
case TypeKindComposite: case TypeKindComposite:
err = get_const_composite_value(gemstone_value->type->impl.composite, err = get_const_composite_value(
llvm_type, gemstone_value->value, gemstone_value->type->impl.composite, llvm_type,
llvm_value); gemstone_value->value, llvm_value);
break; break;
case TypeKindReference: case TypeKindReference:
err = impl_reference_const(unit, gemstone_value, llvm_value); err = impl_reference_const(unit, gemstone_value, llvm_value);
@ -308,10 +315,12 @@ BackendError impl_type(LLVMBackendCompileUnit* unit, Type* gemstone_type,
return err; return err;
} }
BackendError impl_type_define(LLVMBackendCompileUnit* unit, Typedefine* gemstone_type, BackendError impl_type_define(LLVMBackendCompileUnit* unit,
const char* alias, LLVMGlobalScope* scope) { Typedefine* gemstone_type, const char* alias,
LLVMGlobalScope* scope) {
BackendError err = SUCCESS; BackendError err = SUCCESS;
DEBUG("implementing type of kind: %ld as %s", gemstone_type->type->kind, alias); DEBUG("implementing type of kind: %ld as %s", gemstone_type->type->kind,
alias);
err = impl_type(unit, gemstone_type->type, alias, scope); err = impl_type(unit, gemstone_type->type, alias, scope);
@ -330,7 +339,8 @@ BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
BackendError err = SUCCESS; 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);
if (err.kind != Success) { if (err.kind != Success) {
break; break;

View File

@ -1,4 +1,6 @@
#include "expr.h"
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Types.h> #include <llvm-c/Types.h>
@ -7,8 +9,6 @@
#include <set/types.h> #include <set/types.h>
#include <sys/log.h> #include <sys/log.h>
#include "expr.h"
BackendError impl_global_declaration(LLVMBackendCompileUnit* unit, BackendError impl_global_declaration(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, LLVMGlobalScope* scope,
VariableDeclaration* decl, VariableDeclaration* decl,
@ -56,7 +56,8 @@ BackendError impl_global_definiton(LLVMBackendCompileUnit* unit,
// FIXME: resolve initializer expression! // FIXME: resolve initializer expression!
LLVMValueRef initial_value = NULL; LLVMValueRef initial_value = NULL;
err = get_const_type_value(unit, scope, &def->initializer->impl.constant, &initial_value); err = get_const_type_value(unit, scope, &def->initializer->impl.constant,
&initial_value);
if (err.kind == Success) { if (err.kind == Success) {
DEBUG("setting default value"); DEBUG("setting default value");

View File

@ -1,21 +1,21 @@
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Target.h> #include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h> #include <llvm-c/TargetMachine.h>
#include <llvm-c/Types.h> #include <llvm-c/Types.h>
#include <llvm-c/Analysis.h>
#include <llvm/backend.h> #include <llvm/backend.h>
#include <llvm/parser.h> #include <llvm/link/lld.h>
#include <llvm/llvm-ir/func.h>
#include <llvm/llvm-ir/types.h> #include <llvm/llvm-ir/types.h>
#include <llvm/llvm-ir/variables.h> #include <llvm/llvm-ir/variables.h>
#include <llvm/llvm-ir/func.h> #include <llvm/parser.h>
#include <set/types.h> #include <set/types.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/log.h> #include <sys/log.h>
#include <llvm/link/lld.h>
BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target, BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
const TargetConfig* config) { const TargetConfig* config) {
@ -28,7 +28,8 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
char* basename = g_strjoin(".", target->name.str, "ll", NULL); char* basename = g_strjoin(".", target->name.str, "ll", NULL);
// construct file name // construct file name
const char* filename = g_build_filename(config->archive_directory, basename, NULL); const char* filename =
g_build_filename(config->archive_directory, basename, NULL);
INFO("Writing LLVM-IR to %s", filename); INFO("Writing LLVM-IR to %s", filename);
@ -72,11 +73,13 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
switch (file_type) { switch (file_type) {
case LLVMAssemblyFile: case LLVMAssemblyFile:
basename = g_strjoin(".", config->name, "s", NULL); basename = g_strjoin(".", config->name, "s", NULL);
filename = g_build_filename(config->archive_directory, basename, NULL); filename =
g_build_filename(config->archive_directory, basename, NULL);
break; break;
case LLVMObjectFile: case LLVMObjectFile:
basename = g_strjoin(".", config->name, "o", NULL); basename = g_strjoin(".", config->name, "o", NULL);
filename = g_build_filename(config->archive_directory, basename, NULL); filename =
g_build_filename(config->archive_directory, basename, NULL);
break; break;
default: default:
return new_backend_impl_error(Implementation, NULL, return new_backend_impl_error(Implementation, NULL,
@ -86,7 +89,8 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
INFO("export to file: %s", filename); INFO("export to file: %s", filename);
if (LLVMTargetMachineEmitToFile(target_machine, unit->module, filename, if (LLVMTargetMachineEmitToFile(target_machine, unit->module, filename,
file_type, &error) != 0) { file_type, &error)
!= 0) {
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");
@ -120,8 +124,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
LLVMInitializeAllAsmPrinters(); LLVMInitializeAllAsmPrinters();
DEBUG("creating target..."); DEBUG("creating target...");
if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error) != if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error)
0) { != 0) {
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");
@ -145,8 +149,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
return err; return err;
} }
err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error, err =
config); emit_module_to_file(unit, target_machine, LLVMObjectFile, error, config);
LLVMDisposeTargetMachine(target_machine); LLVMDisposeTargetMachine(target_machine);
@ -226,7 +230,8 @@ 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);
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); LLVMDisposeMessage(error);
@ -260,14 +265,16 @@ BackendError parse_module(const Module* module, const TargetConfig* config) {
err = export_module(unit, &target, config); err = export_module(unit, &target, config);
if (err.kind == Success) { if (err.kind == Success) {
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);
if (link_config != NULL) { if (link_config != NULL) {
err = lld_link_target(link_config); err = lld_link_target(link_config);
lld_delete_link_config(link_config); lld_delete_link_config(link_config);
} else { } else {
err = new_backend_impl_error(Implementation, NULL, "libclang error"); err = new_backend_impl_error(Implementation, NULL,
"libclang error");
} }
} }
} }

View File

@ -2,10 +2,10 @@
#ifndef LLVM_BACKEND_PARSE_H_ #ifndef LLVM_BACKEND_PARSE_H_
#define LLVM_BACKEND_PARSE_H_ #define LLVM_BACKEND_PARSE_H_
#include <set/types.h>
#include <codegen/backend.h> #include <codegen/backend.h>
#include <llvm-c/Types.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm-c/Types.h>
#include <set/types.h>
typedef struct LLVMBackendCompileUnit_t { typedef struct LLVMBackendCompileUnit_t {
LLVMContextRef context; LLVMContextRef context;

View File

@ -1,19 +1,21 @@
#include <ast/ast.h> #include <ast/ast.h>
#include <stdlib.h>
#include <sys/log.h>
#include <sys/col.h>
#include <lex/util.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <compiler.h> #include <compiler.h>
#include <lex/util.h>
#include <link/lib.h>
#include <llvm/parser.h> #include <llvm/parser.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <link/lib.h> #include <stdlib.h>
#include <sys/col.h>
#include <sys/log.h>
/** /**
* @brief Log a debug message to inform about beginning exit procedures * @brief Log a debug message to inform about beginning exit procedures
* *
*/ */
void notify_exit(void) { DEBUG("Exiting gemstone..."); } void notify_exit(void) {
DEBUG("Exiting gemstone...");
}
/** /**
* @brief Run compiler setup here * @brief Run compiler setup here

View File

@ -2,12 +2,12 @@
// Created by servostar on 6/5/24. // Created by servostar on 6/5/24.
// //
#include <mem/cache.h>
#include <sys/log.h>
#include <glib.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <glib.h>
#include <mem/cache.h>
#include <string.h>
#include <sys/log.h>
static GHashTable* namespaces = NULL; static GHashTable* namespaces = NULL;
@ -39,16 +39,25 @@ typedef struct MemoryNamespace_t {
typedef MemoryNamespace* MemoryNamespaceRef; typedef MemoryNamespace* MemoryNamespaceRef;
static void namespace_statistics_print(MemoryNamespaceStatistic* memoryNamespaceStatistic, char* name) { static void
namespace_statistics_print(MemoryNamespaceStatistic* memoryNamespaceStatistic,
char* name) {
printf("Memory namespace statistics: `%s`\n", name); printf("Memory namespace statistics: `%s`\n", name);
printf("------------------------------\n"); printf("------------------------------\n");
printf(" allocated bytes: %ld\n", memoryNamespaceStatistic->bytes_allocated); printf(" allocated bytes: %ld\n",
printf(" allocations: %ld\n", memoryNamespaceStatistic->allocation_count); memoryNamespaceStatistic->bytes_allocated);
printf(" reallocations: %ld\n", memoryNamespaceStatistic->reallocation_count); printf(" allocations: %ld\n",
printf(" frees: %ld\n", memoryNamespaceStatistic->manual_free_count); memoryNamespaceStatistic->allocation_count);
printf(" faulty allocations: %ld\n", memoryNamespaceStatistic->faulty_allocations); printf(" reallocations: %ld\n",
printf(" faulty reallocations: %ld\n", memoryNamespaceStatistic->faulty_reallocations); memoryNamespaceStatistic->reallocation_count);
printf(" purged allocations: %ld\n", memoryNamespaceStatistic->purged_free_count); printf(" frees: %ld\n",
memoryNamespaceStatistic->manual_free_count);
printf(" faulty allocations: %ld\n",
memoryNamespaceStatistic->faulty_allocations);
printf(" faulty reallocations: %ld\n",
memoryNamespaceStatistic->faulty_reallocations);
printf(" purged allocations: %ld\n",
memoryNamespaceStatistic->purged_free_count);
printf("\n"); printf("\n");
} }
@ -86,9 +95,11 @@ static void namespace_free_block(MemoryBlock block) {
} }
} }
static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block) { static gboolean namespace_free(MemoryNamespaceRef memoryNamespace,
void* block) {
for (guint i = 0; i < memoryNamespace->blocks->len; i++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
if (current_block.block_ptr == block) { if (current_block.block_ptr == block) {
assert(block != NULL); assert(block != NULL);
@ -105,17 +116,20 @@ static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block)
return FALSE; return FALSE;
} }
static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block, size_t size) { static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block,
size_t size) {
void* reallocated_block = NULL; void* reallocated_block = NULL;
for (guint i = 0; i < memoryNamespace->blocks->len; i++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
if (current_block.block_ptr == block) { if (current_block.block_ptr == block) {
reallocated_block = realloc(current_block.block_ptr, size); reallocated_block = realloc(current_block.block_ptr, size);
if (reallocated_block != NULL) { if (reallocated_block != NULL) {
g_array_index(memoryNamespace->blocks, MemoryBlock, i).block_ptr = reallocated_block; g_array_index(memoryNamespace->blocks, MemoryBlock, i)
.block_ptr = reallocated_block;
memoryNamespace->statistic.bytes_allocated += size; memoryNamespace->statistic.bytes_allocated += size;
memoryNamespace->statistic.reallocation_count++; memoryNamespace->statistic.reallocation_count++;
} else { } else {
@ -137,14 +151,16 @@ static void namespace_delete(MemoryNamespaceRef memoryNamespace) {
static void namespace_purge(MemoryNamespaceRef memoryNamespace) { static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
for (guint i = 0; i < memoryNamespace->blocks->len; i++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
namespace_free_block(current_block); namespace_free_block(current_block);
memoryNamespace->statistic.purged_free_count++; memoryNamespace->statistic.purged_free_count++;
} }
g_array_remove_range(memoryNamespace->blocks, 0, memoryNamespace->blocks->len); g_array_remove_range(memoryNamespace->blocks, 0,
memoryNamespace->blocks->len);
} }
static MemoryNamespaceRef namespace_new() { static MemoryNamespaceRef namespace_new() {
@ -174,7 +190,9 @@ GArray *namespace_new_g_array(MemoryNamespaceRef namespace, guint size) {
return block.block_ptr; return block.block_ptr;
} }
GHashTable *namespace_new_g_hash_table(MemoryNamespaceRef namespace, GHashFunc hash_func, GEqualFunc key_equal_func) { GHashTable* namespace_new_g_hash_table(MemoryNamespaceRef namespace,
GHashFunc hash_func,
GEqualFunc key_equal_func) {
MemoryBlock block; MemoryBlock block;
block.block_ptr = g_hash_table_new(hash_func, key_equal_func); block.block_ptr = g_hash_table_new(hash_func, key_equal_func);
block.kind = GLIB_HashTable; block.kind = GLIB_HashTable;
@ -198,7 +216,8 @@ static void cleanup() {
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
assert(name != NULL); assert(name != NULL);
assert(memoryNamespace != NULL); assert(memoryNamespace != NULL);
@ -261,7 +280,8 @@ void mem_free(void* memory) {
MemoryNamespaceRef memoryNamespace; MemoryNamespaceRef memoryNamespace;
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
if (namespace_free(memoryNamespace, memory)) { if (namespace_free(memoryNamespace, memory)) {
break; break;
@ -306,22 +326,27 @@ void print_memory_statistics() {
total.reallocation_count = 0; total.reallocation_count = 0;
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
namespace_statistics_print(&memoryNamespace->statistic, name); namespace_statistics_print(&memoryNamespace->statistic, name);
total.bytes_allocated += memoryNamespace->statistic.bytes_allocated; total.bytes_allocated += memoryNamespace->statistic.bytes_allocated;
total.faulty_reallocations += memoryNamespace->statistic.faulty_reallocations; total.faulty_reallocations +=
total.faulty_allocations += memoryNamespace->statistic.faulty_allocations; memoryNamespace->statistic.faulty_reallocations;
total.faulty_allocations +=
memoryNamespace->statistic.faulty_allocations;
total.manual_free_count += memoryNamespace->statistic.manual_free_count; total.manual_free_count += memoryNamespace->statistic.manual_free_count;
total.allocation_count += memoryNamespace->statistic.allocation_count; total.allocation_count += memoryNamespace->statistic.allocation_count;
total.purged_free_count += memoryNamespace->statistic.purged_free_count; total.purged_free_count += memoryNamespace->statistic.purged_free_count;
total.reallocation_count += memoryNamespace->statistic.reallocation_count; total.reallocation_count +=
memoryNamespace->statistic.reallocation_count;
} }
namespace_statistics_print(&total, "summary"); namespace_statistics_print(&total, "summary");
printf("Note: untracked are memory allocations from external libraries and non-gc managed components.\n"); printf("Note: untracked are memory allocations from external libraries and "
"non-gc managed components.\n");
} }
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) { GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) {
@ -334,7 +359,8 @@ GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) {
return namespace_new_g_array(cache, element_size); return namespace_new_g_array(cache, element_size);
} }
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func) { GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func,
GEqualFunc key_equal_func) {
MemoryNamespaceRef cache = check_namespace(name); MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) { if (cache == NULL) {

View File

@ -5,9 +5,9 @@
#ifndef GEMSTONE_CACHE_H #ifndef GEMSTONE_CACHE_H
#define GEMSTONE_CACHE_H #define GEMSTONE_CACHE_H
#include <glib.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <stddef.h> #include <stddef.h>
#include <glib.h>
typedef char* MemoryNamespaceName; typedef char* MemoryNamespaceName;
@ -57,8 +57,8 @@ void mem_free_from(MemoryNamespaceName name, void* memory);
/** /**
* @brief Free a block of memory. * @brief Free a block of memory.
* Invoking multiple times on the same pointer will do nothing. * Invoking multiple times on the same pointer will do nothing.
* @attention In case the namespace of the block is known, consider using mem_free_from() * @attention In case the namespace of the block is known, consider using
* to avoid unnecessary overhead. * mem_free_from() to avoid unnecessary overhead.
* @param name * @param name
* @param memory * @param memory
*/ */
@ -91,6 +91,7 @@ void print_memory_statistics();
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size); GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size);
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func); GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func,
GEqualFunc key_equal_func);
#endif // GEMSTONE_CACHE_H #endif // GEMSTONE_CACHE_H

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@
#ifndef SET_TYPES_H_ #ifndef SET_TYPES_H_
#define SET_TYPES_H_ #define SET_TYPES_H_
#include <glib.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <glib.h>
// with of primitive types (int/float) in bytes // with of primitive types (int/float) in bytes
#define BASE_BYTES 4 #define BASE_BYTES 4
@ -67,7 +67,8 @@ typedef struct Type_t Type;
/** /**
* @brief Reference points to a type. * @brief Reference points to a type.
* @attention Can be nested. A reference can point to another reference: REF -> REF -> REF -> Primitive * @attention Can be nested. A reference can point to another reference: REF ->
* REF -> REF -> Primitive
* *
*/ */
typedef Type* ReferenceType; typedef Type* ReferenceType;
@ -101,7 +102,8 @@ typedef struct Variable_t Variable;
typedef struct BoxAccess_t { typedef struct BoxAccess_t {
// list of recursive box accesses // list of recursive box accesses
// contains a list of BoxMembers (each specifying their own type, name and box type) // contains a list of BoxMembers (each specifying their own type, name and
// box type)
GArray* member; GArray* member;
// box variable to access // box variable to access
Variable* variable; Variable* variable;
@ -128,10 +130,9 @@ typedef struct Typedefine_t {
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Typedefine; } Typedefine;
/** /**
* @brief Reprents the value of type. Can be used to definitions, initialization and for expressions contants. * @brief Reprents the value of type. Can be used to definitions, initialization
* and for expressions contants.
* *
*/ */
typedef struct TypeValue_t { typedef struct TypeValue_t {
@ -211,7 +212,8 @@ typedef enum FunctionKind_t {
typedef struct FunctionDefinition_t { typedef struct FunctionDefinition_t {
// hashtable of parameters // hashtable of parameters
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration
// (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
Type* return_value; Type* return_value;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
@ -223,7 +225,8 @@ typedef struct FunctionDefinition_t {
typedef struct FunctionDeclaration_t { typedef struct FunctionDeclaration_t {
// hashtable of parameters // hashtable of parameters
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration
// (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
Type* return_value; Type* return_value;
@ -246,11 +249,7 @@ Parameter get_param_from_func(Function* func, size_t index);
// | Variables | // | Variables |
// '------------------------------------------------' // '------------------------------------------------'
typedef enum StorageQualifier_t { typedef enum StorageQualifier_t { Local, Static, Global } StorageQualifier;
Local,
Static,
Global
} StorageQualifier;
typedef struct VariableDeclaration_t { typedef struct VariableDeclaration_t {
StorageQualifier qualifier; StorageQualifier qualifier;
@ -261,7 +260,8 @@ typedef struct VariableDeclaration_t {
/** /**
* @brief Definition of a variable * @brief Definition of a variable
* *
* @attention NOTE: The types of the initializer and the declaration must be equal * @attention NOTE: The types of the initializer and the declaration must be
* equal
* *
*/ */
typedef struct VariableDefiniton_t { typedef struct VariableDefiniton_t {
@ -311,12 +311,13 @@ typedef struct AddressOf_t {
// '------------------------------------------------' // '------------------------------------------------'
/** /**
* @brief Perform a type cast, converting a value to different type whilest preserving as much of the original * @brief Perform a type cast, converting a value to different type whilest
* values information. * preserving as much of the original values information.
* *
* @attention NOTE: Must check wether the given value's type can be parsed into * @attention NOTE: Must check wether the given value's type can be parsed into
* the target type without loss. * the target type without loss.
* Lossy mean possibly loosing information such when casting a float into an int (no fraction anymore). * Lossy mean possibly loosing information such when casting a float into
* an int (no fraction anymore).
* *
*/ */
typedef struct TypeCast_t { typedef struct TypeCast_t {
@ -328,8 +329,8 @@ typedef struct TypeCast_t {
/** /**
* @brief Perform a reinterpret cast. * @brief Perform a reinterpret cast.
* *
* @attention NOTE: The given value's type must have the size in bytes as the target type. * @attention NOTE: The given value's type must have the size in bytes as the
* Transmuting a short int into a float should yield an error. * target type. Transmuting a short int into a float should yield an error.
* *
*/ */
typedef struct Transmute_t { typedef struct Transmute_t {
@ -362,11 +363,7 @@ typedef enum ArithmeticOperator_t {
* @brief Represents the relational operator. * @brief Represents the relational operator.
* *
*/ */
typedef enum RelationalOperator_t { typedef enum RelationalOperator_t { Equal, Greater, Less } RelationalOperator;
Equal,
Greater,
Less
} RelationalOperator;
// .------------------------------------------------. // .------------------------------------------------.
// | Boolean | // | Boolean |

View File

@ -1,9 +1,9 @@
#include <cfg/opt.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/col.h> #include <sys/col.h>
#include <sys/log.h> #include <sys/log.h>
#include <cfg/opt.h>
#ifdef __unix__ #ifdef __unix__
#include <unistd.h> #include <unistd.h>
@ -65,7 +65,9 @@ int stdout_supports_ansi_esc() {
if (isatty(STDOUT_FILENO)) { if (isatty(STDOUT_FILENO)) {
const char* colors = getenv("COLORTERM"); const char* colors = getenv("COLORTERM");
// check if colors are set and allowed // check if colors are set and allowed
if (colors != NULL && (strcmp(colors, "truecolor") == 0 || strcmp(colors, "24bit") == 0)) { if (colors != NULL
&& (strcmp(colors, "truecolor") == 0
|| strcmp(colors, "24bit") == 0)) {
return ANSI_ENABLED; return ANSI_ENABLED;
} }
} }
@ -79,8 +81,8 @@ int stdout_supports_ansi_esc() {
return ASNI_DISABLED; return ASNI_DISABLED;
} }
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) | if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT)
(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { | (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return ANSI_ENABLED; return ANSI_ENABLED;
} }
#else #else

View File

@ -28,14 +28,17 @@ void col_init(void);
void enable_ansi_colors(); void enable_ansi_colors();
/** /**
* @brief Disable ANSI escape codes. This will set all the above global strings to be empty. * @brief Disable ANSI escape codes. This will set all the above global strings
* to be empty.
*/ */
void disable_ansi_colors(); void disable_ansi_colors();
/** /**
* @brief Check if stdout may support ANSI escape codes. * @brief Check if stdout may support ANSI escape codes.
* @attention This function may report escape codes to be unavailable even if they actually are. * @attention This function may report escape codes to be unavailable even if
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED otherwise * they actually are.
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED
* otherwise
*/ */
[[nodiscard]] [[nodiscard]]
int stdout_supports_ansi_esc(); int stdout_supports_ansi_esc();

View File

@ -1,12 +1,12 @@
#include <assert.h>
#include <cfg/opt.h>
#include <mem/cache.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/log.h>
#include <assert.h>
#include <string.h> #include <string.h>
#include <cfg/opt.h> #include <sys/log.h>
#include <mem/cache.h>
static struct Logger_t { static struct Logger_t {
FILE** streams; FILE** streams;
@ -15,13 +15,11 @@ static struct Logger_t {
int runtime_log_level = LOG_LEVEL_WARNING; int runtime_log_level = LOG_LEVEL_WARNING;
void set_log_level(int level) void set_log_level(int level) {
{
runtime_log_level = level; runtime_log_level = level;
} }
void log_init() void log_init() {
{
if (is_option_set("verbose")) { if (is_option_set("verbose")) {
set_log_level(LOG_LEVEL_INFORMATION); set_log_level(LOG_LEVEL_INFORMATION);
} else if (is_option_set("debug")) { } else if (is_option_set("debug")) {
@ -32,30 +30,26 @@ void log_init()
log_register_stream(LOG_DEFAULT_STREAM); log_register_stream(LOG_DEFAULT_STREAM);
} }
void log_register_stream(FILE* restrict stream) void log_register_stream(FILE* restrict stream) {
{
// replace runtime check with assertion // replace runtime check with assertion
// only to be used in debug target // only to be used in debug target
assert(stream != NULL); assert(stream != NULL);
if (GlobalLogger.stream_count == 0) if (GlobalLogger.stream_count == 0) {
{ GlobalLogger.streams =
GlobalLogger.streams = (FILE**) mem_alloc(MemoryNamespaceLog, sizeof(FILE*)); (FILE**) mem_alloc(MemoryNamespaceLog, sizeof(FILE*));
GlobalLogger.stream_count = 1; GlobalLogger.stream_count = 1;
if (GlobalLogger.streams == NULL) if (GlobalLogger.streams == NULL) {
{
PANIC("failed to allocate stream buffer"); PANIC("failed to allocate stream buffer");
} }
} } else {
else
{
GlobalLogger.stream_count++; GlobalLogger.stream_count++;
size_t bytes = GlobalLogger.stream_count * sizeof(FILE*); size_t bytes = GlobalLogger.stream_count * sizeof(FILE*);
GlobalLogger.streams = (FILE**) mem_realloc(MemoryNamespaceLog, GlobalLogger.streams, bytes); GlobalLogger.streams =
(FILE**) mem_realloc(MemoryNamespaceLog, GlobalLogger.streams, bytes);
if (GlobalLogger.streams == NULL) if (GlobalLogger.streams == NULL) {
{
PANIC("failed to reallocate stream buffer"); PANIC("failed to reallocate stream buffer");
} }
} }
@ -63,32 +57,21 @@ void log_register_stream(FILE* restrict stream)
GlobalLogger.streams[GlobalLogger.stream_count - 1] = stream; GlobalLogger.streams[GlobalLogger.stream_count - 1] = stream;
} }
static void vflogf( static void vflogf(FILE* restrict stream, const char* restrict level,
FILE* restrict stream, const char* restrict file, const unsigned long line,
const char* restrict level, const char* restrict func, const char* restrict format,
const char* restrict file, va_list args) {
const unsigned long line,
const char* restrict func,
const char* restrict format,
va_list args)
{
fprintf(stream, "%s in %s() at %s:%lu: ", level, func, file, line); fprintf(stream, "%s in %s() at %s:%lu: ", level, func, file, line);
vfprintf(stream, format, args); vfprintf(stream, format, args);
} }
void syslog_logf( void syslog_logf(const char* restrict level, const char* restrict file,
const char* restrict level, const unsigned long line, const char* restrict func,
const char* restrict file, const char* restrict format, ...) {
const unsigned long line,
const char* restrict func,
const char* restrict format,
...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);
for (size_t i = 0; i < GlobalLogger.stream_count; i++) for (size_t i = 0; i < GlobalLogger.stream_count; i++) {
{
FILE* stream = GlobalLogger.streams[i]; FILE* stream = GlobalLogger.streams[i];
vflogf(stream, level, file, line, func, format, args); vflogf(stream, level, file, line, func, format, args);
@ -97,13 +80,9 @@ void syslog_logf(
va_end(args); va_end(args);
} }
void syslog_panicf( void syslog_panicf(const char* restrict file, const unsigned long line,
const char* restrict file, const char* restrict func, const char* restrict format,
const unsigned long line, ...) {
const char* restrict func,
const char* restrict format,
...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);
@ -114,13 +93,9 @@ void syslog_panicf(
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
void syslog_fatalf( void syslog_fatalf(const char* restrict file, const unsigned long line,
const char* restrict file, const char* restrict func, const char* restrict format,
const unsigned long line, ...) {
const char* restrict func,
const char* restrict format,
...)
{
va_list args; va_list args;
va_start(args, format); va_start(args, format);

View File

@ -23,9 +23,11 @@
// generally not defined by GCC < 11.3 and MSVC // generally not defined by GCC < 11.3 and MSVC
#ifndef __FILE_NAME__ #ifndef __FILE_NAME__
#if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER) #if defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
#define __FILE_NAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) #define __FILE_NAME__ \
(strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
#else #else
#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #define __FILE_NAME__ \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#endif #endif
#endif #endif
@ -34,24 +36,32 @@
* This macro will print debug information to stderr and call abort() to * This macro will print debug information to stderr and call abort() to
* performa a ungracefull exit. No clean up possible. * performa a ungracefull exit. No clean up possible.
*/ */
#define PANIC(format, ...) syslog_panicf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__) #define PANIC(format, ...) \
syslog_panicf(__FILE_NAME__, __LINE__, __func__, format "\n", ##__VA_ARGS__)
/** /**
* @brief Panic is used in cases where the process is in an invalid or undefined state. * @brief Panic is used in cases where the process is in an invalid or undefined
* This macro will print debug information to stderr and call exit() to * state. This macro will print debug information to stderr and call exit() to
* initiate a gracefull exit, giving the process the opportunity to clean up. * initiate a gracefull exit, giving the process the opportunity to clean
* up.
*/ */
#define FATAL(format, ...) syslog_fatalf(__FILE_NAME__, __LINE__, __func__, format"\n", ##__VA_ARGS__) #define FATAL(format, ...) \
syslog_fatalf(__FILE_NAME__, __LINE__, __func__, format "\n", ##__VA_ARGS__)
/* /*
Standard log macros. These will not terminate the application. Standard log macros. These will not terminate the application.
Can be turned off by setting LOG_LEVEL. All logs which have smaller log numbers Can be turned off by setting LOG_LEVEL. All logs which have smaller log numbers
will not print. will not print.
*/ */
#define ERROR(format, ...) __LOG(LOG_STRING_ERROR, LOG_LEVEL_ERROR, format"\n", ##__VA_ARGS__) #define ERROR(format, ...) \
#define WARN(format, ...) __LOG(LOG_STRING_WARNING, LOG_LEVEL_WARNING, format"\n", ##__VA_ARGS__) __LOG(LOG_STRING_ERROR, LOG_LEVEL_ERROR, format "\n", ##__VA_ARGS__)
#define INFO(format, ...) __LOG(LOG_STRING_INFORMATION, LOG_LEVEL_INFORMATION, format"\n", ##__VA_ARGS__) #define WARN(format, ...) \
#define DEBUG(format, ...) __LOG(LOG_STRING_DEBUG, LOG_LEVEL_DEBUG, format"\n", ##__VA_ARGS__) __LOG(LOG_STRING_WARNING, LOG_LEVEL_WARNING, format "\n", ##__VA_ARGS__)
#define INFO(format, ...) \
__LOG(LOG_STRING_INFORMATION, LOG_LEVEL_INFORMATION, format "\n", \
##__VA_ARGS__)
#define DEBUG(format, ...) \
__LOG(LOG_STRING_DEBUG, LOG_LEVEL_DEBUG, format "\n", ##__VA_ARGS__)
extern int runtime_log_level; extern int runtime_log_level;
@ -59,12 +69,13 @@ extern int runtime_log_level;
do { \ do { \
if (LOG_LEVEL <= priority) \ if (LOG_LEVEL <= priority) \
if (runtime_log_level <= priority) \ if (runtime_log_level <= priority) \
syslog_logf(level, __FILE_NAME__, __LINE__, __func__, format, ##__VA_ARGS__); \ syslog_logf(level, __FILE_NAME__, __LINE__, __func__, format, \
##__VA_ARGS__); \
} while (0) } while (0)
/** /**
* @brief Set the runtime log level. Must be one of: LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, * @brief Set the runtime log level. Must be one of: LOG_LEVEL_ERROR,
* LOG_LEVEL_INFORMATION, LOG_LEVEL_DEBUG * LOG_LEVEL_WARNING, LOG_LEVEL_INFORMATION, LOG_LEVEL_DEBUG
* @param level the new log level * @param level the new log level
*/ */
void set_log_level(int level); void set_log_level(int level);
@ -80,16 +91,13 @@ void set_log_level(int level);
* @param ... * @param ...
*/ */
[[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(4)]] [[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(4)]]
void syslog_logf( void syslog_logf(const char* restrict level, const char* restrict file,
const char* restrict level, unsigned long line, const char* restrict func,
const char* restrict file, const char* restrict format, ...);
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
/** /**
* @brief Log a panic message to stderr and perform gracefull crash with exit() denoting a failure * @brief Log a panic message to stderr and perform gracefull crash with exit()
* denoting a failure
* *
* @param file origin of the message cause * @param file origin of the message cause
* @param line line in which log call was made * @param line line in which log call was made
@ -97,17 +105,13 @@ void syslog_logf(
* @param format the format to print following args in * @param format the format to print following args in
* @param ... * @param ...
*/ */
[[noreturn]] [[noreturn]] [[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]] void syslog_panicf(const char* restrict file, unsigned long line,
void syslog_panicf( const char* restrict func, const char* restrict format, ...);
const char* restrict file,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
/** /**
* @brief Log a critical message to stderr and perform ungracefull crash with abort() * @brief Log a critical message to stderr and perform ungracefull crash with
* abort()
* *
* @param file origin of the message cause * @param file origin of the message cause
* @param line line in which log call was made * @param line line in which log call was made
@ -115,14 +119,9 @@ void syslog_panicf(
* @param format the format to print following args in * @param format the format to print following args in
* @param ... * @param ...
*/ */
[[noreturn]] [[noreturn]] [[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]] void syslog_fatalf(const char* restrict file, unsigned long line,
void syslog_fatalf( const char* restrict func, const char* restrict format, ...);
const char* restrict file,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
/** /**
* @brief Initialize the logger by registering stderr as stream * @brief Initialize the logger by registering stderr as stream
@ -131,7 +130,8 @@ void syslog_fatalf(
void log_init(void); void log_init(void);
/** /**
* @brief Register a stream as output source. Must be freed manually at exit if necessary * @brief Register a stream as output source. Must be freed manually at exit if
* necessary
* *
* @param stream * @param stream
*/ */