~brenns10/funlisp

82700cb159bfe26fb2e0fd4f41884fe7afbc753c — Stephen Brennan 3 years ago 8bf2177
Tabs to spaces (closes #5)
M src/charbuf.c => src/charbuf.c +53 -53
@@ 18,101 18,101 @@

void cb_init(struct charbuf *obj, int capacity)
{
  // Initialization logic
  obj->buf = calloc(sizeof(char), (size_t)capacity);
  obj->buf[0] = '\0';
  obj->capacity = capacity;
  obj->length = 0;
	/* Initialization logic */
	obj->buf = calloc(sizeof(char), (size_t)capacity);
	obj->buf[0] = '\0';
	obj->capacity = capacity;
	obj->length = 0;
}

struct charbuf *cb_create(int capacity)
{
  struct charbuf *obj = calloc(sizeof(struct charbuf), 1);
  cb_init(obj, capacity);
  return obj;
	struct charbuf *obj = calloc(sizeof(struct charbuf), 1);
	cb_init(obj, capacity);
	return obj;
}

void cb_destroy(struct charbuf *obj)
{
  free(obj->buf);
  obj->buf = NULL;
	free(obj->buf);
	obj->buf = NULL;
}

void cb_delete(struct charbuf *obj) {
  cb_destroy(obj);
  free(obj);
	cb_destroy(obj);
	free(obj);
}

/**
   @brief Ensure that the struct charbuf can fit a certain amount of characters.
   @param obj The struct charbuf to expand (if necessary).
   @param minsize The minimum size the struct charbuf should be able to fit.

   Note that minsize should include the NUL byte as part of the character count.
   Therefore, to ensure that the string "four" fits in the buffer, you would
   want to run `cb_expand_to_fit(obj, 5)` (assuming the buffer was empty).
 * @brief Ensure that the struct charbuf can fit a certain amount of characters.
 * @param obj The struct charbuf to expand (if necessary).
 * @param minsize The minimum size the struct charbuf should be able to fit.
 *
 * Note that minsize should include the NUL byte as part of the character count.
 * Therefore, to ensure that the string "four" fits in the buffer, you would
 * want to run `cb_expand_to_fit(obj, 5)` (assuming the buffer was empty).
 */
static void cb_expand_to_fit(struct charbuf *obj, int minsize)
{
  int newcapacity = obj->capacity;
  while (newcapacity < minsize) {
    newcapacity *= 2;
  }
  if (newcapacity != obj->capacity) {
    obj->buf = realloc(obj->buf, sizeof(char) * newcapacity);
    obj->capacity = newcapacity;
  }
	int newcapacity = obj->capacity;
	while (newcapacity < minsize) {
		newcapacity *= 2;
	}
	if (newcapacity != obj->capacity) {
		obj->buf = realloc(obj->buf, sizeof(char) * newcapacity);
		obj->capacity = newcapacity;
	}
}

void cb_concat(struct charbuf *obj, char *buf)
{
  int length = strlen(buf);
  cb_expand_to_fit(obj, obj->length + length + 1);
  strcpy(obj->buf + obj->length, buf);
  obj->length += length;
	int length = strlen(buf);
	cb_expand_to_fit(obj, obj->length + length + 1);
	strcpy(obj->buf + obj->length, buf);
	obj->length += length;
}

void cb_append(struct charbuf *obj, char next)
{
  cb_expand_to_fit(obj, obj->length + 2); // include new character + nul
  obj->buf[obj->length] = next;
  obj->length++;
  obj->buf[obj->length] = '\0';
	cb_expand_to_fit(obj, obj->length + 2); /* include new character + nul */
	obj->buf[obj->length] = next;
	obj->length++;
	obj->buf[obj->length] = '\0';
}

void cb_trim(struct charbuf *obj)
{
  obj->buf = realloc(obj->buf, sizeof(char) * obj->length + 1);
  obj->capacity = obj->length + 1;
	obj->buf = realloc(obj->buf, sizeof(char) * obj->length + 1);
	obj->capacity = obj->length + 1;
}

void cb_clear(struct charbuf *obj)
{
  obj->buf[0] = '\0';
  obj->length = 0;
	obj->buf[0] = '\0';
	obj->length = 0;
}

void cb_vprintf(struct charbuf *obj, char *format, va_list va)
{
  va_list v2;
  int length;
  va_copy(v2, va);
	va_list v2;
	int length;
	va_copy(v2, va);

  // Find the length of the formatted string.
  length = vsnprintf(NULL, 0, format, va);
	/* Find the length of the formatted string. */
	length = vsnprintf(NULL, 0, format, va);

  // Make sure we have enough room for everything.
  cb_expand_to_fit(obj, obj->length + length + 1);
	/* Make sure we have enough room for everything. */
	cb_expand_to_fit(obj, obj->length + length + 1);

  // Put the formatted string into the buffer.
  vsnprintf(obj->buf + obj->length, length + 1, format, v2);
  va_end(v2);
	/* Put the formatted string into the buffer. */
	vsnprintf(obj->buf + obj->length, length + 1, format, v2);
	va_end(v2);
}

void cb_printf(struct charbuf *obj, char *format, ...)
{
  va_list va;
  va_start(va, format);
  cb_vprintf(obj, format, va);
  va_end(va);  // Have to va_stop() it when you're done using it.
	va_list va;
	va_start(va, format);
	cb_vprintf(obj, format, va);
	va_end(va);  /* Have to va_stop() it when you're done using it. */
}

M src/charbuf.h => src/charbuf.h +50 -50
@@ 11,89 11,89 @@
#include <wchar.h>

/**
   @brief A character buffer utility that is easier to handle than a char*.

   This character buffer provides an interface for string processing that allows
   you to be efficient, while not needing to handle nearly as much of the
   allocations that are necessary.  It automatically expands as you add to it.
 * @brief A character buffer utility that is easier to handle than a char*.
 *
 * This character buffer provides an interface for string processing that allows
 * you to be efficient, while not needing to handle nearly as much of the
 * allocations that are necessary. It automatically expands as you add to it.
 */
struct charbuf {
  /**
     @brief Buffer pointer.
   */
  char *buf;
  /**
     @brief Allocated size of the buffer.
   */
  int capacity;
  /**
     @brief Length of the string in the buffer.
   */
  int length;
	/**
	 * @brief Buffer pointer.
	 */
	char *buf;
	/**
	 * @brief Allocated size of the buffer.
	 */
	int capacity;
	/**
	 * @brief Length of the string in the buffer.
	 */
	int length;
};

/**
   @brief Initialize a brand-new character buffer.

   A buffer of the given capacity is initialized, and given an empty string
   value.
   @param obj The struct charbuf to initialize.
   @param capacity Initial capacity of the buffer.
 * @brief Initialize a brand-new character buffer.
 *
 * A buffer of the given capacity is initialized, and given an empty string
 * value.
 * @param obj The struct charbuf to initialize.
 * @param capacity Initial capacity of the buffer.
 */
void cb_init(struct charbuf *obj, int capacity);
/**
   @brief Allocate and initialize a brand-new character buffer.

   A buffer of the given capacity is initialized, and given an empty string
   value.  The struct charbuf struct is also allocated and the pointer returned.
   @param capacity Initial capacity of the buffer.
 * @brief Allocate and initialize a brand-new character buffer.
 *
 * A buffer of the given capacity is initialized, and given an empty string
 * value.  The struct charbuf struct is also allocated and the pointer returned.
 * @param capacity Initial capacity of the buffer.
 */
struct charbuf *cb_create(int capacity);
/**
   @brief Deallocate the contents of the string buffer.
   @param obj The character buffer to deallocate.
 * @brief Deallocate the contents of the string buffer.
 * @param obj The character buffer to deallocate.
 */
void cb_destroy(struct charbuf *obj);
/**
   @brief Deallocate the contents of, and delete the string buffer.
   @param obj The character buffer to delete.
 * @brief Deallocate the contents of, and delete the string buffer.
 * @param obj The character buffer to delete.
 */
void cb_delete(struct charbuf *obj);

/**
   @brief Concat a string onto the end of the character buffer.
   @param obj The buffer to concat onto.
   @param str The string to concat.
 * @brief Concat a string onto the end of the character buffer.
 * @param obj The buffer to concat onto.
 * @param str The string to concat.
 */
void cb_concat(struct charbuf *obj, char *str);
/**
   @brief Append a character onto the end of the character buffer.
   @param obj The buffer to append onto.
   @param next The character to append.
 * @brief Append a character onto the end of the character buffer.
 * @param obj The buffer to append onto.
 * @param next The character to append.
 */
void cb_append(struct charbuf *obj, char next);
/**
   @brief Reallocate the buffer to the exact size of the contained string.
   @param obj The buffer to reallocate.
 * @brief Reallocate the buffer to the exact size of the contained string.
 * @param obj The buffer to reallocate.
 */
void cb_trim(struct charbuf *obj);
/**
   @brief Empty the buffer of its contents.
   @param obj The buffer to clear.
 * @brief Empty the buffer of its contents.
 * @param obj The buffer to clear.
 */
void cb_clear(struct charbuf *obj);
/**
   @brief Format and print a string onto the end of a character buffer.
   @param obj The object to print onto.
   @param format The format string to print.
   @param ... The arguments to the format string.
 * @brief Format and print a string onto the end of a character buffer.
 * @param obj The object to print onto.
 * @param format The format string to print.
 * @param ... The arguments to the format string.
 */
void cb_printf(struct charbuf *obj, char *format, ...);
/**
   @brief Format and print a string onto the struct charbuf using a va_list.
   @param obj The struct charbuf to print into.
   @param format The format string to print.
   @param va The vararg list.
 * @brief Format and print a string onto the struct charbuf using a va_list.
 * @param obj The struct charbuf to print into.
 * @param format The format string to print.
 * @param va The vararg list.
 */
void cb_vprintf(struct charbuf *obj, char *format, va_list va);


M src/gc.c => src/gc.c +37 -37
@@ 9,56 9,56 @@

void lisp_init(lisp_runtime *rt)
{
  rt->nil = type_list->new();
  rt->nil->mark = 0;
  rt->nil->type = type_list;
  rt->nil->next = NULL;
  rt->head = rt->nil;
  rt->tail = rt->nil;
  rb_init(&rt->rb, sizeof(lisp_value*), 16);
	rt->nil = type_list->new();
	rt->nil->mark = 0;
	rt->nil->type = type_list;
	rt->nil->next = NULL;
	rt->head = rt->nil;
	rt->tail = rt->nil;
	rb_init(&rt->rb, sizeof(lisp_value*), 16);
}

void lisp_destroy(lisp_runtime *rt)
{
  lisp_sweep(rt);
  rb_destroy(&rt->rb);
  lisp_free(rt->nil);
	lisp_sweep(rt);
	rb_destroy(&rt->rb);
	lisp_free(rt->nil);
}

void lisp_mark(lisp_runtime *rt, lisp_value *v)
{
  rb_push_back(&rt->rb, &v);
	rb_push_back(&rt->rb, &v);

  while (rt->rb.count > 0) {
    rb_pop_front(&rt->rb, &v);
    v->mark = GC_MARKED;
    struct iterator it = v->type->expand(v);
    while (it.has_next(&it)) {
      v = it.next(&it);
      if (v->mark == GC_NOMARK) {
        v->mark = GC_QUEUED;
        rb_push_back(&rt->rb, &v);
      }
    }
    it.close(&it);
  }
	while (rt->rb.count > 0) {
		rb_pop_front(&rt->rb, &v);
		v->mark = GC_MARKED;
		struct iterator it = v->type->expand(v);
		while (it.has_next(&it)) {
			v = it.next(&it);
			if (v->mark == GC_NOMARK) {
				v->mark = GC_QUEUED;
				rb_push_back(&rt->rb, &v);
			}
		}
		it.close(&it);
	}
}

void lisp_sweep(lisp_runtime *rt)
{
  lisp_value *curr = rt->head;
	lisp_value *curr = rt->head;

  while (curr->next) {
    if (curr->next->mark != GC_MARKED) {
      lisp_value *tmp = curr->next->next;
      lisp_free(curr->next);
      curr->next = tmp;
    } else {
      curr->mark = GC_NOMARK;
      curr = curr->next;
    }
  }
	while (curr->next) {
		if (curr->next->mark != GC_MARKED) {
			lisp_value *tmp = curr->next->next;
			lisp_free(curr->next);
			curr->next = tmp;
		} else {
			curr->mark = GC_NOMARK;
			curr = curr->next;
		}
	}

  curr->mark = GC_NOMARK;
  rt->tail = curr;
	curr->mark = GC_NOMARK;
	rt->tail = curr;
}

M src/hashtable.c => src/hashtable.c +294 -281
@@ 32,167 32,175 @@
 */

unsigned int ht_primes[] = {
  31, // 2^5
  61,
  127,
  257,
  509,
  1021,
  2053,
  4093,
  8191,
  16381,
  32771,
  65537,
  131071,
  262147,
  524287,
  1048573,
  2097143,
  4194301,
  8388617,
  16777213,
  33554467,
  67108859,
  134217757,
  268435459,
  536870909,
  1073741827,
  2147483647,
  4294967291 // 2^32
	31, // 2^5
	61,
	127,
	257,
	509,
	1021,
	2053,
	4093,
	8191,
	16381,
	32771,
	65537,
	131071,
	262147,
	524287,
	1048573,
	2097143,
	4194301,
	8388617,
	16777213,
	33554467,
	67108859,
	134217757,
	268435459,
	536870909,
	1073741827,
	2147483647,
	4294967291 // 2^32
};

int binary_search(unsigned int *array, int len, unsigned int value)
{
  int lo = 0, hi = len, mid;
  while (lo < hi) {
    mid = (lo + hi) / 2;
    if (value <= array[mid]) {
      hi = mid;
    } else {
      lo = mid + 1;
    }
  }
  return lo;
	int lo = 0, hi = len, mid;
	while (lo < hi) {
		mid = (lo + hi) / 2;
		if (value <= array[mid]) {
			hi = mid;
		} else {
			lo = mid + 1;
		}
	}
	return lo;
}

/**
   @brief Returns the next hashtable size.
 * @brief Returns the next hashtable size.

   @param current The current size of the hash table.
   @returns The next size in the sequence for hash tables.
 * @param current The current size of the hash table.
 * @returns The next size in the sequence for hash tables.
 */
int ht_next_size(int current)
{
  int curridx = binary_search(ht_primes, nelem(ht_primes), current);
  return ht_primes[curridx + 1];
	int curridx = binary_search(ht_primes, nelem(ht_primes), current);
	return ht_primes[curridx + 1];
}

unsigned int item_size(const struct hashtable *obj)
{
  return HTA_KEY_OFFSET + obj->key_size + obj->value_size;
	return HTA_KEY_OFFSET + obj->key_size + obj->value_size;
}

unsigned int convert_idx(const struct hashtable *obj, unsigned int orig)
{
  return orig * item_size(obj);
	return orig * item_size(obj);
}

/**
   @brief Find the proper index for insertion into the table.
   @param obj Hash table object.
   @param key Key we're inserting.
 * @brief Find the proper index for insertion into the table.
 * @param obj Hash table object.
 * @param key Key we're inserting.
 */
unsigned int ht_find_insert(const struct hashtable *obj, void *key)
{
  unsigned int index = obj->hash(key) % obj->allocated;
  unsigned int bufidx = convert_idx(obj, index);
  unsigned int j = 1;

  // Continue searching until we either find a non-full slot, or we find the key
  // we're trying to insert.
  // until (cell.mark != full || cell.key == key)
  // while (cell.mark == full && cell.key != key)
  while (HTA_MARK(obj, bufidx) == HT_FULL &&
         obj->equal(key, obj->table + bufidx + HTA_KEY_OFFSET) != 0) {
    // This is quadratic probing, but I'm avoiding squaring numbers:
    // j:     1, 3, 5, 7,  9, 11, ..
    // index: 0, 1, 4, 9, 16, 25, 36
    index = (index + j) % obj->allocated;
    j += 2;
    bufidx = convert_idx(obj, index);
  }

  return index;
	unsigned int index = obj->hash(key) % obj->allocated;
	unsigned int bufidx = convert_idx(obj, index);
	unsigned int j = 1;

	/*
	 * Continue searching until we either find a non-full slot, or we find
	 * the key we're trying to insert:
	 * until (cell.mark != full || cell.key == key)
	 * while (cell.mark == full && cell.key != key)
	 */
	while (HTA_MARK(obj, bufidx) == HT_FULL &&
	       obj->equal(key, obj->table + bufidx + HTA_KEY_OFFSET) != 0) {
		/*
		 * This is quadratic probing, but I'm avoiding squaring numbers:
		 * j:     1, 3, 5, 7,  9, 11, ..
		 * index: 0, 1, 4, 9, 16, 25, 36
		 */
		index = (index + j) % obj->allocated;
		j += 2;
		bufidx = convert_idx(obj, index);
	}

	return index;
}

/**
   @brief Find the proper index for retrieval from the table.
   @param obj Hash table object.
   @param key Key we're looking up.
 * @brief Find the proper index for retrieval from the table.
 * @param obj Hash table object.
 * @param key Key we're looking up.
 */
unsigned int ht_find_retrieve(const struct hashtable *obj, void *key)
{
  unsigned int index = obj->hash(key) % obj->allocated;
  unsigned int bufidx = convert_idx(obj, index);
  unsigned int j = 1;

  // Continue searching until we either find an empty slot, or we find the key
  // we're trying to insert.
  // until (cell.mark == empty || cell.key == key)
  // while (cell.mark != empty && cell.key != key)
  while (HTA_MARK(obj, bufidx) != HT_EMPTY &&
         obj->equal(key, obj->table + bufidx + HTA_KEY_OFFSET) != 0) {
    // This is quadratic probing, but I'm avoiding squaring numbers:
    // j:     1, 3, 5, 7,  9, 11, ..
    // index: 0, 1, 4, 9, 16, 25, 36
    index = (index + j) % obj->allocated;
    j += 2;
    bufidx = convert_idx(obj, index);
  }

  return index;
	unsigned int index = obj->hash(key) % obj->allocated;
	unsigned int bufidx = convert_idx(obj, index);
	unsigned int j = 1;

	/*
	 * Continue searching until we either find an empty slot, or we find
	 * the key we're trying to insert:
	 * until (cell.mark == empty || cell.key == key)
	 * while (cell.mark != empty && cell.key != key)
	 */
	while (HTA_MARK(obj, bufidx) != HT_EMPTY &&
	       obj->equal(key, obj->table + bufidx + HTA_KEY_OFFSET) != 0) {
		/*
		 * This is quadratic probing, but I'm avoiding squaring numbers:
		 * j:     1, 3, 5, 7,  9, 11, ..
		 * index: 0, 1, 4, 9, 16, 25, 36
		 */
		index = (index + j) % obj->allocated;
		j += 2;
		bufidx = convert_idx(obj, index);
	}

	return index;
}

/**
   @brief Expand the hash table, adding increment to the capacity of the table.

   @param table The table to expand.
 * @brief Expand the hash table, adding increment to the capacity of the table.
 *
 * @param table The table to expand.
 */
void ht_resize(struct hashtable *table)
{
  void *old_table;
  unsigned int index, old_allocated, bufidx;

  // Step one: allocate new space for the table
  old_table = table->table;
  old_allocated = table->allocated;
  table->length = 0;
  table->allocated = ht_next_size(old_allocated);
  table->table = calloc(table->allocated, item_size(table));

  // Step two, add the old items to the new table.
  for (index = 0; index < old_allocated; index++) {
    bufidx = convert_idx(table, index);
    if (((int8_t*)old_table)[bufidx] == HT_FULL) {
      ht_insert(table, old_table + bufidx + HTA_KEY_OFFSET,
                 old_table + bufidx + HTA_KEY_OFFSET + table->value_size);
    }
  }

  // Step three: free old data.
  free(old_table);
	void *old_table;
	unsigned int index, old_allocated, bufidx;

	/* Step one: allocate new space for the table */
	old_table = table->table;
	old_allocated = table->allocated;
	table->length = 0;
	table->allocated = ht_next_size(old_allocated);
	table->table = calloc(table->allocated, item_size(table));

	/* Step two, add the old items to the new table. */
	for (index = 0; index < old_allocated; index++) {
		bufidx = convert_idx(table, index);
		if (((int8_t*)old_table)[bufidx] == HT_FULL) {
			ht_insert(table, old_table + bufidx + HTA_KEY_OFFSET,
			          old_table + bufidx + HTA_KEY_OFFSET + table->value_size);
		}
	}

	/* Step three: free old data. */
	free(old_table);
}

/**
   @brief Return the load factor of a hash table.

   @param table The table to find the load factor of.
   @returns The load factor of the hash table.
 * @brief Return the load factor of a hash table.
 *
 * @param table The table to find the load factor of.
 * @returns The load factor of the hash table.
 */
double ht_load_factor(struct hashtable *table)
{
  return ((double) table->length) / ((double) table->allocated);
	return ((double) table->length) / ((double) table->allocated);
}

/*


@@ 200,265 208,270 @@ double ht_load_factor(struct hashtable *table)
 */

void ht_init(struct hashtable *table, hash_t hash_func, comp_t equal,
              unsigned int key_size, unsigned int value_size)
             unsigned int key_size, unsigned int value_size)
{
  // Initialize values
  table->length = 0;
  table->allocated = HASH_TABLE_INITIAL_SIZE;
  table->key_size = key_size;
  table->value_size = value_size;
  table->hash = hash_func;
  table->equal = equal;

  // Allocate table
  table->table = calloc(HASH_TABLE_INITIAL_SIZE, item_size(table));
	/* Initialize values */
	table->length = 0;
	table->allocated = HASH_TABLE_INITIAL_SIZE;
	table->key_size = key_size;
	table->value_size = value_size;
	table->hash = hash_func;
	table->equal = equal;

	/* Allocate table */
	table->table = calloc(HASH_TABLE_INITIAL_SIZE, item_size(table));
}

