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" %}
62 typedef struct Thread Thread;
64 Environment* environment;
66 size_t program_counter;
69 void Thread_initialize(Thread* self, size_t program_counter) {
70 self->environment = Environment_construct();
71 Stack_initialize(&(self->stack));
72 self->program_counter = program_counter;
75 void Thread_deinitialize(Thread* self) {
76 Environment_destruct(self->environment);
77 Stack_deinitialize(&(self->stack));
81 typedef const union Argument Argument;
89 void callBuiltinPow(Thread* thread, size_t argumentCount) {
90 assert(argumentCount == 2);
91 assert(!Stack_isEmpty(&(thread->stack)));
92 Object exponent = Stack_pop(&(thread->stack));
93 assert(exponent.type == INTEGER);
94 assert(exponent.value.integer >= 0);
96 assert(!Stack_isEmpty(&(thread->stack)));
97 Object base = Stack_pop(&(thread->stack));
98 assert(base.type == INTEGER);
101 result.type = INTEGER;
102 result.value.integer = 1;
104 while(exponent.value.integer > 0) {
105 result.value.integer *= base.value.integer;
106 exponent.value.integer--;
109 Stack_push(&(thread->stack), result);
112 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
113 assert(argumentCount > 0);
115 Object arguments[argumentCount];
118 for(count = 0; count < argumentCount; count++) {
119 assert(!Stack_isEmpty(&(thread->stack)));
120 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
123 for(count = 0; count < argumentCount; count ++) {
124 Object arg = arguments[count];
128 if(arg.value.boolean) printf("true");
129 else printf("false");
133 printf("%i", arg.value.integer);
137 printf("%s", arg.value.string);
145 Stack_push(&(thread->stack), BUILTIN_NIL);
148 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
151 callBuiltinPow(thread, argumentCount);
154 callBuiltinPrint(thread, argumentCount);
162 void inst_call(struct Thread* thread, Argument argument) {
163 assert(!Stack_isEmpty(&(thread->stack)));
164 Object f = Stack_pop(&(thread->stack));
165 size_t argumentCount = argument.label;
169 callBuiltin(thread, f.value.builtin, argumentCount);
183 {% with name='add', operation='+' %}
184 {% include "arithmetic_instruction.c" %}
187 void inst_close(Thread* thread, Argument argument) {
191 void inst_drop(Thread* thread, Argument argument) {
192 assert(!Stack_isEmpty(&(thread->stack)));
193 Object result = Stack_pop(&(thread->stack));
194 Object_deinitialize(&result);
197 void inst_end(struct Thread* thread, Argument argument) {
200 {% with name='eq', operation='==' %}
201 {% include "comparison_instruction.c" %}
204 {% with name='gt', operation='>' %}
205 {% include "comparison_instruction.c" %}
208 {% with name='gte', operation='>=' %}
209 {% include "comparison_instruction.c" %}
212 {% with name='idiv', operation='/' %}
213 {% include "arithmetic_instruction.c" %}
216 void inst_jump(Thread* thread, Argument argument) {
217 thread->program_counter = argument.label - 1; // We will increment before running
220 void inst_jump_if_false(Thread* thread, Argument argument) {
221 assert(!Stack_isEmpty(&(thread->stack)));
222 Object result = Stack_pop(&(thread->stack));
223 assert(result.type == BOOLEAN);
225 if(!(result.value.boolean)) {
226 inst_jump(thread, argument);
230 {% with name='lt', operation='<' %}
231 {% include "comparison_instruction.c" %}
234 {% with name='lte', operation='<=' %}
235 {% include "comparison_instruction.c" %}
238 {% with name='mod', operation='%' %}
239 {% include "arithmetic_instruction.c" %}
242 {% with name='mul', operation='*' %}
243 {% include "arithmetic_instruction.c" %}
246 {% with name='neq', operation='!=' %}
247 {% include "comparison_instruction.c" %}
250 void inst_neg(Thread* thread, Argument argument) {
251 assert(!Stack_isEmpty(&(thread->stack)));
252 Object result = Stack_pop(&(thread->stack));
253 assert(result.type == INTEGER);
255 result.value.integer = -(result.value.integer);
257 Stack_push(&(thread->stack), result);
260 void inst_pop(struct Thread* thread, Argument argument) {
261 char* argumentString = argument.string;
263 assert(!Stack_isEmpty(&(thread->stack)));
264 Object result = Stack_pop(&(thread->stack));
266 if(strcmp(argumentString, "print") == 0) {
268 } else if(strcmp(argumentString, "pow") == 0) {
273 Environment_set(thread->environment, argumentString, result);
276 void inst_push(struct Thread* thread, Argument argument) {
277 char* argumentString = argument.string;
279 if(strcmp(argumentString, "false") == 0) {
280 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
281 }else if(strcmp(argumentString, "pow") == 0) {
283 result.type = BUILTIN;
284 result.value.builtin = POW;
285 Stack_push(&(thread->stack), result);
286 } else if(strcmp(argumentString, "print") == 0) {
288 result.type = BUILTIN;
289 result.value.builtin = PRINT;
290 Stack_push(&(thread->stack), result);
291 } else if(strcmp(argumentString, "true") == 0) {
292 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
294 Environment_get_Result result = Environment_get(thread->environment, argumentString);
296 fprintf(stderr, "Variable `%s` not found", argumentString);
299 Stack_push(&(thread->stack), result.result);
303 void inst_push_integer(Thread* thread, Argument argument) {
305 result.type = INTEGER;
306 result.value.integer = argument.integer;
308 Stack_push(&(thread->stack), result);
311 void inst_push_string(Thread* thread, Argument argument) {
313 result.type = STRING;
314 result.value.string = argument.string;
316 Stack_push(&(thread->stack), result);
319 {% with name='sub', operation='-' %}
320 {% include "arithmetic_instruction.c" %}
323 void inst_return(Thread* thread, Argument argument) {
328 typedef const struct Instruction Instruction;
330 void (*instruction)(struct Thread*,Argument);
334 {% for label in labels_to_instruction_indices.keys() %}
335 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
338 const Instruction program[] = {
339 {% for instruction in instruction_list %}
340 (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
346 Thread_initialize(&thread, LABEL___main__);
348 for(; program[thread.program_counter].instruction != inst_end; thread.program_counter++) {
349 program[thread.program_counter].instruction(
351 program[thread.program_counter].argument
355 Thread_deinitialize(&thread);