diff --git a/.github/workflows/msys2-cross-compile.yml b/.github/workflows/msys2-cross-compile.yml
new file mode 100644
index 0000000..770ea3b
--- /dev/null
+++ b/.github/workflows/msys2-cross-compile.yml
@@ -0,0 +1,20 @@
+name: MSYS2
+on: [push, pull_request]
+
+jobs:
+ msys2-mingw64:
+ runs-on: windows-latest
+ defaults:
+ run:
+ shell: msys2 {0}
+ steps:
+ - uses: actions/checkout@v3
+ - uses: msys2/setup-msys2@v2
+ with:
+ msystem: MINGW64
+ update: true
+ install: mingw-w64-x86_64-gcc mingw-w64-x86_64-glib2 bison flex mingw-w64-x86_64-llvm cmake git make
+ - name: CI-Build
+ run: |
+ echo 'Running in MSYS2!'
+ ./ci-build.sh
\ No newline at end of file
diff --git a/README.md b/README.md
index faca249..daaaf32 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,31 @@
-# Gemstone
-Gemstone is a programming language compiler written in C with lex and yacc.
+
+
+
+
+
+## Gemstone
+
+Gemstone is a programming language compiler (short: GSC) written in C based on flex and GNU bison.
+It uses LLVM to produce optimized native binaries for many platforms and uses its own builtin build system for more complex project management.
## Dependencies (build)
### Windows 11
-For setup instruction see issue #30
-
-Requires:
-- Microsoft Build Tools 2022 (includes: CMake, MSVC)
-- WinFlexBison [find it here](https://github.com/lexxmark/winflexbison) (needs to be in PATH)
+#### MSYS2
+Install MSYS2 under Windows 11. Open the MingGW64 environment.
+Install the following packages:
+```
+pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-glib2 bison flex mingw-w64-x86_64-llvm cmake git make
+```
+Clone the repository and build the gemstone compiler:
+```
+cmake . && make release
+```
### GNU/Linux
Requires:
@@ -20,6 +34,8 @@ Requires:
- Make
- bison
- flex
+- LLVM
+- Glib 2.0
## Writing Tests
diff --git a/ci-build.sh b/ci-build.sh
new file mode 100755
index 0000000..8b09b06
--- /dev/null
+++ b/ci-build.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+cmake .
+make release
diff --git a/src/ast/ast.c b/src/ast/ast.c
index db407b7..20132dc 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -1,121 +1,121 @@
#include
#include
-#include
#include
#include
+#include
struct AST_Node_t *AST_new_node(TokenLocation location, enum AST_SyntaxElement_t kind, const char* value) {
- DEBUG("creating new AST node: %d \"%s\"", kind, value);
- assert(kind < AST_ELEMENT_COUNT);
+ DEBUG("creating new AST node: %d \"%s\"", kind, value);
+ assert(kind < AST_ELEMENT_COUNT);
- struct AST_Node_t *node = malloc(sizeof(struct AST_Node_t));
+ struct AST_Node_t *node = mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t));
- if (node == NULL) {
- PANIC("failed to allocate AST node");
- }
+ if (node == NULL) {
+ PANIC("failed to allocate AST node");
+ }
- assert(node != NULL);
+ assert(node != NULL);
- // init to discrete state
- node->parent = NULL;
- node->children = NULL;
- node->child_count = 0;
- node->kind = kind;
- node->value = value;
- node->location = location;
+ // init to discrete state
+ node->parent = NULL;
+ node->children = NULL;
+ node->child_count = 0;
+ node->kind = kind;
+ node->value = value;
+ node->location = location;
- return node;
+ return node;
}
static const char* lookup_table[AST_ELEMENT_COUNT] = { "__UNINIT__" };
void AST_init() {
- DEBUG("initializing global syntax tree...");
+ DEBUG("initializing global syntax tree...");
- INFO("filling lookup table...");
- lookup_table[AST_Stmt] = "stmt";
- lookup_table[AST_Module] = "module";
- lookup_table[AST_Expr] = "expr";
+ INFO("filling lookup table...");
+ lookup_table[AST_Stmt] = "stmt";
+ lookup_table[AST_Module] = "module";
+ lookup_table[AST_Expr] = "expr";
- lookup_table[AST_Add] = "+";
- lookup_table[AST_Sub] = "-";
- lookup_table[AST_Mul] = "*";
- lookup_table[AST_Div] = "/";
+ lookup_table[AST_Add] = "+";
+ lookup_table[AST_Sub] = "-";
+ lookup_table[AST_Mul] = "*";
+ lookup_table[AST_Div] = "/";
- lookup_table[AST_BitAnd] = "&";
- lookup_table[AST_BitOr] = "|";
- lookup_table[AST_BitXor] = "^";
- lookup_table[AST_BitNot] = "!";
+ lookup_table[AST_BitAnd] = "&";
+ lookup_table[AST_BitOr] = "|";
+ lookup_table[AST_BitXor] = "^";
+ lookup_table[AST_BitNot] = "!";
- lookup_table[AST_Eq] = "==";
- lookup_table[AST_Less] = "<";
- lookup_table[AST_Greater] = ">";
+ lookup_table[AST_Eq] = "==";
+ lookup_table[AST_Less] = "<";
+ lookup_table[AST_Greater] = ">";
- lookup_table[AST_BoolAnd] = "&&";
- lookup_table[AST_BoolOr] = "||";
- lookup_table[AST_BoolXor] = "^^";
- lookup_table[AST_BoolNot] = "!!";
+ lookup_table[AST_BoolAnd] = "&&";
+ lookup_table[AST_BoolOr] = "||";
+ lookup_table[AST_BoolXor] = "^^";
+ lookup_table[AST_BoolNot] = "!!";
- lookup_table[AST_While] = "while";
- lookup_table[AST_If] = "if";
- lookup_table[AST_IfElse] = "else if";
- lookup_table[AST_Else] = "else";
+ lookup_table[AST_While] = "while";
+ lookup_table[AST_If] = "if";
+ lookup_table[AST_IfElse] = "else if";
+ lookup_table[AST_Else] = "else";
- lookup_table[AST_Decl] = "decl";
- lookup_table[AST_Assign] = "assign";
- lookup_table[AST_Def] = "def";
+ lookup_table[AST_Decl] = "decl";
+ lookup_table[AST_Assign] = "assign";
+ lookup_table[AST_Def] = "def";
- lookup_table[AST_Typedef] = "typedef";
- lookup_table[AST_Box] = "box";
- lookup_table[AST_Fun] = "fun";
+ lookup_table[AST_Typedef] = "typedef";
+ lookup_table[AST_Box] = "box";
+ lookup_table[AST_Fun] = "fun";
- lookup_table[AST_Call] = "funcall";
- lookup_table[AST_Typecast] = "typecast";
- lookup_table[AST_Transmute] = "transmute";
- lookup_table[AST_Condition] = "condition";
- lookup_table[AST_List] = "list";
- lookup_table[AST_ExprList] = "expr list";
- lookup_table[AST_ArgList] = "arg list";
- lookup_table[AST_ParamList] = "param list";
- lookup_table[AST_StmtList] = "stmt list";
- lookup_table[AST_IdentList] = "ident list";
- lookup_table[AST_Type] = "type";
- lookup_table[AST_Negate] = "-";
- lookup_table[AST_Parameter] = "parameter";
- lookup_table[AST_ParamDecl] = "parameter-declaration";
- lookup_table[AST_AddressOf] = "address of";
- lookup_table[AST_Dereference] = "deref";
- lookup_table[AST_Reference] = "ref";
+ lookup_table[AST_Call] = "funcall";
+ lookup_table[AST_Typecast] = "typecast";
+ lookup_table[AST_Transmute] = "transmute";
+ lookup_table[AST_Condition] = "condition";
+ lookup_table[AST_List] = "list";
+ lookup_table[AST_ExprList] = "expr list";
+ lookup_table[AST_ArgList] = "arg list";
+ lookup_table[AST_ParamList] = "param list";
+ lookup_table[AST_StmtList] = "stmt list";
+ lookup_table[AST_IdentList] = "ident list";
+ lookup_table[AST_Type] = "type";
+ lookup_table[AST_Negate] = "-";
+ lookup_table[AST_Parameter] = "parameter";
+ lookup_table[AST_ParamDecl] = "parameter-declaration";
+ lookup_table[AST_AddressOf] = "address of";
+ lookup_table[AST_Dereference] = "deref";
+ lookup_table[AST_Reference] = "ref";
}
const char* AST_node_to_string(const struct AST_Node_t* node) {
- DEBUG("converting AST node to string: %p", node);
- assert(node != NULL);
+ DEBUG("converting AST node to string: %p", node);
+ assert(node != NULL);
- const char* string;
+ const char* string;
- switch(node->kind) {
- case AST_Int:
- case AST_Float:
- case AST_String:
- case AST_Ident:
- case AST_Macro:
- case AST_Import:
- case AST_Storage:
- case AST_Typekind:
- case AST_Sign:
- case AST_Scale:
- case AST_Qualifyier:
- string = node->value;
- break;
- default:
- string = lookup_table[node->kind];
- }
+ switch(node->kind) {
+ case AST_Int:
+ case AST_Float:
+ case AST_String:
+ case AST_Ident:
+ case AST_Macro:
+ case AST_Import:
+ case AST_Storage:
+ case AST_Typekind:
+ case AST_Sign:
+ case AST_Scale:
+ case AST_Qualifyier:
+ string = node->value;
+ break;
+ default:
+ string = lookup_table[node->kind];
+ }
- assert(string != NULL);
+ assert(string != NULL);
- return string;
+ return string;
}
static inline unsigned long int min(unsigned long int a, unsigned long int b) {
@@ -127,183 +127,182 @@ static inline unsigned long int max(unsigned long int a, unsigned long int b) {
}
void AST_push_node(struct AST_Node_t *owner, struct AST_Node_t *child) {
- DEBUG("Adding new node %p to %p", child, owner);
- assert(owner != NULL);
- assert(child != NULL);
+ DEBUG("Adding new node %p to %p", child, owner);
+ assert(owner != NULL);
+ assert(child != NULL);
- // if there are no children for now
- if (owner->child_count == 0) {
- DEBUG("Allocating new children array");
- owner->children = malloc(sizeof(struct AST_Node_t *));
+ // if there are no children for now
+ if (owner->child_count == 0) {
+ DEBUG("Allocating new children array");
+ owner->children = mem_alloc(MemoryNamespaceAst, sizeof(struct AST_Node_t *));
- } else {
- DEBUG("Rellocating old children array");
- const size_t size = sizeof(struct AST_Node_t *) * (owner->child_count + 1);
- owner->children = realloc(owner->children, size);
- }
+ } else {
+ DEBUG("Rellocating old children array");
+ const size_t size = sizeof(struct AST_Node_t *) * (owner->child_count + 1);
+ owner->children = mem_realloc(MemoryNamespaceAst, owner->children, size);
+ }
- if (owner->children == NULL) {
- PANIC("failed to allocate children array of AST node");
- }
+ if (owner->children == NULL) {
+ PANIC("failed to allocate children array of AST node");
+ }
- owner->location.col_end = max(owner->location.col_end, child->location.col_end);
- owner->location.line_end = max(owner->location.line_end, child->location.line_end);
+ owner->location.col_end = max(owner->location.col_end, child->location.col_end);
+ owner->location.line_end = max(owner->location.line_end, child->location.line_end);
- owner->location.col_start = min(owner->location.col_start, child->location.col_start);
- owner->location.line_start = min(owner->location.line_start, child->location.line_start);
+ owner->location.col_start = min(owner->location.col_start, child->location.col_start);
+ owner->location.line_start = min(owner->location.line_start, child->location.line_start);
- assert(owner->children != NULL);
+ assert(owner->children != NULL);
- owner->children[owner->child_count++] = child;
+ owner->children[owner->child_count++] = child;
}
struct AST_Node_t *AST_get_node(struct AST_Node_t *owner, const size_t idx) {
- DEBUG("retrvieng node %d from %p", idx, owner);
- assert(owner != NULL);
- assert(owner->children != NULL);
- assert(idx < owner->child_count);
+ DEBUG("retrvieng node %d from %p", idx, owner);
+ assert(owner != NULL);
+ assert(owner->children != NULL);
+ assert(idx < owner->child_count);
- if (owner->children == NULL) {
- PANIC("AST owner node has no children");
- }
+ if (owner->children == NULL) {
+ PANIC("AST owner node has no children");
+ }
- struct AST_Node_t *child = owner->children[idx];
+ struct AST_Node_t *child = owner->children[idx];
- if (child == NULL) {
- PANIC("child node is NULL");
- }
+ if (child == NULL) {
+ PANIC("child node is NULL");
+ }
- return child;
+ return child;
}
struct AST_Node_t* AST_remove_child(struct AST_Node_t* owner, const size_t idx) {
- assert(owner != NULL);
- assert(owner->children != NULL);
- assert(idx < owner->child_count);
+ assert(owner != NULL);
+ assert(owner->children != NULL);
+ assert(idx < owner->child_count);
- struct AST_Node_t* child = owner->children[idx];
+ struct AST_Node_t* child = owner->children[idx];
- child->parent = NULL;
+ child->parent = NULL;
- owner->child_count--;
+ owner->child_count--;
- // shift back every following element by one
- for (size_t i = idx; i < owner->child_count; i++) {
- owner->children[i] = owner->children[i + 1];
- }
+ // shift back every following element by one
+ for (size_t i = idx; i < owner->child_count; i++) {
+ owner->children[i] = owner->children[i + 1];
+ }
- return child;
+ return child;
}
struct AST_Node_t* AST_detach_child(struct AST_Node_t* owner, const struct AST_Node_t* child) {
- assert(owner != NULL);
- assert(child != NULL);
- assert(owner->children != NULL);
+ assert(owner != NULL);
+ assert(child != NULL);
+ assert(owner->children != NULL);
- for (size_t i = 0; i < owner->child_count; i++) {
- if (owner->children[i] == child) {
- return AST_remove_child(owner, i);
+ for (size_t i = 0; i < owner->child_count; i++) {
+ if (owner->children[i] == child) {
+ return AST_remove_child(owner, i);
+ }
}
- }
- 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) {
- assert(node != NULL);
+ assert(node != NULL);
- DEBUG("Deleting AST node: %p", node);
+ DEBUG("Deleting AST node: %p", node);
- if (node->children == NULL) {
- return;
- }
+ if (node->parent != NULL) {
+ [[maybe_unused]]
+ const struct AST_Node_t* child = AST_detach_child(node->parent, node);
+ assert(child == node);
+ }
- if (node->parent != NULL) {
- const struct AST_Node_t* child = AST_detach_child(node->parent, node);
- assert(child == node);
- }
+ if (node->children != NULL) {
+ for (size_t i = 0; i < node->child_count; i++) {
+ // prevent detach of children node
+ node->children[i]->parent = NULL;
+ AST_delete_node(node->children[i]);
+ }
+ mem_free(node->children);
+ }
- for (size_t i = 0; i < node->child_count; i++) {
- // prevent detach of children node
- node->children[i]->parent = NULL;
- AST_delete_node(node->children[i]);
- }
-
- free(node->children);
- free(node);
+ mem_free(node);
}
static void AST_visit_nodes_recurse2(struct AST_Node_t *root,
- void (*for_each)(struct AST_Node_t *node,
- size_t depth),
- const size_t depth) {
- DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
+ void (*for_each)(struct AST_Node_t *node,
+ size_t depth),
+ const size_t depth) {
+ DEBUG("Recursive visit of %p at %d with %p", root, depth, for_each);
- assert(root != NULL);
+ assert(root != NULL);
- (for_each)(root, depth);
+ (for_each)(root, depth);
- for (size_t i = 0; i < root->child_count; i++) {
- AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1);
- }
+ for (size_t i = 0; i < root->child_count; i++) {
+ AST_visit_nodes_recurse2(root->children[i], for_each, depth + 1);
+ }
}
void AST_visit_nodes_recurse(struct AST_Node_t *root,
void (*for_each)(struct AST_Node_t *node,
size_t depth)) {
- DEBUG("Starting recursive visit of %p with %p", root, for_each);
+ DEBUG("Starting recursive visit of %p with %p", root, for_each);
- assert(root != NULL);
- assert(for_each != NULL);
+ assert(root != NULL);
+ assert(for_each != NULL);
- 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) {
- DEBUG("Printing graphviz definition of %p", node);
+ DEBUG("Printing graphviz definition of %p", node);
- assert(stream != NULL);
- assert(node != NULL);
+ assert(stream != NULL);
+ assert(node != NULL);
- fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
+ fprintf(stream, "\tnode%p [label=\"%s\"]\n", (void*) node, AST_node_to_string(node));
- if (node->children == NULL) {
- return;
- }
+ if (node->children == NULL) {
+ return;
+ }
- for (size_t i = 0; i < node->child_count; i++) {
- AST_fprint_graphviz_node_definition(stream, node->children[i]);
- }
+ for (size_t i = 0; i < node->child_count; i++) {
+ AST_fprint_graphviz_node_definition(stream, node->children[i]);
+ }
}
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(node != NULL);
+ assert(stream != NULL);
+ assert(node != NULL);
- if (node->children == NULL) {
- return;
- }
+ if (node->children == NULL) {
+ return;
+ }
- for (size_t i = 0; i < node->child_count; i++) {
- fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]);
- AST_fprint_graphviz_node_connection(stream, node->children[i]);
- }
+ for (size_t i = 0; i < node->child_count; i++) {
+ fprintf(stream, "\tnode%p -- node%p\n", (void*) node, (void*) node->children[i]);
+ AST_fprint_graphviz_node_connection(stream, node->children[i]);
+ }
}
void AST_fprint_graphviz(FILE* stream, const struct AST_Node_t* root) {
- DEBUG("Starting print of graphviz graph of %p", root);
+ DEBUG("Starting print of graphviz graph of %p", root);
- assert(stream != NULL);
- assert(root != NULL);
+ assert(stream != NULL);
+ assert(root != NULL);
- fprintf(stream, "graph {\n");
+ fprintf(stream, "graph {\n");
- AST_fprint_graphviz_node_definition(stream, root);
- AST_fprint_graphviz_node_connection(stream, root);
+ AST_fprint_graphviz_node_definition(stream, root);
+ AST_fprint_graphviz_node_connection(stream, root);
- fprintf(stream, "}\n");
+ fprintf(stream, "}\n");
}
AST_NODE_PTR AST_get_node_by_kind(AST_NODE_PTR owner, enum AST_SyntaxElement_t kind) {
diff --git a/src/ast/ast.h b/src/ast/ast.h
index a7fa708..c55acb9 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -12,74 +12,74 @@
* variants of this enum.
*/
enum AST_SyntaxElement_t {
- AST_Stmt = 0,
- AST_Module,
- AST_Expr,
- // Literals
- AST_Int,
- AST_Float,
- AST_String,
- // Control flow
- AST_While,
- AST_If,
- AST_IfElse,
- AST_Else,
- AST_Condition,
- // Variable management
- AST_Decl,
- AST_Assign,
- AST_Def,
- AST_Ident,
- // Arithmetic operators
- AST_Add,
- AST_Sub,
- AST_Mul,
- AST_Div,
- // Bitwise operators
- AST_BitAnd,
- AST_BitOr,
- AST_BitXor,
- AST_BitNot,
- // Boolean operators
- AST_BoolAnd,
- AST_BoolOr,
- AST_BoolXor,
- AST_BoolNot,
- // Logical operators
- AST_Eq,
- AST_Greater,
- AST_Less,
- // Casts
- AST_Typecast, // type cast
- AST_Transmute, // reinterpret cast
- AST_Call, // function call
- AST_Macro, // builtin functions: lineno(), filename(), ...
- // Defintions
- AST_Typedef,
- AST_Box,
- AST_Fun,
- AST_Import,
- // amount of variants
- // in this enums
- AST_List,
- AST_ExprList,
- AST_ArgList,
- AST_ParamList,
- AST_StmtList,
- AST_IdentList,
- AST_Storage,
- AST_Type,
- AST_Typekind,
- AST_Sign,
- AST_Scale,
- AST_Negate,
- AST_Parameter,
- AST_Qualifyier,
- AST_ParamDecl,
- AST_AddressOf,
- AST_Dereference,
- AST_Reference,
- AST_ELEMENT_COUNT
+ AST_Stmt = 0,
+ AST_Module,
+ AST_Expr,
+ // Literals
+ AST_Int,
+ AST_Float,
+ AST_String,
+ // Control flow
+ AST_While,
+ AST_If,
+ AST_IfElse,
+ AST_Else,
+ AST_Condition,
+ // Variable management
+ AST_Decl,
+ AST_Assign,
+ AST_Def,
+ AST_Ident,
+ // Arithmetic operators
+ AST_Add,
+ AST_Sub,
+ AST_Mul,
+ AST_Div,
+ // Bitwise operators
+ AST_BitAnd,
+ AST_BitOr,
+ AST_BitXor,
+ AST_BitNot,
+ // Boolean operators
+ AST_BoolAnd,
+ AST_BoolOr,
+ AST_BoolXor,
+ AST_BoolNot,
+ // Logical operators
+ AST_Eq,
+ AST_Greater,
+ AST_Less,
+ // Casts
+ AST_Typecast, // type cast
+ AST_Transmute, // reinterpret cast
+ AST_Call, // function call
+ AST_Macro, // builtin functions: lineno(), filename(), ...
+ // Defintions
+ AST_Typedef,
+ AST_Box,
+ AST_Fun,
+ AST_Import,
+ // amount of variants
+ // in this enums
+ AST_List,
+ AST_ExprList,
+ AST_ArgList,
+ AST_ParamList,
+ AST_StmtList,
+ AST_IdentList,
+ AST_Storage,
+ AST_Type,
+ AST_Typekind,
+ AST_Sign,
+ AST_Scale,
+ AST_Negate,
+ AST_Parameter,
+ AST_Qualifyier,
+ AST_ParamDecl,
+ AST_AddressOf,
+ AST_Dereference,
+ AST_Reference,
+ AST_ELEMENT_COUNT
};
/**
@@ -90,21 +90,21 @@ enum AST_SyntaxElement_t {
* - value: A string representing an optional value. Can be a integer literal for kind AST_int
*/
struct AST_Node_t {
- // parent node that owns this node
- struct AST_Node_t *parent;
+ // parent node that owns this node
+ struct AST_Node_t *parent;
- // type of AST node: if, declaration, ...
- enum AST_SyntaxElement_t kind;
- // optional value: integer literal, string literal, ...
- const char* value;
+ // type of AST node: if, declaration, ...
+ enum AST_SyntaxElement_t kind;
+ // optional value: integer literal, string literal, ...
+ const char* value;
- TokenLocation location;
+ TokenLocation location;
- // number of child nodes ownd by this node
- // length of children array
- size_t child_count;
- // variable amount of child nodes
- struct AST_Node_t **children;
+ // number of child nodes ownd by this node
+ // length of children array
+ size_t child_count;
+ // variable amount of child nodes
+ struct AST_Node_t **children;
};
/**
diff --git a/src/cfg/opt.c b/src/cfg/opt.c
index 2ef1856..05551ba 100644
--- a/src/cfg/opt.c
+++ b/src/cfg/opt.c
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
static GHashTable* args = NULL;
@@ -17,8 +18,8 @@ static void clean(void) {
g_hash_table_iter_init(&iter, args);
while (g_hash_table_iter_next(&iter, &key, &value)) {
- free(value);
- free(key);
+ mem_free(value);
+ mem_free(key);
}
g_hash_table_destroy(args);
@@ -30,9 +31,9 @@ void parse_options(int argc, char* argv[]) {
atexit(clean);
for (int i = 0; i < argc; i++) {
- Option* option = malloc(sizeof(Option));
+ Option* option = mem_alloc(MemoryNamespaceOpt, sizeof(Option));
option->is_opt = g_str_has_prefix(argv[i], "--");
- option->string = strdup(argv[i] + (option->is_opt ? 2 : 0));
+ option->string = mem_strdup(MemoryNamespaceOpt, argv[i] + (option->is_opt ? 2 : 0));
option->index = i;
option->value = NULL;
@@ -91,15 +92,15 @@ GArray* get_non_options_after(const char* command) {
TargetConfig* default_target_config() {
DEBUG("generating default target config...");
- TargetConfig* config = malloc(sizeof(TargetConfig));
+ TargetConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(TargetConfig));
- config->name = strdup("out");
+ config->name = mem_strdup(MemoryNamespaceOpt, "out");
config->print_ast = false;
config->print_asm = false;
config->print_ir = false;
config->mode = Application;
- config->archive_directory = strdup("archive");
- config->output_directory = strdup("bin");
+ config->archive_directory = mem_strdup(MemoryNamespaceOpt, "archive");
+ config->output_directory = mem_strdup(MemoryNamespaceOpt, "bin");
config->optimization_level = 1;
config->root_module = NULL;
config->link_search_paths = g_array_new(FALSE, FALSE, sizeof(char*));
@@ -142,7 +143,7 @@ TargetConfig* default_target_config_from_args() {
const Option* opt = get_option("output");
if (opt->value != NULL) {
- config->name = strdup(opt->value);
+ config->name = mem_strdup(MemoryNamespaceOpt, (char*) opt->value);
}
}
@@ -186,7 +187,7 @@ TargetConfig* default_target_config_from_args() {
print_message(Warning, "Got more than one file to compile, using first, ignoring others.");
}
- config->root_module = strdup( ((char**) files->data) [0]);
+ config->root_module = mem_strdup(MemoryNamespaceOpt, ((char**) files->data) [0]);
g_array_free(files, TRUE);
}
@@ -210,12 +211,14 @@ void print_help(void) {
" --output=name name of output files without extension",
" --link-paths=[paths,] set a list of directories to for libraries in",
"Options:",
- " --verbose print logs with level information or higher",
- " --debug print debug logs (if not disabled at compile time)",
- " --version print the version",
- " --list-targets print a list of all available targets supported",
- " --help print this help dialog",
- " --color-always always colorize output"
+ " --verbose print logs with level information or higher",
+ " --debug print debug logs (if not disabled at compile time)",
+ " --version print the version",
+ " --list-targets print a list of all available targets supported",
+ " --help print this help dialog",
+ " --color-always always colorize output",
+ " --version print the version",
+ " --print-memory-stats print statistics of the garbage collector"
};
for (unsigned int i = 0; i < sizeof(lines) / sizeof(const char *); i++) {
@@ -395,16 +398,16 @@ int load_project_config(ProjectConfig *config) {
void delete_target_config(TargetConfig* config) {
if (config->root_module != NULL) {
- free(config->root_module);
+ mem_free(config->root_module);
}
if (config->archive_directory != NULL) {
- free(config->archive_directory);
+ mem_free(config->archive_directory);
}
if (config->name != NULL) {
- free(config->name);
+ mem_free(config->name);
}
if (config->output_directory != NULL) {
- free(config->output_directory);
+ mem_free(config->output_directory);
}
if (config->link_search_paths) {
for (guint i = 0; i < config->link_search_paths->len; i++) {
@@ -412,21 +415,21 @@ void delete_target_config(TargetConfig* config) {
}
g_array_free(config->link_search_paths, TRUE);
}
- free(config);
+ mem_free(config);
}
void delete_project_config(ProjectConfig* config) {
if (config->name != NULL) {
- free(config->name);
+ mem_free(config->name);
}
if (config->authors != NULL) {
g_array_free(config->authors, TRUE);
}
if (config->desc != NULL) {
- free(config->desc);
+ mem_free(config->desc);
}
if (config->license != NULL) {
- free(config->license);
+ mem_free(config->license);
}
if (config->targets != NULL) {
GHashTableIter iter;
@@ -442,11 +445,11 @@ void delete_project_config(ProjectConfig* config) {
g_hash_table_destroy(config->targets);
}
- free(config);
+ mem_free_from(MemoryNamespaceOpt, config);
}
ProjectConfig* default_project_config() {
- ProjectConfig* config = malloc(sizeof(ProjectConfig));
+ ProjectConfig* config = mem_alloc(MemoryNamespaceOpt, sizeof(ProjectConfig));
config->authors = NULL;
config->name = NULL;
diff --git a/src/compiler.c b/src/compiler.c
index ec84382..7e5b9e6 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#define GRAPHVIZ_FILE_EXTENSION "gv"
@@ -187,6 +188,9 @@ static void build_target(ModuleFileStack *unit, const TargetConfig *target) {
AST_delete_node(ast);
+ mem_purge_namespace(MemoryNamespaceLex);
+ mem_purge_namespace(MemoryNamespaceAst);
+
print_file_statistics(file);
}
diff --git a/src/io/files.c b/src/io/files.c
index 4fc4f14..ad71281 100644
--- a/src/io/files.c
+++ b/src/io/files.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#ifdef __unix__
@@ -13,9 +14,15 @@
#define MAX_PATH_BYTES PATH_MAX
+#define min(a, b) ((a) > (b) ? (b) : (a))
+
#elif defined(_WIN32) || defined(WIN32)
#include
+// for _fullpath
+#include
+// for _mkdir
+#include
#define MAX_PATH_BYTES _MAX_PATH
@@ -65,10 +72,6 @@ void delete_files(ModuleFileStack *stack) {
// seeking the current line in print_diagnostic()
#define SEEK_BUF_BYTES 256
-static inline unsigned long int min(unsigned long int a, unsigned long int b) {
- return a > b ? b : a;
-}
-
// behaves like fgets except that it has defined behavior when n == 1
static void custom_fgets(char *buffer, size_t n, FILE *stream) {
if (n == 1) {
@@ -120,17 +123,17 @@ void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, c
printf("%s%s:%ld:%s %s%s:%s %s\n", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET,
message);
- free((void *) absolute_path);
+ mem_free((void *) absolute_path);
- const size_t lines = location->line_end - location->line_start + 1;
+ const unsigned long int lines = location->line_end - location->line_start + 1;
- for (size_t l = 0; l < lines; l++) {
+ for (unsigned long int l = 0; l < lines; l++) {
printf(" %4ld | ", location->line_start + l);
- size_t chars = 0;
+ unsigned long int chars = 0;
// print line before token group start
- size_t limit = min(location->col_start, SEEK_BUF_BYTES);
+ unsigned long int limit = min(location->col_start, SEEK_BUF_BYTES);
while (limit > 1) {
custom_fgets(buffer, (int) limit, file->handle);
chars += printf("%s", buffer);
@@ -168,13 +171,13 @@ void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, c
}
printf(" | ");
- for (size_t i = 1; i < location->col_start; i++) {
+ for (unsigned long int i = 1; i < location->col_start; i++) {
printf(" ");
}
printf("%s", accent_color);
printf("^");
- for (size_t 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("~");
}
@@ -298,7 +301,7 @@ int create_directory(const char *path) {
}
const char *get_last_error() {
- return strdup(strerror(errno));
+ return mem_strdup(MemoryNamespaceIo, strerror(errno));
}
const char *get_absolute_path(const char *path) {
diff --git a/src/io/files.h b/src/io/files.h
index e65b9e1..7569361 100644
--- a/src/io/files.h
+++ b/src/io/files.h
@@ -15,9 +15,9 @@
#endif
typedef struct FileDiagnosticStatistics_t {
- size_t error_count;
- size_t warning_count;
- size_t info_count;
+ unsigned long int error_count;
+ unsigned long int warning_count;
+ unsigned long int info_count;
} FileDiagnosticStatistics;
typedef struct ModuleFile_t {
diff --git a/src/lex/lexer.l b/src/lex/lexer.l
index cb507f6..4b1f9ce 100644
--- a/src/lex/lexer.l
+++ b/src/lex/lexer.l
@@ -3,6 +3,7 @@
#include
#include
#include
+ #include
int yyLineNumber = 1;
@@ -89,20 +90,20 @@
"lineno" {DEBUG("\"%s\" tokenized with \'FunLineno\'", yytext); return(FunLineno);};
"extsupport" {DEBUG("\"%s\" tokenized with \'FunExtsupport\'", yytext); return(FunExtsupport);};
-[0-9]+ {DEBUG("\"%s\" tokenized with \'ValInt\'", yytext); yylval.string = strdup(yytext); return(ValInt); };
-[0-9]*\.[0-9]+ {DEBUG("\"%s\" tokenized with \'ValFloat\'", yytext); yylval.string = strdup(yytext); return(ValFloat);};
-[a-zA-Z_0-9]+ {DEBUG("\"%s\" tokenized with \'Ident\'", yytext); yylval.string = strdup(yytext); return(Ident); };
+[0-9]+ {DEBUG("\"%s\" tokenized with \'ValInt\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValInt); };
+[0-9]*\.[0-9]+ {DEBUG("\"%s\" tokenized with \'ValFloat\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValFloat);};
+[a-zA-Z_0-9]+ {DEBUG("\"%s\" tokenized with \'Ident\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(Ident); };
\"([^\"\n])*\" {
yytext = yytext +1;
yytext[yyleng - 2] = 0;
- DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = strdup(yytext); return(ValStr);};
+ DEBUG("\"%s\" tokenized with \'ValStr\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValStr);};
\"\"\"[^\"]*\"\"\" {
yytext = yytext +3;
yytext[yyleng - 4] = 0;
- DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = strdup(yytext); return(ValMultistr);};
+ DEBUG("\"%s\" tokenized with \'ValMultistr\'", yytext); yylval.string = mem_strdup(MemoryNamespaceLex, yytext); return(ValMultistr);};
[ \r\t] { /* ignore whitespace */ };
. { return yytext[0]; /* passthrough unknown token, let parser handle the error */ };
%%
diff --git a/src/lex/util.c b/src/lex/util.c
index 81f2855..83966da 100644
--- a/src/lex/util.c
+++ b/src/lex/util.c
@@ -2,6 +2,8 @@
#include
#include
#include
+#include
+#include
// implementation based on:
// https://github.com/sunxfancy/flex-bison-examples/blob/master/error-handling/ccalc.c
@@ -16,13 +18,8 @@ static int nTokenStart = 0;
static int nTokenLength = 0;
static int nTokenNextStart = 0;
-static void lex_deinit(void) {
- free(buffer);
-}
-
void lex_init(void) {
- buffer = malloc(MAX_READ_BUFFER_SIZE);
- atexit(lex_deinit);
+ buffer = mem_alloc(MemoryNamespaceStatic, MAX_READ_BUFFER_SIZE);
}
void lex_reset(void) {
diff --git a/src/main.c b/src/main.c
index b69b613..e6d9a5d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
/**
* @brief Log a debug message to inform about beginning exit procedures
@@ -18,6 +19,8 @@ void notify_exit(void) { DEBUG("Exiting gemstone..."); }
*
*/
void setup(int argc, char *argv[]) {
+ mem_init();
+
// setup preample
parse_options(argc, argv);
@@ -63,5 +66,9 @@ int main(int argc, char *argv[]) {
run_compiler();
+ if (is_option_set("print-memory-stats")) {
+ print_memory_statistics();
+ }
+
return 0;
}
diff --git a/src/mem/cache.c b/src/mem/cache.c
new file mode 100644
index 0000000..57779c2
--- /dev/null
+++ b/src/mem/cache.c
@@ -0,0 +1,271 @@
+//
+// Created by servostar on 6/5/24.
+//
+
+#include
+#include
+#include
+#include
+#include
+
+static GHashTable* namespaces = NULL;
+
+typedef struct MemoryNamespaceStatistic_t {
+ size_t bytes_allocated;
+ size_t allocation_count;
+ size_t reallocation_count;
+ size_t manual_free_count;
+ size_t faulty_reallocations;
+ size_t faulty_allocations;
+ size_t purged_free_count;
+} MemoryNamespaceStatistic;
+
+typedef struct MemoryNamespace_t {
+ MemoryNamespaceStatistic statistic;
+ GArray* blocks;
+} MemoryNamespace;
+
+typedef MemoryNamespace* MemoryNamespaceRef;
+
+static void namespace_statistics_print(MemoryNamespaceStatistic* memoryNamespaceStatistic, char* name) {
+ printf("Memory namespace statistics: `%s`\n", name);
+ printf("------------------------------\n");
+ printf(" allocated bytes: %ld\n", memoryNamespaceStatistic->bytes_allocated);
+ printf(" allocations: %ld\n", memoryNamespaceStatistic->allocation_count);
+ printf(" reallocations: %ld\n", memoryNamespaceStatistic->reallocation_count);
+ printf(" frees: %ld\n", memoryNamespaceStatistic->manual_free_count);
+ printf(" faulty allocations: %ld\n", memoryNamespaceStatistic->faulty_allocations);
+ printf(" faulty reallocations: %ld\n", memoryNamespaceStatistic->faulty_reallocations);
+ printf(" purged allocations: %ld\n", memoryNamespaceStatistic->purged_free_count);
+ printf("\n");
+}
+
+static void* namespace_malloc(MemoryNamespaceRef memoryNamespace, size_t size) {
+ assert(memoryNamespace != NULL);
+ assert(size != 0);
+
+ void* block = malloc(size);
+
+ if (block == NULL) {
+ memoryNamespace->statistic.faulty_allocations ++;
+ } else {
+ g_array_append_val(memoryNamespace->blocks, block);
+
+ memoryNamespace->statistic.allocation_count ++;
+ memoryNamespace->statistic.bytes_allocated += size;
+ }
+
+ return block;
+}
+
+static gboolean namespace_free(MemoryNamespaceRef memoryNamespace, void* block) {
+ for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
+ void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
+
+ if (current_block == block) {
+ assert(block != NULL);
+
+ free(block);
+ g_array_remove_index(memoryNamespace->blocks, i);
+
+ memoryNamespace->statistic.manual_free_count++;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void* namespace_realloc(MemoryNamespaceRef memoryNamespace, void* block, size_t size) {
+ void* reallocated_block = NULL;
+
+ for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
+ void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
+
+ if (current_block == block) {
+ reallocated_block = realloc(block, size);
+
+ if (reallocated_block != NULL) {
+ g_array_index(memoryNamespace->blocks, void*, i) = reallocated_block;
+ memoryNamespace->statistic.bytes_allocated += size;
+ memoryNamespace->statistic.reallocation_count ++;
+ } else {
+ memoryNamespace->statistic.faulty_reallocations++;
+ }
+
+ break;
+ }
+ }
+
+ return reallocated_block;
+}
+
+static void namespace_delete(MemoryNamespaceRef memoryNamespace) {
+ g_array_free(memoryNamespace->blocks, TRUE);
+ free(memoryNamespace);
+}
+
+static void namespace_purge(MemoryNamespaceRef memoryNamespace) {
+
+ for (guint i = 0; i < memoryNamespace->blocks->len; i++) {
+ void* current_block = g_array_index(memoryNamespace->blocks, void*, i);
+
+ free(current_block);
+
+ memoryNamespace->statistic.purged_free_count ++;
+ }
+
+ g_array_remove_range(memoryNamespace->blocks, 0, memoryNamespace->blocks->len);
+}
+
+static MemoryNamespaceRef namespace_new() {
+ MemoryNamespaceRef memoryNamespace = malloc(sizeof(MemoryNamespace));
+
+ memoryNamespace->blocks = g_array_new(FALSE, FALSE, sizeof(void*));
+ memoryNamespace->statistic.bytes_allocated = 0;
+ memoryNamespace->statistic.allocation_count = 0;
+ memoryNamespace->statistic.manual_free_count = 0;
+ memoryNamespace->statistic.faulty_reallocations = 0;
+ memoryNamespace->statistic.faulty_allocations = 0;
+ memoryNamespace->statistic.purged_free_count = 0;
+ memoryNamespace->statistic.reallocation_count = 0;
+
+ return memoryNamespace;
+}
+
+static void cleanup() {
+ if (namespaces == NULL) {
+ printf("==> Memory cache was unused <==\n");
+ return;
+ }
+
+ GHashTableIter iter;
+ char* name = NULL;
+ MemoryNamespaceRef memoryNamespace = NULL;
+
+ g_hash_table_iter_init(&iter, namespaces);
+
+ while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) {
+ assert(name != NULL);
+ assert(memoryNamespace != NULL);
+
+ namespace_purge(memoryNamespace);
+ namespace_delete(memoryNamespace);
+ }
+}
+
+void mem_init() {
+ atexit(cleanup);
+}
+
+static MemoryNamespaceRef check_namespace(MemoryNamespaceName name) {
+ if (namespaces == NULL) {
+ namespaces = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if (g_hash_table_contains(namespaces, name)) {
+
+ return g_hash_table_lookup(namespaces, name);
+
+ } else {
+ MemoryNamespaceRef namespace = namespace_new();
+
+ g_hash_table_insert(namespaces, name, namespace);
+
+ return namespace;
+ }
+}
+
+void *mem_alloc(MemoryNamespaceName name, size_t size) {
+ MemoryNamespaceRef cache = check_namespace(name);
+
+ if (cache == NULL) {
+ PANIC("memory namespace not created");
+ }
+
+ return namespace_malloc(cache, size);
+}
+
+void *mem_realloc(MemoryNamespaceName name, void *ptr, size_t size) {
+ MemoryNamespaceRef cache = check_namespace(name);
+
+ if (cache == NULL) {
+ PANIC("memory namespace not created");
+ }
+
+ return namespace_realloc(cache, ptr, size);
+}
+
+void mem_free_from(MemoryNamespaceName name, void *memory) {
+ MemoryNamespaceRef cache = check_namespace(name);
+
+ namespace_free(cache, memory);
+}
+
+void mem_free(void* memory) {
+ GHashTableIter iter;
+ char* name;
+ MemoryNamespaceRef memoryNamespace;
+
+ g_hash_table_iter_init(&iter, namespaces);
+ while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) {
+
+ if (namespace_free(memoryNamespace, memory)) {
+ break;
+ }
+ }
+}
+
+void mem_purge_namespace(MemoryNamespaceName name) {
+ if (g_hash_table_contains(namespaces, name)) {
+ MemoryNamespaceRef cache = g_hash_table_lookup(namespaces, name);
+
+ namespace_purge(cache);
+ } else {
+ PANIC("purging invalid namespace: %s", name);
+ }
+}
+
+char* mem_strdup(MemoryNamespaceName name, char* string) {
+ return mem_clone(name, string, strlen(string) + 1);
+}
+
+void* mem_clone(MemoryNamespaceName name, void* data, size_t size) {
+ void *clone = mem_alloc(name, size);
+
+ memcpy(clone, data, size);
+
+ return clone;
+}
+
+void print_memory_statistics() {
+ GHashTableIter iter;
+ char* name;
+ MemoryNamespaceRef memoryNamespace;
+
+ MemoryNamespaceStatistic total;
+ total.bytes_allocated = 0;
+ total.faulty_reallocations = 0;
+ total.faulty_allocations = 0;
+ total.manual_free_count = 0;
+ total.allocation_count = 0;
+ total.purged_free_count = 0;
+ total.reallocation_count = 0;
+
+ g_hash_table_iter_init(&iter, namespaces);
+ while (g_hash_table_iter_next(&iter, (gpointer) &name, (gpointer) &memoryNamespace)) {
+
+ namespace_statistics_print(&memoryNamespace->statistic, name);
+
+ total.bytes_allocated += memoryNamespace->statistic.bytes_allocated;
+ total.faulty_reallocations += memoryNamespace->statistic.faulty_reallocations;
+ total.faulty_allocations += memoryNamespace->statistic.faulty_allocations;
+ total.manual_free_count += memoryNamespace->statistic.manual_free_count;
+ total.allocation_count += memoryNamespace->statistic.allocation_count;
+ total.purged_free_count += memoryNamespace->statistic.purged_free_count;
+ total.reallocation_count += memoryNamespace->statistic.reallocation_count;
+ }
+
+ namespace_statistics_print(&total, "summary");
+
+ printf("Note: untracked are memory allocations from external libraries.\n");
+}
diff --git a/src/mem/cache.h b/src/mem/cache.h
new file mode 100644
index 0000000..d6ac067
--- /dev/null
+++ b/src/mem/cache.h
@@ -0,0 +1,89 @@
+//
+// Created by servostar on 6/5/24.
+//
+
+#ifndef GEMSTONE_CACHE_H
+#define GEMSTONE_CACHE_H
+
+#include
+#include
+
+typedef char* MemoryNamespaceName;
+
+#define MemoryNamespaceAst "AST"
+#define MemoryNamespaceLex "Lexer"
+#define MemoryNamespaceLog "Logging"
+#define MemoryNamespaceOpt "Options"
+#define MemoryNamespaceSet "SET"
+#define MemoryNamespaceLlvm "LLVM"
+#define MemoryNamespaceIo "I/O"
+#define MemoryNamespaceStatic "Static"
+
+/**
+ * @brief Initialize the garbage collector.
+ * Must be done to ensure cleanup of memory.
+ */
+void mem_init();
+
+/**
+ * @brief Allocate a block of memory in the specified namespace.
+ * @attention Must only be freed with mem_free() or mem_free_from()
+ * @param name
+ * @param size
+ * @return pointer to the block
+ */
+void* mem_alloc(MemoryNamespaceName name, size_t size);
+
+/**
+ * @brief Reallocate a block of memory in the specified namespace.
+ * @attention Must only be freed with mem_free() or mem_free_from()
+ * @param name
+ * @param size
+ * @return pointer to the block
+ */
+void* mem_realloc(MemoryNamespaceName name, void *ptr, size_t size);
+
+/**
+ * @brief Free a block of memory from a specified namespace.
+ * Invoking multiple times on the same pointer will do nothing.
+ * @param name
+ * @param memory
+ */
+void mem_free_from(MemoryNamespaceName name, void* memory);
+
+/**
+ * @brief Free a block of memory.
+ * Invoking multiple times on the same pointer will do nothing.
+ * @attention In case the namespace of the block is known, consider using mem_free_from()
+ * to avoid unnecessary overhead.
+ * @param name
+ * @param memory
+ */
+void mem_free(void* memory);
+
+/**
+ * @brief Delete all memory from the given namespace.
+ * @param name
+ */
+void mem_purge_namespace(MemoryNamespaceName name);
+
+/**
+ * @brief Duplicate the given string with memory in the given namespace.
+ * @param name
+ * @param string
+ * @return
+ */
+char* mem_strdup(MemoryNamespaceName name, char* string);
+
+/**
+ * @brief Duplicate the given block of data with memory in the given namespace.
+ * @param name
+ * @param data
+ * @param size
+ * @return
+ */
+void* mem_clone(MemoryNamespaceName name, void* data, size_t size);
+
+void print_memory_statistics();
+
+#endif //GEMSTONE_CACHE_H
diff --git a/src/sys/col.c b/src/sys/col.c
index 2e0cabb..a669b54 100644
--- a/src/sys/col.c
+++ b/src/sys/col.c
@@ -76,8 +76,7 @@ int stdout_supports_ansi_esc() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (!GetConsoleMode(hConsole, &mode)) {
- ERROR("failed to get console mode");
- return ANSI_ENABLED;
+ return ASNI_DISABLED;
}
if ((mode & ENABLE_VIRTUAL_TERMINAL_INPUT) |
diff --git a/src/sys/log.c b/src/sys/log.c
index 7dcf94e..ca00b73 100644
--- a/src/sys/log.c
+++ b/src/sys/log.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
static struct Logger_t {
FILE** streams;
@@ -39,7 +40,7 @@ void log_register_stream(FILE* restrict stream)
if (GlobalLogger.stream_count == 0)
{
- GlobalLogger.streams = (FILE**) malloc(sizeof(FILE*));
+ GlobalLogger.streams = (FILE**) mem_alloc(MemoryNamespaceLog, sizeof(FILE*));
GlobalLogger.stream_count = 1;
if (GlobalLogger.streams == NULL)
@@ -51,7 +52,7 @@ void log_register_stream(FILE* restrict stream)
{
GlobalLogger.stream_count++;
size_t bytes = GlobalLogger.stream_count * sizeof(FILE*);
- GlobalLogger.streams = (FILE**) realloc(GlobalLogger.streams, bytes);
+ GlobalLogger.streams = (FILE**) mem_realloc(MemoryNamespaceLog, GlobalLogger.streams, bytes);
if (GlobalLogger.streams == NULL)
{
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index ca538f2..3ce0770 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -11,4 +11,5 @@ add_subdirectory(input_file)
add_subdirectory(ast)
add_subdirectory(glib)
add_subdirectory(llvm)
-add_subdirectory(project)
\ No newline at end of file
+add_subdirectory(project)
+add_subdirectory(cache)
diff --git a/tests/ast/CMakeLists.txt b/tests/ast/CMakeLists.txt
index 5bd19b6..6e20067 100644
--- a/tests/ast/CMakeLists.txt
+++ b/tests/ast/CMakeLists.txt
@@ -26,6 +26,7 @@ add_executable(ast_build_tree
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
${PROJECT_SOURCE_DIR}/dep/tomlc99/toml.c
build_tree.c)
set_target_properties(ast_build_tree
@@ -47,6 +48,7 @@ add_executable(ast_print_node
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
${PROJECT_SOURCE_DIR}/dep/tomlc99/toml.c
print_node.c)
set_target_properties(ast_print_node
@@ -68,6 +70,7 @@ add_executable(ast_graphviz
${PROJECT_SOURCE_DIR}/src/io/files.c
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
${PROJECT_SOURCE_DIR}/dep/tomlc99/toml.c
print_graphviz.c)
set_target_properties(ast_graphviz
diff --git a/tests/ast/build_tree.c b/tests/ast/build_tree.c
index 2d2459b..ddc3b66 100644
--- a/tests/ast/build_tree.c
+++ b/tests/ast/build_tree.c
@@ -4,6 +4,7 @@
#include
#include
+#include
void generate_statement(const AST_NODE_PTR stmt) {
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
@@ -29,6 +30,7 @@ void generate_branch(const AST_NODE_PTR stmt) {
}
int main(void) {
+ mem_init();
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
diff --git a/tests/ast/gen_graph.c b/tests/ast/gen_graph.c
index c4e2f92..53ef3cc 100644
--- a/tests/ast/gen_graph.c
+++ b/tests/ast/gen_graph.c
@@ -4,8 +4,10 @@
#include
#include
+#include
int main(void) {
+ mem_init();
struct AST_Node_t* node = AST_new_node(empty_location(), AST_If, NULL);
diff --git a/tests/ast/print_graphviz.c b/tests/ast/print_graphviz.c
index c0f69af..888a29d 100644
--- a/tests/ast/print_graphviz.c
+++ b/tests/ast/print_graphviz.c
@@ -4,6 +4,7 @@
#include
#include
+#include
void generate_statement(const AST_NODE_PTR stmt) {
const AST_NODE_PTR add = AST_new_node(empty_location(), AST_Add, NULL);
@@ -29,7 +30,7 @@ void generate_branch(const AST_NODE_PTR stmt) {
}
int main(void) {
-
+ mem_init();
AST_init();
const AST_NODE_PTR root = AST_new_node(empty_location(), AST_Stmt, NULL);
diff --git a/tests/ast/print_node.c b/tests/ast/print_node.c
index 47db685..b76285a 100644
--- a/tests/ast/print_node.c
+++ b/tests/ast/print_node.c
@@ -3,9 +3,10 @@
//
#include
+#include
int main(void) {
-
+ mem_init();
AST_init();
const AST_NODE_PTR node = AST_new_node(empty_location(), 0, "value");
diff --git a/tests/cache/CMakeLists.txt b/tests/cache/CMakeLists.txt
new file mode 100644
index 0000000..586cef3
--- /dev/null
+++ b/tests/cache/CMakeLists.txt
@@ -0,0 +1,38 @@
+include(CTest)
+
+include_directories(${PROJECT_SOURCE_DIR}/src)
+
+# ------------------------------------------------ #
+# Setup Glib 2.0 #
+# ------------------------------------------------ #
+
+find_package(PkgConfig REQUIRED)
+pkg_search_module(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
+include_directories(PRIVATE ${GLIB_INCLUDE_DIRS})
+
+# ------------------------------------------------ #
+# Setup TOML-C99 #
+# ------------------------------------------------ #
+
+include_directories(${PROJECT_SOURCE_DIR}/dep/tomlc99)
+
+# ------------------------------------------------------- #
+# CTEST 1
+# test the memory cache
+
+add_executable(cache
+ ${PROJECT_SOURCE_DIR}/src/sys/log.c
+ ${PROJECT_SOURCE_DIR}/src/sys/col.c
+ ${PROJECT_SOURCE_DIR}/src/cfg/opt.c
+ ${PROJECT_SOURCE_DIR}/src/io/files.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
+ cache_test.c)
+set_target_properties(cache
+ PROPERTIES
+ OUTPUT_NAME "cache"
+ RUNTIME_OUTPUT_DIRECTORY ${GEMSTONE_BINARY_DIR}/tests/cache)
+target_link_libraries(cache PkgConfig::GLIB)
+target_link_libraries(cache tomlc99)
+add_test(NAME cache
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
+ COMMAND ${GEMSTONE_BINARY_DIR}/tests/cache/cache)
diff --git a/tests/cache/cache_test.c b/tests/cache/cache_test.c
new file mode 100644
index 0000000..c49094a
--- /dev/null
+++ b/tests/cache/cache_test.c
@@ -0,0 +1,28 @@
+//
+// Created by servostar on 6/5/24.
+//
+
+#include
+#include
+#include
+#include
+
+int main(int argc, char* argv[]) {
+ mem_init();
+ parse_options(argc, argv);
+ log_init();
+ set_log_level(LOG_LEVEL_DEBUG);
+ col_init();
+
+ for (int i = 0; i < 3; i++) {
+ void* data = mem_alloc(MemoryNamespaceAst, 457);
+ mem_realloc(MemoryNamespaceAst, data, 200);
+ mem_free(data);
+ }
+
+ mem_purge_namespace(MemoryNamespaceOpt);
+
+ print_memory_statistics();
+
+ return 0;
+}
diff --git a/tests/logging/CMakeLists.txt b/tests/logging/CMakeLists.txt
index 2bfa385..5e9cdd0 100644
--- a/tests/logging/CMakeLists.txt
+++ b/tests/logging/CMakeLists.txt
@@ -25,6 +25,7 @@ add_executable(logging_output
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
${PROJECT_SOURCE_DIR}/src/io/files.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
output.c)
set_target_properties(logging_output
PROPERTIES
@@ -45,6 +46,7 @@ add_executable(logging_panic
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
${PROJECT_SOURCE_DIR}/src/io/files.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
panic.c)
set_target_properties(logging_panic
PROPERTIES
@@ -65,6 +67,7 @@ add_executable(logging_streams
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
${PROJECT_SOURCE_DIR}/src/io/files.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
streams.c)
set_target_properties(logging_streams
PROPERTIES
@@ -85,6 +88,7 @@ add_executable(logging_level
${PROJECT_SOURCE_DIR}/src/sys/col.c
${PROJECT_SOURCE_DIR}/src/cfg/opt.c
${PROJECT_SOURCE_DIR}/src/io/files.c
+ ${PROJECT_SOURCE_DIR}/src/mem/cache.c
level.c)
set_target_properties(logging_level
PROPERTIES
diff --git a/tests/logging/level.c b/tests/logging/level.c
index ed89205..c46cf5d 100644
--- a/tests/logging/level.c
+++ b/tests/logging/level.c
@@ -5,10 +5,12 @@
#include "sys/log.h"
#include
#include
+#include
#define LOG_LEVEL LOG_LEVEL_WARNING
int main(int argc, char* argv[]) {
+ mem_init();
parse_options(argc, argv);
log_init();
set_log_level(LOG_LEVEL_DEBUG);
diff --git a/tests/logging/output.c b/tests/logging/output.c
index a6cfdb2..b64840f 100644
--- a/tests/logging/output.c
+++ b/tests/logging/output.c
@@ -5,8 +5,10 @@
#include "sys/log.h"
#include
#include
+#include
int main(int argc, char* argv[]) {
+ mem_init();
parse_options(argc, argv);
log_init();
set_log_level(LOG_LEVEL_DEBUG);
diff --git a/tests/logging/panic.c b/tests/logging/panic.c
index f64f3a1..5502dd9 100644
--- a/tests/logging/panic.c
+++ b/tests/logging/panic.c
@@ -4,8 +4,10 @@
#include "sys/log.h"
#include
+#include
int main(int argc, char* argv[]) {
+ mem_init();
parse_options(argc, argv);
log_init();
set_log_level(LOG_LEVEL_DEBUG);
diff --git a/tests/logging/streams.c b/tests/logging/streams.c
index 5dd7cc2..ded5461 100644
--- a/tests/logging/streams.c
+++ b/tests/logging/streams.c
@@ -5,6 +5,7 @@
#include "sys/log.h"
#include
#include
+#include
static FILE* file;
@@ -15,6 +16,7 @@ void close_file(void) {
}
int main(int argc, char* argv[]) {
+ mem_init();
parse_options(argc, argv);
log_init();
set_log_level(LOG_LEVEL_DEBUG);