Removed not-yet-relevant string type
[fur] / templates / program.c
1 #include <assert.h>
2 #include <inttypes.h>
3 #include <stdbool.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 {% for standard_library in standard_libraries %}
8 #include <{{standard_library}}>
9 {% endfor %}
10
11 struct String;
12 typedef struct String String;
13 enum Type;
14 typedef enum Type Type;
15 union Instance;
16 typedef union Instance Instance;
17 struct Object;
18 typedef struct Object Object;
19 struct Runtime;
20 typedef struct Runtime Runtime;
21
22 const char * const SYMBOL_LIST[] = {
23 {% for symbol in symbol_list %}
24   "{{ symbol }}",
25 {% endfor %}
26 };
27
28 enum Type
29 {
30   BOOLEAN,
31   INTEGER,
32   STRING
33 };
34
35 union Instance
36 {
37   bool boolean;
38   int32_t integer;
39   char* string;
40 };
41
42 struct Object
43 {
44   Type type;
45   Instance instance;
46 };
47
48 const Object TRUE = {
49   BOOLEAN,
50   true
51 };
52
53 const Object FALSE = {
54   BOOLEAN,
55   false
56 };
57
58 struct EnvironmentNode;
59 typedef struct EnvironmentNode EnvironmentNode;
60 struct EnvironmentNode
61 {
62   const char* key;
63   Object value;
64   EnvironmentNode* next;
65 };
66
67 struct Environment;
68 typedef struct Environment Environment;
69 struct Environment
70 {
71   EnvironmentNode* root;
72 };
73
74 Environment* Environment_construct()
75 {
76   // TODO Handle malloc returning NULL
77   Environment* result = malloc(sizeof(Environment));
78   result->root = NULL;
79   return result;
80 }
81
82 void Environment_destruct(Environment* self)
83 {
84   EnvironmentNode* next;
85   for(EnvironmentNode* node = self->root; node != NULL; node = next)
86   {
87     // We don't need to destruct the permanent strings, because those will be destructed at the end when the Runtime is destructed
88     // The above comment represents all heap-allocated objects currently, so we don't need to destruct Objects (yet)
89     next = node->next;
90     free(node);
91   }
92 }
93
94 // This need not be thread safe because environments exist on one thread only
95 void Environment_set(Environment* self, const char* const key, Object value)
96 {
97   EnvironmentNode* node = malloc(sizeof(EnvironmentNode));
98   node->key = key;
99   node->value = value;
100   node->next = self->root;
101   self->root = node;
102 }
103
104 Object Environment_get(Environment* self, const char* const symbol)
105 {
106   for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
107   {
108     // We can compare pointers because pointers are unique in the SYMBOLS_LIST
109     if(node->key == symbol)
110     {
111       return node->value;
112     }
113   }
114
115   // TODO Handle symbol errors
116   assert(false);
117 }
118
119
120 struct Runtime
121 {
122   size_t permanentStringsLength;
123   size_t permanentStringsAllocated;
124   char** permanentStrings;
125 };
126
127 Runtime* Runtime_construct()
128 {
129   Runtime* result = malloc(sizeof(Runtime));
130   result->permanentStringsLength = 0;
131   result->permanentStringsAllocated = 0;
132   result->permanentStrings = NULL;
133   return result;
134 }
135
136 void Runtime_destruct(Runtime* self)
137 {
138   free(self->permanentStrings);
139   free(self);
140 }
141
142 void Runtime_addPermanentString(Runtime* self, char* const string)
143 {
144   // TODO Make this function thread-safe
145   if(self->permanentStringsLength == self->permanentStringsAllocated)
146   {
147     if(self->permanentStringsAllocated == 0)
148     {
149       self->permanentStringsAllocated = 8;
150     }
151     else
152     {
153       self->permanentStringsAllocated = self->permanentStringsAllocated * 2;
154     }
155
156     self->permanentStrings = realloc(
157       self->permanentStrings,
158       sizeof(char* const) * self->permanentStringsAllocated
159     );
160
161     // TODO Handle realloc returning NULL
162   }
163
164   self->permanentStrings[self->permanentStringsLength] = string;
165   self->permanentStringsLength++;
166 }
167
168 Object integerLiteral(int32_t literal)
169 {
170   Object result;
171   result.type = INTEGER;
172   result.instance.integer = literal;
173   return result;
174 }
175
176 Object stringLiteral(Runtime* runtime, char* literal)
177 {
178   Runtime_addPermanentString(runtime, literal);
179
180   Object result;
181   result.type = STRING;
182   result.instance.string = literal;
183   return result;
184 }
185
186 // TODO Make this conditionally added
187 Object builtin$negate(Object input)
188 {
189   assert(input.type == INTEGER);
190
191   Object result;
192   result.type = INTEGER;
193   result.instance.integer = -input.instance.integer;
194   return result;
195 }
196
197 Object builtin$add(Object left, Object right)
198 {
199   assert(left.type == INTEGER);
200   assert(right.type == INTEGER);
201
202   Object result;
203   result.type = INTEGER;
204   result.instance.integer = left.instance.integer + right.instance.integer;
205   return result;
206 }
207
208 Object builtin$subtract(Object left, Object right)
209 {
210   assert(left.type == INTEGER);
211   assert(right.type == INTEGER);
212
213   Object result;
214   result.type = INTEGER;
215   result.instance.integer = left.instance.integer - right.instance.integer;
216   return result;
217 }
218
219 Object builtin$multiply(Object left, Object right)
220 {
221   assert(left.type == INTEGER);
222   assert(right.type == INTEGER);
223
224   Object result;
225   result.type = INTEGER;
226   result.instance.integer = left.instance.integer * right.instance.integer;
227   return result;
228 }
229
230 Object builtin$integerDivide(Object left, Object right)
231 {
232   assert(left.type == INTEGER);
233   assert(right.type == INTEGER);
234
235   Object result;
236   result.type = INTEGER;
237   result.instance.integer = left.instance.integer / right.instance.integer;
238   return result;
239 }
240
241 Object builtin$modularDivide(Object left, Object right)
242 {
243   assert(left.type == INTEGER);
244   assert(right.type == INTEGER);
245
246   Object result;
247   result.type = INTEGER;
248   result.instance.integer = left.instance.integer % right.instance.integer;
249   return result;
250 }
251
252 Object builtin$equals(Object left, Object right)
253 {
254   assert(left.type == INTEGER);
255   assert(right.type == INTEGER);
256
257   Object result = { BOOLEAN, left.instance.integer == right.instance.integer };
258   return result;
259 }
260
261 Object builtin$notEquals(Object left, Object right)
262 {
263   assert(left.type == INTEGER);
264   assert(right.type == INTEGER);
265
266   Object result = { BOOLEAN, left.instance.integer != right.instance.integer };
267   return result;
268 }
269
270 Object builtin$greaterThan(Object left, Object right)
271 {
272   assert(left.type == INTEGER);
273   assert(right.type == INTEGER);
274
275   Object result = { BOOLEAN, left.instance.integer > right.instance.integer };
276   return result;
277 }
278
279 Object builtin$lessThan(Object left, Object right)
280 {
281   assert(left.type == INTEGER);
282   assert(right.type == INTEGER);
283
284   Object result = { BOOLEAN, left.instance.integer < right.instance.integer };
285   return result;
286 }
287
288 Object builtin$greaterThanOrEqual(Object left, Object right)
289 {
290   assert(left.type == INTEGER);
291   assert(right.type == INTEGER);
292
293   Object result = { BOOLEAN, left.instance.integer >= right.instance.integer };
294   return result;
295 }
296
297 Object builtin$lessThanOrEqual(Object left, Object right)
298 {
299   assert(left.type == INTEGER);
300   assert(right.type == INTEGER);
301
302   Object result = { BOOLEAN, left.instance.integer <= right.instance.integer };
303   return result;
304 }
305
306 Object builtin$and(Object left, Object right)
307 {
308   assert(left.type == BOOLEAN);
309   assert(right.type == BOOLEAN);
310
311   Object result = { BOOLEAN, left.instance.boolean && right.instance.boolean };
312   return result;
313 }
314
315 Object builtin$or(Object left, Object right)
316 {
317   assert(left.type == BOOLEAN);
318   assert(right.type == BOOLEAN);
319
320   Object result = { BOOLEAN, left.instance.boolean || right.instance.boolean };
321   return result;
322 }
323
324 {% if 'pow' in builtins %}
325 Object builtin$pow(Object base, Object exponent)
326 {
327   assert(base.type == INTEGER);
328   assert(exponent.type == INTEGER);
329
330   Object result;
331   result.type = INTEGER;
332   result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
333   return result;
334 }
335 {% endif %}
336
337 {% if 'print' in builtins %}
338 void builtin$print(Object output)
339 {
340   switch(output.type)
341   {
342     case BOOLEAN:
343       fputs(output.instance.boolean ? "true" : "false", stdout);
344       break;
345
346     case INTEGER:
347       printf("%" PRId32, output.instance.integer);
348       break;
349
350     case STRING:
351       // Using fwrite instead of printf to handle size_t length
352       printf("%s", output.instance.string);
353       break;
354
355     default:
356       assert(false);
357   }
358 }
359 {% endif %}
360
361 int main(int argc, char** argv)
362 {
363   Runtime* runtime = Runtime_construct();
364   Environment* environment = Environment_construct();
365
366   {% for statement in statements %}
367   {{ statement }}
368   {% endfor %}
369
370   Environment_destruct(environment);
371   Runtime_destruct(runtime);
372
373   return 0;
374 }