7 /* Some terminology used in function names:
8 * - initialize: These functions take a pointer and potentially some other arguments, and use those
9 * to initialize the value pointed to by self. Initialize functions DO NOT allocate the function,
10 * so they can be used to initialize stack-allocated variables.
11 * - construct: This allocates a value for a pointer, initializes it, and returns it. This is for
12 * heap-allocated values. It may be as simple as allocating the memory, calling an initialize, and
14 * - deinitialize: These functions dereference or free any objects pointed to by the self pointer's
15 * value, but they don't actually free the self pointer. This is useful for stack-allocated objects
16 * which point to heap-allocated objects.
17 * - destruct: This dereferences or frees memory pointed to by the self argument, and all the
18 * pointers on the self argument.
21 {% for standard_library in standard_libraries %}
22 #include <{{standard_library}}>
26 typedef enum Type Type;
28 typedef union Instance Instance;
30 typedef struct Object Object;
31 struct EnvironmentNode;
32 typedef struct EnvironmentNode EnvironmentNode;
34 typedef struct Environment Environment;
35 struct EnvironmentPool;
36 typedef struct EnvironmentPool EnvironmentPool;
38 const char* const STRING_LITERAL_LIST[] = {
39 {% for string_literal in string_literal_list %}
40 "{{ string_literal }}",
44 const char* const SYMBOL_LIST[] = {
45 {% for symbol in symbol_list %}
62 typedef struct Closure Closure;
66 Object (*call)(EnvironmentPool*, Environment*, size_t, Object*);
70 typedef struct List List;
78 struct StringConcatenation;
79 typedef struct StringConcatenation StringConcatenation;
87 StringConcatenation* string_concatenation;
88 const char* string_literal;
97 const Object builtin$true = { BOOLEAN, (Instance)(bool){ true } };
98 const Object builtin$false = { BOOLEAN, (Instance)(bool){ false } };
99 const Object builtin$nil = { VOID, { 0 } };
101 struct StringConcatenation
103 size_t referenceCount;
108 Object List_construct(size_t allocate)
110 Object* items = malloc(sizeof(Object) * allocate);
111 Object result = { LIST, (Instance)(List){ allocate, 0, items } };
115 void List_append(Object* list, Object item)
117 assert(list->type == LIST);
119 if(list->instance.list.allocated == list->instance.list.length)
121 list->instance.list.allocated *= 2;
122 list->instance.list.items = realloc(
123 list->instance.list.items,
124 sizeof(Object) * list->instance.list.allocated
128 list->instance.list.items[list->instance.list.length] = item;
129 list->instance.list.length++;
132 Object List_get(Object* list, Object index)
134 assert(list->type == LIST);
135 assert(index.type == INTEGER);
137 return list->instance.list.items[index.instance.integer];
140 struct EnvironmentNode
144 EnvironmentNode* next;
153 EnvironmentNode* root;
156 void Environment_initialize(Environment* self, Environment* parent)
158 self->parent = parent;
161 // We are currently only ever initializing environments at the beginning of running functions, so
162 // for now at least we can assume that we want it to be live immediately.
166 void Object_deinitialize(Object* self)
182 for(size_t i = 0; i < self->instance.list.length; i++) {
183 Object_deinitialize(&(self->instance.list.items[i]));
186 free(self->instance.list.items);
189 case STRING_CONCATENATION:
190 self->instance.string_concatenation->referenceCount--;
192 if(self->instance.string_concatenation->referenceCount == 0)
194 Object_deinitialize(&(self->instance.string_concatenation->left));
195 Object_deinitialize(&(self->instance.string_concatenation->right));
196 free(self->instance.string_concatenation);
205 void Environment_deinitialize(Environment* self)
207 EnvironmentNode* next;
208 for(EnvironmentNode* node = self->root; node != NULL; node = next)
211 Object_deinitialize(&(node->value));
216 void Environment_setLive(Environment* self, bool live)
221 void Environment_mark(Environment* self)
223 if(self == NULL) return;
224 if(self->mark) return; // Prevents infinite recursion in the case of cycles
228 Environment_mark(self->parent);
230 for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
232 switch(node->value.type)
241 Environment_mark(node->value.instance.closure.closed);
250 // This need not be thread safe because environments exist on one thread only
251 void Environment_set(Environment* self, const char* const key, Object value)
253 EnvironmentNode* node = malloc(sizeof(EnvironmentNode));
256 node->next = self->root;
260 Object Environment_get(Environment* self, const char* const symbol)
262 for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
264 // We can compare pointers because pointers are unique in the SYMBOL_LIST
265 if(node->key == symbol)
271 if(self->parent != NULL)
273 return Environment_get(self->parent, symbol);
276 // TODO Handle symbol errors
280 # define POOL_SIZE 64
281 struct EnvironmentPool
284 bool allocatedFlags[POOL_SIZE];
285 Environment environments[POOL_SIZE];
286 EnvironmentPool* overflow;
289 EnvironmentPool* EnvironmentPool_construct();
290 void EnvironmentPool_initialize(EnvironmentPool*);
291 void EnvironmentPool_deinitialize(EnvironmentPool*);
292 void EnvironmentPool_destruct(EnvironmentPool*);
294 EnvironmentPool* EnvironmentPool_construct()
296 EnvironmentPool* result = malloc(sizeof(EnvironmentPool));
297 EnvironmentPool_initialize(result);
301 void EnvironmentPool_initialize(EnvironmentPool* self)
303 self->overflow = NULL;
306 for(size_t i = 0; i < POOL_SIZE; i++)
308 self->allocatedFlags[i] = false;
309 self->environments[i].live = false;
313 void EnvironmentPool_deinitialize(EnvironmentPool* self)
315 // We can assume if this is being called, none of the Environments are live
316 for(int8_t i = 0; i < POOL_SIZE; i++)
318 if(self->allocatedFlags[i]) Environment_deinitialize(&(self->environments[i]));
321 EnvironmentPool_destruct(self->overflow);
324 void EnvironmentPool_destruct(EnvironmentPool* self)
326 if(self == NULL) return;
327 EnvironmentPool_deinitialize(self);
331 void EnvironmentPool_GC(EnvironmentPool* self)
333 // Unmark all the environments
334 for(EnvironmentPool* current = self; current != NULL; current = current->overflow)
336 for(int8_t i = 0; i < POOL_SIZE; i++)
338 current->environments[i].mark = false;
342 // Mark live enviroments and environments referenced by live environments
343 for(EnvironmentPool* current = self; current != NULL; current = current->overflow)
345 for(int8_t i = 0; i < POOL_SIZE; i++)
347 if(current->environments[i].live)
349 Environment_mark(&(current->environments[i]));
354 // TODO We never free pools until the very end--we could free a pool if two pools are empty
355 for(EnvironmentPool* current = self; current != NULL; current = current->overflow)
357 for(int8_t i = POOL_SIZE - 1; i >= 0; i--)
359 if(!current->environments[i].mark && current->allocatedFlags[i])
361 Environment_deinitialize(&(current->environments[i]));
362 current->allocatedFlags[i] = false;
363 current->freeIndex = i;
369 Environment* EnvironmentPool_allocate(EnvironmentPool* self)
371 for(EnvironmentPool* current = self; current != NULL; current = current->overflow)
373 for(; current->freeIndex < POOL_SIZE; current->freeIndex++)
375 if(!current->allocatedFlags[current->freeIndex])
377 current->allocatedFlags[current->freeIndex] = true;
378 return &(current->environments[current->freeIndex]);
383 EnvironmentPool_GC(self);
385 EnvironmentPool* previous;
386 for(EnvironmentPool* current = self; current != NULL; current = current->overflow)
388 for(; current->freeIndex < POOL_SIZE; current->freeIndex++)
390 if(!current->allocatedFlags[current->freeIndex])
392 current->allocatedFlags[current->freeIndex] = true;
393 return &(current->environments[current->freeIndex]);
402 previous->overflow = EnvironmentPool_construct();
403 return EnvironmentPool_allocate(previous->overflow);
406 Object integerLiteral(int32_t literal)
409 result.type = INTEGER;
410 result.instance.integer = literal;
414 Object stringLiteral(const char* literal)
417 result.type = STRING_LITERAL;
418 result.instance.string_literal = literal;
422 // TODO Make this conditionally added
423 Object operator$negate(Object input)
425 assert(input.type == INTEGER);
428 result.type = INTEGER;
429 result.instance.integer = -input.instance.integer;
433 // TODO Make this conditionally added
434 Object operator$concatenate(Object left, Object right)
437 case STRING_CONCATENATION:
438 left.instance.string_concatenation->referenceCount++;
449 case STRING_CONCATENATION:
450 right.instance.string_concatenation->referenceCount++;
460 StringConcatenation* concatenation = malloc(sizeof(StringConcatenation));
461 concatenation->referenceCount = 1;
462 concatenation->left = left;
463 concatenation->right = right;
465 Object result = { STRING_CONCATENATION, (Instance)concatenation };
469 {% for id in infix_declarations %}
470 Object operator${{ id.name }}(Object left, Object right)
472 assert(left.type == {{ id.in_type.upper() }});
473 assert(right.type == {{ id.in_type.upper() }});
476 result.type = {{ id.out_type.upper() }};
477 result.instance.{{ id.out_type.lower() }} = left.instance.{{ id.in_type.lower() }} {{ id.operator }} right.instance.{{ id.in_type.lower() }};
482 {% if 'pow' in builtins %}
483 Object builtin$pow$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args)
487 Object base = args[0];
488 Object exponent = args[1];
490 assert(base.type == INTEGER);
491 assert(exponent.type == INTEGER);
494 result.type = INTEGER;
495 result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
499 Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } };
502 {% if 'print' in builtins %}
503 Object builtin$print$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args)
505 for(size_t i = 0; i < argc; i++)
507 Object output = args[i];
511 fputs(output.instance.boolean ? "true" : "false", stdout);
515 // TODO Print something better
520 printf("%" PRId32, output.instance.integer);
523 case STRING_CONCATENATION:
524 builtin$print$implementation(NULL, NULL, 1, &(output.instance.string_concatenation->left));
525 builtin$print$implementation(NULL, NULL, 1, &(output.instance.string_concatenation->right));
529 // Using fwrite instead of printf to handle size_t length
530 printf("%s", output.instance.string_literal);
540 Object_deinitialize(&output);
543 // TODO Return something better
544 return builtin$false;
547 Object builtin$print = { CLOSURE, (Instance)(Closure){ NULL, builtin$print$implementation } };
549 {% for function_definition in function_definition_list %}
550 {{ function_definition }}
553 int main(int argc, char** argv)
555 EnvironmentPool* environmentPool = EnvironmentPool_construct();
556 Environment* environment = EnvironmentPool_allocate(environmentPool);
557 Environment_initialize(environment, NULL);
559 // TODO Use the symbol from SYMBOL_LIST
560 {% for builtin in builtins %}
561 Environment_set(environment, "{{ builtin }}", builtin${{ builtin }});
564 {% for statement in statements %}
568 Environment_setLive(environment, false);
569 EnvironmentPool_destruct(environmentPool);