919fb8300ba288dfebfc990a80b9cb9e0a1f5c83
[fur] / templates / program2.c
1 #include<assert.h>
2 #include<stdbool.h>
3 #include<stdint.h>
4 #include<stdio.h>
5 #include<stdlib.h>
6 #include<string.h>
7
8 enum Type;
9 typedef enum Type Type;
10 enum Type {
11   BOOLEAN,
12   BUILTIN,
13   CLOSURE,
14   INTEGER,
15   STRING
16 };
17
18 enum Builtin;
19 typedef enum Builtin Builtin;
20 enum Builtin {
21   NIL,
22   POW,
23   PRINT
24 };
25
26 struct Environment;
27 typedef struct Environment Environment;
28
29 struct Closure;
30 typedef struct Closure Closure;
31 struct Closure {
32   Environment* environment;
33   size_t entry;
34 };
35
36 union Value;
37 typedef union Value Value;
38 union Value {
39   Builtin builtin;
40   Closure closure;
41   bool boolean;
42   char* string;
43   int32_t integer;
44 };
45
46 struct Object;
47 typedef struct Object Object;
48 struct Object {
49   Type type;
50   Value value;
51 };
52
53 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
54
55 void Object_deinitialize(Object* self) {
56 }
57
58 {% include "environment.c" %}
59 {% include "stack.c" %}
60
61 struct Thread;
62 typedef struct Thread Thread;
63 struct Thread {
64   Environment* environment;
65   Stack stack;
66   size_t program_counter;
67 };
68
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;
73 }
74
75 void Thread_deinitialize(Thread* self) {
76   Environment_destruct(self->environment);
77   Stack_deinitialize(&(self->stack));
78 }
79
80 union Argument;
81 typedef const union Argument Argument;
82 union Argument {
83   size_t label;
84   void* pointer;
85   char* string;
86   int32_t integer;
87 };
88
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);
95
96   assert(!Stack_isEmpty(&(thread->stack)));
97   Object base = Stack_pop(&(thread->stack));
98   assert(base.type == INTEGER);
99
100   Object result;
101   result.type = INTEGER;
102   result.value.integer = 1;
103
104   while(exponent.value.integer > 0) {
105     result.value.integer *= base.value.integer;
106     exponent.value.integer--;
107   }
108
109   Stack_push(&(thread->stack), result);
110 }
111
112 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
113   assert(argumentCount > 0);
114
115   Object arguments[argumentCount];
116   size_t count;
117
118   for(count = 0; count < argumentCount; count++) {
119     assert(!Stack_isEmpty(&(thread->stack)));
120     arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
121   }
122
123   for(count = 0; count < argumentCount; count ++) {
124     Object arg = arguments[count];
125
126     switch(arg.type) {
127       case BOOLEAN:
128         if(arg.value.boolean) printf("true");
129         else printf("false");
130         break;
131
132       case INTEGER:
133         printf("%i", arg.value.integer);
134         break;
135
136       case STRING:
137         printf("%s", arg.value.string);
138         break;
139
140       default:
141         assert(0);
142     }
143   }
144
145   Stack_push(&(thread->stack), BUILTIN_NIL);
146 }
147
148 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
149   switch(b) {
150     case POW:
151       callBuiltinPow(thread, argumentCount);
152       break;
153     case PRINT:
154       callBuiltinPrint(thread, argumentCount);
155       break;
156
157     default:
158       assert(false);
159   }
160 }
161
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;
166
167   switch(f.type) {
168     case BUILTIN:
169       callBuiltin(thread, f.value.builtin, argumentCount);
170       break;
171
172     case CLOSURE:
173       {
174         assert(false);
175       }
176       break;
177
178     default:
179       assert(false);
180   }
181 }
182
183 {% with name='add', operation='+' %}
184   {% include "arithmetic_instruction.c" %}
185 {% endwith %}
186
187 void inst_close(Thread* thread, Argument argument) {
188   assert(false);
189 }
190
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);
195 }
196
197 void inst_end(struct Thread* thread, Argument argument) {
198 }
199
200 {% with name='eq', operation='==' %}
201   {% include "comparison_instruction.c" %}
202 {% endwith %}
203
204 {% with name='gt', operation='>' %}
205   {% include "comparison_instruction.c" %}
206 {% endwith %}
207
208 {% with name='gte', operation='>=' %}
209   {% include "comparison_instruction.c" %}
210 {% endwith %}
211
212 {% with name='idiv', operation='/' %}
213   {% include "arithmetic_instruction.c" %}
214 {% endwith %}
215
216 void inst_jump(Thread* thread, Argument argument) {
217   thread->program_counter = argument.label - 1; // We will increment before running
218 }
219
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);
224
225   if(!(result.value.boolean)) {
226     inst_jump(thread, argument);
227   }
228 }
229
230 {% with name='lt', operation='<' %}
231   {% include "comparison_instruction.c" %}
232 {% endwith %}
233
234 {% with name='lte', operation='<=' %}
235   {% include "comparison_instruction.c" %}
236 {% endwith %}
237
238 {% with name='mod', operation='%' %}
239   {% include "arithmetic_instruction.c" %}
240 {% endwith %}
241
242 {% with name='mul', operation='*' %}
243   {% include "arithmetic_instruction.c" %}
244 {% endwith %}
245
246 {% with name='neq', operation='!=' %}
247   {% include "comparison_instruction.c" %}
248 {% endwith %}
249
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);
254
255   result.value.integer = -(result.value.integer);
256
257   Stack_push(&(thread->stack), result);
258 }
259
260 void inst_pop(struct Thread* thread, Argument argument) {
261   char* argumentString = argument.string;
262
263   assert(!Stack_isEmpty(&(thread->stack)));
264   Object result = Stack_pop(&(thread->stack));
265
266   if(strcmp(argumentString, "print") == 0) {
267     assert(false);
268   } else if(strcmp(argumentString, "pow") == 0) {
269     assert(false);
270   }
271
272
273   Environment_set(thread->environment, argumentString, result);
274 }
275
276 void inst_push(struct Thread* thread, Argument argument) {
277   char* argumentString = argument.string;
278
279   if(strcmp(argumentString, "false") == 0) {
280     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
281   }else if(strcmp(argumentString, "pow") == 0) {
282     Object result;
283     result.type = BUILTIN;
284     result.value.builtin = POW;
285     Stack_push(&(thread->stack), result);
286   } else if(strcmp(argumentString, "print") == 0) {
287     Object result;
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 });
293   } else {
294     Environment_get_Result result = Environment_get(thread->environment, argumentString);
295     if(!result.found) {
296       fprintf(stderr, "Variable `%s` not found", argumentString);
297       assert(false);
298     }
299     Stack_push(&(thread->stack), result.result);
300   }
301 }
302
303 void inst_push_integer(Thread* thread, Argument argument) {
304   Object result;
305   result.type = INTEGER;
306   result.value.integer = argument.integer;
307
308   Stack_push(&(thread->stack), result);
309 }
310
311 void inst_push_string(Thread* thread, Argument argument) {
312   Object result;
313   result.type = STRING;
314   result.value.string = argument.string;
315
316   Stack_push(&(thread->stack), result);
317 }
318
319 {% with name='sub', operation='-' %}
320   {% include "arithmetic_instruction.c" %}
321 {% endwith %}
322
323 void inst_return(Thread* thread, Argument argument) {
324   assert(false);
325 }
326
327 struct Instruction;
328 typedef const struct Instruction Instruction;
329 struct Instruction {
330   void (*instruction)(struct Thread*,Argument);
331   Argument argument;
332 };
333
334 {% for label in labels_to_instruction_indices.keys() %}
335 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
336 {% endfor %}
337
338 const Instruction program[] = {
339 {% for instruction in instruction_list %}
340   (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
341 {% endfor %}
342 };
343
344 int main() {
345   Thread thread;
346   Thread_initialize(&thread, LABEL___main__);
347
348   for(; program[thread.program_counter].instruction != inst_end; thread.program_counter++) {
349     program[thread.program_counter].instruction(
350       &thread,
351       program[thread.program_counter].argument
352     );
353   }
354
355   Thread_deinitialize(&thread);
356
357   return 0;
358 }