9 typedef enum Type Type;
21 typedef enum Builtin Builtin;
29 typedef struct Object Object;
31 typedef struct Environment Environment;
33 typedef struct Thread Thread;
36 typedef struct Closure Closure;
38 Environment* environment;
43 typedef struct List List;
46 typedef union Value Value;
67 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
69 void Object_deinitialize(Object* self) {
72 {% include "environment.c" %}
73 {% include "stack.c" %}
74 {% include "frame.c" %}
81 void Thread_initialize(Thread* self, size_t programCounter) {
82 Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
83 Stack_initialize(&(self->stack));
86 void Thread_deinitialize(Thread* self) {
87 Frame_deinitialize(&(self->frame));
88 Stack_deinitialize(&(self->stack));
91 Environment* Thread_getEnvironment(Thread* self) {
92 return self->frame.environment;
95 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
96 self->frame.programCounter = programCounter;
99 void Thread_incrementProgramCounter(Thread* self) {
100 self->frame.programCounter++;
103 size_t Thread_getProgramCounter(Thread* self) {
104 return self->frame.programCounter;
108 typedef const union Argument Argument;
117 void callBuiltinPow(Thread* thread, size_t argumentCount) {
118 assert(argumentCount == 2);
119 assert(!Stack_isEmpty(&(thread->stack)));
120 Object exponent = Stack_pop(&(thread->stack));
121 assert(exponent.type == INTEGER);
122 assert(exponent.value.integer >= 0);
124 assert(!Stack_isEmpty(&(thread->stack)));
125 Object base = Stack_pop(&(thread->stack));
126 assert(base.type == INTEGER);
129 result.type = INTEGER;
130 result.value.integer = 1;
132 while(exponent.value.integer > 0) {
133 result.value.integer *= base.value.integer;
134 exponent.value.integer--;
137 Stack_push(&(thread->stack), result);
140 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
141 assert(argumentCount > 0);
143 Object arguments[argumentCount];
146 for(count = 0; count < argumentCount; count++) {
147 assert(!Stack_isEmpty(&(thread->stack)));
148 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
151 for(count = 0; count < argumentCount; count ++) {
152 Object arg = arguments[count];
156 if(arg.value.boolean) printf("true");
157 else printf("false");
161 printf("%i", arg.value.integer);
165 printf("%s", arg.value.string);
173 Stack_push(&(thread->stack), BUILTIN_NIL);
176 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
179 callBuiltinPow(thread, argumentCount);
182 callBuiltinPrint(thread, argumentCount);
190 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
191 assert(argumentCount == 0);
193 Frame* returnFrame = malloc(sizeof(Frame));
194 *returnFrame = thread->frame;
197 Environment_construct(Environment_reference(closure.environment)),
199 closure.entry - 1 // We will increment the frame immediately after this
203 void inst_call(Thread* thread, Argument argument) {
204 assert(!Stack_isEmpty(&(thread->stack)));
205 Object f = Stack_pop(&(thread->stack));
206 size_t argumentCount = argument.label;
210 callBuiltin(thread, f.value.builtin, argumentCount);
214 callClosure(thread, f.value.closure, argumentCount);
222 void inst_concat(Thread* thread, Argument argument) {
223 assert(!Stack_isEmpty(&(thread->stack)));
224 Object left = Stack_pop(&(thread->stack));
225 assert(!Stack_isEmpty(&(thread->stack)));
226 Object right = Stack_pop(&(thread->stack));
228 assert(left.type == STRING);
229 assert(right.type == STRING);
231 char* resultString = malloc(strlen(left.value.string) + strlen(right.value.string) + 1);
232 resultString[0] = '\0';
234 strcat(resultString, left.value.string);
235 strcat(resultString, right.value.string);
237 Object resultObject = (Object) {
242 Stack_push(&(thread->stack), resultObject);
245 {% with name='add', operation='+' %}
246 {% include "arithmetic_instruction.c" %}
249 void inst_close(Thread* thread, Argument argument) {
251 result.type = CLOSURE;
252 result.value.closure.environment = Thread_getEnvironment(thread);
253 result.value.closure.entry = argument.label;
255 Stack_push(&(thread->stack), result);
258 void inst_drop(Thread* thread, Argument argument) {
259 assert(!Stack_isEmpty(&(thread->stack)));
260 Object result = Stack_pop(&(thread->stack));
261 Object_deinitialize(&result);
264 void inst_end(Thread* thread, Argument argument) {
267 {% with name='eq', operation='==' %}
268 {% include "comparison_instruction.c" %}
271 void inst_get(Thread* thread, Argument argument) {
272 assert(!Stack_isEmpty(&(thread->stack)));
273 Object listObject = Stack_pop(&(thread->stack));
274 assert(listObject.type == LIST);
275 List* list = listObject.value.list;
277 assert(!Stack_isEmpty(&(thread->stack)));
278 Object indexObject = Stack_pop(&(thread->stack));
279 assert(indexObject.type == INTEGER);
280 int32_t index = indexObject.value.integer;
283 assert(list != NULL);
288 assert(list != NULL);
289 Stack_push(&(thread->stack), list->head);
292 {% with name='gt', operation='>' %}
293 {% include "comparison_instruction.c" %}
296 {% with name='gte', operation='>=' %}
297 {% include "comparison_instruction.c" %}
300 {% with name='idiv', operation='/' %}
301 {% include "arithmetic_instruction.c" %}
304 void inst_jump(Thread* thread, Argument argument) {
305 Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
308 void inst_jump_if_false(Thread* thread, Argument argument) {
309 assert(!Stack_isEmpty(&(thread->stack)));
310 Object result = Stack_pop(&(thread->stack));
311 assert(result.type == BOOLEAN);
313 if(!(result.value.boolean)) {
314 inst_jump(thread, argument);
318 void inst_list(Thread* thread, Argument argument) {
321 result.value.list = NULL;
323 while(argument.integer > 0) {
324 assert(!Stack_isEmpty(&(thread->stack)));
325 Object item = Stack_pop(&(thread->stack));
327 List* node = malloc(sizeof(List));
329 node->tail = result.value.list;
331 result.value.list = node;
334 Stack_push(&(thread->stack), result);
337 {% with name='lt', operation='<' %}
338 {% include "comparison_instruction.c" %}
341 {% with name='lte', operation='<=' %}
342 {% include "comparison_instruction.c" %}
345 {% with name='mod', operation='%' %}
346 {% include "arithmetic_instruction.c" %}
349 {% with name='mul', operation='*' %}
350 {% include "arithmetic_instruction.c" %}
353 {% with name='neq', operation='!=' %}
354 {% include "comparison_instruction.c" %}
357 void inst_neg(Thread* thread, Argument argument) {
358 assert(!Stack_isEmpty(&(thread->stack)));
359 Object result = Stack_pop(&(thread->stack));
360 assert(result.type == INTEGER);
362 result.value.integer = -(result.value.integer);
364 Stack_push(&(thread->stack), result);
367 void inst_pop(Thread* thread, Argument argument) {
368 char* argumentString = argument.string;
370 assert(!Stack_isEmpty(&(thread->stack)));
371 Object result = Stack_pop(&(thread->stack));
373 if(strcmp(argumentString, "print") == 0) {
375 } else if(strcmp(argumentString, "pow") == 0) {
380 Environment_set(Thread_getEnvironment(thread), argumentString, result);
383 void inst_push(Thread* thread, Argument argument) {
384 char* argumentString = argument.string;
386 if(strcmp(argumentString, "false") == 0) {
387 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
388 }else if(strcmp(argumentString, "pow") == 0) {
390 result.type = BUILTIN;
391 result.value.builtin = POW;
392 Stack_push(&(thread->stack), result);
393 } else if(strcmp(argumentString, "print") == 0) {
395 result.type = BUILTIN;
396 result.value.builtin = PRINT;
397 Stack_push(&(thread->stack), result);
398 } else if(strcmp(argumentString, "true") == 0) {
399 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
401 Environment_get_Result result = Environment_get(
402 Thread_getEnvironment(thread),
406 fprintf(stderr, "Variable `%s` not found", argumentString);
409 Stack_push(&(thread->stack), result.result);
413 void inst_push_integer(Thread* thread, Argument argument) {
415 result.type = INTEGER;
416 result.value.integer = argument.integer;
418 Stack_push(&(thread->stack), result);
421 void inst_push_string(Thread* thread, Argument argument) {
423 result.type = STRING;
424 result.value.string = argument.string;
426 Stack_push(&(thread->stack), result);
429 void inst_push_symbol(Thread* thread, Argument argument) {
430 // TODO Store symbols in a symbol table so they can be looked up by reference
431 // without string comparison
433 result.type = SYMBOL;
434 result.value.symbol = argument.symbol;
437 {% with name='sub', operation='-' %}
438 {% include "arithmetic_instruction.c" %}
441 void inst_return(Thread* thread, Argument argument) {
442 Frame* returnFrame = thread->frame.returnFrame;
444 Frame_deinitialize(&(thread->frame));
448 returnFrame->environment,
449 returnFrame->returnFrame,
450 returnFrame->programCounter
456 void inst_structure(Thread* thread, Argument argument) {
461 typedef const struct Instruction Instruction;
463 void (*instruction)(Thread*,Argument);
467 {% for label in labels_to_instruction_indices.keys() %}
468 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
471 const Instruction program[] = {
472 {% for instruction in instruction_list %}
473 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
479 Thread_initialize(&thread, LABEL___main__);
481 for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
482 program[Thread_getProgramCounter(&thread)].instruction(
484 program[Thread_getProgramCounter(&thread)].argument
488 Thread_deinitialize(&thread);