formatted source with clangd
This commit is contained in:
parent
ed728c8042
commit
e1649657fd
|
@ -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
|
||||||
|
|
|
@ -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
|
153
src/ast/ast.c
153
src/ast/ast.c
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
154
src/cfg/opt.c
154
src/cfg/opt.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
149
src/compiler.c
149
src/compiler.c
|
@ -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);
|
||||||
|
|
|
@ -11,4 +11,4 @@
|
||||||
*/
|
*/
|
||||||
int run_compiler();
|
int run_compiler();
|
||||||
|
|
||||||
#endif //GEMSTONE_COMPILER_H
|
#endif // GEMSTONE_COMPILER_H
|
||||||
|
|
116
src/io/files.c
116
src/io/files.c
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
125
src/lex/util.c
125
src/lex/util.c
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(¶m), 0, &llvm_arg);
|
err = impl_expr(unit, scope, builder, arg, is_parameter_out(¶m),
|
||||||
|
0, &llvm_arg);
|
||||||
|
|
||||||
if (err.kind != Success) {
|
if (err.kind != Success) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_parameter_out(¶m)) {
|
if (is_parameter_out(¶m)) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
18
src/main.c
18
src/main.c
|
@ -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);
|
||||||
|
|
136
src/mem/cache.c
136
src/mem/cache.c
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
1685
src/set/set.c
1685
src/set/set.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
131
src/set/types.h
131
src/set/types.h
|
@ -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);
|
||||||
|
|
||||||
|
|
104
src/sys/col.c
104
src/sys/col.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
122
src/sys/log.h
122
src/sys/log.h
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue