Merge pull request #132 from Servostar/131-clean-up-source-code

formatted source with clangd
This commit is contained in:
servostar 2024-08-10 13:04:47 +02:00 committed by GitHub
commit d01248ba25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 2431 additions and 1936 deletions

View File

@ -1,3 +1,45 @@
BasedOnStyle: Google
IndentWidth: 4
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 <mem/cache.h>
#include <stdio.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);
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) {
PANIC("failed to allocate AST node");
@ -18,24 +21,24 @@ struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t
assert(node != NULL);
// init to discrete state
node->parent = NULL;
node->parent = NULL;
node->children = mem_new_g_array(MemoryNamespaceAst, sizeof(AST_NODE_PTR));
node->kind = kind;
node->value = value;
node->kind = kind;
node->value = value;
node->location = location;
return node;
}
static const char* lookup_table[AST_ELEMENT_COUNT] = { "__UNINIT__" };
static const char* lookup_table[AST_ELEMENT_COUNT] = {"__UNINIT__"};
void AST_init() {
DEBUG("initializing global syntax tree...");
INFO("filling lookup table...");
lookup_table[AST_Stmt] = "stmt";
lookup_table[AST_Stmt] = "stmt";
lookup_table[AST_Module] = "module";
lookup_table[AST_Expr] = "expr";
lookup_table[AST_Expr] = "expr";
lookup_table[AST_Add] = "+";
lookup_table[AST_Sub] = "-";
@ -43,53 +46,53 @@ void AST_init() {
lookup_table[AST_Div] = "/";
lookup_table[AST_BitAnd] = "&";
lookup_table[AST_BitOr] = "|";
lookup_table[AST_BitOr] = "|";
lookup_table[AST_BitXor] = "^";
lookup_table[AST_BitNot] = "!";
lookup_table[AST_Eq] = "==";
lookup_table[AST_Less] = "<";
lookup_table[AST_Eq] = "==";
lookup_table[AST_Less] = "<";
lookup_table[AST_Greater] = ">";
lookup_table[AST_BoolAnd] = "&&";
lookup_table[AST_BoolOr] = "||";
lookup_table[AST_BoolOr] = "||";
lookup_table[AST_BoolXor] = "^^";
lookup_table[AST_BoolNot] = "!!";
lookup_table[AST_While] = "while";
lookup_table[AST_If] = "if";
lookup_table[AST_While] = "while";
lookup_table[AST_If] = "if";
lookup_table[AST_IfElse] = "else if";
lookup_table[AST_Else] = "else";
lookup_table[AST_Else] = "else";
lookup_table[AST_Decl] = "decl";
lookup_table[AST_Decl] = "decl";
lookup_table[AST_Assign] = "assign";
lookup_table[AST_Def] = "def";
lookup_table[AST_Def] = "def";
lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box";
lookup_table[AST_FunDecl] = "fun";
lookup_table[AST_FunDef] = "fun";
lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box";
lookup_table[AST_FunDecl] = "fun";
lookup_table[AST_FunDef] = "fun";
lookup_table[AST_ProcDecl] = "fun";
lookup_table[AST_ProcDef] = "fun";
lookup_table[AST_ProcDef] = "fun";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast";
lookup_table[AST_Transmute] = "transmute";
lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list";
lookup_table[AST_ExprList] = "expr list";
lookup_table[AST_ArgList] = "arg list";
lookup_table[AST_ParamList] = "param list";
lookup_table[AST_StmtList] = "stmt list";
lookup_table[AST_IdentList] = "ident list";
lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration";
lookup_table[AST_AddressOf] = "address of";
lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast";
lookup_table[AST_Transmute] = "transmute";
lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list";
lookup_table[AST_ExprList] = "expr list";
lookup_table[AST_ArgList] = "arg list";
lookup_table[AST_ParamList] = "param list";
lookup_table[AST_StmtList] = "stmt list";
lookup_table[AST_IdentList] = "ident list";
lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration";
lookup_table[AST_AddressOf] = "address of";
lookup_table[AST_Dereference] = "deref";
lookup_table[AST_Reference] = "ref";
lookup_table[AST_Return] = "ret";
lookup_table[AST_Reference] = "ref";
lookup_table[AST_Return] = "ret";
}
const char* AST_node_to_string(const struct AST_Node_t* node) {
@ -98,7 +101,7 @@ const char* AST_node_to_string(const struct AST_Node_t* node) {
const char* string;
switch(node->kind) {
switch (node->kind) {
case AST_Int:
case AST_Char:
case AST_Float:
@ -131,7 +134,7 @@ static inline unsigned long int max(unsigned long int a, unsigned long int b) {
return a > b ? a : b;
}
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) {
DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL);
assert(child != NULL);
@ -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");
}
owner->location.col_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_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.line_start = min(owner->location.line_start, child->location.line_start);
owner->location.col_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) {
owner->location.file = child->location.file;
@ -155,7 +162,7 @@ void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
g_array_append_val(owner->children, child);
}
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
struct AST_Node_t* AST_get_node(struct AST_Node_t* owner, const size_t idx) {
DEBUG("retrvieng node %d from %p", idx, owner);
assert(owner != NULL);
assert(owner->children != NULL);
@ -174,7 +181,8 @@ struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
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->children != NULL);
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;
}
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(child != NULL);
assert(owner->children != NULL);
@ -201,14 +210,14 @@ struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_N
PANIC("Child to detach not a child of parent");
}
void AST_delete_node(struct AST_Node_t *node) {
void AST_delete_node(struct AST_Node_t* node) {
assert(node != NULL);
DEBUG("Deleting AST node: %p", node);
if (node->parent != NULL) {
[[maybe_unused]]
const struct AST_Node_t* child = AST_detach_child(node->parent, node);
[[maybe_unused]] const struct AST_Node_t* child =
AST_detach_child(node->parent, node);
assert(child == node);
}
@ -224,8 +233,8 @@ void AST_delete_node(struct AST_Node_t *node) {
mem_free(node);
}
static void AST_visit_nodes_recurse2(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node,
static void AST_visit_nodes_recurse2(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t* node,
size_t depth),
const size_t depth) {
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
@ -235,12 +244,13 @@ static void AST_visit_nodes_recurse2(struct AST_Node_t *root,
(for_each)(root, depth);
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);
}
}
void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node,
void AST_visit_nodes_recurse(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t* node,
size_t depth)) {
DEBUG("Starting recursive visit of %p with %p", root, for_each);
@ -250,24 +260,28 @@ void AST_visit_nodes_recurse(struct AST_Node_t *root,
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);
assert(stream != 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) {
return;
}
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);
assert(stream != NULL);
@ -298,16 +312,17 @@ void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) {
fprintf(stream, "}\n");
}
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++) {
AST_NODE_PTR child = AST_get_node(owner, i);
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++) {
AST_NODE_PTR child = AST_get_node(owner, i);
if (child->kind == kind) {
return child;
if (child->kind == kind) {
return child;
}
}
}
return NULL;
return NULL;
}
void AST_merge_modules(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {

View File

@ -2,8 +2,8 @@
#ifndef _AST_H_
#define _AST_H_
#include <stdio.h>
#include <io/files.h>
#include <stdio.h>
/**
* @brief The type of a AST node
@ -50,10 +50,10 @@ enum AST_SyntaxElement_t {
AST_Greater,
AST_Less,
// Casts
AST_Typecast, // type cast
AST_Transmute, // reinterpret cast
AST_Call, // function call
AST_Macro, // builtin functions: lineno(), filename(), ...
AST_Typecast, // type cast
AST_Transmute, // reinterpret cast
AST_Call, // function call
AST_Macro, // builtin functions: lineno(), filename(), ...
// Defintions
AST_Typedef,
AST_Box,
@ -93,11 +93,12 @@ enum AST_SyntaxElement_t {
* Every node can have one ancestor (parent) but multiple (also none) children.
* Nodes have two properties:
* - 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 {
// parent node that owns this node
struct AST_Node_t *parent;
struct AST_Node_t* parent;
// type of AST node: if, declaration, ...
enum AST_SyntaxElement_t kind;
@ -116,43 +117,44 @@ typedef struct AST_Node_t {
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);
/**
* @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
* used by the node after this function call.
* @attention The retuned pointer is not to be freed as it may either be a
* statically stored string or used by the node after this function call.
* @param node to return string representation of
* @return string represenation of the node
*/
[[maybe_unused]]
[[gnu::nonnull(1)]]
[[maybe_unused]] [[gnu::nonnull(1)]]
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.
* All other fields are set to either NULL or 0. No allocation for children array is preformed.
* @attention parameter value can be NULL in case no value can be provided for the node
* @brief Create a new node struct on the system heap. Initializes the struct
* with the given values. All other fields are set to either NULL or 0. No
* 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 value an optional value for this node
* @return
*/
[[maybe_unused]]
[[nodiscard("pointer must be freed")]]
[[gnu::returns_nonnull]]
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value);
[[maybe_unused]] [[nodiscard("pointer must be freed")]] [[gnu::returns_nonnull]]
struct AST_Node_t* AST_new_node(TokenLocation location,
enum AST_SyntaxElement_t kind,
const char* value);
/**
* @brief Deallocate this node and all of its children.
* @attention This function will detach this node from its parent if one is present
* Use of the supplied node after this call is undefined behavior
* @attention This function will detach this node from its parent if one is
* present Use of the supplied node after this call is undefined behavior
* @param node The node to deallocate
*/
[[maybe_unused]]
[[gnu::nonnull(1)]]
void AST_delete_node(struct AST_Node_t * node);
[[maybe_unused]] [[gnu::nonnull(1)]]
void AST_delete_node(struct AST_Node_t* node);
/**
* @brief Add a new child node to a parent node
@ -160,59 +162,58 @@ void AST_delete_node(struct AST_Node_t * node);
* @param owner node to add a child to
* @param child node to be added as a child
*/
[[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child);
[[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_push_node(struct AST_Node_t* owner, struct AST_Node_t* child);
/**
* @brief Remove the specified child from the owner.
* @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 idx the index of the child to remove
* @return a pointer to the child which was removed
*/
[[maybe_unused]]
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1)]]
[[maybe_unused]] [[nodiscard("pointer must be freed")]] [[gnu::nonnull(1)]]
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
* and marking the parent of the child as NULL.
* @attention The returned pointer is still valid. It must be freed at some pointer later.
* @brief Detach a child from its parent. This involves removing the child from
* 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.
* @param owner the owner to remove the child from
* @param child the child to detach
* @return a pointer to child detached
*/
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1), gnu::nonnull(1)]]
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child);
[[nodiscard("pointer must be freed")]] [[gnu::nonnull(1), gnu::nonnull(1)]]
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner,
const struct AST_Node_t* child);
/**
* @brief Return a pointer to the n-th child of a node
* @attention Pointer to childen nodes will never 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 idx the index of the child to get a pointer to
* @return a pointer to the n-th child of the owner node
*/
[[maybe_unused]]
[[gnu::nonnull(1)]]
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, size_t idx);
[[maybe_unused]] [[gnu::nonnull(1)]]
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);
/**
* @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 for_each the function to execute
*/
[[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node,
[[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
void AST_visit_nodes_recurse(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t* node,
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 node the topmost ancestor
*/
[[maybe_unused]]
[[gnu::nonnull(1), gnu::nonnull(2)]]
[[maybe_unused]] [[gnu::nonnull(1), gnu::nonnull(2)]]
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)]]
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.
//
#include <assert.h>
#include <cfg/opt.h>
#include <io/files.h>
#include <link/driver.h>
#include <mem/cache.h>
#include <string.h>
#include <sys/log.h>
#include <io/files.h>
#include <assert.h>
#include <toml.h>
#include <mem/cache.h>
#include <link/driver.h>
static GHashTable* args = NULL;
@ -34,14 +34,15 @@ void parse_options(int argc, char* argv[]) {
for (int i = 0; i < argc; i++) {
Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option));
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->value = NULL;
char* equals = strchr(option->string, '=');
if (equals != NULL) {
option->value = equals + 1;
*equals = 0;
*equals = 0;
}
g_hash_table_insert(args, (gpointer) option->string, (gpointer) option);
@ -94,17 +95,18 @@ TargetConfig* default_target_config() {
TargetConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(TargetConfig));
config->name = mem_strdup(MemoryNamespaceOpt, "out");
config->print_ast = false;
config->print_asm = false;
config->print_ir = false;
config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER);
config->mode = Application;
config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->name = mem_strdup(MemoryNamespaceOpt, "out");
config->print_ast = false;
config->print_asm = false;
config->print_ir = false;
config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER);
config->mode = Application;
config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->optimization_level = 1;
config->root_module = NULL;
config->link_search_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
config->root_module = NULL;
config->link_search_paths =
mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
config->lld_fatal_warnings = FALSE;
config->gsc_fatal_warnings = FALSE;
config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
@ -148,7 +150,8 @@ TargetConfig* default_target_config_from_args() {
} else if (strcmp(opt->value, "lib") == 0) {
config->mode = Library;
} else {
print_message(Warning, "Invalid compilation mode: %s", opt->value);
print_message(Warning, "Invalid compilation mode: %s",
opt->value);
}
}
}
@ -169,7 +172,7 @@ TargetConfig* default_target_config_from_args() {
}
}
char* cwd = g_get_current_dir();
char* cwd = g_get_current_dir();
char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
g_array_append_val(config->link_search_paths, cached_cwd);
free(cwd);
@ -180,10 +183,10 @@ TargetConfig* default_target_config_from_args() {
if (opt->value != NULL) {
const char* start = opt->value;
const char* end = NULL;
while((end = strchr(start, ',')) != NULL) {
const char* end = NULL;
while ((end = strchr(start, ',')) != NULL) {
const int len = end - start;
const int len = end - start;
char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len);
link_path[len] = 0;
@ -211,10 +214,12 @@ TargetConfig* default_target_config_from_args() {
} else {
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, ".");
@ -226,10 +231,10 @@ TargetConfig* default_target_config_from_args() {
if (opt->value != NULL) {
const char* start = opt->value;
const char* end = NULL;
while((end = strchr(start, ',')) != NULL) {
const char* end = NULL;
while ((end = strchr(start, ',')) != NULL) {
const int len = end - start;
const int len = end - start;
char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(import_path, start, len);
import_path[len] = 0;
@ -256,39 +261,43 @@ TargetConfig* default_target_config_from_args() {
void print_help(void) {
DEBUG("printing help dialog...");
const char *lines[] = {
const char* lines[] = {
"Gemstone Compiler (c) GPL-2.0",
"Build a project target: gsc build [target]|all",
"Compile non-project file: gsc compile <target-options> [file]",
"Output information: gsc <option>",
"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-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",
" --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",
" --lld-fatal-warnings treat linker warnings as errors",
" --gsc-fatal-warnings treat parser warnings as errors",
"Options:",
" --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",
" --list-targets print a list of all available targets supported",
" --list-driver print a list of all available binary driver",
" --help print this help dialog",
" --color-always always colorize output",
" --print-gc-stats print statistics of the garbage collector"
};
" --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]);
}
}
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);
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);
const toml_datum_t datum = toml_string_in(table, name);
@ -310,7 +320,7 @@ static void get_str(char** string, const toml_table_t *table, const char* name)
}
}
static void get_int(int* integer, const toml_table_t *table, const char* name) {
static void get_int(int* integer, const toml_table_t* table, const char* name) {
DEBUG("retrieving integer %s", name);
const toml_datum_t datum = toml_int_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);
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...");
// project name
@ -350,14 +362,15 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec
get_str(&config->name, project_table, "name");
// author names
toml_array_t *authors = toml_array_in(project_table, "authors");
toml_array_t* authors = toml_array_in(project_table, "authors");
if (authors) {
config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char *));
config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
for (int i = 0;; i++) {
toml_datum_t author = toml_string_at(authors, i);
if (!author.ok)
if (!author.ok) {
break;
}
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;
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;
}
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...");
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->output_directory, target_table, "output");
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->gsc_fatal_warnings, target_table, "gsc_fatal_warnings");
get_bool(&target_config->lld_fatal_warnings, target_table,
"lld_fatal_warnings");
get_bool(&target_config->gsc_fatal_warnings, target_table,
"gsc_fatal_warnings");
get_int(&target_config->optimization_level, target_table, "opt");
@ -413,7 +430,7 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
if (err != PROJECT_OK) {
return err;
}
char* cwd = g_get_current_dir();
char* cwd = g_get_current_dir();
char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
free(cwd);
@ -428,54 +445,59 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
return PROJECT_OK;
}
static int parse_targets(ProjectConfig *config, const toml_table_t *root) {
static int parse_targets(ProjectConfig* config, const toml_table_t* root) {
DEBUG("parsing targets of project \"%s\"", config->name);
toml_table_t *targets = toml_table_in(root, "target");
toml_table_t* targets = toml_table_in(root, "target");
if (targets == NULL) {
print_message(Warning, "Project has no targets");
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++) {
const char *key = toml_key_in(targets, i);
const char* key = toml_key_in(targets, i);
if (key == NULL)
if (key == NULL) {
break;
}
toml_table_t *target = toml_table_in(targets, key);
parse_target(config, target, mem_strdup(MemoryNamespaceOpt, (char*) key));
toml_table_t* target = toml_table_in(targets, key);
parse_target(config, target,
mem_strdup(MemoryNamespaceOpt, (char*) key));
}
return PROJECT_OK;
}
int load_project_config(ProjectConfig *config) {
int load_project_config(ProjectConfig* config) {
DEBUG("loading project config...");
FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r");
FILE* config_file = fopen(PROJECT_CONFIG_FILE, "r");
if (config_file == NULL) {
print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno));
print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE,
strerror(errno));
return PROJECT_SEMANTIC_ERR;
}
char err_buf[TOML_ERROR_MSG_BUF];
toml_table_t *conf = toml_parse_file(config_file, err_buf, sizeof(err_buf));
toml_table_t* conf = toml_parse_file(config_file, err_buf, sizeof(err_buf));
fclose(config_file);
if (conf != NULL) {
int status = PROJECT_SEMANTIC_ERR;
toml_table_t *project = toml_table_in(conf, "project");
int status = PROJECT_SEMANTIC_ERR;
toml_table_t* project = toml_table_in(conf, "project");
if (project != NULL) {
if (parse_project_table(config, project) == PROJECT_OK) {
status = parse_targets(config, conf);
}
} else {
print_message(Error, "Invalid project configuration: missing project table.");
print_message(
Error, "Invalid project configuration: missing project table.");
}
toml_free(conf);
@ -528,7 +550,8 @@ void delete_project_config(ProjectConfig* config) {
char* key;
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);
}
@ -539,14 +562,15 @@ void delete_project_config(ProjectConfig* config) {
}
ProjectConfig* default_project_config() {
ProjectConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig));
ProjectConfig* config =
mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig));
config->authors = NULL;
config->name = NULL;
config->name = NULL;
config->targets = NULL;
config->license = NULL;
config->version = NULL;
config->desc = NULL;
config->desc = NULL;
return config;
}

