9 typedef enum Type Type;
18 typedef enum Builtin Builtin;
26 typedef union Value Value;
35 typedef struct Object Object;
41 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
43 void Object_deinitialize(Object* self) {
46 {% include "environment.c" %}
47 {% include "stack.c" %}
50 typedef struct Thread Thread;
52 Environment* environment;
54 size_t program_counter;
57 void Thread_initialize(Thread* self, size_t program_counter) {
58 self->environment = Environment_construct();
59 Stack_initialize(&(self->stack));
60 self->program_counter = program_counter;
63 void Thread_deinitialize(Thread* self) {
64 Environment_destruct(self->environment);
65 Stack_deinitialize(&(self->stack));
69 typedef const union Argument Argument;
77 void call(struct Thread* thread, Argument argument) {
78 assert(!Stack_isEmpty(&(thread->stack)));
79 Object f = Stack_pop(&(thread->stack));
80 size_t argumentCount = argument.label;
84 switch(f.value.builtin) {
87 assert(argumentCount == 2);
88 assert(!Stack_isEmpty(&(thread->stack)));
89 Object exponent = Stack_pop(&(thread->stack));
90 assert(exponent.type == INTEGER);
91 assert(exponent.value.integer >= 0);
93 assert(!Stack_isEmpty(&(thread->stack)));
94 Object base = Stack_pop(&(thread->stack));
95 assert(base.type == INTEGER);
98 result.type = INTEGER;
99 result.value.integer = 1;
101 while(exponent.value.integer > 0) {
102 result.value.integer *= base.value.integer;
103 exponent.value.integer--;
106 Stack_push(&(thread->stack), result);
111 assert(argumentCount > 0);
113 Object arguments[argumentCount];
116 for(count = 0; count < argumentCount; count++) {
117 assert(!Stack_isEmpty(&(thread->stack)));
118 arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
121 for(count = 0; count < argumentCount; count ++) {
122 Object arg = arguments[count];
126 if(arg.value.boolean) printf("true");
127 else printf("false");
131 printf("%i", arg.value.integer);
135 printf("%s", arg.value.string);
143 Stack_push(&(thread->stack), BUILTIN_NIL);
157 {% with name='add', operation='+' %}
158 {% include "arithmetic_instruction.c" %}
162 void drop(struct Thread* thread, Argument argument) {
163 assert(!Stack_isEmpty(&(thread->stack)));
164 Object result = Stack_pop(&(thread->stack));
165 Object_deinitialize(&result);
168 void end(struct Thread* thread, Argument argument) {
171 {% with name='eq', operation='==' %}
172 {% include "comparison_instruction.c" %}
175 {% with name='gt', operation='>' %}
176 {% include "comparison_instruction.c" %}
179 {% with name='gte', operation='>=' %}
180 {% include "comparison_instruction.c" %}
183 {% with name='idiv', operation='/' %}
184 {% include "arithmetic_instruction.c" %}
187 void jump(Thread* thread, Argument argument) {
188 thread->program_counter = argument.label - 1; // We will increment before running
191 void jump_if_false(Thread* thread, Argument argument) {
192 assert(!Stack_isEmpty(&(thread->stack)));
193 Object result = Stack_pop(&(thread->stack));
194 assert(result.type == BOOLEAN);
196 if(!(result.value.boolean)) {
197 jump(thread, argument);
201 {% with name='lt', operation='<' %}
202 {% include "comparison_instruction.c" %}
205 {% with name='lte', operation='<=' %}
206 {% include "comparison_instruction.c" %}
209 {% with name='mod', operation='%' %}
210 {% include "arithmetic_instruction.c" %}
213 {% with name='mul', operation='*' %}
214 {% include "arithmetic_instruction.c" %}
217 {% with name='neq', operation='!=' %}
218 {% include "comparison_instruction.c" %}
221 void neg(Thread* thread, Argument argument) {
222 assert(!Stack_isEmpty(&(thread->stack)));
223 Object result = Stack_pop(&(thread->stack));
224 assert(result.type == INTEGER);
226 result.value.integer = -(result.value.integer);
228 Stack_push(&(thread->stack), result);
231 void pop(struct Thread* thread, Argument argument) {
232 char* argumentString = argument.string;
234 assert(!Stack_isEmpty(&(thread->stack)));
235 Object result = Stack_pop(&(thread->stack));
237 if(strcmp(argumentString, "print") == 0) {
239 } else if(strcmp(argumentString, "pow") == 0) {
244 Environment_set(thread->environment, argumentString, result);
247 void push(struct Thread* thread, Argument argument) {
248 char* argumentString = argument.string;
250 if(strcmp(argumentString, "false") == 0) {
251 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
252 }else if(strcmp(argumentString, "pow") == 0) {
254 result.type = BUILTIN;
255 result.value.builtin = POW;
256 Stack_push(&(thread->stack), result);
257 } else if(strcmp(argumentString, "print") == 0) {
259 result.type = BUILTIN;
260 result.value.builtin = PRINT;
261 Stack_push(&(thread->stack), result);
262 } else if(strcmp(argumentString, "true") == 0) {
263 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
265 Environment_get_Result result = Environment_get(thread->environment, argumentString);
267 fprintf(stderr, "Variable `%s` not found", argumentString);
270 Stack_push(&(thread->stack), result.result);
274 void push_integer(struct Thread* thread, Argument argument) {
276 result.type = INTEGER;
277 result.value.integer = argument.integer;
279 Stack_push(&(thread->stack), result);
282 void push_string(struct Thread* thread, Argument argument) {
284 result.type = STRING;
285 result.value.string = argument.string;
287 Stack_push(&(thread->stack), result);
290 {% with name='sub', operation='-' %}
291 {% include "arithmetic_instruction.c" %}
295 typedef const struct Instruction Instruction;
297 void (*instruction)(struct Thread*,Argument);
301 {% for label in labels_to_instruction_indices.keys() %}
302 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
305 const Instruction program[] = {
306 {% for instruction in instruction_list %}
307 (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
313 Thread_initialize(&thread, LABEL___main__);
315 for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
316 program[thread.program_counter].instruction(
318 program[thread.program_counter].argument
322 Thread_deinitialize(&thread);