Wrap thread properties in getters/setters
[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 {% include "frame.c" %}
61
62 struct Thread;
63 typedef struct Thread Thread;
64 struct Thread {
65   Environment* environment;
66   Stack stack;
67   size_t programCounter;
68 };
69
70 void Thread_initialize(Thread* self, size_t programCounter) {
71   self->environment = Environment_construct();
72   Stack_initialize(&(self->stack));
73   self->programCounter = programCounter;
74 }
75
76 void Thread_deinitialize(Thread* self) {
77   Environment_destruct(self->environment);
78   Stack_deinitialize(&(self->stack));
79 }
80
81 Environment* Thread_getEnvironment(Thread* self) {
82   return self->environment;
83 }
84
85 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
86   self->programCounter = programCounter;
87 }
88
89 void Thread_incrementProgramCounter(Thread* self) {
90   self->programCounter++;
91 }
92
93 size_t Thread_getProgramCounter(Thread* self) {
94   return self->programCounter;
95 }
96
97 union Argument;
98 typedef const union Argument Argument;
99 union Argument {
100   size_t label;
101   void* pointer;
102   char* string;
103   int32_t integer;
104 };
105
106 void callBuiltinPow(Thread* thread, size_t argumentCount) {
107   assert(argumentCount == 2);
108   assert(!Stack_isEmpty(&(thread->stack)));
109   Object exponent = Stack_pop(&(thread->stack));
110   assert(exponent.type == INTEGER);
111   assert(exponent.value.integer >= 0);
112
113   assert(!Stack_isEmpty(&(thread->stack)));
114   Object base = Stack_pop(&(thread->stack));
115   assert(base.type == INTEGER);
116
117   Object result;
118   result.type = INTEGER;
119   result.value.integer = 1;
120
121   while(exponent.value.integer > 0) {
122     result.value.integer *= base.value.integer;
123     exponent.value.integer--;
124   }
125
126   Stack_push(&(thread->stack), result);
127 }
128
129 void callBuiltinPrint(Thread* thread, size_t argumentCount) {
130   assert(argumentCount > 0);
131
132   Object arguments[argumentCount];
133   size_t count;
134
135   for(count = 0; count < argumentCount; count++) {
136     assert(!Stack_isEmpty(&(thread->stack)));
137     arguments[argumentCount - count - 1] = Stack_pop(&(thread->stack));
138   }
139
140   for(count = 0; count < argumentCount; count ++) {
141     Object arg = arguments[count];
142
143     switch(arg.type) {
144       case BOOLEAN:
145         if(arg.value.boolean) printf("true");
146         else printf("false");
147         break;
148
149       case INTEGER:
150         printf("%i", arg.value.integer);
151         break;
152
153       case STRING:
154         printf("%s", arg.value.string);
155         break;
156
157       default:
158         assert(false);
159     }
160   }
161
162   Stack_push(&(thread->stack), BUILTIN_NIL);
163 }
164
165 void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
166   switch(b) {
167     case POW:
168       callBuiltinPow(thread, argumentCount);
169       break;
170     case PRINT:
171       callBuiltinPrint(thread, argumentCount);
172       break;
173
174     default:
175       assert(false);
176   }
177 }
178
179 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
180   assert(argumentCount == 0);
181
182
183 }
184
185 void inst_call(Thread* thread, Argument argument) {
186   assert(!Stack_isEmpty(&(thread->stack)));
187   Object f = Stack_pop(&(thread->stack));
188   size_t argumentCount = argument.label;
189
190   switch(f.type) {
191     case BUILTIN:
192       callBuiltin(thread, f.value.builtin, argumentCount);
193       break;
194
195     case CLOSURE:
196       callClosure(thread, f.value.closure, argumentCount);
197       break;
198
199     default:
200       assert(false);
201   }
202 }
203
204 {% with name='add', operation='+' %}
205   {% include "arithmetic_instruction.c" %}
206 {% endwith %}
207
208 void inst_close(Thread* thread, Argument argument) {
209   Object result;
210   result.type = CLOSURE;
211   result.value.closure.environment = Thread_getEnvironment(thread);
212   result.value.closure.entry = argument.label;
213
214   Stack_push(&(thread->stack), result);
215 }
216
217 void inst_drop(Thread* thread, Argument argument) {
218   assert(!Stack_isEmpty(&(thread->stack)));
219   Object result = Stack_pop(&(thread->stack));
220   Object_deinitialize(&result);
221 }
222
223 void inst_end(Thread* thread, Argument argument) {
224 }
225
226 {% with name='eq', operation='==' %}
227   {% include "comparison_instruction.c" %}
228 {% endwith %}
229
230 {% with name='gt', operation='>' %}
231   {% include "comparison_instruction.c" %}
232 {% endwith %}
233
234 {% with name='gte', operation='>=' %}
235   {% include "comparison_instruction.c" %}
236 {% endwith %}
237
238 {% with name='idiv', operation='/' %}
239   {% include "arithmetic_instruction.c" %}
240 {% endwith %}
241
242 void inst_jump(Thread* thread, Argument argument) {
243   Thread_setProgramCounter(thread, argument.label - 1); // We will increment before running
244 }
245
246 void inst_jump_if_false(Thread* thread, Argument argument) {
247   assert(!Stack_isEmpty(&(thread->stack)));
248   Object result = Stack_pop(&(thread->stack));
249   assert(result.type == BOOLEAN);
250
251   if(!(result.value.boolean)) {
252     inst_jump(thread, argument);
253   }
254 }
255
256 {% with name='lt', operation='<' %}
257   {% include "comparison_instruction.c" %}
258 {% endwith %}
259
260 {% with name='lte', operation='<=' %}
261   {% include "comparison_instruction.c" %}
262 {% endwith %}
263
264 {% with name='mod', operation='%' %}
265   {% include "arithmetic_instruction.c" %}
266 {% endwith %}
267
268 {% with name='mul', operation='*' %}
269   {% include "arithmetic_instruction.c" %}
270 {% endwith %}
271
272 {% with name='neq', operation='!=' %}
273   {% include "comparison_instruction.c" %}
274 {% endwith %}
275
276 void inst_neg(Thread* thread, Argument argument) {
277   assert(!Stack_isEmpty(&(thread->stack)));
278   Object result = Stack_pop(&(thread->stack));
279   assert(result.type == INTEGER);
280
281   result.value.integer = -(result.value.integer);
282
283   Stack_push(&(thread->stack), result);
284 }
285
286 void inst_pop(Thread* thread, Argument argument) {
287   char* argumentString = argument.string;
288
289   assert(!Stack_isEmpty(&(thread->stack)));
290   Object result = Stack_pop(&(thread->stack));
291
292   if(strcmp(argumentString, "print") == 0) {
293     assert(false);
294   } else if(strcmp(argumentString, "pow") == 0) {
295     assert(false);
296   }
297
298
299   Environment_set(Thread_getEnvironment(thread), argumentString, result);
300 }
301
302 void inst_push(Thread* thread, Argument argument) {
303   char* argumentString = argument.string;
304
305   if(strcmp(argumentString, "false") == 0) {
306     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
307   }else if(strcmp(argumentString, "pow") == 0) {
308     Object result;
309     result.type = BUILTIN;
310     result.value.builtin = POW;
311     Stack_push(&(thread->stack), result);
312   } else if(strcmp(argumentString, "print") == 0) {
313     Object result;
314     result.type = BUILTIN;
315     result.value.builtin = PRINT;
316     Stack_push(&(thread->stack), result);
317   } else if(strcmp(argumentString, "true") == 0) {
318     Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
319   } else {
320     Environment_get_Result result = Environment_get(
321       Thread_getEnvironment(thread),
322       argumentString
323     );
324     if(!result.found) {
325       fprintf(stderr, "Variable `%s` not found", argumentString);
326       assert(false);
327     }
328     Stack_push(&(thread->stack), result.result);
329   }
330 }
331
332 void inst_push_integer(Thread* thread, Argument argument) {
333   Object result;
334   result.type = INTEGER;
335   result.value.integer = argument.integer;
336
337   Stack_push(&(thread->stack), result);
338 }
339
340 void inst_push_string(Thread* thread, Argument argument) {
341   Object result;
342   result.type = STRING;
343   result.value.string = argument.string;
344
345   Stack_push(&(thread->stack), result);
346 }
347
348 {% with name='sub', operation='-' %}
349   {% include "arithmetic_instruction.c" %}
350 {% endwith %}
351
352 void inst_return(Thread* thread, Argument argument) {
353   assert(false);
354 }
355
356 struct Instruction;
357 typedef const struct Instruction Instruction;
358 struct Instruction {
359   void (*instruction)(Thread*,Argument);
360   Argument argument;
361 };
362
363 {% for label in labels_to_instruction_indices.keys() %}
364 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
365 {% endfor %}
366
367 const Instruction program[] = {
368 {% for instruction in instruction_list %}
369   (Instruction){ inst_{{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
370 {% endfor %}
371 };
372
373 int main() {
374   Thread thread;
375   Thread_initialize(&thread, LABEL___main__);
376
377   for(; program[Thread_getProgramCounter(&thread)].instruction != inst_end; Thread_incrementProgramCounter(&thread)) {
378     program[Thread_getProgramCounter(&thread)].instruction(
379       &thread,
380       program[Thread_getProgramCounter(&thread)].argument
381     );
382   }
383
384   Thread_deinitialize(&thread);
385
386   return 0;
387 }