Add an integration test to ensure left recursive parsing of math works
[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 enum Type
29 {
30   INTEGER,
31   STRING
32 };
33
34 union Instance
35 {
36   int32_t integer;
37   String* string;
38 };
39
40 struct Object
41 {
42   Type type;
43   Instance instance;
44 };
45
46 struct Runtime
47 {
48   size_t permanentStringsLength;
49   size_t permanentStringsAllocated;
50   String** permanentStrings;
51 };
52
53 Runtime* Runtime_construct()
54 {
55   Runtime* result = malloc(sizeof(Runtime));
56   result->permanentStringsLength = 0;
57   result->permanentStringsAllocated = 0;
58   result->permanentStrings = NULL;
59   return result;
60 }
61
62 void Runtime_destruct(Runtime* self)
63 {
64   free(self->permanentStrings);
65   free(self);
66 }
67
68 void Runtime_addPermanentString(Runtime* self, String* string)
69 {
70   // TODO Make this function thread-safe
71   if(self->permanentStringsLength == self->permanentStringsAllocated)
72   {
73     if(self->permanentStringsAllocated == 0)
74     {
75       self->permanentStringsAllocated = 8;
76     }
77     else
78     {
79       self->permanentStringsAllocated = self->permanentStringsAllocated * 2;
80     }
81
82     self->permanentStrings = realloc(
83       self->permanentStrings,
84       sizeof(String*) * self->permanentStringsAllocated
85     );
86
87     // TODO Handle realloc returning NULL
88   }
89
90   self->permanentStrings[self->permanentStringsLength] = string;
91   self->permanentStringsLength++;
92 }
93
94 Object integerLiteral(int32_t literal)
95 {
96   Object result;
97   result.type = INTEGER;
98   result.instance.integer = literal;
99   return result;
100 }
101
102 Object stringLiteral(Runtime* runtime, const char* literal)
103 {
104   String* resultString = malloc(sizeof(String));
105   resultString->length = strlen(literal);
106   resultString->characters = malloc(resultString->length);
107   memcpy(resultString->characters, literal, resultString->length);
108   Runtime_addPermanentString(runtime, resultString);
109
110   Object result;
111   result.type = STRING;
112   result.instance.string = resultString;
113   return result;
114 }
115
116 // TODO Make this conditionally added
117 Object builtin$add(Object left, Object right)
118 {
119   assert(left.type == INTEGER);
120   assert(right.type == INTEGER);
121
122   Object result;
123   result.type = INTEGER;
124   result.instance.integer = left.instance.integer + right.instance.integer;
125   return result;
126 }
127
128 Object builtin$subtract(Object left, Object right)
129 {
130   assert(left.type == INTEGER);
131   assert(right.type == INTEGER);
132
133   Object result;
134   result.type = INTEGER;
135   result.instance.integer = left.instance.integer - right.instance.integer;
136   return result;
137 }
138
139 Object builtin$multiply(Object left, Object right)
140 {
141   assert(left.type == INTEGER);
142   assert(right.type == INTEGER);
143
144   Object result;
145   result.type = INTEGER;
146   result.instance.integer = left.instance.integer * right.instance.integer;
147   return result;
148 }
149
150 Object builtin$integerDivide(Object left, Object right)
151 {
152   assert(left.type == INTEGER);
153   assert(right.type == INTEGER);
154
155   Object result;
156   result.type = INTEGER;
157   result.instance.integer = left.instance.integer / right.instance.integer;
158   return result;
159 }
160
161 Object builtin$modularDivide(Object left, Object right)
162 {
163   assert(left.type == INTEGER);
164   assert(right.type == INTEGER);
165
166   Object result;
167   result.type = INTEGER;
168   result.instance.integer = left.instance.integer % right.instance.integer;
169   return result;
170 }
171
172 {% if 'print' in builtins %}
173 void builtin$print(Object output)
174 {
175   switch(output.type)
176   {
177     case INTEGER:
178       printf("%" PRId32, output.instance.integer);
179       break;
180
181     case STRING:
182       // Using fwrite instead of printf to handle size_t length
183       fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout);
184       break;
185
186     default:
187       assert(false);
188   }
189 }
190 {% endif %}
191
192 int main(int argc, char** argv)
193 {
194   Runtime* runtime = Runtime_construct();
195
196   {% for statement in statements %}
197   {{ statement }}
198   {% endfor %}
199
200   Runtime_destruct(runtime);
201
202   return 0;
203 }