8602054d666f93c206724e184b9c53d752939027
[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   BUILTIN,
12   INTEGER,
13   STRING
14 };
15
16 enum Builtin;
17 typedef enum Builtin Builtin;
18 enum Builtin {
19   NIL,
20   POW,
21   PRINT
22 };
23
24 union Value;
25 typedef union Value Value;
26 union Value {
27   Builtin builtin;
28   char* string;
29   int32_t integer;
30 };
31
32 struct Object;
33 typedef struct Object Object;
34 struct Object {
35   Type type;
36   Value value;
37 };
38
39 #define BUILTIN_NIL (Object) { BUILTIN, (Value)(Builtin)NIL }
40
41 void Object_deinitialize(Object* self) {
42 }
43
44 {% include "environment.c" %}
45 {% include "stack.c" %}
46
47 struct Thread;
48 typedef struct Thread Thread;
49 struct Thread {
50   Environment* environment;
51   Stack stack;
52   size_t program_counter;
53 };
54
55 void Thread_initialize(Thread* self, size_t program_counter) {
56   self->environment = Environment_construct();
57   Stack_initialize(&(self->stack));
58   self->program_counter = program_counter;
59 }
60
61 void Thread_deinitialize(Thread* self) {
62   Environment_destruct(self->environment);
63   Stack_deinitialize(&(self->stack));
64 }
65
66 union Argument;
67 typedef const union Argument Argument;
68 union Argument {
69   size_t label;
70   void* pointer;
71   char* string;
72   int32_t integer;
73 };
74
75 void call(struct Thread* thread, Argument argument) {
76   assert(!Stack_isEmpty(&(thread->stack)));
77   Object f = Stack_pop(&(thread->stack));
78   size_t argumentCount = argument.label;
79
80   switch(f.type) {
81     case BUILTIN:
82       switch(f.value.builtin) {
83         case POW:
84           {
85             assert(argumentCount == 2);
86             assert(!Stack_isEmpty(&(thread->stack)));
87             Object exponent = Stack_pop(&(thread->stack));
88             assert(exponent.type == INTEGER);
89             assert(exponent.value.integer >= 0);
90
91             assert(!Stack_isEmpty(&(thread->stack)));
92             Object base = Stack_pop(&(thread->stack));
93             assert(base.type == INTEGER);
94
95             Object result;
96             result.type = INTEGER;
97             result.value.integer = 1;
98
99             while(exponent.value.integer > 0) {
100               result.value.integer *= base.value.integer;
101               exponent.value.integer--;
102             }
103
104             Stack_push(&(thread->stack), result);
105           }
106           break;
107         case PRINT:
108           {
109             // TODO Handle multiple arguments
110             assert(!Stack_isEmpty(&(thread->stack)));
111             Object arg = Stack_pop(&(thread->stack));
112
113             switch(arg.type) {
114               case INTEGER:
115                 printf("%i", arg.value.integer);
116                 break;
117
118               case STRING:
119                 printf("%s", arg.value.string);
120                 break;
121
122               default:
123                 assert(0);
124             }
125
126             Stack_push(&(thread->stack), BUILTIN_NIL);
127           }
128           break;
129
130         default:
131           assert(false);
132       }
133       break;
134
135     default:
136       assert(false);
137   }
138 }
139
140 {% with name='add', operation='+' %}
141   {% include "arithmetic_instruction.c" %}
142 {% endwith %}
143
144
145 void drop(struct Thread* thread, Argument argument) {
146   assert(!Stack_isEmpty(&(thread->stack)));
147   Object result = Stack_pop(&(thread->stack));
148   Object_deinitialize(&result);
149 }
150
151 void end(struct Thread* thread, Argument argument) {
152 }
153
154 {% with name='idiv', operation='/' %}
155   {% include "arithmetic_instruction.c" %}
156 {% endwith %}
157
158 {% with name='mod', operation='%' %}
159   {% include "arithmetic_instruction.c" %}
160 {% endwith %}
161
162 {% with name='mul', operation='*' %}
163   {% include "arithmetic_instruction.c" %}
164 {% endwith %}
165
166 void neg(struct Thread* thread, Argument argument) {
167   assert(!Stack_isEmpty(&(thread->stack)));
168   Object result = Stack_pop(&(thread->stack));
169   assert(result.type == INTEGER);
170
171   result.value.integer = -(result.value.integer);
172
173   Stack_push(&(thread->stack), result);
174 }
175
176 void pop(struct Thread* thread, Argument argument) {
177   char* argumentString = argument.string;
178
179   assert(!Stack_isEmpty(&(thread->stack)));
180   Object result = Stack_pop(&(thread->stack));
181
182   if(strcmp(argumentString, "print") == 0) {
183     assert(false);
184   } else if(strcmp(argumentString, "pow") == 0) {
185     assert(false);
186   }
187
188
189   Environment_set(thread->environment, argumentString, result);
190 }
191
192 void push(struct Thread* thread, Argument argument) {
193   char* argumentString = argument.string;
194
195   if(strcmp(argumentString, "print") == 0) {
196     Object result;
197     result.type = BUILTIN;
198     result.value.builtin = PRINT;
199     Stack_push(&(thread->stack), result);
200   } else if(strcmp(argumentString, "pow") == 0) {
201     Object result;
202     result.type = BUILTIN;
203     result.value.builtin = POW;
204     Stack_push(&(thread->stack), result);
205   } else {
206     Environment_get_Result result = Environment_get(thread->environment, argumentString);
207     if(!result.found) {
208       fprintf(stderr, "Variable `%s` not found", argumentString);
209       assert(false);
210     }
211     Stack_push(&(thread->stack), result.result);
212   }
213 }
214
215 void push_integer(struct Thread* thread, Argument argument) {
216   Object result;
217   result.type = INTEGER;
218   result.value.integer = argument.integer;
219
220   Stack_push(&(thread->stack), result);
221 }
222
223 void push_string(struct Thread* thread, Argument argument) {
224   Object result;
225   result.type = STRING;
226   result.value.string = argument.string;
227
228   Stack_push(&(thread->stack), result);
229 }
230
231 {% with name='sub', operation='-' %}
232   {% include "arithmetic_instruction.c" %}
233 {% endwith %}
234
235 struct Instruction;
236 typedef const struct Instruction Instruction;
237 struct Instruction {
238   void (*instruction)(struct Thread*,Argument);
239   Argument argument;
240 };
241
242 {% for label in labels_to_instruction_indices.keys() %}
243 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
244 {% endfor %}
245
246 const Instruction program[] = {
247 {% for instruction in instruction_list %}
248   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
249 {% endfor %}
250 };
251
252 int main() {
253   Thread thread;
254   Thread_initialize(&thread, 0);
255
256   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
257     program[thread.program_counter].instruction(
258       &thread,
259       program[thread.program_counter].argument
260     );
261   }
262
263   Thread_deinitialize(&thread);
264
265   return 0;
266 }