9 typedef enum Type Type;
22 typedef enum Builtin Builtin;
31 typedef struct Object Object;
33 typedef struct Environment Environment;
35 typedef struct Thread Thread;
38 typedef struct Closure Closure;
40 Environment* environment;
45 typedef struct List List;
48 typedef struct Structure Structure;
51 typedef union Value Value;
79 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
81 void Object_deinitialize(Object* self) {
84 {% include "environment.c" %}
85 {% include "stack.c" %}
86 {% include "frame.c" %}
93 void Thread_initialize(Thread* self, size_t programCounter) {
94 Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
95 Stack_initialize(&(self->stack));
98 void Thread_deinitialize(Thread* self) {
99 Frame_deinitialize(&(self->frame));
100 Stack_deinitialize(&(self->stack));
103 Environment* Thread_getEnvironment(Thread* self) {
104 return self->frame.environment;
107 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
108 self->frame.programCounter = programCounter;
111 void Thread_incrementProgramCounter(Thread* self) {
112 self->frame.programCounter++;
115 size_t Thread_getProgramCounter(Thread* self) {
116 return self->frame.programCounter;
120 typedef const union Argument Argument;
129 void callBuiltinField(Thread* thread, size_t argumentCount) {
130 assert(argumentCount == 2);
132 assert(!Stack_isEmpty(&(thread->stack)));
133 Object key = Stack_pop(&(thread->stack));
134 assert(key.type == STRING); // TODO Make this a symbol
136 assert(!Stack_isEmpty(&(thread->stack)));
137 Object structure = Stack_pop(&(thread->stack));
138 assert(structure.type == STRUCTURE);
140 while(structure.value.structure != NULL) {
141 if(strcmp(structure.value.structure->key, key.value.string) == 0) {
142 Stack_push(&(thread->stack), structure.value.structure->value);
145 structure.value.structure = structure.value.structure->next;
148 assert(false); // Symbol wasn't found in structure
151 void callBuiltinPow(Thread* thread, size_t argumentCount) {
152 assert(argumentCount == 2);
153 assert(!Stack_isEmpty(&(thread->stack)));
154 Object exponent = Stack_pop(&(thread->stack));
155 assert(exponent.type == INTEGER);
156 assert(exponent.value.integer >= 0);
158 assert(!Stack_isEmpty(&(thread->stack)));
159 Object base = Stack_pop(&(thread->stack));
160 assert(base.type == INTEGER);
163 result.type = INTEGER;
164 result.value.integer = 1;
166 while(exponent.value.integer > 0) {
167 result.value.integer *= base.value.integer;
168 exponent.value.integer--;
171 Stack_push(&(thread->stack), result);
174 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
175 assert(argumentCount > 0);
177 Object arguments[argumentCount];
180 for(count = 0; count < argumentCount; count++) {
181 assert(!Stack_isEmpty(&(thread->stack)));
182 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
185 for(count = 0; count < argumentCount; count ++) {
186 Object arg = arguments[count];
190 if(arg.value.boolean) printf("true");
191 else printf("false");
195 printf("%i", arg.value.integer);
199 printf("%s", arg.value.string);
207 Stack_push(&(thread->stack), BUILTIN_NIL);
210 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
213 callBuiltinField(thread, argumentCount);
217 callBuiltinPow(thread, argumentCount);
221 callBuiltinPrint(thread, argumentCount);
229 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
230 // TODO Find a way to assert the argument count
232 Frame* returnFrame = malloc(sizeof(Frame));
233 *returnFrame = thread->frame;
236 Environment_construct(Environment_reference(closure.environment)),
238 closure.entry - 1 // We will increment the frame immediately after this
242 void inst_call(Thread* thread, Argument argument) {
243 assert(!Stack_isEmpty(&(thread->stack)));
244 Object f = Stack_pop(&(thread->stack));
245 size_t argumentCount = argument.label;
249 callBuiltin(thread, f.value.builtin, argumentCount);
253 callClosure(thread, f.value.closure, argumentCount);
261 void inst_concat(Thread* thread, Argument argument) {
262 assert(!Stack_isEmpty(&(thread->stack)));
263 Object left = Stack_pop(&(thread->stack));
264 assert(!Stack_isEmpty(&(thread->stack)));
265 Object right = Stack_pop(&(thread->stack));
267 assert(left.type == STRING);
268 assert(right.type == STRING);
270 char* resultString = malloc(strlen(left.value.string) + strlen(right.value.string) + 1);
271 resultString[0] = '\0';
273 strcat(resultString, left.value.string);
274 strcat(resultString, right.value.string);
276 Object resultObject = (Object) {
281 Stack_push(&(thread->stack), resultObject);
284 {% with name='add', operation='+' %}
285 {% include "arithmetic_instruction.c" %}
288 void inst_close(Thread* thread, Argument argument) {
290 result.type = CLOSURE;
291 result.value.closure.environment = Thread_getEnvironment(thread);
292 result.value.closure.entry = argument.label;
294 Stack_push(&(thread->stack), result);
297 void inst_drop(Thread* thread, Argument argument) {
298 assert(!Stack_isEmpty(&(thread->stack)));
299 Object result = Stack_pop(&(thread->stack));
300 Object_deinitialize(&result);
303 void inst_end(Thread* thread, Argument argument) {
306 {% with name='eq', operation='==' %}
307 {% include "comparison_instruction.c" %}
310 void inst_get(Thread* thread, Argument argument) {
311 assert(!Stack_isEmpty(&(thread->stack)));
312 Object indexObject = Stack_pop(&(thread->stack));
313 assert(indexObject.type == INTEGER);
314 int32_t index = indexObject.value.integer;
316 assert(!Stack_isEmpty(&(thread->stack)));
317 Object listObject = Stack_pop(&(thread->stack));
318 assert(listObject.type == LIST);
319 List* list = listObject.value.list;
322 assert(list != NULL);
327 assert(list != NULL);
328 Stack_push(&(thread->stack), list->head);
331 {% with name='gt', operation='>' %}
332 {% include "comparison_instruction.c" %}
335 {% with name='gte', operation='>=' %}
336 {% include "comparison_instruction.c" %}
339 {% with name='idiv', operation='/' %}
340 {% include "arithmetic_instruction.c" %}
343 void inst_jump(Thread* thread, Argument argument) {
344 Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
347 void inst_jump_if_false(Thread* thread, Argument argument) {
348 assert(!Stack_isEmpty(&(thread->stack)));
349 Object result = Stack_pop(&(thread->stack));
350 assert(result.type == BOOLEAN);
352 if(!(result.value.boolean)) {
353 inst_jump(thread, argument);
357 void inst_list(Thread* thread, Argument argument) {
360 result.value.list = NULL;
362 int32_t count = argument.integer;
365 assert(!Stack_isEmpty(&(thread->stack)));
366 Object item = Stack_pop(&(thread->stack));
368 List* node = malloc(sizeof(List));
370 node->tail = result.value.list;
372 result.value.list = node;
376 Stack_push(&(thread->stack), result);
379 {% with name='lt', operation='<' %}
380 {% include "comparison_instruction.c" %}
383 {% with name='lte', operation='<=' %}
384 {% include "comparison_instruction.c" %}
387 {% with name='mod', operation='%' %}
388 {% include "arithmetic_instruction.c" %}
391 {% with name='mul', operation='*' %}
392 {% include "arithmetic_instruction.c" %}
395 {% with name='neq', operation='!=' %}
396 {% include "comparison_instruction.c" %}
399 void inst_neg(Thread* thread, Argument argument) {
400 assert(!Stack_isEmpty(&(thread->stack)));
401 Object result = Stack_pop(&(thread->stack));
402 assert(result.type == INTEGER);
404 result.value.integer = -(result.value.integer);
406 Stack_push(&(thread->stack), result);
409 void inst_pop(Thread* thread, Argument argument) {
410 char* argumentString = argument.string;
412 assert(!Stack_isEmpty(&(thread->stack)));
413 Object result = Stack_pop(&(thread->stack));
415 if(strcmp(argumentString, "print") == 0) {
417 } else if(strcmp(argumentString, "pow") == 0) {
422 Environment_set(Thread_getEnvironment(thread), argumentString, result);
425 void inst_push(Thread* thread, Argument argument) {
426 char* argumentString = argument.string;
428 if(strcmp(argumentString, "__field__") == 0) {
429 // TODO Make this an instruction
431 result.type = BUILTIN;
432 result.value.builtin = __FIELD__;
433 Stack_push(&(thread->stack), result);
434 } else if(strcmp(argumentString, "false") == 0) {
435 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
436 } else if(strcmp(argumentString, "pow") == 0) {
438 result.type = BUILTIN;
439 result.value.builtin = POW;
440 Stack_push(&(thread->stack), result);
441 } else if(strcmp(argumentString, "print") == 0) {
443 result.type = BUILTIN;
444 result.value.builtin = PRINT;
445 Stack_push(&(thread->stack), result);
446 } else if(strcmp(argumentString, "true") == 0) {
447 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
449 Environment_get_Result result = Environment_get(
450 Thread_getEnvironment(thread),
454 fprintf(stderr, "Variable `%s` not found", argumentString);
457 Stack_push(&(thread->stack), result.result);
461 void inst_push_integer(Thread* thread, Argument argument) {
463 result.type = INTEGER;
464 result.value.integer = argument.integer;
466 Stack_push(&(thread->stack), result);
469 void inst_push_string(Thread* thread, Argument argument) {
471 result.type = STRING;
472 result.value.string = argument.string;
474 Stack_push(&(thread->stack), result);
477 void inst_push_symbol(Thread* thread, Argument argument) {
478 // TODO Store symbols in a symbol table so they can be looked up by reference
479 // without string comparison
481 result.type = SYMBOL;
482 result.value.symbol = argument.symbol;
484 Stack_push(&(thread->stack), result);
487 {% with name='sub', operation='-' %}
488 {% include "arithmetic_instruction.c" %}
491 void inst_return(Thread* thread, Argument argument) {
492 Frame* returnFrame = thread->frame.returnFrame;
494 Frame_deinitialize(&(thread->frame));
498 returnFrame->environment,
499 returnFrame->returnFrame,
500 returnFrame->programCounter
506 void inst_structure(Thread* thread, Argument argument) {
508 result.type = STRUCTURE;
509 result.value.structure = NULL;
511 int32_t count = argument.integer;
514 assert(!Stack_isEmpty(&(thread->stack)));
515 Object key = Stack_pop(&(thread->stack));
516 assert(key.type == SYMBOL);
518 assert(!Stack_isEmpty(&(thread->stack)));
519 Object value = Stack_pop(&(thread->stack));
521 Structure* node = malloc(sizeof(Structure));
522 node->key = key.value.string;
524 node->next = result.value.structure;
526 result.value.structure = node;
530 Stack_push(&(thread->stack), result);
534 typedef const struct Instruction Instruction;
536 void (*instruction)(Thread*,Argument);
540 {% for label in labels_to_instruction_indices.keys() %}
541 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
544 const Instruction program[] = {
545 {% for instruction in instruction_list %}
546 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
552 Thread_initialize(&thread, LABEL___main__);
554 for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
555 program[Thread_getProgramCounter(&thread)].instruction(
557 program[Thread_getProgramCounter(&thread)].argument
561 Thread_deinitialize(&thread);