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 {% with name='lt', operation='<' %}
178 {% include "comparison_instruction.c" %}
181 {% with name='lte', operation='<=' %}
182 {% include "comparison_instruction.c" %}
185 {% with name='mod', operation='%' %}
186 {% include "arithmetic_instruction.c" %}
189 {% with name='mul', operation='*' %}
190 {% include "arithmetic_instruction.c" %}
193 {% with name='neq', operation='!=' %}
194 {% include "comparison_instruction.c" %}
197 void neg(struct Thread* thread, Argument argument) {
198 assert(!Stack_isEmpty(&(thread->stack)));
199 Object result = Stack_pop(&(thread->stack));
200 assert(result.type == INTEGER);
202 result.value.integer = -(result.value.integer);
204 Stack_push(&(thread->stack), result);
207 void pop(struct Thread* thread, Argument argument) {
208 char* argumentString = argument.string;
210 assert(!Stack_isEmpty(&(thread->stack)));
211 Object result = Stack_pop(&(thread->stack));
213 if(strcmp(argumentString, "print") == 0) {
215 } else if(strcmp(argumentString, "pow") == 0) {
220 Environment_set(thread->environment, argumentString, result);
223 void push(struct Thread* thread, Argument argument) {
224 char* argumentString = argument.string;
226 if(strcmp(argumentString, "false") == 0) {
227 Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
228 }else if(strcmp(argumentString, "pow") == 0) {
230 result.type = BUILTIN;
231 result.value.builtin = POW;
232 Stack_push(&(thread->stack), result);
233 } else if(strcmp(argumentString, "print") == 0) {
235 result.type = BUILTIN;
236 result.value.builtin = PRINT;
237 Stack_push(&(thread->stack), result);
238 } else if(strcmp(argumentString, "true") == 0) {
239 Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
241 Environment_get_Result result = Environment_get(thread->environment, argumentString);
243 fprintf(stderr, "Variable `%s` not found", argumentString);
246 Stack_push(&(thread->stack), result.result);
250 void push_integer(struct Thread* thread, Argument argument) {
252 result.type = INTEGER;
253 result.value.integer = argument.integer;
255 Stack_push(&(thread->stack), result);
258 void push_string(struct Thread* thread, Argument argument) {
260 result.type = STRING;
261 result.value.string = argument.string;
263 Stack_push(&(thread->stack), result);
266 {% with name='sub', operation='-' %}
267 {% include "arithmetic_instruction.c" %}
271 typedef const struct Instruction Instruction;
273 void (*instruction)(struct Thread*,Argument);
277 {% for label in labels_to_instruction_indices.keys() %}
278 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
281 const Instruction program[] = {
282 {% for instruction in instruction_list %}
283 (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
289 Thread_initialize(&thread, 0);
291 for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
292 program[thread.program_counter].instruction(
294 program[thread.program_counter].argument
298 Thread_deinitialize(&thread);