A pretty featureful commit:
[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 'pow' in builtins %}
173 Object builtin$pow(Object base, Object exponent)
174 {
175   assert(base.type == INTEGER);
176   assert(exponent.type == INTEGER);
177
178   Object result;
179   result.type = INTEGER;
180   result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
181   return result;
182 }
183 {% endif %}
184
185 {% if 'print' in builtins %}
186 void builtin$print(Object output)
187 {
188   switch(output.type)
189   {
190     case INTEGER:
191       printf("%" PRId32, output.instance.integer);
192       break;
193
194     case STRING:
195       // Using fwrite instead of printf to handle size_t length
196       fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout);
197       break;
198
199     default:
200       assert(false);
201   }
202 }
203 {% endif %}
204
205 int main(int argc, char** argv)
206 {
207   Runtime* runtime = Runtime_construct();
208
209   {% for statement in statements %}
210   {{ statement }}
211   {% endfor %}
212
213   Runtime_destruct(runtime);
214
215   return 0;
216 }