7 {% for standard_library in standard_libraries %}
8 #include <{{standard_library}}>
12 typedef struct String String;
14 typedef enum Type Type;
16 typedef union Instance Instance;
18 typedef struct Object Object;
20 typedef struct Runtime Runtime;
22 const char * const SYMBOL_LIST[] = {
23 {% for symbol in symbol_list %}
53 const Object FALSE = {
58 struct EnvironmentNode;
59 typedef struct EnvironmentNode EnvironmentNode;
60 struct EnvironmentNode
64 EnvironmentNode* next;
68 typedef struct Environment Environment;
71 EnvironmentNode* root;
74 Environment* Environment_construct()
76 // TODO Handle malloc returning NULL
77 Environment* result = malloc(sizeof(Environment));
82 void Environment_destruct(Environment* self)
84 EnvironmentNode* next;
85 for(EnvironmentNode* node = self->root; node != NULL; node = next)
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)
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)
97 EnvironmentNode* node = malloc(sizeof(EnvironmentNode));
100 node->next = self->root;
104 Object Environment_get(Environment* self, const char* const symbol)
106 for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
108 // We can compare pointers because pointers are unique in the SYMBOLS_LIST
109 if(node->key == symbol)
115 // TODO Handle symbol errors
122 size_t permanentStringsLength;
123 size_t permanentStringsAllocated;
124 char** permanentStrings;
127 Runtime* Runtime_construct()
129 Runtime* result = malloc(sizeof(Runtime));
130 result->permanentStringsLength = 0;
131 result->permanentStringsAllocated = 0;
132 result->permanentStrings = NULL;
136 void Runtime_destruct(Runtime* self)
138 free(self->permanentStrings);
142 void Runtime_addPermanentString(Runtime* self, char* const string)
144 // TODO Make this function thread-safe
145 if(self->permanentStringsLength == self->permanentStringsAllocated)
147 if(self->permanentStringsAllocated == 0)
149 self->permanentStringsAllocated = 8;
153 self->permanentStringsAllocated = self->permanentStringsAllocated * 2;
156 self->permanentStrings = realloc(
157 self->permanentStrings,
158 sizeof(char* const) * self->permanentStringsAllocated
161 // TODO Handle realloc returning NULL
164 self->permanentStrings[self->permanentStringsLength] = string;
165 self->permanentStringsLength++;
168 Object integerLiteral(int32_t literal)
171 result.type = INTEGER;
172 result.instance.integer = literal;
176 Object stringLiteral(Runtime* runtime, char* literal)
178 Runtime_addPermanentString(runtime, literal);
181 result.type = STRING;
182 result.instance.string = literal;
186 // TODO Make this conditionally added
187 Object builtin$negate(Object input)
189 assert(input.type == INTEGER);
192 result.type = INTEGER;
193 result.instance.integer = -input.instance.integer;
197 Object builtin$add(Object left, Object right)
199 assert(left.type == INTEGER);
200 assert(right.type == INTEGER);
203 result.type = INTEGER;
204 result.instance.integer = left.instance.integer + right.instance.integer;
208 Object builtin$subtract(Object left, Object right)
210 assert(left.type == INTEGER);
211 assert(right.type == INTEGER);
214 result.type = INTEGER;
215 result.instance.integer = left.instance.integer - right.instance.integer;
219 Object builtin$multiply(Object left, Object right)
221 assert(left.type == INTEGER);
222 assert(right.type == INTEGER);
225 result.type = INTEGER;
226 result.instance.integer = left.instance.integer * right.instance.integer;
230 Object builtin$integerDivide(Object left, Object right)
232 assert(left.type == INTEGER);
233 assert(right.type == INTEGER);
236 result.type = INTEGER;
237 result.instance.integer = left.instance.integer / right.instance.integer;
241 Object builtin$modularDivide(Object left, Object right)
243 assert(left.type == INTEGER);
244 assert(right.type == INTEGER);
247 result.type = INTEGER;
248 result.instance.integer = left.instance.integer % right.instance.integer;
252 Object builtin$equals(Object left, Object right)
254 assert(left.type == INTEGER);
255 assert(right.type == INTEGER);
257 Object result = { BOOLEAN, left.instance.integer == right.instance.integer };
261 Object builtin$notEquals(Object left, Object right)
263 assert(left.type == INTEGER);
264 assert(right.type == INTEGER);
266 Object result = { BOOLEAN, left.instance.integer != right.instance.integer };
270 Object builtin$greaterThan(Object left, Object right)
272 assert(left.type == INTEGER);
273 assert(right.type == INTEGER);
275 Object result = { BOOLEAN, left.instance.integer > right.instance.integer };
279 Object builtin$lessThan(Object left, Object right)
281 assert(left.type == INTEGER);
282 assert(right.type == INTEGER);
284 Object result = { BOOLEAN, left.instance.integer < right.instance.integer };
288 Object builtin$greaterThanOrEqual(Object left, Object right)
290 assert(left.type == INTEGER);
291 assert(right.type == INTEGER);
293 Object result = { BOOLEAN, left.instance.integer >= right.instance.integer };
297 Object builtin$lessThanOrEqual(Object left, Object right)
299 assert(left.type == INTEGER);
300 assert(right.type == INTEGER);
302 Object result = { BOOLEAN, left.instance.integer <= right.instance.integer };
306 Object builtin$and(Object left, Object right)
308 assert(left.type == BOOLEAN);
309 assert(right.type == BOOLEAN);
311 Object result = { BOOLEAN, left.instance.boolean && right.instance.boolean };
315 Object builtin$or(Object left, Object right)
317 assert(left.type == BOOLEAN);
318 assert(right.type == BOOLEAN);
320 Object result = { BOOLEAN, left.instance.boolean || right.instance.boolean };
324 {% if 'pow' in builtins %}
325 Object builtin$pow(Object base, Object exponent)
327 assert(base.type == INTEGER);
328 assert(exponent.type == INTEGER);
331 result.type = INTEGER;
332 result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
337 {% if 'print' in builtins %}
338 void builtin$print(Object output)
343 fputs(output.instance.boolean ? "true" : "false", stdout);
347 printf("%" PRId32, output.instance.integer);
351 // Using fwrite instead of printf to handle size_t length
352 printf("%s", output.instance.string);
361 int main(int argc, char** argv)
363 Runtime* runtime = Runtime_construct();
364 Environment* environment = Environment_construct();
366 {% for statement in statements %}
370 Environment_destruct(environment);
371 Runtime_destruct(runtime);