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

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

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

View File

@ -1,15 +1,18 @@
#include <assert.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <mem/cache.h>
#include <stdio.h> #include <stdio.h>
#include <sys/log.h> #include <sys/log.h>
#include <assert.h>
#include <mem/cache.h>
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) { struct AST_Node_t* AST_new_node(TokenLocation location,
enum AST_SyntaxElement_t kind,
const char* value) {
DEBUG("creating new AST node: %d \"%s\"", kind, value); DEBUG("creating new AST node: %d \"%s\"", kind, value);
assert(kind < AST_ELEMENT_COUNT); assert(kind < AST_ELEMENT_COUNT);
struct AST_Node_t *node = mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t)); struct AST_Node_t* node =
mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t));
if (node == NULL) { if (node == NULL) {
PANIC("failed to allocate AST node"); PANIC("failed to allocate AST node");
@ -18,24 +21,24 @@ struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t
assert(node != NULL); assert(node != NULL);
// init to discrete state // init to discrete state
node->parent = NULL; node->parent = NULL;
node->children = mem_new_g_array(MemoryNamespaceAst, sizeof(AST_NODE_PTR)); node->children = mem_new_g_array(MemoryNamespaceAst, sizeof(AST_NODE_PTR));
node->kind = kind; node->kind = kind;
node->value = value; node->value = value;
node->location = location; node->location = location;
return node; return node;
} }
static const char* lookup_table[AST_ELEMENT_COUNT] = { "__UNINIT__" }; static const char* lookup_table[AST_ELEMENT_COUNT] = {"__UNINIT__"};
void AST_init() { void AST_init() {
DEBUG("initializing global syntax tree..."); DEBUG("initializing global syntax tree...");
INFO("filling lookup table..."); INFO("filling lookup table...");
lookup_table[AST_Stmt] = "stmt"; lookup_table[AST_Stmt] = "stmt";
lookup_table[AST_Module] = "module"; lookup_table[AST_Module] = "module";
lookup_table[AST_Expr] = "expr"; lookup_table[AST_Expr] = "expr";
lookup_table[AST_Add] = "+"; lookup_table[AST_Add] = "+";
lookup_table[AST_Sub] = "-"; lookup_table[AST_Sub] = "-";
@ -43,53 +46,53 @@ void AST_init() {
lookup_table[AST_Div] = "/"; lookup_table[AST_Div] = "/";
lookup_table[AST_BitAnd] = "&"; lookup_table[AST_BitAnd] = "&";
lookup_table[AST_BitOr] = "|"; lookup_table[AST_BitOr] = "|";
lookup_table[AST_BitXor] = "^"; lookup_table[AST_BitXor] = "^";
lookup_table[AST_BitNot] = "!"; lookup_table[AST_BitNot] = "!";
lookup_table[AST_Eq] = "=="; lookup_table[AST_Eq] = "==";
lookup_table[AST_Less] = "<"; lookup_table[AST_Less] = "<";
lookup_table[AST_Greater] = ">"; lookup_table[AST_Greater] = ">";
lookup_table[AST_BoolAnd] = "&&"; lookup_table[AST_BoolAnd] = "&&";
lookup_table[AST_BoolOr] = "||"; lookup_table[AST_BoolOr] = "||";
lookup_table[AST_BoolXor] = "^^"; lookup_table[AST_BoolXor] = "^^";
lookup_table[AST_BoolNot] = "!!"; lookup_table[AST_BoolNot] = "!!";
lookup_table[AST_While] = "while"; lookup_table[AST_While] = "while";
lookup_table[AST_If] = "if"; lookup_table[AST_If] = "if";
lookup_table[AST_IfElse] = "else 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_Assign] = "assign";
lookup_table[AST_Def] = "def"; lookup_table[AST_Def] = "def";
lookup_table[AST_Typedef] = "typedef"; lookup_table[AST_Typedef] = "typedef";
lookup_table[AST_Box] = "box"; lookup_table[AST_Box] = "box";
lookup_table[AST_FunDecl] = "fun"; lookup_table[AST_FunDecl] = "fun";
lookup_table[AST_FunDef] = "fun"; lookup_table[AST_FunDef] = "fun";
lookup_table[AST_ProcDecl] = "fun"; lookup_table[AST_ProcDecl] = "fun";
lookup_table[AST_ProcDef] = "fun"; lookup_table[AST_ProcDef] = "fun";
lookup_table[AST_Call] = "funcall"; lookup_table[AST_Call] = "funcall";
lookup_table[AST_Typecast] = "typecast"; lookup_table[AST_Typecast] = "typecast";
lookup_table[AST_Transmute] = "transmute"; lookup_table[AST_Transmute] = "transmute";
lookup_table[AST_Condition] = "condition"; lookup_table[AST_Condition] = "condition";
lookup_table[AST_List] = "list"; lookup_table[AST_List] = "list";
lookup_table[AST_ExprList] = "expr list"; lookup_table[AST_ExprList] = "expr list";
lookup_table[AST_ArgList] = "arg list"; lookup_table[AST_ArgList] = "arg list";
lookup_table[AST_ParamList] = "param list"; lookup_table[AST_ParamList] = "param list";
lookup_table[AST_StmtList] = "stmt list"; lookup_table[AST_StmtList] = "stmt list";
lookup_table[AST_IdentList] = "ident list"; lookup_table[AST_IdentList] = "ident list";
lookup_table[AST_Type] = "type"; lookup_table[AST_Type] = "type";
lookup_table[AST_Negate] = "-"; lookup_table[AST_Negate] = "-";
lookup_table[AST_Parameter] = "parameter"; lookup_table[AST_Parameter] = "parameter";
lookup_table[AST_ParamDecl] = "parameter-declaration"; lookup_table[AST_ParamDecl] = "parameter-declaration";
lookup_table[AST_AddressOf] = "address of"; lookup_table[AST_AddressOf] = "address of";
lookup_table[AST_Dereference] = "deref"; lookup_table[AST_Dereference] = "deref";
lookup_table[AST_Reference] = "ref"; lookup_table[AST_Reference] = "ref";
lookup_table[AST_Return] = "ret"; lookup_table[AST_Return] = "ret";
} }
const char* AST_node_to_string(const struct AST_Node_t* node) { 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; const char* string;
switch(node->kind) { switch (node->kind) {
case AST_Int: case AST_Int:
case AST_Char: case AST_Char:
case AST_Float: 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; 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); DEBUG("Adding new node %p to %p", child, owner);
assert(owner != NULL); assert(owner != NULL);
assert(child != 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"); PANIC("failed to allocate children array of AST node");
} }
owner->location.col_end = max(owner->location.col_end, child->location.col_end); owner->location.col_end =
owner->location.line_end = max(owner->location.line_end, child->location.line_end); max(owner->location.col_end, child->location.col_end);
owner->location.line_end =
max(owner->location.line_end, child->location.line_end);
owner->location.col_start = min(owner->location.col_start, child->location.col_start); owner->location.col_start =
owner->location.line_start = min(owner->location.line_start, child->location.line_start); min(owner->location.col_start, child->location.col_start);
owner->location.line_start =
min(owner->location.line_start, child->location.line_start);
if (owner->location.file == NULL) { if (owner->location.file == NULL) {
owner->location.file = child->location.file; owner->location.file = child->location.file;
@ -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); 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); DEBUG("retrvieng node %d from %p", idx, owner);
assert(owner != NULL); assert(owner != NULL);
assert(owner->children != 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; return child;
} }
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) { struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner,
const size_t idx) {
assert(owner != NULL); assert(owner != NULL);
assert(owner->children != NULL); assert(owner->children != NULL);
assert(idx < owner->children->len); assert(idx < owner->children->len);
@ -187,7 +195,8 @@ struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx)
return child; return child;
} }
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) { struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner,
const struct AST_Node_t* child) {
assert(owner != NULL); assert(owner != NULL);
assert(child != NULL); assert(child != NULL);
assert(owner->children != NULL); assert(owner->children != NULL);
@ -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"); 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); assert(node != NULL);
DEBUG("Deleting AST node: %p", node); DEBUG("Deleting AST node: %p", node);
if (node->parent != NULL) { if (node->parent != NULL) {
[[maybe_unused]] [[maybe_unused]] const struct AST_Node_t* child =
const struct AST_Node_t* child = AST_detach_child(node->parent, node); AST_detach_child(node->parent, node);
assert(child == node); assert(child == node);
} }
@ -224,8 +233,8 @@ void AST_delete_node(struct AST_Node_t *node) {
mem_free(node); mem_free(node);
} }
static void AST_visit_nodes_recurse2(struct AST_Node_t *root, static void AST_visit_nodes_recurse2(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(struct AST_Node_t* node,
size_t depth), size_t depth),
const size_t depth) { const size_t depth) {
DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each); 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_each)(root, depth);
for (size_t i = 0; i < root->children->len; i++) { for (size_t i = 0; i < root->children->len; i++) {
AST_visit_nodes_recurse2(g_array_index(root->children, AST_NODE_PTR, i), for_each, depth + 1); AST_visit_nodes_recurse2(g_array_index(root->children, AST_NODE_PTR, i),
for_each, depth + 1);
} }
} }
void AST_visit_nodes_recurse(struct AST_Node_t *root, void AST_visit_nodes_recurse(struct AST_Node_t* root,
void (*for_each)(struct AST_Node_t *node, void (*for_each)(struct AST_Node_t* node,
size_t depth)) { size_t depth)) {
DEBUG("Starting recursive visit of %p with %p", root, for_each); 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); AST_visit_nodes_recurse2(root, for_each, 0);
} }
static void AST_fprint_graphviz_node_definition(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_definition(FILE* stream,
const struct AST_Node_t* node) {
DEBUG("Printing graphviz definition of %p", node); DEBUG("Printing graphviz definition of %p", node);
assert(stream != NULL); assert(stream != NULL);
assert(node != NULL); assert(node != NULL);
fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node)); fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node,
AST_node_to_string(node));
if (node->children == NULL) { if (node->children == NULL) {
return; return;
} }
for (size_t i = 0; i < node->children->len; i++) { for (size_t i = 0; i < node->children->len; i++) {
AST_fprint_graphviz_node_definition(stream, g_array_index(node->children, AST_NODE_PTR, i)); AST_fprint_graphviz_node_definition(
stream, g_array_index(node->children, AST_NODE_PTR, i));
} }
} }
static void AST_fprint_graphviz_node_connection(FILE* stream, const struct AST_Node_t* node) { static void AST_fprint_graphviz_node_connection(FILE* stream,
const struct AST_Node_t* node) {
DEBUG("Printing graphviz connection of %p", node); DEBUG("Printing graphviz connection of %p", node);
assert(stream != NULL); assert(stream != NULL);
@ -298,16 +312,17 @@ void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) {
fprintf(stream, "}\n"); fprintf(stream, "}\n");
} }
AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner, enum AST_SyntaxElement_t kind) { AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner,
for (size_t i = 0; i < owner->children->len; i++) { enum AST_SyntaxElement_t kind) {
AST_NODE_PTR child = AST_get_node(owner, i); for (size_t i = 0; i < owner->children->len; i++) {
AST_NODE_PTR child = AST_get_node(owner, i);
if (child->kind == kind) { if (child->kind == kind) {
return child; return child;
}
} }
}
return NULL; return NULL;
} }
void AST_merge_modules(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) { void AST_merge_modules(AST_NODE_PTR dst, size_t k, AST_NODE_PTR src) {

View File

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

View File

@ -2,14 +2,14 @@
// Created by servostar on 5/31/24. // Created by servostar on 5/31/24.
// //
#include <assert.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <io/files.h>
#include <link/driver.h>
#include <mem/cache.h>
#include <string.h> #include <string.h>
#include <sys/log.h> #include <sys/log.h>
#include <io/files.h>
#include <assert.h>
#include <toml.h> #include <toml.h>
#include <mem/cache.h>
#include <link/driver.h>
static GHashTable* args = NULL; static GHashTable* args = NULL;
@ -34,14 +34,15 @@ void parse_options(int argc, char* argv[]) {
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option)); Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option));
option->is_opt = g_str_has_prefix(argv[i], "--"); option->is_opt = g_str_has_prefix(argv[i], "--");
option->string = mem_strdup(MemoryNamespaceOpt, argv[i] + (option->is_opt ? 2 : 0)); option->string =
mem_strdup(MemoryNamespaceOpt, argv[i] + (option->is_opt ? 2 : 0));
option->index = i; option->index = i;
option->value = NULL; option->value = NULL;
char* equals = strchr(option->string, '='); char* equals = strchr(option->string, '=');
if (equals != NULL) { if (equals != NULL) {
option->value = equals + 1; option->value = equals + 1;
*equals = 0; *equals = 0;
} }
g_hash_table_insert(args, (gpointer) option->string, (gpointer) option); 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)); TargetConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(TargetConfig));
config->name = mem_strdup(MemoryNamespaceOpt, "out"); config->name = mem_strdup(MemoryNamespaceOpt, "out");
config->print_ast = false; config->print_ast = false;
config->print_asm = false; config->print_asm = false;
config->print_ir = false; config->print_ir = false;
config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER); config->driver = mem_strdup(MemoryNamespaceOpt, DEFAULT_DRIVER);
config->mode = Application; config->mode = Application;
config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive"); config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin"); config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->optimization_level = 1; config->optimization_level = 1;
config->root_module = NULL; config->root_module = NULL;
config->link_search_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); config->link_search_paths =
mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
config->lld_fatal_warnings = FALSE; config->lld_fatal_warnings = FALSE;
config->gsc_fatal_warnings = FALSE; config->gsc_fatal_warnings = FALSE;
config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*)); config->import_paths = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
@ -148,7 +150,8 @@ TargetConfig* default_target_config_from_args() {
} else if (strcmp(opt->value, "lib") == 0) { } else if (strcmp(opt->value, "lib") == 0) {
config->mode = Library; config->mode = Library;
} else { } else {
print_message(Warning, "Invalid compilation mode: %s", opt->value); print_message(Warning, "Invalid compilation mode: %s",
opt->value);
} }
} }
} }
@ -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); char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
g_array_append_val(config->link_search_paths, cached_cwd); g_array_append_val(config->link_search_paths, cached_cwd);
free(cwd); free(cwd);
@ -180,10 +183,10 @@ TargetConfig* default_target_config_from_args() {
if (opt->value != NULL) { if (opt->value != NULL) {
const char* start = opt->value; const char* start = opt->value;
const char* end = NULL; const char* end = NULL;
while((end = strchr(start, ',')) != NULL) { while ((end = strchr(start, ',')) != NULL) {
const int len = end - start; const int len = end - start;
char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1); char* link_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(link_path, start, len); memcpy(link_path, start, len);
link_path[len] = 0; link_path[len] = 0;
@ -211,10 +214,12 @@ TargetConfig* default_target_config_from_args() {
} else { } else {
if (files->len > 1) { if (files->len > 1) {
print_message(Warning, "Got more than one file to compile, using first, ignoring others."); print_message(Warning, "Got more than one file to compile, using "
"first, ignoring others.");
} }
config->root_module = mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0)); config->root_module =
mem_strdup(MemoryNamespaceOpt, g_array_index(files, char*, 0));
} }
char* default_import_path = mem_strdup(MemoryNamespaceOpt, "."); char* default_import_path = mem_strdup(MemoryNamespaceOpt, ".");
@ -226,10 +231,10 @@ TargetConfig* default_target_config_from_args() {
if (opt->value != NULL) { if (opt->value != NULL) {
const char* start = opt->value; const char* start = opt->value;
const char* end = NULL; const char* end = NULL;
while((end = strchr(start, ',')) != NULL) { while ((end = strchr(start, ',')) != NULL) {
const int len = end - start; const int len = end - start;
char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1); char* import_path = mem_alloc(MemoryNamespaceOpt, len + 1);
memcpy(import_path, start, len); memcpy(import_path, start, len);
import_path[len] = 0; import_path[len] = 0;
@ -256,39 +261,43 @@ TargetConfig* default_target_config_from_args() {
void print_help(void) { void print_help(void) {
DEBUG("printing help dialog..."); DEBUG("printing help dialog...");
const char *lines[] = { const char* lines[] = {
"Gemstone Compiler (c) GPL-2.0", "Gemstone Compiler (c) GPL-2.0",
"Build a project target: gsc build [target]|all", "Build a project target: gsc build [target]|all",
"Compile non-project file: gsc compile <target-options> [file]", "Compile non-project file: gsc compile <target-options> [file]",
"Output information: gsc <option>", "Output information: gsc <option>",
"Target options:", "Target options:",
" --print-ast print resulting abstract syntax tree to a file", " --print-ast print resulting abstract syntax tree to a "
"file",
" --print-asm print resulting assembly language to a file", " --print-asm print resulting assembly language to a file",
" --print-ir print resulting LLVM-IR to a file", " --print-ir print resulting LLVM-IR to a file",
" --mode=[app|lib] set the compilation mode to either application or library", " --mode=[app|lib] set the compilation mode to either "
"application or library",
" --output=name name of output files without extension", " --output=name name of output files without extension",
" --driver set binary driver to use", " --driver set binary driver to use",
" --link-paths=[paths,] set a list of directories to for libraries in", " --link-paths=[paths,] set a list of directories to for libraries "
"in",
" --all-fatal-warnings treat all warnings as errors", " --all-fatal-warnings treat all warnings as errors",
" --lld-fatal-warnings treat linker warnings as errors", " --lld-fatal-warnings treat linker warnings as errors",
" --gsc-fatal-warnings treat parser warnings as errors", " --gsc-fatal-warnings treat parser warnings as errors",
"Options:", "Options:",
" --verbose print logs with level information or higher", " --verbose print logs with level information or higher",
" --debug print debug logs (if not disabled at compile time)", " --debug print debug logs (if not disabled at compile "
"time)",
" --version print the version", " --version print the version",
" --list-targets print a list of all available targets supported", " --list-targets print a list of all available targets supported",
" --list-driver print a list of all available binary driver", " --list-driver print a list of all available binary driver",
" --help print this help dialog", " --help print this help dialog",
" --color-always always colorize output", " --color-always always colorize output",
" --print-gc-stats print statistics of the garbage collector" " --print-gc-stats print statistics of the garbage collector"};
};
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) { for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char*); i++) {
printf("%s\n", lines[i]); printf("%s\n", lines[i]);
} }
} }
static void get_bool(bool* boolean, const toml_table_t *table, const char* name) { static void get_bool(bool* boolean, const toml_table_t* table,
const char* name) {
DEBUG("retrieving boolean %s", name); DEBUG("retrieving boolean %s", name);
const toml_datum_t datum = toml_bool_in(table, name); const toml_datum_t datum = toml_bool_in(table, name);
@ -299,7 +308,8 @@ static void get_bool(bool* boolean, const toml_table_t *table, const char* name)
} }
} }
static void get_str(char** string, const toml_table_t *table, const char* name) { static void get_str(char** string, const toml_table_t* table,
const char* name) {
DEBUG("retrieving string %s", name); DEBUG("retrieving string %s", name);
const toml_datum_t datum = toml_string_in(table, name); const toml_datum_t datum = toml_string_in(table, name);
@ -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); DEBUG("retrieving integer %s", name);
const toml_datum_t datum = toml_int_in(table, 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); const toml_array_t* toml_array = toml_array_in(table, name);
if (toml_array) { if (toml_array) {
@ -336,7 +347,8 @@ static void get_array(GArray* array, const toml_table_t *table, const char* name
} }
} }
static int parse_project_table(ProjectConfig *config, const toml_table_t *project_table) { static int parse_project_table(ProjectConfig* config,
const toml_table_t* project_table) {
DEBUG("parsing project table..."); DEBUG("parsing project table...");
// project name // project name
@ -350,14 +362,15 @@ static int parse_project_table(ProjectConfig *config, const toml_table_t *projec
get_str(&config->name, project_table, "name"); get_str(&config->name, project_table, "name");
// author names // author names
toml_array_t *authors = toml_array_in(project_table, "authors"); toml_array_t* authors = toml_array_in(project_table, "authors");
if (authors) { if (authors) {
config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char *)); config->authors = mem_new_g_array(MemoryNamespaceOpt, sizeof(char*));
for (int i = 0;; i++) { for (int i = 0;; i++) {
toml_datum_t author = toml_string_at(authors, i); toml_datum_t author = toml_string_at(authors, i);
if (!author.ok) if (!author.ok) {
break; break;
}
g_array_append_val(config->authors, author.u.s); g_array_append_val(config->authors, author.u.s);
} }
@ -383,11 +396,13 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
*mode = Library; *mode = Library;
return PROJECT_OK; return PROJECT_OK;
} }
print_message(Error, "Invalid project configuration, mode is invalid: %s", name); print_message(Error, "Invalid project configuration, mode is invalid: %s",
name);
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
static int parse_target(const ProjectConfig *config, const toml_table_t *target_table, const char* name) { static int parse_target(const ProjectConfig* config,
const toml_table_t* target_table, const char* name) {
DEBUG("parsing target table..."); DEBUG("parsing target table...");
TargetConfig* target_config = default_target_config(); TargetConfig* target_config = default_target_config();
@ -402,8 +417,10 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
get_str(&target_config->root_module, target_table, "root"); get_str(&target_config->root_module, target_table, "root");
get_str(&target_config->output_directory, target_table, "output"); get_str(&target_config->output_directory, target_table, "output");
get_str(&target_config->archive_directory, target_table, "archive"); get_str(&target_config->archive_directory, target_table, "archive");
get_bool(&target_config->lld_fatal_warnings, target_table, "lld_fatal_warnings"); get_bool(&target_config->lld_fatal_warnings, target_table,
get_bool(&target_config->gsc_fatal_warnings, target_table, "gsc_fatal_warnings"); "lld_fatal_warnings");
get_bool(&target_config->gsc_fatal_warnings, target_table,
"gsc_fatal_warnings");
get_int(&target_config->optimization_level, target_table, "opt"); get_int(&target_config->optimization_level, target_table, "opt");
@ -413,7 +430,7 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
if (err != PROJECT_OK) { if (err != PROJECT_OK) {
return err; return err;
} }
char* cwd = g_get_current_dir(); char* cwd = g_get_current_dir();
char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd); char* cached_cwd = mem_strdup(MemoryNamespaceOpt, cwd);
free(cwd); free(cwd);
@ -428,54 +445,59 @@ static int parse_target(const ProjectConfig *config, const toml_table_t *target_
return PROJECT_OK; 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); 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) { if (targets == NULL) {
print_message(Warning, "Project has no targets"); print_message(Warning, "Project has no targets");
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
config->targets = mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal); config->targets =
mem_new_g_hash_table(MemoryNamespaceOpt, g_str_hash, g_str_equal);
for (int i = 0; i < toml_table_ntab(targets); i++) { for (int i = 0; i < toml_table_ntab(targets); i++) {
const char *key = toml_key_in(targets, i); const char* key = toml_key_in(targets, i);
if (key == NULL) if (key == NULL) {
break; break;
}
toml_table_t *target = toml_table_in(targets, key); toml_table_t* target = toml_table_in(targets, key);
parse_target(config, target, mem_strdup(MemoryNamespaceOpt, (char*) key)); parse_target(config, target,
mem_strdup(MemoryNamespaceOpt, (char*) key));
} }
return PROJECT_OK; return PROJECT_OK;
} }
int load_project_config(ProjectConfig *config) { int load_project_config(ProjectConfig* config) {
DEBUG("loading project 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) { if (config_file == NULL) {
print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE, strerror(errno)); print_message(Error, "Cannot open file %s: %s", PROJECT_CONFIG_FILE,
strerror(errno));
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
char err_buf[TOML_ERROR_MSG_BUF]; 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); fclose(config_file);
if (conf != NULL) { if (conf != NULL) {
int status = PROJECT_SEMANTIC_ERR; int status = PROJECT_SEMANTIC_ERR;
toml_table_t *project = toml_table_in(conf, "project"); toml_table_t* project = toml_table_in(conf, "project");
if (project != NULL) { if (project != NULL) {
if (parse_project_table(config, project) == PROJECT_OK) { if (parse_project_table(config, project) == PROJECT_OK) {
status = parse_targets(config, conf); status = parse_targets(config, conf);
} }
} else { } else {
print_message(Error, "Invalid project configuration: missing project table."); print_message(
Error, "Invalid project configuration: missing project table.");
} }
toml_free(conf); toml_free(conf);
@ -528,7 +550,8 @@ void delete_project_config(ProjectConfig* config) {
char* key; char* key;
TargetConfig* val; TargetConfig* val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) { while (
g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
delete_target_config(val); delete_target_config(val);
} }
@ -539,14 +562,15 @@ void delete_project_config(ProjectConfig* config) {
} }
ProjectConfig* default_project_config() { ProjectConfig* default_project_config() {
ProjectConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig)); ProjectConfig* config =
mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig));
config->authors = NULL; config->authors = NULL;
config->name = NULL; config->name = NULL;
config->targets = NULL; config->targets = NULL;
config->license = NULL; config->license = NULL;
config->version = NULL; config->version = NULL;
config->desc = NULL; config->desc = NULL;
return config; return config;
} }