struct hashtable *ht_create(hash_t hash_func, comp_t equal,
                    unsigned int key_size, unsigned int value_size)
                            unsigned int key_size, unsigned int value_size)
{
  // Allocate and create the table.
  struct hashtable *table;
  table = calloc(sizeof(struct hashtable), 1);
  ht_init(table, hash_func, equal, key_size, value_size);
  return table;
	/* Allocate and create the table. */
	struct hashtable *table;
	table = calloc(sizeof(struct hashtable), 1);
	ht_init(table, hash_func, equal, key_size, value_size);
	return table;
}

void ht_destroy(struct hashtable *table)
{
  free(table->table);
	free(table->table);
}

void ht_delete(struct hashtable *table)
{
  if (!table) {
    return;
  }
	if (!table) {
		return;
	}

  ht_destroy(table);
  free(table);
	ht_destroy(table);
	free(table);
}

void ht_insert(struct hashtable *table, void *key, void *value)
{
  unsigned int index, bufidx;
  if (ht_load_factor(table) > HASH_TABLE_MAX_LOAD_FACTOR) {
    ht_resize(table);
  }

  // First, probe for the key as if we're trying to return it.  If we find it,
  // we update the existing key.
  index = ht_find_retrieve(table, key);
  bufidx = convert_idx(table, index);
  if (HTA_MARK(table, bufidx) == HT_FULL) {
    memcpy(table->table + bufidx + HTA_KEY_OFFSET + table->key_size, value,
           table->value_size);
    return;
  }

  // If we don't find the key, then we find the first open slot or gravestone.
  index = ht_find_insert(table, key);
  bufidx = convert_idx(table, index);
  HTA_MARK(table, bufidx) = HT_FULL;
  memcpy(table->table + bufidx + HTA_KEY_OFFSET, key, table->key_size);
  memcpy(table->table + bufidx + HTA_KEY_OFFSET + table->key_size, value,
         table->value_size);
  table->length++;
	unsigned int index, bufidx;
	if (ht_load_factor(table) > HASH_TABLE_MAX_LOAD_FACTOR) {
		ht_resize(table);
	}

	/*
	 * First, probe for the key as if we're trying to return it. If we find
	 * it, we update the existing key.
	 */
	index = ht_find_retrieve(table, key);
	bufidx = convert_idx(table, index);
	if (HTA_MARK(table, bufidx) == HT_FULL) {
		memcpy(table->table + bufidx + HTA_KEY_OFFSET + table->key_size,
		       value, table->value_size);
		return;
	}

	/*
	 * If we don't find the key, then we find the first open slot or
	 * gravestone.
	 */
	index = ht_find_insert(table, key);
	bufidx = convert_idx(table, index);
	HTA_MARK(table, bufidx) = HT_FULL;
	memcpy(table->table + bufidx + HTA_KEY_OFFSET, key, table->key_size);
	memcpy(table->table + bufidx + HTA_KEY_OFFSET + table->key_size, value,
	       table->value_size);
	table->length++;
}

void ht_insert_ptr(struct hashtable *table, void *key, void *value)
{
  ht_insert(table, &key, &value);
	ht_insert(table, &key, &value);
}

int ht_remove(struct hashtable *table, void *key)
{
  unsigned int index = ht_find_retrieve(table, key);
  unsigned int bufidx = convert_idx(table, index);

  // If the returned slot isn't full, that means we couldn't find it.
  if (HTA_MARK(table, bufidx) != HT_FULL) {
    return -1;
  }

  // Mark the slot with a "grave stone", indicating it is deleted.
  HTA_MARK(table, bufidx) = HT_GRAVE;
  table->length--;
  return 0;
	unsigned int index = ht_find_retrieve(table, key);
	unsigned int bufidx = convert_idx(table, index);

	/* If the returned slot isn't full, that means we couldn't find it. */
	if (HTA_MARK(table, bufidx) != HT_FULL) {
		return -1;
	}

	/* Mark the slot with a "grave stone", indicating it is deleted. */
	HTA_MARK(table, bufidx) = HT_GRAVE;
	table->length--;
	return 0;
}

int ht_remove_ptr(struct hashtable *table, void *key)
{
  ht_remove(table, &key);
	ht_remove(table, &key);
}

void *ht_get(struct hashtable const *table, void *key)
{
  unsigned int index = ht_find_retrieve(table, key);
  unsigned int bufidx = convert_idx(table, index);
	unsigned int index = ht_find_retrieve(table, key);
	unsigned int bufidx = convert_idx(table, index);

  // If the slot is not marked full, we didn't find the key.
  if (HTA_MARK(table, bufidx) != HT_FULL) {
    return NULL;
  }
	/* If the slot is not marked full, we didn't find the key. */
	if (HTA_MARK(table, bufidx) != HT_FULL) {
		return NULL;
	}

  // Otherwise, return the value.
  return table->table + bufidx + HTA_KEY_OFFSET + table->key_size;
	/* Otherwise, return the value. */
	return table->table + bufidx + HTA_KEY_OFFSET + table->key_size;
}

void *ht_get_ptr(struct hashtable const *table, void *key)
{
  void **result = ht_get(table, &key);
  if (!result) {
    return NULL;
  }
  return *result;
	void **result = ht_get(table, &key);
	if (!result) {
		return NULL;
	}
	return *result;
}

bool ht_contains(struct hashtable const *table, void *key)
{
  return ht_get(table, key) != NULL;
	return ht_get(table, key) != NULL;
}

bool ht_contains_ptr(struct hashtable const *table, void *key)
{
  return ht_contains(table, &key);
	return ht_contains(table, &key);
}

unsigned int ht_string_hash(void *data)
{
  char *theString = *(char**)data;
  unsigned int hash = 0;
	char *theString = *(char**)data;
	unsigned int hash = 0;

  while (theString && *theString != '\0' ) {
    hash = (hash << 5) - hash + *theString;
    theString++;
  }
	while (theString && *theString != '\0' ) {
		hash = (hash << 5) - hash + *theString;
		theString++;
	}

  return hash;
	return hash;
}

int ht_string_comp(void *left, void *right)
{
  char **l = (char**)left, **r = (char**)right;
  return strcmp(*l,*r);
	char **l = (char**)left, **r = (char**)right;
	return strcmp(*l,*r);
}

int ht_int_comp(void *left, void *right)
{
  int *l = (int*)left, *r = (int*)right;
  return *l - *r;
	int *l = (int*)left, *r = (int*)right;
	return *l - *r;
}

void ht_print(FILE* f, struct hashtable const *table, print_t key, print_t value,
               int full_mode)
              int full_mode)
{
  unsigned int i, bufidx;
  char *MARKS[] = {"EMPTY", " FULL", "GRAVE"};

  for (i = 0; i < table->allocated; i++) {
    bufidx = convert_idx(table, i);
    int8_t mark = HTA_MARK(table, bufidx);
    if (full_mode || mark == HT_FULL) {
      printf("[%04d|%05d|%s]:\n", i, bufidx, MARKS[mark]);
      if (mark == HT_FULL) {
        printf("  key: ");
        if (key) key(f, table->table + bufidx + HTA_KEY_OFFSET);
        printf("\n  value: ");
        if (value) value(f, table->table + bufidx + HTA_KEY_OFFSET + table->key_size);
        printf("\n");
      }
    }
  }
	unsigned int i, bufidx;
	char *MARKS[] = {"EMPTY", " FULL", "GRAVE"};

	for (i = 0; i < table->allocated; i++) {
		bufidx = convert_idx(table, i);
		int8_t mark = HTA_MARK(table, bufidx);
		if (full_mode || mark == HT_FULL) {
			printf("[%04d|%05d|%s]:\n", i, bufidx, MARKS[mark]);
			if (mark == HT_FULL) {
				printf("  key: ");
				if (key) key(f, table->table + bufidx + HTA_KEY_OFFSET);
				printf("\n  value: ");
				if (value) value(f, table->table + bufidx + HTA_KEY_OFFSET + table->key_size);
				printf("\n");
			}
		}
	}
}

static void *ht_next(struct iterator *iter)
{
  struct hashtable *table = iter->ds;
  unsigned int bufidx;
  int8_t mark = HT_EMPTY;
	struct hashtable *table = iter->ds;
	unsigned int bufidx;
	int8_t mark = HT_EMPTY;

  for (; mark != HT_FULL && iter->state_int < table->allocated; iter->state_int++) {
    bufidx = convert_idx(table, iter->state_int);
    mark = HTA_MARK(table, bufidx);
  }
	for (; mark != HT_FULL && iter->state_int < table->allocated; iter->state_int++) {
		bufidx = convert_idx(table, iter->state_int);
		mark = HTA_MARK(table, bufidx);
	}

  if (mark != HT_FULL) return NULL;
	if (mark != HT_FULL) return NULL;

  iter->index++;
	iter->index++;

  if (!iter->state_ptr)
    return table->table + bufidx + HTA_KEY_OFFSET;
  else
    return table->table + bufidx + HTA_KEY_OFFSET + table->key_size;
	if (!iter->state_ptr)
		return table->table + bufidx + HTA_KEY_OFFSET;
	else
		return table->table + bufidx + HTA_KEY_OFFSET + table->key_size;
}

static void *ht_next_ptr(struct iterator *iter)
{
  void **res = ht_next(iter);
  if (res == NULL)
    return NULL;
  return *res;
	void **res = ht_next(iter);
	if (res == NULL)
		return NULL;
	return *res;
}

static bool ht_has_next(struct iterator *iter)
{
  struct hashtable *table = iter->ds;
  return iter->index < table->length;
	struct hashtable *table = iter->ds;
	return iter->index < table->length;
}

struct iterator ht_iter_keys(struct hashtable *table)
{
  struct iterator it = {
    .ds = table,
    .index = 0,
    .state_int = 0,
    .state_ptr = NULL, /* when null, return keys, else return values */
    .has_next = ht_has_next,
    .next = ht_next,
    .close = iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds = table,
		.index = 0,
		.state_int = 0,
		.state_ptr = NULL, /* when null, return keys, else return values */
		.has_next = ht_has_next,
		.next = ht_next,
		.close = iterator_close_noop,
	};
	return it;
}

