76fc2f804db601251d93ecb63d7f6f95c8165f10
[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, const union 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, const union 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, const union 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 pop(struct Thread* thread, const union Argument argument) {
167   char* argumentString = argument.string;
168
169   assert(!Stack_isEmpty(&(thread->stack)));
170   Object result = Stack_pop(&(thread->stack));
171
172   if(strcmp(argumentString, "print") == 0) {
173     assert(false);
174   } else if(strcmp(argumentString, "pow") == 0) {
175     assert(false);
176   }
177
178
179   Environment_set(thread->environment, argumentString, result);
180 }
181
182 void push(struct Thread* thread, const union Argument argument) {
183   char* argumentString = argument.string;
184
185   if(strcmp(argumentString, "print") == 0) {
186     Object result;
187     result.type = BUILTIN;
188     result.value.builtin = PRINT;
189     Stack_push(&(thread->stack), result);
190   } else if(strcmp(argumentString, "pow") == 0) {
191     Object result;
192     result.type = BUILTIN;
193     result.value.builtin = POW;
194     Stack_push(&(thread->stack), result);
195   } else {
196     Environment_get_Result result = Environment_get(thread->environment, argumentString);
197     if(!result.found) {
198       fprintf(stderr, "Variable `%s` not found", argumentString);
199       assert(false);
200     }
201     Stack_push(&(thread->stack), result.result);
202   }
203 }
204
205 void push_integer(struct Thread* thread, const union Argument argument) {
206   Object result;
207   result.type = INTEGER;
208   result.value.integer = argument.integer;
209
210   Stack_push(&(thread->stack), result);
211 }
212
213 void push_string(struct Thread* thread, const union Argument argument) {
214   Object result;
215   result.type = STRING;
216   result.value.string = argument.string;
217
218   Stack_push(&(thread->stack), result);
219 }
220
221 {% with name='sub', operation='-' %}
222   {% include "arithmetic_instruction.c" %}
223 {% endwith %}
224
225 struct Instruction;
226 typedef const struct Instruction Instruction;
227 struct Instruction {
228   void (*instruction)(struct Thread*,const union Argument);
229   Argument argument;
230 };
231
232 {% for label in labels_to_instruction_indices.keys() %}
233 #define LABEL_{{ label }} {{ labels_to_instruction_indices[label] }}
234 {% endfor %}
235
236 const Instruction program[] = {
237 {% for instruction in instruction_list %}
238   (Instruction){ {{ instruction.instruction }}, (Argument){{ generate_argument(instruction) }} },
239 {% endfor %}
240 };
241
242 int main() {
243   Thread thread;
244   Thread_initialize(&thread, 0);
245
246   for(; program[thread.program_counter].instruction != end; thread.program_counter++) {
247     program[thread.program_counter].instruction(
248       &thread,
249       program[thread.program_counter].argument
250     );
251   }
252
253   Thread_deinitialize(&thread);
254
255   return 0;
256 }