commit 007a93168438b5b05a866687f73add369188bb9d Author: Zander Thannhauser Date: Thu Nov 28 18:36:25 2024 -0600 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0216fa --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ + +bin/ + diff --git a/avl/avl.c b/avl/avl.c new file mode 100644 index 0000000..a74dd88 --- /dev/null +++ b/avl/avl.c @@ -0,0 +1,641 @@ +/***************************************************************************** + + avl.c - Source code for the AVL-tree library. + + Copyright (C) 1998 Michael H. Buselli + Copyright (C) 2000-2002 Wessel Dankers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Augmented AVL-tree. Original by Michael H. Buselli . + + Modified by Wessel Dankers to add a bunch of bloat to + the sourcecode, change the interface and squash a few bugs. + Mail him if you find new bugs. + +*****************************************************************************/ + +#include +#include +#include +#include "avl.h" + +static void avl_rebalance(avl_tree_t *, avl_node_t *); + +#ifdef AVL_COUNT +#define NODE_COUNT(n) ((n) ? (n)->count : 0) +#define L_COUNT(n) (NODE_COUNT((n)->left)) +#define R_COUNT(n) (NODE_COUNT((n)->right)) +#define CALC_COUNT(n) (L_COUNT(n) + R_COUNT(n) + 1) +#endif + +#ifdef AVL_DEPTH +#define NODE_DEPTH(n) ((n) ? (n)->depth : 0) +#define L_DEPTH(n) (NODE_DEPTH((n)->left)) +#define R_DEPTH(n) (NODE_DEPTH((n)->right)) +#define CALC_DEPTH(n) ((L_DEPTH(n) > R_DEPTH(n) ? L_DEPTH(n) : R_DEPTH(n)) + 1) +#endif + +#ifndef AVL_DEPTH +/* Also known as ffs() (from BSD) */ +static int lg(unsigned int u) { + int r = 1; + if(!u) return 0; + if(u & 0xffff0000) { u >>= 16; r += 16; } + if(u & 0x0000ff00) { u >>= 8; r += 8; } + if(u & 0x000000f0) { u >>= 4; r += 4; } + if(u & 0x0000000c) { u >>= 2; r += 2; } + if(u & 0x00000002) r++; + return r; +} +#endif + +static int avl_check_balance(avl_node_t *avlnode) { +#ifdef AVL_DEPTH + int d; + d = R_DEPTH(avlnode) - L_DEPTH(avlnode); + return d<-1?-1:d>1?1:0; +#else +/* int d; + * d = lg(R_COUNT(avlnode)) - lg(L_COUNT(avlnode)); + * d = d<-1?-1:d>1?1:0; + */ +#ifdef AVL_COUNT + int pl, r; + + pl = lg(L_COUNT(avlnode)); + r = R_COUNT(avlnode); + + if(r>>pl+1) + return 1; + if(pl<2 || r>>pl-2) + return 0; + return -1; +#else +#error No balancing possible. +#endif +#endif +} + +#ifdef AVL_COUNT +unsigned int avl_count(const avl_tree_t *avltree) { + return NODE_COUNT(avltree->top); +} + +avl_node_t *avl_at(const avl_tree_t *avltree, unsigned int index) { + avl_node_t *avlnode; + unsigned int c; + + avlnode = avltree->top; + + while(avlnode) { + c = L_COUNT(avlnode); + + if(index < c) { + avlnode = avlnode->left; + } else if(index > c) { + avlnode = avlnode->right; + index -= c+1; + } else { + return avlnode; + } + } + return NULL; +} + +unsigned int avl_index(const avl_node_t *avlnode) { + avl_node_t *next; + unsigned int c; + + c = L_COUNT(avlnode); + + while((next = avlnode->parent)) { + if(avlnode == next->right) + c += L_COUNT(next) + 1; + avlnode = next; + } + + return c; +} +#endif + +int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode) { + avl_node_t *node; + int c; + + if (!avlnode) + avlnode = &node; + + if (!cmp) + { + cmp = avltree->cmp; + } + + node = avltree->top; + + if (!node) + return *avlnode = NULL, 0; + + for (;;) { + c = cmp(item, node->item); + + if(c < 0) { + if(node->left) + node = node->left; + else + return *avlnode = node, -1; + } else if(c > 0) { + if(node->right) + node = node->right; + else + return *avlnode = node, 1; + } else { + return *avlnode = node, 0; + } + } +} + +/* + * avl_search: + * Return a pointer to a node with the given item in the tree. + * If no such item is in the tree, then NULL is returned. + */ +avl_node_t *avl_search(const avl_tree_t *avltree, const void *item) { + avl_node_t *node; + return avl_search_closest(avltree, item, NULL, &node) ? NULL : node; +} + +avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp) { + avl_node_t *node; + return avl_search_closest(avltree, item, cmp, &node) ? NULL : node; +} + +avl_tree_t *avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) { + if(rc) { + rc->head = NULL; + rc->tail = NULL; + rc->top = NULL; + rc->cmp = cmp; + rc->freeitem = freeitem; + } + return rc; +} + +avl_tree_t *avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) { + return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem); +} + +void avl_clear_tree(avl_tree_t *avltree) { + avltree->top = avltree->head = avltree->tail = NULL; +} + +void avl_free_nodes(avl_tree_t *avltree) { + avl_node_t *node, *next; + avl_freeitem_t freeitem; + + freeitem = avltree->freeitem; + + for(node = avltree->head; node; node = next) { + next = node->next; + if(freeitem) + freeitem(node->item); + free(node); + } + + avl_clear_tree(avltree); +} + +/* + * avl_free_tree: + * Free all memory used by this tree. If freeitem is not NULL, then + * it is assumed to be a destructor for the items referenced in the avl_ + * tree, and they are deleted as well. + */ +void avl_free_tree(avl_tree_t *avltree) { + if (avltree) { + avl_free_nodes(avltree); + free(avltree); + } +} + +static void avl_clear_node(avl_node_t *newnode) { + newnode->left = newnode->right = NULL; + #ifdef AVL_COUNT + newnode->count = 1; + #endif + #ifdef AVL_DEPTH + newnode->depth = 1; + #endif +} + +avl_node_t *avl_init_node(avl_node_t *newnode, void *item) { + if(newnode) { +/* avl_clear_node(newnode); */ + newnode->item = item; + } + return newnode; +} + +avl_node_t *avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) { + avl_clear_node(newnode); + newnode->prev = newnode->next = newnode->parent = NULL; + avltree->head = avltree->tail = avltree->top = newnode; + return newnode; +} + +avl_node_t *avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { + if(!node) + return avltree->tail + ? avl_insert_after(avltree, avltree->tail, newnode) + : avl_insert_top(avltree, newnode); + + if(node->left) + return avl_insert_after(avltree, node->prev, newnode); + + avl_clear_node(newnode); + + newnode->next = node; + newnode->parent = node; + + newnode->prev = node->prev; + if(node->prev) + node->prev->next = newnode; + else + avltree->head = newnode; + node->prev = newnode; + + node->left = newnode; + avl_rebalance(avltree, node); + return newnode; +} + +avl_node_t *avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) { + if(!node) + return avltree->head + ? avl_insert_before(avltree, avltree->head, newnode) + : avl_insert_top(avltree, newnode); + + if(node->right) + return avl_insert_before(avltree, node->next, newnode); + + avl_clear_node(newnode); + + newnode->prev = node; + newnode->parent = node; + + newnode->next = node->next; + if(node->next) + node->next->prev = newnode; + else + avltree->tail = newnode; + node->next = newnode; + + node->right = newnode; + avl_rebalance(avltree, node); + return newnode; +} + +avl_node_t *avl_insert_node(avl_tree_t *avltree, avl_node_t *newnode) { + avl_node_t *node; + + if(!avltree->top) + return avl_insert_top(avltree, newnode); + + switch(avl_search_closest(avltree, newnode->item, avltree->cmp, &node)) { + case -1: + return avl_insert_before(avltree, node, newnode); + case 1: + return avl_insert_after(avltree, node, newnode); + } + + return NULL; +} + +/* + * avl_insert: + * Create a new node and insert an item there. + * Returns the new node on success or NULL if no memory could be allocated. + */ +avl_node_t *avl_insert(avl_tree_t *avltree, void *item) { + avl_node_t *newnode; + + newnode = avl_init_node(malloc(sizeof(avl_node_t)), item); + if(newnode) { + if(avl_insert_node(avltree, newnode)) + return newnode; + free(newnode); + errno = EEXIST; + } + return NULL; +} + +/* + * avl_unlink_node: + * Removes the given node. Does not delete the item at that node. + * The item of the node may be freed before calling avl_unlink_node. + * (In other words, it is not referenced by this function.) + */ +void avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) { + avl_node_t *parent; + avl_node_t **superparent; + avl_node_t *subst, *left, *right; + avl_node_t *balnode; + + if(avlnode->prev) + avlnode->prev->next = avlnode->next; + else + avltree->head = avlnode->next; + + if(avlnode->next) + avlnode->next->prev = avlnode->prev; + else + avltree->tail = avlnode->prev; + + parent = avlnode->parent; + + superparent = parent + ? avlnode == parent->left ? &parent->left : &parent->right + : &avltree->top; + + left = avlnode->left; + right = avlnode->right; + if(!left) { + *superparent = right; + if(right) + right->parent = parent; + balnode = parent; + } else if(!right) { + *superparent = left; + left->parent = parent; + balnode = parent; + } else { + subst = avlnode->prev; + if(subst == left) { + balnode = subst; + } else { + balnode = subst->parent; + balnode->right = subst->left; + if(balnode->right) + balnode->right->parent = balnode; + subst->left = left; + left->parent = subst; + } + subst->right = right; + subst->parent = parent; + right->parent = subst; + *superparent = subst; + } + + avl_rebalance(avltree, balnode); +} + +void *avl_delete_node(avl_tree_t *avltree, avl_node_t *avlnode) { + void *item = NULL; + if(avlnode) { + item = avlnode->item; + avl_unlink_node(avltree, avlnode); + if(avltree->freeitem) + avltree->freeitem(item); + free(avlnode); + } + return item; +} + +void *avl_delete(avl_tree_t *avltree, const void *item) { + return avl_delete_node(avltree, avl_search(avltree, item)); +} + +avl_node_t *avl_fixup_node(avl_tree_t *avltree, avl_node_t *newnode) { + avl_node_t *oldnode = NULL, *node; + + if(!avltree || !newnode) + return NULL; + + node = newnode->prev; + if(node) { + oldnode = node->next; + node->next = newnode; + } else { + avltree->head = newnode; + } + + node = newnode->next; + if(node) { + oldnode = node->prev; + node->prev = newnode; + } else { + avltree->tail = newnode; + } + + node = newnode->parent; + if(node) { + if(node->left == oldnode) + node->left = newnode; + else + node->right = newnode; + } else { + oldnode = avltree->top; + avltree->top = newnode; + } + + return oldnode; +} + +/* + * avl_rebalance: + * Rebalances the tree if one side becomes too heavy. This function + * assumes that both subtrees are AVL-trees with consistant data. The + * function has the additional side effect of recalculating the count of + * the tree at this node. It should be noted that at the return of this + * function, if a rebalance takes place, the top of this subtree is no + * longer going to be the same node. + */ +void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) { + avl_node_t *child; + avl_node_t *gchild; + avl_node_t *parent; + avl_node_t **superparent; + + parent = avlnode; + + while(avlnode) { + parent = avlnode->parent; + + superparent = parent + ? avlnode == parent->left ? &parent->left : &parent->right + : &avltree->top; + + switch(avl_check_balance(avlnode)) { + case -1: + child = avlnode->left; + #ifdef AVL_DEPTH + if(L_DEPTH(child) >= R_DEPTH(child)) { + #else + #ifdef AVL_COUNT + if(L_COUNT(child) >= R_COUNT(child)) { + #else + #error No balancing possible. + #endif + #endif + avlnode->left = child->right; + if(avlnode->left) + avlnode->left->parent = avlnode; + child->right = avlnode; + avlnode->parent = child; + *superparent = child; + child->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + #endif + } else { + gchild = child->right; + avlnode->left = gchild->right; + if(avlnode->left) + avlnode->left->parent = avlnode; + child->right = gchild->left; + if(child->right) + child->right->parent = child; + gchild->right = avlnode; + if(gchild->right) + gchild->right->parent = gchild; + gchild->left = child; + if(gchild->left) + gchild->left->parent = gchild; + *superparent = gchild; + gchild->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + gchild->count = CALC_COUNT(gchild); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + gchild->depth = CALC_DEPTH(gchild); + #endif + } + break; + case 1: + child = avlnode->right; + #ifdef AVL_DEPTH + if(R_DEPTH(child) >= L_DEPTH(child)) { + #else + #ifdef AVL_COUNT + if(R_COUNT(child) >= L_COUNT(child)) { + #else + #error No balancing possible. + #endif + #endif + avlnode->right = child->left; + if(avlnode->right) + avlnode->right->parent = avlnode; + child->left = avlnode; + avlnode->parent = child; + *superparent = child; + child->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + #endif + } else { + gchild = child->left; + avlnode->right = gchild->left; + if(avlnode->right) + avlnode->right->parent = avlnode; + child->left = gchild->right; + if(child->left) + child->left->parent = child; + gchild->left = avlnode; + if(gchild->left) + gchild->left->parent = gchild; + gchild->right = child; + if(gchild->right) + gchild->right->parent = gchild; + *superparent = gchild; + gchild->parent = parent; + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + child->count = CALC_COUNT(child); + gchild->count = CALC_COUNT(gchild); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + child->depth = CALC_DEPTH(child); + gchild->depth = CALC_DEPTH(gchild); + #endif + } + break; + default: + #ifdef AVL_COUNT + avlnode->count = CALC_COUNT(avlnode); + #endif + #ifdef AVL_DEPTH + avlnode->depth = CALC_DEPTH(avlnode); + #endif + } + avlnode = parent; + } +} + +void avl_foreach(avl_tree_t* tree, void (*callback)(void*)) +{ + for (avl_node_t* node = tree->head; node; node = node->next) + { + callback(node->item); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/avl/avl.h b/avl/avl.h new file mode 100644 index 0000000..851d8d3 --- /dev/null +++ b/avl/avl.h @@ -0,0 +1,208 @@ +/***************************************************************************** + + avl.h - Source code for the AVL-tree library. + + Copyright (C) 1998 Michael H. Buselli + Copyright (C) 2000-2002 Wessel Dankers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Augmented AVL-tree. Original by Michael H. Buselli . + + Modified by Wessel Dankers to add a bunch of bloat to + the sourcecode, change the interface and squash a few bugs. + Mail him if you find new bugs. + +*****************************************************************************/ + +#ifndef _AVL_H +#define _AVL_H + +/* We need either depths, counts or both (the latter being the default) */ +#if !defined(AVL_DEPTH) && !defined(AVL_COUNT) +#define AVL_DEPTH +#define AVL_COUNT +#endif + +/* User supplied function to compare two items like strcmp() does. + * For example: cmp(a,b) will return: + * -1 if a < b + * 0 if a = b + * 1 if a > b + */ +typedef int (*avl_compare_t)(const void *, const void *); + +/* User supplied function to delete an item when a node is free()d. + * If NULL, the item is not free()d. + */ +typedef void (*avl_freeitem_t)(void *); + +typedef struct avl_node_t { + struct avl_node_t *next; + struct avl_node_t *prev; + struct avl_node_t *parent; + struct avl_node_t *left; + struct avl_node_t *right; + void *item; +#ifdef AVL_COUNT + unsigned int count; +#endif +#ifdef AVL_DEPTH + int depth; +#endif +} avl_node_t; + +typedef struct avl_tree_t { + avl_node_t *head; + avl_node_t *tail; + avl_node_t *top; + avl_compare_t cmp; + avl_freeitem_t freeitem; +} avl_tree_t; + +/* Initializes a new tree for elements that will be ordered using + * the supplied strcmp()-like function. + * Returns the value of avltree (even if it's NULL). + * O(1) */ +extern avl_tree_t *avl_init_tree(avl_tree_t *avltree, avl_compare_t, avl_freeitem_t); + +/* Allocates and initializes a new tree for elements that will be + * ordered using the supplied strcmp()-like function. + * Returns NULL if memory could not be allocated. + * O(1) */ +extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_freeitem_t); + +/* Frees the entire tree efficiently. Nodes will be free()d. + * If the tree's freeitem is not NULL it will be invoked on every item. + * O(n) */ +extern void avl_free_tree(avl_tree_t *); + +/* Reinitializes the tree structure for reuse. Nothing is free()d. + * Compare and freeitem functions are left alone. + * O(1) */ +extern void avl_clear_tree(avl_tree_t *); + +/* Free()s all nodes in the tree but leaves the tree itself. + * If the tree's freeitem is not NULL it will be invoked on every item. + * O(n) */ +extern void avl_free_nodes(avl_tree_t *); + +/* Initializes memory for use as a node. Returns NULL if avlnode is NULL. + * O(1) */ +extern avl_node_t *avl_init_node(avl_node_t *avlnode, void *item); + +/* Insert an item into the tree and return the new node. + * Returns NULL and sets errno if memory for the new node could not be + * allocated or if the node is already in the tree (EEXIST). + * O(lg n) */ +extern avl_node_t *avl_insert(avl_tree_t *, void *item); + +/* Insert a node into the tree and return it. + * Returns NULL if the node is already in the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *); + +/* Insert a node in an empty tree. If avlnode is NULL, the tree will be + * cleared and ready for re-use. + * If the tree is not empty, the old nodes are left dangling. + * O(1) */ +extern avl_node_t *avl_insert_top(avl_tree_t *, avl_node_t *avlnode); + +/* Insert a node before another node. Returns the new node. + * If old is NULL, the item is appended to the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_before(avl_tree_t *, avl_node_t *old, avl_node_t *new); + +/* Insert a node after another node. Returns the new node. + * If old is NULL, the item is prepended to the tree. + * O(lg n) */ +extern avl_node_t *avl_insert_after(avl_tree_t *, avl_node_t *old, avl_node_t *new); + +/* Deletes a node from the tree. Returns immediately if the node is NULL. + * The item will not be free()d regardless of the tree's freeitem handler. + * This function comes in handy if you need to update the search key. + * O(lg n) */ +extern void avl_unlink_node(avl_tree_t *, avl_node_t *); + +/* Deletes a node from the tree. Returns immediately if the node is NULL. + * If the tree's freeitem is not NULL, it is invoked on the item. + * If it is, returns the item. + * O(lg n) */ +extern void *avl_delete_node(avl_tree_t *, avl_node_t *); + +/* Searches for an item in the tree and deletes it if found. + * If the tree's freeitem is not NULL, it is invoked on the item. + * If it is, returns the item. + * O(lg n) */ +extern void *avl_delete(avl_tree_t *, const void *item); + +/* If exactly one node is moved in memory, this will fix the pointers + * in the tree that refer to it. It must be an exact shallow copy. + * Returns the pointer to the old position. + * O(1) */ +extern avl_node_t *avl_fixup_node(avl_tree_t *, avl_node_t *new); + +/* Searches for a node with the key closest (or equal) to the given item. + * If avlnode is not NULL, *avlnode will be set to the node found or NULL + * if the tree is empty. Return values: + * -1 if the returned node is smaller + * 0 if the returned node is equal or if the tree is empty + * 1 if the returned node is greater + * O(lg n) */ +int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_compare_t cmp, avl_node_t **avlnode); + +/* Searches for the item in the tree and returns a matching node if found + * or NULL if not. + * O(lg n) */ +extern avl_node_t *avl_search(const avl_tree_t *, const void *item); + +avl_node_t *avl_search2(const avl_tree_t *avltree, const void *item, avl_compare_t cmp); + +void avl_foreach(avl_tree_t* tree, void (*callback)(void*)); + +#ifdef AVL_COUNT +/* Returns the number of nodes in the tree. + * O(1) */ +extern unsigned int avl_count(const avl_tree_t *); + +/* Searches a node by its rank in the list. Counting starts at 0. + * Returns NULL if the index exceeds the number of nodes in the tree. + * O(lg n) */ +extern avl_node_t *avl_at(const avl_tree_t *, unsigned int); + +/* Returns the rank of a node in the list. Counting starts at 0. + * O(lg n) */ +extern unsigned int avl_index(const avl_node_t *); +#endif + +#endif + + + + + + + + + + + + + + + + + + diff --git a/buildtypes/debug-dotout-valgrind.txt b/buildtypes/debug-dotout-valgrind.txt new file mode 100644 index 0000000..25b197a --- /dev/null +++ b/buildtypes/debug-dotout-valgrind.txt @@ -0,0 +1,17 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D DEBUG_BUILD +-D DOTOUT_BUILD +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/debug-dotout.txt b/buildtypes/debug-dotout.txt new file mode 100644 index 0000000..d2ec8fa --- /dev/null +++ b/buildtypes/debug-dotout.txt @@ -0,0 +1,16 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D DEBUG_BUILD +-D DOTOUT_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/debug-valgrind.txt b/buildtypes/debug-valgrind.txt new file mode 100644 index 0000000..414b0bb --- /dev/null +++ b/buildtypes/debug-valgrind.txt @@ -0,0 +1,16 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D DEBUG_BUILD +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/debug.txt b/buildtypes/debug.txt new file mode 100644 index 0000000..32093d6 --- /dev/null +++ b/buildtypes/debug.txt @@ -0,0 +1,18 @@ + +-g + +-I . + +-D _GNU_SOURCE + +-D DEBUG_BUILD + +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/release.txt b/buildtypes/release.txt new file mode 100644 index 0000000..c298d80 --- /dev/null +++ b/buildtypes/release.txt @@ -0,0 +1,12 @@ + +-I . + +-D RELEASE_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment + diff --git a/buildtypes/test-dotout-valgrind.txt b/buildtypes/test-dotout-valgrind.txt new file mode 100644 index 0000000..767d143 --- /dev/null +++ b/buildtypes/test-dotout-valgrind.txt @@ -0,0 +1,17 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D TEST_BUILD +-D DOTOUT_BUILD +-D VALGRIND_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/test-dotout.txt b/buildtypes/test-dotout.txt new file mode 100644 index 0000000..db2a6a5 --- /dev/null +++ b/buildtypes/test-dotout.txt @@ -0,0 +1,16 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D TEST_BUILD +-D DOTOUT_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/buildtypes/test.txt b/buildtypes/test.txt new file mode 100644 index 0000000..e2faf5e --- /dev/null +++ b/buildtypes/test.txt @@ -0,0 +1,15 @@ + +-g + +-I . + +-D _GNU_SOURCE +-D TEST_BUILD + +-Wall +-Werror +-Wfatal-errors +-Wstrict-prototypes + +-Wno-comment +-Wno-unused diff --git a/builtins/arithmetic/add.c b/builtins/arithmetic/add.c new file mode 100644 index 0000000..4970fe7 --- /dev/null +++ b/builtins/arithmetic/add.c @@ -0,0 +1,90 @@ + +#include + +#include +#include + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "add.h" + +struct value* builtin_add( + BUILTIN_PARAMETER_DECLARATION) +{ + struct value* retval = NULL; + ENTER; + + if (arguments->kind == vk_null) + { + TODO; + } + else + { + assert(arguments->kind == vk_list); + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = evalfunc(arguments_lv->first, environment, gc); + + switch (first->kind) + { + case vk_integer: + { + intmax_t sum = 0; + + sum += first->subclass.integer.value; + + for (struct value* link = arguments_lv->rest; + link->kind == vk_list; + link = link->subclass.list.rest) + { + struct value* element = link->subclass.list.first; + + struct value* evaluated = evalfunc(element, environment, gc); + + if (evaluated->kind != vk_integer) + { + TODO; + } + + dpvlu(evaluated->subclass.integer.value); + + sum += evaluated->subclass.integer.value; + + gc_dec_external_refcount(gc, evaluated); + } + + dpvlu(sum); + + retval = new_integer_value(gc, sum); + + break; + } + + case vk_string: + TODO; + break; + + case vk_list: + TODO; + break; + + default: + TODO; + break; + } + + gc_dec_external_refcount(gc, first); + } + + EXIT; + return retval; +} + + + + + + diff --git a/builtins/arithmetic/add.h b/builtins/arithmetic/add.h new file mode 100644 index 0000000..4af28f2 --- /dev/null +++ b/builtins/arithmetic/add.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_add( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/arithmetic/div.c b/builtins/arithmetic/div.c new file mode 100644 index 0000000..fe09b1f --- /dev/null +++ b/builtins/arithmetic/div.c @@ -0,0 +1,13 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "div.h" + +struct value* builtin_div( + BUILTIN_PARAMETER_DECLARATION) +{ + TODO; +} + diff --git a/builtins/arithmetic/div.h b/builtins/arithmetic/div.h new file mode 100644 index 0000000..eb3376a --- /dev/null +++ b/builtins/arithmetic/div.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_div( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/arithmetic/mul.c b/builtins/arithmetic/mul.c new file mode 100644 index 0000000..dcc76b0 --- /dev/null +++ b/builtins/arithmetic/mul.c @@ -0,0 +1,85 @@ + +#include + +#include +#include + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "mul.h" + +struct value* builtin_mul( + BUILTIN_PARAMETER_DECLARATION) +{ + struct value* retval = NULL; + ENTER; + + if (arguments->kind == vk_null) + { + TODO; + } + else + { + assert(arguments->kind == vk_list); + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = evalfunc(arguments_lv->first, environment, gc); + + switch (first->kind) + { + case vk_integer: + { + intmax_t product = 1; + + product *= first->subclass.integer.value; + + for (struct value* link = arguments_lv->rest; + link->kind == vk_list; + link = link->subclass.list.rest) + { + struct value* element = link->subclass.list.first; + + struct value* evaluated = evalfunc(element, environment, gc); + + if (evaluated->kind != vk_integer) + { + TODO; + } + + dpvlu(evaluated->subclass.integer.value); + + product *= evaluated->subclass.integer.value; + + gc_dec_external_refcount(gc, evaluated); + } + + dpvlu(product); + + retval = new_integer_value(gc, product); + + break; + } + + case vk_string: + TODO; + break; + + case vk_list: + TODO; + break; + + default: + TODO; + break; + } + + gc_dec_external_refcount(gc, first); + } + + EXIT; + return retval; +} + diff --git a/builtins/arithmetic/mul.h b/builtins/arithmetic/mul.h new file mode 100644 index 0000000..3ee5ab1 --- /dev/null +++ b/builtins/arithmetic/mul.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_mul( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/arithmetic/rem.c b/builtins/arithmetic/rem.c new file mode 100644 index 0000000..32ff7af --- /dev/null +++ b/builtins/arithmetic/rem.c @@ -0,0 +1,13 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "rem.h" + +struct value* builtin_rem( + BUILTIN_PARAMETER_DECLARATION) +{ + TODO; +} + diff --git a/builtins/arithmetic/rem.h b/builtins/arithmetic/rem.h new file mode 100644 index 0000000..90c5071 --- /dev/null +++ b/builtins/arithmetic/rem.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_rem( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/arithmetic/sub.c b/builtins/arithmetic/sub.c new file mode 100644 index 0000000..8344fef --- /dev/null +++ b/builtins/arithmetic/sub.c @@ -0,0 +1,83 @@ + +#include + +#include +#include + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "sub.h" + +struct value* builtin_sub( + BUILTIN_PARAMETER_DECLARATION) +{ + struct value* retval = NULL; + ENTER; + + if (arguments->kind == vk_null) + { + TODO; + } + else + { + assert(arguments->kind == vk_list); + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = evalfunc(arguments_lv->first, environment, gc); + + switch (first->kind) + { + case vk_integer: + { + intmax_t sub = first->subclass.integer.value; + + for (struct value* link = arguments_lv->rest; + link->kind == vk_list; + link = link->subclass.list.rest) + { + struct value* element = link->subclass.list.first; + + struct value* evaluated = evalfunc(element, environment, gc); + + if (evaluated->kind != vk_integer) + { + TODO; + } + + dpvlu(evaluated->subclass.integer.value); + + sub -= evaluated->subclass.integer.value; + + gc_dec_external_refcount(gc, evaluated); + } + + dpvlu(sub); + + retval = new_integer_value(gc, sub); + + break; + } + + case vk_string: + TODO; + break; + + case vk_list: + TODO; + break; + + default: + TODO; + break; + } + + gc_dec_external_refcount(gc, first); + } + + EXIT; + return retval; +} + diff --git a/builtins/arithmetic/sub.h b/builtins/arithmetic/sub.h new file mode 100644 index 0000000..10b4bdb --- /dev/null +++ b/builtins/arithmetic/sub.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_sub( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/equal_to.c b/builtins/comparision/equal_to.c new file mode 100644 index 0000000..94fa1ba --- /dev/null +++ b/builtins/comparision/equal_to.c @@ -0,0 +1,70 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "equal_to.h" + +struct value* builtin_equal_to( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp == 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + + + + + + + diff --git a/builtins/comparision/equal_to.h b/builtins/comparision/equal_to.h new file mode 100644 index 0000000..1b2d3e4 --- /dev/null +++ b/builtins/comparision/equal_to.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_equal_to( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/greater_than.c b/builtins/comparision/greater_than.c new file mode 100644 index 0000000..fce2875 --- /dev/null +++ b/builtins/comparision/greater_than.c @@ -0,0 +1,64 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "greater_than.h" + +struct value* builtin_greater_than( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp > 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + diff --git a/builtins/comparision/greater_than.h b/builtins/comparision/greater_than.h new file mode 100644 index 0000000..c47c4fa --- /dev/null +++ b/builtins/comparision/greater_than.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_greater_than( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/greater_than_equal_to.c b/builtins/comparision/greater_than_equal_to.c new file mode 100644 index 0000000..644625e --- /dev/null +++ b/builtins/comparision/greater_than_equal_to.c @@ -0,0 +1,64 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "greater_than_equal_to.h" + +struct value* builtin_greater_than_equal_to( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp >= 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + diff --git a/builtins/comparision/greater_than_equal_to.h b/builtins/comparision/greater_than_equal_to.h new file mode 100644 index 0000000..428f302 --- /dev/null +++ b/builtins/comparision/greater_than_equal_to.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_greater_than_equal_to( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/less_than.c b/builtins/comparision/less_than.c new file mode 100644 index 0000000..d3a397a --- /dev/null +++ b/builtins/comparision/less_than.c @@ -0,0 +1,64 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "less_than.h" + +struct value* builtin_less_than( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp < 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + diff --git a/builtins/comparision/less_than.h b/builtins/comparision/less_than.h new file mode 100644 index 0000000..0b61622 --- /dev/null +++ b/builtins/comparision/less_than.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_less_than( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/less_than_equal_to.c b/builtins/comparision/less_than_equal_to.c new file mode 100644 index 0000000..1d4c65b --- /dev/null +++ b/builtins/comparision/less_than_equal_to.c @@ -0,0 +1,64 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "less_than_equal_to.h" + +struct value* builtin_less_than_equal_to( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp <= 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + diff --git a/builtins/comparision/less_than_equal_to.h b/builtins/comparision/less_than_equal_to.h new file mode 100644 index 0000000..84807d2 --- /dev/null +++ b/builtins/comparision/less_than_equal_to.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_less_than_equal_to( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/comparision/not_equal_to.c b/builtins/comparision/not_equal_to.c new file mode 100644 index 0000000..9df4bc6 --- /dev/null +++ b/builtins/comparision/not_equal_to.c @@ -0,0 +1,64 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include +#include +#include + +#include "not_equal_to.h" + +struct value* builtin_not_equal_to( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + + exit(1); + } + + struct value* first_eval = evalfunc(first, environment, gc); + + struct value* second_eval = evalfunc(second, environment, gc); + + int cmp = compare_values(first_eval, second_eval); + + struct value* result = new_boolean_value(gc, cmp != 0); + + gc_dec_external_refcount(gc, first_eval); + gc_dec_external_refcount(gc, second_eval); + + EXIT; + return result; +} + diff --git a/builtins/comparision/not_equal_to.h b/builtins/comparision/not_equal_to.h new file mode 100644 index 0000000..ecf39bf --- /dev/null +++ b/builtins/comparision/not_equal_to.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_not_equal_to( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/core/define.c b/builtins/core/define.c new file mode 100644 index 0000000..43d13b4 --- /dev/null +++ b/builtins/core/define.c @@ -0,0 +1,81 @@ + +#include + +#include +#include +#include + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "define.h" + +struct value* builtin_define( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + if (first->kind != vk_identifier) + { + TODO; + exit(1); + } + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + exit(1); + } + + struct value* second = rest->subclass.list.first; + + if (rest->subclass.list.rest->kind != vk_null) + { + TODO; + exit(1); + } + + struct value* result = evalfunc(second, environment, gc); + + environment_value_define( + /* environment: */ environment, + /* name: */ first->subclass.identifier.name, + /* value: */ result); + + gc_dec_external_refcount(gc, result); + + struct value* retval = new_null_value(gc); + + EXIT; + return retval; +} + + + + + + + + + + + + + + + + diff --git a/builtins/core/define.h b/builtins/core/define.h new file mode 100644 index 0000000..c7989d7 --- /dev/null +++ b/builtins/core/define.h @@ -0,0 +1,8 @@ + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +struct value* builtin_define( + BUILTIN_PARAMETER_DECLARATION); + + + diff --git a/builtins/core/ifelse.c b/builtins/core/ifelse.c new file mode 100644 index 0000000..459cc2e --- /dev/null +++ b/builtins/core/ifelse.c @@ -0,0 +1,91 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include + +#include + +#include "ifelse.h" + +struct value* builtin_ifelse( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_list) + { + TODO; + exit(1); + } + + struct value* third = restrest->subclass.list.first; + + struct value* restrestrest = restrest->subclass.list.rest; + + if (restrestrest->kind != vk_null) + { + TODO; + exit(1); + } + + struct value* conditional = evalfunc(first, environment, gc); + + if (conditional->kind != vk_boolean) + { + TODO; + exit(1); + } + + struct value* result = evalfunc( + /* expression: */ conditional->subclass.boolean.value ? second : third, + /* environment: */ environment, + /* garbage collection: */ gc); + + gc_dec_external_refcount(gc, conditional); + + EXIT; + return result; +} + + + + + + + + + + + + + + + + + + diff --git a/builtins/core/ifelse.h b/builtins/core/ifelse.h new file mode 100644 index 0000000..2a82ca1 --- /dev/null +++ b/builtins/core/ifelse.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_ifelse( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/core/lambda.c b/builtins/core/lambda.c new file mode 100644 index 0000000..99756ab --- /dev/null +++ b/builtins/core/lambda.c @@ -0,0 +1,70 @@ + +#include + +#include +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "lambda.h" + +struct value* builtin_lambda( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + if (first->kind != vk_list && first->kind != vk_null) + { + TODO; + exit(1); + } + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + exit(1); + } + + struct value* second = rest->subclass.list.first; + + if (rest->subclass.list.rest->kind != vk_null) + { + TODO; + exit(1); + } + + struct value* result = new_user_lambda_value( + /* garbage collector: */ gc, + /* captured environment: */ environment, + /* parameters: */ first, + /* body: */ second); + + EXIT; + return result; +} + + + + + + + + + + + + + diff --git a/builtins/core/lambda.h b/builtins/core/lambda.h new file mode 100644 index 0000000..45cedf7 --- /dev/null +++ b/builtins/core/lambda.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_lambda( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/core/let.c b/builtins/core/let.c new file mode 100644 index 0000000..2755e48 --- /dev/null +++ b/builtins/core/let.c @@ -0,0 +1,70 @@ + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "let.h" + +struct value* builtin_let( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + TODO; + #if 0 + if (arguments->kind == vk_null) + { + TODO; + + exit(1); + } + + assert(arguments->kind == vk_list); + + struct list_value* arguments_lv = &arguments->subvalue.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind == vk_null) + { + TODO; + exit(1); + } + + assert(rest->kind == vk_list); + + struct value* second = rest->first; + + if (second->rest->kind != vk_null) + { + TODO; + exit(1); + } + + TODO; + + TODO; + #endif + + EXIT; +} + + + + + + + + + + + + + + + + + + diff --git a/builtins/core/let.h b/builtins/core/let.h new file mode 100644 index 0000000..7a01f21 --- /dev/null +++ b/builtins/core/let.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_let( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/core/letrec.c b/builtins/core/letrec.c new file mode 100644 index 0000000..e69de29 diff --git a/builtins/core/letrec.h b/builtins/core/letrec.h new file mode 100644 index 0000000..e69de29 diff --git a/builtins/defines/BUILTIN_PARAMETER_DECLARATION.h b/builtins/defines/BUILTIN_PARAMETER_DECLARATION.h new file mode 100644 index 0000000..19feada --- /dev/null +++ b/builtins/defines/BUILTIN_PARAMETER_DECLARATION.h @@ -0,0 +1,11 @@ + +#define BUILTIN_PARAMETER_DECLARATION \ + struct value* arguments, \ + struct value* environment, \ + struct gc* gc, \ + struct value* (*evalfunc)( \ + struct value* value, \ + struct value* environment, \ + struct gc* gc) \ + + diff --git a/builtins/defines/BUILTIN_PARAMETER_PROTOTYPE.h b/builtins/defines/BUILTIN_PARAMETER_PROTOTYPE.h new file mode 100644 index 0000000..8d61081 --- /dev/null +++ b/builtins/defines/BUILTIN_PARAMETER_PROTOTYPE.h @@ -0,0 +1,11 @@ + +#define BUILTIN_PARAMETER_PROTOTYPE \ + struct value*, \ + struct value*, \ + struct gc*, \ + struct value* (*evalfunc)( \ + struct value* value, \ + struct value* environment, \ + struct gc* gc) \ + + diff --git a/builtins/list/cons.c b/builtins/list/cons.c new file mode 100644 index 0000000..c8a0205 --- /dev/null +++ b/builtins/list/cons.c @@ -0,0 +1,78 @@ + +#include + +#include + +#include + +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "cons.h" + +struct value* builtin_cons( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + if (arguments->kind != vk_list) + { + TODO; + + exit(1); + } + + struct list_value* arguments_lv = &arguments->subclass.list; + + struct value* first = arguments_lv->first; + + struct value* rest = arguments_lv->rest; + + if (rest->kind != vk_list) + { + TODO; + exit(1); + } + + struct value* second = rest->subclass.list.first; + + struct value* restrest = rest->subclass.list.rest; + + if (restrest->kind != vk_null) + { + TODO; + exit(1); + } + + struct value* eval_first = evalfunc(first, environment, gc); + + struct value* eval_second = evalfunc(second, environment, gc); + + struct value* result = new_list_value( + /* garbage collector: */ gc, + /* first: */ eval_first); + + result->subclass.list.rest = eval_second; + + gc_dec_external_refcount(gc, eval_first); + + gc_dec_external_refcount(gc, eval_second); + + EXIT; + return result; +} + + + + + + + + + + + + + + diff --git a/builtins/list/cons.h b/builtins/list/cons.h new file mode 100644 index 0000000..0e8f5f0 --- /dev/null +++ b/builtins/list/cons.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_cons( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/list/list.c b/builtins/list/list.c new file mode 100644 index 0000000..b58f8b6 --- /dev/null +++ b/builtins/list/list.c @@ -0,0 +1,86 @@ + +#include + +#include +#include +#include + +#include +#include + +#include "../defines/BUILTIN_PARAMETER_DECLARATION.h" + +#include "list.h" + +struct value* builtin_list( + BUILTIN_PARAMETER_DECLARATION) +{ + ENTER; + + struct value* retval = NULL; + + struct value* tail = NULL; + + for (struct value* moving = arguments; + moving->kind == vk_list; + moving = moving->subclass.list.rest) + { + struct value* element = moving->subclass.list.first; + + struct value* result = evalfunc(element, environment, gc); + + struct value* link = new_list_value(gc, result); + + if (tail) + { + tail->subclass.list.rest = link; + + gc_dec_external_refcount(gc, tail); + + tail = gc_inc_external_refcount(gc, link); + } + else + { + retval = gc_inc_external_refcount(gc, link); + + tail = gc_inc_external_refcount(gc, link); + } + + gc_dec_external_refcount(gc, link); + gc_dec_external_refcount(gc, result); + } + + struct value* null = new_null_value(gc); + + if (tail) + { + tail->subclass.list.rest = null; + } + else + { + TODO; + } + + gc_dec_external_refcount(gc, null); + + gc_dec_external_refcount(gc, tail); + + EXIT; + return retval; +} + + + + + + + + + + + + + + + + diff --git a/builtins/list/list.h b/builtins/list/list.h new file mode 100644 index 0000000..dfc8b6c --- /dev/null +++ b/builtins/list/list.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +struct value* builtin_list( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/builtins/logical/and.c b/builtins/logical/and.c new file mode 100644 index 0000000..e69de29 diff --git a/builtins/logical/and.h b/builtins/logical/and.h new file mode 100644 index 0000000..e69de29 diff --git a/builtins/logical/not.c b/builtins/logical/not.c new file mode 100644 index 0000000..e69de29 diff --git a/builtins/logical/not.h b/builtins/logical/not.h new file mode 100644 index 0000000..e69de29 diff --git a/builtins/logical/or.c b/builtins/logical/or.c new file mode 100644 index 0000000..e69de29 diff --git a/builtins/logical/or.h b/builtins/logical/or.h new file mode 100644 index 0000000..e69de29 diff --git a/builtins/typedefs/builtin_funcptr_t.h b/builtins/typedefs/builtin_funcptr_t.h new file mode 100644 index 0000000..ab3b40a --- /dev/null +++ b/builtins/typedefs/builtin_funcptr_t.h @@ -0,0 +1,6 @@ + +#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h" + +typedef struct value* (*builtin_funcptr_t)( + BUILTIN_PARAMETER_PROTOTYPE); + diff --git a/cmdln/free.c b/cmdln/free.c new file mode 100644 index 0000000..f4d2535 --- /dev/null +++ b/cmdln/free.c @@ -0,0 +1,17 @@ + +#include + +#include + +#include "free.h" + +void free_cmdln_flags( + struct cmdln_flags* flags) +{ + ENTER; + + free(flags); + + EXIT; +} + diff --git a/cmdln/free.h b/cmdln/free.h new file mode 100644 index 0000000..7f682a7 --- /dev/null +++ b/cmdln/free.h @@ -0,0 +1,5 @@ + +struct cmdln_flags; + +void free_cmdln_flags( + struct cmdln_flags* flags); diff --git a/cmdln/process.c b/cmdln/process.c new file mode 100644 index 0000000..762907a --- /dev/null +++ b/cmdln/process.c @@ -0,0 +1,223 @@ + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include "struct.h" +#include "process.h" + +struct cmdln_flags* process_cmdln_flags( + int argc, + char* const* argv) +{ + ENTER; + + struct gc_flags gc_flags = { + .minimum = GARBAGE_COLLECTION_MINIMUM, + .run_every = GARBAGE_COLLECTION_RUN_EVERY, + .process_limit = GARBAGE_COLLECTION_PROCESS_LIMIT, + .dotout = false, + }; + + bool verbose = false; + + bool macro_expansion_dotout = false; + + bool evaluation_dotout = false; + + static const struct option long_options[] = { + {"garbage-collection-minimum", required_argument, 0, 1}, + {"garbage-collection-run-every", required_argument, 0, 2}, + {"garbage-collection-process-limit", required_argument, 0, 3}, + {"garbage-collection-dotout", required_argument, 0, 4}, + + {"macro-expansion-dotout", required_argument, 0, 5}, + + {"evaluation-dotout", required_argument, 0, 6}, + + {"verbose", no_argument, 0, 'v'}, + + {0, 0, 0, 0} + }; + + for (int c; (c = getopt_long(argc, argv, "" + "\1\2\3\4\5\6" + "v" + "", long_options, NULL)) >= 0; ) + { + switch (c) + { + size_t parse_size(const char* opt) + { + ENTER; + + dpvs(opt); + + errno = 0; + + char* m; + + unsigned long val = strtoul(opt, &m, 10); + + if (errno) + { + TODO; + } + + switch (*m) + { + case 'B': + break; + + case 'K': + TODO; + break; + + case 'M': + TODO; + break; + + case 'G': + TODO; + break; + + default: + TODO; + break; + } + + dpvlu(val); + + EXIT; + return val; + } + + case 1: // --garbage-collection-minimum + { + size_t size = parse_size(optarg); + + gc_flags.minimum = size; + + dpvlu(gc_flags.minimum); + + break; + } + + case 2: // --garbage-collection-run-every + { + size_t size = parse_size(optarg); + + gc_flags.run_every = size; + + dpvlu(gc_flags.run_every); + + break; + } + + case 3: // --garbage-collection-process-limit + { + size_t size = parse_size(optarg); + + gc_flags.process_limit = size; + + dpvlu(gc_flags.process_limit); + + break; + } + + case 4: // --garbage-collection-dotout + { + gc_flags.dotout = true; + + dpvb(gc_flags.dotout); + + break; + } + + case 5: // --macro-expansion-dotout + { + macro_expansion_dotout = true; + + dpvb(macro_expansion_dotout); + + break; + } + + case 6: // --evaluation-dotout + { + evaluation_dotout = true; + + dpvb(evaluation_dotout); + + break; + } + + case 'v': + { + verbose = true; + + dpvb(verbose); + + break; + } + + default: + TODO; + exit(1); + break; + } + } + + if (gc_flags.process_limit < gc_flags.run_every) + { + TODO; + } + + struct cmdln_flags* flags = smalloc(sizeof(*flags)); + + flags->gc_flags = gc_flags; + + flags->macro_expansion_dotout = macro_expansion_dotout; + + flags->evaluation_dotout = evaluation_dotout; + + flags->verbose = verbose; + + flags->input_file = argv[optind++]; + + flags->argv = &argv[optind++]; + + if (!flags->input_file) + { + TODO; + } + + EXIT; + return flags; +} + + + + + + + + + + + + + + + + + diff --git a/cmdln/process.h b/cmdln/process.h new file mode 100644 index 0000000..81a2bd0 --- /dev/null +++ b/cmdln/process.h @@ -0,0 +1,7 @@ + + +struct cmdln_flags* process_cmdln_flags( + int argc, + char* const* argv); + + diff --git a/cmdln/struct.h b/cmdln/struct.h new file mode 100644 index 0000000..301b941 --- /dev/null +++ b/cmdln/struct.h @@ -0,0 +1,24 @@ + +#include + +struct cmdln_flags +{ + struct gc_flags gc_flags; + // size_t minimum; + // size_t retrigger; + // size_t process_limit; + // bool dotout; + + bool macro_expansion_dotout; + + bool evaluation_dotout; + + bool verbose; + // print expression before evaluating + + const char* input_file; + // "-" means stdin + + char* const* argv; +}; + diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..148d63d --- /dev/null +++ b/debug.c @@ -0,0 +1,91 @@ + +#include + +int debug_depth; + +void dpvs_implementation( + const char* expression, + char quote, + const unsigned char* string_value, + size_t len) +{ + printf("%*s", debug_depth, ""); + + printf("%s = %c", expression, quote); + + for (const unsigned char* m = string_value; len && *m; m++, len--) + { + switch (*m) + { + case ' ': + case '~': + case '@': + case '$': + case ',': + case '%': + case '^': + case '&': + case '\'': + case '*': + case '#': + case '`': + case ';': + case '.': + case '=': + case '/': + case '+': + case '-': + case '_': + case '!': + case ':': + case '<': case '>': + case '(': case ')': + case '[': case ']': + case '{': case '}': + case '0' ... '9': + case 'a' ... 'z': + case 'A' ... 'Z': + putchar(*m); + break; + + case '\\': + printf("\\\\"); + break; + + case '\"': + printf("\\\""); + break; + + case '\e': + printf("\\e"); + break; + + case '\n': + printf("\\n"); + break; + + default: + printf("\\x%02X", *m); + break; + } + } + + + printf("%c\n", quote); +} + + + + + + + + + + + + + + + + diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..cb34645 --- /dev/null +++ b/debug.h @@ -0,0 +1,264 @@ + +#if (defined(DEBUG_BUILD) || defined(TEST_BUILD)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmdln_flags; +struct gc; +struct istream; +struct tokenizer; +struct value; +struct stringtree; +struct gc_flags; +struct linked_list; +struct link; +struct string; +struct istream_inheritance; +struct istream; +struct environment_value; +struct value_inheritance; + +#include +/*#include */ + +/*#include */ + +/*#include */ +/*#include */ + +/*#include */ +/*#include */ +/*#include */ +/*#include */ + +/*#include */ +/*#include */ +/*#include */ + +/*#include */ +/*#include */ + +/*#include */ + +/*#include */ + +#endif + +#ifdef DEBUG_BUILD + +extern int debug_depth; + +#define HERE \ + printf("%*s" "HERE at %s:%i\n", debug_depth, "", __PRETTY_FUNCTION__, __LINE__); + +#define ENTER \ + printf("%*s" "%s\n", debug_depth++, "", __PRETTY_FUNCTION__); + +#define EXIT \ + assert(debug_depth), printf("%*s" "return; // from %s\n", debug_depth--, "", __FUNCTION__); + +#define TODO \ + { \ + printf("TODO hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t child = fork(); \ + \ + if (child < 0) \ + {\ + perror("fork");\ + }\ + else if (child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char buffer[100]; \ + snprintf(buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, buffer, NULL); \ + }\ + \ + exit(1); \ + } + +#define CHECK \ + { \ + printf("CHECK hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t child = fork(); \ + \ + if (child < 0) \ + {\ + perror("fork");\ + }\ + else if (child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char buffer[100]; \ + snprintf(buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, buffer, NULL); \ + }\ + \ + exit(1); \ + } + +#define NOPE \ + { \ + printf("NOPE hit at %s:%i!\n", __FILE__, __LINE__); \ + \ + pid_t child = fork(); \ + \ + if (child < 0) \ + {\ + perror("fork");\ + }\ + else if (child)\ + {\ + int wstatus = 0;\ + \ + if (waitpid(child, &wstatus, 0) < 0)\ + perror("waitpid");\ + else if (wstatus)\ + fprintf(stderr, "child failed!");\ + }\ + else\ + {\ + char buffer[100]; \ + snprintf(buffer, 100, "+%u", __LINE__); \ + execlp("gedit", "gedit", __FILE__, buffer, NULL); \ + }\ + \ + exit(1); \ + } + +extern void dpvs_implementation( + const char*, + char quote, + const unsigned char*, + size_t); + +#define dpvs(str) \ + dpvs_implementation(#str, '\"', (const unsigned char*) str, (size_t) -1); + +#define dpvsn(str, len) \ + dpvs_implementation(#str, '\"', (const unsigned char*) str, (size_t) (len)); + +#define dpvss(str) \ + dpvs_implementation(#str, str->data, str->len); + +#define dpvb(b) \ + printf("%*s" "%s = %s\n", debug_depth, "", #b, (b) ? "true" : "false"); + +#define dputs(s) \ + printf("%*s" "%s\n", debug_depth, "", s); + +#define dpvc(c) \ + dpvs_implementation(#c, '\'', (const unsigned char[1]) {c}, (size_t) 1); + +#define dpvp(p) \ + printf("%*s" "%s = %p\n", debug_depth, "", #p, p); + +#define dpvf(f) \ + printf("%*s" "%s = %f\n", debug_depth, "", #f, f); + +#define dpvi(x) \ + printf("%*s" "%s = %i\n", debug_depth, "", #x, (x)); + +#define dpvhhu(x) \ + printf("%*s" "%s = %hhu\n", debug_depth, "", #x, (x)); + +#define dpvu(x) \ + printf("%*s" "%s = %u\n", debug_depth, "", #x, (x)); + +#define dpvlu(x) \ + printf("%*s" "%s = %lu\n", debug_depth, "", #x, (x)); + +#else + +#define ENTER ; + +#define EXIT ; + +#define HERE ; + +#define TODO assert(!"TODO"); + +#define CHECK assert(!"CHECK"); + +#define NOPE assert(!"NOPE"); + +#define dpvp(_) ; + +#define dpvs(_) ; + +#define dpvss(_) ; + +#define dpvsn(str, len) ; + +#define dpvb(_) ; + +#define dputs(_) ; + +#define dpvc(_) ; + +#define dpvi(_) ; + +#define dpvf(_) ; + +#define dpvhhu(_) ; + +#define dpvlu(_) ; + +#define dpvu(_) ; + +#endif + + + + + + + + + + + + + + + + + diff --git a/defines/MAX_MACRO_DEPTH.h b/defines/MAX_MACRO_DEPTH.h new file mode 100644 index 0000000..617eae1 --- /dev/null +++ b/defines/MAX_MACRO_DEPTH.h @@ -0,0 +1,3 @@ + +#define MAX_MACRO_DEPTH 3 + diff --git a/defines/argv0.h b/defines/argv0.h new file mode 100644 index 0000000..5cad7a4 --- /dev/null +++ b/defines/argv0.h @@ -0,0 +1,4 @@ + +#define argv0 \ + (program_invocation_name) + diff --git a/evaluate.c b/evaluate.c new file mode 100644 index 0000000..541e954 --- /dev/null +++ b/evaluate.c @@ -0,0 +1,174 @@ + +#include + +#include + +#include +#include + +#include + +#include +#include +#include + +#include "evaluate.h" + +struct value* evaluate( + struct value* value, + struct value* environment, + struct gc* gc) +{ + struct value* retval; + + ENTER; + + switch (value->kind) + { + case vk_null: + case vk_boolean: + case vk_integer: + case vk_user_lambda: + case vk_builtin_lambda: + { + retval = gc_inc_external_refcount(gc, value); + + break; + } + + case vk_identifier: + { + struct identifier_value* specific = &value->subclass.identifier; + + retval = environment_value_lookup(environment, specific->name); + + if (!retval) + { + fprintf(stderr, "unknown variable: %s\n", specific->name->data); + + exit(1); + } + + break; + } + + case vk_list: + { + struct list_value* specific = &value->subclass.list; + + struct value* first = evaluate(specific->first, environment, gc); + + switch (first->kind) + { + case vk_builtin_lambda: + { + retval = (first->subclass.builtin_lambda.funcptr)( + /* arguments: */ specific->rest, + /* environment: */ environment, + /* garbage collector: */ gc, + /* evalfunc: */ evaluate); + + break; + } + + case vk_user_lambda: + { + struct user_lambda_value* lambda = + &first->subclass.user_lambda; + + struct value* parameter_environment = new_environment_value( + /* garbage collection: */ gc, + /* fallback environment: */ lambda->environment); + + struct value *parameter_names, *parameter_expressions; + + for (parameter_names = lambda->parameters, + parameter_expressions = specific->rest; + parameter_names->kind == vk_list && + parameter_expressions->kind == vk_list; + parameter_names = parameter_names->subclass.list.rest, + parameter_expressions = parameter_expressions->subclass.list.rest) + { + struct value* parameter_name = parameter_names->subclass.list.first; + + struct value* parameter_expression = parameter_expressions->subclass.list.first; + + if (parameter_name->kind != vk_identifier) + { + TODO; + exit(1); + } + + struct value* parameter_value = evaluate( + /* expression: */ parameter_expression, + /* environment: */ environment, + /* garbage collection: */ gc); + + environment_value_define( + /* environment: */ parameter_environment, + /* name: */ parameter_name->subclass.identifier.name, + /* value: */ parameter_value); + + gc_dec_external_refcount(gc, parameter_value); + } + + if (false + || parameter_names->kind == vk_list + || parameter_expressions->kind == vk_list) + { + TODO; + exit(1); + } + + retval = evaluate(lambda->body, parameter_environment, gc); + + gc_dec_external_refcount(gc, parameter_environment); + + break; + } + + default: + { + TODO; + exit(1); + } + } + + gc_dec_external_refcount(gc, first); + + break; + } + + case vk_quote: + { + struct quote_value* specific = &value->subclass.quote; + + retval = gc_inc_external_refcount(gc, specific->subexpression); + + break; + } + + default: + { + dpvu(value->kind); + + TODO; + + break; + } + } + + EXIT; + return retval; +} + + + + + + + + + + + diff --git a/evaluate.h b/evaluate.h new file mode 100644 index 0000000..fcc42f1 --- /dev/null +++ b/evaluate.h @@ -0,0 +1,5 @@ + +struct value* evaluate( + struct value* value, + struct value* environment, + struct gc* gc); diff --git a/examples/sandbox.txt b/examples/sandbox.txt new file mode 100644 index 0000000..2311fcc --- /dev/null +++ b/examples/sandbox.txt @@ -0,0 +1,50 @@ + +# comments + +# # (define fib +# # (lambda (x) +# # (?: (> x 1) +# # (+ (fib (- x 1)) (fib (- x 2))) +# # 1))) +# +# # (fib 1) +# # (fib 2) +# # (fib 3) +# # (fib 4) +# # (fib 5) +# +# (define! let! +# (lambda! (a b c) +# ((lambda (list! a) c) b))) +# +# (let! x 3 (+ x 2)) +# +# (define! let2! +# (lambda! (a b c d e) +# ((lambda (list! a b) e) c d))) +# +# (let2! x y 3 5 (+ x y 2)) + +# (define! let3! +# (lambda! (a b c) +# (cons! (lambda a c) b))) +# +# (let3! (x y z) (1 2 3) (+ x y z 2)) + +(define Y + (lambda (f) + (f (lambda (x) ((Y f) x))))) + +(define almost-factorial + (lambda (f) + (lambda (n) + (if/else (= n 0) + 1 + (* n (f (- n 1))))))) + +(define factorial (Y almost-factorial)) + +(factorial 1) +(factorial 2) +(factorial 3) +(factorial 4) diff --git a/expand_macro.c b/expand_macro.c new file mode 100644 index 0000000..df2c43e --- /dev/null +++ b/expand_macro.c @@ -0,0 +1,215 @@ + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include "expand_macro.h" + +struct value* expand_macro( + struct value* value, + struct value* environment, + struct gc* gc) +{ + struct value* retval; + ENTER; + + switch (value->kind) + { + case vk_null: + case vk_integer: + case vk_boolean: + case vk_string: + { + dputs("case null, integer, boolean, string:"); + + retval = gc_inc_external_refcount(gc, value); + + break; + } + + case vk_identifier: + { + dputs("case vk_identifier:"); + + struct string* name = value->subclass.identifier.name; + + struct value* result = environment_value_lookup(environment, name); + + // if the lookup fails, don't change the variable + retval = result ?: gc_inc_external_refcount(gc, value); + + break; + } + + case vk_list: + { + dputs("case vk_list:"); + + struct list_value* specific = &value->subclass.list; + + struct value* first = expand_macro(specific->first, environment, gc); + + switch (first->kind) + { + case vk_builtin_lambda: + { + struct builtin_lambda_value* builtin = + &first->subclass.builtin_lambda; + + retval = (builtin->funcptr)( + /* list: */ specific->rest, + /* environment: */ environment, + /* garbage collector: */ gc, + /* evaluate function: */ expand_macro); + + break; + } + + case vk_user_lambda: + { + struct user_lambda_value* lambda = + &first->subclass.user_lambda; + + struct value* parameter_environment = new_environment_value( + /* garbage collection: */ gc, + /* fallback environment: */ lambda->environment); + + struct value *parameter_names, *parameter_expressions; + + for (parameter_names = lambda->parameters, + parameter_expressions = specific->rest; + parameter_names->kind == vk_list && + parameter_expressions->kind == vk_list; + parameter_names = parameter_names->subclass.list.rest, + parameter_expressions = parameter_expressions->subclass.list.rest) + { + struct value* parameter_name = parameter_names->subclass.list.first; + + struct value* parameter_expression = parameter_expressions->subclass.list.first; + + if (parameter_name->kind != vk_identifier) + { + TODO; + exit(1); + } + + struct value* parameter_value = expand_macro( + /* expression: */ parameter_expression, + /* environment: */ environment, + /* garbage collection: */ gc); + + environment_value_define( + /* environment: */ parameter_environment, + /* name: */ parameter_name->subclass.identifier.name, + /* value: */ parameter_value); + + gc_dec_external_refcount(gc, parameter_value); + } + + if (false + || parameter_names->kind == vk_list + || parameter_expressions->kind == vk_list) + { + TODO; + exit(1); + } + + retval = expand_macro(lambda->body, parameter_environment, gc); + + gc_dec_external_refcount(gc, parameter_environment); + + break; + } + + default: + { + retval = new_list_value(gc, first); + + struct value* tail = gc_inc_external_refcount(gc, retval); + + struct value* link; + + for (link = specific->rest; + link->kind == vk_list; + link = link->subclass.list.rest) + { + struct value* expanded = expand_macro( + /* element: */ link->subclass.list.first, + /* environment: */ environment, + /* garbage_collector: */ gc); + + struct value* new = new_list_value(gc, expanded); + + tail->subclass.list.rest = new; + gc_dec_external_refcount(gc, tail); + tail = gc_inc_external_refcount(gc, new); + + gc_dec_external_refcount(gc, new); + + gc_dec_external_refcount(gc, expanded); + } + + assert(link->kind == vk_null); + + tail->subclass.list.rest = link; + + gc_dec_external_refcount(gc, tail); + break; + } + } + + gc_dec_external_refcount(gc, first); + + break; + } + + case vk_quote: + { + dputs("case vk_quote:"); + + struct quote_value* specific = &value->subclass.quote; + + struct value* expanded_subexpression = expand_macro( + /* expression: */ specific->subexpression, + /* environment: */ environment, + /* gc: */ gc); + + retval = new_quote_value(gc, expanded_subexpression); + + gc_dec_external_refcount(gc, expanded_subexpression); + break; + } + + default: + TODO; + break; + } + + EXIT; + return retval; +} + + + + + + + + + + + + + + diff --git a/expand_macro.h b/expand_macro.h new file mode 100644 index 0000000..b6628ce --- /dev/null +++ b/expand_macro.h @@ -0,0 +1,5 @@ + +struct value* expand_macro( + struct value* value, + struct value* environment, + struct gc* gc); diff --git a/gc/allocate_node.c b/gc/allocate_node.c new file mode 100644 index 0000000..575afa4 --- /dev/null +++ b/gc/allocate_node.c @@ -0,0 +1,313 @@ + +#include + +#include +#include +#include + +#include +#include + +#include "linked_list/struct.h" +#include "linked_list/init.h" +#include "linked_list/append.h" +#include "linked_list/remove.h" +#include "linked_list/clear.h" +#include "linked_list/pop.h" + +#include "flags.h" +#include "struct.h" +#include "dotout.h" +#include "allocate_node.h" + +struct value* gc_allocate_node( + struct gc* this) +{ + ENTER; + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: start"); + } + #endif + + // check if we need to garbage-collect + if (true + && this->flags->minimum < this->bytes_currently_allocated + && this->bytes_currently_allocated > this->bytes_of_last_garbage_collection + && this->bytes_currently_allocated - this->bytes_of_last_garbage_collection + > this->flags->run_every) + { + dpvlu(this->bytes_currently_allocated); + dpvlu(this->bytes_of_last_garbage_collection); + dpvlu(this->flags->run_every); + dpvlu(this->flags->process_limit); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: time to garbage collect"); + } + #endif + + size_t i = 0, n = this->flags->process_limit; + + for (; this->grey.head && i < n; i += sizeof(struct value)) + { + dputs("processing grey..."); + + struct value* grey = linked_list_pop( + /* linked list: */ &this->grey, + /* link offset: */ offsetof(struct value, grey)); + + value_foreach_accessible_subvalue(grey, ({ + void callback(struct value* subvalue) + { + if (subvalue->white.in_set) + { + // remove from white set + linked_list_remove( + /* list: */ &this->white, + /* element: */ subvalue, + /* offset of link: */ offsetof(struct value, white)); + + // add to grey set + linked_list_append( + /* list: */ &this->grey, + /* element: */ subvalue, + /* offset of link: */ offsetof(struct value, grey)); + } + } + + callback; + })); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: processing grey (%lu of %lu)", i, n); + } + #endif + } + + if (i < n) + { + assert(!this->grey.head); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: all greys are gone, but we can still do more"); + } + #endif + + // if we haven't hit the process limit yet then the grey set must be \ + empty. If that's the case, then start processing the white nodes. + + for (; this->white.head && i < n; i += sizeof(struct value)) + { + struct value* white = linked_list_pop( + /* linked list: */ &this->white, + /* link offset: */ offsetof(struct value, white)); + + // remove white from "internally_referenced" + linked_list_remove( + /* linked list: */ &this->internally_referenced, + /* element: */ white, + /* link offset: */ offsetof(struct value, internally_referenced)); + + assert(white->external_refcount == 0); + assert(white->externally_referenced.in_set == false); + assert(white->internally_referenced.in_set == false); + assert(white->grey.in_set == false); + assert(white->white.in_set == false); + assert(white->reaped.in_set == false); + + dpvp(white); + dpvp(white->inheritance); + + dpvb(VALGRIND_CHECK_VALUE_IS_DEFINED(white)); + + shallow_free_value(white); + + // reset value: + #ifdef VALGRIND_BUILD + VALGRIND_MAKE_MEM_UNDEFINED(white, sizeof(*white)); + + link_init(&white->internally_referenced); + link_init(&white->reaped); + link_init(&white->grey); + link_init(&white->white); + link_init(&white->externally_referenced); + + white->external_refcount = 0; + #endif + + #ifdef DOTOUT_BUILD + white->kind = vk_uninitalized; + #endif + + linked_list_append( + /* list: */ &this->reaped, + /* element: */ white, + /* offset of link: */ offsetof(struct value, reaped)); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: processing whites (%lu of %lu)", i, n); + } + #endif + } + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: done with white"); + } + #endif + + // with garbage collection offically done, we still need to set up \\ + for next time: + { + // reset the white set to match the allocated set: + { + linked_list_deep_clear( + /* linked list: */ &this->white, + /* link offset: */ offsetof(struct value, white)); + + for (struct value* v = this->internally_referenced.head; + v; v = v->internally_referenced.next) + { + linked_list_append( + /* linked list: */ &this->white, + /* element: */ v, + /* link offset: */ offsetof(struct value, white)); + } + } + + // reset the grey set to match "keep forever" set + { + linked_list_deep_clear( + /* linked list: */ &this->grey, + /* link offset: */ offsetof(struct value, grey)); + + for (struct value* v = this->externally_referenced.head; + v; v = v->externally_referenced.next) + { + linked_list_append( + /* linked list: */ &this->grey, + /* element: */ v, + /* link offset: */ offsetof(struct value, grey)); + } + } + + this->bytes_of_last_garbage_collection = this->bytes_currently_allocated; + } + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: reset grey and white sets"); + } + #endif + } + } + + // check if the free-list is empty: + if (!this->reaped.head) + { + // if so, allocate a new block + + if (this->blocks.n == this->blocks.cap) + { + this->blocks.cap = this->blocks.cap << 1 ?: 1; + + this->blocks.data = srealloc( + this->blocks.data, + sizeof(*this->blocks.data) * this->blocks.cap); + } + + this->next_block_cap = this->next_block_cap << 1 ?: 1; + + struct value* new_block = smalloc( + /* size: */ sizeof(*new_block) * this->next_block_cap); + + this->blocks.data[this->blocks.n++] = (struct block_info) { + .start = new_block, + .cap = this->next_block_cap, + }; + + // iterate through each block, appending to free list + for (size_t i = 0; i < this->next_block_cap; i++) + { + struct value* value = &new_block[i]; + + #ifdef VALGRIND_BUILD + VALGRIND_MAKE_MEM_UNDEFINED(value, sizeof(*value)); + #endif + + #ifdef DOTOUT_BUILD + value->kind = vk_uninitalized; + #endif + + link_init(&value->internally_referenced); + link_init(&value->reaped); + link_init(&value->grey); + link_init(&value->white); + link_init(&value->externally_referenced); + + value->external_refcount = 0; + + linked_list_append( + /* list: */ &this->reaped, + /* element: */ value, + /* offset of link: */ offsetof(struct value, reaped)); + } + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: loaded new block"); + } + #endif + } + + this->bytes_currently_allocated += sizeof(struct value); + + // pop first element off of free list + struct value* new = linked_list_pop( + /* list: */ &this->reaped, + /* link offset: */ offsetof(struct value, reaped)); + + new->external_refcount = 1; + + // add to "keep this forever" set + linked_list_append( + /* list: */ &this->externally_referenced, + /* element: */ new, + /* link offset: */ offsetof(struct value, externally_referenced)); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_allocate_node: pop first element off of free list, add to externally_referenced set"); + } + #endif + + EXIT; + return new; +} + + + + + + + + + + + + diff --git a/gc/allocate_node.h b/gc/allocate_node.h new file mode 100644 index 0000000..03fbb1b --- /dev/null +++ b/gc/allocate_node.h @@ -0,0 +1,3 @@ + +struct value* gc_allocate_node( + struct gc* this); diff --git a/gc/dec_external_refcount.c b/gc/dec_external_refcount.c new file mode 100644 index 0000000..f83f9c8 --- /dev/null +++ b/gc/dec_external_refcount.c @@ -0,0 +1,77 @@ + +#include + +#include + +#include "linked_list/append.h" +#include "linked_list/remove.h" + +#include "dotout.h" +#include "flags.h" +#include "struct.h" +#include "dec_external_refcount.h" + +void gc_dec_external_refcount( + struct gc* this, + struct value* value) +{ + ENTER; + + if (value) + { + assert(value->external_refcount > 0); + + if (value->external_refcount > 1) + { + value->external_refcount--; + } + else if (value->external_refcount == 1) + { + assert(value->externally_referenced.in_set == true); + assert(value->internally_referenced.in_set == false); + assert(value->white.in_set == false); + assert(value->reaped.in_set == false); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_dec_external_refcount: before"); + } + #endif + + value->external_refcount--; + + linked_list_remove( + /* linked list: */ &this->externally_referenced, + /* element: */ value, + /* link offset: */ offsetof(struct value, externally_referenced)); + + // it might be in the grey set, but that's okay. + + linked_list_append( + /* linked list: */ &this->internally_referenced, + /* element: */ value, + /* link offset: */ offsetof(struct value, internally_referenced)); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_dec_external_refcount: after"); + } + #endif + + assert(value->internally_referenced.in_set); + } + else + { + NOPE; + } + } + + EXIT; +} + + + + + diff --git a/gc/dec_external_refcount.h b/gc/dec_external_refcount.h new file mode 100644 index 0000000..10e13c9 --- /dev/null +++ b/gc/dec_external_refcount.h @@ -0,0 +1,4 @@ + +void gc_dec_external_refcount( + struct gc* gc, + struct value* value); diff --git a/gc/defines/GARBAGE_COLLECTION_MINIMUM.h b/gc/defines/GARBAGE_COLLECTION_MINIMUM.h new file mode 100644 index 0000000..9e443ce --- /dev/null +++ b/gc/defines/GARBAGE_COLLECTION_MINIMUM.h @@ -0,0 +1,9 @@ + +// units are in bytes, not number of lisp_value structs: + +#ifdef RELEASE_BUILD + #define GARBAGE_COLLECTION_MINIMUM (10 * 1024 * 1024) +#else + #define GARBAGE_COLLECTION_MINIMUM (10 * 10) +#endif + diff --git a/gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h b/gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h new file mode 100644 index 0000000..87d1587 --- /dev/null +++ b/gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h @@ -0,0 +1,10 @@ + +// units are in bytes, not number of lisp_value structs: + +#ifdef RELEASE_BUILD + #define GARBAGE_COLLECTION_PROCESS_LIMIT (2 * 1024 * 1024) +#else + #define GARBAGE_COLLECTION_PROCESS_LIMIT (2 * 10) +#endif + +// must be *at least* the run every diff --git a/gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h b/gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h new file mode 100644 index 0000000..4e74097 --- /dev/null +++ b/gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h @@ -0,0 +1,10 @@ + +// units are in bytes, not number of lisp_value structs: + + +#ifdef RELEASE_BUILD + #define GARBAGE_COLLECTION_RUN_EVERY (1024 * 1024) +#else + #define GARBAGE_COLLECTION_RUN_EVERY (10) +#endif + diff --git a/gc/dotout.c b/gc/dotout.c new file mode 100644 index 0000000..62018cf --- /dev/null +++ b/gc/dotout.c @@ -0,0 +1,353 @@ + + +#ifdef DOTOUT_BUILD +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "struct.h" +#include "dotout.h" + +static size_t counter = 0; + +static const char* value_kind_to_string[] = { + [vk_uninitalized] = "uninitalized", + [vk_null] = "null", + [vk_builtin_lambda] = "builtin-lambda", + [vk_envrionment] = "environment", + [vk_identifier] = "identifier", + [vk_boolean] = "boolean", + [vk_integer] = "integer", + [vk_list] = "list", + [vk_string] = "string", + [vk_quote] = "quote", +}; + +void gc_dotout( + const struct gc* this, + const char* label_fmt, + ...) +{ + ENTER; + + char path[PATH_MAX]; + + sprintf(path, "/tmp/12-%08lu-gc.dot", counter++); + + dpvs(path); + + FILE* stream = fopen(path, "w"); + + fprintf(stream, "" + "digraph {" "\n" + "node [" "\n" + "shape = box" "\n" + "fontcolor = black" "\n" + "color = black" "\n" + "fillcolor = white" "\n" + "style = filled" "\n" + "]" "\n" + + "edge [" "\n" + "color = white" "\n" + "]" "\n" + + "fontcolor = white" "\n" + + "bgcolor = \"#331122\"" "\n" + + "overlap = false" "\n" + + "rankdir = LR" "\n" + ""); + + // print label: + { + fprintf(stream, "label = \""); + + va_list ap; + + va_start(ap, label_fmt); + + vfprintf(stream, label_fmt, ap); + + va_end(ap); + + fprintf(stream, "\"" "\n"); + } + + #if 0 + fprintf(stream, "" + "a [" "\n" + "label = \"total_bytes_currently_allocated = %lu\"" "\n" + "]" "\n" + "", this->bytes_currently_allocated); + + fprintf(stream, "" + "b [" "\n" + "label = \"last_garbage_collection = %lu\"" "\n" + "]" "\n" + "", this->bytes_of_last_garbage_collection); + + fprintf(stream, "" + "internally_referenced_head [ label = \"internally_referenced head\" ]" "\n" + "internally_referenced_tail [ label = \"internally_referenced tail\" ]" "\n" + ""); + + fprintf(stream, "" + "reaped_head [ label = \"reaped head\" ]" "\n" + "reaped_tail [ label = \"reaped tail\" ]" "\n" + ""); + + fprintf(stream, "" + "grey_head [ label = \"grey head\" ]" "\n" + "grey_tail [ label = \"grey tail\" ]" "\n" + ""); + + fprintf(stream, "" + "white_head [ label = \"white head\" ]" "\n" + "white_tail [ label = \"white tail\" ]" "\n" + ""); + + fprintf(stream, "" + "externally_referenced_head [ label = \"externally_referenced head\" ]" "\n" + "externally_referenced_tail [ label = \"externally_referenced tail\" ]" "\n" + ""); + #endif + + #if 1 + if (this->internally_referenced.head) + { + fprintf(stream, "" + "internally_referenced_head:e -> \"%p\":w [ style = dashed ]" "\n" + + "\"%p\":e -> internally_referenced_tail:w [ style = dashed ]" "\n" + "", this->internally_referenced.head, this->internally_referenced.tail); + } + + if (this->reaped.head) + { + fprintf(stream, "" + "reaped_head:e -> \"%p\":w [ style = dashed ]" "\n" + + "\"%p\":e -> reaped_tail:w [ style = dashed ]" "\n" + "", this->reaped.head, this->reaped.tail); + } + + if (this->grey.head) + { + fprintf(stream, "" + "grey_head:e -> \"%p\":w [ style = dashed ]" "\n" + + "\"%p\":e -> grey_tail:w [ style = dashed ]" "\n" + "", this->grey.head, this->grey.tail); + } + + if (this->white.head) + { + fprintf(stream, "" + "white_head:e -> \"%p\":w [ style = dashed ]" "\n" + + "\"%p\":e -> white_tail:w [ style = dashed ]" "\n" + "", this->white.head, this->white.tail); + } + + if (this->externally_referenced.head) + { + fprintf(stream, "" + "externally_referenced_head:e -> \"%p\":w [ style = dashed ]" "\n" + + "\"%p\":e -> externally_referenced_tail:w [ style = dashed ]" "\n" + "", this->externally_referenced.head, this->externally_referenced.tail); + } + #endif + + for (size_t i = 0; i < this->blocks.n; i++) + { + struct block_info info = this->blocks.data[i]; + + struct value* start = info.start; + + for (size_t j = 0, m = info.cap; j < m; j++) + { + struct value* value = &start[j]; + + const char* kindstring = value_kind_to_string[value->kind]; + + if (!kindstring) + { + dpvu(value->kind); + + TODO; + } + + struct stringtree* tree = new_stringtree(); + + stringtree_append_formatstr(tree, "\"%p\" [", value); + + stringtree_append_formatstr(tree, "shape = record" "\n"); + + if (value->grey.in_set) + { + stringtree_append_formatstr(tree, "fillcolor = grey" "\n"); + } + else if (value->white.in_set) + { + stringtree_append_formatstr(tree, "fillcolor = white" "\n"); + } + else if (value->reaped.in_set) + { + stringtree_append_formatstr(tree, "fillcolor = purple" "\n"); + } + else if (value->externally_referenced.in_set) + { + stringtree_append_formatstr(tree, "fillcolor = green" "\n"); + } + else + { + stringtree_append_formatstr(tree, "fillcolor = darkgreen" "\n"); + } + + stringtree_append_formatstr(tree, "label = \""); + + stringtree_append_formatstr(tree, "(%lu, %lu)", i, j); + + #if 0 + if (value->kind != vk_uninitalized) + { + struct stringtree* pprint = value_prettyprint(value); + + stringtree_append_formatstr(tree, "| "); + + stringtree_append_stringtree(tree, pprint); + + free_stringtree(pprint); + } + #endif + + #if 1 + stringtree_append_formatstr(tree, "| kind = %s", kindstring); + #endif + + if (value->externally_referenced.in_set) + { + stringtree_append_formatstr(tree, "| refcount = %lu", + value->external_refcount); + } + else + { + assert(value->external_refcount == 0); + } + + if (value->internally_referenced.in_set) + { + stringtree_append_string_const(tree, "| internally_referenced"); + } + + if (value->reaped.in_set) + { + stringtree_append_string_const(tree, "| reaped"); + } + + if (value->white.in_set) + { + stringtree_append_string_const(tree, "| white"); + } + + if (value->grey.in_set) + { + stringtree_append_string_const(tree, "| grey"); + } + + if (value->externally_referenced.in_set) + { + stringtree_append_string_const(tree, "| externally_referenced"); + } + + stringtree_append_formatstr(tree, "\"" "\n"); + + stringtree_append_formatstr(tree, "]"); + + stringtree_println(tree, stream); + + if (value->kind != vk_uninitalized) + { + value_foreach_accessible_subvalue(value, ({ + void callback(struct value* subvalue) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = solid ]" "\n" + "", value, subvalue); + } + callback; + })); + } + + #if 1 + if (value->internally_referenced.next) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = dashed]" "\n" + "", value, value->internally_referenced.next); + } + + if (value->reaped.next) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = dashed ]" "\n" + "", value, value->reaped.next); + } + + if (value->grey.next) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = dashed ]" "\n" + "", value, value->grey.next); + } + + if (value->white.next) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = dashed ]" "\n" + "", value, value->white.next); + } + + if (value->externally_referenced.next) + { + fprintf(stream, "" + "\"%p\":e -> \"%p\":w [ style = dashed ]" "\n" + "", value, value->externally_referenced.next); + } + #endif + + free_stringtree(tree); + } + } + + fprintf(stream, "" + "}" "\n" + ""); + + fclose(stream); + + EXIT; +} + + + + + + + + + + + +#endif diff --git a/gc/dotout.h b/gc/dotout.h new file mode 100644 index 0000000..a8cf0e1 --- /dev/null +++ b/gc/dotout.h @@ -0,0 +1,9 @@ + +#ifdef DOTOUT_BUILD + +void gc_dotout( + const struct gc* this, + const char* label_fmt, + ...); + +#endif diff --git a/gc/flags.h b/gc/flags.h new file mode 100644 index 0000000..97467d7 --- /dev/null +++ b/gc/flags.h @@ -0,0 +1,14 @@ + +#include + +struct gc_flags +{ + size_t minimum; + + size_t run_every; + + size_t process_limit; + + bool dotout; +}; + diff --git a/gc/free.c b/gc/free.c new file mode 100644 index 0000000..ba92159 --- /dev/null +++ b/gc/free.c @@ -0,0 +1,51 @@ + +#include + +#include +#include + +#include "dotout.h" +#include "flags.h" +#include "struct.h" +#include "free.h" + +void free_gc( + struct gc* this) +{ + ENTER; + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "free_gc: bye!"); + } + #endif + + for (size_t i = 0; i < this->blocks.n; i++) + { + struct block_info info = this->blocks.data[i]; + + struct value* start = info.start; + + for (size_t j = 0, m = info.cap; j < m; j++) + { + struct value* value = &start[j]; + + dpvp(value); + + if (!value->reaped.in_set) + { + shallow_free_value(value); + } + } + + free(info.start); + } + + free(this->blocks.data); + + free(this); + + EXIT; +} + diff --git a/gc/free.h b/gc/free.h new file mode 100644 index 0000000..0765fd7 --- /dev/null +++ b/gc/free.h @@ -0,0 +1,3 @@ + +void free_gc( + struct gc* this); diff --git a/gc/inc_external_refcount.c b/gc/inc_external_refcount.c new file mode 100644 index 0000000..38e4a3c --- /dev/null +++ b/gc/inc_external_refcount.c @@ -0,0 +1,74 @@ + +#include + +#include + +#include "linked_list/remove.h" +#include "linked_list/append.h" + +#include "dotout.h" +#include "flags.h" +#include "struct.h" +#include "inc_external_refcount.h" + +struct value* gc_inc_external_refcount( + struct gc* this, + struct value* value) +{ + ENTER; + + if (value) + { + if (value->external_refcount == 0) + { + assert(value->internally_referenced.in_set == true); + assert(value->externally_referenced.in_set == false); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_inc_external_refcount: before"); + } + #endif + + value->external_refcount++; + + linked_list_remove( + /* linked list: */ &this->internally_referenced, + /* element: */ value, + /* link offset: */ offsetof(struct value, internally_referenced)); + + if (value->white.in_set) + { + linked_list_remove( + /* linked list: */ &this->white, + /* element: */ value, + /* link offset: */ offsetof(struct value, white)); + } + + // if it's in the grey set, that's not a problem + + linked_list_append( + /* linked list: */ &this->externally_referenced, + /* element: */ value, + /* link offset: */ offsetof(struct value, externally_referenced)); + + #ifdef DOTOUT_BUILD + if (this->flags->dotout) + { + gc_dotout(this, "gc_inc_external_refcount: after"); + } + #endif + + assert(value->externally_referenced.in_set); + } + else + { + value->external_refcount++; + } + } + + EXIT; + return value; +} + diff --git a/gc/inc_external_refcount.h b/gc/inc_external_refcount.h new file mode 100644 index 0000000..b2edeaa --- /dev/null +++ b/gc/inc_external_refcount.h @@ -0,0 +1,4 @@ + +struct value* gc_inc_external_refcount( + struct gc* gc, + struct value* value); diff --git a/gc/linked_list/append.c b/gc/linked_list/append.c new file mode 100644 index 0000000..4bcda81 --- /dev/null +++ b/gc/linked_list/append.c @@ -0,0 +1,63 @@ + +#include + +#include "struct.h" +#include "append.h" + +void linked_list_append( + struct linked_list* this, + struct value* value, + size_t offset) +{ + ENTER; + + if (this->tail) + { + struct value* tail = this->tail; + + struct link* tail_link = (void*) tail + offset; + + tail_link->next = value; + + struct link* value_link = (void*) value + offset; + + assert(value_link->in_set == false); + + value_link->in_set = true; + + value_link->prev = tail; + value_link->next = NULL; + + this->tail = value; + } + else + { + this->tail = this->head = value; + + struct link* link = (void*) value + offset; + + assert(link->in_set == false); + + link->in_set = true; + + link->prev = NULL; + link->next = NULL; + } + + EXIT; +} + + + + + + + + + + + + + + + diff --git a/gc/linked_list/append.h b/gc/linked_list/append.h new file mode 100644 index 0000000..12a1777 --- /dev/null +++ b/gc/linked_list/append.h @@ -0,0 +1,8 @@ + +void linked_list_append( + struct linked_list* this, + struct value* value, + size_t offset); + + + diff --git a/gc/linked_list/clear.c b/gc/linked_list/clear.c new file mode 100644 index 0000000..96f19d9 --- /dev/null +++ b/gc/linked_list/clear.c @@ -0,0 +1,55 @@ + +#include + +#include "struct.h" +#include "clear.h" + +void linked_list_deep_clear( + struct linked_list* list, + size_t link_offset) +{ + ENTER; + + for (struct value* head = list->head, *next; head; head = next) + { + struct link* link = (void*) head + link_offset; + + next = link->next; + + link->prev = NULL; + link->next = NULL; + + link->in_set = false; + } + + list->head = NULL; + + list->tail = NULL; + + EXIT; +} + +void linked_list_shallow_clear( + struct linked_list* list) +{ + ENTER; + + list->head = NULL; + + list->tail = NULL; + + EXIT; +} + +void link_clear( + struct link* link) +{ + ENTER; + + link->prev = NULL; + + link->next = NULL; + + EXIT; +} + diff --git a/gc/linked_list/clear.h b/gc/linked_list/clear.h new file mode 100644 index 0000000..7649458 --- /dev/null +++ b/gc/linked_list/clear.h @@ -0,0 +1,10 @@ + +void linked_list_deep_clear( + struct linked_list* list, + size_t link_offset); + +void linked_list_shallow_clear( + struct linked_list* list); + +void link_clear( + struct link* link); diff --git a/gc/linked_list/init.c b/gc/linked_list/init.c new file mode 100644 index 0000000..c896cfd --- /dev/null +++ b/gc/linked_list/init.c @@ -0,0 +1,35 @@ + +#include + +#include "struct.h" +#include "init.h" + +void linked_list_init( + struct linked_list* list) +{ + ENTER; + + list->head = NULL; + + list->tail = NULL; + + EXIT; +} + +void link_init( + struct link* link) +{ + ENTER; + + link->in_set = false; + + link->prev = NULL; + + link->next = NULL; + + EXIT; +} + + + + diff --git a/gc/linked_list/init.h b/gc/linked_list/init.h new file mode 100644 index 0000000..8699e1a --- /dev/null +++ b/gc/linked_list/init.h @@ -0,0 +1,6 @@ + +void linked_list_init( + struct linked_list* list); + +void link_init( + struct link* link); diff --git a/gc/linked_list/pop.c b/gc/linked_list/pop.c new file mode 100644 index 0000000..a2fc9c4 --- /dev/null +++ b/gc/linked_list/pop.c @@ -0,0 +1,64 @@ + +#include + +#include + +#include "struct.h" +#include "pop.h" + +struct value* linked_list_pop( + struct linked_list* list, + size_t offset) +{ + ENTER; + + assert(list->head); + + struct value* value = list->head; + + struct link* link = (void*) value + offset; + + assert(link->in_set == true); + + if (link->next) + { + struct value* new_head = link->next; + + struct link* new_head_link = (void*) new_head + offset; + + new_head_link->prev = NULL; + + list->head = new_head; + } + else + { + // this is the last link, so we'll clear the list: + list->head = list->tail = NULL; + } + + link->in_set = false; + + #ifndef RELEASE_BUILD + // not strictly necessary, but makes the dotout easier to read. + link->next = link->prev = NULL; + #endif + + EXIT; + return value; +} + + + + + + + + + + + + + + + + diff --git a/gc/linked_list/pop.h b/gc/linked_list/pop.h new file mode 100644 index 0000000..5fa6f8d --- /dev/null +++ b/gc/linked_list/pop.h @@ -0,0 +1,4 @@ + +struct value* linked_list_pop( + struct linked_list* list, + size_t offset); diff --git a/gc/linked_list/remove.c b/gc/linked_list/remove.c new file mode 100644 index 0000000..a5d7f41 --- /dev/null +++ b/gc/linked_list/remove.c @@ -0,0 +1,65 @@ + +#include + +#include "struct.h" +#include "remove.h" + +void linked_list_remove( + struct linked_list* list, + struct value* element, + size_t link_offset) +{ + ENTER; + + assert(list->head); + + struct link* link = (void*) element + link_offset; + + assert(link->in_set); + + if (link->prev) + { + struct link* prev_link = (void*) link->prev + link_offset; + + prev_link->next = link->next; + } + else + { + list->head = link->next; + } + + if (link->next) + { + struct link* next_link = (void*) link->next + link_offset; + + next_link->prev = link->prev; + } + else + { + list->tail = link->prev; + } + + link->prev = link->next = NULL; + link->in_set = false; + + EXIT; +} + + + + + + + + + + + + + + + + + + + diff --git a/gc/linked_list/remove.h b/gc/linked_list/remove.h new file mode 100644 index 0000000..4a78a6f --- /dev/null +++ b/gc/linked_list/remove.h @@ -0,0 +1,5 @@ + +void linked_list_remove( + struct linked_list* list, + struct value* element, + size_t link_offset); diff --git a/gc/linked_list/struct.h b/gc/linked_list/struct.h new file mode 100644 index 0000000..c5e3441 --- /dev/null +++ b/gc/linked_list/struct.h @@ -0,0 +1,21 @@ + +#ifndef STRUCT_LINKED_LIST +#define STRUCT_LINKED_LIST + +struct linked_list +{ + struct value* head; + + struct value* tail; +}; + +struct link +{ + bool in_set; + + struct value* prev; + + struct value* next; +}; + +#endif diff --git a/gc/mark_as_mortal.c b/gc/mark_as_mortal.c new file mode 100644 index 0000000..1ef674c --- /dev/null +++ b/gc/mark_as_mortal.c @@ -0,0 +1,49 @@ + +#if 0 +#include +#include + +#include + +#include "struct.h" + +#include "linked_list/append.h" +#include "linked_list/remove.h" + +#include "flags.h" +#include "dotout.h" +#include "mark_as_mortal.h" + +void gc_mark_as_mortal( + struct gc* this, + struct value* value) +{ + ENTER; + + if (this->flags->dotout) + { + gc_dotout(this, "gc_mark_as_mortal: start"); + } + + assert(value->immortal.in_set); + + linked_list_remove( + /* linked list: */ &this->immortal, + /* element: */ value, + /* link offset: */ offsetof(struct value, immortal)); + + linked_list_append( + /* linked list: */ &this->mortal, + /* element: */ value, + /* link offset: */ offsetof(struct value, mortal)); + + assert(value->mortal.in_set); + + if (this->flags->dotout) + { + gc_dotout(this, "gc_mark_as_mortal: end"); + } + + EXIT; +} +#endif diff --git a/gc/mark_as_mortal.h b/gc/mark_as_mortal.h new file mode 100644 index 0000000..ccc5648 --- /dev/null +++ b/gc/mark_as_mortal.h @@ -0,0 +1,8 @@ + +#if 0 + +void gc_mark_as_mortal( + struct gc* gc, + struct value* value); + +#endif diff --git a/gc/new.c b/gc/new.c new file mode 100644 index 0000000..e4da198 --- /dev/null +++ b/gc/new.c @@ -0,0 +1,52 @@ + +#include + +#include + +#include "linked_list/init.h" + +#include "struct.h" +#include "new.h" + +struct gc* new_gc( + const struct gc_flags* flags) +{ + ENTER; + + struct gc* this = smalloc(sizeof(*this)); + + this->flags = flags; + + linked_list_init(&this->internally_referenced); + linked_list_init(&this->reaped); + linked_list_init(&this->grey); + linked_list_init(&this->white); + linked_list_init(&this->externally_referenced); + + this->bytes_currently_allocated = 0; + + this->bytes_of_last_garbage_collection = 0; + + this->blocks.data = NULL; + this->blocks.n = 0; + this->blocks.cap = 0; + + this->next_block_cap = 0; + + EXIT; + return this; +} + + + + + + + + + + + + + + diff --git a/gc/new.h b/gc/new.h new file mode 100644 index 0000000..05118a6 --- /dev/null +++ b/gc/new.h @@ -0,0 +1,3 @@ + +struct gc* new_gc( + const struct gc_flags* flags); diff --git a/gc/struct.h b/gc/struct.h new file mode 100644 index 0000000..ae5d344 --- /dev/null +++ b/gc/struct.h @@ -0,0 +1,28 @@ + +#include "linked_list/struct.h" + +struct gc +{ + const struct gc_flags* flags; // don't free. + + struct linked_list internally_referenced, externally_referenced; + struct linked_list grey, white; + struct linked_list reaped; + + size_t bytes_currently_allocated; + + size_t bytes_of_last_garbage_collection; + + struct { + struct block_info { + struct value* start; + + size_t cap; + }* data; + + size_t n, cap; + } blocks; + + size_t next_block_cap; +}; + diff --git a/main.c b/main.c new file mode 100644 index 0000000..ee832c3 --- /dev/null +++ b/main.c @@ -0,0 +1,170 @@ + +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "expand_macro.h" +#include "evaluate.h" + +int main( + int argc, char* const* argv) +{ + int i; + ENTER; + + struct cmdln_flags* flags = process_cmdln_flags(argc, argv); + + struct gc* gc = new_gc( + /* garbage collection flags: */ &flags->gc_flags); + + struct value* environments[MAX_MACRO_DEPTH + 1]; + + for (i = 0; i < MAX_MACRO_DEPTH; i++) + { + struct value* environment = new_environment_value( + /* garbage collector: */ gc, + /* fallback environment: */ NULL); + + environment_value_add_builtins( + /* this: */ environment, + /* macro-depth: */ MAX_MACRO_DEPTH - i); + + environments[i] = environment; + } + + environments[i] = new_environment_value( + /* garbage collector: */ gc, + /* fallback environment: */ NULL); + + environment_value_add_builtins( + /* this: */ environments[i], + /* macro-depth (proper evaluation is zero depth): */ 0); + + struct istream* stream = new_file_istream( + /* path: */ flags->input_file); + + istream_read(stream); + + struct tokenizer* tokenizer = new_tokenizer(stream); + + tokenizer_next_token(tokenizer); + + while (tokenizer->token != t_EOF) + { + struct value* value = parse(tokenizer, gc); + + if (flags->verbose) + { + struct stringtree* tree = value_prettyprint(value); + + stringtree_prepend_string_const(tree, "parsed: "); + + stringtree_println(tree, stdout); + + free_stringtree(tree); + } + + // macro expansions: + for (i = 0; i < MAX_MACRO_DEPTH; i++) + { + struct value* expanded = expand_macro( + /* expression: */ value, + /* environment: */ environments[i], + /* garbage collector/allocator: */ gc); + + if (flags->verbose) + { + struct stringtree* tree = value_prettyprint(expanded); + + stringtree_prepend_string_const(tree, "macro expanded: "); + + stringtree_println(tree, stdout); + + free_stringtree(tree); + } + + gc_dec_external_refcount(gc, value), value = expanded; + } + + // evaluate: + struct value* result = evaluate( + /* expression: */ value, + /* environment: */ environments[i], + /* garbage collector/allocator: */ gc); + + if (flags->verbose) + { + struct stringtree* tree = value_prettyprint(result); + + stringtree_prepend_string_const(tree, "result: "); + + stringtree_println(tree, stdout); + + free_stringtree(tree); + } + + gc_dec_external_refcount(gc, result); + gc_dec_external_refcount(gc, value); + } + + free_tokenizer(tokenizer); + + free_istream(stream); + + free_gc(gc); + + free_cmdln_flags(flags); + + EXIT; + return 0; +} + + + + + + + + + + + + + + + + + + + + + diff --git a/makefile b/makefile new file mode 100644 index 0000000..32f855d --- /dev/null +++ b/makefile @@ -0,0 +1,71 @@ + +# vim: noexpandtab tabstop=4 : + +buildtype ?= release + +optionset = buildtypes/${buildtype}.txt + +prefix = bin/${buildtype}-buildtype + +default: ${prefix}/12 + +.PRECIOUS: %/ + +%/: + @mkdir -p $@ + +srclist.mk: + find -name '*.c' -! -path '*/junk/*' | sed "s/^/srcs += /" | sort -V > ${@} + +include srclist.mk + +${prefix}/%.o ${prefix}/%.d: %.c ${optionset} | ${prefix}/%/ + @echo "compiling (${buildtype}) ${<} ..." + @gcc -c @${optionset} $< -MD -MF ${prefix}/${*}.d -o ${prefix}/${*}.o || (gedit $<; false) + +objs = $(patsubst %.c,${prefix}/%.o,${srcs}) + +${prefix}/12: ${objs} ${optionset} | ${prefix}/${1}/ + @echo "linking (${buildtype}) ${1}" + @gcc @${optionset} ${objs} -o ${@} + +#args += --garbage-collection-minimum 100B +#args += --garbage-collection-run-every 100B +#args += --garbage-collection-process-limit 200B +#args += --garbage-collection-dotout /tmp/ + +#args += --macro-expansion-dotout /tmp/ + +#args += --evaluation-dotout /tmp/ + +args += --verbose + +args += ./examples/sandbox.txt + +run: ${prefix}/12 + $< ${args} + +valrun: ${prefix}/12 + valgrind --exit-on-first-error=yes --error-exitcode=1 -- $< ${args} + +valrun-leak: ${prefix}/12 + valgrind --exit-on-first-error=yes --error-exitcode=1 --leak-check=full -- $< ${args} + +include $(patsubst %.c,${prefix}/%.d,${srcs}) + + + + + + + + + + + + + + + + + diff --git a/memory/smalloc.c b/memory/smalloc.c new file mode 100644 index 0000000..8d5de92 --- /dev/null +++ b/memory/smalloc.c @@ -0,0 +1,25 @@ + +#include +#include + +#include + +#include "smalloc.h" + +void* smalloc(size_t size) +{ + ENTER; + + dpvlu(size); + + void* ptr = malloc(size); + + if (!ptr) + { + TODO; + } + + EXIT; + return ptr; +} + diff --git a/memory/smalloc.h b/memory/smalloc.h new file mode 100644 index 0000000..63e1aa5 --- /dev/null +++ b/memory/smalloc.h @@ -0,0 +1,4 @@ + +#include + +void* smalloc(size_t size); diff --git a/memory/srealloc.c b/memory/srealloc.c new file mode 100644 index 0000000..b76269f --- /dev/null +++ b/memory/srealloc.c @@ -0,0 +1,22 @@ + +#include + +#include "srealloc.h" + +void* srealloc( + void* oldptr, + size_t size) +{ + ENTER; + + void* newptr = realloc(oldptr, size); + + if (!newptr) + { + TODO; + } + + EXIT; + return newptr; +} + diff --git a/memory/srealloc.h b/memory/srealloc.h new file mode 100644 index 0000000..1e21af7 --- /dev/null +++ b/memory/srealloc.h @@ -0,0 +1,4 @@ + +void* srealloc( + void* oldptr, + size_t size); diff --git a/parse/istream/file/free.c b/parse/istream/file/free.c new file mode 100644 index 0000000..b96d780 --- /dev/null +++ b/parse/istream/file/free.c @@ -0,0 +1,18 @@ + +#include + +#include "struct.h" +#include "free.h" + +void free_file_istream( + struct istream* super) +{ + ENTER; + + struct file_istream* this = (void*) super; + + close(this->fd); + + EXIT; +} + diff --git a/parse/istream/file/free.h b/parse/istream/file/free.h new file mode 100644 index 0000000..e57b287 --- /dev/null +++ b/parse/istream/file/free.h @@ -0,0 +1,3 @@ + +void free_file_istream( + struct istream* super); diff --git a/parse/istream/file/inheritance.c b/parse/istream/file/inheritance.c new file mode 100644 index 0000000..2628ad1 --- /dev/null +++ b/parse/istream/file/inheritance.c @@ -0,0 +1,16 @@ + +#include + +#include "../inheritance.h" + +#include "free.h" +#include "read.h" +#include "inheritance.h" + +struct istream_inheritance file_istream_inheritance = +{ + .read = file_istream_read, + + .free = free_file_istream, +}; + diff --git a/parse/istream/file/inheritance.h b/parse/istream/file/inheritance.h new file mode 100644 index 0000000..c79a5f4 --- /dev/null +++ b/parse/istream/file/inheritance.h @@ -0,0 +1,6 @@ + +#include "../inheritance.h" + +extern struct istream_inheritance file_istream_inheritance; + + diff --git a/parse/istream/file/new.c b/parse/istream/file/new.c new file mode 100644 index 0000000..ccb2f9d --- /dev/null +++ b/parse/istream/file/new.c @@ -0,0 +1,37 @@ + +#include + +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct istream* new_file_istream( + const char* input_file) +{ + ENTER; + + struct file_istream* this = (void*) new_istream( + &file_istream_inheritance, + sizeof(*this)); + + int fd = open(input_file, O_RDONLY); + + if (fd < 0) + { + TODO; + } + + this->fd = fd; + + this->i = 0; + this->n = 0; + + EXIT; + return (void*) this; +} + + + + diff --git a/parse/istream/file/new.h b/parse/istream/file/new.h new file mode 100644 index 0000000..638002a --- /dev/null +++ b/parse/istream/file/new.h @@ -0,0 +1,3 @@ + +struct istream* new_file_istream( + const char* input_file); diff --git a/parse/istream/file/read.c b/parse/istream/file/read.c new file mode 100644 index 0000000..3731022 --- /dev/null +++ b/parse/istream/file/read.c @@ -0,0 +1,45 @@ + +#include + +#include "struct.h" +#include "read.h" + +void file_istream_read( + struct istream* super) +{ + ENTER; + + struct file_istream* this = (void*) super; + + if (this->i < this->n) + { + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + else + { + ssize_t read_retval = read(this->fd, this->buffer, sizeof(this->buffer)); + + if (read_retval < 0) + { + TODO; + } + else if (!read_retval) + { + super->c = 0; + } + else + { + this->i = 0; + this->n = read_retval; + + super->c = this->buffer[this->i++]; + + dpvc(super->c); + } + } + + EXIT; +} + diff --git a/parse/istream/file/read.h b/parse/istream/file/read.h new file mode 100644 index 0000000..986c836 --- /dev/null +++ b/parse/istream/file/read.h @@ -0,0 +1,3 @@ + +void file_istream_read( + struct istream* this); diff --git a/parse/istream/file/struct.h b/parse/istream/file/struct.h new file mode 100644 index 0000000..ef1acb0 --- /dev/null +++ b/parse/istream/file/struct.h @@ -0,0 +1,15 @@ + +#include "../struct.h" + +struct file_istream +{ + struct istream super; + + int fd; + + uint8_t buffer[4096]; + + size_t i, n; +}; + + diff --git a/parse/istream/free.c b/parse/istream/free.c new file mode 100644 index 0000000..afa507b --- /dev/null +++ b/parse/istream/free.c @@ -0,0 +1,26 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "free.h" + +void free_istream( + struct istream* this) +{ + ENTER; + + if (this && !--this->refcount) + { + assert(this); + assert(this->inheritance); + assert(this->inheritance->free); + + (this->inheritance->free)(this); + + free(this); + } + + EXIT; +} + diff --git a/parse/istream/free.h b/parse/istream/free.h new file mode 100644 index 0000000..9813ada --- /dev/null +++ b/parse/istream/free.h @@ -0,0 +1,3 @@ + +void free_istream( + struct istream* this); diff --git a/parse/istream/inc.c b/parse/istream/inc.c new file mode 100644 index 0000000..97848f2 --- /dev/null +++ b/parse/istream/inc.c @@ -0,0 +1,15 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct istream* inc_istream( + struct istream* this) +{ + if (this) + this->refcount++; + + return this; +} + diff --git a/parse/istream/inc.h b/parse/istream/inc.h new file mode 100644 index 0000000..71f5e4b --- /dev/null +++ b/parse/istream/inc.h @@ -0,0 +1,3 @@ + +struct istream* inc_istream( + struct istream* this); diff --git a/parse/istream/inheritance.h b/parse/istream/inheritance.h new file mode 100644 index 0000000..4d53c89 --- /dev/null +++ b/parse/istream/inheritance.h @@ -0,0 +1,14 @@ + +#ifndef STRUCT_ISTREAM_INHERITANCE +#define STRUCT_ISTREAM_INHERITANCE + +struct istream_inheritance +{ + void (*read)( + struct istream*); + + void (*free)( + struct istream*); +}; + +#endif diff --git a/parse/istream/new.c b/parse/istream/new.c new file mode 100644 index 0000000..c22798a --- /dev/null +++ b/parse/istream/new.c @@ -0,0 +1,26 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct istream* new_istream( + const struct istream_inheritance* inheritance, + size_t alloc_size) +{ + ENTER; + + struct istream* this = smalloc(alloc_size); + + this->inheritance = inheritance; + + this->c = 0; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/istream/new.h b/parse/istream/new.h new file mode 100644 index 0000000..d521732 --- /dev/null +++ b/parse/istream/new.h @@ -0,0 +1,6 @@ + + +struct istream* new_istream( + const struct istream_inheritance* inheritance, + size_t alloc_size); + diff --git a/parse/istream/read.c b/parse/istream/read.c new file mode 100644 index 0000000..1a6d893 --- /dev/null +++ b/parse/istream/read.c @@ -0,0 +1,21 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "read.h" + +void istream_read( + struct istream* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->read); + + (this->inheritance->read)(this); + + EXIT; +} + diff --git a/parse/istream/read.h b/parse/istream/read.h new file mode 100644 index 0000000..c052b84 --- /dev/null +++ b/parse/istream/read.h @@ -0,0 +1,3 @@ + +void istream_read( + struct istream* this); diff --git a/parse/istream/struct.h b/parse/istream/struct.h new file mode 100644 index 0000000..ee53430 --- /dev/null +++ b/parse/istream/struct.h @@ -0,0 +1,12 @@ + +struct istream_inheritance; + +struct istream +{ + const struct istream_inheritance* inheritance; + + uint8_t c; + + unsigned refcount; +}; + diff --git a/parse/parse.c b/parse/parse.c new file mode 100644 index 0000000..bc90ff6 --- /dev/null +++ b/parse/parse.c @@ -0,0 +1,182 @@ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tokenizer/struct.h" +#include "tokenizer/next.h" + +#include "parse.h" + +struct value* parse( + struct tokenizer* tokenizer, + struct gc* gc) +{ + struct value* retval; + ENTER; + + switch (tokenizer->token) + { + case t_null: + { + retval = new_null_value(gc); + + tokenizer_next_token(tokenizer); + break; + } + + case t_true: + { + retval = new_boolean_value(gc, true); + + tokenizer_next_token(tokenizer); + break; + } + + case t_false: + { + retval = new_boolean_value(gc, false); + + tokenizer_next_token(tokenizer); + break; + } + + case t_integer: + { + intmax_t val; + + const char* s = tokenizer->rawtoken.data; + + char *m; + + errno = 0; + + val = strtoul(s, &m, 0); + + if (errno || *m) + { + TODO; + } + + retval = new_integer_value(gc, val); + + tokenizer_next_token(tokenizer); + break; + } + + case t_identifier: + { + dpvs(tokenizer->rawtoken.data); + + struct string* string = new_string( + /* data: */ tokenizer->rawtoken.data, + /* len: */ tokenizer->rawtoken.n); + + retval = new_identifier_value(gc, string); + + tokenizer_next_token(tokenizer); + + free_string(string); + break; + } + + case t_gravemark: + { + tokenizer_next_token(tokenizer); + + struct value* subexpression = parse( + /* tokenizer: */ tokenizer, + /* garbage collector: */ gc); + + retval = new_quote_value(gc, subexpression); + + gc_dec_external_refcount(gc, subexpression); + break; + } + + case t_oparen: + { + tokenizer_next_token(tokenizer); + + struct value *head = NULL, *tail = NULL; + + while (tokenizer->token != t_cparen) + { + struct value* element = parse(tokenizer, gc); + + struct value* link = new_list_value(gc, element); + + if (tail) + { + tail->subclass.list.rest = link; + + gc_dec_external_refcount(gc, tail); + tail = gc_inc_external_refcount(gc, link); + } + else + { + retval = gc_inc_external_refcount(gc, link); + + head = gc_inc_external_refcount(gc, link); + tail = gc_inc_external_refcount(gc, link); + } + + gc_dec_external_refcount(gc, link); + gc_dec_external_refcount(gc, element); + } + + struct value* null = new_null_value(gc); + + // append null sentiental: + if (tail) + { + tail->subclass.list.rest = null; + } + else + { + retval = gc_inc_external_refcount(gc, null); + } + + gc_dec_external_refcount(gc, head); + gc_dec_external_refcount(gc, tail); + gc_dec_external_refcount(gc, null); + + tokenizer_next_token(tokenizer); + break; + } + + default: + TODO; + break; + } + + EXIT; + return retval; +} + + + + + + + + + + + + + + + diff --git a/parse/parse.h b/parse/parse.h new file mode 100644 index 0000000..f63d969 --- /dev/null +++ b/parse/parse.h @@ -0,0 +1,4 @@ + +struct value* parse( + struct tokenizer* tokenizer, + struct gc* gc); diff --git a/parse/tokenizer/free.c b/parse/tokenizer/free.c new file mode 100644 index 0000000..e13e887 --- /dev/null +++ b/parse/tokenizer/free.c @@ -0,0 +1,25 @@ + +#include + +#include "../istream/free.h" + +#include "struct.h" +#include "free.h" + +void free_tokenizer( + struct tokenizer* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free(this->rawtoken.data); + + free_istream(this->stream); + + free(this); + } + + EXIT; +} + diff --git a/parse/tokenizer/free.h b/parse/tokenizer/free.h new file mode 100644 index 0000000..13b0b22 --- /dev/null +++ b/parse/tokenizer/free.h @@ -0,0 +1,3 @@ + +void free_tokenizer( + struct tokenizer* this); diff --git a/parse/tokenizer/new.c b/parse/tokenizer/new.c new file mode 100644 index 0000000..a22e893 --- /dev/null +++ b/parse/tokenizer/new.c @@ -0,0 +1,31 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct tokenizer* new_tokenizer( + struct istream* stream) +{ + ENTER; + + struct tokenizer* this = smalloc(sizeof(*this)); + + this->stream = inc_istream(stream); + + this->token = t_uninitalized; + + this->rawtoken.data = NULL; + this->rawtoken.n = 0; + this->rawtoken.cap = 0; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/parse/tokenizer/new.h b/parse/tokenizer/new.h new file mode 100644 index 0000000..ba006d2 --- /dev/null +++ b/parse/tokenizer/new.h @@ -0,0 +1,4 @@ + + +struct tokenizer* new_tokenizer( + struct istream* stream); diff --git a/parse/tokenizer/next.c b/parse/tokenizer/next.c new file mode 100644 index 0000000..e7523bf --- /dev/null +++ b/parse/tokenizer/next.c @@ -0,0 +1,354 @@ + +#include + +#include + +#include +#include + +#include "struct.h" +#include "next.h" + +static const enum state { + s_error, + + s_EOF, + + s_null, + + s_true, + + s_false, + + s_integer, + + // symbols: + s_gravemark, + s_oparen, + s_cparen, + + s_identifier, + + s_start, + + s_skipping_comment, + + s_reading_oparen, + s_reading_cparen, + + s_reading_integer, + + s_reading_identifier, + + s_reading_gravemark, + + s_reading_n, + s_reading_nu, + s_reading_nul, + s_reading_null, + + s_reading_t, + s_reading_tr, + s_reading_tru, + s_reading_true, + + s_reading_f, + s_reading_fa, + s_reading_fal, + s_reading_fals, + s_reading_false, + + number_of_states, +} lookup[number_of_states][256] = { + + #define ANY 0 ... 255 + + // EOF: + [s_start][0] = s_EOF, + + // skip whitespace + [s_start][' '] = s_start, + [s_start]['\t'] = s_start, + [s_start]['\n'] = s_start, + + // skip comments: + [s_start]['#'] = s_skipping_comment, + [s_skipping_comment][ANY] = s_skipping_comment, + [s_skipping_comment]['\n'] = s_start, + + // brackets: + [s_start]['('] = s_reading_oparen, + [s_reading_oparen][ANY] = s_oparen, + [s_start][')'] = s_reading_cparen, + [s_reading_cparen][ANY] = s_cparen, + + // symbols: + [s_start]['`'] = s_reading_gravemark, + [s_reading_gravemark][ANY] = s_gravemark, + + // integer literals: + [s_start]['0' ... '9'] = s_reading_integer, + [s_reading_integer][ ANY ] = s_integer, + [s_reading_integer]['0' ... '9'] = s_reading_integer, + + // identifiers + [s_start]['?'] = s_reading_identifier, + [s_start]['!'] = s_reading_identifier, + [s_start]['>'] = s_reading_identifier, + [s_start]['<'] = s_reading_identifier, + [s_start]['='] = s_reading_identifier, + [s_start]['+'] = s_reading_identifier, + [s_start]['*'] = s_reading_identifier, + [s_start]['_'] = s_reading_identifier, + [s_start]['-'] = s_reading_identifier, + [s_start]['/'] = s_reading_identifier, + [s_start]['a' ... 'z'] = s_reading_identifier, + [s_start]['A' ... 'Z'] = s_reading_identifier, + [s_reading_identifier][ANY] = s_identifier, + [s_reading_identifier][':'] = s_reading_identifier, + [s_reading_identifier]['='] = s_reading_identifier, + [s_reading_identifier]['!'] = s_reading_identifier, + [s_reading_identifier]['+'] = s_reading_identifier, + [s_reading_identifier]['*'] = s_reading_identifier, + [s_reading_identifier]['_'] = s_reading_identifier, + [s_reading_identifier]['/'] = s_reading_identifier, + [s_reading_identifier]['-'] = s_reading_identifier, + [s_reading_identifier]['a' ... 'z'] = s_reading_identifier, + [s_reading_identifier]['A' ... 'Z'] = s_reading_identifier, + [s_reading_identifier]['0' ... '9'] = s_reading_identifier, + + // "null" keyword: + [s_start]['n'] = s_reading_n, + [s_reading_n][ANY] = s_identifier, + [s_reading_n]['_'] = s_reading_identifier, + [s_reading_n]['-'] = s_reading_identifier, + [s_reading_n]['a' ... 'z'] = s_reading_identifier, + [s_reading_n]['A' ... 'Z'] = s_reading_identifier, + [s_reading_n]['u'] = s_reading_nu, + [s_reading_nu][ANY] = s_identifier, + [s_reading_nu]['_'] = s_reading_identifier, + [s_reading_nu]['-'] = s_reading_identifier, + [s_reading_nu]['a' ... 'z'] = s_reading_identifier, + [s_reading_nu]['A' ... 'Z'] = s_reading_identifier, + [s_reading_nu]['l'] = s_reading_nul, + [s_reading_nul][ANY] = s_identifier, + [s_reading_nul]['_'] = s_reading_identifier, + [s_reading_nul]['-'] = s_reading_identifier, + [s_reading_nul]['a' ... 'z'] = s_reading_identifier, + [s_reading_nul]['A' ... 'Z'] = s_reading_identifier, + [s_reading_nul]['l'] = s_reading_null, + [s_reading_null][ANY] = s_null, + [s_reading_null]['_'] = s_reading_identifier, + [s_reading_null]['-'] = s_reading_identifier, + [s_reading_null]['a' ... 'z'] = s_reading_identifier, + [s_reading_null]['A' ... 'Z'] = s_reading_identifier, + + // "true" keyword: + [s_start]['t'] = s_reading_t, + [s_reading_t][ANY] = s_identifier, + [s_reading_t]['_'] = s_reading_identifier, + [s_reading_t]['-'] = s_reading_identifier, + [s_reading_t]['a' ... 'z'] = s_reading_identifier, + [s_reading_t]['A' ... 'Z'] = s_reading_identifier, + [s_reading_t]['r'] = s_reading_tr, + [s_reading_tr][ANY] = s_identifier, + [s_reading_tr]['_'] = s_reading_identifier, + [s_reading_tr]['-'] = s_reading_identifier, + [s_reading_tr]['a' ... 'z'] = s_reading_identifier, + [s_reading_tr]['A' ... 'Z'] = s_reading_identifier, + [s_reading_tr]['u'] = s_reading_tru, + [s_reading_tru][ANY] = s_identifier, + [s_reading_tru]['_'] = s_reading_identifier, + [s_reading_tru]['-'] = s_reading_identifier, + [s_reading_tru]['a' ... 'z'] = s_reading_identifier, + [s_reading_tru]['A' ... 'Z'] = s_reading_identifier, + [s_reading_tru]['e'] = s_reading_true, + [s_reading_true][ANY] = s_true, + [s_reading_true]['_'] = s_reading_identifier, + [s_reading_true]['-'] = s_reading_identifier, + [s_reading_true]['a' ... 'z'] = s_reading_identifier, + [s_reading_true]['A' ... 'Z'] = s_reading_identifier, + + // "false" keyword: + [s_start]['f'] = s_reading_f, + [s_reading_f][ANY] = s_identifier, + [s_reading_f]['_'] = s_reading_identifier, + [s_reading_f]['-'] = s_reading_identifier, + [s_reading_f]['a' ... 'z'] = s_reading_identifier, + [s_reading_f]['A' ... 'Z'] = s_reading_identifier, + [s_reading_f]['a'] = s_reading_fa, + [s_reading_fa][ANY] = s_identifier, + [s_reading_fa]['_'] = s_reading_identifier, + [s_reading_fa]['-'] = s_reading_identifier, + [s_reading_fa]['a' ... 'z'] = s_reading_identifier, + [s_reading_fa]['A' ... 'Z'] = s_reading_identifier, + [s_reading_fa]['l'] = s_reading_fal, + [s_reading_fal][ANY] = s_identifier, + [s_reading_fal]['_'] = s_reading_identifier, + [s_reading_fal]['-'] = s_reading_identifier, + [s_reading_fal]['a' ... 'z'] = s_reading_identifier, + [s_reading_fal]['A' ... 'Z'] = s_reading_identifier, + [s_reading_fal]['s'] = s_reading_fals, + [s_reading_fals][ANY] = s_identifier, + [s_reading_fals]['_'] = s_reading_identifier, + [s_reading_fals]['-'] = s_reading_identifier, + [s_reading_fals]['a' ... 'z'] = s_reading_identifier, + [s_reading_fals]['A' ... 'Z'] = s_reading_identifier, + [s_reading_fals]['e'] = s_reading_false, + [s_reading_false][ANY] = s_false, + [s_reading_false]['_'] = s_reading_identifier, + [s_reading_false]['-'] = s_reading_identifier, + [s_reading_false]['a' ... 'z'] = s_reading_identifier, + [s_reading_false]['A' ... 'Z'] = s_reading_identifier, +}; + +void tokenizer_next_token( + struct tokenizer* this) +{ + ENTER; + + this->rawtoken.n = 0; + + void append(uint8_t c) + { + ENTER; + + if (this->rawtoken.n == this->rawtoken.cap) + { + this->rawtoken.cap = this->rawtoken.cap << 1 ?: 1; + + this->rawtoken.data = srealloc( + this->rawtoken.data, + sizeof(*this->rawtoken.data) * this->rawtoken.cap); + } + + this->rawtoken.data[this->rawtoken.n++] = c; + + EXIT; + } + + enum state state = s_start; + + while (state >= s_start) + { + dpvc(this->stream->c); + + state = lookup[state][this->stream->c]; + + if (state > s_start) + { + append(this->stream->c); + + istream_read(this->stream); + } + + if (state == s_start) + { + this->rawtoken.n = 0; + + istream_read(this->stream); + } + } + + append(0), this->rawtoken.n--; + + switch (state) + { + case s_error: + { + TODO; + + break; + } + + case s_EOF: + { + this->token = t_EOF; + + break; + } + + case s_gravemark: + { + this->token = t_gravemark; + + break; + } + + case s_oparen: + { + this->token = t_oparen; + + break; + } + + case s_cparen: + { + this->token = t_cparen; + + break; + } + + case s_null: + { + this->token = t_null; + + break; + } + + case s_true: + { + this->token = t_true; + + break; + } + + case s_false: + { + this->token = t_false; + + break; + } + + case s_identifier: + { + this->token = t_identifier; + + break; + } + + case s_integer: + { + this->token = t_integer; + + break; + } + + default: + TODO; + break; + } + + EXIT; +} + + + + + + + + + + + + + + + + + + + + + diff --git a/parse/tokenizer/next.h b/parse/tokenizer/next.h new file mode 100644 index 0000000..e6d02c3 --- /dev/null +++ b/parse/tokenizer/next.h @@ -0,0 +1,3 @@ + +void tokenizer_next_token( + struct tokenizer* this); diff --git a/parse/tokenizer/struct.h b/parse/tokenizer/struct.h new file mode 100644 index 0000000..856a754 --- /dev/null +++ b/parse/tokenizer/struct.h @@ -0,0 +1,18 @@ + +#include "token.h" + +struct tokenizer +{ + struct istream* stream; // needs to free after. + + enum token token; + + struct { + char* data; + + size_t n, cap; + } rawtoken; + + unsigned refcount; +}; + diff --git a/parse/tokenizer/token.h b/parse/tokenizer/token.h new file mode 100644 index 0000000..0ffdbe9 --- /dev/null +++ b/parse/tokenizer/token.h @@ -0,0 +1,24 @@ + +enum token +{ + t_uninitalized, + + t_EOF, + + t_null, + + t_true, + + t_false, + + t_identifier, + + t_oparen, + t_cparen, + + t_integer, + + t_gravemark, + +}; + diff --git a/srclist.mk b/srclist.mk new file mode 100644 index 0000000..1be8810 --- /dev/null +++ b/srclist.mk @@ -0,0 +1,133 @@ +srcs += ./avl/avl.c +srcs += ./builtins/arithmetic/add.c +srcs += ./builtins/arithmetic/div.c +srcs += ./builtins/arithmetic/mul.c +srcs += ./builtins/arithmetic/rem.c +srcs += ./builtins/arithmetic/sub.c +srcs += ./builtins/comparision/equal_to.c +srcs += ./builtins/comparision/greater_than.c +srcs += ./builtins/comparision/greater_than_equal_to.c +srcs += ./builtins/comparision/less_than.c +srcs += ./builtins/comparision/less_than_equal_to.c +srcs += ./builtins/comparision/not_equal_to.c +srcs += ./builtins/core/define.c +srcs += ./builtins/core/ifelse.c +srcs += ./builtins/core/lambda.c +srcs += ./builtins/core/let.c +srcs += ./builtins/core/letrec.c +srcs += ./builtins/list/cons.c +srcs += ./builtins/list/list.c +srcs += ./builtins/logical/and.c +srcs += ./builtins/logical/not.c +srcs += ./builtins/logical/or.c +srcs += ./cmdln/free.c +srcs += ./cmdln/process.c +srcs += ./debug.c +srcs += ./evaluate.c +srcs += ./expand_macro.c +srcs += ./gc/allocate_node.c +srcs += ./gc/dec_external_refcount.c +srcs += ./gc/dotout.c +srcs += ./gc/free.c +srcs += ./gc/inc_external_refcount.c +srcs += ./gc/linked_list/append.c +srcs += ./gc/linked_list/clear.c +srcs += ./gc/linked_list/init.c +srcs += ./gc/linked_list/pop.c +srcs += ./gc/linked_list/remove.c +srcs += ./gc/mark_as_mortal.c +srcs += ./gc/new.c +srcs += ./main.c +srcs += ./memory/smalloc.c +srcs += ./memory/srealloc.c +srcs += ./parse/istream/file/free.c +srcs += ./parse/istream/file/inheritance.c +srcs += ./parse/istream/file/new.c +srcs += ./parse/istream/file/read.c +srcs += ./parse/istream/free.c +srcs += ./parse/istream/inc.c +srcs += ./parse/istream/new.c +srcs += ./parse/istream/read.c +srcs += ./parse/parse.c +srcs += ./parse/tokenizer/free.c +srcs += ./parse/tokenizer/new.c +srcs += ./parse/tokenizer/next.c +srcs += ./stringtree/append.c +srcs += ./stringtree/free.c +srcs += ./stringtree/inc.c +srcs += ./stringtree/new.c +srcs += ./stringtree/prepend.c +srcs += ./stringtree/print.c +srcs += ./stringtree/println.c +srcs += ./string/compare.c +srcs += ./string/free.c +srcs += ./string/inc.c +srcs += ./string/new.c +srcs += ./value/boolean/compare.c +srcs += ./value/boolean/foreach_accessible_subvalue.c +srcs += ./value/boolean/inheritance.c +srcs += ./value/boolean/new.c +srcs += ./value/boolean/prettyprint.c +srcs += ./value/boolean/shallow_free.c +srcs += ./value/builtin_lambda/compare.c +srcs += ./value/builtin_lambda/foreach_accessible_subvalue.c +srcs += ./value/builtin_lambda/inheritance.c +srcs += ./value/builtin_lambda/new.c +srcs += ./value/builtin_lambda/prettyprint.c +srcs += ./value/builtin_lambda/shallow_free.c +srcs += ./value/compare.c +srcs += ./value/environment/add_builtins.c +srcs += ./value/environment/compare.c +srcs += ./value/environment/define.c +srcs += ./value/environment/foreach_accessible_subvalue.c +srcs += ./value/environment/inheritance.c +srcs += ./value/environment/lookup.c +srcs += ./value/environment/new.c +srcs += ./value/environment/prettyprint.c +srcs += ./value/environment/shallow_free.c +srcs += ./value/environment/variable/compare.c +srcs += ./value/environment/variable/free.c +srcs += ./value/environment/variable/new.c +srcs += ./value/foreach_accessible_subvalue.c +srcs += ./value/identifier/compare.c +srcs += ./value/identifier/foreach_accessible_subvalue.c +srcs += ./value/identifier/inheritance.c +srcs += ./value/identifier/new.c +srcs += ./value/identifier/prettyprint.c +srcs += ./value/identifier/shallow_free.c +srcs += ./value/integer/compare.c +srcs += ./value/integer/foreach_accessible_subvalue.c +srcs += ./value/integer/inheritance.c +srcs += ./value/integer/new.c +srcs += ./value/integer/prettyprint.c +srcs += ./value/integer/shallow_free.c +srcs += ./value/list/compare.c +srcs += ./value/list/foreach_accessible_subvalue.c +srcs += ./value/list/inheritance.c +srcs += ./value/list/new.c +srcs += ./value/list/prettyprint.c +srcs += ./value/list/shallow_free.c +srcs += ./value/new.c +srcs += ./value/null/compare.c +srcs += ./value/null/foreach_accessible_subvalue.c +srcs += ./value/null/inheritance.c +srcs += ./value/null/new.c +srcs += ./value/null/prettyprint.c +srcs += ./value/null/shallow_free.c +srcs += ./value/prettyprint.c +srcs += ./value/quote/compare.c +srcs += ./value/quote/foreach_accessible_subvalue.c +srcs += ./value/quote/inheritance.c +srcs += ./value/quote/new.c +srcs += ./value/quote/prettyprint.c +srcs += ./value/quote/shallow_free.c +srcs += ./value/shallow_free.c +srcs += ./value/string/compare.c +srcs += ./value/string/prettyprint.c +srcs += ./value/string/shallow_free.c +srcs += ./value/user_lambda/compare.c +srcs += ./value/user_lambda/foreach_accessible_subvalue.c +srcs += ./value/user_lambda/inheritance.c +srcs += ./value/user_lambda/new.c +srcs += ./value/user_lambda/prettyprint.c +srcs += ./value/user_lambda/shallow_free.c diff --git a/string/compare.c b/string/compare.c new file mode 100644 index 0000000..15c0090 --- /dev/null +++ b/string/compare.c @@ -0,0 +1,15 @@ + +#include + +#include + +#include "struct.h" +#include "compare.h" + +int compare_strings( + const struct string* a, + const struct string* b) +{ + return strcmp((void*) a->data, (void*) b->data); +} + diff --git a/string/compare.h b/string/compare.h new file mode 100644 index 0000000..527e90b --- /dev/null +++ b/string/compare.h @@ -0,0 +1,4 @@ + +int compare_strings( + const struct string* a, + const struct string* b); diff --git a/string/free.c b/string/free.c new file mode 100644 index 0000000..5fc5081 --- /dev/null +++ b/string/free.c @@ -0,0 +1,19 @@ + +#include + +#include "struct.h" +#include "free.h" + +void free_string( + struct string* this) +{ + ENTER; + + if (this && !--this->refcount) + { + free(this->data); + free(this); + } + + EXIT; +} diff --git a/string/free.h b/string/free.h new file mode 100644 index 0000000..cebb049 --- /dev/null +++ b/string/free.h @@ -0,0 +1,3 @@ + +void free_string( + struct string* this); diff --git a/string/inc.c b/string/inc.c new file mode 100644 index 0000000..71af1cf --- /dev/null +++ b/string/inc.c @@ -0,0 +1,18 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct string* inc_string( + struct string* this) +{ + ENTER; + + if (this) + this->refcount++; + + EXIT; + return this; +} + diff --git a/string/inc.h b/string/inc.h new file mode 100644 index 0000000..edbd190 --- /dev/null +++ b/string/inc.h @@ -0,0 +1,3 @@ + +struct string* inc_string( + struct string* this); diff --git a/string/new.c b/string/new.c new file mode 100644 index 0000000..aa1bb12 --- /dev/null +++ b/string/new.c @@ -0,0 +1,93 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct string* new_string( + const char* str, + size_t olen) +{ + ENTER; + + struct string* this = smalloc(sizeof(*this)); + + uint8_t* copy = (void*) strndup(str, olen); + + unsigned len = strlen((void*) copy); + + this->data = copy; + this->n = len; + this->refcount = 1; + + EXIT; + return this; +} + +struct string* new_string_from_format( + const char* fmt, ...) +{ + ENTER; + + TODO; + + EXIT; +/* return this;*/ +} + +struct string* new_string_from_vargs( + const char* fmt, va_list va) +{ + ENTER; + + char* buffer = NULL; + + int ret = vasprintf(&buffer, fmt, va); + + if (ret < 0) + { + TODO; + } + + struct string* new = new_string(buffer, ret); + + free(buffer); + + EXIT; + return new; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/string/new.h b/string/new.h new file mode 100644 index 0000000..0af85de --- /dev/null +++ b/string/new.h @@ -0,0 +1,10 @@ + +struct string* new_string( + const char* str, + size_t len); + +struct string* new_string_from_format( + const char* fmt, ...); + +struct string* new_string_from_vargs( + const char* fmt, va_list va); diff --git a/string/struct.h b/string/struct.h new file mode 100644 index 0000000..6c0a799 --- /dev/null +++ b/string/struct.h @@ -0,0 +1,9 @@ + +struct string +{ + uint8_t* data; + size_t n; + + unsigned refcount; +}; + diff --git a/stringtree/append.c b/stringtree/append.c new file mode 100644 index 0000000..4744bff --- /dev/null +++ b/stringtree/append.c @@ -0,0 +1,154 @@ + +#include + +#include + +#include +#include +#include + +#include "inc.h" +#include "struct.h" +#include "append.h" + +void stringtree_append_string_const( + struct stringtree* this, + const char* cstr) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_cstr; + new->cstr = cstr; + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + +void stringtree_append_formatstr( + struct stringtree* this, + const char* fmt, ...) +{ + ENTER; + + va_list va; + + va_start(va, fmt); + + struct string* string = new_string_from_vargs(fmt, va); + + stringtree_append_string(this, string); + + free_string(string); + + va_end(va); + + EXIT; +} + +void stringtree_append_string( + struct stringtree* this, + struct string* string) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_string; + new->string = inc_string(string); + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + +void stringtree_append_stringtree( + struct stringtree* this, + struct stringtree* stringtree) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_stringtree; + new->stringtree = inc_stringtree(stringtree); + new->prev = NULL; + new->next = NULL; + + if (this->tail) + { + this->tail->next = new; + new->prev = this->tail; + + this->tail = new; + } + else + { + this->head = new; + this->tail = new; + } + + EXIT; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/stringtree/append.h b/stringtree/append.h new file mode 100644 index 0000000..fa7dd25 --- /dev/null +++ b/stringtree/append.h @@ -0,0 +1,20 @@ + +struct stringtree; +struct string; + +void stringtree_append_string( + struct stringtree* this, + struct string* string); + + +void stringtree_append_string_const( + struct stringtree* this, + const char* cstr); + +void stringtree_append_formatstr( + struct stringtree* this, + const char* fmt, ...); + +void stringtree_append_stringtree( + struct stringtree* this, + struct stringtree* subtree); diff --git a/stringtree/free.c b/stringtree/free.c new file mode 100644 index 0000000..c51f851 --- /dev/null +++ b/stringtree/free.c @@ -0,0 +1,46 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_stringtree( + struct stringtree* this) +{ + ENTER; + + if (this && !--this->refcount) + { + for (struct child* child = this->head, *next; child; child = next) + { + switch (child->kind) + { + case ck_cstr: + break; + + case ck_string: + free_string(child->string); + break; + + case ck_stringtree: + free_stringtree(child->stringtree); + break; + + default: + TODO; + break; + } + + next = child->next; + + free(child); + } + + free(this); + } + + EXIT; +} + diff --git a/stringtree/free.h b/stringtree/free.h new file mode 100644 index 0000000..a9574db --- /dev/null +++ b/stringtree/free.h @@ -0,0 +1,3 @@ + +void free_stringtree( + struct stringtree* this); diff --git a/stringtree/inc.c b/stringtree/inc.c new file mode 100644 index 0000000..a548e85 --- /dev/null +++ b/stringtree/inc.c @@ -0,0 +1,18 @@ + +#include + +#include "struct.h" +#include "inc.h" + +struct stringtree* inc_stringtree( + struct stringtree* this) +{ + ENTER; + + if (this) + this->refcount++; + + EXIT; + return this; +} + diff --git a/stringtree/inc.h b/stringtree/inc.h new file mode 100644 index 0000000..c9936a2 --- /dev/null +++ b/stringtree/inc.h @@ -0,0 +1,3 @@ + +struct stringtree* inc_stringtree( + struct stringtree* this); diff --git a/stringtree/new.c b/stringtree/new.c new file mode 100644 index 0000000..f673212 --- /dev/null +++ b/stringtree/new.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct stringtree* new_stringtree(void) +{ + ENTER; + + struct stringtree* this = smalloc(sizeof(*this)); + + this->head = NULL; + this->tail = NULL; + + this->refcount = 1; + + EXIT; + return this; +} + diff --git a/stringtree/new.h b/stringtree/new.h new file mode 100644 index 0000000..d1bd579 --- /dev/null +++ b/stringtree/new.h @@ -0,0 +1,2 @@ + +struct stringtree* new_stringtree(void); diff --git a/stringtree/prepend.c b/stringtree/prepend.c new file mode 100644 index 0000000..877de06 --- /dev/null +++ b/stringtree/prepend.c @@ -0,0 +1,36 @@ + +#include + +#include + +#include "struct.h" +#include "prepend.h" + +void stringtree_prepend_string_const( + struct stringtree* this, + const char* cstr) +{ + ENTER; + + struct child* new = smalloc(sizeof(*new)); + + new->kind = ck_cstr; + new->cstr = cstr; + new->prev = NULL; + new->next = NULL; + + if (this->head) + { + new->next = this->head; + this->head->prev = new; + + this->head = new; + } + else + { + TODO; + } + + EXIT; +} + diff --git a/stringtree/prepend.h b/stringtree/prepend.h new file mode 100644 index 0000000..8d7b46c --- /dev/null +++ b/stringtree/prepend.h @@ -0,0 +1,4 @@ + +void stringtree_prepend_string_const( + struct stringtree* this, + const char* literal); diff --git a/stringtree/print.c b/stringtree/print.c new file mode 100644 index 0000000..447adc7 --- /dev/null +++ b/stringtree/print.c @@ -0,0 +1,64 @@ + +#include + +#include + +#include "struct.h" +#include "print.h" + +void stringtree_print( + const struct stringtree* this, + FILE* stream) +{ + ENTER; + + for (struct child* child = this->head; child; child = child->next) + { + switch (child->kind) + { + case ck_cstr: + { + fputs(child->cstr, stream); + + break; + } + + case ck_string: + { + fputs((void*) child->string->data, stream); + + break; + } + + case ck_stringtree: + { + stringtree_print( + /* subtree: */ child->stringtree, + /* stream: */ stream); + + break; + } + + default: + TODO; + break; + } + } + + EXIT; +} + + + + + + + + + + + + + + + diff --git a/stringtree/print.h b/stringtree/print.h new file mode 100644 index 0000000..1ec3fcf --- /dev/null +++ b/stringtree/print.h @@ -0,0 +1,4 @@ + +void stringtree_print( + const struct stringtree* this, + FILE* stream); diff --git a/stringtree/println.c b/stringtree/println.c new file mode 100644 index 0000000..111e618 --- /dev/null +++ b/stringtree/println.c @@ -0,0 +1,17 @@ + +#include + +#include "print.h" +#include "println.h" + +void stringtree_println( + const struct stringtree* this, + FILE* stream) +{ + ENTER; + + stringtree_print(this, stream), fputs("\n", stream); + + EXIT; +} + diff --git a/stringtree/println.h b/stringtree/println.h new file mode 100644 index 0000000..cb3d856 --- /dev/null +++ b/stringtree/println.h @@ -0,0 +1,4 @@ + +void stringtree_println( + const struct stringtree* this, + FILE* stream); diff --git a/stringtree/struct.h b/stringtree/struct.h new file mode 100644 index 0000000..afa089e --- /dev/null +++ b/stringtree/struct.h @@ -0,0 +1,25 @@ + +struct stringtree +{ + struct child + { + enum child_kind { + ck_cstr, + ck_string, + ck_stringtree, + } kind; + + union { + const char* cstr; + + struct string* string; + + struct stringtree* stringtree; + }; + + struct child *prev, *next; + } *head, *tail; + + unsigned refcount; +}; + diff --git a/value/boolean/compare.c b/value/boolean/compare.c new file mode 100644 index 0000000..10c6527 --- /dev/null +++ b/value/boolean/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_boolean_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/boolean/compare.h b/value/boolean/compare.h new file mode 100644 index 0000000..f4e7ba2 --- /dev/null +++ b/value/boolean/compare.h @@ -0,0 +1,4 @@ + +int compare_boolean_values( + const struct value* a, + const struct value* b); diff --git a/value/boolean/foreach_accessible_subvalue.c b/value/boolean/foreach_accessible_subvalue.c new file mode 100644 index 0000000..44a9315 --- /dev/null +++ b/value/boolean/foreach_accessible_subvalue.c @@ -0,0 +1,17 @@ + +#include + +#include "foreach_accessible_subvalue.h" + +void boolean_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/boolean/foreach_accessible_subvalue.h b/value/boolean/foreach_accessible_subvalue.h new file mode 100644 index 0000000..885e469 --- /dev/null +++ b/value/boolean/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void boolean_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/boolean/inheritance.c b/value/boolean/inheritance.c new file mode 100644 index 0000000..86096d2 --- /dev/null +++ b/value/boolean/inheritance.c @@ -0,0 +1,21 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance boolean_value_inheritance = +{ + .foreach_accessible_subvalue = boolean_value_foreach_accessible_subvalue, + + .prettyprint = boolean_value_prettyprint, + + .shallow_free = shallow_free_boolean_value, + + .compare = compare_boolean_values, +}; + diff --git a/value/boolean/inheritance.h b/value/boolean/inheritance.h new file mode 100644 index 0000000..7d002d4 --- /dev/null +++ b/value/boolean/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance boolean_value_inheritance; + + diff --git a/value/boolean/new.c b/value/boolean/new.c new file mode 100644 index 0000000..627d64e --- /dev/null +++ b/value/boolean/new.c @@ -0,0 +1,29 @@ + +#include + +#include "../struct.h" +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_boolean_value( + struct gc* gc, + bool literal) +{ + ENTER; + + struct value* super = new_value( + /* garbage collection: */ gc, + /* kind: */ vk_boolean, + /* inheritance: */ &boolean_value_inheritance); + + struct boolean_value* this = &super->subclass.boolean; + + this->value = literal; + + EXIT; + return super; +} + diff --git a/value/boolean/new.h b/value/boolean/new.h new file mode 100644 index 0000000..b357543 --- /dev/null +++ b/value/boolean/new.h @@ -0,0 +1,5 @@ + +struct value* new_boolean_value( + struct gc* gc, + bool literal); + diff --git a/value/boolean/prettyprint.c b/value/boolean/prettyprint.c new file mode 100644 index 0000000..89c04c5 --- /dev/null +++ b/value/boolean/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* boolean_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_boolean); + + const struct boolean_value* this = &super->subclass.boolean; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string_const(tree, this->value ? "true" : "false"); + + EXIT; + return tree; +} + diff --git a/value/boolean/prettyprint.h b/value/boolean/prettyprint.h new file mode 100644 index 0000000..0c897d6 --- /dev/null +++ b/value/boolean/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* boolean_value_prettyprint( + const struct value* super); diff --git a/value/boolean/shallow_free.c b/value/boolean/shallow_free.c new file mode 100644 index 0000000..ff2f409 --- /dev/null +++ b/value/boolean/shallow_free.c @@ -0,0 +1,20 @@ + +#include + +/*#include */ + +#include "../struct.h" + +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_boolean_value( + struct value* super) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/boolean/shallow_free.h b/value/boolean/shallow_free.h new file mode 100644 index 0000000..d57dba3 --- /dev/null +++ b/value/boolean/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_boolean_value( + struct value* super); diff --git a/value/boolean/struct.h b/value/boolean/struct.h new file mode 100644 index 0000000..7785b7e --- /dev/null +++ b/value/boolean/struct.h @@ -0,0 +1,10 @@ + +#ifndef STRUCT_BOOLEAN_VALUE +#define STRUCT_BOOLEAN_VALUE + +struct boolean_value +{ + bool value; +}; + +#endif diff --git a/value/builtin_lambda/compare.c b/value/builtin_lambda/compare.c new file mode 100644 index 0000000..a77acd6 --- /dev/null +++ b/value/builtin_lambda/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_builtin_lambda_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/builtin_lambda/compare.h b/value/builtin_lambda/compare.h new file mode 100644 index 0000000..d4e35f0 --- /dev/null +++ b/value/builtin_lambda/compare.h @@ -0,0 +1,4 @@ + +int compare_builtin_lambda_values( + const struct value* a, + const struct value* b); diff --git a/value/builtin_lambda/foreach_accessible_subvalue.c b/value/builtin_lambda/foreach_accessible_subvalue.c new file mode 100644 index 0000000..1d38740 --- /dev/null +++ b/value/builtin_lambda/foreach_accessible_subvalue.c @@ -0,0 +1,17 @@ + +#include + +#include "foreach_accessible_subvalue.h" + +void builtin_lambda_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/builtin_lambda/foreach_accessible_subvalue.h b/value/builtin_lambda/foreach_accessible_subvalue.h new file mode 100644 index 0000000..9bd232b --- /dev/null +++ b/value/builtin_lambda/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void builtin_lambda_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/builtin_lambda/inheritance.c b/value/builtin_lambda/inheritance.c new file mode 100644 index 0000000..d401631 --- /dev/null +++ b/value/builtin_lambda/inheritance.c @@ -0,0 +1,17 @@ + +#include "../inheritance.h" + +#include "inheritance.h" +#include "shallow_free.h" +#include "prettyprint.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance builtin_lambda_value_inheritance = +{ + .foreach_accessible_subvalue = builtin_lambda_value_foreach_accessible_subvalue, + .shallow_free = shallow_free_builtin_lambda_value, + .prettyprint = builtin_lambda_value_prettyprint, + .compare = compare_builtin_lambda_values, +}; + diff --git a/value/builtin_lambda/inheritance.h b/value/builtin_lambda/inheritance.h new file mode 100644 index 0000000..cffd266 --- /dev/null +++ b/value/builtin_lambda/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance builtin_lambda_value_inheritance; + + diff --git a/value/builtin_lambda/new.c b/value/builtin_lambda/new.c new file mode 100644 index 0000000..e9781ee --- /dev/null +++ b/value/builtin_lambda/new.c @@ -0,0 +1,37 @@ + +#include + +#include + +#include "../struct.h" +#include "../new.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_builtin_lambda_value( + struct gc* gc, + struct string* name, + builtin_funcptr_t funcptr) +{ + ENTER; + + struct value* super = new_value( + /* garbage collection/allocator: */ gc, + /* kind: */ vk_builtin_lambda, + /* inheritance: */ &builtin_lambda_value_inheritance); + + struct builtin_lambda_value* this = &super->subclass.builtin_lambda; + + this->name = inc_string(name); + + this->funcptr = funcptr; + + EXIT; + return super; +} + + + + diff --git a/value/builtin_lambda/new.h b/value/builtin_lambda/new.h new file mode 100644 index 0000000..bcbc7bd --- /dev/null +++ b/value/builtin_lambda/new.h @@ -0,0 +1,7 @@ + +#include + +struct value* new_builtin_lambda_value( + struct gc* gc, + struct string* name, + builtin_funcptr_t funcptr); diff --git a/value/builtin_lambda/prettyprint.c b/value/builtin_lambda/prettyprint.c new file mode 100644 index 0000000..d581527 --- /dev/null +++ b/value/builtin_lambda/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* builtin_lambda_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_builtin_lambda); + + const struct builtin_lambda_value* this = &super->subclass.builtin_lambda; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string(tree, this->name); + + EXIT; + return tree; +} + diff --git a/value/builtin_lambda/prettyprint.h b/value/builtin_lambda/prettyprint.h new file mode 100644 index 0000000..b3f56ed --- /dev/null +++ b/value/builtin_lambda/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* builtin_lambda_value_prettyprint( + const struct value* super); diff --git a/value/builtin_lambda/shallow_free.c b/value/builtin_lambda/shallow_free.c new file mode 100644 index 0000000..b01969c --- /dev/null +++ b/value/builtin_lambda/shallow_free.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "../struct.h" + +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_builtin_lambda_value( + struct value* super) +{ + ENTER; + + assert(super->kind == vk_builtin_lambda); + + struct builtin_lambda_value* this = &super->subclass.builtin_lambda; + + free_string(this->name); + + EXIT; +} + diff --git a/value/builtin_lambda/shallow_free.h b/value/builtin_lambda/shallow_free.h new file mode 100644 index 0000000..d450b00 --- /dev/null +++ b/value/builtin_lambda/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_builtin_lambda_value( + struct value* super); diff --git a/value/builtin_lambda/struct.h b/value/builtin_lambda/struct.h new file mode 100644 index 0000000..868f43e --- /dev/null +++ b/value/builtin_lambda/struct.h @@ -0,0 +1,14 @@ + +#ifndef STRUCT_BUILDIN_LAMBDA_VALUE +#define STRUCT_BUILDIN_LAMBDA_VALUE + +#include + +struct builtin_lambda_value +{ + struct string* name; + + builtin_funcptr_t funcptr; +}; + +#endif diff --git a/value/compare.c b/value/compare.c new file mode 100644 index 0000000..57dba12 --- /dev/null +++ b/value/compare.c @@ -0,0 +1,40 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "compare.h" + +int compare_values( + const struct value* a, + const struct value* b) +{ + ENTER; + + int cmp = 0; + + if (a == b) + { + cmp = 0; + } + else if (a->kind > b->kind) + { + cmp = +1; + } + else if (a->kind < b->kind) + { + cmp = -1; + } + else + { + assert(a); + assert(a->inheritance); + assert(a->inheritance->compare); + + cmp = (a->inheritance->compare)(a, b); + } + + EXIT; + return cmp; +} + diff --git a/value/compare.h b/value/compare.h new file mode 100644 index 0000000..f29c48d --- /dev/null +++ b/value/compare.h @@ -0,0 +1,4 @@ + +int compare_values( + const struct value* a, + const struct value* b); diff --git a/value/environment/add_builtins.c b/value/environment/add_builtins.c new file mode 100644 index 0000000..7d6846d --- /dev/null +++ b/value/environment/add_builtins.c @@ -0,0 +1,126 @@ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +/*#include */ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "define.h" +#include "add_builtins.h" + +void environment_value_add_builtins( + struct value* super, + unsigned macro_level) +{ + ENTER; + + struct environment_value* this = &super->subclass.environment; + + #define DECLARE_LAMBDA(name, funcptr) \ + { \ + char buffer[100 + MAX_MACRO_DEPTH + 1]; \ + char* m = stpcpy(buffer, name); \ + for (unsigned i = 0; i < macro_level; i++) \ + *m++ = '!'; \ + *m = 0; \ + struct string* string = new_string(buffer, -1); \ + struct value* value = new_builtin_lambda_value(this->gc, string, funcptr); \ + environment_value_define(super, string, value); \ + gc_dec_external_refcount(this->gc, value); \ + free_string(string); \ + } + + DECLARE_LAMBDA("+", builtin_add); + DECLARE_LAMBDA("-", builtin_sub); + DECLARE_LAMBDA("*", builtin_mul); + DECLARE_LAMBDA("×", builtin_mul); + DECLARE_LAMBDA("/", builtin_div); + DECLARE_LAMBDA("÷", builtin_div); + DECLARE_LAMBDA("%", builtin_rem); + + // comparisions: + DECLARE_LAMBDA("=", builtin_equal_to); + DECLARE_LAMBDA("==", builtin_equal_to); + DECLARE_LAMBDA(">", builtin_greater_than); + DECLARE_LAMBDA(">=", builtin_greater_than_equal_to); + DECLARE_LAMBDA("<", builtin_less_than); + DECLARE_LAMBDA("<=", builtin_less_than_equal_to); + DECLARE_LAMBDA("!=", builtin_not_equal_to); + DECLARE_LAMBDA("<>", builtin_not_equal_to); + + // λ, lambda + DECLARE_LAMBDA("λ", builtin_lambda); + DECLARE_LAMBDA("lambda", builtin_lambda); + + // define + DECLARE_LAMBDA("define", builtin_define); + + // apply + + // let + // DECLARE_LAMBDA("let", builtin_let); + // DECLARE_LAMBDA("letrec", builtin_letrec); + + // letrec + + // ?:, if/else + DECLARE_LAMBDA("?:", builtin_ifelse); + DECLARE_LAMBDA("if/else", builtin_ifelse); + + // list + DECLARE_LAMBDA("cons", builtin_cons); + DECLARE_LAMBDA("list", builtin_list); + + // eval + + EXIT; +} + + + + + + + + + + + + + + + + + + diff --git a/value/environment/add_builtins.h b/value/environment/add_builtins.h new file mode 100644 index 0000000..c9a3a58 --- /dev/null +++ b/value/environment/add_builtins.h @@ -0,0 +1,4 @@ + +void environment_value_add_builtins( + struct value* this, + unsigned macro_level); diff --git a/value/environment/compare.c b/value/environment/compare.c new file mode 100644 index 0000000..8a1f2fa --- /dev/null +++ b/value/environment/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_environment_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/environment/compare.h b/value/environment/compare.h new file mode 100644 index 0000000..50b8cd8 --- /dev/null +++ b/value/environment/compare.h @@ -0,0 +1,4 @@ + +int compare_environment_values( + const struct value* a, + const struct value* b); diff --git a/value/environment/define.c b/value/environment/define.c new file mode 100644 index 0000000..41a5727 --- /dev/null +++ b/value/environment/define.c @@ -0,0 +1,39 @@ + +#include + +#include + +#include "../struct.h" + +#include "variable/new.h" + +#include "struct.h" +#include "define.h" + +void environment_value_define( + struct value* super, + struct string* name, + struct value* value) +{ + ENTER; + + assert(super->kind == vk_envrionment); + + struct environment_value* this = &super->subclass.environment; + + struct variable* variable = new_variable(name, value); + + void* ptr = avl_insert(this->tree, variable); + + if (!ptr) + { + TODO; + } + + EXIT; +} + + + + + diff --git a/value/environment/define.h b/value/environment/define.h new file mode 100644 index 0000000..c726370 --- /dev/null +++ b/value/environment/define.h @@ -0,0 +1,5 @@ + +void environment_value_define( + struct value* this, + struct string* name, + struct value* value); diff --git a/value/environment/foreach_accessible_subvalue.c b/value/environment/foreach_accessible_subvalue.c new file mode 100644 index 0000000..542e195 --- /dev/null +++ b/value/environment/foreach_accessible_subvalue.c @@ -0,0 +1,40 @@ + +#include + +#include + +#include "../struct.h" + +#include "variable/struct.h" + +#include "struct.h" + +#include "foreach_accessible_subvalue.h" + +void envrionment_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + assert(super->kind == vk_envrionment); + + const struct environment_value* this = &super->subclass.environment; + + if (this->fallback) + { + callback((void*) this->fallback); + } + + for (const struct avl_node_t* node = this->tree->head; + node; node = node->next) + { + struct variable* variable = node->item; + + callback(variable->value); + } + + EXIT; +} + diff --git a/value/environment/foreach_accessible_subvalue.h b/value/environment/foreach_accessible_subvalue.h new file mode 100644 index 0000000..5117245 --- /dev/null +++ b/value/environment/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void envrionment_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/environment/inheritance.c b/value/environment/inheritance.c new file mode 100644 index 0000000..8ebbb22 --- /dev/null +++ b/value/environment/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance envrionment_value_inheritance = +{ + .foreach_accessible_subvalue = envrionment_value_foreach_accessible_subvalue, + .shallow_free = shallow_free_environment_value, + .prettyprint = environment_value_prettyprint, + .compare = compare_environment_values, +}; + diff --git a/value/environment/inheritance.h b/value/environment/inheritance.h new file mode 100644 index 0000000..adcad54 --- /dev/null +++ b/value/environment/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance envrionment_value_inheritance; + + diff --git a/value/environment/lookup.c b/value/environment/lookup.c new file mode 100644 index 0000000..4dd4214 --- /dev/null +++ b/value/environment/lookup.c @@ -0,0 +1,57 @@ + +#include + +#include + +#include + +#include + +#include "../struct.h" + +#include "variable/struct.h" + +#include "struct.h" +#include "lookup.h" + +struct value* environment_value_lookup( + struct value* super, + struct string* name) +{ + struct value* retval = NULL; + ENTER; + + dpvs(name->data); + + for (struct value* moving = super; + !retval && moving; + moving = moving->subclass.environment.fallback) + { + assert(moving->kind == vk_envrionment); + + struct environment_value* spec = &moving->subclass.environment; + + struct avl_node_t* node = avl_search(spec->tree, &name); + + if (node) + { + struct variable* variable = node->item; + + retval = gc_inc_external_refcount(spec->gc, variable->value); + } + } + + EXIT; + return retval; +} + + + + + + + + + + + diff --git a/value/environment/lookup.h b/value/environment/lookup.h new file mode 100644 index 0000000..4bb962f --- /dev/null +++ b/value/environment/lookup.h @@ -0,0 +1,4 @@ + +struct value* environment_value_lookup( + struct value* super, + struct string* name); diff --git a/value/environment/new.c b/value/environment/new.c new file mode 100644 index 0000000..77cdec9 --- /dev/null +++ b/value/environment/new.c @@ -0,0 +1,43 @@ + +#include + +#include + +#include "../struct.h" +#include "../new.h" + +#include "variable/compare.h" +#include "variable/free.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_environment_value( + struct gc* gc, + struct value* fallback) +{ + ENTER; + + struct value* super = new_value( + /* garbage collection: */ gc, + /* kind: */ vk_envrionment, + /* inheritance: */ &envrionment_value_inheritance); + + struct environment_value* this = &super->subclass.environment; + + if (fallback) + { + assert(fallback->kind == vk_envrionment); + } + + this->fallback = fallback; + + this->gc = gc; + + this->tree = avl_alloc_tree(compare_variables, free_variable); + + EXIT; + return super; +} + diff --git a/value/environment/new.h b/value/environment/new.h new file mode 100644 index 0000000..28ef3b2 --- /dev/null +++ b/value/environment/new.h @@ -0,0 +1,4 @@ + +struct value* new_environment_value( + struct gc* gc, + struct value* fallback); diff --git a/value/environment/prettyprint.c b/value/environment/prettyprint.c new file mode 100644 index 0000000..da68995 --- /dev/null +++ b/value/environment/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* environment_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_envrionment); + + const struct environment_value* this = &super->subclass.environment; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string_const(tree, "(environment)"); + + EXIT; + return tree; +} + diff --git a/value/environment/prettyprint.h b/value/environment/prettyprint.h new file mode 100644 index 0000000..1a958be --- /dev/null +++ b/value/environment/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* environment_value_prettyprint( + const struct value* super); diff --git a/value/environment/shallow_free.c b/value/environment/shallow_free.c new file mode 100644 index 0000000..22e7c38 --- /dev/null +++ b/value/environment/shallow_free.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "../struct.h" + +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_environment_value( + struct value* super) +{ + ENTER; + + assert(super->kind == vk_envrionment); + + struct environment_value* this = &super->subclass.environment; + + avl_free_tree(this->tree); + + EXIT; +} + diff --git a/value/environment/shallow_free.h b/value/environment/shallow_free.h new file mode 100644 index 0000000..3ad8bd1 --- /dev/null +++ b/value/environment/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_environment_value( + struct value* super); diff --git a/value/environment/struct.h b/value/environment/struct.h new file mode 100644 index 0000000..ed4a91a --- /dev/null +++ b/value/environment/struct.h @@ -0,0 +1,14 @@ + +#ifndef STRUCT_ENVIRONMENT_VALUE +#define STRUCT_ENVIRONMENT_VALUE + +struct environment_value +{ + struct value* fallback; + + struct gc* gc; + + struct avl_tree_t* tree; +}; + +#endif diff --git a/value/environment/variable/compare.c b/value/environment/variable/compare.c new file mode 100644 index 0000000..38fb485 --- /dev/null +++ b/value/environment/variable/compare.c @@ -0,0 +1,23 @@ + +#include + +#include + +#include "struct.h" +#include "compare.h" + +int compare_variables( + const void* a, const void* b) +{ + ENTER; + + const struct variable* A = a, *B = b; + + int cmp = compare_strings(A->name, B->name); + + dpvi(cmp); + + EXIT; + return cmp; +} + diff --git a/value/environment/variable/compare.h b/value/environment/variable/compare.h new file mode 100644 index 0000000..fef7056 --- /dev/null +++ b/value/environment/variable/compare.h @@ -0,0 +1,3 @@ + +int compare_variables( + const void* a, const void* b); diff --git a/value/environment/variable/free.c b/value/environment/variable/free.c new file mode 100644 index 0000000..2ec031d --- /dev/null +++ b/value/environment/variable/free.c @@ -0,0 +1,25 @@ + +#include + +#include + +#include "struct.h" +#include "free.h" + +void free_variable( + void* ptr) +{ + ENTER; + + // I'm only ever getting called by a shallow free, \\ + so I shouldn't free my value, only by name. + + struct variable* this = ptr; + + free_string(this->name); + + free(this); + + EXIT; +} + diff --git a/value/environment/variable/free.h b/value/environment/variable/free.h new file mode 100644 index 0000000..4424430 --- /dev/null +++ b/value/environment/variable/free.h @@ -0,0 +1,3 @@ + +void free_variable( + void* ptr); diff --git a/value/environment/variable/new.c b/value/environment/variable/new.c new file mode 100644 index 0000000..3529d8e --- /dev/null +++ b/value/environment/variable/new.c @@ -0,0 +1,27 @@ + +#include + +#include + +#include + +#include "struct.h" + +#include "new.h" + +struct variable* new_variable( + struct string* name, + struct value* value) +{ + ENTER; + + struct variable* this = smalloc(sizeof(*this)); + + this->name = inc_string(name); + + this->value = value; + + EXIT; + return this; +} + diff --git a/value/environment/variable/new.h b/value/environment/variable/new.h new file mode 100644 index 0000000..2cf1d71 --- /dev/null +++ b/value/environment/variable/new.h @@ -0,0 +1,4 @@ + +struct variable* new_variable( + struct string* name, + struct value* value); diff --git a/value/environment/variable/struct.h b/value/environment/variable/struct.h new file mode 100644 index 0000000..b04e0b0 --- /dev/null +++ b/value/environment/variable/struct.h @@ -0,0 +1,11 @@ + +struct string; +struct value; + +struct variable +{ + struct string* name; + + struct value* value; +}; + diff --git a/value/foreach_accessible_subvalue.c b/value/foreach_accessible_subvalue.c new file mode 100644 index 0000000..5acf226 --- /dev/null +++ b/value/foreach_accessible_subvalue.c @@ -0,0 +1,22 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "foreach_accessible_subvalue.h" + +void value_foreach_accessible_subvalue( + const struct value* this, + void (*callback)(struct value* subvalue)) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->foreach_accessible_subvalue); + + (this->inheritance->foreach_accessible_subvalue)(this, callback); + + EXIT; +} + diff --git a/value/foreach_accessible_subvalue.h b/value/foreach_accessible_subvalue.h new file mode 100644 index 0000000..c7fcfe0 --- /dev/null +++ b/value/foreach_accessible_subvalue.h @@ -0,0 +1,4 @@ + +void value_foreach_accessible_subvalue( + const struct value* this, + void (*callback)(struct value* subvalue)); diff --git a/value/identifier/compare.c b/value/identifier/compare.c new file mode 100644 index 0000000..70ea9af --- /dev/null +++ b/value/identifier/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_identifier_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/identifier/compare.h b/value/identifier/compare.h new file mode 100644 index 0000000..ac13e66 --- /dev/null +++ b/value/identifier/compare.h @@ -0,0 +1,4 @@ + +int compare_identifier_values( + const struct value* a, + const struct value* b); diff --git a/value/identifier/foreach_accessible_subvalue.c b/value/identifier/foreach_accessible_subvalue.c new file mode 100644 index 0000000..6139a5b --- /dev/null +++ b/value/identifier/foreach_accessible_subvalue.c @@ -0,0 +1,17 @@ + +#include + +#include "foreach_accessible_subvalue.h" + +void identifier_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/identifier/foreach_accessible_subvalue.h b/value/identifier/foreach_accessible_subvalue.h new file mode 100644 index 0000000..3674960 --- /dev/null +++ b/value/identifier/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void identifier_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/identifier/inheritance.c b/value/identifier/inheritance.c new file mode 100644 index 0000000..62f5923 --- /dev/null +++ b/value/identifier/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance identifier_value_inheritance = +{ + .prettyprint = identifier_value_prettyprint, + .foreach_accessible_subvalue = identifier_value_foreach_accessible_subvalue, + .shallow_free = shallow_free_identifier_value, + .compare = compare_identifier_values, +}; + diff --git a/value/identifier/inheritance.h b/value/identifier/inheritance.h new file mode 100644 index 0000000..b1458f4 --- /dev/null +++ b/value/identifier/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance identifier_value_inheritance; + + diff --git a/value/identifier/new.c b/value/identifier/new.c new file mode 100644 index 0000000..f540c92 --- /dev/null +++ b/value/identifier/new.c @@ -0,0 +1,32 @@ + +#include + +#include + +#include "../struct.h" +#include "../new.h" +#include "../kind.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_identifier_value( + struct gc* gc, + struct string* name) +{ + ENTER; + + struct value* super = new_value( + /* garbage collector/allocator: */ gc, + /* kind: */ vk_identifier, + /* inheritance: */ &identifier_value_inheritance); + + struct identifier_value* this = &super->subclass.identifier; + + this->name = inc_string(name); + + EXIT; + return super; +} + diff --git a/value/identifier/new.h b/value/identifier/new.h new file mode 100644 index 0000000..d12e12d --- /dev/null +++ b/value/identifier/new.h @@ -0,0 +1,4 @@ + +struct value* new_identifier_value( + struct gc* gc, + struct string* name); diff --git a/value/identifier/prettyprint.c b/value/identifier/prettyprint.c new file mode 100644 index 0000000..5c9908a --- /dev/null +++ b/value/identifier/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* identifier_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_identifier); + + const struct identifier_value* this = &super->subclass.identifier; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string(tree, this->name); + + EXIT; + return tree; +} + diff --git a/value/identifier/prettyprint.h b/value/identifier/prettyprint.h new file mode 100644 index 0000000..290917d --- /dev/null +++ b/value/identifier/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* identifier_value_prettyprint( + const struct value* super); diff --git a/value/identifier/shallow_free.c b/value/identifier/shallow_free.c new file mode 100644 index 0000000..cced46b --- /dev/null +++ b/value/identifier/shallow_free.c @@ -0,0 +1,24 @@ + +#include + +#include + +#include "../struct.h" + +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_identifier_value( + struct value* super) +{ + ENTER; + + assert(super->kind == vk_identifier); + + struct identifier_value* this = &super->subclass.identifier; + + free_string(this->name); + + EXIT; +} + diff --git a/value/identifier/shallow_free.h b/value/identifier/shallow_free.h new file mode 100644 index 0000000..205076c --- /dev/null +++ b/value/identifier/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_identifier_value( + struct value* super); diff --git a/value/identifier/struct.h b/value/identifier/struct.h new file mode 100644 index 0000000..b72c5d2 --- /dev/null +++ b/value/identifier/struct.h @@ -0,0 +1,10 @@ + +#ifndef STRUCT_IDENTIFIER_VALUE +#define STRUCT_IDENTIFIER_VALUE + +struct identifier_value +{ + struct string* name; +}; + +#endif diff --git a/value/inheritance.h b/value/inheritance.h new file mode 100644 index 0000000..d2b52ae --- /dev/null +++ b/value/inheritance.h @@ -0,0 +1,21 @@ + +struct value; + +struct value_inheritance +{ + void (*foreach_accessible_subvalue)( + const struct value* this, + void (*callback)( + struct value* subvalue)); + + struct stringtree* (*prettyprint)( + const struct value* this); + + int (*compare)( + const struct value*, + const struct value*); + + void (*shallow_free)( + struct value* this); +}; + diff --git a/value/integer/compare.c b/value/integer/compare.c new file mode 100644 index 0000000..d7ee4e2 --- /dev/null +++ b/value/integer/compare.c @@ -0,0 +1,31 @@ + +#include + +#include "../struct.h" + +#include "struct.h" +#include "compare.h" + +int compare_integer_values( + const struct value* a, + const struct value* b) +{ + int cmp; + ENTER; + + assert(a->kind == vk_integer && b->kind == vk_integer); + + const struct integer_value* A = &a->subclass.integer; + + const struct integer_value* B = &b->subclass.integer; + + if (A->value > B->value) + cmp = +1; + else if (A->value < B->value) + cmp = -1; + else + cmp = +0; + + EXIT; + return cmp; +} diff --git a/value/integer/compare.h b/value/integer/compare.h new file mode 100644 index 0000000..067b2ec --- /dev/null +++ b/value/integer/compare.h @@ -0,0 +1,4 @@ + +int compare_integer_values( + const struct value* a, + const struct value* b); diff --git a/value/integer/foreach_accessible_subvalue.c b/value/integer/foreach_accessible_subvalue.c new file mode 100644 index 0000000..8c5c8bc --- /dev/null +++ b/value/integer/foreach_accessible_subvalue.c @@ -0,0 +1,17 @@ + +#include + +#include "foreach_accessible_subvalue.h" + +void integer_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/integer/foreach_accessible_subvalue.h b/value/integer/foreach_accessible_subvalue.h new file mode 100644 index 0000000..1563e87 --- /dev/null +++ b/value/integer/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void integer_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/integer/inheritance.c b/value/integer/inheritance.c new file mode 100644 index 0000000..ca33673 --- /dev/null +++ b/value/integer/inheritance.c @@ -0,0 +1,17 @@ + +#include "../inheritance.h" + +#include "inheritance.h" +#include "shallow_free.h" +#include "prettyprint.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance integer_value_inheritance = +{ + .prettyprint = integer_value_prettyprint, + .foreach_accessible_subvalue = integer_value_foreach_accessible_subvalue, + .shallow_free = shallow_free_integer_value, + .compare = compare_integer_values, +}; + diff --git a/value/integer/inheritance.h b/value/integer/inheritance.h new file mode 100644 index 0000000..2d0a8d3 --- /dev/null +++ b/value/integer/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance integer_value_inheritance; + + diff --git a/value/integer/new.c b/value/integer/new.c new file mode 100644 index 0000000..02758e3 --- /dev/null +++ b/value/integer/new.c @@ -0,0 +1,29 @@ + +#include + +#include "../struct.h" +#include "../new.h" + +#include "inheritance.h" +#include "struct.h" +#include "new.h" + +struct value* new_integer_value( + struct gc* gc, + intmax_t value) +{ + ENTER; + + struct value* super = new_value( + /* gc: */ gc, + /* kind: */ vk_integer, + /* inheritance: */ &integer_value_inheritance); + + struct integer_value* this = &super->subclass.integer; + + this->value = value; + + EXIT; + return super; +} + diff --git a/value/integer/new.h b/value/integer/new.h new file mode 100644 index 0000000..e9be46c --- /dev/null +++ b/value/integer/new.h @@ -0,0 +1,4 @@ + +struct value* new_integer_value( + struct gc* gc, + intmax_t value); diff --git a/value/integer/prettyprint.c b/value/integer/prettyprint.c new file mode 100644 index 0000000..8ba2182 --- /dev/null +++ b/value/integer/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* integer_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_integer); + + const struct integer_value* this = &super->subclass.integer; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_formatstr(tree, "%" PRIiMAX, this->value); + + EXIT; + return tree; +} + diff --git a/value/integer/prettyprint.h b/value/integer/prettyprint.h new file mode 100644 index 0000000..e4deb4d --- /dev/null +++ b/value/integer/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* integer_value_prettyprint( + const struct value* super); diff --git a/value/integer/shallow_free.c b/value/integer/shallow_free.c new file mode 100644 index 0000000..fb31339 --- /dev/null +++ b/value/integer/shallow_free.c @@ -0,0 +1,20 @@ + +#include + +/*#include */ + +#include "../struct.h" + +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_integer_value( + struct value* super) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/integer/shallow_free.h b/value/integer/shallow_free.h new file mode 100644 index 0000000..b8fedc7 --- /dev/null +++ b/value/integer/shallow_free.h @@ -0,0 +1,4 @@ + +void shallow_free_integer_value( + struct value* super); + diff --git a/value/integer/struct.h b/value/integer/struct.h new file mode 100644 index 0000000..c9ef415 --- /dev/null +++ b/value/integer/struct.h @@ -0,0 +1,10 @@ + +#ifndef STRUCT_INTEGER_VALUE +#define STRUCT_INTEGER_VALUE + +struct integer_value +{ + intmax_t value; +}; + +#endif diff --git a/value/kind.h b/value/kind.h new file mode 100644 index 0000000..471879c --- /dev/null +++ b/value/kind.h @@ -0,0 +1,23 @@ + +#ifndef ENUM_VALUE_KIND +#define ENUM_VALUE_KIND + +enum value_kind +{ + #ifdef DOTOUT_BUILD + vk_uninitalized, + #endif + + vk_null, + vk_boolean, + vk_list, + vk_identifier, + vk_integer, + vk_string, + vk_quote, + vk_user_lambda, + vk_builtin_lambda, + vk_envrionment, +}; + +#endif diff --git a/value/list/compare.c b/value/list/compare.c new file mode 100644 index 0000000..d96805e --- /dev/null +++ b/value/list/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_list_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/list/compare.h b/value/list/compare.h new file mode 100644 index 0000000..76e70d8 --- /dev/null +++ b/value/list/compare.h @@ -0,0 +1,4 @@ + +int compare_list_values( + const struct value* a, + const struct value* b); diff --git a/value/list/foreach_accessible_subvalue.c b/value/list/foreach_accessible_subvalue.c new file mode 100644 index 0000000..0a28f6a --- /dev/null +++ b/value/list/foreach_accessible_subvalue.c @@ -0,0 +1,29 @@ + +#include + +#include "../struct.h" + +#include "struct.h" +#include "foreach_accessible_subvalue.h" + +void list_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + assert(super->kind == vk_list); + + const struct list_value* this = &super->subclass.list; + + callback(this->first); + + if (this->rest) + { + callback(this->rest); + } + + EXIT; +} + diff --git a/value/list/foreach_accessible_subvalue.h b/value/list/foreach_accessible_subvalue.h new file mode 100644 index 0000000..211cbda --- /dev/null +++ b/value/list/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void list_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/list/inheritance.c b/value/list/inheritance.c new file mode 100644 index 0000000..ffdd714 --- /dev/null +++ b/value/list/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance list_value_inheritance = +{ + .foreach_accessible_subvalue = list_value_foreach_accessible_subvalue, + .prettyprint = list_value_prettyprint, + .shallow_free = shallow_free_list_value, + .compare = compare_list_values, +}; + diff --git a/value/list/inheritance.h b/value/list/inheritance.h new file mode 100644 index 0000000..89bc1e1 --- /dev/null +++ b/value/list/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance list_value_inheritance; + + diff --git a/value/list/new.c b/value/list/new.c new file mode 100644 index 0000000..f094dd4 --- /dev/null +++ b/value/list/new.c @@ -0,0 +1,31 @@ + +#include + +#include "../struct.h" +#include "../new.h" +#include "../kind.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_list_value( + struct gc* gc, + struct value* first) +{ + ENTER; + + struct value* super = new_value( + /* garbage collector/allocator: */ gc, + /* kind: */ vk_list, + /* inheritance: */ &list_value_inheritance); + + struct list_value* this = &super->subclass.list; + + this->first = first; + this->rest = NULL; + + EXIT; + return super; +} + diff --git a/value/list/new.h b/value/list/new.h new file mode 100644 index 0000000..a379894 --- /dev/null +++ b/value/list/new.h @@ -0,0 +1,4 @@ + +struct value* new_list_value( + struct gc* gc, + struct value* element); diff --git a/value/list/prettyprint.c b/value/list/prettyprint.c new file mode 100644 index 0000000..79b4809 --- /dev/null +++ b/value/list/prettyprint.c @@ -0,0 +1,60 @@ + +#include + +#include +#include +#include + +#include "../struct.h" +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* list_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_list); + + const struct list_value* this = &super->subclass.list; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string_const(tree, "("); + + bool first = true; + + for (const struct value* link = super; + link && link->kind == vk_list; + link = link->subclass.list.rest) + { + struct stringtree* element = value_prettyprint( + /* element: */ link->subclass.list.first); + + if (first) + first = false; + else + stringtree_append_string_const(tree, " "); + + stringtree_append_stringtree(tree, element); + + free_stringtree(element); + } + + stringtree_append_string_const(tree, ")"); + + EXIT; + return tree; +} + + + + + + + + + + diff --git a/value/list/prettyprint.h b/value/list/prettyprint.h new file mode 100644 index 0000000..6f9b788 --- /dev/null +++ b/value/list/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* list_value_prettyprint( + const struct value* super); diff --git a/value/list/shallow_free.c b/value/list/shallow_free.c new file mode 100644 index 0000000..d9af959 --- /dev/null +++ b/value/list/shallow_free.c @@ -0,0 +1,15 @@ + +#include + +#include "shallow_free.h" + +void shallow_free_list_value( + struct value* super) +{ + ENTER + + ; + + EXIT; +} + diff --git a/value/list/shallow_free.h b/value/list/shallow_free.h new file mode 100644 index 0000000..270cf86 --- /dev/null +++ b/value/list/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_list_value( + struct value* super); diff --git a/value/list/struct.h b/value/list/struct.h new file mode 100644 index 0000000..d9ea6cf --- /dev/null +++ b/value/list/struct.h @@ -0,0 +1,12 @@ + +#ifndef STRUCT_LIST_VALUE +#define STRUCT_LIST_VALUE + +struct list_value +{ + struct value* first; + + struct value* rest; +}; + +#endif diff --git a/value/new.c b/value/new.c new file mode 100644 index 0000000..dc24f4a --- /dev/null +++ b/value/new.c @@ -0,0 +1,28 @@ + +#include + +#include + +#include + +#include "struct.h" +#include "new.h" + +struct value* new_value( + struct gc* gc, + enum value_kind kind, + const struct value_inheritance* inheritance) +{ + ENTER; + + assert(inheritance); + + struct value* this = gc_allocate_node(gc); + + this->kind = kind; + + this->inheritance = inheritance; + + EXIT; + return this; +} diff --git a/value/new.h b/value/new.h new file mode 100644 index 0000000..5ddd84b --- /dev/null +++ b/value/new.h @@ -0,0 +1,9 @@ + +struct gc; + +#include "kind.h" + +struct value* new_value( + struct gc* gc, + enum value_kind kind, + const struct value_inheritance* inheritance); diff --git a/value/null/compare.c b/value/null/compare.c new file mode 100644 index 0000000..08d8ea3 --- /dev/null +++ b/value/null/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_null_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/null/compare.h b/value/null/compare.h new file mode 100644 index 0000000..13e33f8 --- /dev/null +++ b/value/null/compare.h @@ -0,0 +1,4 @@ + +int compare_null_values( + const struct value* a, + const struct value* b); diff --git a/value/null/foreach_accessible_subvalue.c b/value/null/foreach_accessible_subvalue.c new file mode 100644 index 0000000..4bd99db --- /dev/null +++ b/value/null/foreach_accessible_subvalue.c @@ -0,0 +1,17 @@ + +#include + +#include "foreach_accessible_subvalue.h" + +void null_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + ; + + EXIT; +} + diff --git a/value/null/foreach_accessible_subvalue.h b/value/null/foreach_accessible_subvalue.h new file mode 100644 index 0000000..38ee25e --- /dev/null +++ b/value/null/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void null_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/null/inheritance.c b/value/null/inheritance.c new file mode 100644 index 0000000..0de45b4 --- /dev/null +++ b/value/null/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance null_value_inheritance = +{ + .foreach_accessible_subvalue = null_value_foreach_accessible_subvalue, + .prettyprint = null_value_prettyprint, + .shallow_free = shallow_free_null_value, + .compare = compare_null_values, +}; + diff --git a/value/null/inheritance.h b/value/null/inheritance.h new file mode 100644 index 0000000..f158663 --- /dev/null +++ b/value/null/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance null_value_inheritance; + + diff --git a/value/null/new.c b/value/null/new.c new file mode 100644 index 0000000..aeb0ceb --- /dev/null +++ b/value/null/new.c @@ -0,0 +1,24 @@ + +#include + +#include "../new.h" +#include "../kind.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_null_value( + struct gc* gc) +{ + ENTER; + + struct value* super = new_value( + /* garbage collector/allocator: */ gc, + /* kind: */ vk_null, + /* inheritance: */ &null_value_inheritance); + + EXIT; + return super; +} + diff --git a/value/null/new.h b/value/null/new.h new file mode 100644 index 0000000..bb53afa --- /dev/null +++ b/value/null/new.h @@ -0,0 +1,3 @@ + +struct value* new_null_value( + struct gc* gc); diff --git a/value/null/prettyprint.c b/value/null/prettyprint.c new file mode 100644 index 0000000..14318c8 --- /dev/null +++ b/value/null/prettyprint.c @@ -0,0 +1,28 @@ + +#include + +#include +#include + +#include "../struct.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* null_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_null); + + const struct identifier_value* this = &super->subclass.identifier; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string_const(tree, "null"); + + EXIT; + return tree; +} + diff --git a/value/null/prettyprint.h b/value/null/prettyprint.h new file mode 100644 index 0000000..8384691 --- /dev/null +++ b/value/null/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* null_value_prettyprint( + const struct value* super); diff --git a/value/null/shallow_free.c b/value/null/shallow_free.c new file mode 100644 index 0000000..77deb30 --- /dev/null +++ b/value/null/shallow_free.c @@ -0,0 +1,15 @@ + +#include + +#include "shallow_free.h" + +void shallow_free_null_value( + struct value* super) +{ + ENTER + + ; + + EXIT; +} + diff --git a/value/null/shallow_free.h b/value/null/shallow_free.h new file mode 100644 index 0000000..933ddaf --- /dev/null +++ b/value/null/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_null_value( + struct value* super); diff --git a/value/null/struct.h b/value/null/struct.h new file mode 100644 index 0000000..291dd52 --- /dev/null +++ b/value/null/struct.h @@ -0,0 +1,10 @@ + +#ifndef STRUCT_NULL_VALUE +#define STRUCT_NULL_VALUE + +struct null_value +{ + +}; + +#endif diff --git a/value/prettyprint.c b/value/prettyprint.c new file mode 100644 index 0000000..04700a5 --- /dev/null +++ b/value/prettyprint.c @@ -0,0 +1,22 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* value_prettyprint( + struct value* this) +{ + ENTER; + + assert(this); + assert(this->inheritance); + assert(this->inheritance->prettyprint); + + struct stringtree* tree = (this->inheritance->prettyprint)(this); + + EXIT; + return tree; +} + diff --git a/value/prettyprint.h b/value/prettyprint.h new file mode 100644 index 0000000..576d7b6 --- /dev/null +++ b/value/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* value_prettyprint( + struct value* this); diff --git a/value/quote/compare.c b/value/quote/compare.c new file mode 100644 index 0000000..9a4810d --- /dev/null +++ b/value/quote/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_quote_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/quote/compare.h b/value/quote/compare.h new file mode 100644 index 0000000..a43c544 --- /dev/null +++ b/value/quote/compare.h @@ -0,0 +1,4 @@ + +int compare_quote_values( + const struct value* a, + const struct value* b); diff --git a/value/quote/foreach_accessible_subvalue.c b/value/quote/foreach_accessible_subvalue.c new file mode 100644 index 0000000..5782449 --- /dev/null +++ b/value/quote/foreach_accessible_subvalue.c @@ -0,0 +1,24 @@ + +#include + +#include "../struct.h" + +#include "struct.h" +#include "foreach_accessible_subvalue.h" + +void quote_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + assert(super->kind == vk_quote); + + const struct quote_value* this = &super->subclass.quote; + + callback(this->subexpression); + + EXIT; +} + diff --git a/value/quote/foreach_accessible_subvalue.h b/value/quote/foreach_accessible_subvalue.h new file mode 100644 index 0000000..4a20146 --- /dev/null +++ b/value/quote/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void quote_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/quote/inheritance.c b/value/quote/inheritance.c new file mode 100644 index 0000000..0d06532 --- /dev/null +++ b/value/quote/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance quote_value_inheritance = +{ + .foreach_accessible_subvalue = quote_value_foreach_accessible_subvalue, + .prettyprint = quote_value_prettyprint, + .shallow_free = shallow_free_quote_value, + .compare = compare_quote_values, +}; + diff --git a/value/quote/inheritance.h b/value/quote/inheritance.h new file mode 100644 index 0000000..7f1dbc9 --- /dev/null +++ b/value/quote/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance quote_value_inheritance; + + diff --git a/value/quote/new.c b/value/quote/new.c new file mode 100644 index 0000000..1bacb5e --- /dev/null +++ b/value/quote/new.c @@ -0,0 +1,30 @@ + +#include + +#include "../struct.h" +#include "../new.h" +#include "../kind.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_quote_value( + struct gc* gc, + struct value* subexpression) +{ + ENTER; + + struct value* super = new_value( + /* garbage collector/allocator: */ gc, + /* kind: */ vk_quote, + /* inheritance: */ "e_value_inheritance); + + struct quote_value* this = &super->subclass.quote; + + this->subexpression = subexpression; + + EXIT; + return super; +} + diff --git a/value/quote/new.h b/value/quote/new.h new file mode 100644 index 0000000..60cf5b6 --- /dev/null +++ b/value/quote/new.h @@ -0,0 +1,4 @@ + +struct value* new_quote_value( + struct gc* gc, + struct value* subexpression); diff --git a/value/quote/prettyprint.c b/value/quote/prettyprint.c new file mode 100644 index 0000000..642cdc6 --- /dev/null +++ b/value/quote/prettyprint.c @@ -0,0 +1,29 @@ + +#include + +#include +#include + +#include "../struct.h" +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* quote_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_quote); + + const struct quote_value* this = &super->subclass.quote; + + struct stringtree* tree = value_prettyprint(this->subexpression); + + stringtree_prepend_string_const(tree, "`"); + + EXIT; + return tree; +} + diff --git a/value/quote/prettyprint.h b/value/quote/prettyprint.h new file mode 100644 index 0000000..1ad194d --- /dev/null +++ b/value/quote/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* quote_value_prettyprint( + const struct value* super); diff --git a/value/quote/shallow_free.c b/value/quote/shallow_free.c new file mode 100644 index 0000000..a1eb578 --- /dev/null +++ b/value/quote/shallow_free.c @@ -0,0 +1,15 @@ + +#include + +#include "shallow_free.h" + +void shallow_free_quote_value( + struct value* super) +{ + ENTER + + ; + + EXIT; +} + diff --git a/value/quote/shallow_free.h b/value/quote/shallow_free.h new file mode 100644 index 0000000..c26d548 --- /dev/null +++ b/value/quote/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_quote_value( + struct value* super); diff --git a/value/quote/struct.h b/value/quote/struct.h new file mode 100644 index 0000000..a77ed88 --- /dev/null +++ b/value/quote/struct.h @@ -0,0 +1,10 @@ + +#ifndef STRUCT_QUOTE_VALUE +#define STRUCT_QUOTE_VALUE + +struct quote_value +{ + struct value* subexpression; +}; + +#endif diff --git a/value/shallow_free.c b/value/shallow_free.c new file mode 100644 index 0000000..a4d7586 --- /dev/null +++ b/value/shallow_free.c @@ -0,0 +1,53 @@ + +#include + +#include "inheritance.h" +#include "struct.h" +#include "shallow_free.h" + +void shallow_free_value( + struct value* this) +{ + ENTER; + +/* #ifdef VALGRIND_BUILD*/ +/* if (!VALGRIND_CHECK_VALUE_IS_DEFINED(this))*/ +/* {*/ +/* TODO;*/ +/* }*/ +/* #endif*/ + + dpvp(this); + +/* #ifdef VALGRIND_BUILD*/ +/* if (!VALGRIND_CHECK_VALUE_IS_DEFINED(this->kind))*/ +/* {*/ +/* TODO;*/ +/* }*/ +/* #endif*/ + + dpvu(this->kind); + +/* #ifdef VALGRIND_BUILD*/ +/* if (!VALGRIND_CHECK_VALUE_IS_DEFINED(this->inheritance))*/ +/* {*/ +/* TODO;*/ +/* }*/ +/* #endif*/ + + dpvp(this->inheritance); + + dpvp(this->inheritance->shallow_free); + + assert(this); + assert(this->inheritance); + assert(this->inheritance->shallow_free); + + (this->inheritance->shallow_free)(this); + + // free(this); + // I don't free myself, GC does that. + + EXIT; +} + diff --git a/value/shallow_free.h b/value/shallow_free.h new file mode 100644 index 0000000..203a9b3 --- /dev/null +++ b/value/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_value( + struct value* value); diff --git a/value/string/compare.c b/value/string/compare.c new file mode 100644 index 0000000..e69de29 diff --git a/value/string/compare.h b/value/string/compare.h new file mode 100644 index 0000000..e69de29 diff --git a/value/string/prettyprint.c b/value/string/prettyprint.c new file mode 100644 index 0000000..e69de29 diff --git a/value/string/prettyprint.h b/value/string/prettyprint.h new file mode 100644 index 0000000..e69de29 diff --git a/value/string/shallow_free.c b/value/string/shallow_free.c new file mode 100644 index 0000000..e69de29 diff --git a/value/string/shallow_free.h b/value/string/shallow_free.h new file mode 100644 index 0000000..e69de29 diff --git a/value/struct.h b/value/struct.h new file mode 100644 index 0000000..12ede52 --- /dev/null +++ b/value/struct.h @@ -0,0 +1,62 @@ + +#include + +#include "kind.h" + +#include "list/struct.h" +#include "null/struct.h" +#include "boolean/struct.h" +#include "identifier/struct.h" +#include "integer/struct.h" +#include "quote/struct.h" +#include "user_lambda/struct.h" +#include "builtin_lambda/struct.h" +#include "environment/struct.h" + +struct value_inheritance; + +struct value +{ + struct link internally_referenced, reaped, grey, white, externally_referenced; + size_t external_refcount; + // size_t garbage_collection_count; + // no need to initalize or maintain, entirely handled by GC. + + const struct value_inheritance* inheritance; + + enum value_kind kind; + + union + { + struct null_value null; + + struct boolean_value boolean; + + struct identifier_value identifier; + + struct integer_value integer; + + struct quote_value quote; + + struct list_value list; + + struct user_lambda_value user_lambda; + + struct builtin_lambda_value builtin_lambda; + + struct environment_value environment; + } subclass; +}; + + + + + + + + + + + + + diff --git a/value/user_lambda/compare.c b/value/user_lambda/compare.c new file mode 100644 index 0000000..ca7fb5c --- /dev/null +++ b/value/user_lambda/compare.c @@ -0,0 +1,11 @@ + +#include + +#include "compare.h" + +int compare_user_lambda_values( + const struct value* a, + const struct value* b) +{ + TODO; +} diff --git a/value/user_lambda/compare.h b/value/user_lambda/compare.h new file mode 100644 index 0000000..a36fc35 --- /dev/null +++ b/value/user_lambda/compare.h @@ -0,0 +1,4 @@ + +int compare_user_lambda_values( + const struct value* a, + const struct value* b); diff --git a/value/user_lambda/foreach_accessible_subvalue.c b/value/user_lambda/foreach_accessible_subvalue.c new file mode 100644 index 0000000..767b754 --- /dev/null +++ b/value/user_lambda/foreach_accessible_subvalue.c @@ -0,0 +1,28 @@ + +#include + +#include "../struct.h" + +#include "struct.h" +#include "foreach_accessible_subvalue.h" + +void user_lambda_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)) +{ + ENTER; + + assert(super->kind == vk_user_lambda); + + const struct user_lambda_value* this = &super->subclass.user_lambda; + + callback(this->environment); + + callback(this->parameters); + + callback(this->body); + + EXIT; +} + diff --git a/value/user_lambda/foreach_accessible_subvalue.h b/value/user_lambda/foreach_accessible_subvalue.h new file mode 100644 index 0000000..3dd8829 --- /dev/null +++ b/value/user_lambda/foreach_accessible_subvalue.h @@ -0,0 +1,7 @@ + +struct value; + +void user_lambda_value_foreach_accessible_subvalue( + const struct value* super, + void (*callback)( + struct value* subvalue)); diff --git a/value/user_lambda/inheritance.c b/value/user_lambda/inheritance.c new file mode 100644 index 0000000..6e53ec6 --- /dev/null +++ b/value/user_lambda/inheritance.c @@ -0,0 +1,18 @@ + +#include "../inheritance.h" + +#include "inheritance.h" + +#include "prettyprint.h" +#include "shallow_free.h" +#include "foreach_accessible_subvalue.h" +#include "compare.h" + +struct value_inheritance user_lambda_value_inheritance = +{ + .foreach_accessible_subvalue = user_lambda_value_foreach_accessible_subvalue, + .prettyprint = user_lambda_value_prettyprint, + .shallow_free = shallow_free_user_lambda_value, + .compare = compare_user_lambda_values, +}; + diff --git a/value/user_lambda/inheritance.h b/value/user_lambda/inheritance.h new file mode 100644 index 0000000..fdfc6e6 --- /dev/null +++ b/value/user_lambda/inheritance.h @@ -0,0 +1,4 @@ + +extern struct value_inheritance user_lambda_value_inheritance; + + diff --git a/value/user_lambda/new.c b/value/user_lambda/new.c new file mode 100644 index 0000000..5f3b422 --- /dev/null +++ b/value/user_lambda/new.c @@ -0,0 +1,50 @@ + +#include + +#include "../struct.h" +#include "../new.h" +#include "../kind.h" + +#include "struct.h" +#include "inheritance.h" +#include "new.h" + +struct value* new_user_lambda_value( + struct gc* gc, + struct value* environment, + struct value* parameters, + struct value* body) +{ + ENTER; + + struct value* super = new_value( + /* garbage collector/allocator: */ gc, + /* kind: */ vk_user_lambda, + /* inheritance: */ &user_lambda_value_inheritance); + + struct user_lambda_value* this = &super->subclass.user_lambda; + + this->environment = environment; + this->parameters = parameters; + this->body = body; + + EXIT; + return super; +} + + + + + + + + + + + + + + + + + diff --git a/value/user_lambda/new.h b/value/user_lambda/new.h new file mode 100644 index 0000000..53230e7 --- /dev/null +++ b/value/user_lambda/new.h @@ -0,0 +1,6 @@ + +struct value* new_user_lambda_value( + struct gc* gc, + struct value* environment, + struct value* parameters, + struct value* body); diff --git a/value/user_lambda/prettyprint.c b/value/user_lambda/prettyprint.c new file mode 100644 index 0000000..2816fea --- /dev/null +++ b/value/user_lambda/prettyprint.c @@ -0,0 +1,64 @@ + +#include + +#include +#include +#include + +#include "../struct.h" +#include "../prettyprint.h" + +#include "struct.h" +#include "prettyprint.h" + +struct stringtree* user_lambda_value_prettyprint( + const struct value* super) +{ + ENTER; + + assert(super->kind == vk_user_lambda); + + const struct user_lambda_value* this = &super->subclass.user_lambda; + + struct stringtree* tree = new_stringtree(); + + stringtree_append_string_const(tree, "(lambda "); + + { + struct stringtree* parameters = value_prettyprint(this->parameters); + + stringtree_append_stringtree(tree, parameters); + + free_stringtree(parameters); + } + + stringtree_append_string_const(tree, " "); + + { + struct stringtree* body = value_prettyprint(this->body); + + stringtree_append_stringtree(tree, body); + + free_stringtree(body); + } + + stringtree_append_string_const(tree, ")"); + + EXIT; + return tree; +} + + + + + + + + + + + + + + + diff --git a/value/user_lambda/prettyprint.h b/value/user_lambda/prettyprint.h new file mode 100644 index 0000000..a4fbf4d --- /dev/null +++ b/value/user_lambda/prettyprint.h @@ -0,0 +1,3 @@ + +struct stringtree* user_lambda_value_prettyprint( + const struct value* super); diff --git a/value/user_lambda/shallow_free.c b/value/user_lambda/shallow_free.c new file mode 100644 index 0000000..0d58f1c --- /dev/null +++ b/value/user_lambda/shallow_free.c @@ -0,0 +1,15 @@ + +#include + +#include "shallow_free.h" + +void shallow_free_user_lambda_value( + struct value* super) +{ + ENTER + + ; + + EXIT; +} + diff --git a/value/user_lambda/shallow_free.h b/value/user_lambda/shallow_free.h new file mode 100644 index 0000000..3ee9c50 --- /dev/null +++ b/value/user_lambda/shallow_free.h @@ -0,0 +1,3 @@ + +void shallow_free_user_lambda_value( + struct value* super); diff --git a/value/user_lambda/struct.h b/value/user_lambda/struct.h new file mode 100644 index 0000000..21735f7 --- /dev/null +++ b/value/user_lambda/struct.h @@ -0,0 +1,14 @@ + +#ifndef STRUCT_USER_LAMBDA_VALUE +#define STRUCT_USER_LAMBDA_VALUE + +struct user_lambda_value +{ + struct value* environment; + + struct value* parameters; // list of names; + + struct value* body; +}; + +#endif