Add a negation operator
[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$negate(Object input)
118 {
119   assert(input.type == INTEGER);
120
121   Object result;
122   result.type = INTEGER;
123   result.instance.integer = -input.instance.integer;
124   return result;
125 }
126
127 Object builtin$add(Object left, Object right)
128 {
129   assert(left.type == INTEGER);
130   assert(right.type == INTEGER);
131
132   Object result;
133   result.type = INTEGER;
134   result.instance.integer = left.instance.integer + right.instance.integer;
135   return result;
136 }
137
138 Object builtin$subtract(Object left, Object right)
139 {
140   assert(left.type == INTEGER);
141   assert(right.type == INTEGER);
142
143   Object result;
144   result.type = INTEGER;
145   result.instance.integer = left.instance.integer - right.instance.integer;
146   return result;
147 }
148
149 Object builtin$multiply(Object left, Object right)
150 {
151   assert(left.type == INTEGER);
152   assert(right.type == INTEGER);
153
154   Object result;
155   result.type = INTEGER;
156   result.instance.integer = left.instance.integer * right.instance.integer;
157   return result;
158 }
159
160 Object builtin$integerDivide(Object left, Object right)
161 {
162   assert(left.type == INTEGER);
163   assert(right.type == INTEGER);
164
165   Object result;
166   result.type = INTEGER;
167   result.instance.integer = left.instance.integer / right.instance.integer;
168   return result;
169 }
170
171 Object builtin$modularDivide(Object left, Object right)
172 {
173   assert(left.type == INTEGER);
174   assert(right.type == INTEGER);
175
176   Object result;
177   result.type = INTEGER;
178   result.instance.integer = left.instance.integer % right.instance.integer;
179   return result;
180 }
181
182 {% if 'pow' in builtins %}
183 Object builtin$pow(Object base, Object exponent)
184 {
185   assert(base.type == INTEGER);
186   assert(exponent.type == INTEGER);
187
188   Object result;
189   result.type = INTEGER;
190   result.instance.integer = pow(base.instance.integer, exponent.instance.integer);
191   return result;
192 }
193 {% endif %}
194
195 {% if 'print' in builtins %}
196 void builtin$print(Object output)
197 {
198   switch(output.type)
199   {
200     case INTEGER:
201       printf("%" PRId32, output.instance.integer);
202       break;
203
204     case STRING:
205       // Using fwrite instead of printf to handle size_t length
206       fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout);
207       break;
208
209     default:
210       assert(false);
211   }
212 }
213 {% endif %}
214
215 int main(int argc, char** argv)
216 {
217   Runtime* runtime = Runtime_construct();
218
219   {% for statement in statements %}
220   {{ statement }}
221   {% endfor %}
222
223   Runtime_destruct(runtime);
224
225   return 0;
226 }