9 typedef enum Type Type;
22 typedef enum Builtin Builtin;
30 typedef struct Object Object;
32 typedef struct Environment Environment;
34 typedef struct Thread Thread;
37 typedef struct Closure Closure;
39 Environment* environment;
44 typedef struct List List;
47 typedef struct Structure Structure;
50 typedef union Value Value;
78 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
80 void Object_deinitialize(Object* self) {
83 {% include "environment.c" %}
84 {% include "stack.c" %}
85 {% include "frame.c" %}
92 void Thread_initialize(Thread* self, size_t programCounter) {
93 Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
94 Stack_initialize(&(self->stack));
97 void Thread_deinitialize(Thread* self) {
98 Frame_deinitialize(&(self->frame));
99 Stack_deinitialize(&(self->stack));
102 Environment* Thread_getEnvironment(Thread* self) {
103 return self->frame.environment;
106 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
107 self->frame.programCounter = programCounter;
110 void Thread_incrementProgramCounter(Thread* self) {
111 self->frame.programCounter++;
114 size_t Thread_getProgramCounter(Thread* self) {
115 return self->frame.programCounter;
119 typedef const union Argument Argument;
128 void callBuiltinPow(Thread* thread, size_t argumentCount) {
129 assert(argumentCount == 2);
130 assert(!Stack_isEmpty(&(thread->stack)));
131 Object exponent = Stack_pop(&(thread->stack));
132 assert(exponent.type == INTEGER);
133 assert(exponent.value.integer >= 0);
135 assert(!Stack_isEmpty(&(thread->stack)));
136 Object base = Stack_pop(&(thread->stack));
137 assert(base.type == INTEGER);
140 result.type = INTEGER;
141 result.value.integer = 1;
143 while(exponent.value.integer > 0) {
144 result.value.integer *= base.value.integer;
145 exponent.value.integer--;
148 Stack_push(&(thread->stack), result);
151 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
152 assert(argumentCount > 0);
154 Object arguments[argumentCount];
157 for(count = 0; count < argumentCount; count++) {
158 assert(!Stack_isEmpty(&(thread->stack)));
159 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
162 for(count = 0; count < argumentCount; count ++) {
163 Object arg = arguments[count];
167 if(arg.value.boolean) printf("true");
168 else printf("false");
172 printf("%i", arg.value.integer);
176 printf("%s", arg.value.string);
184 Stack_push(&(thread->stack), BUILTIN_NIL);
187 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
190 callBuiltinPow(thread, argumentCount);
194 callBuiltinPrint(thread, argumentCount);
202 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
203 // TODO Find a way to assert the argument count
205 Frame* returnFrame = malloc(sizeof(Frame));
206 *returnFrame = thread->frame;
209 Environment_construct(Environment_reference(closure.environment)),
211 closure.entry - 1 // We will increment the frame immediately after this
215 void inst_call(Thread* thread, Argument argument) {
216 assert(!Stack_isEmpty(&(thread->stack)));
217 Object f = Stack_pop(&(thread->stack));
218 size_t argumentCount = argument.label;
222 callBuiltin(thread, f.value.builtin, argumentCount);
226 callClosure(thread, f.value.closure, argumentCount);
234 void inst_concat(Thread* thread, Argument argument) {
235 assert(!Stack_isEmpty(&(thread->stack)));
236 Object left = Stack_pop(&(thread->stack));
237 assert(!Stack_isEmpty(&(thread->stack)));
238 Object right = Stack_pop(&(thread->stack));
240 assert(left.type == STRING);
241 assert(right.type == STRING);
243 char* resultString = malloc(strlen(left.value.string) + strlen(right.value.string) + 1);
244 resultString[0] = '\0';
246 strcat(resultString, left.value.string);
247 strcat(resultString, right.value.string);
249 Object resultObject = (Object) {
254 Stack_push(&(thread->stack), resultObject);
257 {% with name='add', operation='+' %}
258 {% include "arithmetic_instruction.c" %}
261 void inst_close(Thread* thread, Argument argument) {
263 result.type = CLOSURE;
264 result.value.closure.environment = Thread_getEnvironment(thread);
265 result.value.closure.entry = argument.label;
267 Stack_push(&(thread->stack), result);
270 void inst_drop(Thread* thread, Argument argument) {
271 assert(!Stack_isEmpty(&(thread->stack)));
272 Object result = Stack_pop(&(thread->stack));
273 Object_deinitialize(&result);
276 void inst_end(Thread* thread, Argument argument) {
279 {% with name='eq', operation='==' %}
280 {% include "comparison_instruction.c" %}
283 void inst_field(Thread* thread, Argument argument) {
284 assert(!Stack_isEmpty(&(thread->stack)));
285 Object key = Stack_pop(&(thread->stack));
286 assert(key.type == SYMBOL);
288 assert(!Stack_isEmpty(&(thread->stack)));
289 Object structure = Stack_pop(&(thread->stack));
290 assert(structure.type == STRUCTURE);
292 while(structure.value.structure != NULL) {
293 if(strcmp(structure.value.structure->key, key.value.string) == 0) {
294 Stack_push(&(thread->stack), structure.value.structure->value);
297 structure.value.structure = structure.value.structure->next;
300 assert(false); // Symbol wasn't found in structure
303 void inst_get(Thread* thread, Argument argument) {
304 assert(!Stack_isEmpty(&(thread->stack)));
305 Object indexObject = Stack_pop(&(thread->stack));
306 assert(indexObject.type == INTEGER);
307 int32_t index = indexObject.value.integer;
309 assert(!Stack_isEmpty(&(thread->stack)));
310 Object listObject = Stack_pop(&(thread->stack));
311 assert(listObject.type == LIST);
312 List* list = listObject.value.list;
315 assert(list != NULL);
320 assert(list != NULL);
321 Stack_push(&(thread->stack), list->head);
324 {% with name='gt', operation='>' %}
325 {% include "comparison_instruction.c" %}
328 {% with name='gte', operation='>=' %}
329 {% include "comparison_instruction.c" %}
332 {% with name='idiv', operation='/' %}
333 {% include "arithmetic_instruction.c" %}
336 void inst_jump(Thread* thread, Argument argument) {
337 Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
340 void inst_jump_if_false(Thread* thread, Argument argument) {
341 assert(!Stack_isEmpty(&(thread->stack)));
342 Object result = Stack_pop(&(thread->stack));
343 assert(result.type == BOOLEAN);
345 if(!(result.value.boolean)) {
346 inst_jump(thread, argument);
350 void inst_list(Thread* thread, Argument argument) {
353 result.value.list = NULL;
355 int32_t count = argument.integer;
358 assert(!Stack_isEmpty(&(thread->stack)));
359 Object item = Stack_pop(&(thread->stack));
361 List* node = malloc(sizeof(List));
363 node->tail = result.value.list;
365 result.value.list = node;
369 Stack_push(&(thread->stack), result);
372 {% with name='lt', operation='<' %}
373 {% include "comparison_instruction.c" %}
376 {% with name='lte', operation='<=' %}
377 {% include "comparison_instruction.c" %}
380 {% with name='mod', operation='%' %}
381 {% include "arithmetic_instruction.c" %}
384 {% with name='mul', operation='*' %}
385 {% include "arithmetic_instruction.c" %}
388 {% with name='neq', operation='!=' %}
389 {% include "comparison_instruction.c" %}
392 void inst_neg(Thread* thread, Argument argument) {
393 assert(!Stack_isEmpty(&(thread->stack)));
394 Object result = Stack_pop(&(thread->stack));
395 assert(result.type == INTEGER);
397 result.value.integer = -(result.value.integer);
399 Stack_push(&(thread->stack), result);
402 void inst_pop(Thread* thread, Argument argument) {
403 char* argumentString = argument.string;
405 assert(!Stack_isEmpty(&(thread->stack)));
406 Object result = Stack_pop(&(thread->stack));
408 if(strcmp(argumentString, "print") == 0) {
410 } else if(strcmp(argumentString, "pow") == 0) {
415 Environment_set(Thread_getEnvironment(thread), argumentString, result);
418 void inst_push(Thread* thread, Argument argument) {
419 char* argumentString = argument.string;
421 if(strcmp(argumentString, "false") == 0) {
422 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
423 } else if(strcmp(argumentString, "pow") == 0) {
425 result.type = BUILTIN;
426 result.value.builtin = POW;
427 Stack_push(&(thread->stack), result);
428 } else if(strcmp(argumentString, "print") == 0) {
430 result.type = BUILTIN;
431 result.value.builtin = PRINT;
432 Stack_push(&(thread->stack), result);
433 } else if(strcmp(argumentString, "true") == 0) {
434 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
436 Environment_get_Result result = Environment_get(
437 Thread_getEnvironment(thread),
441 fprintf(stderr, "Variable `%s` not found", argumentString);
444 Stack_push(&(thread->stack), result.result);
448 void inst_push_integer(Thread* thread, Argument argument) {
450 result.type = INTEGER;
451 result.value.integer = argument.integer;
453 Stack_push(&(thread->stack), result);
456 void inst_push_string(Thread* thread, Argument argument) {
458 result.type = STRING;
459 result.value.string = argument.string;
461 Stack_push(&(thread->stack), result);
464 void inst_push_symbol(Thread* thread, Argument argument) {
465 // TODO Store symbols in a symbol table so they can be looked up by reference
466 // without string comparison
468 result.type = SYMBOL;
469 result.value.symbol = argument.symbol;
471 Stack_push(&(thread->stack), result);
474 {% with name='sub', operation='-' %}
475 {% include "arithmetic_instruction.c" %}
478 void inst_return(Thread* thread, Argument argument) {
479 Frame* returnFrame = thread->frame.returnFrame;
481 Frame_deinitialize(&(thread->frame));
485 returnFrame->environment,
486 returnFrame->returnFrame,
487 returnFrame->programCounter
493 void inst_structure(Thread* thread, Argument argument) {
495 result.type = STRUCTURE;
496 result.value.structure = NULL;
498 int32_t count = argument.integer;
501 assert(!Stack_isEmpty(&(thread->stack)));
502 Object key = Stack_pop(&(thread->stack));
503 assert(key.type == SYMBOL);
505 assert(!Stack_isEmpty(&(thread->stack)));
506 Object value = Stack_pop(&(thread->stack));
508 Structure* node = malloc(sizeof(Structure));
509 node->key = key.value.string;
511 node->next = result.value.structure;
513 result.value.structure = node;
517 Stack_push(&(thread->stack), result);
521 typedef const struct Instruction Instruction;
523 void (*instruction)(Thread*,Argument);
527 {% for label in labels_to_instruction_indices.keys() %}
528 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
531 const Instruction program[] = {
532 {% for instruction in instruction_list %}
533 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
539 Thread_initialize(&thread, LABEL___main__);
541 for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
542 program[Thread_getProgramCounter(&thread)].instruction(
544 program[Thread_getProgramCounter(&thread)].argument
548 Thread_deinitialize(&thread);