first commit
This commit is contained in:
commit
007a931684
309 changed files with 8953 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
bin/
|
||||||
|
|
||||||
641
avl/avl.c
Normal file
641
avl/avl.c
Normal file
|
|
@ -0,0 +1,641 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
avl.c - Source code for the AVL-tree library.
|
||||||
|
|
||||||
|
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
|
||||||
|
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
|
||||||
|
|
||||||
|
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 <cosine@cosine.org>.
|
||||||
|
|
||||||
|
Modified by Wessel Dankers <wsl@nl.linux.org> 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
208
avl/avl.h
Normal file
208
avl/avl.h
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
|
||||||
|
avl.h - Source code for the AVL-tree library.
|
||||||
|
|
||||||
|
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
|
||||||
|
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
|
||||||
|
|
||||||
|
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 <cosine@cosine.org>.
|
||||||
|
|
||||||
|
Modified by Wessel Dankers <wsl@nl.linux.org> 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
17
buildtypes/debug-dotout-valgrind.txt
Normal file
17
buildtypes/debug-dotout-valgrind.txt
Normal file
|
|
@ -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
|
||||||
16
buildtypes/debug-dotout.txt
Normal file
16
buildtypes/debug-dotout.txt
Normal file
|
|
@ -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
|
||||||
16
buildtypes/debug-valgrind.txt
Normal file
16
buildtypes/debug-valgrind.txt
Normal file
|
|
@ -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
|
||||||
18
buildtypes/debug.txt
Normal file
18
buildtypes/debug.txt
Normal file
|
|
@ -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
|
||||||
12
buildtypes/release.txt
Normal file
12
buildtypes/release.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
-I .
|
||||||
|
|
||||||
|
-D RELEASE_BUILD
|
||||||
|
|
||||||
|
-Wall
|
||||||
|
-Werror
|
||||||
|
-Wfatal-errors
|
||||||
|
-Wstrict-prototypes
|
||||||
|
|
||||||
|
-Wno-comment
|
||||||
|
|
||||||
17
buildtypes/test-dotout-valgrind.txt
Normal file
17
buildtypes/test-dotout-valgrind.txt
Normal file
|
|
@ -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
|
||||||
16
buildtypes/test-dotout.txt
Normal file
16
buildtypes/test-dotout.txt
Normal file
|
|
@ -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
|
||||||
15
buildtypes/test.txt
Normal file
15
buildtypes/test.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
-g
|
||||||
|
|
||||||
|
-I .
|
||||||
|
|
||||||
|
-D _GNU_SOURCE
|
||||||
|
-D TEST_BUILD
|
||||||
|
|
||||||
|
-Wall
|
||||||
|
-Werror
|
||||||
|
-Wfatal-errors
|
||||||
|
-Wstrict-prototypes
|
||||||
|
|
||||||
|
-Wno-comment
|
||||||
|
-Wno-unused
|
||||||
90
builtins/arithmetic/add.c
Normal file
90
builtins/arithmetic/add.c
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/integer/new.h>
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/arithmetic/add.h
Normal file
6
builtins/arithmetic/add.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_add(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
13
builtins/arithmetic/div.c
Normal file
13
builtins/arithmetic/div.c
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include "div.h"
|
||||||
|
|
||||||
|
struct value* builtin_div(
|
||||||
|
BUILTIN_PARAMETER_DECLARATION)
|
||||||
|
{
|
||||||
|
TODO;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/arithmetic/div.h
Normal file
6
builtins/arithmetic/div.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_div(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
85
builtins/arithmetic/mul.c
Normal file
85
builtins/arithmetic/mul.c
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/integer/new.h>
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/arithmetic/mul.h
Normal file
6
builtins/arithmetic/mul.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_mul(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
13
builtins/arithmetic/rem.c
Normal file
13
builtins/arithmetic/rem.c
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include "rem.h"
|
||||||
|
|
||||||
|
struct value* builtin_rem(
|
||||||
|
BUILTIN_PARAMETER_DECLARATION)
|
||||||
|
{
|
||||||
|
TODO;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/arithmetic/rem.h
Normal file
6
builtins/arithmetic/rem.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_rem(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
83
builtins/arithmetic/sub.c
Normal file
83
builtins/arithmetic/sub.c
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/integer/new.h>
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/arithmetic/sub.h
Normal file
6
builtins/arithmetic/sub.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_sub(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
70
builtins/comparision/equal_to.c
Normal file
70
builtins/comparision/equal_to.c
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/comparision/equal_to.h
Normal file
6
builtins/comparision/equal_to.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_equal_to(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
64
builtins/comparision/greater_than.c
Normal file
64
builtins/comparision/greater_than.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/comparision/greater_than.h
Normal file
6
builtins/comparision/greater_than.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_greater_than(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
64
builtins/comparision/greater_than_equal_to.c
Normal file
64
builtins/comparision/greater_than_equal_to.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/comparision/greater_than_equal_to.h
Normal file
6
builtins/comparision/greater_than_equal_to.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_greater_than_equal_to(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
64
builtins/comparision/less_than.c
Normal file
64
builtins/comparision/less_than.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/comparision/less_than.h
Normal file
6
builtins/comparision/less_than.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_less_than(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
64
builtins/comparision/less_than_equal_to.c
Normal file
64
builtins/comparision/less_than_equal_to.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/comparision/less_than_equal_to.h
Normal file
6
builtins/comparision/less_than_equal_to.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_less_than_equal_to(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
64
builtins/comparision/not_equal_to.c
Normal file
64
builtins/comparision/not_equal_to.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/compare.h>
|
||||||
|
#include <value/boolean/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
6
builtins/comparision/not_equal_to.h
Normal file
6
builtins/comparision/not_equal_to.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_not_equal_to(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
81
builtins/core/define.c
Normal file
81
builtins/core/define.c
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/environment/define.h>
|
||||||
|
#include <value/null/new.h>
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
8
builtins/core/define.h
Normal file
8
builtins/core/define.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
struct value* builtin_define(
|
||||||
|
BUILTIN_PARAMETER_DECLARATION);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
91
builtins/core/ifelse.c
Normal file
91
builtins/core/ifelse.c
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_DECLARATION.h"
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/core/ifelse.h
Normal file
6
builtins/core/ifelse.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_ifelse(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
70
builtins/core/lambda.c
Normal file
70
builtins/core/lambda.c
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/user_lambda/new.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/core/lambda.h
Normal file
6
builtins/core/lambda.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_lambda(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
70
builtins/core/let.c
Normal file
70
builtins/core/let.c
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/core/let.h
Normal file
6
builtins/core/let.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_let(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
0
builtins/core/letrec.c
Normal file
0
builtins/core/letrec.c
Normal file
0
builtins/core/letrec.h
Normal file
0
builtins/core/letrec.h
Normal file
11
builtins/defines/BUILTIN_PARAMETER_DECLARATION.h
Normal file
11
builtins/defines/BUILTIN_PARAMETER_DECLARATION.h
Normal file
|
|
@ -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) \
|
||||||
|
|
||||||
|
|
||||||
11
builtins/defines/BUILTIN_PARAMETER_PROTOTYPE.h
Normal file
11
builtins/defines/BUILTIN_PARAMETER_PROTOTYPE.h
Normal file
|
|
@ -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) \
|
||||||
|
|
||||||
|
|
||||||
78
builtins/list/cons.c
Normal file
78
builtins/list/cons.c
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#include <value/list/new.h>
|
||||||
|
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/list/cons.h
Normal file
6
builtins/list/cons.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_cons(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
86
builtins/list/list.c
Normal file
86
builtins/list/list.c
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/list/new.h>
|
||||||
|
#include <value/null/new.h>
|
||||||
|
|
||||||
|
#include <gc/inc_external_refcount.h>
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
builtins/list/list.h
Normal file
6
builtins/list/list.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
struct value* builtin_list(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
0
builtins/logical/and.c
Normal file
0
builtins/logical/and.c
Normal file
0
builtins/logical/and.h
Normal file
0
builtins/logical/and.h
Normal file
0
builtins/logical/not.c
Normal file
0
builtins/logical/not.c
Normal file
0
builtins/logical/not.h
Normal file
0
builtins/logical/not.h
Normal file
0
builtins/logical/or.c
Normal file
0
builtins/logical/or.c
Normal file
0
builtins/logical/or.h
Normal file
0
builtins/logical/or.h
Normal file
6
builtins/typedefs/builtin_funcptr_t.h
Normal file
6
builtins/typedefs/builtin_funcptr_t.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "../defines/BUILTIN_PARAMETER_PROTOTYPE.h"
|
||||||
|
|
||||||
|
typedef struct value* (*builtin_funcptr_t)(
|
||||||
|
BUILTIN_PARAMETER_PROTOTYPE);
|
||||||
|
|
||||||
17
cmdln/free.c
Normal file
17
cmdln/free.c
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include "free.h"
|
||||||
|
|
||||||
|
void free_cmdln_flags(
|
||||||
|
struct cmdln_flags* flags)
|
||||||
|
{
|
||||||
|
ENTER;
|
||||||
|
|
||||||
|
free(flags);
|
||||||
|
|
||||||
|
EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
5
cmdln/free.h
Normal file
5
cmdln/free.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
struct cmdln_flags;
|
||||||
|
|
||||||
|
void free_cmdln_flags(
|
||||||
|
struct cmdln_flags* flags);
|
||||||
223
cmdln/process.c
Normal file
223
cmdln/process.c
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <memory/smalloc.h>
|
||||||
|
|
||||||
|
#include <gc/defines/GARBAGE_COLLECTION_MINIMUM.h>
|
||||||
|
#include <gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h>
|
||||||
|
#include <gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7
cmdln/process.h
Normal file
7
cmdln/process.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
struct cmdln_flags* process_cmdln_flags(
|
||||||
|
int argc,
|
||||||
|
char* const* argv);
|
||||||
|
|
||||||
|
|
||||||
24
cmdln/struct.h
Normal file
24
cmdln/struct.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
#include <gc/flags.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
91
debug.c
Normal file
91
debug.c
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
264
debug.h
Normal file
264
debug.h
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
|
||||||
|
#if (defined(DEBUG_BUILD) || defined(TEST_BUILD))
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <valgrind/memcheck.h>
|
||||||
|
|
||||||
|
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 <defines/argv0.h>
|
||||||
|
/*#include <defines/RES.h>*/
|
||||||
|
|
||||||
|
/*#include <macros/N.h>*/
|
||||||
|
|
||||||
|
/*#include <memory/smalloc.h>*/
|
||||||
|
/*#include <memory/srealloc.h>*/
|
||||||
|
|
||||||
|
/*#include <string/struct.h>*/
|
||||||
|
/*#include <string/new.h>*/
|
||||||
|
/*#include <string/inc.h>*/
|
||||||
|
/*#include <string/free.h>*/
|
||||||
|
|
||||||
|
/*#include <string/new.h>*/
|
||||||
|
/*#include <string/write.h>*/
|
||||||
|
/*#include <string/free.h>*/
|
||||||
|
|
||||||
|
/*#include <structs/charset.h>*/
|
||||||
|
/*#include <structs/value.h>*/
|
||||||
|
|
||||||
|
/*#include <enums/syntax_type.h>*/
|
||||||
|
|
||||||
|
/*#include <misc/ptrcmp.h>*/
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
defines/MAX_MACRO_DEPTH.h
Normal file
3
defines/MAX_MACRO_DEPTH.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
#define MAX_MACRO_DEPTH 3
|
||||||
|
|
||||||
4
defines/argv0.h
Normal file
4
defines/argv0.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
#define argv0 \
|
||||||
|
(program_invocation_name)
|
||||||
|
|
||||||
174
evaluate.c
Normal file
174
evaluate.c
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <string/struct.h>
|
||||||
|
|
||||||
|
#include <gc/inc_external_refcount.h>
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#include <value/environment/new.h>
|
||||||
|
#include <value/environment/define.h>
|
||||||
|
#include <value/environment/lookup.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
5
evaluate.h
Normal file
5
evaluate.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
struct value* evaluate(
|
||||||
|
struct value* value,
|
||||||
|
struct value* environment,
|
||||||
|
struct gc* gc);
|
||||||
50
examples/sandbox.txt
Normal file
50
examples/sandbox.txt
Normal file
|
|
@ -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)
|
||||||
215
expand_macro.c
Normal file
215
expand_macro.c
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#include <value/environment/new.h>
|
||||||
|
#include <value/environment/define.h>
|
||||||
|
#include <value/environment/lookup.h>
|
||||||
|
|
||||||
|
#include <value/quote/new.h>
|
||||||
|
|
||||||
|
#include <value/list/new.h>
|
||||||
|
|
||||||
|
#include <gc/inc_external_refcount.h>
|
||||||
|
#include <gc/dec_external_refcount.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
5
expand_macro.h
Normal file
5
expand_macro.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
struct value* expand_macro(
|
||||||
|
struct value* value,
|
||||||
|
struct value* environment,
|
||||||
|
struct gc* gc);
|
||||||
313
gc/allocate_node.c
Normal file
313
gc/allocate_node.c
Normal file
|
|
@ -0,0 +1,313 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/shallow_free.h>
|
||||||
|
#include <value/foreach_accessible_subvalue.h>
|
||||||
|
|
||||||
|
#include <memory/smalloc.h>
|
||||||
|
#include <memory/srealloc.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
gc/allocate_node.h
Normal file
3
gc/allocate_node.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
struct value* gc_allocate_node(
|
||||||
|
struct gc* this);
|
||||||
77
gc/dec_external_refcount.c
Normal file
77
gc/dec_external_refcount.c
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4
gc/dec_external_refcount.h
Normal file
4
gc/dec_external_refcount.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
void gc_dec_external_refcount(
|
||||||
|
struct gc* gc,
|
||||||
|
struct value* value);
|
||||||
9
gc/defines/GARBAGE_COLLECTION_MINIMUM.h
Normal file
9
gc/defines/GARBAGE_COLLECTION_MINIMUM.h
Normal file
|
|
@ -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
|
||||||
|
|
||||||
10
gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h
Normal file
10
gc/defines/GARBAGE_COLLECTION_PROCESS_LIMIT.h
Normal file
|
|
@ -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
|
||||||
10
gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h
Normal file
10
gc/defines/GARBAGE_COLLECTION_RUN_EVERY.h
Normal file
|
|
@ -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
|
||||||
|
|
||||||
353
gc/dotout.c
Normal file
353
gc/dotout.c
Normal file
|
|
@ -0,0 +1,353 @@
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef DOTOUT_BUILD
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <stringtree/new.h>
|
||||||
|
#include <stringtree/append.h>
|
||||||
|
#include <stringtree/println.h>
|
||||||
|
#include <stringtree/free.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/prettyprint.h>
|
||||||
|
#include <value/foreach_accessible_subvalue.h>
|
||||||
|
|
||||||
|
#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
|
||||||
9
gc/dotout.h
Normal file
9
gc/dotout.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
#ifdef DOTOUT_BUILD
|
||||||
|
|
||||||
|
void gc_dotout(
|
||||||
|
const struct gc* this,
|
||||||
|
const char* label_fmt,
|
||||||
|
...);
|
||||||
|
|
||||||
|
#endif
|
||||||
14
gc/flags.h
Normal file
14
gc/flags.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct gc_flags
|
||||||
|
{
|
||||||
|
size_t minimum;
|
||||||
|
|
||||||
|
size_t run_every;
|
||||||
|
|
||||||
|
size_t process_limit;
|
||||||
|
|
||||||
|
bool dotout;
|
||||||
|
};
|
||||||
|
|
||||||
51
gc/free.c
Normal file
51
gc/free.c
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
#include <value/shallow_free.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
3
gc/free.h
Normal file
3
gc/free.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
void free_gc(
|
||||||
|
struct gc* this);
|
||||||
74
gc/inc_external_refcount.c
Normal file
74
gc/inc_external_refcount.c
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
4
gc/inc_external_refcount.h
Normal file
4
gc/inc_external_refcount.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
struct value* gc_inc_external_refcount(
|
||||||
|
struct gc* gc,
|
||||||
|
struct value* value);
|
||||||
63
gc/linked_list/append.c
Normal file
63
gc/linked_list/append.c
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
8
gc/linked_list/append.h
Normal file
8
gc/linked_list/append.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
void linked_list_append(
|
||||||
|
struct linked_list* this,
|
||||||
|
struct value* value,
|
||||||
|
size_t offset);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
55
gc/linked_list/clear.c
Normal file
55
gc/linked_list/clear.c
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
10
gc/linked_list/clear.h
Normal file
10
gc/linked_list/clear.h
Normal file
|
|
@ -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);
|
||||||
35
gc/linked_list/init.c
Normal file
35
gc/linked_list/init.c
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
6
gc/linked_list/init.h
Normal file
6
gc/linked_list/init.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
void linked_list_init(
|
||||||
|
struct linked_list* list);
|
||||||
|
|
||||||
|
void link_init(
|
||||||
|
struct link* link);
|
||||||
64
gc/linked_list/pop.c
Normal file
64
gc/linked_list/pop.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
4
gc/linked_list/pop.h
Normal file
4
gc/linked_list/pop.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
struct value* linked_list_pop(
|
||||||
|
struct linked_list* list,
|
||||||
|
size_t offset);
|
||||||
65
gc/linked_list/remove.c
Normal file
65
gc/linked_list/remove.c
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
5
gc/linked_list/remove.h
Normal file
5
gc/linked_list/remove.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
void linked_list_remove(
|
||||||
|
struct linked_list* list,
|
||||||
|
struct value* element,
|
||||||
|
size_t link_offset);
|
||||||
21
gc/linked_list/struct.h
Normal file
21
gc/linked_list/struct.h
Normal file
|
|
@ -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
|
||||||
49
gc/mark_as_mortal.c
Normal file
49
gc/mark_as_mortal.c
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <value/struct.h>
|
||||||
|
|
||||||
|
#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
|
||||||
8
gc/mark_as_mortal.h
Normal file
8
gc/mark_as_mortal.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
|
void gc_mark_as_mortal(
|
||||||
|
struct gc* gc,
|
||||||
|
struct value* value);
|
||||||
|
|
||||||
|
#endif
|
||||||
52
gc/new.c
Normal file
52
gc/new.c
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <memory/smalloc.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3
gc/new.h
Normal file
3
gc/new.h
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
struct gc* new_gc(
|
||||||
|
const struct gc_flags* flags);
|
||||||
28
gc/struct.h
Normal file
28
gc/struct.h
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue