ffd014ca1ffeede9cef8c49f7abdba8b41c87070
[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             // TODO Handle multiple arguments
112             assert(!Stack_isEmpty(&(thread->stack)));
113             Object arg = Stack_pop(&(thread->stack));
114
115             switch(arg.type) {
116               case BOOLEAN:
117                 if(arg.value.boolean) printf("true");
118                 else printf("false");
119                 break;
120
121               case INTEGER:
122                 printf("%i", arg.value.integer);
123                 break;
124
125               case STRING:
126                 printf("%s", arg.value.string);
127                 break;
128
129               default:
130                 assert(0);
131             }
132
133             Stack_push(&(thread->stack), BUILTIN_NIL);
134           }
135           break;
136
137         default:
138           assert(false);
139       }
140       break;
141
142     default:
143       assert(false);
144   }
145 }
146
147 {% with name='add', operation='+' %}
148   {% include "arithmetic_instruction.c" %}
149 {% endwith %}
150
151
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);
156 }
157
158 void end(struct Thread* thread, Argument argument) {
159 }
160
161 {% with name='eq', operation='==' %}
162   {% include "comparison_instruction.c" %}
163 {% endwith %}
164
165 {% with name='gt', operation='>' %}
166   {% include "comparison_instruction.c" %}
167 {% endwith %}
168
169 {% with name='gte', operation='>=' %}
170   {% include "comparison_instruction.c" %}
171 {% endwith %}
172
173 {% with name='idiv', operation='/' %}
174   {% include "arithmetic_instruction.c" %}
175 {% endwith %}
176
177 {% with name='lt', operation='<' %}
178   {% include "comparison_instruction.c" %}
179 {% endwith %}
180
181 {% with name='lte', operation='<=' %}
182   {% include "comparison_instruction.c" %}
183 {% endwith %}
184
185 {% with name='mod', operation='%' %}
186   {% include "arithmetic_instruction.c" %}
187 {% endwith %}
188
189 {% with name='mul', operation='*' %}
190   {% include "arithmetic_instruction.c" %}
191 {% endwith %}
192
193 {% with name='neq', operation='!=' %}
194   {% include "comparison_instruction.c" %}
195 {% endwith %}
196
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);
201
202   result.value.integer = -(result.value.integer);
203
204   Stack_push(&(thread->stack), result);
205 }
206
207 void pop(struct Thread* thread, Argument argument) {
208   char* argumentString = argument.string;
209
210   assert(!Stack_isEmpty(&(thread->stack)));
211   Object result = Stack_pop(&(thread->stack));
212
213   if(strcmp(argumentString, "print") == 0) {
214     assert(false);
215   } else if(strcmp(argumentString, "pow") == 0) {
216     assert(false);
217   }
218
219
220   Environment_set(thread->environment, argumentString, result);
221 }
222
223 void push(struct Thread* thread, Argument argument) {
224   char* argumentString = argument.string;
225
226   if(strcmp(argumentString, "false") == 0) {
227     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
228   }else if(strcmp(argumentString, "pow") == 0) {
229     Object result;
230     result.type = BUILTIN;
231     result.value.builtin = POW;
232     Stack_push(&(thread->stack), result);
233   } else if(strcmp(argumentString, "print") == 0) {
234     Object result;
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 });
240   } else {
241     Environment_get_Result result = Environment_get(thread->environment, argumentString);
242     if(!result.found) {
243       fprintf(stderr, "Variable `%s` not found", argumentString);
244       assert(false);
245     }
246     Stack_push(&(thread->stack), result.result);
247   }
248 }
249
250 void push_integer(struct Thread* thread, Argument argument) {
251   Object result;
252   result.type = INTEGER;
253   result.value.integer = argument.integer;
254
255   Stack_push(&(thread->stack), result);
256 }
257
258 void push_string(struct Thread* thread, Argument argument) {
259   Object result;
260   result.type = STRING;
261   result.value.string = argument.string;
262
263   Stack_push(&(thread->stack), result);
264 }
265
266 {% with name='sub', operation='-' %}
267   {% include "arithmetic_instruction.c" %}
268 {% endwith %}
269
270 struct Instruction;
271 typedef const struct Instruction Instruction;
272 struct Instruction {
273   void (*instruction)(struct Thread*,Argument);
274   Argument argument;
275 };
276
277 {% for label in labels_to_instruction_indices.keys() %}
278 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
279 {% endfor %}
280
281 const Instruction program[] = {
282 {% for instruction in instruction_list %}
283   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
284 {% endfor %}
285 };
286
287 int main() {
288   Thread thread;
289   Thread_initialize(&thread, 0);
290
291   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
292     program[thread.program_counter].instruction(
293       &thread,
294       program[thread.program_counter].argument
295     );
296   }
297
298   Thread_deinitialize(&thread);
299
300   return 0;
301 }