89d80de7fbe1561096efb71fe51dc53b23b9c8b7
[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   INTEGER,
14   STRING
15 };
16
17 enum Builtin;
18 typedef enum Builtin Builtin;
19 enum Builtin {
20   NIL,
21   POW,
22   PRINT
23 };
24
25 union Value;
26 typedef union Value Value;
27 union Value {
28   Builtin builtin;
29   bool boolean;
30   char* string;
31   int32_t integer;
32 };
33
34 struct Object;
35 typedef struct Object Object;
36 struct Object {
37   Type type;
38   Value value;
39 };
40
41 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
42
43 void Object_deinitialize(Object* self) {
44 }
45
46 {% include "environment.c" %}
47 {% include "stack.c" %}
48
49 struct Thread;
50 typedef struct Thread Thread;
51 struct Thread {
52   Environment* environment;
53   Stack stack;
54   size_t program_counter;
55 };
56
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;
61 }
62
63 void Thread_deinitialize(Thread* self) {
64   Environment_destruct(self->environment);
65   Stack_deinitialize(&(self->stack));
66 }
67
68 union Argument;
69 typedef const union Argument Argument;
70 union Argument {
71   size_t label;
72   void* pointer;
73   char* string;
74   int32_t integer;
75 };
76
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;
81
82   switch(f.type) {
83     case BUILTIN:
84       switch(f.value.builtin) {
85         case POW:
86           {
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);
92
93             assert(!Stack_isEmpty(&(thread->stack)));
94             Object base = Stack_pop(&(thread->stack));
95             assert(base.type == INTEGER);
96
97             Object result;
98             result.type = INTEGER;
99             result.value.integer = 1;
100
101             while(exponent.value.integer > 0) {
102               result.value.integer *= base.value.integer;
103               exponent.value.integer--;
104             }
105
106             Stack_push(&(thread->stack), result);
107           }
108           break;
109         case PRINT:
110           {
111             assert(argumentCount > 0);
112
113             Object arguments[argumentCount];
114             size_t count;
115
116             for(count = 0; count < argumentCount; count++) {
117               assert(!Stack_isEmpty(&(thread->stack)));
118               arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
119             }
120
121             for(count = 0; count < argumentCount; count ++) {
122               Object arg = arguments[count];
123
124               switch(arg.type) {
125                 case BOOLEAN:
126                   if(arg.value.boolean) printf("true");
127                   else printf("false");
128                   break;
129
130                 case INTEGER:
131                   printf("%i", arg.value.integer);
132                   break;
133
134                 case STRING:
135                   printf("%s", arg.value.string);
136                   break;
137
138                 default:
139                   assert(0);
140               }
141             }
142
143             Stack_push(&(thread->stack), BUILTIN_NIL);
144           }
145           break;
146
147         default:
148           assert(false);
149       }
150       break;
151
152     default:
153       assert(false);
154   }
155 }
156
157 {% with name='add', operation='+' %}
158   {% include "arithmetic_instruction.c" %}
159 {% endwith %}
160
161
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);
166 }
167
168 void end(struct Thread* thread, Argument argument) {
169 }
170
171 {% with name='eq', operation='==' %}
172   {% include "comparison_instruction.c" %}
173 {% endwith %}
174
175 {% with name='gt', operation='>' %}
176   {% include "comparison_instruction.c" %}
177 {% endwith %}
178
179 {% with name='gte', operation='>=' %}
180   {% include "comparison_instruction.c" %}
181 {% endwith %}
182
183 {% with name='idiv', operation='/' %}
184   {% include "arithmetic_instruction.c" %}
185 {% endwith %}
186
187 void jump(Thread* thread, Argument argument) {
188   thread->program_counter = argument.label - 1; // We will increment before running
189 }
190
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);
195
196   if(!(result.value.boolean)) {
197     jump(thread, argument);
198   }
199 }
200
201 {% with name='lt', operation='<' %}
202   {% include "comparison_instruction.c" %}
203 {% endwith %}
204
205 {% with name='lte', operation='<=' %}
206   {% include "comparison_instruction.c" %}
207 {% endwith %}
208
209 {% with name='mod', operation='%' %}
210   {% include "arithmetic_instruction.c" %}
211 {% endwith %}
212
213 {% with name='mul', operation='*' %}
214   {% include "arithmetic_instruction.c" %}
215 {% endwith %}
216
217 {% with name='neq', operation='!=' %}
218   {% include "comparison_instruction.c" %}
219 {% endwith %}
220
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);
225
226   result.value.integer = -(result.value.integer);
227
228   Stack_push(&(thread->stack), result);
229 }
230
231 void pop(struct Thread* thread, Argument argument) {
232   char* argumentString = argument.string;
233
234   assert(!Stack_isEmpty(&(thread->stack)));
235   Object result = Stack_pop(&(thread->stack));
236
237   if(strcmp(argumentString, "print") == 0) {
238     assert(false);
239   } else if(strcmp(argumentString, "pow") == 0) {
240     assert(false);
241   }
242
243
244   Environment_set(thread->environment, argumentString, result);
245 }
246
247 void push(struct Thread* thread, Argument argument) {
248   char* argumentString = argument.string;
249
250   if(strcmp(argumentString, "false") == 0) {
251     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
252   }else if(strcmp(argumentString, "pow") == 0) {
253     Object result;
254     result.type = BUILTIN;
255     result.value.builtin = POW;
256     Stack_push(&(thread->stack), result);
257   } else if(strcmp(argumentString, "print") == 0) {
258     Object result;
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 });
264   } else {
265     Environment_get_Result result = Environment_get(thread->environment, argumentString);
266     if(!result.found) {
267       fprintf(stderr, "Variable `%s` not found", argumentString);
268       assert(false);
269     }
270     Stack_push(&(thread->stack), result.result);
271   }
272 }
273
274 void push_integer(struct Thread* thread, Argument argument) {
275   Object result;
276   result.type = INTEGER;
277   result.value.integer = argument.integer;
278
279   Stack_push(&(thread->stack), result);
280 }
281
282 void push_string(struct Thread* thread, Argument argument) {
283   Object result;
284   result.type = STRING;
285   result.value.string = argument.string;
286
287   Stack_push(&(thread->stack), result);
288 }
289
290 {% with name='sub', operation='-' %}
291   {% include "arithmetic_instruction.c" %}
292 {% endwith %}
293
294 struct Instruction;
295 typedef const struct Instruction Instruction;
296 struct Instruction {
297   void (*instruction)(struct Thread*,Argument);
298   Argument argument;
299 };
300
301 {% for label in labels_to_instruction_indices.keys() %}
302 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
303 {% endfor %}
304
305 const Instruction program[] = {
306 {% for instruction in instruction_list %}
307   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
308 {% endfor %}
309 };
310
311 int main() {
312   Thread thread;
313   Thread_initialize(&thread, LABEL___main__);
314
315   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
316     program[thread.program_counter].instruction(
317       &thread,
318       program[thread.program_counter].argument
319     );
320   }
321
322   Thread_deinitialize(&thread);
323
324   return 0;
325 }