View File

@ -8,10 +8,10 @@
#include <glib.h>
#define MAX_TARGETS_PER_PROJECT 100
#define PROJECT_CONFIG_FILE "build.toml"
#define PROJECT_CONFIG_FILE "build.toml"
#define PROJECT_OK 0
#define PROJECT_TOML_ERR 1
#define PROJECT_OK 0
#define PROJECT_TOML_ERR 1
#define PROJECT_SEMANTIC_ERR 2
#define TOML_ERROR_MSG_BUF 256
@ -49,7 +49,8 @@ typedef struct TargetConfig_t {
char* root_module;
// output directory for binaries
char* output_directory;
// output directory for intermediate representations (LLVM-IR, Assembly, ...)
// output directory for intermediate representations (LLVM-IR, Assembly,
// ...)
char* archive_directory;
// binary driver for executable generation
char* driver;
@ -130,7 +131,7 @@ TargetConfig* default_target_config_from_args();
* @return
*/
[[gnu::nonnull(1)]]
int load_project_config(ProjectConfig *config);
int load_project_config(ProjectConfig* config);
/**
* @brief Print a help dialog to stdout.
@ -182,10 +183,9 @@ const Option* get_option(const char* option);
* @param command
* @return an array of options that followed command.
*/
[[gnu::nonnull(1)]]
[[nodiscard("must be freed")]]
[[gnu::nonnull(1)]] [[nodiscard("must be freed")]]
GArray* get_non_options_after(const char* command);
void init_toml();
#endif //GEMSTONE_OPT_H
#endif // GEMSTONE_OPT_H

View File

@ -1,5 +1,6 @@
#include "set/types.h"
#include <codegen/backend.h>
#include <sys/log.h>
@ -12,18 +13,19 @@ static struct CodegenBackend_t {
BackendError new_backend_error(BackendErrorKind kind) {
BackendError error;
error.kind = kind;
error.kind = kind;
error.impl.ast_node = NULL;
error.impl.message = NULL;
error.impl.message = NULL;
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;
error.kind = kind;
error.kind = kind;
error.impl.ast_node = node;
error.impl.message = message;
error.impl.message = message;
return error;
}
@ -39,7 +41,8 @@ BackendError init_backend(void) {
BackendError code = CodegenBackend.init_func();
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;
}
@ -57,18 +60,21 @@ BackendError deinit_backend(void) {
BackendError code = CodegenBackend.deinit_func();
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 new_backend_error(Success);
}
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.deinit_func = deinit_func;
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.deinit_func = deinit_func;
CodegenBackend.codegen_func = codegen_func;
CodegenBackend.name = name;
CodegenBackend.name = name;
return new_backend_error(Success);
}
@ -83,7 +89,8 @@ BackendError generate_code(const Module* root, const TargetConfig* target) {
BackendError code = CodegenBackend.codegen_func(root, target);
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;
}

View File

@ -2,9 +2,9 @@
#ifndef CODEGN_BACKEND_H_
#define CODEGN_BACKEND_H_
#include <set/types.h>
#include <ast/ast.h>
#include <cfg/opt.h>
#include <set/types.h>
typedef struct BackendImplError_t {
// faulty AST node
@ -28,8 +28,8 @@ typedef struct BackendError_t {
} BackendError;
/**
* @brief Function called by the compiler backend to generate an intermediate format
* from AST. Returns a custom container for its intermediate language.
* @brief Function called by the compiler backend to generate an intermediate
* format from AST. Returns a custom container for its intermediate language.
*/
typedef BackendError (*codegen)(const Module*, const TargetConfig* target);
@ -47,13 +47,16 @@ typedef BackendError (*codegen_deinit)(void);
* @brief Set the backend functions to use
*
* @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 name name of the backend
*/
[[nodiscard]]
[[gnu::nonnull(1), gnu::nonnull(2), 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);
[[nodiscard]] [[gnu::nonnull(1), gnu::nonnull(2), 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);
/**
* @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_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)

View File

@ -2,42 +2,41 @@
// 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 <ast/ast.h>
#include <cfg/opt.h>
#include <codegen/backend.h>
#include <compiler.h>
#include <io/files.h>
#include <lex/util.h>
#include <llvm/backend.h>
#include <mem/cache.h>
#include <set/set.h>
#include <stdlib.h>
#include <sys/log.h>
#include <yacc/parser.tab.h>
#define GRAPHVIZ_FILE_EXTENSION "gv"
extern void yyrestart(FILE *);
extern void yyrestart(FILE*);
// Module AST node used by the parser for AST construction.
[[maybe_unused]]
AST_NODE_PTR root;
[[maybe_unused]] AST_NODE_PTR root;
// Current file which gets compiled the parser.
// NOTE: due to global state no concurrent compilation is possible
// on parser level.
[[maybe_unused]]
ModuleFile *current_file;
[[maybe_unused]] ModuleFile* current_file;
/**
* @brief Compile the specified file into AST
* @param ast Initialized AST module node to build program rules
* @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")]]
[[gnu::nonnull(1), gnu::nonnull(1)]]
static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
[[nodiscard("AST may be in invalid state")]] [[gnu::nonnull(1),
gnu::nonnull(1)]]
static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile* file) {
assert(file->path != NULL);
assert(ast != NULL);
@ -45,15 +44,16 @@ static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
if (file->handle == NULL) {
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;
}
DEBUG("parsing file: %s", file->path);
// setup global state
root = ast;
root = ast;
current_file = file;
yyin = file->handle;
yyin = file->handle;
yyrestart(yyin);
lex_reset();
@ -72,7 +72,7 @@ static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
* @param target
* @return EXIT_SUCCESS if successful EXIT_FAILURE otherwise
*/
static int setup_target_environment(const TargetConfig *target) {
static int setup_target_environment(const TargetConfig* target) {
DEBUG("setting up environment for target: %s", target->name);
assert(target->output_directory != NULL);
@ -80,21 +80,23 @@ static int setup_target_environment(const TargetConfig *target) {
int result = create_directory(target->archive_directory);
if (result != 0 && errno != EEXIST) {
const char *message = get_last_error();
const char* message = get_last_error();
assert(message != NULL);
print_message(Error, "Unable to create directory: %s: %s", target->archive_directory, message);
free((void *) message);
print_message(Error, "Unable to create directory: %s: %s",
target->archive_directory, message);
free((void*) message);
return EXIT_FAILURE;
}
result = create_directory(target->output_directory);
if (result != 0 && errno != EEXIST) {
const char *message = get_last_error();
const char* message = get_last_error();
assert(message != NULL);
print_message(Error, "Unable to create directory: %s: %s", target->output_directory, message);
free((void *) message);
print_message(Error, "Unable to create directory: %s: %s",
target->output_directory, message);
free((void*) message);
return EXIT_FAILURE;
}
@ -104,11 +106,12 @@ 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 target
*/
static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig* target) {
assert(ast != NULL);
assert(target != NULL);
DEBUG("printing AST to file: %s", target->name);
@ -120,16 +123,18 @@ static void print_ast_to_file(AST_NODE_PTR ast, const TargetConfig *target) {
// create file path to write graphviz to
// 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
char *path = g_build_filename(target->archive_directory, filename, NULL);
char* path = g_build_filename(target->archive_directory, filename, NULL);
DEBUG("Opening file to graph: %s", path);
FILE *output = fopen(path, "w");
FILE* output = fopen(path, "w");
if (output == NULL) {
char *message = (char*) get_last_error();
print_message(Error, "Unable to open file for syntax tree at: %s: %s", path, message);
char* message = (char*) get_last_error();
print_message(Error, "Unable to open file for syntax tree at: %s: %s",
path, message);
free(message);
} else {
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);
}
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...");
llvm_backend_init();
@ -173,20 +179,23 @@ static int run_backend_codegen(const Module* module, const TargetConfig* target)
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);
if (!g_str_has_suffix(import_target_name, ".gsc")) {
char* full_filename = g_strjoin("", import_target_name, ".gsc", NULL);
import_target_name = mem_strdup(MemoryNamespaceLld, full_filename);
import_target_name = mem_strdup(MemoryNamespaceLld, full_filename);
g_free(full_filename);
}
for (guint i = 0; i < config->import_paths->len; i++) {
const char* import_directory_path = g_array_index(config->import_paths, char*, i);
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* cwd = g_get_current_dir();
char* path =
g_build_filename(import_directory_path, import_target_name, NULL);
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
@ -208,9 +217,13 @@ const char* get_absolute_import_path(const TargetConfig* config, const char* imp
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) {
@ -219,9 +232,11 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
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) {
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;
}
@ -229,10 +244,12 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
continue;
}
ModuleFile *imported_file = push_file(unit, path);
AST_NODE_PTR imported_module = AST_new_node(empty_location(imported_file), AST_Module, NULL);
ModuleFile* imported_file = push_file(unit, path);
AST_NODE_PTR imported_module =
AST_new_node(empty_location(imported_file), AST_Module, NULL);
if (compile_file_to_ast(imported_module, imported_file) == EXIT_SUCCESS) {
if (compile_file_to_ast(imported_module, imported_file)
== EXIT_SUCCESS) {
AST_merge_modules(root_module, i + 1, imported_module);
} else {
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);
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_array_append_val(target->import_paths, cached_directory);
}
@ -258,13 +276,14 @@ static int compile_module_with_dependencies(ModuleFileStack *unit, ModuleFile* f
* @param unit
* @param target
*/
static int build_target(ModuleFileStack *unit, const TargetConfig *target) {
static int build_target(ModuleFileStack* unit, const TargetConfig* target) {
int err = EXIT_SUCCESS;
print_message(Info, "Building target: %s", target->name);
ModuleFile *file = push_file(unit, target->root_module);
AST_NODE_PTR root_module = AST_new_node(empty_location(file), AST_Module, NULL);
ModuleFile* file = push_file(unit, target->root_module);
AST_NODE_PTR root_module =
AST_new_node(empty_location(file), AST_Module, NULL);
err = compile_module_with_dependencies(unit, file, target, root_module);
if (err == EXIT_SUCCESS) {
@ -273,7 +292,7 @@ static int build_target(ModuleFileStack *unit, const TargetConfig *target) {
if (err == 0) {
print_ast_to_file(root_module, target);
Module *module = create_set(root_module);
Module* module = create_set(root_module);
if (module != NULL) {
err = run_backend_codegen(module, target);
@ -300,10 +319,10 @@ static int build_target(ModuleFileStack *unit, const TargetConfig *target) {
* Creates a single target by the given command line arguments.
* @param unit
*/
static int compile_file(ModuleFileStack *unit) {
static int compile_file(ModuleFileStack* unit) {
INFO("compiling basic files...");
TargetConfig *target = default_target_config_from_args();
TargetConfig* target = default_target_config_from_args();
if (target->root_module == NULL) {
print_message(Error, "No input file specified.");
@ -323,7 +342,8 @@ static int compile_file(ModuleFileStack *unit) {
* @param unit
* @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;
if (is_option_set("all")) {
@ -332,9 +352,10 @@ static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *con
g_hash_table_iter_init(&iter, config->targets);
char *key;
TargetConfig *val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
char* key;
TargetConfig* val;
while (
g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
err = build_target(unit, val);
}
return err;
@ -345,10 +366,11 @@ static int build_project_targets(ModuleFileStack *unit, const ProjectConfig *con
if (targets != NULL) {
for (guint i = 0; i < targets->len; i++) {
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)) {
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 {
print_message(Error, "Unknown target: %s", target_name);
}
@ -363,12 +385,13 @@ 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
*/
static int build_project(ModuleFileStack *unit) {
ProjectConfig *config = default_project_config();
int err = load_project_config(config);
static int build_project(ModuleFileStack* unit) {
ProjectConfig* config = default_project_config();
int err = load_project_config(config);
if (err == PROJECT_OK) {
err = build_project_targets(unit, config);

View File

@ -11,4 +11,4 @@
*/
int run_compiler();
#endif //GEMSTONE_COMPILER_H
#endif // GEMSTONE_COMPILER_H

View File

@ -2,13 +2,13 @@
// Created by servostar on 5/30/24.
//
#include <assert.h>
#include <io/files.h>
#include <mem/cache.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/log.h>
#include <assert.h>
#include <sys/col.h>
#include <mem/cache.h>
#include <sys/log.h>
#ifdef __unix__
@ -37,29 +37,30 @@ ModuleFileStack new_file_stack() {
return stack;
}
ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
ModuleFile* push_file(ModuleFileStack* stack, const char* path) {
assert(stack != NULL);
// lazy init of heap stack
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));
new_file->handle = NULL;
new_file->path = path;
new_file->handle = NULL;
new_file->path = path;
new_file->statistics.warning_count = 0;
new_file->statistics.error_count = 0;
new_file->statistics.info_count = 0;
new_file->statistics.error_count = 0;
new_file->statistics.info_count = 0;
g_array_append_val(stack->files, new_file);
return new_file;
}
void delete_files(ModuleFileStack *stack) {
void delete_files(ModuleFileStack* stack) {
for (size_t i = 0; i < stack->files->len; i++) {
const ModuleFile *file = g_array_index(stack->files, ModuleFile*, i);
const ModuleFile* file = g_array_index(stack->files, ModuleFile*, i);
if (file->handle != NULL) {
DEBUG("closing file: %s", file->path);
@ -78,7 +79,7 @@ void delete_files(ModuleFileStack *stack) {
#define SEEK_BUF_BYTES 256
// behaves like fgets except that it has defined behavior when n == 1
static void custom_fgets(char *buffer, size_t n, FILE *stream) {
static void custom_fgets(char* buffer, size_t n, FILE* stream) {
if (feof(stream)) {
buffer[0] = '\n';
buffer[1] = 0;
@ -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->handle != NULL);
assert(location != NULL);
@ -101,37 +103,39 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
// reset to start
rewind(location->file->handle);
char *buffer = alloca(SEEK_BUF_BYTES);
char* buffer = alloca(SEEK_BUF_BYTES);
unsigned long int line_count = 1;
// 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;
}
const char *accent_color = RESET;
const char *kind_text = "unknown";
const char* accent_color = RESET;
const char* kind_text = "unknown";
switch (kind) {
case Info:
kind_text = "info";
kind_text = "info";
accent_color = CYAN;
location->file->statistics.info_count++;
break;
case Warning:
kind_text = "warning";
kind_text = "warning";
accent_color = YELLOW;
location->file->statistics.warning_count++;
break;
case Error:
kind_text = "error";
kind_text = "error";
accent_color = RED;
location->file->statistics.error_count++;
break;
}
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_start(args, message);
@ -142,9 +146,10 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("\n");
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++) {
printf(" %4ld | ", location->line_start + l);
@ -166,11 +171,13 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("%s", accent_color);
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) {
custom_fgets(buffer, (int) limit, location->file->handle);
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) {
goto cont;
@ -185,7 +192,7 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("%s", buffer);
} while (strchr(buffer, '\n') == NULL);
cont:
cont:
printf("%s", RESET);
}
@ -196,22 +203,25 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
printf("%s", accent_color);
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("%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) {
TokenLocation location;
location.line_start = line_start;
location.line_end = line_end;
location.col_start = col_start;
location.col_end = col_end;
location.file = file;
location.line_end = line_end;
location.col_start = col_start;
location.col_end = col_end;
location.file = file;
return location;
}
@ -220,16 +230,18 @@ TokenLocation empty_location(ModuleFile* file) {
TokenLocation location;
location.line_start = 0;
location.line_end = 0;
location.col_start = 0;
location.col_end = 0;
location.file = file;
location.line_end = 0;
location.col_start = 0;
location.col_end = 0;
location.file = file;
return location;
}
void print_file_statistics(ModuleFile *file) {
if (file->statistics.info_count + file->statistics.warning_count + file->statistics.error_count < 1) {
void print_file_statistics(ModuleFile* file) {
if (file->statistics.info_count + file->statistics.warning_count
+ file->statistics.error_count
< 1) {
return;
}
@ -250,11 +262,11 @@ void print_file_statistics(ModuleFile *file) {
printf("\n\n");
}
void print_unit_statistics(ModuleFileStack *file_stack) {
void print_unit_statistics(ModuleFileStack* file_stack) {
FileDiagnosticStatistics stats;
stats.info_count = 0;
stats.info_count = 0;
stats.warning_count = 0;
stats.error_count = 0;
stats.error_count = 0;
for (size_t i = 0; i < file_stack->files->len; i++) {
ModuleFile* file = g_array_index(file_stack->files, ModuleFile*, i);
@ -285,20 +297,20 @@ void print_unit_statistics(ModuleFileStack *file_stack) {
printf("\n\n");
}
void print_message(Message kind, const char *fmt, ...) {
const char *accent_color = RESET;
const char *kind_text = "unknown";
void print_message(Message kind, const char* fmt, ...) {
const char* accent_color = RESET;
const char* kind_text = "unknown";
switch (kind) {
case Info:
kind_text = "info";
kind_text = "info";
accent_color = CYAN;
break;
case Warning:
kind_text = "warning";
kind_text = "warning";
accent_color = YELLOW;
break;
case Error:
kind_text = "error";
kind_text = "error";
accent_color = RED;
break;
}
@ -313,7 +325,7 @@ void print_message(Message kind, const char *fmt, ...) {
va_end(args);
}
int create_directory(const char *path) {
int create_directory(const char* path) {
assert(path != NULL);
DEBUG("creating directory: %s", path);
@ -321,16 +333,16 @@ int create_directory(const char *path) {
return g_mkdir_with_parents(path, 0755);
}
const char *get_last_error() {
const char* get_last_error() {
return mem_strdup(MemoryNamespaceIo, strerror(errno));
}
const char *get_absolute_path(const char *path) {
const char* get_absolute_path(const char* path) {
assert(path != NULL);
DEBUG("resolving absolute path of: %s", path);
char* cwd = g_get_current_dir();
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
g_free(cwd);

View File

@ -5,8 +5,8 @@
#ifndef GEMSTONE_FILES_H
#define GEMSTONE_FILES_H
#include <stdio.h>
#include <glib.h>
#include <stdio.h>
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR "\\"
@ -21,20 +21,16 @@ typedef struct FileDiagnosticStatistics_t {
} FileDiagnosticStatistics;
typedef struct ModuleFile_t {
const char *path;
FILE *handle;
const char* path;
FILE* handle;
FileDiagnosticStatistics statistics;
} ModuleFile;
typedef struct ModuleFileStack_t {
GArray *files;
GArray* files;
} ModuleFileStack;
typedef enum Message_t {
Info,
Warning,
Error
} Message;
typedef enum Message_t { Info, Warning, Error } Message;
typedef struct TokenLocation_t {
unsigned long int line_start;
@ -58,14 +54,14 @@ ModuleFileStack new_file_stack();
* @return A new file module
*/
[[gnu::nonnull(1), gnu::nonnull(2)]]
ModuleFile *push_file(ModuleFileStack *stack, const char *path);
ModuleFile* push_file(ModuleFileStack* stack, const char* path);
/**
* @brief Delete all files in the stack and the stack itself
* @param stack
*/
[[gnu::nonnull(1)]]
void delete_files(ModuleFileStack *stack);
void delete_files(ModuleFileStack* stack);
/**
* Create a new token location
@ -75,7 +71,9 @@ void delete_files(ModuleFileStack *stack);
* @param col_end
* @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);
/**
@ -92,7 +90,8 @@ TokenLocation empty_location(ModuleFile* file);
* @param message
*/
[[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)]]
/**
@ -101,25 +100,27 @@ void print_diagnostic(TokenLocation *location, Message kind, const char *message
* @param fmt
* @param ...
*/
void print_message(Message kind, const char *fmt, ...);
void print_message(Message kind, const char* fmt, ...);
/**
* @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
*/
[[gnu::nonnull(1)]]
void print_file_statistics(ModuleFile *file);
void print_file_statistics(ModuleFile* file);
/**
* @brief Print statistics of all files in the module stack.
* @param file_stack
*/
[[gnu::nonnull(1)]]
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
* @return 0 if successful, anything else otherwise
*/
@ -138,8 +139,7 @@ const char* get_last_error();
* @param path
* @return
*/
[[gnu::nonnull(1)]]
[[nodiscard("pointer must be freed")]]
[[gnu::nonnull(1)]] [[nodiscard("pointer must be freed")]]
const char* get_absolute_path(const char* path);
#endif //GEMSTONE_FILES_H
#endif // GEMSTONE_FILES_H

View File

@ -1,88 +1,89 @@
#include <lex/util.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <lex/util.h>
#include <mem/cache.h>
#include <stdlib.h>
#include <string.h>
// implementation based on:
// https://github.com/sunxfancy/flex-bison-examples/blob/master/error-handling/ccalc.c
char* buffer = NULL;
static int eof = 0;
static int nRow = 0;
static int nBuffer = 0;
static int lBuffer = 0;
static int nTokenStart = 0;
static int nTokenLength = 0;
static int eof = 0;
static int nRow = 0;
static int nBuffer = 0;
static int lBuffer = 0;
static int nTokenStart = 0;
static int nTokenLength = 0;
static int nTokenNextStart = 0;
void lex_init(void) {
buffer = mem_alloc(MemoryNamespaceStatic, MAX_READ_BUFFER_SIZE);
buffer = mem_alloc(MemoryNamespaceStatic, MAX_READ_BUFFER_SIZE);
}
void lex_reset(void) {
eof = 0;
nRow = 0;
nBuffer = 0;
lBuffer = 0;
nTokenStart = 0;
nTokenLength = 0;
eof = 0;
nRow = 0;
nBuffer = 0;
lBuffer = 0;
nTokenStart = 0;
nTokenLength = 0;
nTokenNextStart = 0;
}
void beginToken(char *t) {
nTokenStart = nTokenNextStart;
nTokenLength = (int) strlen(t);
nTokenNextStart = nBuffer + 1;
void beginToken(char* t) {
nTokenStart = nTokenNextStart;
nTokenLength = (int) strlen(t);
nTokenNextStart = nBuffer + 1;
yylloc.first_line = nRow;
yylloc.first_column = nTokenStart;
yylloc.last_line = nRow;
yylloc.last_column = nTokenStart + nTokenLength - 1;
yylloc.first_line = nRow;
yylloc.first_column = nTokenStart;
yylloc.last_line = nRow;
yylloc.last_column = nTokenStart + nTokenLength - 1;
}
int nextChar(char *dst) {
int frc;
int nextChar(char* dst) {
int frc;
if (eof)
return 0;
while (nBuffer >= lBuffer) {
frc = getNextLine();
if (frc != 0) {
return 0;
if (eof) {
return 0;
}
}
dst[0] = buffer[nBuffer];
nBuffer += 1;
while (nBuffer >= lBuffer) {
frc = getNextLine();
if (frc != 0) {
return 0;
}
}
return dst[0] != 0;
dst[0] = buffer[nBuffer];
nBuffer += 1;
return dst[0] != 0;
}
int getNextLine(void) {
char *p;
char* p;
nBuffer = 0;
nTokenStart = -1;
nTokenNextStart = 1;
eof = 0;
nBuffer = 0;
nTokenStart = -1;
nTokenNextStart = 1;
eof = 0;
p = fgets(buffer, MAX_READ_BUFFER_SIZE, yyin);
if (p == NULL) {
if (ferror(yyin)) {
return -1;
p = fgets(buffer, MAX_READ_BUFFER_SIZE, yyin);
if (p == NULL) {
if (ferror(yyin)) {
return -1;
}
eof = 1;
return 1;
}
eof = 1;
return 1;
}
nRow += 1;
lBuffer = (int) strlen(buffer);
nRow += 1;
lBuffer = (int) strlen(buffer);
return 0;
return 0;
}
struct ConstEscSeq {
@ -91,22 +92,10 @@ struct ConstEscSeq {
};
static struct ConstEscSeq sequences[] = {
{
"\\n",
"\n"
},
{
"\\\\",
"\\"
},
{
"\\t",
"\t"
},
{
"\\r",
"\r"
}
{"\\n", "\n"},
{"\\\\", "\\"},
{"\\t", "\t"},
{"\\r", "\r"}
};
char* collapse_escape_sequences(char* string) {

View File

@ -2,8 +2,8 @@
#ifndef LEX_UTIL_H_
#define LEX_UTIL_H_
#include <yacc/parser.tab.h>
#include <stdio.h>
#include <yacc/parser.tab.h>
#define MAX_READ_BUFFER_SIZE 1000
@ -23,13 +23,13 @@ void lex_reset(void);
* @param t the text of the token. Must be null terminated
*/
[[gnu::nonnull(1)]]
void beginToken(char *t);
void beginToken(char* t);
/**
* @brief Stores the next character into the supplied buffer
* @param dst the buffer to store character in
*/
int nextChar(char *dst);
int nextChar(char* dst);
/**
* @brief Reads the next line from yyin into a global buffer

View File

@ -2,8 +2,8 @@
// Created by servostar on 18.07.24.
//
#include <link/clang/driver.h>
#include <io/files.h>
#include <link/clang/driver.h>
#include <mem/cache.h>
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++) {
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 ");
@ -33,9 +34,9 @@ bool clang_link(TargetLinkConfig* config) {
BinaryDriver* clang_get_driver() {
BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver));
BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof(BinaryDriver));
driver->name = "clang";
driver->name = "clang";
driver->link_func = &clang_link;
return driver;

View File

@ -17,4 +17,4 @@ typedef struct BinaryDriver_t {
driver_link link_func;
} BinaryDriver;
#endif //GEMSTONE_DRIVER_H
#endif // GEMSTONE_DRIVER_H

View File

@ -2,8 +2,8 @@
// Created by servostar on 18.07.24.
//
#include <link/clang/driver.h>
#include <io/files.h>
#include <link/clang/driver.h>
#include <mem/cache.h>
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++) {
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 ");
@ -33,9 +34,9 @@ bool gcc_link(TargetLinkConfig* config) {
BinaryDriver* gcc_get_driver() {
BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof (BinaryDriver));
BinaryDriver* driver = mem_alloc(MemoryNamespaceLld, sizeof(BinaryDriver));
driver->name = "gcc";
driver->name = "gcc";
driver->link_func = &gcc_link;
return driver;

View File

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

View File

@ -15,4 +15,4 @@ bool link_run(TargetLinkConfig*);
void link_print_available_driver();
#endif //GEMSTONE_LIB_H
#endif // GEMSTONE_LIB_H

View File

@ -6,29 +6,29 @@
#include <llvm-c/TargetMachine.h>
#include <llvm/backend.h>
#include <llvm/parser.h>
#include <sys/log.h>
#include <mem/cache.h>
#include <sys/log.h>
Target create_native_target() {
DEBUG("creating native target...");
Target target;
target.name.str = "tmp";
target.name.str = "tmp";
target.name.allocation = NONE;
target.triple.str = LLVMGetDefaultTargetTriple();
target.triple.str = LLVMGetDefaultTargetTriple();
target.triple.allocation = LLVM;
assert(target.triple.str != NULL);
target.cpu.str = LLVMGetHostCPUName();
target.cpu.str = LLVMGetHostCPUName();
target.cpu.allocation = LLVM;
assert(target.cpu.str != NULL);
target.features.str = LLVMGetHostCPUFeatures();
target.features.str = LLVMGetHostCPUFeatures();
target.features.allocation = LLVM;
assert(target.features.str != NULL);
target.opt = LLVMCodeGenLevelNone;
target.opt = LLVMCodeGenLevelNone;
target.reloc = LLVMRelocDefault;
target.model = LLVMCodeModelDefault;
@ -55,7 +55,7 @@ static char* create_target_output_name(const TargetConfig* config) {
prefix = "lib";
}
char* name = g_strjoin("", prefix, config->name, NULL);
char* name = g_strjoin("", prefix, config->name, NULL);
char* cached_name = mem_strdup(MemoryNamespaceLlvm, name);
g_free(name);
@ -67,13 +67,13 @@ Target create_target_from_config(const TargetConfig* config) {
Target target = create_native_target();
target.name.str = create_target_output_name(config);
target.name.allocation = NONE; // freed later by compiler
target.name.str = create_target_output_name(config);
target.name.allocation = NONE; // freed later by compiler
target.opt = llvm_opt_from_int(config->optimization_level);
INFO("Configured target: %s/%d: (%s) on %s { %s }", target.name.str, target.opt,
target.triple.str, target.cpu.str, target.features.str);
INFO("Configured target: %s/%d: (%s) on %s { %s }", target.name.str,
target.opt, target.triple.str, target.cpu.str, target.features.str);
return target;
}
@ -116,8 +116,8 @@ static BackendError llvm_backend_codegen_deinit(void) {
void llvm_backend_init() {
BackendError err =
set_backend(&llvm_backend_codegen_init, &llvm_backend_codegen_deinit,
&llvm_backend_codegen, "LLVM");
set_backend(&llvm_backend_codegen_init, &llvm_backend_codegen_deinit,
&llvm_backend_codegen, "LLVM");
if (err.kind != Success) {
PANIC("unable to init llvm backend: %ld", err);

View File

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

View File

@ -2,23 +2,26 @@
// Created by servostar on 6/4/24.
//
#include <link/lib.h>
#include <llvm/link/lld.h>
#include <sys/log.h>
#include <mem/cache.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);
for (guint i = 0; i < config->link_search_paths->len; i++) {
const char* link_directory_path = g_array_index(config->link_search_paths, char*, i);
const char* link_directory_path =
g_array_index(config->link_search_paths, char*, i);
INFO("searching at: %s", link_directory_path);
char* path = g_build_filename(link_directory_path, link_target_name, NULL);
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
char* path =
g_build_filename(link_directory_path, link_target_name, NULL);
char* cwd = g_get_current_dir();
char* canonical = g_canonicalize_filename(path, cwd);
char* cached_canonical = mem_strdup(MemoryNamespaceLld, canonical);
const gboolean exists = g_file_test(canonical, G_FILE_TEST_EXISTS);
@ -38,21 +41,28 @@ const char* get_absolute_link_path(const TargetConfig* config, const char* link_
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");
TargetLinkConfig* config = mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig));
TargetLinkConfig* config =
mem_alloc(MemoryNamespaceLld, sizeof(TargetLinkConfig));
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->driver = target_config->driver;
config->driver = target_config->driver;
// append build object file
char* basename = g_strjoin(".", target_config->name, "o", NULL);
char* filename = g_build_filename(target_config->archive_directory, basename, NULL);
char* filename =
g_build_filename(target_config->archive_directory, basename, NULL);
g_free(basename);
const char* target_object = get_absolute_link_path(target_config, (const char*) filename);
const char* target_object =
get_absolute_link_path(target_config, (const char*) filename);
if (target_object == NULL) {
ERROR("failed to resolve path to target object: %s", filename);
g_free(filename);
@ -65,7 +75,8 @@ TargetLinkConfig* lld_create_link_config(__attribute__((unused)) const Target* t
{
// output file after linking
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);
@ -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* dependency_object = get_absolute_link_path(target_config, library);
const char* dependency_object =
get_absolute_link_path(target_config, library);
if (dependency_object == NULL) {
ERROR("failed to resolve path to dependency object: %s", library);
print_message(Warning, "failed to resolve path to dependency object: %s", dependency); lld_delete_link_config(config);
print_message(Warning,
"failed to resolve path to dependency object: %s",
dependency);
lld_delete_link_config(config);
lld_delete_link_config(config);
g_free((void*) library);
return NULL;

View File

@ -8,7 +8,10 @@
#include <codegen/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);

View File

@ -4,16 +4,16 @@
#include <llvm/llvm-ir/expr.h>
#include <llvm/llvm-ir/types.h>
#include <sys/log.h>
#include <mem/cache.h>
#include <sys/log.h>
BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit,
LLVMLocalScope *scope,
BackendError impl_bitwise_operation(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope,
LLVMBuilderRef builder,
Operation *operation,
LLVMValueRef *llvm_result) {
Expression *rhs = NULL;
Expression *lhs = NULL;
Operation* operation,
LLVMValueRef* llvm_result) {
Expression* rhs = NULL;
Expression* lhs = NULL;
LLVMValueRef llvm_rhs = NULL;
LLVMValueRef llvm_lhs = NULL;
@ -32,13 +32,16 @@ BackendError impl_bitwise_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.bitwise) {
case BitwiseAnd:
*llvm_result = LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "bitwise and");
*llvm_result =
LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "bitwise and");
break;
case BitwiseOr:
*llvm_result = LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "bitwise or");
*llvm_result =
LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "bitwise or");
break;
case BitwiseXor:
*llvm_result = LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "bitwise xor");
*llvm_result =
LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "bitwise xor");
break;
case BitwiseNot:
*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.
* A boolean value hereby meaning an integer of the same type as the input
* value but with the value of either 0 or one.
* A boolean value hereby meaning an integer of the same type as the
* input value but with the value of either 0 or one.
* @param builder
* @param integral
* @return
*/
[[maybe_unused]]
static LLVMValueRef convert_integral_to_boolean(
LLVMBuilderRef builder, LLVMValueRef integral) {
[[maybe_unused]]
static LLVMValueRef convert_integral_to_boolean(LLVMBuilderRef builder,
LLVMValueRef integral) {
// type of input
LLVMTypeRef valueType = LLVMTypeOf(integral);
// zero value of same type as integral
@ -67,13 +70,13 @@ static LLVMValueRef convert_integral_to_boolean(
return LLVMBuildICmp(builder, LLVMIntNE, zero, integral, "to boolean");
}
BackendError impl_logical_operation(LLVMBackendCompileUnit *unit,
LLVMLocalScope *scope,
BackendError impl_logical_operation(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope,
LLVMBuilderRef builder,
Operation *operation,
LLVMValueRef *llvm_result) {
Expression *rhs = NULL;
Expression *lhs = NULL;
Operation* operation,
LLVMValueRef* llvm_result) {
Expression* rhs = NULL;
Expression* lhs = NULL;
LLVMValueRef llvm_rhs = NULL;
LLVMValueRef llvm_lhs = NULL;
@ -92,13 +95,16 @@ BackendError impl_logical_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.logical) {
case LogicalAnd:
*llvm_result = LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "logical and");
*llvm_result =
LLVMBuildAnd(builder, llvm_lhs, llvm_rhs, "logical and");
break;
case LogicalOr:
*llvm_result = LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "logical or");
*llvm_result =
LLVMBuildOr(builder, llvm_lhs, llvm_rhs, "logical or");
break;
case LogicalXor:
*llvm_result = LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "logical xor");
*llvm_result =
LLVMBuildXor(builder, llvm_lhs, llvm_rhs, "logical xor");
break;
case LogicalNot:
*llvm_result = LLVMBuildNot(builder, llvm_rhs, "logical not");
@ -108,7 +114,7 @@ BackendError impl_logical_operation(LLVMBackendCompileUnit *unit,
return SUCCESS;
}
static LLVMBool is_floating_point(Type *value) {
static LLVMBool is_floating_point(Type* value) {
if (value->kind == TypeKindPrimitive) {
return value->impl.primitive == Float;
}
@ -120,7 +126,7 @@ static LLVMBool is_floating_point(Type *value) {
return FALSE;
}
static LLVMBool is_integral(Type *value) {
static LLVMBool is_integral(Type* value) {
if (value->kind == TypeKindPrimitive) {
return value->impl.primitive == Int;
}
@ -132,13 +138,13 @@ static LLVMBool is_integral(Type *value) {
return FALSE;
}
BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
LLVMLocalScope *scope,
BackendError impl_relational_operation(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope,
LLVMBuilderRef builder,
Operation *operation,
LLVMValueRef *llvm_result) {
Expression *rhs = NULL;
Expression *lhs = NULL;
Operation* operation,
LLVMValueRef* llvm_result) {
Expression* rhs = NULL;
Expression* lhs = NULL;
LLVMValueRef llvm_rhs = NULL;
LLVMValueRef llvm_lhs = NULL;
@ -151,39 +157,41 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
if (is_integral(rhs->result)) {
// integral type
LLVMIntPredicate operator = 0;
LLVMIntPredicate operator= 0;
switch (operation->impl.relational) {
case Equal:
operator = LLVMIntEQ;
operator= LLVMIntEQ;
break;
case Greater:
operator = LLVMIntSGT;
operator= LLVMIntSGT;
break;
case Less:
operator = LLVMIntSLT;
operator= LLVMIntSLT;
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)) {
// integral type
LLVMRealPredicate operator = 0;
LLVMRealPredicate operator= 0;
switch (operation->impl.relational) {
case Equal:
operator = LLVMRealOEQ;
operator= LLVMRealOEQ;
break;
case Greater:
operator = LLVMRealOGT;
operator= LLVMRealOGT;
break;
case Less:
operator = LLVMRealOLT;
operator= LLVMRealOLT;
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 {
PANIC("invalid type for relational operator");
}
@ -193,13 +201,13 @@ BackendError impl_relational_operation(LLVMBackendCompileUnit *unit,
return SUCCESS;
}
BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
LLVMLocalScope *scope,
BackendError impl_arithmetic_operation(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope,
LLVMBuilderRef builder,
Operation *operation,
LLVMValueRef *llvm_result) {
Expression *rhs = NULL;
Expression *lhs = NULL;
Operation* operation,
LLVMValueRef* llvm_result) {
Expression* rhs = NULL;
Expression* lhs = NULL;
LLVMValueRef llvm_rhs = NULL;
LLVMValueRef llvm_lhs = NULL;
@ -220,19 +228,24 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.arithmetic) {
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;
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;
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;
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;
case Negate:
*llvm_result = LLVMBuildNeg(builder, llvm_rhs, "signed integer negate");
*llvm_result =
LLVMBuildNeg(builder, llvm_rhs, "signed integer negate");
break;
}
@ -240,19 +253,24 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
switch (operation->impl.arithmetic) {
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;
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;
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;
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;
case Negate:
*llvm_result = LLVMBuildFNeg(builder, llvm_rhs, "floating point negate");
*llvm_result =
LLVMBuildFNeg(builder, llvm_rhs, "floating point negate");
break;
}
@ -263,9 +281,9 @@ BackendError impl_arithmetic_operation(LLVMBackendCompileUnit *unit,
return SUCCESS;
}
BackendError impl_operation(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Operation *operation,
LLVMValueRef *llvm_result) {
BackendError impl_operation(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Operation* operation,
LLVMValueRef* llvm_result) {
BackendError err;
switch (operation->kind) {
@ -292,9 +310,9 @@ BackendError impl_operation(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
return err;
}
BackendError impl_transmute(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Transmute *transmute,
LLVMValueRef *llvm_result) {
BackendError impl_transmute(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Transmute* transmute,
LLVMValueRef* llvm_result) {
LLVMValueRef operand = NULL;
impl_expr(unit, scope, builder, transmute->operand, FALSE, 0, &operand);
@ -305,13 +323,13 @@ BackendError impl_transmute(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
// if target type is valid
if (err.kind == Success) {
*llvm_result =
LLVMBuildBitCast(builder, operand, target_type, "transmute");
LLVMBuildBitCast(builder, operand, target_type, "transmute");
}
return err;
}
static LLVMBool is_type_signed(const Type *type) {
static LLVMBool is_type_signed(const Type* type) {
switch (type->kind) {
case TypeKindPrimitive:
return 1;
@ -322,10 +340,9 @@ static LLVMBool is_type_signed(const Type *type) {
}
}
BackendError impl_typecast(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, TypeCast *typecast,
bool reference,
LLVMValueRef *llvm_result) {
BackendError impl_typecast(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, TypeCast* typecast,
bool reference, LLVMValueRef* llvm_result) {
LLVMValueRef operand = NULL;
impl_expr(unit, scope, builder, typecast->operand, reference, 0, &operand);
@ -340,17 +357,17 @@ BackendError impl_typecast(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBool dst_signed = is_type_signed(typecast->targetType);
LLVMBool src_signed = is_type_signed(typecast->operand->result);
const LLVMOpcode opcode =
LLVMGetCastOpcode(operand, src_signed, target_type, dst_signed);
LLVMGetCastOpcode(operand, src_signed, target_type, dst_signed);
*llvm_result =
LLVMBuildCast(builder, opcode, operand, target_type, "expr.typecast");
LLVMBuildCast(builder, opcode, operand, target_type, "expr.typecast");
return err;
}
BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Variable *variable,
LLVMBool reference,
LLVMValueRef *llvm_result) {
BackendError impl_variable_load(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope, LLVMBuilderRef builder,
Variable* variable, LLVMBool reference,
LLVMValueRef* llvm_result) {
LLVMValueRef llvm_variable = get_variable(scope, variable->name);
@ -363,7 +380,8 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
}
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) {
@ -379,7 +397,8 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
*llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
*llvm_result =
LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
} else {
*llvm_result = llvm_variable;
}
@ -388,14 +407,15 @@ BackendError impl_variable_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *sc
return SUCCESS;
}
BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Parameter *parameter,
LLVMBool reference,
LLVMValueRef *llvm_result) {
BackendError impl_parameter_load(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope, LLVMBuilderRef builder,
Parameter* parameter, LLVMBool reference,
LLVMValueRef* llvm_result) {
LLVMValueRef llvm_variable = NULL;
if (g_hash_table_contains(scope->func_scope->params, parameter->name)) {
llvm_variable = g_hash_table_lookup(scope->func_scope->params, parameter->name);
llvm_variable =
g_hash_table_lookup(scope->func_scope->params, parameter->name);
}
Type* type;
@ -410,7 +430,8 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
type = decl.type;
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) {
@ -422,7 +443,8 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
get_type_impl(unit, scope->func_scope->global_scope, type, &llvm_type);
if (LLVMGetTypeKind(LLVMTypeOf(llvm_variable)) == LLVMPointerTypeKind) {
*llvm_result = LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
*llvm_result =
LLVMBuildLoad2(builder, llvm_type, llvm_variable, "");
} else {
*llvm_result = llvm_variable;
}
@ -431,11 +453,12 @@ BackendError impl_parameter_load(LLVMBackendCompileUnit *unit, LLVMLocalScope *s
return SUCCESS;
}
BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, AddressOf* addressOf,
LLVMValueRef *llvm_result) {
BackendError impl_address_of(LLVMBackendCompileUnit* unit,
LLVMLocalScope* scope, LLVMBuilderRef builder,
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) {
return err;
@ -444,45 +467,49 @@ BackendError impl_address_of(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope
return SUCCESS;
}
BackendError impl_deref(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Dereference* dereference,
bool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result) {
BackendError impl_deref(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Dereference* dereference,
bool reference, uint32_t deref_depth,
LLVMValueRef* llvm_result) {
BackendError err;
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) {
return err;
}
LLVMTypeRef llvm_deref_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, dereference->variable->result->impl.reference, &llvm_deref_type);
err = get_type_impl(unit, scope->func_scope->global_scope,
dereference->variable->result->impl.reference,
&llvm_deref_type);
if (err.kind != Success) {
return err;
}
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) {
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) {
*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;
}
BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Expression *expr,
LLVMBool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result) {
BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Expression* expr,
LLVMBool reference, uint32_t deref_depth,
LLVMValueRef* llvm_result) {
DEBUG("implementing expression: %ld", expr->kind);
BackendError err = SUCCESS;
@ -497,8 +524,7 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break;
case ExpressionKindTypeCast:
err = impl_typecast(unit, scope, builder, &expr->impl.typecast,
reference,
llvm_result);
reference, llvm_result);
break;
case ExpressionKindOperation:
err = impl_operation(unit, scope, builder, &expr->impl.operation,
@ -506,13 +532,12 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break;
case ExpressionKindVariable:
err = impl_variable_load(unit, scope, builder, expr->impl.variable,
reference,
llvm_result);
reference, llvm_result);
break;
case ExpressionKindParameter:
err = impl_parameter_load(unit, scope, builder, expr->impl.parameter,
reference,
llvm_result);
err =
impl_parameter_load(unit, scope, builder, expr->impl.parameter,
reference, llvm_result);
break;
case ExpressionKindAddressOf:
err = impl_address_of(unit, scope, builder, &expr->impl.addressOf,
@ -520,15 +545,15 @@ BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
break;
case ExpressionKindDereference:
err = impl_deref(unit, scope, builder, &expr->impl.dereference,
reference,
deref_depth,
llvm_result);
reference, deref_depth, llvm_result);
break;
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;
default:
err = new_backend_impl_error(Implementation, NULL, "unknown expression");
err = new_backend_impl_error(Implementation, NULL,
"unknown expression");
break;
}

View File

@ -10,10 +10,9 @@
#include <llvm/llvm-ir/func.h>
#include <llvm/parser.h>
BackendError impl_expr(LLVMBackendCompileUnit *unit, LLVMLocalScope *scope,
LLVMBuilderRef builder, Expression *expr,
LLVMBool reference,
uint32_t deref_depth,
LLVMValueRef *llvm_result);
BackendError impl_expr(LLVMBackendCompileUnit* unit, LLVMLocalScope* scope,
LLVMBuilderRef builder, Expression* expr,
LLVMBool reference, uint32_t deref_depth,
LLVMValueRef* llvm_result);
#endif // LLVM_BACKEND_EXPR_H
#endif // LLVM_BACKEND_EXPR_H

View File

@ -2,21 +2,21 @@
#include <codegen/backend.h>
#include <llvm-c/Core.h>
#include <llvm-c/Types.h>
#include <llvm/llvm-ir/expr.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/types.h>
#include <llvm/llvm-ir/variables.h>
#include <llvm/parser.h>
#include <mem/cache.h>
#include <set/types.h>
#include <sys/log.h>
#include <mem/cache.h>
#include <llvm/llvm-ir/expr.h>
LLVMLocalScope* new_local_scope(LLVMLocalScope* parent) {
LLVMLocalScope* scope = malloc(sizeof(LLVMLocalScope));
scope->func_scope = parent->func_scope;
scope->vars = g_hash_table_new(g_str_hash, g_str_equal);
scope->func_scope = parent->func_scope;
scope->vars = g_hash_table_new(g_str_hash, g_str_equal);
scope->parent_scope = parent;
return scope;
@ -27,8 +27,7 @@ void delete_local_scope(LLVMLocalScope* scope) {
free(scope);
}
LLVMValueRef get_parameter(const LLVMFuncScope* scope,
const char* name) {
LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name) {
if (g_hash_table_contains(scope->params, name)) {
return g_hash_table_lookup(scope->params, name);
}
@ -45,7 +44,8 @@ LLVMValueRef get_variable(const LLVMLocalScope* scope, const char* 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;
}
@ -63,7 +63,8 @@ LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name) {
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;
}
@ -77,17 +78,17 @@ BackendError impl_param_type(LLVMBackendCompileUnit* unit,
if (param->kind == ParameterDeclarationKind) {
gemstone_type = param->impl.declaration.type;
qualifier = param->impl.declaration.qualifier;
qualifier = param->impl.declaration.qualifier;
} else {
gemstone_type = param->impl.definiton.declaration.type;
qualifier = param->impl.definiton.declaration.qualifier;
qualifier = param->impl.definiton.declaration.qualifier;
}
// wrap output variables as pointers
if (qualifier == Out || qualifier == InOut) {
Type* reference_type = alloca(sizeof(Type));
reference_type->kind = TypeKindReference;
reference_type->kind = TypeKindReference;
reference_type->impl.reference = gemstone_type;
gemstone_type = reference_type;
@ -104,7 +105,8 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
DEBUG("implementing function declaration: %s()", func->name);
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;
if (func->kind == FunctionDeclarationKind) {
@ -117,7 +119,7 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
Parameter* param = &g_array_index(func_params, Parameter, i);
LLVMTypeRef llvm_type = NULL;
err = impl_param_type(unit, scope, param, &llvm_type);
err = impl_param_type(unit, scope, param, &llvm_type);
if (err.kind != Success) {
return err;
@ -131,17 +133,19 @@ BackendError impl_func_type(LLVMBackendCompileUnit* unit,
LLVMTypeRef llvm_return_type = LLVMVoidTypeInContext(unit->context);
if (func->kind == FunctionDeclarationKind) {
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 {
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 =
LLVMFunctionType(llvm_return_type,
(LLVMTypeRef*)llvm_params->data, llvm_params->len, 0);
LLVMTypeRef llvm_fun_type = LLVMFunctionType(
llvm_return_type, (LLVMTypeRef*) llvm_params->data, llvm_params->len, 0);
*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,
LLVMGlobalScope* global_scope,
Function* func, const char* name) {
LLVMGlobalScope* global_scope, Function* func,
const char* name) {
BackendError err = SUCCESS;
LLVMValueRef llvm_func = LLVMGetNamedFunction(unit->module, name);
@ -162,57 +166,66 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
// NOTE: lives till the end of the function
LLVMFuncScope* func_scope = alloca(sizeof(LLVMFuncScope));
func_scope->llvm_func = llvm_func;
func_scope->llvm_func = llvm_func;
func_scope->global_scope = global_scope;
func_scope->params = g_hash_table_new(g_str_hash, g_str_equal);
func_scope->params = g_hash_table_new(g_str_hash, g_str_equal);
// create function body builder
LLVMBasicBlockRef entry =
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.entry");
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.entry");
LLVMBuilderRef builder = LLVMCreateBuilderInContext(unit->context);
LLVMPositionBuilderAtEnd(builder, entry);
// create value references for parameter
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);
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_end_body_block = NULL;
err = impl_block(unit, builder, func_scope, &llvm_start_body_block, &llvm_end_body_block, func->impl.definition.body);
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);
if (err.kind == Success) {
LLVMPositionBuilderAtEnd(builder, entry);
LLVMBuildBr(builder, llvm_start_body_block);
LLVMValueRef terminator = LLVMGetBasicBlockTerminator(llvm_end_body_block);
LLVMValueRef terminator =
LLVMGetBasicBlockTerminator(llvm_end_body_block);
if (terminator == NULL) {
// insert returning end block
LLVMBasicBlockRef end_block =
LLVMAppendBasicBlockInContext(unit->context, llvm_func, "func.end");
LLVMBasicBlockRef end_block = LLVMAppendBasicBlockInContext(
unit->context, llvm_func, "func.end");
LLVMPositionBuilderAtEnd(builder, end_block);
LLVMValueRef llvm_return = NULL;
if (func->kind == FunctionDeclarationKind) {
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) {
return err;
}
LLVMBuildRet(builder, llvm_return);
}else {
} else {
LLVMBuildRetVoid(builder);
}
} else {
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) {
return err;
}
@ -237,7 +250,8 @@ BackendError impl_func_def(LLVMBackendCompileUnit* unit,
}
BackendError impl_function_types(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope, GHashTable* functions) {
LLVMGlobalScope* scope,
GHashTable* functions) {
DEBUG("implementing functions...");
GHashTableIter iterator;
g_hash_table_iter_init(&iterator, functions);
@ -271,7 +285,7 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit,
Function* func = (Function*) val;
if (func->kind != FunctionDeclarationKind) {
err = impl_func_def(unit, scope, func, (const char*)key);
err = impl_func_def(unit, scope, func, (const char*) key);
}
if (err.kind != Success) {
@ -285,22 +299,23 @@ BackendError impl_functions(LLVMBackendCompileUnit* unit,
return err;
}
gboolean is_parameter_out(Parameter *param) {
gboolean is_parameter_out(Parameter* param) {
gboolean is_out = FALSE;
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 {
is_out = param->impl.definiton.declaration.qualifier == Out ||
param->impl.definiton.declaration.qualifier == InOut;
is_out = param->impl.definiton.declaration.qualifier == Out
|| param->impl.definiton.declaration.qualifier == InOut;
}
return is_out;
}
BackendError impl_func_call(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
const FunctionCall *call,
BackendError impl_func_call(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const FunctionCall* call,
LLVMValueRef* return_value) {
DEBUG("implementing function call...");
BackendError err = SUCCESS;
@ -310,10 +325,11 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
// prevent memory allocation when number of bytes would be zero
// avoid going of assertion in memory cache
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++) {
Expression *arg = g_array_index(call->expressions, Expression*, i);
Expression* arg = g_array_index(call->expressions, Expression*, i);
GArray* param_list;
if (call->function->kind == FunctionDeclarationKind) {
@ -325,18 +341,24 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
Parameter param = g_array_index(param_list, Parameter, i);
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) {
break;
}
if (is_parameter_out(&param)) {
if ((arg->kind == ExpressionKindParameter && !is_parameter_out(arg->impl.parameter)) || arg->kind != ExpressionKindParameter) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), 0, false);
if ((arg->kind == ExpressionKindParameter
&& !is_parameter_out(arg->impl.parameter))
|| arg->kind != ExpressionKindParameter) {
LLVMValueRef index =
LLVMConstInt(LLVMInt32Type(), 0, false);
LLVMTypeRef llvm_type = NULL;
get_type_impl(unit, scope->func_scope->global_scope, param.impl.declaration.type, &llvm_type);
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg, &index, 1, "");
get_type_impl(unit, scope->func_scope->global_scope,
param.impl.declaration.type, &llvm_type);
llvm_arg = LLVMBuildGEP2(builder, llvm_type, llvm_arg,
&index, 1, "");
}
}
@ -345,16 +367,20 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
}
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) {
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) {
*return_value = value;
@ -363,4 +389,3 @@ BackendError impl_func_call(LLVMBackendCompileUnit *unit,
return err;
}

View File

@ -2,9 +2,8 @@
#ifndef LLVM_BACKEND_FUNC_H_
#define LLVM_BACKEND_FUNC_H_
#include <llvm/parser.h>
#include <glib.h>
#include <llvm/parser.h>
typedef struct LLVMFuncScope_t {
LLVMGlobalScope* global_scope;
@ -33,16 +32,14 @@ LLVMValueRef get_parameter(const LLVMFuncScope* scope, const char* name);
LLVMBool is_parameter(const LLVMLocalScope* scope, const char* name);
BackendError impl_function_types(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope,
GHashTable* variables);
LLVMGlobalScope* scope, GHashTable* variables);
BackendError impl_functions(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope,
GHashTable* variables);
LLVMGlobalScope* scope, GHashTable* variables);
BackendError impl_func_call(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
const FunctionCall *call,
BackendError impl_func_call(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const FunctionCall* call,
LLVMValueRef* return_value);
#endif // LLVM_BACKEND_FUNC_H_

View File

@ -2,72 +2,74 @@
// Created by servostar on 5/28/24.
//
#include <assert.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/func.h>
#include <llvm/llvm-ir/stmt.h>
#include <llvm/llvm-ir/types.h>
#include <assert.h>
#include <llvm/parser.h>
#include <mem/cache.h>
#include <sys/log.h>
BackendError impl_param_load(
LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
const StorageExpr *expr,
LLVMValueRef* storage_target) {
BackendError impl_param_load(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const StorageExpr* expr,
LLVMValueRef* storage_target) {
BackendError err = SUCCESS;
if (expr->impl.parameter->impl.declaration.qualifier == Out || expr->impl.parameter->impl.declaration.qualifier == InOut) {
if (expr->impl.parameter->impl.declaration.qualifier == Out
|| expr->impl.parameter->impl.declaration.qualifier == InOut) {
LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope->func_scope->global_scope, expr->impl.parameter->impl.declaration.type, &llvm_type);
err = get_type_impl(unit, scope->func_scope->global_scope,
expr->impl.parameter->impl.declaration.type,
&llvm_type);
if (err.kind != Success) {
return err;
}
*storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target, "strg.param.out.load");
*storage_target = LLVMBuildLoad2(builder, llvm_type, *storage_target,
"strg.param.out.load");
}
return err;
}
BackendError impl_storage_expr(
LLVMBackendCompileUnit *unit,
LLVMBuilderRef
builder,
LLVMLocalScope *scope,
const StorageExpr *expr,
LLVMValueRef* storage_target) {
BackendError impl_storage_expr(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const StorageExpr* expr,
LLVMValueRef* storage_target) {
BackendError err = SUCCESS;
switch (expr->kind) {
case StorageExprKindVariable:
*storage_target =
get_variable(scope, expr->impl.variable->name);
*storage_target = get_variable(scope, expr->impl.variable->name);
break;
case StorageExprKindParameter:
*storage_target =
get_parameter(scope->func_scope, expr->impl.parameter->name);
get_parameter(scope->func_scope, expr->impl.parameter->name);
break;
case StorageExprKindDereference:
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) {
return err;
}
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) {
return err;
}
if (expr->impl.dereference.array->kind == StorageExprKindParameter) {
err = impl_param_load(unit, builder, scope, expr->impl.dereference.array, &array);
if (expr->impl.dereference.array->kind
== StorageExprKindParameter) {
err = impl_param_load(unit, builder, scope,
expr->impl.dereference.array, &array);
if (err.kind != Success) {
return err;
}
@ -75,21 +77,26 @@ BackendError impl_storage_expr(
if (true) {
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) {
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;
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) {
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;
case StorageExprKindBoxAccess:
@ -100,24 +107,22 @@ BackendError impl_storage_expr(
return err;
}
BackendError impl_assign_stmt(
LLVMBackendCompileUnit *unit,
LLVMBuilderRef
builder,
LLVMLocalScope *scope,
const Assignment *assignment
) {
BackendError impl_assign_stmt(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const Assignment* assignment) {
BackendError err = SUCCESS;
DEBUG("implementing assignment for variable: %p", assignment);
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) {
return err;
}
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) {
return err;
}
@ -127,16 +132,18 @@ BackendError impl_assign_stmt(
return err;
}
BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
const Block *block, LLVMBasicBlockRef *llvm_start_block, LLVMBasicBlockRef *llvm_end_block) {
BackendError impl_basic_block(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
const Block* block,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block) {
DEBUG("implementing basic block...");
BackendError err = SUCCESS;
LLVMLocalScope *block_scope = new_local_scope(scope);
LLVMLocalScope* block_scope = new_local_scope(scope);
// append a new LLVM basic block
*llvm_start_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"stmt.block.start");
*llvm_start_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "stmt.block.start");
LLVMPositionBuilderAtEnd(builder, *llvm_start_block);
LLVMBasicBlockRef end_previous_block = *llvm_start_block;
@ -148,8 +155,9 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
Statement* stmt = g_array_index(block->statemnts, Statement*, i);
LLVMBasicBlockRef llvm_next_start_block = NULL;
LLVMBasicBlockRef llvm_next_end_block = NULL;
err = impl_stmt(unit, builder, scope, stmt, &llvm_next_start_block, &llvm_next_end_block);
LLVMBasicBlockRef llvm_next_end_block = NULL;
err = impl_stmt(unit, builder, scope, stmt, &llvm_next_start_block,
&llvm_next_end_block);
if (err.kind != Success) {
return err;
}
@ -164,8 +172,8 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
}
if (terminated) {
end_previous_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"ret.after");
end_previous_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "ret.after");
LLVMPositionBuilderAtEnd(builder, end_previous_block);
}
}
@ -177,30 +185,32 @@ BackendError impl_basic_block(LLVMBackendCompileUnit *unit,
return err;
}
BackendError impl_while(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
BackendError impl_while(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block,
const While *while_stmt) {
const While* while_stmt) {
DEBUG("implementing while...");
BackendError err;
// Create condition block
LLVMBasicBlockRef while_cond_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"loop.while.cond");
LLVMBasicBlockRef while_cond_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "loop.while.cond");
*llvm_start_block = while_cond_block;
LLVMPositionBuilderAtEnd(builder, while_cond_block);
// Resolve condition in block to a variable
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) {
return err;
}
// build body of loop
LLVMBasicBlockRef while_start_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);
LLVMBasicBlockRef while_end_body_block = NULL;
err = impl_basic_block(unit, builder, scope, &while_stmt->block,
&while_start_body_block, &while_end_body_block);
if (err.kind != Success) {
return err;
}
@ -210,11 +220,12 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
LLVMBuildBr(builder, while_cond_block);
// builder will continue after the loop
LLVMBasicBlockRef while_after_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"loop.while.after");
LLVMBasicBlockRef while_after_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "loop.while.after");
// build conditional branch at end of condition 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);
@ -223,46 +234,52 @@ BackendError impl_while(LLVMBackendCompileUnit *unit,
return err;
}
BackendError
impl_cond_block(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLVMLocalScope *scope, Expression *cond,
const Block *block, LLVMBasicBlockRef *cond_block, LLVMBasicBlockRef *start_body_block, LLVMBasicBlockRef *end_body_block,
LLVMValueRef *llvm_cond) {
BackendError impl_cond_block(LLVMBackendCompileUnit* unit,
LLVMBuilderRef builder, LLVMLocalScope* scope,
Expression* cond, const Block* block,
LLVMBasicBlockRef* cond_block,
LLVMBasicBlockRef* start_body_block,
LLVMBasicBlockRef* end_body_block,
LLVMValueRef* llvm_cond) {
BackendError err;
*cond_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"stmt.branch.cond");
*cond_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "stmt.branch.cond");
LLVMPositionBuilderAtEnd(builder, *cond_block);
// Resolve condition in block to a variable
err = impl_expr(unit, scope, builder, cond, FALSE, 0, llvm_cond);
if (err.kind == Success) {
// 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;
}
BackendError impl_branch(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMLocalScope *scope,
BackendError impl_branch(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope,
LLVMBasicBlockRef* branch_start_block,
LLVMBasicBlockRef* branch_end_block,
const Branch *branch) {
const Branch* branch) {
BackendError err = SUCCESS;
GArray *cond_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef));
GArray *start_body_blocks = 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_blocks = g_array_new(FALSE, FALSE, sizeof(LLVMBasicBlockRef));
GArray* start_body_blocks =
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));
// add If to arrays
{
LLVMBasicBlockRef cond_block = NULL;
LLVMBasicBlockRef cond_block = NULL;
LLVMBasicBlockRef start_body_block = NULL;
LLVMBasicBlockRef end_body_block = NULL;
LLVMValueRef cond_value = NULL;
LLVMBasicBlockRef end_body_block = NULL;
LLVMValueRef cond_value = NULL;
err = impl_cond_block(unit, builder, scope, branch->ifBranch.conditon, &branch->ifBranch.block,
&cond_block,
err = impl_cond_block(unit, builder, scope, branch->ifBranch.conditon,
&branch->ifBranch.block, &cond_block,
&start_body_block, &end_body_block, &cond_value);
g_array_append_val(cond_blocks, cond_block);
@ -274,15 +291,16 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
// generate else if(s)
if (branch->elseIfBranches != NULL) {
for (size_t i = 0; i < branch->elseIfBranches->len; i++) {
LLVMBasicBlockRef cond_block = NULL;
LLVMBasicBlockRef cond_block = NULL;
LLVMBasicBlockRef start_body_block = NULL;
LLVMBasicBlockRef end_body_block = NULL;
LLVMValueRef cond_value = NULL;
LLVMBasicBlockRef end_body_block = NULL;
LLVMValueRef cond_value = NULL;
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,
&start_body_block, &end_body_block, &cond_value);
err = impl_cond_block(
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(start_body_blocks, start_body_block);
@ -296,13 +314,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
// else block
if (branch->elseBranch.block.statemnts != 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);
}
if (after_block == NULL) {
after_block = LLVMAppendBasicBlockInContext(unit->context, scope->func_scope->llvm_func,
"stmt.branch.after");
after_block = LLVMAppendBasicBlockInContext(
unit->context, scope->func_scope->llvm_func, "stmt.branch.after");
}
LLVMPositionBuilderAtEnd(builder, after_block);
@ -313,10 +332,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
}
for (size_t i = 0; i < cond_blocks->len - 1; i++) {
LLVMBasicBlockRef next_block = g_array_index(cond_blocks, LLVMBasicBlockRef, i + 1);
LLVMBasicBlockRef cond_block = 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);
LLVMBasicBlockRef next_block =
g_array_index(cond_blocks, LLVMBasicBlockRef, i + 1);
LLVMBasicBlockRef cond_block =
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);
LLVMPositionBuilderAtEnd(builder, cond_block);
@ -327,7 +350,7 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
}
*branch_start_block = g_array_index(cond_blocks, LLVMBasicBlockRef, 0);
*branch_end_block = after_block;
*branch_end_block = after_block;
g_array_free(cond_blocks, TRUE);
g_array_free(start_body_blocks, TRUE);
@ -337,15 +360,14 @@ BackendError impl_branch(LLVMBackendCompileUnit *unit,
return err;
}
BackendError impl_decl(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
VariableDeclaration *decl,
const char *name) {
BackendError impl_decl(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope, VariableDeclaration* decl,
const char* name) {
DEBUG("implementing local declaration: %s", name);
BackendError err = SUCCESS;
BackendError err = SUCCESS;
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) {
return err;
@ -355,7 +377,8 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit,
LLVMValueRef local = LLVMBuildAlloca(builder, llvm_type, name);
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) {
DEBUG("setting default value...");
@ -368,10 +391,8 @@ BackendError impl_decl(LLVMBackendCompileUnit *unit,
return err;
}
BackendError impl_return(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
Return *returnStmt) {
BackendError impl_return(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope, Return* returnStmt) {
BackendError err = SUCCESS;
LLVMValueRef expr = NULL;
@ -385,22 +406,22 @@ BackendError impl_return(LLVMBackendCompileUnit *unit,
return err;
}
BackendError impl_def(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
VariableDefiniton *def,
const char *name) {
BackendError impl_def(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope, VariableDefiniton* def,
const char* name) {
DEBUG("implementing local definition: %s", name);
BackendError err = SUCCESS;
BackendError err = SUCCESS;
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) {
return err;
}
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) {
return err;
}
@ -414,45 +435,52 @@ BackendError impl_def(LLVMBackendCompileUnit *unit,
return err;
}
BackendError impl_var(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder,
LLVMLocalScope *scope,
Variable *var) {
BackendError impl_var(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMLocalScope* scope, Variable* var) {
BackendError err;
switch (var->kind) {
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;
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;
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;
}
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);
DEBUG("implementing statement: %ld", stmt->kind);
BackendError err;
switch (stmt->kind) {
case StatementKindAssignment:
err = impl_assign_stmt(unit, builder, scope, &stmt->impl.assignment);
err =
impl_assign_stmt(unit, builder, scope, &stmt->impl.assignment);
break;
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;
case StatementKindDeclaration:
case StatementKindDefinition:
err = impl_var(unit, builder, scope, stmt->impl.variable);
break;
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;
case StatementKindFunctionCall:
err = impl_func_call(unit, builder, scope, &stmt->impl.call, NULL);
@ -461,27 +489,28 @@ BackendError impl_stmt(LLVMBackendCompileUnit *unit, LLVMBuilderRef builder, LLV
err = impl_return(unit, builder, scope, &stmt->impl.returnStmt);
break;
default:
err = new_backend_impl_error(Implementation, NULL, "Unexpected statement kind");
err = new_backend_impl_error(Implementation, NULL,
"Unexpected statement kind");
break;
}
return err;
}
BackendError impl_block(LLVMBackendCompileUnit *unit,
LLVMBuilderRef builder, LLVMFuncScope *scope,
BackendError impl_block(LLVMBackendCompileUnit* unit, LLVMBuilderRef builder,
LLVMFuncScope* scope,
LLVMBasicBlockRef* llvm_start_block,
LLVMBasicBlockRef* llvm_end_block,
const Block *block) {
LLVMBasicBlockRef* llvm_end_block, const Block* block) {
DEBUG("Implementing function block...");
BackendError err = SUCCESS;
LLVMLocalScope *function_entry_scope = malloc(sizeof(LLVMLocalScope));
function_entry_scope->func_scope = scope;
LLVMLocalScope* function_entry_scope = malloc(sizeof(LLVMLocalScope));
function_entry_scope->func_scope = scope;
function_entry_scope->vars = g_hash_table_new(g_str_hash, g_str_equal);
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);

View File

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

View File

@ -3,12 +3,12 @@
#include <llvm-c/Types.h>
#include <llvm/llvm-ir/types.h>
#include <llvm/parser.h>
#include <mem/cache.h>
#include <set/set.h>
#include <set/types.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
static BackendError get_const_primitive_value(PrimitiveType primitive,
@ -24,7 +24,7 @@ static BackendError get_const_primitive_value(PrimitiveType primitive,
break;
case Char:
gunichar codepoint = g_utf8_get_char(value);
*llvm_value = LLVMConstInt(llvm_type, codepoint, false);
*llvm_value = LLVMConstInt(llvm_type, codepoint, false);
break;
}
@ -39,28 +39,35 @@ static BackendError get_const_composite_value(CompositeType composite,
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;
if (compareTypes(value->type, (Type*) &StringLiteralType)) {
// 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];
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);
LLVMSetGlobalConstant(string_global, true);
LLVMSetUnnamedAddress(string_global, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(string_global, 1);
// Cast the global variable to a pointer type if needed
LLVMTypeRef i8_ptr_type = LLVMPointerType(LLVMInt8TypeInContext(unit->context), 0);
LLVMValueRef global_str_ptr = LLVMConstBitCast(string_global, i8_ptr_type);
LLVMTypeRef i8_ptr_type =
LLVMPointerType(LLVMInt8TypeInContext(unit->context), 0);
LLVMValueRef global_str_ptr =
LLVMConstBitCast(string_global, i8_ptr_type);
*llvm_value = global_str_ptr;
} 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;
}
@ -79,22 +86,22 @@ BackendError get_const_type_value(LLVMBackendCompileUnit* unit,
switch (gemstone_value->type->kind) {
case TypeKindPrimitive:
err = get_const_primitive_value(gemstone_value->type->impl.primitive,
llvm_type, gemstone_value->value,
llvm_value);
err = get_const_primitive_value(
gemstone_value->type->impl.primitive, llvm_type,
gemstone_value->value, llvm_value);
break;
case TypeKindComposite:
err = get_const_composite_value(gemstone_value->type->impl.composite,
llvm_type, gemstone_value->value,
llvm_value);
err = get_const_composite_value(
gemstone_value->type->impl.composite, llvm_type,
gemstone_value->value, llvm_value);
break;
case TypeKindReference:
err = impl_reference_const(unit, gemstone_value, llvm_value);
break;
case TypeKindBox:
err =
new_backend_impl_error(Implementation, gemstone_value->nodePtr,
"boxes cannot be constant value");
new_backend_impl_error(Implementation, gemstone_value->nodePtr,
"boxes cannot be constant value");
break;
default:
PANIC("invalid value kind: %ld", gemstone_value->type->kind);
@ -128,7 +135,7 @@ BackendError impl_primtive_type(LLVMBackendCompileUnit* unit,
BackendError impl_integral_type(LLVMBackendCompileUnit* unit, Scale scale,
LLVMTypeRef* llvm_type) {
size_t bits = (int)(BASE_BYTES * scale) * BITS_PER_BYTE;
size_t bits = (int) (BASE_BYTES * scale) * BITS_PER_BYTE;
DEBUG("implementing integral type of size: %ld", bits);
LLVMTypeRef integral_type = LLVMIntTypeInContext(unit->context, bits);
@ -142,7 +149,7 @@ BackendError impl_float_type(LLVMBackendCompileUnit* unit, Scale scale,
DEBUG("implementing floating point...");
LLVMTypeRef float_type = NULL;
size_t bytes = (int)(scale * BASE_BYTES);
size_t bytes = (int) (scale * BASE_BYTES);
DEBUG("requested float of bytes: %ld", bytes);
switch (bytes) {
case 2:
@ -188,8 +195,8 @@ BackendError impl_composite_type(LLVMBackendCompileUnit* unit,
} else {
ERROR("unsigned floating point not supported");
err = new_backend_impl_error(
Implementation, composite->nodePtr,
"unsigned floating-point not supported");
Implementation, composite->nodePtr,
"unsigned floating-point not supported");
}
break;
default:
@ -228,7 +235,7 @@ BackendError get_type_impl(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
break;
case TypeKindBox:
err =
impl_box_type(unit, scope, gemstone_type->impl.box, llvm_type);
impl_box_type(unit, scope, gemstone_type->impl.box, llvm_type);
break;
default:
PANIC("invalid type kind: %ld", gemstone_type->kind);
@ -252,9 +259,9 @@ BackendError impl_box_type(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
DEBUG("implementing box members...");
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
Type* member_type = ((BoxMember*)val)->type;
Type* member_type = ((BoxMember*) val)->type;
DEBUG("implementing member: %s ", ((BoxMember*)val)->name);
DEBUG("implementing member: %s ", ((BoxMember*) val)->name);
LLVMTypeRef llvm_local_type = NULL;
err = get_type_impl(unit, scope, member_type, &llvm_local_type);
@ -269,7 +276,7 @@ BackendError impl_box_type(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
if (err.kind == Success) {
*llvm_type =
LLVMStructType((LLVMTypeRef*)members->data, members->len, 0);
LLVMStructType((LLVMTypeRef*) members->data, members->len, 0);
}
g_array_free(members, FALSE);
@ -284,7 +291,7 @@ BackendError impl_reference_type(LLVMBackendCompileUnit* unit,
DEBUG("implementing reference type...");
BackendError err = SUCCESS;
LLVMTypeRef type = NULL;
err = get_type_impl(unit, scope, reference, &type);
err = get_type_impl(unit, scope, reference, &type);
if (err.kind == Success) {
*llvm_type = LLVMPointerType(type, 0);
@ -302,16 +309,18 @@ BackendError impl_type(LLVMBackendCompileUnit* unit, Type* gemstone_type,
err = get_type_impl(unit, scope, gemstone_type, &llvm_type);
if (err.kind == Success) {
g_hash_table_insert(scope->types, (gpointer)alias, llvm_type);
g_hash_table_insert(scope->types, (gpointer) alias, llvm_type);
}
return err;
}
BackendError impl_type_define(LLVMBackendCompileUnit* unit, Typedefine* gemstone_type,
const char* alias, LLVMGlobalScope* scope) {
BackendError impl_type_define(LLVMBackendCompileUnit* unit,
Typedefine* gemstone_type, const char* alias,
LLVMGlobalScope* scope) {
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);
@ -330,7 +339,8 @@ BackendError impl_types(LLVMBackendCompileUnit* unit, LLVMGlobalScope* scope,
BackendError err = SUCCESS;
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) {
break;
@ -375,8 +385,8 @@ BackendError get_composite_default_value(CompositeType* composite,
err = get_primitive_default_value(Float, llvm_type, llvm_value);
} else {
err = new_backend_impl_error(
Implementation, composite->nodePtr,
"unsigned floating-point not supported");
Implementation, composite->nodePtr,
"unsigned floating-point not supported");
}
break;
default:
@ -411,7 +421,7 @@ BackendError get_box_default_value(LLVMBackendCompileUnit* unit,
GArray* constants = g_array_new(FALSE, FALSE, sizeof(LLVMValueRef));
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
Type* member_type = ((BoxMember*)val)->type;
Type* member_type = ((BoxMember*) val)->type;
LLVMValueRef constant = NULL;
err = get_type_default_value(unit, scope, member_type, &constant);
@ -424,7 +434,7 @@ BackendError get_box_default_value(LLVMBackendCompileUnit* unit,
DEBUG("build %ld member default values", constants->len);
*llvm_value = LLVMConstNamedStruct(
llvm_type, (LLVMValueRef*)constants->data, constants->len);
llvm_type, (LLVMValueRef*) constants->data, constants->len);
g_array_free(constants, FALSE);

View File

@ -23,4 +23,4 @@ BackendError get_const_type_value(LLVMBackendCompileUnit* unit,
TypeValue* gemstone_value,
LLVMValueRef* llvm_value);
#endif // LLVM_BACKEND_TYPES_H_
#endif // LLVM_BACKEND_TYPES_H_

View File

@ -1,4 +1,6 @@
#include "expr.h"
#include <codegen/backend.h>
#include <llvm-c/Core.h>
#include <llvm-c/Types.h>
@ -7,16 +9,14 @@
#include <set/types.h>
#include <sys/log.h>
#include "expr.h"
BackendError impl_global_declaration(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope,
VariableDeclaration* decl,
const char* name) {
DEBUG("implementing global declaration: %s", name);
BackendError err = SUCCESS;
BackendError err = SUCCESS;
LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope, decl->type, &llvm_type);
err = get_type_impl(unit, scope, decl->type, &llvm_type);
if (err.kind != Success) {
return err;
@ -31,7 +31,7 @@ BackendError impl_global_declaration(LLVMBackendCompileUnit* unit,
if (err.kind == Success) {
DEBUG("setting default value...");
LLVMSetInitializer(global, initial_value);
g_hash_table_insert(scope->variables, (gpointer)name, global);
g_hash_table_insert(scope->variables, (gpointer) name, global);
} else {
ERROR("unable to initialize global variable: %s", err.impl.message);
}
@ -43,7 +43,7 @@ BackendError impl_global_definiton(LLVMBackendCompileUnit* unit,
LLVMGlobalScope* scope,
VariableDefiniton* def, const char* name) {
DEBUG("implementing global definition: %s", name);
BackendError err = SUCCESS;
BackendError err = SUCCESS;
LLVMTypeRef llvm_type = NULL;
err = get_type_impl(unit, scope, def->declaration.type, &llvm_type);
@ -56,12 +56,13 @@ BackendError impl_global_definiton(LLVMBackendCompileUnit* unit,
// FIXME: resolve initializer expression!
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) {
DEBUG("setting default value");
LLVMSetInitializer(global, initial_value);
g_hash_table_insert(scope->variables, (gpointer)name, global);
g_hash_table_insert(scope->variables, (gpointer) name, global);
}
return err;
@ -76,7 +77,7 @@ BackendError impl_global_variable(LLVMBackendCompileUnit* unit,
switch (gemstone_var->kind) {
case VariableKindDeclaration:
err = impl_global_declaration(
unit, scope, &gemstone_var->impl.declaration, alias);
unit, scope, &gemstone_var->impl.declaration, alias);
break;
case VariableKindDefinition:
err = impl_global_definiton(unit, scope,
@ -108,7 +109,7 @@ BackendError impl_global_variables(LLVMBackendCompileUnit* unit,
size_t variable_count = 0;
while (g_hash_table_iter_next(&iterator, &key, &val) != FALSE) {
err =
impl_global_variable(unit, (Variable*)val, (const char*)key, scope);
impl_global_variable(unit, (Variable*) val, (const char*) key, scope);
if (err.kind != Success) {
break;

View File

@ -14,4 +14,4 @@ BackendError impl_global_variables(LLVMBackendCompileUnit* unit,
LLVMValueRef get_global_variable(LLVMGlobalScope* scope, char* name);
#endif // LLVM_BACKEND_VARIABLES_H_
#endif // LLVM_BACKEND_VARIABLES_H_

View File

@ -1,21 +1,21 @@
#include <codegen/backend.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h>
#include <llvm-c/Target.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Types.h>
#include <llvm-c/Analysis.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/variables.h>
#include <llvm/llvm-ir/func.h>
#include <llvm/parser.h>
#include <set/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/log.h>
#include <llvm/link/lld.h>
BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
const TargetConfig* config) {
@ -28,7 +28,8 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
char* basename = g_strjoin(".", target->name.str, "ll", NULL);
// 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);
@ -51,7 +52,7 @@ BackendError export_IR(LLVMBackendCompileUnit* unit, const Target* target,
INFO("%ld bytes written to %s", bytes, filename);
g_free((char*)filename);
g_free((char*) filename);
g_free(basename);
// clean up LLVM-IR string
@ -72,11 +73,13 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
switch (file_type) {
case LLVMAssemblyFile:
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;
case LLVMObjectFile:
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;
default:
return new_backend_impl_error(Implementation, NULL,
@ -86,10 +89,11 @@ BackendError emit_module_to_file(LLVMBackendCompileUnit* unit,
INFO("export to file: %s", filename);
if (LLVMTargetMachineEmitToFile(target_machine, unit->module, filename,
file_type, &error) != 0) {
file_type, &error)
!= 0) {
ERROR("failed to emit code: %s", error);
err =
new_backend_impl_error(Implementation, NULL, "failed to emit code");
new_backend_impl_error(Implementation, NULL, "failed to emit code");
} else {
print_message(Info, "Generated code was written to: %s", filename);
@ -110,7 +114,7 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
target->triple.str, target->features.str);
LLVMTargetRef llvm_target = NULL;
char* error = NULL;
char* error = NULL;
LLVMInitializeAllTargets();
LLVMInitializeAllTargetInfos();
@ -120,8 +124,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
LLVMInitializeAllAsmPrinters();
DEBUG("creating target...");
if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error) !=
0) {
if (LLVMGetTargetFromTriple(target->triple.str, &llvm_target, &error)
!= 0) {
ERROR("failed to create target machine: %s", error);
err = new_backend_impl_error(Implementation, NULL,
"unable to create target machine");
@ -131,8 +135,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
DEBUG("Creating target machine...");
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
llvm_target, target->triple.str, target->cpu.str, target->features.str,
target->opt, target->reloc, target->model);
llvm_target, target->triple.str, target->cpu.str, target->features.str,
target->opt, target->reloc, target->model);
print_message(Info, "Generating code for: %s", target->triple.str);
@ -145,8 +149,8 @@ BackendError export_object(LLVMBackendCompileUnit* unit, const Target* target,
return err;
}
err = emit_module_to_file(unit, target_machine, LLVMObjectFile, error,
config);
err =
emit_module_to_file(unit, target_machine, LLVMObjectFile, error, config);
LLVMDisposeTargetMachine(target_machine);
@ -226,7 +230,8 @@ static BackendError build_module(LLVMBackendCompileUnit* unit,
char* error = NULL;
if (LLVMVerifyModule(unit->module, LLVMReturnStatusAction, &error)) {
print_message(Error, "Unable to compile due to: %s", error);
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);
@ -246,7 +251,7 @@ BackendError parse_module(const Module* module, const TargetConfig* config) {
DEBUG("creating LLVM context and module");
unit->context = LLVMContextCreate();
unit->module =
LLVMModuleCreateWithNameInContext(config->root_module, unit->context);
LLVMModuleCreateWithNameInContext(config->root_module, unit->context);
LLVMGlobalScope* global_scope = new_global_scope(module);
@ -260,14 +265,16 @@ BackendError parse_module(const Module* module, const TargetConfig* config) {
err = export_module(unit, &target, config);
if (err.kind == Success) {
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) {
err = lld_link_target(link_config);
lld_delete_link_config(link_config);
} else {
err = new_backend_impl_error(Implementation, NULL, "libclang error");
err = new_backend_impl_error(Implementation, NULL,
"libclang error");
}
}
}
@ -289,10 +296,10 @@ LLVMGlobalScope* new_global_scope(const Module* module) {
DEBUG("creating global scope...");
LLVMGlobalScope* scope = malloc(sizeof(LLVMGlobalScope));
scope->module = (Module*) module;
scope->module = (Module*) module;
scope->functions = g_hash_table_new(g_str_hash, g_str_equal);
scope->variables = g_hash_table_new(g_str_hash, g_str_equal);
scope->types = g_hash_table_new(g_str_hash, g_str_equal);
scope->types = g_hash_table_new(g_str_hash, g_str_equal);
return scope;
}

View File

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

View File

@ -1,25 +1,27 @@
#include <ast/ast.h>
#include <stdlib.h>
#include <sys/log.h>
#include <sys/col.h>
#include <lex/util.h>
#include <cfg/opt.h>
#include <compiler.h>
#include <lex/util.h>
#include <link/lib.h>
#include <llvm/parser.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
*
*/
void notify_exit(void) { DEBUG("Exiting gemstone..."); }
void notify_exit(void) {
DEBUG("Exiting gemstone...");
}
/**
* @brief Run compiler setup here
*
*/
void setup(int argc, char *argv[]) {
void setup(int argc, char* argv[]) {
mem_init();
// setup preample
@ -46,7 +48,7 @@ void setup(int argc, char *argv[]) {
DEBUG("finished starting up gemstone...");
}
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
if (argc <= 1) {
print_help();
exit(1);

View File

@ -2,12 +2,12 @@
// 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 <cfg/opt.h>
#include <glib.h>
#include <mem/cache.h>
#include <string.h>
#include <sys/log.h>
static GHashTable* namespaces = NULL;
@ -39,16 +39,25 @@ typedef struct MemoryNamespace_t {
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("------------------------------\n");
printf(" allocated bytes: %ld\n", memoryNamespaceStatistic->bytes_allocated);
printf(" allocations: %ld\n", memoryNamespaceStatistic->allocation_count);
printf(" reallocations: %ld\n", memoryNamespaceStatistic->reallocation_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(" allocated bytes: %ld\n",
memoryNamespaceStatistic->bytes_allocated);
printf(" allocations: %ld\n",
memoryNamespaceStatistic->allocation_count);
printf(" reallocations: %ld\n",
memoryNamespaceStatistic->reallocation_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");
}
@ -58,14 +67,14 @@ static void* namespace_malloc(MemoryNamespaceRef memoryNamespace, size_t size) {
MemoryBlock block;
block.block_ptr = malloc(size);
block.kind = GenericBlock;
block.kind = GenericBlock;
if (block.block_ptr == NULL) {
memoryNamespace->statistic.faulty_allocations ++;
memoryNamespace->statistic.faulty_allocations++;
} else {
g_array_append_val(memoryNamespace->blocks, block);
memoryNamespace->statistic.allocation_count ++;
memoryNamespace->statistic.allocation_count++;
memoryNamespace->statistic.bytes_allocated += size;
}
@ -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++) {
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) {
assert(block != NULL);
@ -105,19 +116,22 @@ static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block)
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;
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) {
reallocated_block = realloc(current_block.block_ptr, size);
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.reallocation_count ++;
memoryNamespace->statistic.reallocation_count++;
} else {
memoryNamespace->statistic.faulty_reallocations++;
}
@ -137,51 +151,55 @@ static void namespace_delete(MemoryNamespaceRef memoryNamespace) {
static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
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);
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() {
MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace));
memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(MemoryBlock));
memoryNamespace->statistic.bytes_allocated = 0;
memoryNamespace->statistic.allocation_count = 0;
memoryNamespace->statistic.manual_free_count = 0;
memoryNamespace->statistic.bytes_allocated = 0;
memoryNamespace->statistic.allocation_count = 0;
memoryNamespace->statistic.manual_free_count = 0;
memoryNamespace->statistic.faulty_reallocations = 0;
memoryNamespace->statistic.faulty_allocations = 0;
memoryNamespace->statistic.purged_free_count = 0;
memoryNamespace->statistic.reallocation_count = 0;
memoryNamespace->statistic.faulty_allocations = 0;
memoryNamespace->statistic.purged_free_count = 0;
memoryNamespace->statistic.reallocation_count = 0;
return memoryNamespace;
}
GArray *namespace_new_g_array(MemoryNamespaceRef namespace, guint size) {
GArray* namespace_new_g_array(MemoryNamespaceRef namespace, guint size) {
MemoryBlock block;
block.block_ptr = g_array_new(FALSE, FALSE, size);
block.kind = GLIB_Array;
block.kind = GLIB_Array;
g_array_append_val(namespace->blocks, block);
namespace->statistic.bytes_allocated += sizeof(GArray*);
namespace->statistic.allocation_count ++;
namespace->statistic.allocation_count++;
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;
block.block_ptr = g_hash_table_new(hash_func, key_equal_func);
block.kind = GLIB_HashTable;
block.kind = GLIB_HashTable;
g_array_append_val(namespace->blocks, block);
namespace->statistic.bytes_allocated += sizeof(GHashTable*);
namespace->statistic.allocation_count ++;
namespace->statistic.allocation_count++;
return block.block_ptr;
}
@ -193,12 +211,13 @@ static void cleanup() {
}
GHashTableIter iter;
char* name = NULL;
char* name = NULL;
MemoryNamespaceRef memoryNamespace = NULL;
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(memoryNamespace != NULL);
@ -229,7 +248,7 @@ static MemoryNamespaceRef check_namespace(MemoryNamespaceName name) {
}
}
void *mem_alloc(MemoryNamespaceName name, size_t size) {
void* mem_alloc(MemoryNamespaceName name, size_t size) {
MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) {
@ -239,7 +258,7 @@ void *mem_alloc(MemoryNamespaceName name, size_t size) {
return namespace_malloc(cache, size);
}
void *mem_realloc(MemoryNamespaceName name, void *ptr, size_t size) {
void* mem_realloc(MemoryNamespaceName name, void* ptr, size_t size) {
MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) {
@ -249,7 +268,7 @@ void *mem_realloc(MemoryNamespaceName name, void *ptr, size_t size) {
return namespace_realloc(cache, ptr, size);
}
void mem_free_from(MemoryNamespaceName name, void *memory) {
void mem_free_from(MemoryNamespaceName name, void* memory) {
MemoryNamespaceRef cache = check_namespace(name);
namespace_free(cache, memory);
@ -261,7 +280,8 @@ void mem_free(void* memory) {
MemoryNamespaceRef memoryNamespace;
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)) {
break;
@ -284,7 +304,7 @@ char* mem_strdup(MemoryNamespaceName name, char* string) {
}
void* mem_clone(MemoryNamespaceName name, void* data, size_t size) {
void *clone = mem_alloc(name, size);
void* clone = mem_alloc(name, size);
memcpy(clone, data, size);
@ -297,31 +317,36 @@ void print_memory_statistics() {
MemoryNamespaceRef memoryNamespace;
MemoryNamespaceStatistic total;
total.bytes_allocated = 0;
total.bytes_allocated = 0;
total.faulty_reallocations = 0;
total.faulty_allocations = 0;
total.manual_free_count = 0;
total.allocation_count = 0;
total.purged_free_count = 0;
total.reallocation_count = 0;
total.faulty_allocations = 0;
total.manual_free_count = 0;
total.allocation_count = 0;
total.purged_free_count = 0;
total.reallocation_count = 0;
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);
total.bytes_allocated += memoryNamespace->statistic.bytes_allocated;
total.faulty_reallocations += memoryNamespace->statistic.faulty_reallocations;
total.faulty_allocations += memoryNamespace->statistic.faulty_allocations;
total.faulty_reallocations +=
memoryNamespace->statistic.faulty_reallocations;
total.faulty_allocations +=
memoryNamespace->statistic.faulty_allocations;
total.manual_free_count += memoryNamespace->statistic.manual_free_count;
total.allocation_count += memoryNamespace->statistic.allocation_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");
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) {
@ -334,7 +359,8 @@ GArray* mem_new_g_array(MemoryNamespaceName name, guint 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);
if (cache == NULL) {

View File

@ -5,21 +5,21 @@
#ifndef GEMSTONE_CACHE_H
#define GEMSTONE_CACHE_H
#include <glib.h>
#include <mem/cache.h>
#include <stddef.h>
#include <glib.h>
typedef char* MemoryNamespaceName;
#define MemoryNamespaceAst "AST"
#define MemoryNamespaceLex "Lexer"
#define MemoryNamespaceLog "Logging"
#define MemoryNamespaceOpt "Options"
#define MemoryNamespaceTOML "TOML"
#define MemoryNamespaceSet "SET"
#define MemoryNamespaceLlvm "LLVM"
#define MemoryNamespaceLld "LLD"
#define MemoryNamespaceIo "I/O"
#define MemoryNamespaceAst "AST"
#define MemoryNamespaceLex "Lexer"
#define MemoryNamespaceLog "Logging"
#define MemoryNamespaceOpt "Options"
#define MemoryNamespaceTOML "TOML"
#define MemoryNamespaceSet "SET"
#define MemoryNamespaceLlvm "LLVM"
#define MemoryNamespaceLld "LLD"
#define MemoryNamespaceIo "I/O"
#define MemoryNamespaceStatic "Static"
/**
@ -44,7 +44,7 @@ void* mem_alloc(MemoryNamespaceName name, size_t size);
* @param size
* @return pointer to the block
*/
void* mem_realloc(MemoryNamespaceName name, void *ptr, size_t size);
void* mem_realloc(MemoryNamespaceName name, void* ptr, size_t size);
/**
* @brief Free a block of memory from a specified namespace.
@ -57,8 +57,8 @@ void mem_free_from(MemoryNamespaceName name, void* memory);
/**
* @brief Free a block of memory.
* 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()
* to avoid unnecessary overhead.
* @attention In case the namespace of the block is known, consider using
* mem_free_from() to avoid unnecessary overhead.
* @param name
* @param memory
*/
@ -91,6 +91,7 @@ void print_memory_statistics();
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

@ -4,16 +4,16 @@
#include <ast/ast.h>
#include <set/types.h>
#define SEMANTIC_OK 0
#define SEMANTIC_OK 0
#define SEMANTIC_ERROR 1
// type of string literal
extern const Type StringLiteralType;
Module * create_set(AST_NODE_PTR rootNodePtr );
Module* create_set(AST_NODE_PTR rootNodePtr);
void delete_set(Module* module);
bool compareTypes(Type *leftType, Type *rightType);
bool compareTypes(Type* leftType, Type* rightType);
#endif

View File

@ -2,8 +2,8 @@
#ifndef SET_TYPES_H_
#define SET_TYPES_H_
#include <glib.h>
#include <ast/ast.h>
#include <glib.h>
// with of primitive types (int/float) in bytes
#define BASE_BYTES 4
@ -14,9 +14,9 @@
*/
typedef enum PrimitiveType_t {
// 4 byte signed integer in two's complement
Int =0,
Int = 0,
// 4 byte IEEE-754 single precision
Float =1,
Float = 1,
// 4 byte encoded UTF-8 codepoint
Char = 2,
} PrimitiveType;
@ -67,7 +67,8 @@ typedef struct Type_t 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;
@ -93,7 +94,7 @@ typedef struct BoxMember_t {
typedef struct BoxType_t {
// hashtable of members.
// Associates the memebers name (const char*) with its type (BoxMember)
GHashTable* member; //BoxMember Pointer
GHashTable* member; // BoxMember Pointer
AST_NODE_PTR nodePtr;
} BoxType;
@ -101,7 +102,8 @@ typedef struct Variable_t Variable;
typedef struct BoxAccess_t {
// 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;
// box variable to access
Variable* variable;
@ -124,19 +126,18 @@ typedef struct Type_t {
typedef struct Typedefine_t {
const char* name;
Type *type;
Type* type;
AST_NODE_PTR nodePtr;
} 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 {
// the type
Type *type;
Type* type;
// UTF-8 representation of the type's value
const char* value;
AST_NODE_PTR nodePtr;
@ -167,7 +168,7 @@ typedef enum IO_Qualifier_t {
*
*/
typedef struct ParameterDeclaration_t {
Type *type;
Type* type;
IO_Qualifier qualifier;
AST_NODE_PTR nodePtr;
} ParameterDeclaration;
@ -180,7 +181,7 @@ typedef struct ParameterDefinition_t {
ParameterDeclaration declaration;
// value to initalize the declaration with
// NOTE: type of initializer and declaration MUST be equal
Expression *initializer;
Expression* initializer;
AST_NODE_PTR nodePtr;
} ParameterDefinition;
@ -202,7 +203,7 @@ typedef struct Parameter_t {
ParameterDefinition definiton;
} impl;
AST_NODE_PTR nodePtr;
} Parameter; // fix typo
} Parameter; // fix typo
typedef enum FunctionKind_t {
FunctionDeclarationKind,
@ -211,19 +212,21 @@ typedef enum FunctionKind_t {
typedef struct FunctionDefinition_t {
// 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
Type* return_value;
AST_NODE_PTR nodePtr;
// body of function
Block *body;
Block* body;
// name of function
const char* name;
} FunctionDefinition;
typedef struct FunctionDeclaration_t {
// 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
AST_NODE_PTR nodePtr;
Type* return_value;
@ -237,7 +240,7 @@ typedef struct Function_t {
FunctionDeclaration declaration;
} impl;
AST_NODE_PTR nodePtr;
const char * name;
const char* name;
} Function;
Parameter get_param_from_func(Function* func, size_t index);
@ -246,27 +249,24 @@ Parameter get_param_from_func(Function* func, size_t index);
// | Variables |
// '------------------------------------------------'
typedef enum StorageQualifier_t {
Local,
Static,
Global
} StorageQualifier;
typedef enum StorageQualifier_t { Local, Static, Global } StorageQualifier;
typedef struct VariableDeclaration_t {
StorageQualifier qualifier;
Type *type;
Type* type;
AST_NODE_PTR nodePtr;
} VariableDeclaration;
/**
* @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 {
VariableDeclaration declaration;
Expression *initializer;
Expression* initializer;
AST_NODE_PTR nodePtr;
} VariableDefiniton;
@ -291,7 +291,7 @@ typedef struct Dereference_t {
Expression* index;
Expression* variable;
AST_NODE_PTR nodePtr;
}Dereference;
} Dereference;
typedef struct StorageExpr_t StorageExpr;
@ -304,23 +304,24 @@ typedef struct StorageDereference_t {
typedef struct AddressOf_t {
Expression* variable;
AST_NODE_PTR node_ptr;
}AddressOf;
} AddressOf;
// .------------------------------------------------.
// | Casts |
// '------------------------------------------------'
/**
* @brief Perform a type cast, converting a value to different type whilest preserving as much of the original
* values information.
* @brief Perform a type cast, converting a value to different type whilest
* preserving as much of the original values information.
*
* @attention NOTE: Must check wether the given value's type can be parsed into
* 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 {
Type *targetType;
Type* targetType;
Expression* operand;
AST_NODE_PTR nodePtr;
} TypeCast;
@ -328,12 +329,12 @@ typedef struct TypeCast_t {
/**
* @brief Perform a reinterpret cast.
*
* @attention NOTE: The given value's type must have the size in bytes as the target type.
* Transmuting a short int into a float should yield an error.
* @attention NOTE: The given value's type must have the size in bytes as the
* target type. Transmuting a short int into a float should yield an error.
*
*/
typedef struct Transmute_t {
Type *targetType;
Type* targetType;
Expression* operand;
AST_NODE_PTR nodePtr;
} Transmute;
@ -362,11 +363,7 @@ typedef enum ArithmeticOperator_t {
* @brief Represents the relational operator.
*
*/
typedef enum RelationalOperator_t {
Equal,
Greater,
Less
} RelationalOperator;
typedef enum RelationalOperator_t { Equal, Greater, Less } RelationalOperator;
// .------------------------------------------------.
// | Boolean |
@ -424,7 +421,7 @@ typedef struct Operation_t {
LogicalOperator logical;
BitwiseOperator bitwise;
} impl;
GArray* operands; //Expression*
GArray* operands; // Expression*
AST_NODE_PTR nodePtr;
} Operation;
@ -498,7 +495,7 @@ typedef struct Block_t {
// '------------------------------------------------'
typedef struct While_t {
Expression *conditon;
Expression* conditon;
Block block;
AST_NODE_PTR nodePtr;
} While;
@ -508,13 +505,13 @@ typedef struct While_t {
// '------------------------------------------------'
typedef struct If_t {
Expression *conditon;
Expression* conditon;
Block block;
AST_NODE_PTR nodePtr;
} If;
typedef struct ElseIf_t {
Expression *conditon;
Expression* conditon;
Block block;
AST_NODE_PTR nodePtr;
} ElseIf;
@ -584,7 +581,7 @@ typedef struct Statement_t {
While whileLoop;
Branch branch;
Assignment assignment;
Variable *variable;
Variable* variable;
Return returnStmt;
} impl;
AST_NODE_PTR nodePtr;
@ -595,7 +592,7 @@ typedef struct Statement_t {
// '------------------------------------------------'
typedef struct Module_t {
GHashTable* boxes; //BoxType
GHashTable* boxes; // BoxType
GHashTable* types; //
GHashTable* functions;
GHashTable* variables;
@ -638,7 +635,7 @@ void delete_typecast(TypeCast* cast);
void delete_box_member(BoxMember* member);
void delete_box_type(BoxType *box_type);
void delete_box_type(BoxType* box_type);
void delete_composite([[maybe_unused]] CompositeType* composite);

View File

@ -1,9 +1,9 @@
#include <cfg/opt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/col.h>
#include <sys/log.h>
#include <cfg/opt.h>
#ifdef __unix__
#include <unistd.h>
@ -11,47 +11,47 @@
#include <Windows.h>
#endif
char *RED;
char *YELLOW;
char *MAGENTA;
char *CYAN;
char *GREEN;
char *RESET;
char *BOLD;
char *FAINT;
char* RED;
char* YELLOW;
char* MAGENTA;
char* CYAN;
char* GREEN;
char* RESET;
char* BOLD;
char* FAINT;
void col_init(void) {
if (stdout_supports_ansi_esc()) {
enable_ansi_colors();
} else {
disable_ansi_colors();
}
if (stdout_supports_ansi_esc()) {
enable_ansi_colors();
} else {
disable_ansi_colors();
}
}
void disable_ansi_colors() {
DEBUG("disabling ANSI escape codes");
DEBUG("disabling ANSI escape codes");
RED = "";
YELLOW = "";
MAGENTA = "";
CYAN = "";
GREEN = "";
RESET = "";
BOLD = "";
FAINT = "";
RED = "";
YELLOW = "";
MAGENTA = "";
CYAN = "";
GREEN = "";
RESET = "";
BOLD = "";
FAINT = "";
}
void enable_ansi_colors() {
DEBUG("enabling ANSI escape codes");
DEBUG("enabling ANSI escape codes");
RED = "\x1b[31m";
YELLOW = "\x1b[33m";
MAGENTA = "\x1b[35m";
CYAN = "\x1b[36m";
GREEN = "\x1b[32m";
RESET = "\x1b[0m";
BOLD = "\x1b[1m";
FAINT = "\x1b[2m";
RED = "\x1b[31m";
YELLOW = "\x1b[33m";
MAGENTA = "\x1b[35m";
CYAN = "\x1b[36m";
GREEN = "\x1b[32m";
RESET = "\x1b[0m";
BOLD = "\x1b[1m";
FAINT = "\x1b[2m";
}
int stdout_supports_ansi_esc() {
@ -61,31 +61,33 @@ int stdout_supports_ansi_esc() {
}
#ifdef __unix__
// check if TTY
if (isatty(STDOUT_FILENO)) {
const char *colors = getenv("COLORTERM");
// check if colors are set and allowed
if (colors != NULL && (strcmp(colors, "truecolor") == 0 || strcmp(colors, "24bit") == 0)) {
return ANSI_ENABLED;
// check if TTY
if (isatty(STDOUT_FILENO)) {
const char* colors = getenv("COLORTERM");
// check if colors are set and allowed
if (colors != NULL
&& (strcmp(colors, "truecolor") == 0
|| strcmp(colors, "24bit") == 0)) {
return ANSI_ENABLED;
}
}
}
#elif defined(_WIN32) || defined(WIN32)
// see:
// https://stackoverflow.com/questions/63913005/how-to-test-if-console-supports-ansi-color-codes
DWORD mode;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// see:
// https://stackoverflow.com/questions/63913005/how-to-test-if-console-supports-ansi-color-codes
DWORD mode;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (!GetConsoleMode(hConsole, &mode)) {
return ASNI_DISABLED;
}
if (!GetConsoleMode(hConsole, &mode)) {
return ASNI_DISABLED;
}
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) |
(mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return ANSI_ENABLED;
}
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT)
| (mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return ANSI_ENABLED;
}
#else
#warning "unsupported platform, ASNI escape codes disabled by default"
#endif
return ASNI_DISABLED;
return ASNI_DISABLED;
}

View File

@ -2,19 +2,19 @@
#ifndef COLORS_H_
#define COLORS_H_
#define ANSI_ENABLED 1
#define ANSI_ENABLED 1
#define ASNI_DISABLED 0
// Common escape codes
// can be used to print colored text
extern char *RED;
extern char *YELLOW;
extern char *MAGENTA;
extern char *CYAN;
extern char *GREEN;
extern char *RESET;
extern char *BOLD;
extern char *FAINT;
extern char* RED;
extern char* YELLOW;
extern char* MAGENTA;
extern char* CYAN;
extern char* GREEN;
extern char* RESET;
extern char* BOLD;
extern char* FAINT;
/**
* @brief Initialize global state
@ -28,14 +28,17 @@ void col_init(void);
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();
/**
* @brief Check if stdout may support ANSI escape codes.
* @attention This function may report escape codes to be unavailable even if they actually are.
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED otherwise
* @attention This function may report escape codes to be unavailable even if
* they actually are.
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED
* otherwise
*/
[[nodiscard]]
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 <stdio.h>
#include <stdlib.h>
#include <sys/log.h>
#include <assert.h>
#include <string.h>
#include <cfg/opt.h>
#include <mem/cache.h>
#include <sys/log.h>
static struct Logger_t {
FILE** streams;
@ -15,13 +15,11 @@ static struct Logger_t {
int runtime_log_level = LOG_LEVEL_WARNING;
void set_log_level(int level)
{
void set_log_level(int level) {
runtime_log_level = level;
}
void log_init()
{
void log_init() {
if (is_option_set("verbose")) {
set_log_level(LOG_LEVEL_INFORMATION);
} else if (is_option_set("debug")) {
@ -32,30 +30,26 @@ void log_init()
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
// only to be used in debug target
assert(stream != NULL);
if (GlobalLogger.stream_count == 0)
{
GlobalLogger.streams = (FILE**) mem_alloc(MemoryNamespaceLog, sizeof(FILE*));
if (GlobalLogger.stream_count == 0) {
GlobalLogger.streams =
(FILE**) mem_alloc(MemoryNamespaceLog, sizeof(FILE*));
GlobalLogger.stream_count = 1;
if (GlobalLogger.streams == NULL)
{
if (GlobalLogger.streams == NULL) {
PANIC("failed to allocate stream buffer");
}
}
else
{
} else {
GlobalLogger.stream_count++;
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");
}
}
@ -63,32 +57,21 @@ void log_register_stream(FILE* restrict stream)
GlobalLogger.streams[GlobalLogger.stream_count - 1] = stream;
}
static void vflogf(
FILE* restrict stream,
const char* restrict level,
const char* restrict file,
const unsigned long line,
const char* restrict func,
const char* restrict format,
va_list args)
{
static void vflogf(FILE* restrict stream, const char* restrict level,
const char* restrict file, 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);
vfprintf(stream, format, args);
}
void syslog_logf(
const char* restrict level,
const char* restrict file,
const unsigned long line,
const char* restrict func,
const char* restrict format,
...)
{
void syslog_logf(const char* restrict level, const char* restrict file,
const unsigned long line, const char* restrict func,
const char* restrict format, ...) {
va_list args;
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];
vflogf(stream, level, file, line, func, format, args);
@ -97,13 +80,9 @@ void syslog_logf(
va_end(args);
}
void syslog_panicf(
const char* restrict file,
const unsigned long line,
const char* restrict func,
const char* restrict format,
...)
{
void syslog_panicf(const char* restrict file, const unsigned long line,
const char* restrict func, const char* restrict format,
...) {
va_list args;
va_start(args, format);
@ -114,13 +93,9 @@ void syslog_panicf(
exit(EXIT_FAILURE);
}
void syslog_fatalf(
const char* restrict file,
const unsigned long line,
const char* restrict func,
const char* restrict format,
...)
{
void syslog_fatalf(const char* restrict file, const unsigned long line,
const char* restrict func, const char* restrict format,
...) {
va_list args;
va_start(args, format);

View File

@ -5,10 +5,10 @@
#define LOG_DEFAULT_STREAM stderr
#define LOG_LEVEL_ERROR 3
#define LOG_LEVEL_WARNING 2
#define LOG_LEVEL_INFORMATION 1
#define LOG_LEVEL_DEBUG 0
#define LOG_LEVEL_ERROR 3
#define LOG_LEVEL_WARNING 2
#define LOG_LEVEL_INFORMATION 1
#define LOG_LEVEL_DEBUG 0
#define LOG_LEVEL LOG_LEVEL_DEBUG
@ -23,9 +23,11 @@
// generally not defined by GCC < 11.3 and MSVC
#ifndef __FILE_NAME__
#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
#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define __FILE_NAME__ \
(strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#endif
#endif
@ -34,37 +36,46 @@
* This macro will print debug information to stderr and call abort() to
* 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.
* This macro will print debug information to stderr and call exit() to
* initiate a gracefull exit, giving the process the opportunity to clean up.
* @brief Panic is used in cases where the process is in an invalid or undefined
* 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.
*/
#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.
Can be turned off by setting LOG_LEVEL. All logs which have smaller log numbers
will not print.
*/
#define ERROR(format, ...) __LOG(LOG_STRING_ERROR, LOG_LEVEL_ERROR, format"\n", ##__VA_ARGS__)
#define WARN(format, ...) __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__)
#define ERROR(format, ...) \
__LOG(LOG_STRING_ERROR, LOG_LEVEL_ERROR, format "\n", ##__VA_ARGS__)
#define WARN(format, ...) \
__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;
#define __LOG(level, priority, format, ...) \
do { \
if (LOG_LEVEL <= priority) \
if (runtime_log_level <= priority) \
syslog_logf(level, __FILE_NAME__, __LINE__, __func__, format, ##__VA_ARGS__); \
} while(0)
#define __LOG(level, priority, format, ...) \
do { \
if (LOG_LEVEL <= priority) \
if (runtime_log_level <= priority) \
syslog_logf(level, __FILE_NAME__, __LINE__, __func__, format, \
##__VA_ARGS__); \
} while (0)
/**
* @brief Set the runtime log level. Must be one of: LOG_LEVEL_ERROR, LOG_LEVEL_WARNING,
* LOG_LEVEL_INFORMATION, LOG_LEVEL_DEBUG
* @brief Set the runtime log level. Must be one of: LOG_LEVEL_ERROR,
* LOG_LEVEL_WARNING, LOG_LEVEL_INFORMATION, LOG_LEVEL_DEBUG
* @param level the new log level
*/
void set_log_level(int level);
@ -80,16 +91,13 @@ void set_log_level(int level);
* @param ...
*/
[[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(4)]]
void syslog_logf(
const char* restrict level,
const char* restrict file,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
void syslog_logf(const char* restrict level, const char* restrict file,
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 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 ...
*/
[[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_panicf(
const char* restrict file,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
[[noreturn]] [[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_panicf(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 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 ...
*/
[[noreturn]]
[[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_fatalf(
const char* restrict file,
unsigned long line,
const char* restrict func,
const char* restrict format,
...);
[[noreturn]] [[gnu::nonnull(1), gnu::nonnull(3), gnu::nonnull(4)]]
void syslog_fatalf(const char* restrict file, unsigned long line,
const char* restrict func, const char* restrict format, ...);
/**
* @brief Initialize the logger by registering stderr as stream
@ -131,7 +130,8 @@ void syslog_fatalf(
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
*/