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