1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
|
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "eval.h"
#define DEPTH_MAX 32
#define PARAMETERS_MAX 8
static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out);
static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out);
static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out);
void machine_init(struct Machine* machine)
{
memset(machine, 0, sizeof *machine);
}
static struct Variable* find_variable(struct Machine* machine, const char* name)
{
for (size_t index = 0; index < VARIABLES_MAX; index++)
{
struct Variable* variable = &machine->variables[index];
if (variable->declared && strcmp(variable->name, name) == 0)
return variable;
}
return NULL;
}
static bool bind_variable(struct Machine* machine, const char* name, int64_t value)
{
for (size_t index = 0; index < VARIABLES_MAX; index++)
{
struct Variable* variable = &machine->variables[index];
if (variable->declared)
continue;
(void)snprintf(variable->name, sizeof variable->name, "%s", name);
variable->value = value;
variable->declared = true;
return true;
}
return false;
}
static struct Function* find_function(struct Machine* machine, const char* name)
{
for (size_t index = 0; index < FUNCTIONS_MAX; index++)
{
struct Function* function = &machine->functions[index];
if (function->defined && strcmp(function->name, name) == 0)
return function;
}
return NULL;
}
static int complain(const struct Node* node, const char* message)
{
(void)fprintf(stderr, "line %d: %s\n", node->line, message);
return 1;
}
static int evaluate_operands(struct Machine* machine, const struct Node* node, int64_t* left,
int64_t* right)
{
if (evaluate_value(machine, node->first, left))
return 1;
return evaluate_value(machine, node->second, right);
}
static int evaluate_value(struct Machine* machine, const struct Node* node, int64_t* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type type;
struct Variable* variable = NULL;
bool truth = false;
switch (node->kind)
{
case VALUE_DIFFERENCE:
*out = (int64_t)node->first->character - (int64_t)node->second->character;
return 0;
case VALUE_SUM:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left + right;
return 0;
case VALUE_PRODUCT:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left * right;
return 0;
case VALUE_QUOTIENT:
if (evaluate_operands(machine, node, &left, &right))
return 1;
if (right == 0)
return complain(node, "division by zero");
*out = left / right;
return 0;
case VALUE_EXTENT:
case VALUE_TUPLE_SIZE:
if (evaluate_type(machine, node->first, &type))
return 1;
*out = type.kind == KIND_ARRAY ? type.number : 0;
return 0;
case VALUE_INTEGRAL_CONSTANT: return evaluate_value(machine, node->first, out);
case VALUE_VARIABLE:
variable = find_variable(machine, node->name);
if (variable == NULL)
return complain(node, "that name was never declared");
*out = variable->value;
return 0;
case VALUE_DECLVAL:
if (evaluate_type(machine, node->first, &type))
return 1;
if (type.kind != KIND_VALUE)
return complain(node, "declval of a type with no value in it, what did you expect");
*out = type.number;
return 0;
case VALUE_CONDITIONAL:
if (evaluate_condition(machine, node->first, &truth))
return 1;
return evaluate_value(machine, truth ? node->second : node->third, out);
default: break;
}
assert(!"the parser handed a non-value where a value goes");
return 1;
}
static bool render(const struct Type* type, char* buffer, size_t size)
{
int written = 0;
switch (type->kind)
{
case KIND_VOID: written = snprintf(buffer, size, "%s", ""); break;
case KIND_INT32: written = snprintf(buffer, size, "int32_t"); break;
case KIND_BYTE: written = snprintf(buffer, size, "byte"); break;
case KIND_SIZE: written = snprintf(buffer, size, "size_t"); break;
case KIND_ARRAY:
written = snprintf(buffer, size, "array[%" PRId64 "]", type->number);
break;
case KIND_CHAR: written = snprintf(buffer, size, "char"); break;
case KIND_CHAR_CONSTANT: written = snprintf(buffer, size, "%c", (char)type->number); break;
case KIND_VALUE: written = snprintf(buffer, size, "%" PRId64, type->number); break;
case KIND_TUPLE: written = snprintf(buffer, size, "%s", type->text); break;
}
return written < 0 || (size_t)written >= size;
}
static int evaluate_tuple(struct Machine* machine, const struct Node* node, struct Type* out)
{
out->kind = KIND_TUPLE;
size_t used = 0;
for (const struct Node* element = node->first; element != NULL; element = element->next)
{
struct Type inner;
if (evaluate_type(machine, element, &inner))
return 1;
if (render(&inner, out->text + used, sizeof out->text - used))
return complain(node, "that tuple is too much to say in one breath");
used = strlen(out->text);
}
return 0;
}
static int invoke(struct Machine* machine, const struct Node* node, struct Type* out)
{
struct Function* function = find_function(machine, node->name);
if (function == NULL)
return complain(node, "no such function, define it first, like everything else");
if (machine->depth >= DEPTH_MAX)
return complain(node, "too deep, this was never meant to scale");
struct Type arguments[PARAMETERS_MAX];
size_t count = 0;
const struct Node* parameter = function->node->first;
const struct Node* argument = node->first;
while (parameter != NULL && argument != NULL)
{
if (count == PARAMETERS_MAX)
return complain(node, "too many arguments, nobody needs that many");
if (evaluate_type(machine, argument, &arguments[count]))
return 1;
if (arguments[count].kind != KIND_VALUE)
return complain(argument, "an argument carries a value, decltype it");
count++;
parameter = parameter->next;
argument = argument->next;
}
if (parameter != NULL || argument != NULL)
return complain(node, "wrong number of arguments, count them again");
struct Variable saved[VARIABLES_MAX];
memcpy(saved, machine->variables, sizeof saved);
memset(machine->variables, 0, sizeof machine->variables);
parameter = function->node->first;
for (size_t index = 0; index < count; index++)
{
(void)bind_variable(machine, parameter->name, arguments[index].number);
parameter = parameter->next;
}
machine->depth++;
enum RunStatus status = execute(machine, function->node->body);
machine->depth--;
memcpy(machine->variables, saved, sizeof saved);
if (status == RUN_FAILED)
return 1;
if (status == RUN_RETURNED)
*out = machine->returned;
else
{
out->kind = KIND_VOID;
out->number = 0;
out->text[0] = '\0';
}
return 0;
}
static int evaluate_type(struct Machine* machine, const struct Node* node, struct Type* out)
{
out->kind = KIND_VOID;
out->number = 0;
out->text[0] = '\0';
struct Type element;
bool truth = false;
switch (node->kind)
{
case TYPE_VOID: return 0;
case TYPE_INT32: out->kind = KIND_INT32; return 0;
case TYPE_BYTE: out->kind = KIND_BYTE; return 0;
case TYPE_SIZE: out->kind = KIND_SIZE; return 0;
case TYPE_CHAR: out->kind = KIND_CHAR; return 0;
case TYPE_TUPLE: return evaluate_tuple(machine, node, out);
case TYPE_INVOKE: return invoke(machine, node, out);
case TYPE_CHAR_CONSTANT:
if (evaluate_value(machine, node->first, &out->number))
return 1;
out->kind = KIND_CHAR_CONSTANT;
return 0;
case TYPE_REMOVE_CV: return evaluate_type(machine, node->first, out);
case TYPE_ARRAY:
if (evaluate_type(machine, node->first, &element) ||
evaluate_value(machine, node->second, &out->number))
return 1;
out->kind = KIND_ARRAY;
return 0;
case TYPE_CONDITIONAL:
if (evaluate_condition(machine, node->first, &truth))
return 1;
return evaluate_type(machine, truth ? node->second : node->third, out);
case TYPE_DECLTYPE:
if (evaluate_value(machine, node->first, &out->number))
return 1;
out->kind = KIND_VALUE;
return 0;
default: break;
}
assert(!"the parser handed a non-type where a type goes");
return 1;
}
static bool same_type(const struct Type* left, const struct Type* right)
{
return left->kind == right->kind && left->number == right->number &&
strcmp(left->text, right->text) == 0;
}
static int evaluate_condition(struct Machine* machine, const struct Node* node, bool* out)
{
int64_t left = 0;
int64_t right = 0;
struct Type left_type;
struct Type right_type;
*out = false;
switch (node->kind)
{
case COND_TRUE: *out = true; return 0;
case COND_FALSE: return 0;
case COND_IS_SAME:
if (evaluate_type(machine, node->first, &left_type) ||
evaluate_type(machine, node->second, &right_type))
return 1;
*out = same_type(&left_type, &right_type);
return 0;
case COND_EQUAL:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left == right;
return 0;
case COND_LESS:
if (evaluate_operands(machine, node, &left, &right))
return 1;
*out = left < right;
return 0;
default: break;
}
assert(!"the parser handed a non-condition where a condition goes");
return 1;
}
static enum RunStatus declare(struct Machine* machine, const struct Node* node)
{
if (find_variable(machine, node->name) != NULL)
{
(void)complain(node, "already declared, and there is no changing that");
return RUN_FAILED;
}
struct Type type;
if (evaluate_type(machine, node->first, &type))
return RUN_FAILED;
if (type.kind != KIND_VALUE)
{
(void)complain(node, "that type carries no value, decltype something");
return RUN_FAILED;
}
if (!bind_variable(machine, node->name, type.number))
{
(void)complain(node, "too many variables, this was never meant to scale");
return RUN_FAILED;
}
return RUN_DONE;
}
static enum RunStatus undeclare(struct Machine* machine, const struct Node* node)
{
struct Variable* variable = find_variable(machine, node->name);
if (variable == NULL)
{
(void)complain(node, "cannot undeclare what was never declared");
return RUN_FAILED;
}
variable->declared = false;
return RUN_DONE;
}
static enum RunStatus emit(struct Machine* machine, const struct Node* node)
{
struct Type type;
if (evaluate_type(machine, node->first, &type))
return RUN_FAILED;
if (type.kind == KIND_VOID)
return RUN_DONE;
char text[TEXT_LENGTH_MAX + 1];
if (render(&type, text, sizeof text))
{
(void)complain(node, "that is too much to say in one breath");
return RUN_FAILED;
}
(void)printf("%s\n", text);
return RUN_DONE;
}
static enum RunStatus enable_if(struct Machine* machine, const struct Node* node)
{
bool truth = false;
if (evaluate_condition(machine, node->first, &truth))
return RUN_FAILED;
if (!truth)
return RUN_DONE;
return execute(machine, node->body);
}
static enum RunStatus repeat(struct Machine* machine, const struct Node* node)
{
int64_t count = 0;
if (evaluate_value(machine, node->first, &count))
return RUN_FAILED;
for (int64_t index = 0; index < count; index++)
{
enum RunStatus status = execute(machine, node->body);
if (status != RUN_DONE)
return status;
}
return RUN_DONE;
}
static enum RunStatus static_assert_statement(struct Machine* machine, const struct Node* node)
{
bool truth = false;
if (evaluate_condition(machine, node->first, &truth))
return RUN_FAILED;
if (!truth)
{
(void)complain(node, "static assertion failed, at runtime, which is the best time");
return RUN_FAILED;
}
return RUN_DONE;
}
static enum RunStatus define(struct Machine* machine, const struct Node* node)
{
if (find_function(machine, node->name) != NULL)
{
(void)complain(node, "already defined, functions are forever");
return RUN_FAILED;
}
for (size_t index = 0; index < FUNCTIONS_MAX; index++)
{
struct Function* function = &machine->functions[index];
if (function->defined)
continue;
(void)snprintf(function->name, sizeof function->name, "%s", node->name);
function->node = node;
function->defined = true;
return RUN_DONE;
}
(void)complain(node, "too many functions, this was never meant to scale");
return RUN_FAILED;
}
static enum RunStatus return_statement(struct Machine* machine, const struct Node* node)
{
if (machine->depth == 0)
{
(void)complain(node, "return from what, exactly");
return RUN_FAILED;
}
if (evaluate_type(machine, node->first, &machine->returned))
return RUN_FAILED;
return RUN_RETURNED;
}
static enum RunStatus execute_one(struct Machine* machine, const struct Node* node)
{
switch (node->kind)
{
case STMT_DECLARE: return declare(machine, node);
case STMT_UNDECLARE: return undeclare(machine, node);
case STMT_ENABLE_IF: return enable_if(machine, node);
case STMT_REPEAT: return repeat(machine, node);
case STMT_EMIT: return emit(machine, node);
case STMT_STATIC_ASSERT: return static_assert_statement(machine, node);
case STMT_DEFINE: return define(machine, node);
case STMT_RETURN: return return_statement(machine, node);
default: break;
}
assert(!"the parser handed a non-statement where a statement goes");
return RUN_FAILED;
}
enum RunStatus execute(struct Machine* machine, const struct Node* statement)
{
while (statement != NULL)
{
enum RunStatus status = execute_one(machine, statement);
if (status != RUN_DONE)
return status;
statement = statement->next;
}
return RUN_DONE;
}
|