View File

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

View File

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

View File

@ -2,9 +2,9 @@
#ifndef CODEGN_BACKEND_H_ #ifndef CODEGN_BACKEND_H_
#define CODEGN_BACKEND_H_ #define CODEGN_BACKEND_H_
#include <set/types.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <set/types.h>
typedef struct BackendImplError_t { typedef struct BackendImplError_t {
// faulty AST node // faulty AST node
@ -28,8 +28,8 @@ typedef struct BackendError_t {
} BackendError; } BackendError;
/** /**
* @brief Function called by the compiler backend to generate an intermediate format * @brief Function called by the compiler backend to generate an intermediate
* from AST. Returns a custom container for its intermediate language. * format from AST. Returns a custom container for its intermediate language.
*/ */
typedef BackendError (*codegen)(const Module*, const TargetConfig* target); typedef BackendError (*codegen)(const Module*, const TargetConfig* target);
@ -45,51 +45,55 @@ typedef BackendError (*codegen_deinit)(void);
/** /**
* @brief Set the backend functions to use * @brief Set the backend functions to use
* *
* @param init_func the function to call for initializing the backend * @param init_func the function to call for initializing the backend
* @param deinit_func the function to call for undoing the initialization of the backend * @param deinit_func the function to call for undoing the initialization of the
* backend
* @param codegen_func the function to call when generating code * @param codegen_func the function to call when generating code
* @param name name of the backend * @param name name of the backend
*/ */
[[nodiscard]] [[nodiscard]] [[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(3),
[[gnu::nonnull(1), gnu::nonnull(2), gnu::nonnull(3), gnu::nonnull(3)]] gnu::nonnull(3)]]
BackendError set_backend(const codegen_init init_func, const codegen_deinit deinit_func, const codegen codegen_func, const char* name); BackendError set_backend(const codegen_init init_func,
const codegen_deinit deinit_func,
const codegen codegen_func, const char* name);
/** /**
* @brief Call the initialization function of the backend * @brief Call the initialization function of the backend
* *
* @return BackendError * @return BackendError
*/ */
[[nodiscard]] [[nodiscard]]
BackendError init_backend(void); BackendError init_backend(void);
/** /**
* @brief Call the undo initialization function of the backend * @brief Call the undo initialization function of the backend
* *
* @return BackendError * @return BackendError
*/ */
[[nodiscard]] [[nodiscard]]
BackendError deinit_backend(void); BackendError deinit_backend(void);
/** /**
* @brief Generate intermediate code with the registered backend * @brief Generate intermediate code with the registered backend
* *
* @param root the root node of the AST * @param root the root node of the AST
* @param code output pointer to the intermediate code * @param code output pointer to the intermediate code
* @return BackendError * @return BackendError
*/ */
[[nodiscard]] [[nodiscard]]
BackendError generate_code(const Module* root, const TargetConfig* target); BackendError generate_code(const Module* root, const TargetConfig* target);
/** /**
* @brief Create a new backend error * @brief Create a new backend error
* *
* @param kind must ne != Implementation * @param kind must ne != Implementation
* @return BackendError * @return BackendError
*/ */
BackendError new_backend_error(BackendErrorKind kind); BackendError new_backend_error(BackendErrorKind kind);
BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node, const char* message); BackendError new_backend_impl_error(BackendErrorKind kind, AST_NODE_PTR node,
const char* message);
#define SUCCESS new_backend_error(Success) #define SUCCESS new_backend_error(Success)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,12 +2,12 @@
// Created by servostar on 6/5/24. // Created by servostar on 6/5/24.
// //
#include <mem/cache.h>
#include <sys/log.h>
#include <glib.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include <cfg/opt.h> #include <cfg/opt.h>
#include <glib.h>
#include <mem/cache.h>
#include <string.h>
#include <sys/log.h>
static GHashTable* namespaces = NULL; static GHashTable* namespaces = NULL;
@ -39,16 +39,25 @@ typedef struct MemoryNamespace_t {
typedef MemoryNamespace* MemoryNamespaceRef; typedef MemoryNamespace* MemoryNamespaceRef;
static void namespace_statistics_print(MemoryNamespaceStatistic* memoryNamespaceStatistic, char* name) { static void
namespace_statistics_print(MemoryNamespaceStatistic* memoryNamespaceStatistic,
char* name) {
printf("Memory namespace statistics: `%s`\n", name); printf("Memory namespace statistics: `%s`\n", name);
printf("------------------------------\n"); printf("------------------------------\n");
printf(" allocated bytes: %ld\n", memoryNamespaceStatistic->bytes_allocated); printf(" allocated bytes: %ld\n",
printf(" allocations: %ld\n", memoryNamespaceStatistic->allocation_count); memoryNamespaceStatistic->bytes_allocated);
printf(" reallocations: %ld\n", memoryNamespaceStatistic->reallocation_count); printf(" allocations: %ld\n",
printf(" frees: %ld\n", memoryNamespaceStatistic->manual_free_count); memoryNamespaceStatistic->allocation_count);
printf(" faulty allocations: %ld\n", memoryNamespaceStatistic->faulty_allocations); printf(" reallocations: %ld\n",
printf(" faulty reallocations: %ld\n", memoryNamespaceStatistic->faulty_reallocations); memoryNamespaceStatistic->reallocation_count);
printf(" purged allocations: %ld\n", memoryNamespaceStatistic->purged_free_count); printf(" frees: %ld\n",
memoryNamespaceStatistic->manual_free_count);
printf(" faulty allocations: %ld\n",
memoryNamespaceStatistic->faulty_allocations);
printf(" faulty reallocations: %ld\n",
memoryNamespaceStatistic->faulty_reallocations);
printf(" purged allocations: %ld\n",
memoryNamespaceStatistic->purged_free_count);
printf("\n"); printf("\n");
} }
@ -58,14 +67,14 @@ static void* namespace_malloc(MemoryNamespaceRef memoryNamespace, size_t size) {
MemoryBlock block; MemoryBlock block;
block.block_ptr = malloc(size); block.block_ptr = malloc(size);
block.kind = GenericBlock; block.kind = GenericBlock;
if (block.block_ptr == NULL) { if (block.block_ptr == NULL) {
memoryNamespace->statistic.faulty_allocations ++; memoryNamespace->statistic.faulty_allocations++;
} else { } else {
g_array_append_val(memoryNamespace->blocks, block); g_array_append_val(memoryNamespace->blocks, block);
memoryNamespace->statistic.allocation_count ++; memoryNamespace->statistic.allocation_count++;
memoryNamespace->statistic.bytes_allocated += size; 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++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
if (current_block.block_ptr == block) { if (current_block.block_ptr == block) {
assert(block != NULL); assert(block != NULL);
@ -105,19 +116,22 @@ static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block)
return FALSE; return FALSE;
} }
static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block, size_t size) { static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block,
size_t size) {
void* reallocated_block = NULL; void* reallocated_block = NULL;
for (guint i = 0; i < memoryNamespace->blocks->len; i++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
if (current_block.block_ptr == block) { if (current_block.block_ptr == block) {
reallocated_block = realloc(current_block.block_ptr, size); reallocated_block = realloc(current_block.block_ptr, size);
if (reallocated_block != NULL) { if (reallocated_block != NULL) {
g_array_index(memoryNamespace->blocks, MemoryBlock, i).block_ptr = reallocated_block; g_array_index(memoryNamespace->blocks, MemoryBlock, i)
.block_ptr = reallocated_block;
memoryNamespace->statistic.bytes_allocated += size; memoryNamespace->statistic.bytes_allocated += size;
memoryNamespace->statistic.reallocation_count ++; memoryNamespace->statistic.reallocation_count++;
} else { } else {
memoryNamespace->statistic.faulty_reallocations++; memoryNamespace->statistic.faulty_reallocations++;
} }
@ -137,51 +151,55 @@ static void namespace_delete(MemoryNamespaceRef memoryNamespace) {
static void namespace_purge(MemoryNamespaceRef memoryNamespace) { static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
for (guint i = 0; i < memoryNamespace->blocks->len; i++) { for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
MemoryBlock current_block = g_array_index(memoryNamespace->blocks, MemoryBlock, i); MemoryBlock current_block =
g_array_index(memoryNamespace->blocks, MemoryBlock, i);
namespace_free_block(current_block); namespace_free_block(current_block);
memoryNamespace->statistic.purged_free_count ++; memoryNamespace->statistic.purged_free_count++;
} }
g_array_remove_range(memoryNamespace->blocks, 0, memoryNamespace->blocks->len); g_array_remove_range(memoryNamespace->blocks, 0,
memoryNamespace->blocks->len);
} }
static MemoryNamespaceRef namespace_new() { static MemoryNamespaceRef namespace_new() {
MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace)); MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace));
memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(MemoryBlock)); memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(MemoryBlock));
memoryNamespace->statistic.bytes_allocated = 0; memoryNamespace->statistic.bytes_allocated = 0;
memoryNamespace->statistic.allocation_count = 0; memoryNamespace->statistic.allocation_count = 0;
memoryNamespace->statistic.manual_free_count = 0; memoryNamespace->statistic.manual_free_count = 0;
memoryNamespace->statistic.faulty_reallocations = 0; memoryNamespace->statistic.faulty_reallocations = 0;
memoryNamespace->statistic.faulty_allocations = 0; memoryNamespace->statistic.faulty_allocations = 0;
memoryNamespace->statistic.purged_free_count = 0; memoryNamespace->statistic.purged_free_count = 0;
memoryNamespace->statistic.reallocation_count = 0; memoryNamespace->statistic.reallocation_count = 0;
return memoryNamespace; return memoryNamespace;
} }
GArray *namespace_new_g_array(MemoryNamespaceRef namespace, guint size) { GArray* namespace_new_g_array(MemoryNamespaceRef namespace, guint size) {
MemoryBlock block; MemoryBlock block;
block.block_ptr = g_array_new(FALSE, FALSE, size); block.block_ptr = g_array_new(FALSE, FALSE, size);
block.kind = GLIB_Array; block.kind = GLIB_Array;
g_array_append_val(namespace->blocks, block); g_array_append_val(namespace->blocks, block);
namespace->statistic.bytes_allocated += sizeof(GArray*); namespace->statistic.bytes_allocated += sizeof(GArray*);
namespace->statistic.allocation_count ++; namespace->statistic.allocation_count++;
return block.block_ptr; return block.block_ptr;
} }
GHashTable *namespace_new_g_hash_table(MemoryNamespaceRef namespace, GHashFunc hash_func, GEqualFunc key_equal_func) { GHashTable* namespace_new_g_hash_table(MemoryNamespaceRef namespace,
GHashFunc hash_func,
GEqualFunc key_equal_func) {
MemoryBlock block; MemoryBlock block;
block.block_ptr = g_hash_table_new(hash_func, key_equal_func); block.block_ptr = g_hash_table_new(hash_func, key_equal_func);
block.kind = GLIB_HashTable; block.kind = GLIB_HashTable;
g_array_append_val(namespace->blocks, block); g_array_append_val(namespace->blocks, block);
namespace->statistic.bytes_allocated += sizeof(GHashTable*); namespace->statistic.bytes_allocated += sizeof(GHashTable*);
namespace->statistic.allocation_count ++; namespace->statistic.allocation_count++;
return block.block_ptr; return block.block_ptr;
} }
@ -193,12 +211,13 @@ static void cleanup() {
} }
GHashTableIter iter; GHashTableIter iter;
char* name = NULL; char* name = NULL;
MemoryNamespaceRef memoryNamespace = NULL; MemoryNamespaceRef memoryNamespace = NULL;
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
assert(name != NULL); assert(name != NULL);
assert(memoryNamespace != NULL); assert(memoryNamespace != NULL);
@ -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); MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) { if (cache == NULL) {
@ -239,7 +258,7 @@ void *mem_alloc(MemoryNamespaceName name, size_t size) {
return namespace_malloc(cache, 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); MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) { if (cache == NULL) {
@ -249,7 +268,7 @@ void *mem_realloc(MemoryNamespaceName name, void *ptr, size_t size) {
return namespace_realloc(cache, ptr, 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); MemoryNamespaceRef cache = check_namespace(name);
namespace_free(cache, memory); namespace_free(cache, memory);
@ -261,7 +280,8 @@ void mem_free(void* memory) {
MemoryNamespaceRef memoryNamespace; MemoryNamespaceRef memoryNamespace;
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
if (namespace_free(memoryNamespace, memory)) { if (namespace_free(memoryNamespace, memory)) {
break; break;
@ -284,7 +304,7 @@ char* mem_strdup(MemoryNamespaceName name, char* string) {
} }
void* mem_clone(MemoryNamespaceName name, void* data, size_t size) { 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); memcpy(clone, data, size);
@ -297,31 +317,36 @@ void print_memory_statistics() {
MemoryNamespaceRef memoryNamespace; MemoryNamespaceRef memoryNamespace;
MemoryNamespaceStatistic total; MemoryNamespaceStatistic total;
total.bytes_allocated = 0; total.bytes_allocated = 0;
total.faulty_reallocations = 0; total.faulty_reallocations = 0;
total.faulty_allocations = 0; total.faulty_allocations = 0;
total.manual_free_count = 0; total.manual_free_count = 0;
total.allocation_count = 0; total.allocation_count = 0;
total.purged_free_count = 0; total.purged_free_count = 0;
total.reallocation_count = 0; total.reallocation_count = 0;
g_hash_table_iter_init(&iter, namespaces); g_hash_table_iter_init(&iter, namespaces);
while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) { while (g_hash_table_iter_next(&iter, (gpointer) &name,
(gpointer) &memoryNamespace)) {
namespace_statistics_print(&memoryNamespace->statistic, name); namespace_statistics_print(&memoryNamespace->statistic, name);
total.bytes_allocated += memoryNamespace->statistic.bytes_allocated; total.bytes_allocated += memoryNamespace->statistic.bytes_allocated;
total.faulty_reallocations += memoryNamespace->statistic.faulty_reallocations; total.faulty_reallocations +=
total.faulty_allocations += memoryNamespace->statistic.faulty_allocations; memoryNamespace->statistic.faulty_reallocations;
total.faulty_allocations +=
memoryNamespace->statistic.faulty_allocations;
total.manual_free_count += memoryNamespace->statistic.manual_free_count; total.manual_free_count += memoryNamespace->statistic.manual_free_count;
total.allocation_count += memoryNamespace->statistic.allocation_count; total.allocation_count += memoryNamespace->statistic.allocation_count;
total.purged_free_count += memoryNamespace->statistic.purged_free_count; total.purged_free_count += memoryNamespace->statistic.purged_free_count;
total.reallocation_count += memoryNamespace->statistic.reallocation_count; total.reallocation_count +=
memoryNamespace->statistic.reallocation_count;
} }
namespace_statistics_print(&total, "summary"); namespace_statistics_print(&total, "summary");
printf("Note: untracked are memory allocations from external libraries and non-gc managed components.\n"); printf("Note: untracked are memory allocations from external libraries and "
"non-gc managed components.\n");
} }
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) { GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) {
@ -334,7 +359,8 @@ GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size) {
return namespace_new_g_array(cache, element_size); return namespace_new_g_array(cache, element_size);
} }
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func) { GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func,
GEqualFunc key_equal_func) {
MemoryNamespaceRef cache = check_namespace(name); MemoryNamespaceRef cache = check_namespace(name);
if (cache == NULL) { if (cache == NULL) {

View File

@ -5,21 +5,21 @@
#ifndef GEMSTONE_CACHE_H #ifndef GEMSTONE_CACHE_H
#define GEMSTONE_CACHE_H #define GEMSTONE_CACHE_H
#include <glib.h>
#include <mem/cache.h> #include <mem/cache.h>
#include <stddef.h> #include <stddef.h>
#include <glib.h>
typedef char* MemoryNamespaceName; typedef char* MemoryNamespaceName;
#define MemoryNamespaceAst "AST" #define MemoryNamespaceAst "AST"
#define MemoryNamespaceLex "Lexer" #define MemoryNamespaceLex "Lexer"
#define MemoryNamespaceLog "Logging" #define MemoryNamespaceLog "Logging"
#define MemoryNamespaceOpt "Options" #define MemoryNamespaceOpt "Options"
#define MemoryNamespaceTOML "TOML" #define MemoryNamespaceTOML "TOML"
#define MemoryNamespaceSet "SET" #define MemoryNamespaceSet "SET"
#define MemoryNamespaceLlvm "LLVM" #define MemoryNamespaceLlvm "LLVM"
#define MemoryNamespaceLld "LLD" #define MemoryNamespaceLld "LLD"
#define MemoryNamespaceIo "I/O" #define MemoryNamespaceIo "I/O"
#define MemoryNamespaceStatic "Static" #define MemoryNamespaceStatic "Static"
/** /**
@ -44,7 +44,7 @@ void* mem_alloc(MemoryNamespaceName name, size_t size);
* @param size * @param size
* @return pointer to the block * @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. * @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. * @brief Free a block of memory.
* Invoking multiple times on the same pointer will do nothing. * Invoking multiple times on the same pointer will do nothing.
* @attention In case the namespace of the block is known, consider using mem_free_from() * @attention In case the namespace of the block is known, consider using
* to avoid unnecessary overhead. * mem_free_from() to avoid unnecessary overhead.
* @param name * @param name
* @param memory * @param memory
*/ */
@ -91,6 +91,7 @@ void print_memory_statistics();
GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size); GArray* mem_new_g_array(MemoryNamespaceName name, guint element_size);
GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func, GEqualFunc key_equal_func); GHashTable* mem_new_g_hash_table(MemoryNamespaceName name, GHashFunc hash_func,
GEqualFunc key_equal_func);
#endif //GEMSTONE_CACHE_H #endif // GEMSTONE_CACHE_H

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -2,28 +2,28 @@
#ifndef SET_TYPES_H_ #ifndef SET_TYPES_H_
#define SET_TYPES_H_ #define SET_TYPES_H_
#include <glib.h>
#include <ast/ast.h> #include <ast/ast.h>
#include <glib.h>
// with of primitive types (int/float) in bytes // with of primitive types (int/float) in bytes
#define BASE_BYTES 4 #define BASE_BYTES 4
/** /**
* @brief Primitive types form the basis of all other types. * @brief Primitive types form the basis of all other types.
* *
*/ */
typedef enum PrimitiveType_t { typedef enum PrimitiveType_t {
// 4 byte signed integer in two's complement // 4 byte signed integer in two's complement
Int =0, Int = 0,
// 4 byte IEEE-754 single precision // 4 byte IEEE-754 single precision
Float =1, Float = 1,
// 4 byte encoded UTF-8 codepoint // 4 byte encoded UTF-8 codepoint
Char = 2, Char = 2,
} PrimitiveType; } PrimitiveType;
/** /**
* @brief Represents the sign of a composite type. * @brief Represents the sign of a composite type.
* *
*/ */
typedef enum Sign_t { typedef enum Sign_t {
// type has no sign bit // type has no sign bit
@ -36,13 +36,13 @@ typedef enum Sign_t {
* @brief Represents the scale of composite type which is multiplied * @brief Represents the scale of composite type which is multiplied
* with the base size in order to retrieve the the composites size. * with the base size in order to retrieve the the composites size.
* @attention Valid value are: { 1/8, 1/4, 1/2, 1, 2, 4, 8 } * @attention Valid value are: { 1/8, 1/4, 1/2, 1, 2, 4, 8 }
* *
*/ */
typedef double Scale; typedef double Scale;
/** /**
* @brief A composite type is an extended definition of a primitive type. * @brief A composite type is an extended definition of a primitive type.
* *
*/ */
typedef struct CompositeType_t { typedef struct CompositeType_t {
// sign of composite // sign of composite
@ -54,7 +54,7 @@ typedef struct CompositeType_t {
/** /**
* @brief Specifies the specific type of the generic type struct. * @brief Specifies the specific type of the generic type struct.
* *
*/ */
typedef enum TypeKind_t { typedef enum TypeKind_t {
TypeKindPrimitive, TypeKindPrimitive,
@ -67,8 +67,9 @@ typedef struct Type_t Type;
/** /**
* @brief Reference points to a type. * @brief Reference points to a type.
* @attention Can be nested. A reference can point to another reference: REF -> REF -> REF -> Primitive * @attention Can be nested. A reference can point to another reference: REF ->
* * REF -> REF -> Primitive
*
*/ */
typedef Type* ReferenceType; typedef Type* ReferenceType;
@ -88,12 +89,12 @@ typedef struct BoxMember_t {
/** /**
* @brief Essentially a g lorified struct * @brief Essentially a g lorified struct
* *
*/ */
typedef struct BoxType_t { typedef struct BoxType_t {
// hashtable of members. // hashtable of members.
// Associates the memebers name (const char*) with its type (BoxMember) // Associates the memebers name (const char*) with its type (BoxMember)
GHashTable* member; //BoxMember Pointer GHashTable* member; // BoxMember Pointer
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} BoxType; } BoxType;
@ -101,7 +102,8 @@ typedef struct Variable_t Variable;
typedef struct BoxAccess_t { typedef struct BoxAccess_t {
// list of recursive box accesses // list of recursive box accesses
// contains a list of BoxMembers (each specifying their own type, name and box type) // contains a list of BoxMembers (each specifying their own type, name and
// box type)
GArray* member; GArray* member;
// box variable to access // box variable to access
Variable* variable; Variable* variable;
@ -124,19 +126,18 @@ typedef struct Type_t {
typedef struct Typedefine_t { typedef struct Typedefine_t {
const char* name; const char* name;
Type *type; Type* type;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Typedefine; } Typedefine;
/** /**
* @brief Reprents the value of type. Can be used to definitions, initialization and for expressions contants. * @brief Reprents the value of type. Can be used to definitions, initialization
* * and for expressions contants.
*
*/ */
typedef struct TypeValue_t { typedef struct TypeValue_t {
// the type // the type
Type *type; Type* type;
// UTF-8 representation of the type's value // UTF-8 representation of the type's value
const char* value; const char* value;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
@ -148,7 +149,7 @@ typedef struct TypeValue_t {
/** /**
* @brief Specifies a parameters I/O properties * @brief Specifies a parameters I/O properties
* *
*/ */
typedef enum IO_Qualifier_t { typedef enum IO_Qualifier_t {
// Can be read from but not written to. // Can be read from but not written to.
@ -164,23 +165,23 @@ typedef enum IO_Qualifier_t {
/** /**
* @brief A functions parameter declaration. * @brief A functions parameter declaration.
* *
*/ */
typedef struct ParameterDeclaration_t { typedef struct ParameterDeclaration_t {
Type *type; Type* type;
IO_Qualifier qualifier; IO_Qualifier qualifier;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} ParameterDeclaration; } ParameterDeclaration;
/** /**
* @brief A functions parameter. * @brief A functions parameter.
* *
*/ */
typedef struct ParameterDefinition_t { typedef struct ParameterDefinition_t {
ParameterDeclaration declaration; ParameterDeclaration declaration;
// value to initalize the declaration with // value to initalize the declaration with
// NOTE: type of initializer and declaration MUST be equal // NOTE: type of initializer and declaration MUST be equal
Expression *initializer; Expression* initializer;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} ParameterDefinition; } ParameterDefinition;
@ -191,18 +192,18 @@ typedef enum ParameterKind_t {
/** /**
* @brief A parameter can either be a declaration or a definition * @brief A parameter can either be a declaration or a definition
* *
*/ */
typedef struct Parameter_t { typedef struct Parameter_t {
const char* name; const char* name;
ParameterKind kind; ParameterKind kind;
union ParameterImplementation { union ParameterImplementation {
ParameterDeclaration declaration; ParameterDeclaration declaration;
ParameterDefinition definiton; ParameterDefinition definiton;
} impl; } impl;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Parameter; // fix typo } Parameter; // fix typo
typedef enum FunctionKind_t { typedef enum FunctionKind_t {
FunctionDeclarationKind, FunctionDeclarationKind,
@ -211,19 +212,21 @@ typedef enum FunctionKind_t {
typedef struct FunctionDefinition_t { typedef struct FunctionDefinition_t {
// hashtable of parameters // hashtable of parameters
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration
// (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
Type* return_value; Type* return_value;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
// body of function // body of function
Block *body; Block* body;
// name of function // name of function
const char* name; const char* name;
} FunctionDefinition; } FunctionDefinition;
typedef struct FunctionDeclaration_t { typedef struct FunctionDeclaration_t {
// hashtable of parameters // hashtable of parameters
// associates a parameters name (const char*) with its parameter declaration (ParameterDeclaration) // associates a parameters name (const char*) with its parameter declaration
// (ParameterDeclaration)
GArray* parameter; // Parameter GArray* parameter; // Parameter
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
Type* return_value; Type* return_value;
@ -237,7 +240,7 @@ typedef struct Function_t {
FunctionDeclaration declaration; FunctionDeclaration declaration;
} impl; } impl;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
const char * name; const char* name;
} Function; } Function;
Parameter get_param_from_func(Function* func, size_t index); 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 | // | Variables |
// '------------------------------------------------' // '------------------------------------------------'
typedef enum StorageQualifier_t { typedef enum StorageQualifier_t { Local, Static, Global } StorageQualifier;
Local,
Static,
Global
} StorageQualifier;
typedef struct VariableDeclaration_t { typedef struct VariableDeclaration_t {
StorageQualifier qualifier; StorageQualifier qualifier;
Type *type; Type* type;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} VariableDeclaration; } VariableDeclaration;
/** /**
* @brief Definition of a variable * @brief Definition of a variable
* *
* @attention NOTE: The types of the initializer and the declaration must be equal * @attention NOTE: The types of the initializer and the declaration must be
* * equal
*
*/ */
typedef struct VariableDefiniton_t { typedef struct VariableDefiniton_t {
VariableDeclaration declaration; VariableDeclaration declaration;
Expression *initializer; Expression* initializer;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} VariableDefiniton; } VariableDefiniton;
@ -291,7 +291,7 @@ typedef struct Dereference_t {
Expression* index; Expression* index;
Expression* variable; Expression* variable;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
}Dereference; } Dereference;
typedef struct StorageExpr_t StorageExpr; typedef struct StorageExpr_t StorageExpr;
@ -304,23 +304,24 @@ typedef struct StorageDereference_t {
typedef struct AddressOf_t { typedef struct AddressOf_t {
Expression* variable; Expression* variable;
AST_NODE_PTR node_ptr; AST_NODE_PTR node_ptr;
}AddressOf; } AddressOf;
// .------------------------------------------------. // .------------------------------------------------.
// | Casts | // | Casts |
// '------------------------------------------------' // '------------------------------------------------'
/** /**
* @brief Perform a type cast, converting a value to different type whilest preserving as much of the original * @brief Perform a type cast, converting a value to different type whilest
* values information. * preserving as much of the original values information.
* *
* @attention NOTE: Must check wether the given value's type can be parsed into * @attention NOTE: Must check wether the given value's type can be parsed into
* the target type without loss. * the target type without loss.
* Lossy mean possibly loosing information such when casting a float into an int (no fraction anymore). * Lossy mean possibly loosing information such when casting a float into
* an int (no fraction anymore).
* *
*/ */
typedef struct TypeCast_t { typedef struct TypeCast_t {
Type *targetType; Type* targetType;
Expression* operand; Expression* operand;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} TypeCast; } TypeCast;
@ -328,12 +329,12 @@ typedef struct TypeCast_t {
/** /**
* @brief Perform a reinterpret cast. * @brief Perform a reinterpret cast.
* *
* @attention NOTE: The given value's type must have the size in bytes as the target type. * @attention NOTE: The given value's type must have the size in bytes as the
* Transmuting a short int into a float should yield an error. * target type. Transmuting a short int into a float should yield an error.
* *
*/ */
typedef struct Transmute_t { typedef struct Transmute_t {
Type *targetType; Type* targetType;
Expression* operand; Expression* operand;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Transmute; } Transmute;
@ -344,7 +345,7 @@ typedef struct Transmute_t {
/** /**
* @brief Represents the arithmetic operator. * @brief Represents the arithmetic operator.
* *
*/ */
typedef enum ArithmeticOperator_t { typedef enum ArithmeticOperator_t {
Add, Add,
@ -360,13 +361,9 @@ typedef enum ArithmeticOperator_t {
/** /**
* @brief Represents the relational operator. * @brief Represents the relational operator.
* *
*/ */
typedef enum RelationalOperator_t { typedef enum RelationalOperator_t { Equal, Greater, Less } RelationalOperator;
Equal,
Greater,
Less
} RelationalOperator;
// .------------------------------------------------. // .------------------------------------------------.
// | Boolean | // | Boolean |
@ -420,11 +417,11 @@ typedef struct Operation_t {
union OperationImplementation { union OperationImplementation {
ArithmeticOperator arithmetic; ArithmeticOperator arithmetic;
RelationalOperator relational; RelationalOperator relational;
BooleanOperator boolean; BooleanOperator boolean;
LogicalOperator logical; LogicalOperator logical;
BitwiseOperator bitwise; BitwiseOperator bitwise;
} impl; } impl;
GArray* operands; //Expression* GArray* operands; // Expression*
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} Operation; } Operation;
@ -498,7 +495,7 @@ typedef struct Block_t {
// '------------------------------------------------' // '------------------------------------------------'
typedef struct While_t { typedef struct While_t {
Expression *conditon; Expression* conditon;
Block block; Block block;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} While; } While;
@ -508,13 +505,13 @@ typedef struct While_t {
// '------------------------------------------------' // '------------------------------------------------'
typedef struct If_t { typedef struct If_t {
Expression *conditon; Expression* conditon;
Block block; Block block;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} If; } If;
typedef struct ElseIf_t { typedef struct ElseIf_t {
Expression *conditon; Expression* conditon;
Block block; Block block;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
} ElseIf; } ElseIf;
@ -584,7 +581,7 @@ typedef struct Statement_t {
While whileLoop; While whileLoop;
Branch branch; Branch branch;
Assignment assignment; Assignment assignment;
Variable *variable; Variable* variable;
Return returnStmt; Return returnStmt;
} impl; } impl;
AST_NODE_PTR nodePtr; AST_NODE_PTR nodePtr;
@ -595,7 +592,7 @@ typedef struct Statement_t {
// '------------------------------------------------' // '------------------------------------------------'
typedef struct Module_t { typedef struct Module_t {
GHashTable* boxes; //BoxType GHashTable* boxes; // BoxType
GHashTable* types; // GHashTable* types; //
GHashTable* functions; GHashTable* functions;
GHashTable* variables; GHashTable* variables;
@ -638,7 +635,7 @@ void delete_typecast(TypeCast* cast);
void delete_box_member(BoxMember* member); 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); void delete_composite([[maybe_unused]] CompositeType* composite);

View File

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

View File

@ -2,19 +2,19 @@
#ifndef COLORS_H_ #ifndef COLORS_H_
#define COLORS_H_ #define COLORS_H_
#define ANSI_ENABLED 1 #define ANSI_ENABLED 1
#define ASNI_DISABLED 0 #define ASNI_DISABLED 0
// Common escape codes // Common escape codes
// can be used to print colored text // can be used to print colored text
extern char *RED; extern char* RED;
extern char *YELLOW; extern char* YELLOW;
extern char *MAGENTA; extern char* MAGENTA;
extern char *CYAN; extern char* CYAN;
extern char *GREEN; extern char* GREEN;
extern char *RESET; extern char* RESET;
extern char *BOLD; extern char* BOLD;
extern char *FAINT; extern char* FAINT;
/** /**
* @brief Initialize global state * @brief Initialize global state
@ -28,14 +28,17 @@ void col_init(void);
void enable_ansi_colors(); void enable_ansi_colors();
/** /**
* @brief Disable ANSI escape codes. This will set all the above global strings to be empty. * @brief Disable ANSI escape codes. This will set all the above global strings
* to be empty.
*/ */
void disable_ansi_colors(); void disable_ansi_colors();
/** /**
* @brief Check if stdout may support ANSI escape codes. * @brief Check if stdout may support ANSI escape codes.
* @attention This function may report escape codes to be unavailable even if they actually are. * @attention This function may report escape codes to be unavailable even if
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED otherwise * they actually are.
* @return ANSI_ENABLED if escape sequences are supported ASNI_DISABLED
* otherwise
*/ */
[[nodiscard]] [[nodiscard]]
int stdout_supports_ansi_esc(); int stdout_supports_ansi_esc();

View File

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

View File

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