+const Object builtin$true = { BOOLEAN, (Instance)(bool){ true } };
+const Object builtin$false = { BOOLEAN, (Instance)(bool){ false } };
+const Object builtin$nil = { VOID, { 0 } };
+
+struct StringConcatenation
+{
+ size_t referenceCount;
+ Object left;
+ Object right;
+};
+
+Object List_construct(size_t allocate)
+{
+ Object* items = malloc(sizeof(Object) * allocate);
+ Object result = { LIST, (Instance)(List){ allocate, 0, items } };
+ return result;
+}
+
+void List_append(Object* list, Object item)
+{
+ assert(list->type == LIST);
+
+ if(list->instance.list.allocated == list->instance.list.length)
+ {
+ list->instance.list.allocated *= 2;
+ list->instance.list.items = realloc(
+ list->instance.list.items,
+ sizeof(Object) * list->instance.list.allocated
+ );
+ }
+
+ list->instance.list.items[list->instance.list.length] = item;
+ list->instance.list.length++;
+}
+
+Object List_get(Object* list, Object index)
+{
+ assert(list->type == LIST);
+ assert(index.type == INTEGER);
+
+ return list->instance.list.items[index.instance.integer];
+}
+
+struct EnvironmentNode
+{
+ const char* key;
+ Object value;
+ EnvironmentNode* next;
+};
+
+struct Environment
+{
+ bool mark;
+ bool live;
+
+ Environment* parent;
+ EnvironmentNode* root;
+};
+
+void Environment_initialize(Environment* self, Environment* parent)
+{
+ self->parent = parent;
+ self->root = NULL;
+
+ // We are currently only ever initializing environments at the beginning of running functions, so
+ // for now at least we can assume that we want it to be live immediately.
+ self->live = true;
+}
+
+void Object_deinitialize(Object* self)
+{
+ switch(self->type)
+ {
+ case BOOLEAN:
+ break;
+ case CLOSURE:
+ break;
+ case INTEGER:
+ break;
+ case STRING_LITERAL:
+ break;
+ case VOID:
+ break;
+
+ case LIST:
+ for(size_t i = 0; i < self->instance.list.length; i++) {
+ Object_deinitialize(&(self->instance.list.items[i]));
+ }
+
+ free(self->instance.list.items);
+ break;
+
+ case STRING_CONCATENATION:
+ self->instance.string_concatenation->referenceCount--;
+
+ if(self->instance.string_concatenation->referenceCount == 0)
+ {
+ Object_deinitialize(&(self->instance.string_concatenation->left));
+ Object_deinitialize(&(self->instance.string_concatenation->right));
+ free(self->instance.string_concatenation);
+ }
+ break;
+
+ default:
+ assert(false);
+ }
+}
+
+void Environment_deinitialize(Environment* self)
+{
+ EnvironmentNode* next;
+ for(EnvironmentNode* node = self->root; node != NULL; node = next)
+ {
+ next = node->next;
+ Object_deinitialize(&(node->value));
+ free(node);
+ }
+}
+
+void Environment_setLive(Environment* self, bool live)
+{
+ self->live = live;
+}
+
+void Environment_mark(Environment* self)
+{
+ if(self == NULL) return;
+ if(self->mark) return; // Prevents infinite recursion in the case of cycles
+
+ self->mark = true;
+
+ Environment_mark(self->parent);
+
+ for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
+ {
+ switch(node->value.type)
+ {
+ case BOOLEAN:
+ case INTEGER:
+ case STRING_LITERAL:
+ case VOID:
+ break;
+
+ case CLOSURE:
+ Environment_mark(node->value.instance.closure.closed);
+ break;
+
+ default:
+ assert(false);
+ }
+ }
+}
+
+// This need not be thread safe because environments exist on one thread only
+void Environment_set(Environment* self, const char* const key, Object value)
+{
+ EnvironmentNode* node = malloc(sizeof(EnvironmentNode));
+ node->key = key;
+ node->value = value;
+ node->next = self->root;
+ self->root = node;
+}
+
+Object Environment_get(Environment* self, const char* const symbol)
+{
+ for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
+ {
+ // We can compare pointers because pointers are unique in the SYMBOL_LIST
+ if(node->key == symbol)
+ {
+ return node->value;
+ }
+ }
+
+ if(self->parent != NULL)
+ {
+ return Environment_get(self->parent, symbol);
+ }
+
+ // TODO Handle symbol errors
+ assert(false);
+}
+
+# define POOL_SIZE 64
+struct EnvironmentPool