struct iterator ht_iter_keys_ptr(struct hashtable *table)
{
  struct iterator it = {
    .ds = table,
    .index = 0,
    .state_int = 0,
    .state_ptr = NULL, /* when null, return keys, else return values */
    .has_next = ht_has_next,
    .next = ht_next_ptr,
    .close = iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds = table,
		.index = 0,
		.state_int = 0,
		.state_ptr = NULL, /* when null, return keys, else return values */
		.has_next = ht_has_next,
		.next = ht_next_ptr,
		.close = iterator_close_noop,
	};
	return it;
}

struct iterator ht_iter_values(struct hashtable *table)
{
  struct iterator it = {
    .ds = table,
    .index = 0,
    .state_int = 0,
    .state_ptr = table, /* when null, return keys, else return values */
    .has_next = ht_has_next,
    .next = ht_next,
    .close = iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds = table,
		.index = 0,
		.state_int = 0,
		.state_ptr = table, /* when null, return keys, else return values */
		.has_next = ht_has_next,
		.next = ht_next,
		.close = iterator_close_noop,
	};
	return it;
}

struct iterator ht_iter_values_ptr(struct hashtable *table)
{
  struct iterator it = {
    .ds = table,
    .index = 0,
    .state_int = 0,
    .state_ptr = table, /* when null, return keys, else return values */
    .has_next = ht_has_next,
    .next = ht_next_ptr,
    .close = iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds = table,
		.index = 0,
		.state_int = 0,
		.state_ptr = table, /* when null, return keys, else return values */
		.has_next = ht_has_next,
		.next = ht_next_ptr,
		.close = iterator_close_noop,
	};
	return it;
}

M src/hashtable.h => src/hashtable.h +56 -56
@@ 18,97 18,97 @@ typedef int (*print_t)(FILE *f, void *data);

struct hashtable
{
  unsigned int length;    /* number of items currently in the table */
  unsigned int allocated; /* number of items allocated */
	unsigned int length;    /* number of items currently in the table */
	unsigned int allocated; /* number of items allocated */

  unsigned int key_size;
  unsigned int value_size;
	unsigned int key_size;
	unsigned int value_size;

  hash_t hash;
  comp_t equal;
	hash_t hash;
	comp_t equal;

  void *table;
	void *table;
};

/**
   @brief Initialize a hash table in memory already allocated.
   @param table A pointer to the table to initialize.
   @param hash_func A hash function for the table.
   @param equal A comparison function for void pointers
   @param key_size Size of keys.
   @param value_size Size of values.
 * @brief Initialize a hash table in memory already allocated.
 * @param table A pointer to the table to initialize.
 * @param hash_func A hash function for the table.
 * @param equal A comparison function for void pointers
 * @param key_size Size of keys.
 * @param value_size Size of values.
 */
void ht_init(struct hashtable *table, hash_t hash_func, comp_t equal,
              unsigned int key_size, unsigned int value_size);
             unsigned int key_size, unsigned int value_size);
/**
   @brief Allocate and initialize a hash table.
   @param hash_func A function that takes one void* and returns a hash value
   generated from it.  It should be a good hash function.
   @param equal A comparison function for void pointers.
   @param key_size Size of keys.
   @param value_size Size of values.
   @returns A pointer to the new hash table.
 * @brief Allocate and initialize a hash table.
 * @param hash_func A function that takes one void* and returns a hash value
 * generated from it.  It should be a good hash function.
 * @param equal A comparison function for void pointers.
 * @param key_size Size of keys.
 * @param value_size Size of values.
 * @returns A pointer to the new hash table.
 */
struct hashtable *ht_create(hash_t hash_func, comp_t equal,
                    unsigned int key_size, unsigned int value_size);
                            unsigned int key_size, unsigned int value_size);
/**
   @brief Free any resources used by the hash table, but doesn't free the
   pointer.  Doesn't perform any actions on the data as it is deleted.

   If pointers are contained within the hash table, they are not freed. Use to
   specify a deletion action on the hash table.
   @param table The table to destroy.
 * @brief Free any resources used by the hash table, but doesn't free the
 * pointer.  Doesn't perform any actions on the data as it is deleted.
 *
 * If pointers are contained within the hash table, they are not freed. Use to
 * specify a deletion action on the hash table.
 * @param table The table to destroy.
 */
void ht_destroy(struct hashtable *table);
/**
   @brief Free the hash table and its resources.  No pointers contained in the
   table will be freed.
   @param table The table to free.
 * @brief Free the hash table and its resources.	No pointers contained in the
 * table will be freed.
 * @param table The table to free.
 */
void ht_delete(struct hashtable *table);

/**
   @brief Insert data into the hash table.

   Expands the hash table if the load factor is below a threshold.  If the key
   already exists in the table, then the function will overwrite it with the new
   data provided.
   @param table A pointer to the hash table.
   @param key The key to insert.
   @param value The value to insert at the key.
 * @brief Insert data into the hash table.
 *
 * Expands the hash table if the load factor is below a threshold.	If the key
 * already exists in the table, then the function will overwrite it with the new
 * data provided.
 * @param table A pointer to the hash table.
 * @param key The key to insert.
 * @param value The value to insert at the key.
 */
void ht_insert(struct hashtable *table, void *key, void *value);
void ht_insert_ptr(struct hashtable *table, void *key, void *value);
/**
   @brief Remove the key, value pair stored in the hash table.

   This function does not call a deleter on the stored data.
   @param table A pointer to the hash table.
   @param key The key to delete.
   @return -1 on failure, 0 otherwise
 * @brief Remove the key, value pair stored in the hash table.
 *
 * This function does not call a deleter on the stored data.
 * @param table A pointer to the hash table.
 * @param key The key to delete.
 * @return -1 on failure, 0 otherwise
 */
int ht_remove(struct hashtable *table, void *key);
int ht_remove_ptr(struct hashtable *table, void *key);
/**
   @brief Return the value associated with the key provided.
   @param table A pointer to the hash table.
   @param key The key whose value to retrieve.
   @returns The value associated the key, NULL if not found
 * @brief Return the value associated with the key provided.
 * @param table A pointer to the hash table.
 * @param key The key whose value to retrieve.
 * @returns The value associated the key, NULL if not found
 */
void *ht_get(struct hashtable const *table, void *key);
void *ht_get_ptr(struct hashtable const *table, void *key);
/**
   @brief Return true when a key is contained in the table.
   @param table A pointer to the hash table.
   @param key The key to search for.
   @returns Whether the key is present.
 * @brief Return true when a key is contained in the table.
 * @param table A pointer to the hash table.
 * @param key The key to search for.
 * @returns Whether the key is present.
 */
bool ht_contains(struct hashtable const *table, void *key);
bool ht_contains_ptr(struct hashtable const *table, void *key);
/**
   @brief Return the hash of the data, interpreting it as a string.
   @param data The string to hash, assuming that the value contained is a char*.
   @returns The hash value of the string.
 * @brief Return the hash of the data, interpreting it as a string.
 * @param data The string to hash, assuming that the value contained is a char*.
 * @returns The hash value of the string.
 */
unsigned int ht_string_hash(void *data);


M src/iter.c => src/iter.c +62 -62
@@ 14,113 14,113 @@ void iterator_close_noop(struct iterator *iter) {}

static bool sv_has_next(struct iterator *iter)
{
  return iter->index == 0;
	return iter->index == 0;
}

static void *sv_next(struct iterator *iter)
{
  iter->index++;
  return iter->ds;
	iter->index++;
	return iter->ds;
}

struct iterator iterator_single_value(void *value)
{
  struct iterator it = {
    .ds=value,
    .index=0,
    .has_next=sv_has_next,
    .next=sv_next,
    .close=iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds=value,
		.index=0,
		.has_next=sv_has_next,
		.next=sv_next,
		.close=iterator_close_noop,
	};
	return it;
}

static bool cc_has_next(struct iterator *iter)
{
  struct iterator *its = iter->ds;
  intptr_t max_iterators = (intptr_t) iter->state_ptr;
  bool has_next;
	struct iterator *its = iter->ds;
	intptr_t max_iterators = (intptr_t) iter->state_ptr;
	bool has_next;

  while (iter->state_int < max_iterators) {
    has_next = its[iter->state_int].has_next(&its[iter->state_int]);
    if (has_next) {
      return true;
    }
	while (iter->state_int < max_iterators) {
		has_next = its[iter->state_int].has_next(&its[iter->state_int]);
		if (has_next) {
			return true;
		}

    its[iter->state_int].close(&its[iter->state_int]);
    iter->state_int++;
  }
		its[iter->state_int].close(&its[iter->state_int]);
		iter->state_int++;
	}

  return false;
	return false;
}

static void *cc_next(struct iterator *iter)
{
  struct iterator *its = iter->ds;
  void *result = its[iter->state_int].next(&its[iter->state_int]);
  if (result) {
    iter->index++;
  }
  return result;
	struct iterator *its = iter->ds;
	void *result = its[iter->state_int].next(&its[iter->state_int]);
	if (result) {
		iter->index++;
	}
	return result;
}

static void cc_close(struct iterator *iter)
{
  free(iter->ds);
	free(iter->ds);
}

struct iterator iterator_concat(struct iterator *its, size_t n)
{
  struct iterator it = {
    .ds = its,
    .index = 0,
    .state_int = 0,
    .state_ptr = (void*) n,

    .has_next = cc_has_next,
    .next = cc_next,
    .close = cc_close,
  };
  return it;
	struct iterator it = {
		.ds = its,
		.index = 0,
		.state_int = 0,
		.state_ptr = (void*) n,

		.has_next = cc_has_next,
		.next = cc_next,
		.close = cc_close,
	};
	return it;
}

struct iterator iterator_concat2(struct iterator left, struct iterator right)
{
  struct iterator *arr = calloc(sizeof(struct iterator), 2);
  arr[0] = left;
  arr[1] = right;
  return iterator_concat(arr, 2);
	struct iterator *arr = calloc(sizeof(struct iterator), 2);
	arr[0] = left;
	arr[1] = right;
	return iterator_concat(arr, 2);
}

struct iterator iterator_concat3(struct iterator a, struct iterator b,
                                 struct iterator c)
																 struct iterator c)
{
  struct iterator *arr = calloc(sizeof(struct iterator), 3);
  arr[0] = a;
  arr[1] = b;
  arr[2] = c;
  return iterator_concat(arr, 3);
	struct iterator *arr = calloc(sizeof(struct iterator), 3);
	arr[0] = a;
	arr[1] = b;
	arr[2] = c;
	return iterator_concat(arr, 3);
}

static void *empty_next(struct iterator *iter)
{
  (void)iter;
  return NULL;
	(void)iter;
	return NULL;
}

static bool empty_has_next(struct iterator *iter)
{
  (void)iter;
  return false;
	(void)iter;
	return false;
}

struct iterator iterator_empty()
{
  struct iterator it = {
    .index=0,
    .next=empty_next,
    .has_next=empty_has_next,
    .close=iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.index=0,
		.next=empty_next,
		.has_next=empty_has_next,
		.close=iterator_close_noop,
	};
	return it;
}

M src/iter.h => src/iter.h +11 -11
@@ 9,19 9,19 @@
#define _ITER_H

struct iterator {
  void *ds;        /* the container data structure */
  size_t index;    /* zero-based index for the iterator */
  int state_int;   /* some state variables that may help */
  void *state_ptr;
	void *ds;        /* the container data structure */
	size_t index;    /* zero-based index for the iterator */
	int state_int;   /* some state variables that may help */
	void *state_ptr;

  /* do we have a next item? */
  bool (*has_next)(struct iterator *iter);
	/* do we have a next item? */
	bool (*has_next)(struct iterator *iter);

  /* return the next item (or null) */
  void *(*next)(struct iterator *iter);
	/* return the next item (or null) */
	void *(*next)(struct iterator *iter);

  /* free resources held by the iterator */
  void (*close)(struct iterator *iter);
	/* free resources held by the iterator */
	void (*close)(struct iterator *iter);
};

void iterator_close_noop(struct iterator *iter);


@@ 34,6 34,6 @@ struct iterator iterator_concat(struct iterator *its, size_t n);
/* these use the above function */
struct iterator iterator_concat2(struct iterator left, struct iterator right);
struct iterator iterator_concat3(
  struct iterator a, struct iterator b, struct iterator c);
	struct iterator a, struct iterator b, struct iterator c);

#endif

M src/lisp.h => src/lisp.h +48 -48
@@ 19,94 19,94 @@
#define GC_MARKED 'b'

#define LISP_VALUE_HEAD             \
  struct {                          \
    struct lisp_type  *type;        \
    struct lisp_value *next;        \
    char mark;                      \
  }
	struct {                          \
		struct lisp_type  *type;        \
		struct lisp_value *next;        \
		char mark;                      \
	}


// Type declarations.
/* Type declarations. */
typedef struct lisp_value {
  LISP_VALUE_HEAD;
	LISP_VALUE_HEAD;
} lisp_value;

// A lisp_runtime is NOT a lisp_value!
/* A lisp_runtime is NOT a lisp_value! */
typedef struct {
  lisp_value *head;
  lisp_value *tail;
	lisp_value *head;
	lisp_value *tail;

  // Some special values we don't want to lose track of
  lisp_value *nil;
	/* Some special values we don't want to lose track of */
	lisp_value *nil;

  struct ringbuf rb;
	struct ringbuf rb;
} lisp_runtime;

// The below ARE lisp_values!
/* The below ARE lisp_values! */
typedef struct lisp_scope {
  LISP_VALUE_HEAD;
  struct hashtable scope;
  struct lisp_scope *up;
	LISP_VALUE_HEAD;
	struct hashtable scope;
	struct lisp_scope *up;
} lisp_scope;

typedef struct {
  LISP_VALUE_HEAD;
  lisp_value *left;
  lisp_value *right;
	LISP_VALUE_HEAD;
	lisp_value *left;
	lisp_value *right;
} lisp_list;

typedef struct lisp_type {
  LISP_VALUE_HEAD;
  const char *name;
  void (*print)(FILE *f, lisp_value *value);
  lisp_value * (*new)(void);
  void (*free)(void *value);
  struct iterator (*expand)(lisp_value*);
  lisp_value * (*eval)(lisp_runtime *rt, lisp_scope *scope, lisp_value *value);
  lisp_value * (*call)(lisp_runtime *rt, lisp_scope *scope, lisp_value *callable, lisp_value *arg);
	LISP_VALUE_HEAD;
	const char *name;
	void (*print)(FILE *f, lisp_value *value);
	lisp_value * (*new)(void);
	void (*free)(void *value);
	struct iterator (*expand)(lisp_value*);
	lisp_value * (*eval)(lisp_runtime *rt, lisp_scope *scope, lisp_value *value);
	lisp_value * (*call)(lisp_runtime *rt, lisp_scope *scope, lisp_value *callable, lisp_value *arg);
} lisp_type;

typedef struct {
  LISP_VALUE_HEAD;
  char *sym;
	LISP_VALUE_HEAD;
	char *sym;
} lisp_symbol;

typedef struct {
  LISP_VALUE_HEAD;
  char *message;
	LISP_VALUE_HEAD;
	char *message;
} lisp_error;

typedef struct {
  LISP_VALUE_HEAD;
  int x;
	LISP_VALUE_HEAD;
	int x;
} lisp_integer;

typedef struct {
  LISP_VALUE_HEAD;
  char *s;
	LISP_VALUE_HEAD;
	char *s;
} lisp_string;

typedef lisp_value * (*lisp_builtin_func)(lisp_runtime*, lisp_scope*,lisp_value*);
typedef struct {
  LISP_VALUE_HEAD;
  lisp_builtin_func call;
  char *name;
	LISP_VALUE_HEAD;
	lisp_builtin_func call;
	char *name;
} lisp_builtin;

