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;
28 const char * const SYMBOL_LIST[] = {
29 {% for symbol in symbol_list %}
52 struct EnvironmentNode;
53 typedef struct EnvironmentNode EnvironmentNode;
54 struct EnvironmentNode
58 EnvironmentNode* next;
62 typedef struct Environment Environment;
65 EnvironmentNode* root;
68 Environment* Environment_construct()
70 // TODO Handle malloc returning NULL
71 Environment* result = malloc(sizeof(Environment));
76 void Environment_destruct(Environment* self)
78 EnvironmentNode* next;
79 for(EnvironmentNode* node = self->root; node != NULL; node = next)
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)
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)
91 EnvironmentNode* node = malloc(sizeof(EnvironmentNode));
94 node->next = self->root;
98 Object Environment_get(Environment* self, const char* const symbol)
100 for(EnvironmentNode* node = self->root; node != NULL; node = node->next)
102 // We can compare pointers because pointers are unique in the SYMBOLS_LIST
103 if(node->key == symbol)
109 // TODO Handle symbol errors
116 size_t permanentStringsLength;
117 size_t permanentStringsAllocated;
118 String** permanentStrings;
121 Runtime* Runtime_construct()
123 Runtime* result = malloc(sizeof(Runtime));
124 result->permanentStringsLength = 0;
125 result->permanentStringsAllocated = 0;
126 result->permanentStrings = NULL;
130 void Runtime_destruct(Runtime* self)
132 for(size_t i = 0; i < self->permanentStringsLength; i++)
134 free(self->permanentStrings[i]);
137 free(self->permanentStrings);
141 void Runtime_addPermanentString(Runtime* self, String* string)
143 // TODO Make this function thread-safe
144 if(self->permanentStringsLength == self->permanentStringsAllocated)
146 if(self->permanentStringsAllocated == 0)
148 self->permanentStringsAllocated = 8;
152 self->permanentStringsAllocated = self->permanentStringsAllocated * 2;
155 self->permanentStrings = realloc(
156 self->permanentStrings,
157 sizeof(String*) * self->permanentStringsAllocated
160 // TODO Handle realloc returning NULL
163 self->permanentStrings[self->permanentStringsLength] = string;
164 self->permanentStringsLength++;
167 Object integerLiteral(int32_t literal)
170 result.type = INTEGER;
171 result.instance.integer = literal;
175 Object stringLiteral(Runtime* runtime, const char* literal)
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);
184 result.type = STRING;
185 result.instance.string = resultString;
189 // TODO Make this conditionally added
190 Object builtin$negate(Object input)
192 assert(input.type == INTEGER);
195 result.type = INTEGER;
196 result.instance.integer = -input.instance.integer;
200 Object builtin$add(Object left, Object right)
202 assert(left.type == INTEGER);
203 assert(right.type == INTEGER);
206 result.type = INTEGER;
207 result.instance.integer = left.instance.integer + right.instance.integer;
211 Object builtin$subtract(Object left, Object right)
213 assert(left.type == INTEGER);
214 assert(right.type == INTEGER);
217 result.type = INTEGER;
218 result.instance.integer = left.instance.integer - right.instance.integer;
222 Object builtin$multiply(Object left, Object right)
224 assert(left.type == INTEGER);
225 assert(right.type == INTEGER);
228 result.type = INTEGER;
229 result.instance.integer = left.instance.integer * right.instance.integer;
233 Object builtin$integerDivide(Object left, Object right)
235 assert(left.type == INTEGER);
236 assert(right.type == INTEGER);
239 result.type = INTEGER;
240 result.instance.integer = left.instance.integer / right.instance.integer;
244 Object builtin$modularDivide(Object left, Object right)
246 assert(left.type == INTEGER);
247 assert(right.type == INTEGER);
250 result.type = INTEGER;
251 result.instance.integer = left.instance.integer % right.instance.integer;
255 {% if 'pow' in builtins %}
256 Object builtin$pow(Object base, Object exponent)
258 assert(base.type == INTEGER);
259 assert(exponent.type == INTEGER);
262 result.type = INTEGER;
263 result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
268 {% if 'print' in builtins %}
269 void builtin$print(Object output)
274 printf("%" PRId32, output.instance.integer);
278 // Using fwrite instead of printf to handle size_t length
279 fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout);
288 int main(int argc, char** argv)
290 Runtime* runtime = Runtime_construct();
291 Environment* environment = Environment_construct();
293 {% for statement in statements %}
297 Environment_destruct(environment);
298 Runtime_destruct(runtime);