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