typedef struct {
  LISP_VALUE_HEAD;
  lisp_list *args;
  lisp_value *code;
  lisp_scope *closure;
	LISP_VALUE_HEAD;
	lisp_list *args;
	lisp_value *code;
	lisp_scope *closure;
} lisp_lambda;

// Interpreter stuff
/* Interpreter stuff */
void lisp_init(lisp_runtime *rt);
void lisp_mark(lisp_runtime *rt, lisp_value *v);
void lisp_sweep(lisp_runtime *rt);
void lisp_destroy(lisp_runtime *rt);

// Shortcuts for type operations.
/* Shortcuts for type operations. */
void lisp_print(FILE *f, lisp_value *value);
void lisp_free(lisp_value *value);
lisp_value *lisp_eval(lisp_runtime *rt, lisp_scope *scope, lisp_value *value);


@@ 114,14 114,14 @@ lisp_value *lisp_call(lisp_runtime *rt, lisp_scope *scope, lisp_value *callable,
                      lisp_value *arguments);
lisp_value *lisp_new(lisp_runtime *rt, lisp_type *typ);

// Shortcuts for creation of objects
/* Shortcuts for creation of objects */
lisp_symbol *lisp_symbol_new(lisp_runtime *rt, char *string);
lisp_error *lisp_error_new(lisp_runtime *rt, char *message);
lisp_builtin *lisp_builtin_new(lisp_runtime *rt, char *name,
                               lisp_builtin_func call);
lisp_value *lisp_nil_new(lisp_runtime *rt);

// Helper functions
/* Helper functions */
void lisp_scope_bind(lisp_scope *scope, lisp_symbol *symbol, lisp_value *value);
lisp_value *lisp_scope_lookup(lisp_runtime *rt, lisp_scope *scope,
                              lisp_symbol *symbol);


