9 typedef enum Type Type;
19 typedef enum Builtin Builtin;
27 typedef struct Environment Environment;
30 typedef struct Closure Closure;
32 Environment* environment;
37 typedef union Value Value;
47 typedef struct Object Object;
53 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
55 void Object_deinitialize(Object* self) {
58 {% include "environment.c" %}
59 {% include "stack.c" %}
60 {% include "frame.c" %}
63 typedef struct Thread Thread;
65 Environment* environment;
67 size_t programCounter;
70 void Thread_initialize(Thread* self, size_t programCounter) {
71 self->environment = Environment_construct();
72 Stack_initialize(&(self->stack));
73 self->programCounter = programCounter;
76 void Thread_deinitialize(Thread* self) {
77 Environment_destruct(self->environment);
78 Stack_deinitialize(&(self->stack));
81 Environment* Thread_getEnvironment(Thread* self) {
82 return self->environment;
85 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
86 self->programCounter = programCounter;
89 void Thread_incrementProgramCounter(Thread* self) {
90 self->programCounter++;
93 size_t Thread_getProgramCounter(Thread* self) {
94 return self->programCounter;
98 typedef const union Argument Argument;
106 void callBuiltinPow(Thread* thread, size_t argumentCount) {
107 assert(argumentCount == 2);
108 assert(!Stack_isEmpty(&(thread->stack)));
109 Object exponent = Stack_pop(&(thread->stack));
110 assert(exponent.type == INTEGER);
111 assert(exponent.value.integer >= 0);
113 assert(!Stack_isEmpty(&(thread->stack)));
114 Object base = Stack_pop(&(thread->stack));
115 assert(base.type == INTEGER);
118 result.type = INTEGER;
119 result.value.integer = 1;
121 while(exponent.value.integer > 0) {
122 result.value.integer *= base.value.integer;
123 exponent.value.integer--;
126 Stack_push(&(thread->stack), result);
129 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
130 assert(argumentCount > 0);
132 Object arguments[argumentCount];
135 for(count = 0; count < argumentCount; count++) {
136 assert(!Stack_isEmpty(&(thread->stack)));
137 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
140 for(count = 0; count < argumentCount; count ++) {
141 Object arg = arguments[count];
145 if(arg.value.boolean) printf("true");
146 else printf("false");
150 printf("%i", arg.value.integer);
154 printf("%s", arg.value.string);
162 Stack_push(&(thread->stack), BUILTIN_NIL);
165 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
168 callBuiltinPow(thread, argumentCount);
171 callBuiltinPrint(thread, argumentCount);
179 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
180 assert(argumentCount == 0);
185 void inst_call(Thread* thread, Argument argument) {
186 assert(!Stack_isEmpty(&(thread->stack)));
187 Object f = Stack_pop(&(thread->stack));
188 size_t argumentCount = argument.label;
192 callBuiltin(thread, f.value.builtin, argumentCount);
196 callClosure(thread, f.value.closure, argumentCount);
204 {% with name='add', operation='+' %}
205 {% include "arithmetic_instruction.c" %}
208 void inst_close(Thread* thread, Argument argument) {
210 result.type = CLOSURE;
211 result.value.closure.environment = Thread_getEnvironment(thread);
212 result.value.closure.entry = argument.label;
214 Stack_push(&(thread->stack), result);
217 void inst_drop(Thread* thread, Argument argument) {
218 assert(!Stack_isEmpty(&(thread->stack)));
219 Object result = Stack_pop(&(thread->stack));
220 Object_deinitialize(&result);
223 void inst_end(Thread* thread, Argument argument) {
226 {% with name='eq', operation='==' %}
227 {% include "comparison_instruction.c" %}
230 {% with name='gt', operation='>' %}
231 {% include "comparison_instruction.c" %}
234 {% with name='gte', operation='>=' %}
235 {% include "comparison_instruction.c" %}
238 {% with name='idiv', operation='/' %}
239 {% include "arithmetic_instruction.c" %}
242 void inst_jump(Thread* thread, Argument argument) {
243 Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
246 void inst_jump_if_false(Thread* thread, Argument argument) {
247 assert(!Stack_isEmpty(&(thread->stack)));
248 Object result = Stack_pop(&(thread->stack));
249 assert(result.type == BOOLEAN);
251 if(!(result.value.boolean)) {
252 inst_jump(thread, argument);
256 {% with name='lt', operation='<' %}
257 {% include "comparison_instruction.c" %}
260 {% with name='lte', operation='<=' %}
261 {% include "comparison_instruction.c" %}
264 {% with name='mod', operation='%' %}
265 {% include "arithmetic_instruction.c" %}
268 {% with name='mul', operation='*' %}
269 {% include "arithmetic_instruction.c" %}
272 {% with name='neq', operation='!=' %}
273 {% include "comparison_instruction.c" %}
276 void inst_neg(Thread* thread, Argument argument) {
277 assert(!Stack_isEmpty(&(thread->stack)));
278 Object result = Stack_pop(&(thread->stack));
279 assert(result.type == INTEGER);
281 result.value.integer = -(result.value.integer);
283 Stack_push(&(thread->stack), result);
286 void inst_pop(Thread* thread, Argument argument) {
287 char* argumentString = argument.string;
289 assert(!Stack_isEmpty(&(thread->stack)));
290 Object result = Stack_pop(&(thread->stack));
292 if(strcmp(argumentString, "print") == 0) {
294 } else if(strcmp(argumentString, "pow") == 0) {
299 Environment_set(Thread_getEnvironment(thread), argumentString, result);
302 void inst_push(Thread* thread, Argument argument) {
303 char* argumentString = argument.string;
305 if(strcmp(argumentString, "false") == 0) {
306 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
307 }else if(strcmp(argumentString, "pow") == 0) {
309 result.type = BUILTIN;
310 result.value.builtin = POW;
311 Stack_push(&(thread->stack), result);
312 } else if(strcmp(argumentString, "print") == 0) {
314 result.type = BUILTIN;
315 result.value.builtin = PRINT;
316 Stack_push(&(thread->stack), result);
317 } else if(strcmp(argumentString, "true") == 0) {
318 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
320 Environment_get_Result result = Environment_get(
321 Thread_getEnvironment(thread),
325 fprintf(stderr, "Variable `%s` not found", argumentString);
328 Stack_push(&(thread->stack), result.result);
332 void inst_push_integer(Thread* thread, Argument argument) {
334 result.type = INTEGER;
335 result.value.integer = argument.integer;
337 Stack_push(&(thread->stack), result);
340 void inst_push_string(Thread* thread, Argument argument) {
342 result.type = STRING;
343 result.value.string = argument.string;
345 Stack_push(&(thread->stack), result);
348 {% with name='sub', operation='-' %}
349 {% include "arithmetic_instruction.c" %}
352 void inst_return(Thread* thread, Argument argument) {
357 typedef const struct Instruction Instruction;
359 void (*instruction)(Thread*,Argument);
363 {% for label in labels_to_instruction_indices.keys() %}
364 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
367 const Instruction program[] = {
368 {% for instruction in instruction_list %}
369 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
375 Thread_initialize(&thread, LABEL___main__);
377 for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
378 program[Thread_getProgramCounter(&thread)].instruction(
380 program[Thread_getProgramCounter(&thread)].argument
384 Thread_deinitialize(&thread);