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 // TODO Handle multiple arguments
112 assert(!Stack_isEmpty(&(thread->stack)));
113 Object arg = Stack_pop(&(thread->stack));
117 if(arg.value.boolean) printf("true");
118 else printf("false");
122 printf("%i", arg.value.integer);
126 printf("%s", arg.value.string);
133 Stack_push(&(thread->stack), BUILTIN_NIL);
147 {% with name='add', operation='+' %}
148 {% include "arithmetic_instruction.c" %}
152 void drop(struct Thread* thread, Argument argument) {
153 assert(!Stack_isEmpty(&(thread->stack)));
154 Object result = Stack_pop(&(thread->stack));
155 Object_deinitialize(&result);
158 void end(struct Thread* thread, Argument argument) {
161 {% with name='eq', operation='==' %}
162 {% include "comparison_instruction.c" %}
165 {% with name='gt', operation='>' %}
166 {% include "comparison_instruction.c" %}
169 {% with name='gte', operation='>=' %}
170 {% include "comparison_instruction.c" %}
173 {% with name='idiv', operation='/' %}
174 {% include "arithmetic_instruction.c" %}
177 void jump(Thread* thread, Argument argument) {
178 thread->program_counter = argument.label - 1; // We will increment before running
181 void jump_if_false(Thread* thread, Argument argument) {
182 assert(!Stack_isEmpty(&(thread->stack)));
183 Object result = Stack_pop(&(thread->stack));
184 assert(result.type == BOOLEAN);
186 if(!(result.value.boolean)) {
187 jump(thread, argument);
191 {% with name='lt', operation='<' %}
192 {% include "comparison_instruction.c" %}
195 {% with name='lte', operation='<=' %}
196 {% include "comparison_instruction.c" %}
199 {% with name='mod', operation='%' %}
200 {% include "arithmetic_instruction.c" %}
203 {% with name='mul', operation='*' %}
204 {% include "arithmetic_instruction.c" %}
207 {% with name='neq', operation='!=' %}
208 {% include "comparison_instruction.c" %}
211 void neg(Thread* thread, Argument argument) {
212 assert(!Stack_isEmpty(&(thread->stack)));
213 Object result = Stack_pop(&(thread->stack));
214 assert(result.type == INTEGER);
216 result.value.integer = -(result.value.integer);
218 Stack_push(&(thread->stack), result);
221 void pop(struct Thread* thread, Argument argument) {
222 char* argumentString = argument.string;
224 assert(!Stack_isEmpty(&(thread->stack)));
225 Object result = Stack_pop(&(thread->stack));
227 if(strcmp(argumentString, "print") == 0) {
229 } else if(strcmp(argumentString, "pow") == 0) {
234 Environment_set(thread->environment, argumentString, result);
237 void push(struct Thread* thread, Argument argument) {
238 char* argumentString = argument.string;
240 if(strcmp(argumentString, "false") == 0) {
241 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
242 }else if(strcmp(argumentString, "pow") == 0) {
244 result.type = BUILTIN;
245 result.value.builtin = POW;
246 Stack_push(&(thread->stack), result);
247 } else if(strcmp(argumentString, "print") == 0) {
249 result.type = BUILTIN;
250 result.value.builtin = PRINT;
251 Stack_push(&(thread->stack), result);
252 } else if(strcmp(argumentString, "true") == 0) {
253 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
255 Environment_get_Result result = Environment_get(thread->environment, argumentString);
257 fprintf(stderr, "Variable `%s` not found", argumentString);
260 Stack_push(&(thread->stack), result.result);
264 void push_integer(struct Thread* thread, Argument argument) {
266 result.type = INTEGER;
267 result.value.integer = argument.integer;
269 Stack_push(&(thread->stack), result);
272 void push_string(struct Thread* thread, Argument argument) {
274 result.type = STRING;
275 result.value.string = argument.string;
277 Stack_push(&(thread->stack), result);
280 {% with name='sub', operation='-' %}
281 {% include "arithmetic_instruction.c" %}
285 typedef const struct Instruction Instruction;
287 void (*instruction)(struct Thread*,Argument);
291 {% for label in labels_to_instruction_indices.keys() %}
292 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
295 const Instruction program[] = {
296 {% for instruction in instruction_list %}
297 (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
303 Thread_initialize(&thread, LABEL___main__);
305 for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
306 program[thread.program_counter].instruction(
308 program[thread.program_counter].argument
312 Thread_deinitialize(&thread);