@@ 131,7 131,7 @@ lisp_value *lisp_eval_list(lisp_runtime *rt, lisp_scope *scope, lisp_value *list
lisp_value *lisp_parse(lisp_runtime *rt, char *input);
bool lisp_get_args(lisp_list *list, char *format, ...);
lisp_value *lisp_quote(lisp_runtime *rt, lisp_value *value);
// List functions
/* List functions */
int lisp_list_length(lisp_list *list);
bool lisp_nil_p(lisp_value *l);


M src/main.c => src/main.c +20 -20
@@ 6,26 6,26 @@

int main(int argc, char **argv)
{
  lisp_runtime rt;
  lisp_init(&rt);
  lisp_scope *scope = (lisp_scope*)lisp_new(&rt, type_scope);
  lisp_scope_populate_builtins(&rt, scope);
	lisp_runtime rt;
	lisp_init(&rt);
	lisp_scope *scope = (lisp_scope*)lisp_new(&rt, type_scope);
	lisp_scope_populate_builtins(&rt, scope);

  while (true) {
    char *input = readline("> ");
    if (input == NULL) {
      break;
    }
    lisp_value *value = lisp_parse(&rt, input);
    add_history(input);
    free(input);
    lisp_value *result = lisp_eval(&rt, scope, value);
    lisp_print(stdout, result);
    fprintf(stdout, "\n");
    lisp_mark(&rt, (lisp_value*)scope);
    lisp_sweep(&rt);
  }
	while (true) {
		char *input = readline("> ");
		if (input == NULL) {
			break;
		}
		lisp_value *value = lisp_parse(&rt, input);
		add_history(input);
		free(input);
		lisp_value *result = lisp_eval(&rt, scope, value);
		lisp_print(stdout, result);
		fprintf(stdout, "\n");
		lisp_mark(&rt, (lisp_value*)scope);
		lisp_sweep(&rt);
	}

  lisp_destroy(&rt);
  return 0;
	lisp_destroy(&rt);
	return 0;
}

M src/parse.c => src/parse.c +111 -112
@@ 14,150 14,149 @@
#include "charbuf.h"

typedef struct {
  lisp_value *result;
  int index;
	lisp_value *result;
	int index;
} result;

result lisp_parse_value(lisp_runtime *rt, char *input, int index);

result lisp_parse_integer(lisp_runtime *rt, char *input, int index)
{
  //printf("lisp_parse_integer(%s, %d)\n", input, index);
  int n;
  lisp_integer *v = (lisp_integer*)lisp_new(rt, type_integer);
  sscanf(input + index, "%d%n", &v->x, &n);
  return (result){(lisp_value*)v, index + n};
	int n;
	lisp_integer *v = (lisp_integer*)lisp_new(rt, type_integer);
	sscanf(input + index, "%d%n", &v->x, &n);
	return (result){(lisp_value*)v, index + n};
}

char lisp_escape(char escape)
{
  switch (escape) {
  case 'a':
    return '\a';
  case 'b':
    return '\b';
  case 'f':
    return '\f';
  case 'n':
    return '\n';
  case 'r':
    return '\b';
  case 't':
    return '\t';
  case 'v':
    return '\v';
  default:
    return escape;
  }
	switch (escape) {
	case 'a':
		return '\a';
	case 'b':
		return '\b';
	case 'f':
		return '\f';
	case 'n':
		return '\n';
	case 'r':
		return '\b';
	case 't':
		return '\t';
	case 'v':
		return '\v';
	default:
		return escape;
	}
}

result lisp_parse_string(lisp_runtime *rt, char *input, int index)
{
  int i = index + 1;
  struct charbuf cb;
  cb_init(&cb, 16);
  while (input[i] && input[i] != '"') {
    if (input[i] == '\\') {
      cb_append(&cb, lisp_escape(input[++i]));
    } else {
      cb_append(&cb, input[i]);
    }
    i++;
  }
  cb_trim(&cb);
  lisp_string *str = (lisp_string*)lisp_new(rt, type_string);
  str->s = cb.buf;
  return (result){(lisp_value*)str, ++i};
	int i = index + 1;
	struct charbuf cb;
	cb_init(&cb, 16);
	while (input[i] && input[i] != '"') {
		if (input[i] == '\\') {
			cb_append(&cb, lisp_escape(input[++i]));
		} else {
			cb_append(&cb, input[i]);
		}
		i++;
	}
	cb_trim(&cb);
	lisp_string *str = (lisp_string*)lisp_new(rt, type_string);
	str->s = cb.buf;
	return (result){(lisp_value*)str, ++i};
}

result lisp_parse_list_or_sexp(lisp_runtime *rt, char *input, int index)
{
  while (isspace(input[index])) {index++;}
  if (input[index] == ')') {
    return (result){(lisp_value*)lisp_nil_new(rt), index + 1};
  }

  result r = lisp_parse_value(rt, input, index);
  index = r.index;
  lisp_list *rv = (lisp_list*)lisp_new(rt, type_list);
  rv->left = r.result;
  lisp_list *l = rv;

  while (true) {
    while (isspace(input[index])) {
      index++;
    }

    if (input[index] == '.') {
      index++;
      result r = lisp_parse_value(rt, input, index);
      index = r.index;
      l->right = r.result;
      return (result){(lisp_value*)rv, index};
    } else if (input[index] == ')') {
      index++;
      l->right = lisp_nil_new(rt);
      return (result){(lisp_value*)rv, index};
    } else {
      result r = lisp_parse_value(rt, input, index);
      l->right = lisp_new(rt, type_list);
      l = (lisp_list*)l->right;
      l->left = r.result;
      index = r.index;
    }
  }
	while (isspace(input[index])) {index++;}
	if (input[index] == ')') {
		return (result){(lisp_value*)lisp_nil_new(rt), index + 1};
	}

	result r = lisp_parse_value(rt, input, index);
	index = r.index;
	lisp_list *rv = (lisp_list*)lisp_new(rt, type_list);
	rv->left = r.result;
	lisp_list *l = rv;

	while (true) {
		while (isspace(input[index])) {
			index++;
		}

		if (input[index] == '.') {
			index++;
			result r = lisp_parse_value(rt, input, index);
			index = r.index;
			l->right = r.result;
			return (result){(lisp_value*)rv, index};
		} else if (input[index] == ')') {
			index++;
			l->right = lisp_nil_new(rt);
			return (result){(lisp_value*)rv, index};
		} else {
			result r = lisp_parse_value(rt, input, index);
			l->right = lisp_new(rt, type_list);
			l = (lisp_list*)l->right;
			l->left = r.result;
			index = r.index;
		}
	}
}

result lisp_parse_symbol(lisp_runtime *rt, char *input, int index)
{
  int n = 0;
  while (input[index + n] && !isspace(input[index + n]) &&
         input[index + n] != ')' && input[index + n] != '.' &&
         input[index + n] != '\'') {
    n++;
  }
  lisp_symbol *s = (lisp_symbol*)lisp_new(rt, type_symbol);
  s->sym = malloc(n + 1);
  strncpy(s->sym, input + index, n);
  s->sym[n] = '\0';
  return (result){(lisp_value*)s, index + n};
	int n = 0;
	while (input[index + n] && !isspace(input[index + n]) &&
	       input[index + n] != ')' && input[index + n] != '.' &&
	       input[index + n] != '\'') {
		n++;
	}
	lisp_symbol *s = (lisp_symbol*)lisp_new(rt, type_symbol);
	s->sym = malloc(n + 1);
	strncpy(s->sym, input + index, n);
	s->sym[n] = '\0';
	return (result){(lisp_value*)s, index + n};
}

result lisp_parse_quote(lisp_runtime *rt, char *input, int index)
{
  result r = lisp_parse_value(rt, input, index + 1);
  r.result = lisp_quote(rt, r.result);
  return r;
	result r = lisp_parse_value(rt, input, index + 1);
	r.result = lisp_quote(rt, r.result);
	return r;
}

result lisp_parse_value(lisp_runtime *rt, char *input, int index)
{
  while (isspace(input[index])) {
    index++;
  }

  if (input[index] == '"') {
    return lisp_parse_string(rt, input, index);
  }
  if (input[index] == '\0') {
    return (result){NULL, index};
  }
  if (input[index] == ')') {
    return (result){lisp_nil_new(rt), index + 1};
  }
  if (input[index] == '(') {
    return lisp_parse_list_or_sexp(rt, input, index + 1);
  }
  if (input[index] == '\'') {
    return lisp_parse_quote(rt, input, index);
  }
  if (isdigit(input[index])) {
    return lisp_parse_integer(rt, input, index);
  }
  return lisp_parse_symbol(rt, input, index);
	while (isspace(input[index])) {
		index++;
	}

	if (input[index] == '"') {
		return lisp_parse_string(rt, input, index);
	}
	if (input[index] == '\0') {
		return (result){NULL, index};
	}
	if (input[index] == ')') {
		return (result){lisp_nil_new(rt), index + 1};
	}
	if (input[index] == '(') {
		return lisp_parse_list_or_sexp(rt, input, index + 1);
	}
	if (input[index] == '\'') {
		return lisp_parse_quote(rt, input, index);
	}
	if (isdigit(input[index])) {
		return lisp_parse_integer(rt, input, index);
	}
	return lisp_parse_symbol(rt, input, index);
}

lisp_value *lisp_parse(lisp_runtime *rt, char *input)
{
  return lisp_parse_value(rt, input, 0).result;
	return lisp_parse_value(rt, input, 0).result;
}

M src/ringbuf.c => src/ringbuf.c +38 -38
@@ 5,69 5,69 @@

void rb_init(struct ringbuf *rb, int dsize, int init)
{
  rb->dsize = dsize;
  rb->nalloc = init;
  rb->start = 0;
  rb->count = 0;
  rb->data = calloc(dsize, init);
	rb->dsize = dsize;
	rb->nalloc = init;
	rb->start = 0;
	rb->count = 0;
	rb->data = calloc(dsize, init);
}

void rb_destroy(struct ringbuf *rb)
{
  free(rb->data);
	free(rb->data);
}

void rb_grow(struct ringbuf *rb)
{
  int oldalloc = rb->nalloc;
  rb->nalloc *= 2;
  rb->data = realloc(rb->data, rb->nalloc * rb->dsize);
	int oldalloc = rb->nalloc;
	rb->nalloc *= 2;
	rb->data = realloc(rb->data, rb->nalloc * rb->dsize);

  for (int i = 0; i < rb->count; i++) {
    int oldindex = (rb->start + i) % oldalloc;
    int newindex = (rb->start + i) % rb->nalloc;
    if (oldindex != newindex) {
      memcpy(rb->data + newindex * rb->dsize,
             rb->data + oldindex * rb->dsize, rb->nalloc);
    }
  }
	for (int i = 0; i < rb->count; i++) {
		int oldindex = (rb->start + i) % oldalloc;
		int newindex = (rb->start + i) % rb->nalloc;
		if (oldindex != newindex) {
			memcpy(rb->data + newindex * rb->dsize,
			       rb->data + oldindex * rb->dsize, rb->nalloc);
		}
	}
}

void rb_push_front(struct ringbuf *rb, void *src)
{
  if (rb->count >= rb->nalloc) {
    rb_grow(rb);
  }
	if (rb->count >= rb->nalloc) {
		rb_grow(rb);
	}

  // ensure the new start index is still positive
  int newstart = (rb->start + rb->nalloc - 1) % rb->nalloc;
  rb->start = newstart;
  memcpy(rb->data + rb->start * rb->dsize, src, rb->dsize);
  rb->count++;
	/* ensure the new start index is still positive */
	int newstart = (rb->start + rb->nalloc - 1) % rb->nalloc;
	rb->start = newstart;
	memcpy(rb->data + rb->start * rb->dsize, src, rb->dsize);
	rb->count++;
}

void rb_pop_front(struct ringbuf *rb, void *dst)
{
  int newstart = (rb->start + 1) % rb->nalloc;
  memcpy(dst, rb->data + rb->start * rb->dsize, rb->dsize);
  rb->start = newstart;
  rb->count--;
	int newstart = (rb->start + 1) % rb->nalloc;
	memcpy(dst, rb->data + rb->start * rb->dsize, rb->dsize);
	rb->start = newstart;
	rb->count--;
}

void rb_push_back(struct ringbuf *rb, void *src)
{
  if (rb->count >= rb->nalloc) {
    rb_grow(rb);
  }
	if (rb->count >= rb->nalloc) {
		rb_grow(rb);
	}

  int index = (rb->start + rb->count) % rb->nalloc;
  memcpy(rb->data + index * rb->dsize, src, rb->dsize);
  rb->count++;
	int index = (rb->start + rb->count) % rb->nalloc;
	memcpy(rb->data + index * rb->dsize, src, rb->dsize);
	rb->count++;
}

void rb_pop_back(struct ringbuf *rb, void *dst)
{
  int index = (rb->start + rb->count - 1) % rb->nalloc;
  memcpy(dst, rb->data + index * rb->dsize, rb->dsize);
  rb->count--;
	int index = (rb->start + rb->count - 1) % rb->nalloc;
	memcpy(dst, rb->data + index * rb->dsize, rb->dsize);
	rb->count--;
}

M src/ringbuf.h => src/ringbuf.h +34 -34
@@ 8,67 8,67 @@
#define _RINGBUF_H

/**
   A ring buffer data structure. This buffer can be inserted into and removed
   from at either end in constant time, except for memory allocations which may
   have to occur to expand the buffer. However these always double the buffer
   size, which means the number of allocations is logarithmic with respect to
   the number of insertions.
 * A ring buffer data structure. This buffer can be inserted into and removed
 * from at either end in constant time, except for memory allocations which may
 * have to occur to expand the buffer. However these always double the buffer
 * size, which means the number of allocations is logarithmic with respect to
 * the number of insertions.
 */
struct ringbuf {

  void *data;
  int dsize;
	void *data;
	int dsize;

  int nalloc;
  int start;
  int count;
	int nalloc;
	int start;
	int count;

};

/**
   @brief Initialize a ring buffer.
   @param rb Pointer to a ring buffer struct.
   @param dsize Size of data type to store in ring buffer.
   @param init Initial amount of space to allocate.
 * @brief Initialize a ring buffer.
 * @param rb Pointer to a ring buffer struct.
 * @param dsize Size of data type to store in ring buffer.
 * @param init Initial amount of space to allocate.
 */
void rb_init(struct ringbuf *rb, int dsize, int init);
/**
   @brief Free all resources held by the ring buffer.
   @param rb Pointer to the ring buffer struct.
 * @brief Free all resources held by the ring buffer.
 * @param rb Pointer to the ring buffer struct.
 */
void rb_destroy(struct ringbuf *rb);
/**
   @brief Add an item to the front of the ring buffer.  May trigger expansion.
   @param src Area of memory to read from.
 * @brief Add an item to the front of the ring buffer.	May trigger expansion.
 * @param src Area of memory to read from.
 */
void rb_push_front(struct ringbuf *rb, void *src);
/**
   @brief Remove an item from the front of the ring buffer.
   @param dst Area of memory to write resulting data to.

   Note that behavior is unbefined if you decide to pop from an empty buffer.
 * @brief Remove an item from the front of the ring buffer.
 * @param dst Area of memory to write resulting data to.
 *
 * Note that behavior is unbefined if you decide to pop from an empty buffer.
 */
void rb_pop_front(struct ringbuf *rb, void *dst);
/**
   @brief Add an item to the end of the ring buffer.  May trigger expansion.
   @param src Area of memory to read from.
 * @brief Add an item to the end of the ring buffer.	May trigger expansion.
 * @param src Area of memory to read from.
*/
void rb_push_back(struct ringbuf *rb, void *src);
/**
   @brief Remove an item from the end of the ring buffer.
   @param dst Area of memory to write resulting data to.

   Note that behavior is undefined if you decide to pop from an empty buffer.
 * @brief Remove an item from the end of the ring buffer.
 * @param dst Area of memory to write resulting data to.
 *
 * Note that behavior is undefined if you decide to pop from an empty buffer.
*/
void rb_pop_back(struct ringbuf *rb, void *dst);

/**
   @brief Expand a ring buffer (by doubling its size).
   @param rb Pointer to ring buffer.

   Note that this is mostly an internal function, and is exposed in the header
   for testing purposes. No guarantee is made that its interface will stay the
   same, or that it will continue to exist.
 * @brief Expand a ring buffer (by doubling its size).
 * @param rb Pointer to ring buffer.
 *
 * Note that this is mostly an internal function, and is exposed in the header
 * for testing purposes. No guarantee is made that its interface will stay the
 * same, or that it will continue to exist.
 */
void rb_grow(struct ringbuf *rb);


M src/types.c => src/types.c +286 -286
@@ 19,39 19,39 @@

static lisp_value *eval_error(lisp_runtime *rt, lisp_scope *s, lisp_value *v)
{
  (void)s;
  (void)v;
  return (lisp_value*) lisp_error_new(rt, "cannot evaluate this object");
	(void)s;
	(void)v;
	return (lisp_value*) lisp_error_new(rt, "cannot evaluate this object");
}

static lisp_value *eval_same(lisp_runtime *rt, lisp_scope *s, lisp_value *v)
{
  (void)rt;
  (void)s;
  return v;
	(void)rt;
	(void)s;
	return v;
}

static lisp_value *call_error(lisp_runtime *rt, lisp_scope *s, lisp_value *c,
                              lisp_value *v)
{
  (void)s;
  (void)c;
  (void)v;
  return (lisp_value*) lisp_error_new(rt, "not callable!");
	(void)s;
	(void)c;
	(void)v;
	return (lisp_value*) lisp_error_new(rt, "not callable!");
}

static lisp_value *call_same(lisp_runtime *rt, lisp_scope *s, lisp_value *c,
                             lisp_value *v)
{
  (void)rt;
  (void)s;
  (void)v;
  return c;
	(void)rt;
	(void)s;
	(void)v;
	return c;
}

static bool has_next_index_lt_state(struct iterator *iter)
{
  return iter->index < iter->state_int;
	return iter->index < iter->state_int;
}

/*


@@ 62,27 62,27 @@ static void type_print(FILE *f, lisp_value *v);
static lisp_value *type_new(void);

static lisp_type type_type_obj = {
  .type=&type_type_obj,
  .name="type",
  .print=type_print,
  .new=type_new,
  .eval=eval_error,
  .free=free,
  .call=call_error,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="type",
	.print=type_print,
	.new=type_new,
	.eval=eval_error,
	.free=free,
	.call=call_error,
	.expand=iterator_empty,
};
lisp_type *type_type = &type_type_obj;

static void type_print(FILE *f, lisp_value *v)
{
  lisp_type *value = (lisp_type*) v;
  fprintf(f, "%s", value->name);
	lisp_type *value = (lisp_type*) v;
	fprintf(f, "%s", value->name);
}

static lisp_value *type_new(void)
{
  lisp_type *type = malloc(sizeof(lisp_type));
  return (lisp_value*)type;
	lisp_type *type = malloc(sizeof(lisp_type));
	return (lisp_value*)type;
}

/*


@@ 95,76 95,76 @@ static void scope_free(void *v);
static struct iterator scope_expand(lisp_value *);

static lisp_type type_scope_obj = {
  .type=&type_type_obj,
  .name="scope",
  .print=scope_print,
  .new=scope_new,
  .eval=eval_error,
  .free=scope_free,
  .call=call_error,
  .expand=scope_expand,
	.type=&type_type_obj,
	.name="scope",
	.print=scope_print,
	.new=scope_new,
	.eval=eval_error,
	.free=scope_free,
	.call=call_error,
	.expand=scope_expand,
};
lisp_type *type_scope = &type_scope_obj;

static unsigned int symbol_hash(void *symbol)
{
  lisp_symbol **sym = symbol;
  return ht_string_hash(&(*sym)->sym);
	lisp_symbol **sym = symbol;
	return ht_string_hash(&(*sym)->sym);
}

static int symbol_compare(void *left, void *right)
{
  lisp_symbol **sym1 = left;
  lisp_symbol **sym2 = right;
  return strcmp((*sym1)->sym, (*sym2)->sym);
	lisp_symbol **sym1 = left;
	lisp_symbol **sym2 = right;
	return strcmp((*sym1)->sym, (*sym2)->sym);
}

static lisp_value *scope_new(void)
{
  lisp_scope *scope = malloc(sizeof(lisp_scope));
  scope->up = NULL;
  ht_init(&scope->scope, symbol_hash, symbol_compare, sizeof(void*), sizeof(void*));
  return (lisp_value*)scope;
	lisp_scope *scope = malloc(sizeof(lisp_scope));
	scope->up = NULL;
	ht_init(&scope->scope, symbol_hash, symbol_compare, sizeof(void*), sizeof(void*));
	return (lisp_value*)scope;
}

static void scope_free(void *v)
{
  lisp_scope *scope = (lisp_scope*) v;
  ht_destroy(&scope->scope);
  free(scope);
	lisp_scope *scope = (lisp_scope*) v;
	ht_destroy(&scope->scope);
	free(scope);
}

static void scope_print(FILE *f, lisp_value *v)
{
  lisp_scope *scope = (lisp_scope*) v;
  struct iterator it = ht_iter_keys_ptr(&scope->scope);
  fprintf(f, "(scope:");
  while (it.has_next(&it)) {
    lisp_value *key = it.next(&it);
    lisp_value *value = ht_get_ptr(&scope->scope, key);
    fprintf(f, " ");
    lisp_print(f, key);
    fprintf(f, ": ");
    lisp_print(f, value);
  }
  fprintf(f, ")");
	lisp_scope *scope = (lisp_scope*) v;
	struct iterator it = ht_iter_keys_ptr(&scope->scope);
	fprintf(f, "(scope:");
	while (it.has_next(&it)) {
		lisp_value *key = it.next(&it);
		lisp_value *value = ht_get_ptr(&scope->scope, key);
		fprintf(f, " ");
		lisp_print(f, key);
		fprintf(f, ": ");
		lisp_print(f, value);
	}
	fprintf(f, ")");
}

static struct iterator scope_expand(lisp_value *v)
{
  lisp_scope *scope = (lisp_scope *) v;
  if (scope->up) {
    return iterator_concat3(
      iterator_single_value(&scope->up),
      ht_iter_keys_ptr(&scope->scope),
      ht_iter_values_ptr(&scope->scope)
    );
  } else {
    return iterator_concat2(
      ht_iter_keys_ptr(&scope->scope),
      ht_iter_values_ptr(&scope->scope)
    );
  }
	lisp_scope *scope = (lisp_scope *) v;
	if (scope->up) {
		return iterator_concat3(
			iterator_single_value(&scope->up),
			ht_iter_keys_ptr(&scope->scope),
			ht_iter_values_ptr(&scope->scope)
		);
	} else {
		return iterator_concat2(
			ht_iter_keys_ptr(&scope->scope),
			ht_iter_values_ptr(&scope->scope)
		);
	}
}

/*


@@ 177,101 177,101 @@ static lisp_value *list_eval(lisp_runtime*, lisp_scope*, lisp_value*);
static struct iterator list_expand(lisp_value*);

static lisp_type type_list_obj = {
  .type=&type_type_obj,
  .name="list",
  .print=list_print,
  .new=list_new,
  .eval=list_eval,
  .free=free,
  .call=call_error,
  .expand=list_expand,
	.type=&type_type_obj,
	.name="list",
	.print=list_print,
	.new=list_new,
	.eval=list_eval,
	.free=free,
	.call=call_error,
	.expand=list_expand,
};
lisp_type *type_list = &type_list_obj;

static lisp_value *list_eval(lisp_runtime *rt, lisp_scope *scope, lisp_value *v)
{
  lisp_list *list = (lisp_list*) v;
  if (list->right->type != type_list) {
    return (lisp_value*) lisp_error_new(rt, "bad function call syntax");
  }
  lisp_value *callable = lisp_eval(rt, scope, list->left);
  lisp_value *rv = lisp_call(rt, scope, callable, list->right);
  return rv;
	lisp_list *list = (lisp_list*) v;
	if (list->right->type != type_list) {
		return (lisp_value*) lisp_error_new(rt, "bad function call syntax");
	}
	lisp_value *callable = lisp_eval(rt, scope, list->left);
	lisp_value *rv = lisp_call(rt, scope, callable, list->right);
	return rv;
}

static void list_print_internal(FILE *f, lisp_list *list)
{
  if (lisp_nil_p((lisp_value*)list)) {
    return;
  }
  lisp_print(f, list->left);
  if (list->right->type != type_list) {
    fprintf(f, " . ");
    lisp_print(f, list->right);
    return;
  } else if (!lisp_nil_p((lisp_value*)list)) {
    fprintf(f, " ");
    list_print_internal(f, (lisp_list*)list->right);
  }
	if (lisp_nil_p((lisp_value*)list)) {
		return;
	}
	lisp_print(f, list->left);
	if (list->right->type != type_list) {
		fprintf(f, " . ");
		lisp_print(f, list->right);
		return;
	} else if (!lisp_nil_p((lisp_value*)list)) {
		fprintf(f, " ");
		list_print_internal(f, (lisp_list*)list->right);
	}
}

static void list_print(FILE *f, lisp_value *v)
{
  fprintf(f, "(");
  list_print_internal(f, (lisp_list*)v);
  fprintf(f, ")");
	fprintf(f, "(");
	list_print_internal(f, (lisp_list*)v);
	fprintf(f, ")");
}

static lisp_value *list_new(void)
{
  lisp_list *list = malloc(sizeof(lisp_list));
  list->left = NULL;
  list->right = NULL;
  return (lisp_value*) list;
	lisp_list *list = malloc(sizeof(lisp_list));
	list->left = NULL;
	list->right = NULL;
	return (lisp_value*) list;
}

bool lisp_nil_p(lisp_value *l)
{
  return (l->type == type_list) &&
    (((lisp_list*)l)->right == NULL) &&
    (((lisp_list*)l)->left == NULL);
	return (l->type == type_list) &&
		(((lisp_list*)l)->right == NULL) &&
		(((lisp_list*)l)->left == NULL);
}

static void *list_expand_next(struct iterator *it)
{
  lisp_list *l = (lisp_list*) it->ds;
  it->index++;
  switch (it->index) {
  case 1:
    return l->left;
  case 2:
    return l->right;
  default:
    return NULL;
  }
	lisp_list *l = (lisp_list*) it->ds;
	it->index++;
	switch (it->index) {
	case 1:
		return l->left;
	case 2:
		return l->right;
	default:
		return NULL;
	}
}

static bool list_has_next(struct iterator *it)
{
  lisp_value *l = (lisp_value*)it->ds;
  if (lisp_nil_p(l)) {
    return false;
  } else {
    return it->index < it->state_int;
  }
	lisp_value *l = (lisp_value*)it->ds;
	if (lisp_nil_p(l)) {
		return false;
	} else {
		return it->index < it->state_int;
	}
}

static struct iterator list_expand(lisp_value *v)
{
  struct iterator it = {
    .ds=v,
    .state_int=2,
    .index=0,
    .next=list_expand_next,
    .has_next=list_has_next,
    .close=iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds=v,
		.state_int=2,
		.index=0,
		.next=list_expand_next,
		.has_next=list_has_next,
		.close=iterator_close_noop,
	};
	return it;
}

/*


@@ 285,43 285,43 @@ static void symbol_free(void *v);
static struct iterator symbol_expand(lisp_value*v);

static lisp_type type_symbol_obj = {
  .type=&type_type_obj,
  .name="symbol",
  .print=symbol_print,
  .new=symbol_new,
  .eval=symbol_eval,
  .free=symbol_free,
  .call=call_error,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="symbol",
	.print=symbol_print,
	.new=symbol_new,
	.eval=symbol_eval,
	.free=symbol_free,
	.call=call_error,
	.expand=iterator_empty,
};
lisp_type *type_symbol = &type_symbol_obj;

static void symbol_print(FILE *f, lisp_value *v)
{
  lisp_symbol *symbol = (lisp_symbol*) v;
  fprintf(f, "%s", symbol->sym);
	lisp_symbol *symbol = (lisp_symbol*) v;
	fprintf(f, "%s", symbol->sym);
}

static lisp_value *symbol_new(void)
{
  lisp_symbol *symbol = malloc(sizeof(lisp_symbol));
  symbol->sym = NULL;
  return (lisp_value*)symbol;
	lisp_symbol *symbol = malloc(sizeof(lisp_symbol));
	symbol->sym = NULL;
	return (lisp_value*)symbol;
}

static lisp_value *symbol_eval(lisp_runtime *rt, lisp_scope *scope,
                               lisp_value *value)
{
  (void)rt;
  lisp_symbol *symbol = (lisp_symbol*) value;
  return lisp_scope_lookup(rt, scope, symbol);
	(void)rt;
	lisp_symbol *symbol = (lisp_symbol*) value;
	return lisp_scope_lookup(rt, scope, symbol);
}

static void symbol_free(void *v)
{
  lisp_symbol *symbol = (lisp_symbol*) v;
  free(symbol->sym);
  free(symbol);
	lisp_symbol *symbol = (lisp_symbol*) v;
	free(symbol->sym);
	free(symbol);
}

/*


@@ 333,36 333,36 @@ static lisp_value *error_new(void);
static void error_free(void *v);

static lisp_type type_error_obj = {
  .type=&type_type_obj,
  .name="error",
  .print=error_print,
  .new=error_new,
  .eval=eval_same,
  .free=error_free,
  .call=call_same,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="error",
	.print=error_print,
	.new=error_new,
	.eval=eval_same,
	.free=error_free,
	.call=call_same,
	.expand=iterator_empty,
};
lisp_type *type_error = &type_error_obj;

static void error_print(FILE *f, lisp_value *v)
{
  lisp_error *error = (lisp_error*) v;
  fprintf(f, "error: %s", error->message);
	lisp_error *error = (lisp_error*) v;
	fprintf(f, "error: %s", error->message);
}

static lisp_value *error_new(void)
{
  lisp_error *error = malloc(sizeof(lisp_error));
  error->type = type_error;
  error->message = NULL;
  return (lisp_value*)error;
	lisp_error *error = malloc(sizeof(lisp_error));
	error->type = type_error;
	error->message = NULL;
	return (lisp_value*)error;
}

static void error_free(void *v)
{
  lisp_error *error = (lisp_error*) v;
  free(error->message);
  free(error);
	lisp_error *error = (lisp_error*) v;
	free(error->message);
	free(error);
}

/*


@@ 373,28 373,28 @@ static void integer_print(FILE *f, lisp_value *v);
static lisp_value *integer_new(void);

static lisp_type type_integer_obj = {
  .type=&type_type_obj,
  .name="integer",
  .print=integer_print,
  .new=integer_new,
  .eval=eval_same,
  .free=free,
  .call=call_error,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="integer",
	.print=integer_print,
	.new=integer_new,
	.eval=eval_same,
	.free=free,
	.call=call_error,
	.expand=iterator_empty,
};
lisp_type *type_integer = &type_integer_obj;

static void integer_print(FILE *f, lisp_value *v)
{
  lisp_integer *integer = (lisp_integer*) v;
  fprintf(f, "%d", integer->x);
	lisp_integer *integer = (lisp_integer*) v;
	fprintf(f, "%d", integer->x);
}

static lisp_value *integer_new(void)
{
  lisp_integer *integer = malloc(sizeof(lisp_integer));
  integer->x = 0;
  return (lisp_value*)integer;
	lisp_integer *integer = malloc(sizeof(lisp_integer));
	integer->x = 0;
	return (lisp_value*)integer;
}

// string


@@ 404,35 404,35 @@ static lisp_value *string_new(void);
static void string_free(void *v);

static lisp_type type_string_obj = {
  .type=&type_type_obj,
  .name="string",
  .print=string_print,
  .new=string_new,
  .eval=eval_same,
  .free=string_free,
  .call=call_error,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="string",
	.print=string_print,
	.new=string_new,
	.eval=eval_same,
	.free=string_free,
	.call=call_error,
	.expand=iterator_empty,
};
lisp_type *type_string = &type_string_obj;

static void string_print(FILE *f, lisp_value *v)
{
  lisp_string *str = (lisp_string*) v;
  fprintf(f, "%s", str->s);
	lisp_string *str = (lisp_string*) v;
	fprintf(f, "%s", str->s);
}

static lisp_value *string_new(void)
{
  lisp_string *str = malloc(sizeof(lisp_string));
  str->s = NULL;
  return (lisp_value*)str;
	lisp_string *str = malloc(sizeof(lisp_string));
	str->s = NULL;
	return (lisp_value*)str;
}

static void string_free(void *v)
{
  lisp_string *str = (lisp_string*) v;
  free(str->s);
  free(str);
	lisp_string *str = (lisp_string*) v;
	free(str->s);
	free(str);
}

/*


@@ 445,36 445,36 @@ static lisp_value *builtin_call(lisp_runtime *rt, lisp_scope *scope,
                                lisp_value *c, lisp_value *arguments);

static lisp_type type_builtin_obj = {
  .type=&type_type_obj,
  .name="builtin",
  .print=builtin_print,
  .new=builtin_new,
  .eval=eval_error,
  .free=free,
  .call=builtin_call,
  .expand=iterator_empty,
	.type=&type_type_obj,
	.name="builtin",
	.print=builtin_print,
	.new=builtin_new,
	.eval=eval_error,
	.free=free,
	.call=builtin_call,
	.expand=iterator_empty,
};
lisp_type *type_builtin = &type_builtin_obj;

static void builtin_print(FILE *f, lisp_value *v)
{
  lisp_builtin *builtin = (lisp_builtin*) v;
  fprintf(f, "<builtin function %s>", builtin->name);
	lisp_builtin *builtin = (lisp_builtin*) v;
	fprintf(f, "<builtin function %s>", builtin->name);
}

static lisp_value *builtin_new()
{
  lisp_builtin *builtin = malloc(sizeof(lisp_builtin));
  builtin->call = NULL;
  builtin->name = NULL;
  return (lisp_value*) builtin;
	lisp_builtin *builtin = malloc(sizeof(lisp_builtin));
	builtin->call = NULL;
	builtin->name = NULL;
	return (lisp_value*) builtin;
}

static lisp_value *builtin_call(lisp_runtime *rt, lisp_scope *scope,
                                lisp_value *c, lisp_value *arguments)
{
  lisp_builtin *builtin = (lisp_builtin*) c;
  return builtin->call(rt, scope, arguments);
	lisp_builtin *builtin = (lisp_builtin*) c;
	return builtin->call(rt, scope, arguments);
}

/*


@@ 488,83 488,83 @@ static lisp_value *lambda_call(lisp_runtime *rt, lisp_scope *scope,
static struct iterator lambda_expand(lisp_value *v);

static lisp_type type_lambda_obj = {
  .type=&type_type_obj,
  .name="lambda",
  .print=lambda_print,
  .new=lambda_new,
  .eval=eval_error,
  .free=free,
  .call=lambda_call,
  .expand=lambda_expand,
	.type=&type_type_obj,
	.name="lambda",
	.print=lambda_print,
	.new=lambda_new,
	.eval=eval_error,
	.free=free,
	.call=lambda_call,
	.expand=lambda_expand,
};
lisp_type *type_lambda = &type_lambda_obj;

static void lambda_print(FILE *f, lisp_value *v)
{
  (void)v;
  fprintf(f, "<lambda function>");
	(void)v;
	fprintf(f, "<lambda function>");
}

static lisp_value *lambda_new()
{
  lisp_lambda *lambda = malloc(sizeof(lisp_lambda));
  lambda->args = NULL;
  lambda->code = NULL;
  return (lisp_value*) lambda;
	lisp_lambda *lambda = malloc(sizeof(lisp_lambda));
	lambda->args = NULL;
	lambda->code = NULL;
	return (lisp_value*) lambda;
}

static lisp_value *lambda_call(lisp_runtime *rt, lisp_scope *scope,
                               lisp_value *c, lisp_value *arguments)
{
  lisp_lambda *lambda = (lisp_lambda*) c;
  lisp_list *argvalues = (lisp_list*)lisp_eval_list(rt, scope, arguments);
  lisp_scope *inner = (lisp_scope*)lisp_new(rt, type_scope);
  inner->up = lambda->closure;
	lisp_lambda *lambda = (lisp_lambda*) c;
	lisp_list *argvalues = (lisp_list*)lisp_eval_list(rt, scope, arguments);
	lisp_scope *inner = (lisp_scope*)lisp_new(rt, type_scope);
	inner->up = lambda->closure;

  lisp_list *it1 = lambda->args, *it2 = argvalues;
  while (!lisp_nil_p((lisp_value*)it1) && !lisp_nil_p((lisp_value*)it2)) {
    lisp_scope_bind(inner, (lisp_symbol*) it1->left, it2->left);
    it1 = (lisp_list*) it1->right;
    it2 = (lisp_list*) it2->right;
  }
	lisp_list *it1 = lambda->args, *it2 = argvalues;
	while (!lisp_nil_p((lisp_value*)it1) && !lisp_nil_p((lisp_value*)it2)) {
		lisp_scope_bind(inner, (lisp_symbol*) it1->left, it2->left);
		it1 = (lisp_list*) it1->right;
		it2 = (lisp_list*) it2->right;
	}

  if (!lisp_nil_p((lisp_value*)it1)) {
    return (lisp_value*) lisp_error_new(rt, "not enough arguments");
  }
  if (!lisp_nil_p((lisp_value*)it2)) {
    return (lisp_value*) lisp_error_new(rt, "too many arguments");
  }
	if (!lisp_nil_p((lisp_value*)it1)) {
		return (lisp_value*) lisp_error_new(rt, "not enough arguments");
	}
	if (!lisp_nil_p((lisp_value*)it2)) {
		return (lisp_value*) lisp_error_new(rt, "too many arguments");
	}

  return lisp_eval(rt, inner, lambda->code);
	return lisp_eval(rt, inner, lambda->code);
}

static void *lambda_expand_next(struct iterator *it)
{
  lisp_lambda *l = (lisp_lambda*)it->ds;
  it->index++;
  switch (it->index) {
  case 1:
    return l->args;
  case 2:
    return l->code;
  case 3:
    return l->closure;
  default:
    return NULL;
  }
	lisp_lambda *l = (lisp_lambda*)it->ds;
	it->index++;
	switch (it->index) {
	case 1:
		return l->args;
	case 2:
		return l->code;
	case 3:
		return l->closure;
	default:
		return NULL;
	}
}

static struct iterator lambda_expand(lisp_value *v)
{
  struct iterator it = {
    .ds=v,
    .state_int=3,
    .index=0,
    .next=lambda_expand_next,
    .has_next=has_next_index_lt_state,
    .close=iterator_close_noop,
  };
  return it;
	struct iterator it = {
		.ds=v,
		.state_int=3,
		.index=0,
		.next=lambda_expand_next,
		.has_next=has_next_index_lt_state,
		.close=iterator_close_noop,
	};
	return it;
}

/*


@@ 573,41 573,41 @@ static struct iterator lambda_expand(lisp_value *v)

void lisp_print(FILE *f, lisp_value *value)
{
  value->type->print(f, value);
	value->type->print(f, value);
}

void lisp_free(lisp_value *value)
{
  value->type->free(value);
	value->type->free(value);
}

lisp_value *lisp_eval(lisp_runtime *rt, lisp_scope *scope, lisp_value *value)
{
  return value->type->eval(rt, scope, value);
	return value->type->eval(rt, scope, value);
}

lisp_value *lisp_call(lisp_runtime *rt, lisp_scope *scope,
                      lisp_value *callable, lisp_value *args)
{
  if (callable->type == type_error) {
    return callable;
  }
	if (callable->type == type_error) {
		return callable;
	}

  return callable->type->call(rt, scope, callable, args);
	return callable->type->call(rt, scope, callable, args);
}

lisp_value *lisp_new(lisp_runtime *rt, lisp_type *typ)
{
  lisp_value *new = typ->new();
  new->type = typ;
  new->next = NULL;
  new->mark = GC_NOMARK;
  if (rt->head == NULL) {
    rt->head = new;
    rt->tail = new;
  } else {
    rt->tail->next = new;
    rt->tail = new;
  }
  return new;
	lisp_value *new = typ->new();
	new->type = typ;
	new->next = NULL;
	new->mark = GC_NOMARK;
	if (rt->head == NULL) {
		rt->head = new;
		rt->tail = new;
	} else {
		rt->tail->next = new;
		rt->tail = new;
	}
	return new;
}

M src/util.c => src/util.c +423 -423
@@ 14,615 14,615 @@

static lisp_list *lisp_new_pair_list(lisp_runtime *rt, lisp_value *one, lisp_value *two)
{
  lisp_list *first_node = (lisp_list*) lisp_new(rt, type_list);
  lisp_list *second_node = (lisp_list*) lisp_new(rt, type_list);
  first_node->left = one;
  first_node->right = (lisp_value*) second_node;
  second_node->left = two;
  second_node->right = lisp_nil_new(rt);
  return first_node;
	lisp_list *first_node = (lisp_list*) lisp_new(rt, type_list);
	lisp_list *second_node = (lisp_list*) lisp_new(rt, type_list);
	first_node->left = one;
	first_node->right = (lisp_value*) second_node;
	second_node->left = two;
	second_node->right = lisp_nil_new(rt);
	return first_node;
}

void lisp_scope_bind(lisp_scope *scope, lisp_symbol *symbol, lisp_value *value)
{
  ht_insert_ptr(&scope->scope, symbol, value);
	ht_insert_ptr(&scope->scope, symbol, value);
}

lisp_value *lisp_scope_lookup(lisp_runtime *rt, lisp_scope *scope,
                              lisp_symbol *symbol)
{
  lisp_value *v = ht_get_ptr(&scope->scope, symbol);
  if (!v) {
    if (scope->up) {
      return lisp_scope_lookup(rt, scope->up, symbol);
    } else {
      return (lisp_value*)lisp_error_new(rt, "symbol not found in scope");
    }
  } else {
    return v;
  }
	lisp_value *v = ht_get_ptr(&scope->scope, symbol);
	if (!v) {
		if (scope->up) {
			return lisp_scope_lookup(rt, scope->up, symbol);
		} else {
			return (lisp_value*)lisp_error_new(rt, "symbol not found in scope");
		}
	} else {
		return v;
	}
}

void lisp_scope_add_builtin(lisp_runtime *rt, lisp_scope *scope, char *name,
                            lisp_builtin_func call)
{
  lisp_symbol *symbol = lisp_symbol_new(rt, name);
  lisp_builtin *builtin = lisp_builtin_new(rt, name, call);
  lisp_scope_bind(scope, symbol, (lisp_value*)builtin);
	lisp_symbol *symbol = lisp_symbol_new(rt, name);
	lisp_builtin *builtin = lisp_builtin_new(rt, name, call);
	lisp_scope_bind(scope, symbol, (lisp_value*)builtin);
}

void lisp_scope_replace_or_insert(lisp_scope *scope, lisp_symbol *key, lisp_value *value)
{
  lisp_scope *s = scope;
	lisp_scope *s = scope;

  // First go up the chain checking for the name.
  while (s) {
    if (ht_contains_ptr(&s->scope, key)) {
      // If we find it, replace it.
      ht_insert_ptr(&s->scope, key, value);
      return;
    }
    s = s->up;
  }
	// First go up the chain checking for the name.
	while (s) {
		if (ht_contains_ptr(&s->scope, key)) {
			// If we find it, replace it.
			ht_insert_ptr(&s->scope, key, value);
			return;
		}
		s = s->up;
	}

  // If we never find it, insert it in the "lowest" scope.
  ht_insert_ptr(&scope->scope, key, value);
	// If we never find it, insert it in the "lowest" scope.
	ht_insert_ptr(&scope->scope, key, value);
}

lisp_symbol *lisp_symbol_new(lisp_runtime *rt, char *sym)
{
  lisp_symbol *err = (lisp_symbol*)lisp_new(rt, type_symbol);
  int len = strlen(sym);
  err->sym = malloc(len + 1);
  strncpy(err->sym, sym, len);
  err->sym[len] = '\0';
  return err;
	lisp_symbol *err = (lisp_symbol*)lisp_new(rt, type_symbol);
	int len = strlen(sym);
	err->sym = malloc(len + 1);
	strncpy(err->sym, sym, len);
	err->sym[len] = '\0';
	return err;
}

lisp_error *lisp_error_new(lisp_runtime *rt, char *message)
{
  lisp_error *err = (lisp_error*)lisp_new(rt, type_error);
  int len = strlen(message);
  err->message = malloc(len + 1);
  strncpy(err->message, message, len);
  err->message[len] = '\0';
  return err;
	lisp_error *err = (lisp_error*)lisp_new(rt, type_error);
	int len = strlen(message);
	err->message = malloc(len + 1);
	strncpy(err->message, message, len);
	err->message[len] = '\0';
	return err;
}

lisp_builtin *lisp_builtin_new(lisp_runtime *rt, char *name,
                               lisp_builtin_func call)
{
  lisp_builtin *builtin = (lisp_builtin*)lisp_new(rt, type_builtin);
  builtin->call = call;
  builtin->name = name;
  return builtin;
	lisp_builtin *builtin = (lisp_builtin*)lisp_new(rt, type_builtin);
	builtin->call = call;
	builtin->name = name;
	return builtin;
}

lisp_value *lisp_nil_new(lisp_runtime *rt)
{
  if (rt->nil == NULL) {
    rt->nil = lisp_new(rt, type_list);
  }
  return rt->nil;
	if (rt->nil == NULL) {
		rt->nil = lisp_new(rt, type_list);
	}
	return rt->nil;
}

lisp_value *lisp_eval_list(lisp_runtime *rt, lisp_scope *scope, lisp_value *l)
{
  if (lisp_nil_p(l)) {
    return l;
  }
  lisp_list *list = (lisp_list*) l;
  lisp_list *result = (lisp_list*)lisp_new(rt, type_list);
  result->left = lisp_eval(rt, scope, list->left);
  result->right = lisp_eval_list(rt, scope, list->right);
  return (lisp_value*) result;
	if (lisp_nil_p(l)) {
		return l;
	}
	lisp_list *list = (lisp_list*) l;
	lisp_list *result = (lisp_list*)lisp_new(rt, type_list);
	result->left = lisp_eval(rt, scope, list->left);
	result->right = lisp_eval_list(rt, scope, list->right);
	return (lisp_value*) result;
}

int lisp_list_length(lisp_list *list)
{
  int length = 0;
  while (list->type == type_list && !lisp_nil_p((lisp_value*)list)) {
    length++;
    list = (lisp_list*)list->right;
  }
  return length;
	int length = 0;
	while (list->type == type_list && !lisp_nil_p((lisp_value*)list)) {
		length++;
		list = (lisp_list*)list->right;
	}
	return length;
}

lisp_value *lisp_quote(lisp_runtime *rt, lisp_value *value) {
  lisp_list *l = (lisp_list*)lisp_new(rt, type_list);
  lisp_symbol *q = lisp_symbol_new(rt, "quote");
  l->left = (lisp_value*)q;
  lisp_list *s = (lisp_list*) lisp_new(rt, type_list);
  s->right = lisp_nil_new(rt);
  l->right = (lisp_value*)s;
  s->left = value;
  return (lisp_value*)l;
	lisp_list *l = (lisp_list*)lisp_new(rt, type_list);
	lisp_symbol *q = lisp_symbol_new(rt, "quote");
	l->left = (lisp_value*)q;
	lisp_list *s = (lisp_list*) lisp_new(rt, type_list);
	s->right = lisp_nil_new(rt);
	l->right = (lisp_value*)s;
	s->left = value;
	return (lisp_value*)l;
}

static lisp_type *lisp_get_type(char c)
{
  switch (c) {
  case 'd':
    return type_integer;
  case 'l':
    return type_list;
  case 's':
    return type_symbol;
  case 'S':
    return type_string;
  case 'o':
    return type_scope;
  case 'e':
    return type_error;
  case 'b':
    return type_builtin;
  case 't':
    return type_type;
  }
  return NULL;
	switch (c) {
	case 'd':
		return type_integer;
	case 'l':
		return type_list;
	case 's':
		return type_symbol;
	case 'S':
		return type_string;
	case 'o':
		return type_scope;
	case 'e':
		return type_error;
	case 'b':
		return type_builtin;
	case 't':
		return type_type;
	}
	return NULL;
}

bool lisp_get_args(lisp_list *list, char *format, ...)
{
  va_list va;
  va_start(va, format);
  lisp_value **v;
  while (!lisp_nil_p((lisp_value*)list) && *format != '\0') {
    lisp_type *type = lisp_get_type(*format);
    if (type != NULL && type != list->left->type) {
      return false;
    }
    v = va_arg(va, lisp_value**);
    *v = list->left;
    list = (lisp_list*)list->right;
    format += 1;
  }
  if (strlen(format) != 0 || !lisp_nil_p((lisp_value*)list)) {
    return false;
  }
  return true;
	va_list va;
	va_start(va, format);
	lisp_value **v;
	while (!lisp_nil_p((lisp_value*)list) && *format != '\0') {
		lisp_type *type = lisp_get_type(*format);
		if (type != NULL && type != list->left->type) {
			return false;
		}
		v = va_arg(va, lisp_value**);
		*v = list->left;
		list = (lisp_list*)list->right;
		format += 1;
	}
	if (strlen(format) != 0 || !lisp_nil_p((lisp_value*)list)) {
		return false;
	}
	return true;
}

static lisp_value *lisp_builtin_eval(lisp_runtime *rt, lisp_scope *scope,
                                     lisp_value *arguments)
{
  lisp_list *evald = (lisp_list*)lisp_eval_list(rt, scope, arguments);
  lisp_value *result = lisp_eval(rt, scope, evald->left);
  return result;
	lisp_list *evald = (lisp_list*)lisp_eval_list(rt, scope, arguments);
	lisp_value *result = lisp_eval(rt, scope, evald->left);
	return result;
}

static lisp_value *lisp_builtin_car(lisp_runtime *rt, lisp_scope *scope,
                                    lisp_value *a)
{
  lisp_list *firstarg;
  lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
  if (!lisp_get_args(arglist, "l", &firstarg)) {
    return (lisp_value*)lisp_error_new(rt, "wrong arguments to car");
  }
  if (lisp_list_length(firstarg) == 0) {
    return (lisp_value*)lisp_error_new(rt, "expected at least one item");
  }
  return firstarg->left;
	lisp_list *firstarg;
	lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
	if (!lisp_get_args(arglist, "l", &firstarg)) {
		return (lisp_value*)lisp_error_new(rt, "wrong arguments to car");
	}
	if (lisp_list_length(firstarg) == 0) {
		return (lisp_value*)lisp_error_new(rt, "expected at least one item");
	}
	return firstarg->left;
}

static lisp_value *lisp_builtin_cdr(lisp_runtime *rt, lisp_scope *scope,
                                    lisp_value *a)
{
  lisp_list *firstarg;
  lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
  if (!lisp_get_args(arglist, "l", &firstarg)) {
    return (lisp_value*) lisp_error_new(rt, "wrong arguments to cdr");
  }
  // save rv because firstarg may be deleted after decref
  return firstarg->right;
	lisp_list *firstarg;
	lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
	if (!lisp_get_args(arglist, "l", &firstarg)) {
		return (lisp_value*) lisp_error_new(rt, "wrong arguments to cdr");
	}
	// save rv because firstarg may be deleted after decref
	return firstarg->right;
}

static lisp_value *lisp_builtin_quote(lisp_runtime *rt, lisp_scope *scope,
                                      lisp_value *a)
{
  (void)scope;
  lisp_value *firstarg;
  lisp_list *arglist = (lisp_list*) a;
  if (!lisp_get_args(arglist, "*", &firstarg)) {
    return (lisp_value*) lisp_error_new(rt, "wrong arguments to quote");
  }
  return arglist->left;
	(void)scope;
	lisp_value *firstarg;
	lisp_list *arglist = (lisp_list*) a;
	if (!lisp_get_args(arglist, "*", &firstarg)) {
		return (lisp_value*) lisp_error_new(rt, "wrong arguments to quote");
	}
	return arglist->left;
}

static lisp_value *lisp_builtin_cons(lisp_runtime *rt, lisp_scope *scope,
                                     lisp_value *a)
{
  lisp_value *a1;
  lisp_value *l;
  lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
  if (!lisp_get_args(arglist, "**", &a1, &l)) {
    return (lisp_value*) lisp_error_new(rt, "wrong arguments to cons");
  }
  lisp_list *new = (lisp_list*)lisp_new(rt, type_list);
  new->left = a1;
  new->right = (lisp_value*)l;
  return (lisp_value*)new;
	lisp_value *a1;
	lisp_value *l;
	lisp_list *arglist = (lisp_list*) lisp_eval_list(rt, scope, a);
	if (!lisp_get_args(arglist, "**", &a1, &l)) {
		return (lisp_value*) lisp_error_new(rt, "wrong arguments to cons");
	}
	lisp_list *new = (lisp_list*)lisp_new(rt, type_list);
	new->left = a1;
	new->right = (lisp_value*)l;
	return (lisp_value*)new;
}

static lisp_value *lisp_builtin_lambda(lisp_runtime *rt, lisp_scope *scope,
                                       lisp_value *a)
{
  lisp_list *argnames;
  lisp_value *code;
  lisp_list *our_args = (lisp_list*)a;
  (void)scope;
	lisp_list *argnames;
	lisp_value *code;
	lisp_list *our_args = (lisp_list*)a;
	(void)scope;

  if (!lisp_get_args(our_args, "l*", &argnames, &code)) {
    return (lisp_value*) lisp_error_new(rt, "expected argument list and code");
  }
	if (!lisp_get_args(our_args, "l*", &argnames, &code)) {
		return (lisp_value*) lisp_error_new(rt, "expected argument list and code");
	}

  lisp_list *it = argnames;
  while (!lisp_nil_p((lisp_value*)it)) {
    if (it->left->type != type_symbol) {
      return (lisp_value*) lisp_error_new(rt, "argument names must be symbols");
    }
    it = (lisp_list*) it->right;
  }
	lisp_list *it = argnames;
	while (!lisp_nil_p((lisp_value*)it)) {
		if (it->left->type != type_symbol) {
			return (lisp_value*) lisp_error_new(rt, "argument names must be symbols");
		}
		it = (lisp_list*) it->right;
	}

  lisp_lambda *lambda = (lisp_lambda*)lisp_new(rt, type_lambda);
  lambda->args = argnames;
  lambda->code = code;
  lambda->closure = scope;
  return (lisp_value*) lambda;
	lisp_lambda *lambda = (lisp_lambda*)lisp_new(rt, type_lambda);
	lambda->args = argnames;
	lambda->code = code;
	lambda->closure = scope;
	return (lisp_value*) lambda;
}

static lisp_value *lisp_builtin_define(lisp_runtime *rt, lisp_scope *scope,
                                       lisp_value *a)
{
  lisp_symbol *s;
  lisp_value *expr;
	lisp_symbol *s;
	lisp_value *expr;

  if (!lisp_get_args((lisp_list*)a, "s*", &s, &expr)) {
    return (lisp_value*) lisp_error_new(rt, "expected name and expression");
  }
	if (!lisp_get_args((lisp_list*)a, "s*", &s, &expr)) {
		return (lisp_value*) lisp_error_new(rt, "expected name and expression");
	}

  lisp_value *evald = lisp_eval(rt, scope, expr);
  lisp_scope_replace_or_insert(scope, s, evald);
  //lisp_scope_bind(scope, s, evald);
  return evald;
	lisp_value *evald = lisp_eval(rt, scope, expr);
	lisp_scope_replace_or_insert(scope, s, evald);
	//lisp_scope_bind(scope, s, evald);
	return evald;
}

static lisp_value *lisp_builtin_plus(lisp_runtime *rt, lisp_scope *scope,
                                     lisp_value *a)
{
  lisp_integer *i;
  lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
  int sum = 0;
	lisp_integer *i;
	lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
	int sum = 0;

  while (!lisp_nil_p((lisp_value*)args)) {
    if (args->left->type != type_integer) {
      return (lisp_value*) lisp_error_new(rt, "expect integers for addition");
    }
    i = (lisp_integer*) args->left;
    sum += i->x;
    args = (lisp_list*)args->right;
  }
	while (!lisp_nil_p((lisp_value*)args)) {
		if (args->left->type != type_integer) {
			return (lisp_value*) lisp_error_new(rt, "expect integers for addition");
		}
		i = (lisp_integer*) args->left;
		sum += i->x;
		args = (lisp_list*)args->right;
	}

  i = (lisp_integer*)lisp_new(rt, type_integer);
  i->x = sum;
  return (lisp_value*)i;
	i = (lisp_integer*)lisp_new(rt, type_integer);
	i->x = sum;
	return (lisp_value*)i;
}

static lisp_value *lisp_builtin_minus(lisp_runtime *rt, lisp_scope *scope,
                                      lisp_value *a)
{
  lisp_integer *i;
  lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
  int val = 0;
  int len = lisp_list_length(args);

  if (len < 1) {
    return (lisp_value*) lisp_error_new(rt, "expected at least one arg");
  } else if (len == 1) {
    i = (lisp_integer*) args->left;
    val = - i->x;
  } else {
    i = (lisp_integer*) args->left;
    val = i->x;
    args = (lisp_list*)args->right;
    while (!lisp_nil_p((lisp_value*)args)) {
      if (args->left->type != type_integer) {
        return (lisp_value*)lisp_error_new(rt, "expected integer");
      }
      i = (lisp_integer*) args->left;
      val -= i->x;
      args = (lisp_list*) args->right;
    }
  }

  i = (lisp_integer*)lisp_new(rt, type_integer);
  i->x = val;
  return (lisp_value*)i;
	lisp_integer *i;
	lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
	int val = 0;
	int len = lisp_list_length(args);

	if (len < 1) {
		return (lisp_value*) lisp_error_new(rt, "expected at least one arg");
	} else if (len == 1) {
		i = (lisp_integer*) args->left;
		val = - i->x;
	} else {
		i = (lisp_integer*) args->left;
		val = i->x;
		args = (lisp_list*)args->right;
		while (!lisp_nil_p((lisp_value*)args)) {
			if (args->left->type != type_integer) {
				return (lisp_value*)lisp_error_new(rt, "expected integer");
			}
			i = (lisp_integer*) args->left;
			val -= i->x;
			args = (lisp_list*) args->right;
		}
	}

	i = (lisp_integer*)lisp_new(rt, type_integer);
	i->x = val;
	return (lisp_value*)i;
}

static lisp_value *lisp_builtin_multiply(lisp_runtime *rt, lisp_scope *scope,
                                         lisp_value *a)
{
  lisp_integer *i;
  lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
  int product = 1;
	lisp_integer *i;
	lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
	int product = 1;

  while (!lisp_nil_p((lisp_value*)args)) {
    if (args->left->type != type_integer) {
      return (lisp_value*) lisp_error_new(rt, "expect integers for multiplication");
    }
    i = (lisp_integer*) args->left;
    product *= i->x;
    args = (lisp_list*)args->right;
  }
	while (!lisp_nil_p((lisp_value*)args)) {
		if (args->left->type != type_integer) {
			return (lisp_value*) lisp_error_new(rt, "expect integers for multiplication");
		}
		i = (lisp_integer*) args->left;
		product *= i->x;
		args = (lisp_list*)args->right;
	}

  i = (lisp_integer*)lisp_new(rt, type_integer);
  i->x = product;
  return (lisp_value*)i;
	i = (lisp_integer*)lisp_new(rt, type_integer);
	i->x = product;
	return (lisp_value*)i;
}

static lisp_value *lisp_builtin_divide(lisp_runtime *rt, lisp_scope *scope,
                                       lisp_value *a)
{
  lisp_integer *i;
  lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
  int val = 0;
  int len = lisp_list_length(args);

  if (len < 1) {
    return (lisp_value*) lisp_error_new(rt, "expected at least one arg");
  }
  i = (lisp_integer*) args->left;
  val = i->x;
  args = (lisp_list*)args->right;
  while (!lisp_nil_p((lisp_value*)args)) {
    if (args->left->type != type_integer) {
      return (lisp_value*)lisp_error_new(rt, "expected integer");
    }
    i = (lisp_integer*) args->left;
    if (i->x == 0) {
      return (lisp_value*) lisp_error_new(rt, "divide by zero");
    }
    val /= i->x;
    args = (lisp_list*) args->right;
  }

  i = (lisp_integer*)lisp_new(rt, type_integer);
  i->x = val;
  return (lisp_value*)i;
	lisp_integer *i;
	lisp_list *args = (lisp_list*)lisp_eval_list(rt, scope, a);
	int val = 0;
	int len = lisp_list_length(args);

	if (len < 1) {
		return (lisp_value*) lisp_error_new(rt, "expected at least one arg");
	}
	i = (lisp_integer*) args->left;
	val = i->x;
	args = (lisp_list*)args->right;
	while (!lisp_nil_p((lisp_value*)args)) {
		if (args->left->type != type_integer) {
			return (lisp_value*)lisp_error_new(rt, "expected integer");
		}
		i = (lisp_integer*) args->left;
		if (i->x == 0) {
			return (lisp_value*) lisp_error_new(rt, "divide by zero");
		}
		val /= i->x;
		args = (lisp_list*) args->right;
	}

	i = (lisp_integer*)lisp_new(rt, type_integer);
	i->x = val;
	return (lisp_value*)i;
}

static lisp_value *lisp_builtin_cmp_util(lisp_runtime *rt, lisp_scope *scope,
                                         lisp_value *a)
{
  lisp_integer *first, *second;
  lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
	lisp_integer *first, *second;
	lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);

  if (!lisp_get_args((lisp_list*)args, "dd", &first, &second)) {
    return (lisp_value*) lisp_error_new(rt, "expected two integers");
  }
	if (!lisp_get_args((lisp_list*)args, "dd", &first, &second)) {
		return (lisp_value*) lisp_error_new(rt, "expected two integers");
	}

  lisp_integer *result = (lisp_integer*)lisp_new(rt, type_integer);
  result->x = first->x - second->x;
  return (lisp_value*)result;
	lisp_integer *result = (lisp_integer*)lisp_new(rt, type_integer);
	result->x = first->x - second->x;
	return (lisp_value*)result;
}

static lisp_value *lisp_builtin_eq(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
  if (v->type == type_integer) {
    v->x = (v->x == 0);
  }
  return (lisp_value*)v;
	lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
	if (v->type == type_integer) {
		v->x = (v->x == 0);
	}
	return (lisp_value*)v;
}

static lisp_value *lisp_builtin_gt(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
  if (v->type == type_integer) {
    v->x = (v->x > 0);
  }
  return (lisp_value*)v;
	lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
	if (v->type == type_integer) {
		v->x = (v->x > 0);
	}
	return (lisp_value*)v;
}

static lisp_value *lisp_builtin_ge(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
  if (v->type == type_integer) {
    v->x = (v->x >= 0);
  }
  return (lisp_value*)v;
	lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
	if (v->type == type_integer) {
		v->x = (v->x >= 0);
	}
	return (lisp_value*)v;
}

static lisp_value *lisp_builtin_lt(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
  if (v->type == type_integer) {
    v->x = (v->x < 0);
  }
  return (lisp_value*)v;
	lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
	if (v->type == type_integer) {
		v->x = (v->x < 0);
	}
	return (lisp_value*)v;
}

static lisp_value *lisp_builtin_le(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
  if (v->type == type_integer) {
    v->x = (v->x <= 0);
  }
  return (lisp_value*)v;
	lisp_integer *v = (lisp_integer*)lisp_builtin_cmp_util(rt, scope, a);
	if (v->type == type_integer) {
		v->x = (v->x <= 0);
	}
	return (lisp_value*)v;
}

static lisp_value *lisp_builtin_if(lisp_runtime *rt, lisp_scope *scope,
                                   lisp_value *a)
{
  lisp_value *condition, *body_true, *body_false;
	lisp_value *condition, *body_true, *body_false;

  if (!lisp_get_args((lisp_list*)a, "***", &condition, &body_true, &body_false)) {
    return (lisp_value*) lisp_error_new(rt, "expected condition and two bodies");
  }
	if (!lisp_get_args((lisp_list*)a, "***", &condition, &body_true, &body_false)) {
		return (lisp_value*) lisp_error_new(rt, "expected condition and two bodies");
	}

  condition = lisp_eval(rt, scope, condition);
  if (condition->type == type_integer && ((lisp_integer*)condition)->x) {
    return lisp_eval(rt, scope, body_true);
  } else {
    return lisp_eval(rt, scope, body_false);
  }
	condition = lisp_eval(rt, scope, condition);
	if (condition->type == type_integer && ((lisp_integer*)condition)->x) {
		return lisp_eval(rt, scope, body_true);
	} else {
		return lisp_eval(rt, scope, body_false);
	}
}

static lisp_value *lisp_builtin_null_p(lisp_runtime *rt, lisp_scope *scope,
                                       lisp_value *a)
{
  lisp_value *v;
  lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
	lisp_value *v;
	lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);

  if (!lisp_get_args(args, "*", &v)) {
    return (lisp_value*) lisp_error_new(rt, "expected one argument");
  }
	if (!lisp_get_args(args, "*", &v)) {
		return (lisp_value*) lisp_error_new(rt, "expected one argument");
	}

  lisp_integer *result = (lisp_integer*) lisp_new(rt, type_integer);
  result->x = (int) lisp_nil_p(v);
  return (lisp_value*)result;
	lisp_integer *result = (lisp_integer*) lisp_new(rt, type_integer);
	result->x = (int) lisp_nil_p(v);
	return (lisp_value*)result;
}

static lisp_list *get_quoted_left_items(lisp_runtime *rt, lisp_list *list_of_lists)
{
  lisp_list *left_items = NULL, *rv;
  while (!lisp_nil_p((lisp_value*)list_of_lists)) {
    // Create or advance left_items to the next list.
    if (left_items == NULL) {
      left_items = (lisp_list*) lisp_new(rt, type_list);
      rv = left_items;
    } else {
      left_items->right = lisp_new(rt, type_list);
      left_items = (lisp_list*) left_items->right;
    }
    // Check the next node in the list to make sure it's actually a list.
    if (lisp_nil_p(list_of_lists->left)) {
      return NULL;
    }
    // Get the next node in the list and get the argument.
    lisp_list *l = (lisp_list*) list_of_lists->left;
    left_items->left = lisp_quote(rt, l->left);
    list_of_lists = (lisp_list*) list_of_lists->right;
  }
  left_items->right = lisp_nil_new(rt);
  return rv;
	lisp_list *left_items = NULL, *rv;
	while (!lisp_nil_p((lisp_value*)list_of_lists)) {
		// Create or advance left_items to the next list.
		if (left_items == NULL) {
			left_items = (lisp_list*) lisp_new(rt, type_list);
			rv = left_items;
		} else {
			left_items->right = lisp_new(rt, type_list);
			left_items = (lisp_list*) left_items->right;
		}
		// Check the next node in the list to make sure it's actually a list.
		if (lisp_nil_p(list_of_lists->left)) {
			return NULL;
		}
		// Get the next node in the list and get the argument.
		lisp_list *l = (lisp_list*) list_of_lists->left;
		left_items->left = lisp_quote(rt, l->left);
		list_of_lists = (lisp_list*) list_of_lists->right;
	}
	left_items->right = lisp_nil_new(rt);
	return rv;
}

static lisp_list *advance_lists(lisp_runtime *rt, lisp_list *list_of_lists)
{
  lisp_list *right_items = NULL, *rv;
  while (!lisp_nil_p((lisp_value*)list_of_lists)) {
    // Create or advance left_items to the next list.
    if (right_items == NULL) {
      right_items = (lisp_list*) lisp_new(rt, type_list);
      rv = right_items;
    } else {
      right_items->right = lisp_new(rt, type_list);
      right_items = (lisp_list*) right_items->right;
    }
    // Check the next node in the list to make sure it's actually a list.
    if (list_of_lists->left->type != type_list) {
      return NULL;
    }
    // Get the next node in the list and get the argument.
    lisp_list *l = (lisp_list*) list_of_lists->left;
    right_items->left = l->right;
    list_of_lists = (lisp_list*) list_of_lists->right;
  }
  right_items->right = lisp_nil_new(rt);
  return rv;
	lisp_list *right_items = NULL, *rv;
	while (!lisp_nil_p((lisp_value*)list_of_lists)) {
		// Create or advance left_items to the next list.
		if (right_items == NULL) {
			right_items = (lisp_list*) lisp_new(rt, type_list);
			rv = right_items;
		} else {
			right_items->right = lisp_new(rt, type_list);
			right_items = (lisp_list*) right_items->right;
		}
		// Check the next node in the list to make sure it's actually a list.
		if (list_of_lists->left->type != type_list) {
			return NULL;
		}
		// Get the next node in the list and get the argument.
		lisp_list *l = (lisp_list*) list_of_lists->left;
		right_items->left = l->right;
		list_of_lists = (lisp_list*) list_of_lists->right;
	}
	right_items->right = lisp_nil_new(rt);
	return rv;
}

static lisp_value *lisp_builtin_map(lisp_runtime *rt, lisp_scope *scope,
                                    lisp_value *a)
{
  lisp_value *f;
  lisp_list *ret = NULL, *args, *rv;
  lisp_list *map_args = (lisp_list *) lisp_eval_list(rt, scope, a);

  // Get the function from the first argument in the list.
  f = map_args->left;
  if (map_args->right->type != type_list) {
    return (lisp_value*) lisp_error_new(rt, "need at least two arguments");
  }
  map_args = (lisp_list*) map_args->right;
  while ((args = get_quoted_left_items(rt, map_args)) != NULL) {
    if (ret == NULL) {
      ret = (lisp_list*) lisp_new(rt, type_list);
      rv = ret;
    } else {
      ret->right = lisp_new(rt, type_list);
      ret = (lisp_list*) ret->right;
    }
    ret->left = lisp_call(rt, scope, f, (lisp_value*)args);
    map_args = advance_lists(rt, map_args);
  }
  ret->right = lisp_nil_new(rt);
  return (lisp_value*) rv;
	lisp_value *f;
	lisp_list *ret = NULL, *args, *rv;
	lisp_list *map_args = (lisp_list *) lisp_eval_list(rt, scope, a);

	// Get the function from the first argument in the list.
	f = map_args->left;
	if (map_args->right->type != type_list) {
		return (lisp_value*) lisp_error_new(rt, "need at least two arguments");
	}
	map_args = (lisp_list*) map_args->right;
	while ((args = get_quoted_left_items(rt, map_args)) != NULL) {
		if (ret == NULL) {
			ret = (lisp_list*) lisp_new(rt, type_list);
			rv = ret;
		} else {
			ret->right = lisp_new(rt, type_list);
			ret = (lisp_list*) ret->right;
		}
		ret->left = lisp_call(rt, scope, f, (lisp_value*)args);
		map_args = advance_lists(rt, map_args);
	}
	ret->right = lisp_nil_new(rt);
	return (lisp_value*) rv;
}

static lisp_value *lisp_builtin_reduce(lisp_runtime *rt, lisp_scope *scope, lisp_value *a)
{
  lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
  int length = lisp_list_length(args);
  lisp_value *callable, *initializer;
  lisp_list *list;

  if (length == 2) {
    if (!lisp_get_args(args, "*l", &callable, &list)) {
      return (lisp_value*) lisp_error_new(rt, "reduce: callable and list required");
    }
    if (lisp_list_length(list) < 2) {
      return (lisp_value*) lisp_error_new(rt, "reduce: list must have at least 2 entries");
    }
    initializer = list->left;
    list = (lisp_list*)list->right;
	lisp_list *args = (lisp_list*) lisp_eval_list(rt, scope, a);
	int length = lisp_list_length(args);
	lisp_value *callable, *initializer;
	lisp_list *list;

	if (length == 2) {
		if (!lisp_get_args(args, "*l", &callable, &list)) {
			return (lisp_value*) lisp_error_new(rt, "reduce: callable and list required");
		}
		if (lisp_list_length(list) < 2) {
			return (lisp_value*) lisp_error_new(rt, "reduce: list must have at least 2 entries");
		}
		initializer = list->left;
		list = (lisp_list*)list->right;
 } else if (length == 3) {
    if (!lisp_get_args(args, "**l", &callable, &initializer, &list)) {
      return (lisp_value*) lisp_error_new(rt, "reduce: callable, initializer, and list required");
    }
    if (lisp_list_length(list) < 1) {
      return (lisp_value*) lisp_error_new(rt, "reduce: list must have at least 1 entry");
    }
  } else {
    return (lisp_value*) lisp_error_new(rt, "reduce: 2 or 3 arguments required");
  }

  while (!lisp_nil_p((lisp_value*)list)) {
    initializer = lisp_call(rt, scope, callable,
                            (lisp_value*) lisp_new_pair_list(rt, initializer, list->left));
    list = (lisp_list*) list->right;
  }
  return initializer;
		if (!lisp_get_args(args, "**l", &callable, &initializer, &list)) {
			return (lisp_value*) lisp_error_new(rt, "reduce: callable, initializer, and list required");
		}
		if (lisp_list_length(list) < 1) {
			return (lisp_value*) lisp_error_new(rt, "reduce: list must have at least 1 entry");
		}
	} else {
		return (lisp_value*) lisp_error_new(rt, "reduce: 2 or 3 arguments required");
	}

	while (!lisp_nil_p((lisp_value*)list)) {
		initializer = lisp_call(rt, scope, callable,
		                        (lisp_value*) lisp_new_pair_list(rt, initializer, list->left));
		list = (lisp_list*) list->right;
	}
	return initializer;
}

void lisp_scope_populate_builtins(lisp_runtime *rt, lisp_scope *scope)
{
  lisp_scope_add_builtin(rt, scope, "eval", lisp_builtin_eval);
  lisp_scope_add_builtin(rt, scope, "car", lisp_builtin_car);
  lisp_scope_add_builtin(rt, scope, "cdr", lisp_builtin_cdr);
  lisp_scope_add_builtin(rt, scope, "quote", lisp_builtin_quote);
  lisp_scope_add_builtin(rt, scope, "cons", lisp_builtin_cons);
  lisp_scope_add_builtin(rt, scope, "lambda", lisp_builtin_lambda);
  lisp_scope_add_builtin(rt, scope, "define", lisp_builtin_define);
  lisp_scope_add_builtin(rt, scope, "+", lisp_builtin_plus);
  lisp_scope_add_builtin(rt, scope, "-", lisp_builtin_minus);
  lisp_scope_add_builtin(rt, scope, "*", lisp_builtin_multiply);
  lisp_scope_add_builtin(rt, scope, "/", lisp_builtin_divide);
  lisp_scope_add_builtin(rt, scope, "==", lisp_builtin_eq);
  lisp_scope_add_builtin(rt, scope, "=", lisp_builtin_eq);
  lisp_scope_add_builtin(rt, scope, ">", lisp_builtin_gt);
  lisp_scope_add_builtin(rt, scope, ">=", lisp_builtin_ge);
  lisp_scope_add_builtin(rt, scope, "<", lisp_builtin_lt);
  lisp_scope_add_builtin(rt, scope, "<=", lisp_builtin_le);
  lisp_scope_add_builtin(rt, scope, "if", lisp_builtin_if);
  lisp_scope_add_builtin(rt, scope, "null?", lisp_builtin_null_p);
  lisp_scope_add_builtin(rt, scope, "map", lisp_builtin_map);
  lisp_scope_add_builtin(rt, scope, "reduce", lisp_builtin_reduce);
	lisp_scope_add_builtin(rt, scope, "eval", lisp_builtin_eval);
	lisp_scope_add_builtin(rt, scope, "car", lisp_builtin_car);
	lisp_scope_add_builtin(rt, scope, "cdr", lisp_builtin_cdr);
	lisp_scope_add_builtin(rt, scope, "quote", lisp_builtin_quote);
	lisp_scope_add_builtin(rt, scope, "cons", lisp_builtin_cons);
	lisp_scope_add_builtin(rt, scope, "lambda", lisp_builtin_lambda);
	lisp_scope_add_builtin(rt, scope, "define", lisp_builtin_define);
	lisp_scope_add_builtin(rt, scope, "+", lisp_builtin_plus);
	lisp_scope_add_builtin(rt, scope, "-", lisp_builtin_minus);
	lisp_scope_add_builtin(rt, scope, "*", lisp_builtin_multiply);
	lisp_scope_add_builtin(rt, scope, "/", lisp_builtin_divide);
	lisp_scope_add_builtin(rt, scope, "==", lisp_builtin_eq);
	lisp_scope_add_builtin(rt, scope, "=", lisp_builtin_eq);
	lisp_scope_add_builtin(rt, scope, ">", lisp_builtin_gt);
	lisp_scope_add_builtin(rt, scope, ">=", lisp_builtin_ge);
	lisp_scope_add_builtin(rt, scope, "<", lisp_builtin_lt);
	lisp_scope_add_builtin(rt, scope, "<=", lisp_builtin_le);
	lisp_scope_add_builtin(rt, scope, "if", lisp_builtin_if);
	lisp_scope_add_builtin(rt, scope, "null?", lisp_builtin_null_p);
	lisp_scope_add_builtin(rt, scope, "map", lisp_builtin_map);
	lisp_scope_add_builtin(rt, scope, "reduce", lisp_builtin_reduce);
}