1610a540db5c977f832eb7e163feda85395b5c5b
[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               case INTEGER:
121                 printf("%i", arg.value.integer);
122                 break;
123
124               case STRING:
125                 printf("%s", arg.value.string);
126                 break;
127
128               default:
129                 assert(0);
130             }
131
132             Stack_push(&(thread->stack), BUILTIN_NIL);
133           }
134           break;
135
136         default:
137           assert(false);
138       }
139       break;
140
141     default:
142       assert(false);
143   }
144 }
145
146 {% with name='add', operation='+' %}
147   {% include "arithmetic_instruction.c" %}
148 {% endwith %}
149
150
151 void drop(struct Thread* thread, Argument argument) {
152   assert(!Stack_isEmpty(&(thread->stack)));
153   Object result = Stack_pop(&(thread->stack));
154   Object_deinitialize(&result);
155 }
156
157 void end(struct Thread* thread, Argument argument) {
158 }
159
160 {% with name='idiv', operation='/' %}
161   {% include "arithmetic_instruction.c" %}
162 {% endwith %}
163
164 {% with name='mod', operation='%' %}
165   {% include "arithmetic_instruction.c" %}
166 {% endwith %}
167
168 {% with name='mul', operation='*' %}
169   {% include "arithmetic_instruction.c" %}
170 {% endwith %}
171
172 void neg(struct Thread* thread, Argument argument) {
173   assert(!Stack_isEmpty(&(thread->stack)));
174   Object result = Stack_pop(&(thread->stack));
175   assert(result.type == INTEGER);
176
177   result.value.integer = -(result.value.integer);
178
179   Stack_push(&(thread->stack), result);
180 }
181
182 void pop(struct Thread* thread, Argument argument) {
183   char* argumentString = argument.string;
184
185   assert(!Stack_isEmpty(&(thread->stack)));
186   Object result = Stack_pop(&(thread->stack));
187
188   if(strcmp(argumentString, "print") == 0) {
189     assert(false);
190   } else if(strcmp(argumentString, "pow") == 0) {
191     assert(false);
192   }
193
194
195   Environment_set(thread->environment, argumentString, result);
196 }
197
198 void push(struct Thread* thread, Argument argument) {
199   char* argumentString = argument.string;
200
201   if(strcmp(argumentString, "false") == 0) {
202     Stack_push(&(thread->stack), (Object){ BOOLEAN, false });
203   }else if(strcmp(argumentString, "pow") == 0) {
204     Object result;
205     result.type = BUILTIN;
206     result.value.builtin = POW;
207     Stack_push(&(thread->stack), result);
208   } else if(strcmp(argumentString, "print") == 0) {
209     Object result;
210     result.type = BUILTIN;
211     result.value.builtin = PRINT;
212     Stack_push(&(thread->stack), result);
213   } else if(strcmp(argumentString, "true") == 0) {
214     Stack_push(&(thread->stack), (Object){ BOOLEAN, true });
215   } else {
216     Environment_get_Result result = Environment_get(thread->environment, argumentString);
217     if(!result.found) {
218       fprintf(stderr, "Variable `%s` not found", argumentString);
219       assert(false);
220     }
221     Stack_push(&(thread->stack), result.result);
222   }
223 }
224
225 void push_integer(struct Thread* thread, Argument argument) {
226   Object result;
227   result.type = INTEGER;
228   result.value.integer = argument.integer;
229
230   Stack_push(&(thread->stack), result);
231 }
232
233 void push_string(struct Thread* thread, Argument argument) {
234   Object result;
235   result.type = STRING;
236   result.value.string = argument.string;
237
238   Stack_push(&(thread->stack), result);
239 }
240
241 {% with name='sub', operation='-' %}
242   {% include "arithmetic_instruction.c" %}
243 {% endwith %}
244
245 struct Instruction;
246 typedef const struct Instruction Instruction;
247 struct Instruction {
248   void (*instruction)(struct Thread*,Argument);
249   Argument argument;
250 };
251
252 {% for label in labels_to_instruction_indices.keys() %}
253 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
254 {% endfor %}
255
256 const Instruction program[] = {
257 {% for instruction in instruction_list %}
258   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
259 {% endfor %}
260 };
261
262 int main() {
263   Thread thread;
264   Thread_initialize(&thread, 0);
265
266   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
267     program[thread.program_counter].instruction(
268       &thread,
269       program[thread.program_counter].argument
270     );
271   }
272
273   Thread_deinitialize(&thread);
274
275   return 0;
276 }