9 typedef enum Type Type;
19 typedef enum Builtin Builtin;
27 typedef struct Object Object;
29 typedef struct Environment Environment;
31 typedef struct Thread Thread;
34 typedef struct Closure Closure;
36 Environment* environment;
41 typedef union Value Value;
55 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
57 void Object_deinitialize(Object* self) {
60 {% include "environment.c" %}
61 {% include "stack.c" %}
62 {% include "frame.c" %}
69 void Thread_initialize(Thread* self, size_t programCounter) {
70 Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
71 Stack_initialize(&(self->stack));
74 void Thread_deinitialize(Thread* self) {
75 Frame_deinitialize(&(self->frame));
76 Stack_deinitialize(&(self->stack));
79 Environment* Thread_getEnvironment(Thread* self) {
80 return self->frame.environment;
83 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
84 self->frame.programCounter = programCounter;
87 void Thread_incrementProgramCounter(Thread* self) {
88 self->frame.programCounter++;
91 size_t Thread_getProgramCounter(Thread* self) {
92 return self->frame.programCounter;
96 typedef const union Argument Argument;
104 void callBuiltinPow(Thread* thread, size_t argumentCount) {
105 assert(argumentCount == 2);
106 assert(!Stack_isEmpty(&(thread->stack)));
107 Object exponent = Stack_pop(&(thread->stack));
108 assert(exponent.type == INTEGER);
109 assert(exponent.value.integer >= 0);
111 assert(!Stack_isEmpty(&(thread->stack)));
112 Object base = Stack_pop(&(thread->stack));
113 assert(base.type == INTEGER);
116 result.type = INTEGER;
117 result.value.integer = 1;
119 while(exponent.value.integer > 0) {
120 result.value.integer *= base.value.integer;
121 exponent.value.integer--;
124 Stack_push(&(thread->stack), result);
127 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
128 assert(argumentCount > 0);
130 Object arguments[argumentCount];
133 for(count = 0; count < argumentCount; count++) {
134 assert(!Stack_isEmpty(&(thread->stack)));
135 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
138 for(count = 0; count < argumentCount; count ++) {
139 Object arg = arguments[count];
143 if(arg.value.boolean) printf("true");
144 else printf("false");
148 printf("%i", arg.value.integer);
152 printf("%s", arg.value.string);
160 Stack_push(&(thread->stack), BUILTIN_NIL);
163 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
166 callBuiltinPow(thread, argumentCount);
169 callBuiltinPrint(thread, argumentCount);
177 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
178 assert(argumentCount == 0);
180 Frame* returnFrame = malloc(sizeof(Frame));
181 *returnFrame = thread->frame;
184 Environment_construct(Environment_reference(closure.environment)),
186 closure.entry - 1 // We will increment the frame immediately after this
190 void inst_call(Thread* thread, Argument argument) {
191 assert(!Stack_isEmpty(&(thread->stack)));
192 Object f = Stack_pop(&(thread->stack));
193 size_t argumentCount = argument.label;
197 callBuiltin(thread, f.value.builtin, argumentCount);
201 callClosure(thread, f.value.closure, argumentCount);
209 {% with name='add', operation='+' %}
210 {% include "arithmetic_instruction.c" %}
213 void inst_close(Thread* thread, Argument argument) {
215 result.type = CLOSURE;
216 result.value.closure.environment = Thread_getEnvironment(thread);
217 result.value.closure.entry = argument.label;
219 Stack_push(&(thread->stack), result);
222 void inst_drop(Thread* thread, Argument argument) {
223 assert(!Stack_isEmpty(&(thread->stack)));
224 Object result = Stack_pop(&(thread->stack));
225 Object_deinitialize(&result);
228 void inst_end(Thread* thread, Argument argument) {
231 {% with name='eq', operation='==' %}
232 {% include "comparison_instruction.c" %}
235 {% with name='gt', operation='>' %}
236 {% include "comparison_instruction.c" %}
239 {% with name='gte', operation='>=' %}
240 {% include "comparison_instruction.c" %}
243 {% with name='idiv', operation='/' %}
244 {% include "arithmetic_instruction.c" %}
247 void inst_jump(Thread* thread, Argument argument) {
248 Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
251 void inst_jump_if_false(Thread* thread, Argument argument) {
252 assert(!Stack_isEmpty(&(thread->stack)));
253 Object result = Stack_pop(&(thread->stack));
254 assert(result.type == BOOLEAN);
256 if(!(result.value.boolean)) {
257 inst_jump(thread, argument);
261 {% with name='lt', operation='<' %}
262 {% include "comparison_instruction.c" %}
265 {% with name='lte', operation='<=' %}
266 {% include "comparison_instruction.c" %}
269 {% with name='mod', operation='%' %}
270 {% include "arithmetic_instruction.c" %}
273 {% with name='mul', operation='*' %}
274 {% include "arithmetic_instruction.c" %}
277 {% with name='neq', operation='!=' %}
278 {% include "comparison_instruction.c" %}
281 void inst_neg(Thread* thread, Argument argument) {
282 assert(!Stack_isEmpty(&(thread->stack)));
283 Object result = Stack_pop(&(thread->stack));
284 assert(result.type == INTEGER);
286 result.value.integer = -(result.value.integer);
288 Stack_push(&(thread->stack), result);
291 void inst_pop(Thread* thread, Argument argument) {
292 char* argumentString = argument.string;
294 assert(!Stack_isEmpty(&(thread->stack)));
295 Object result = Stack_pop(&(thread->stack));
297 if(strcmp(argumentString, "print") == 0) {
299 } else if(strcmp(argumentString, "pow") == 0) {
304 Environment_set(Thread_getEnvironment(thread), argumentString, result);
307 void inst_push(Thread* thread, Argument argument) {
308 char* argumentString = argument.string;
310 if(strcmp(argumentString, "false") == 0) {
311 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
312 }else if(strcmp(argumentString, "pow") == 0) {
314 result.type = BUILTIN;
315 result.value.builtin = POW;
316 Stack_push(&(thread->stack), result);
317 } else if(strcmp(argumentString, "print") == 0) {
319 result.type = BUILTIN;
320 result.value.builtin = PRINT;
321 Stack_push(&(thread->stack), result);
322 } else if(strcmp(argumentString, "true") == 0) {
323 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
325 Environment_get_Result result = Environment_get(
326 Thread_getEnvironment(thread),
330 fprintf(stderr, "Variable `%s` not found", argumentString);
333 Stack_push(&(thread->stack), result.result);
337 void inst_push_integer(Thread* thread, Argument argument) {
339 result.type = INTEGER;
340 result.value.integer = argument.integer;
342 Stack_push(&(thread->stack), result);
345 void inst_push_string(Thread* thread, Argument argument) {
347 result.type = STRING;
348 result.value.string = argument.string;
350 Stack_push(&(thread->stack), result);
353 {% with name='sub', operation='-' %}
354 {% include "arithmetic_instruction.c" %}
357 void inst_return(Thread* thread, Argument argument) {
358 Frame* returnFrame = thread->frame.returnFrame;
360 Frame_deinitialize(&(thread->frame));
364 returnFrame->environment,
365 returnFrame->returnFrame,
366 returnFrame->programCounter
373 typedef const struct Instruction Instruction;
375 void (*instruction)(Thread*,Argument);
379 {% for label in labels_to_instruction_indices.keys() %}
380 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
383 const Instruction program[] = {
384 {% for instruction in instruction_list %}
385 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
391 Thread_initialize(&thread, LABEL___main__);
393 for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
394 program[Thread_getProgramCounter(&thread)].instruction(
396 program[Thread_getProgramCounter(&thread)].argument
400 Thread_deinitialize(&thread);