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