2 c734c0e9 2021-08-03 op * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 c734c0e9 2021-08-03 op * Permission to use, copy, modify, and distribute this software for any
5 c734c0e9 2021-08-03 op * purpose with or without fee is hereby granted, provided that the above
6 c734c0e9 2021-08-03 op * copyright notice and this permission notice appear in all copies.
8 c734c0e9 2021-08-03 op * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 c734c0e9 2021-08-03 op * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 c734c0e9 2021-08-03 op * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 c734c0e9 2021-08-03 op * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 c734c0e9 2021-08-03 op * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 c734c0e9 2021-08-03 op * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 c734c0e9 2021-08-03 op * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 c734c0e9 2021-08-03 op #include "compat.h"
19 c734c0e9 2021-08-03 op #include <assert.h>
20 c734c0e9 2021-08-03 op #include <inttypes.h>
21 c734c0e9 2021-08-03 op #include <stdio.h>
22 c734c0e9 2021-08-03 op #include <stdlib.h>
23 c734c0e9 2021-08-03 op #include <string.h>
24 c734c0e9 2021-08-03 op #include <syslog.h>
26 c734c0e9 2021-08-03 op #include "utils.h"
27 c734c0e9 2021-08-03 op #include "script.h"
28 c734c0e9 2021-08-03 op #include "log.h"
30 c734c0e9 2021-08-03 op #define DEBUG 0
32 c734c0e9 2021-08-03 op static struct procs procs = TAILQ_HEAD_INITIALIZER(procs);
33 c734c0e9 2021-08-03 op static struct tests tests = TAILQ_HEAD_INITIALIZER(tests);
35 c734c0e9 2021-08-03 op static struct proc *curr_proc;
36 c734c0e9 2021-08-03 op static struct test *curr_test;
38 c734c0e9 2021-08-03 op static struct op *curr_block;
40 c734c0e9 2021-08-03 op static struct op *curr_argv;
41 c734c0e9 2021-08-03 op static int curr_argc;
43 c734c0e9 2021-08-03 op #define STACK_HEIGHT 16
44 c734c0e9 2021-08-03 op static struct value vstack[STACK_HEIGHT];
45 c734c0e9 2021-08-03 op static int stackh;
47 c734c0e9 2021-08-03 op static struct value v_false = {.type = V_NUM, .v = {.num = 0}};
48 c734c0e9 2021-08-03 op static struct value v_true = {.type = V_NUM, .v = {.num = 1}};
51 c734c0e9 2021-08-03 op global_set(char *sym, struct op *op)
53 c734c0e9 2021-08-03 op assert(op->type == OP_LITERAL);
57 c734c0e9 2021-08-03 op newop(int type)
59 c734c0e9 2021-08-03 op struct op *op;
61 c734c0e9 2021-08-03 op op = xcalloc(1, sizeof(*op));
62 c734c0e9 2021-08-03 op op->type = type;
68 c734c0e9 2021-08-03 op free_op(struct op *op)
70 c734c0e9 2021-08-03 op /* TODO: probably more... */
75 c734c0e9 2021-08-03 op op_assign(char *sym, struct op *expr)
77 c734c0e9 2021-08-03 op struct op *op;
79 c734c0e9 2021-08-03 op op = newop(OP_ASSIGN);
80 c734c0e9 2021-08-03 op op->v.assign.name = sym;
81 c734c0e9 2021-08-03 op op->v.assign.expr = expr;
87 c734c0e9 2021-08-03 op op_assert(struct op *expr)
89 c734c0e9 2021-08-03 op struct op *op;
91 c734c0e9 2021-08-03 op op = newop(OP_ASSERT);
92 c734c0e9 2021-08-03 op op->v.assert = expr;
98 c734c0e9 2021-08-03 op op_var(char *sym)
100 c734c0e9 2021-08-03 op struct op *op;
102 c734c0e9 2021-08-03 op op = newop(OP_VAR);
103 c734c0e9 2021-08-03 op op->v.var = sym;
109 c734c0e9 2021-08-03 op op_lit_str(char *str)
111 c734c0e9 2021-08-03 op struct op *op;
113 c734c0e9 2021-08-03 op op = newop(OP_LITERAL);
114 c734c0e9 2021-08-03 op op->v.literal.type = V_NUM;
115 c734c0e9 2021-08-03 op op->v.literal.v.str = str;
121 c734c0e9 2021-08-03 op op_lit_num(uint64_t n)
123 c734c0e9 2021-08-03 op struct op *op;
125 c734c0e9 2021-08-03 op op = newop(OP_LITERAL);
126 c734c0e9 2021-08-03 op op->v.literal.type = V_NUM;
127 c734c0e9 2021-08-03 op op->v.literal.v.num = n;
133 c734c0e9 2021-08-03 op op_cmp_eq(struct op *a, struct op *b)
135 c734c0e9 2021-08-03 op struct op *op;
137 c734c0e9 2021-08-03 op op = newop(OP_CMP_EQ);
138 c734c0e9 2021-08-03 op op->v.cmp_eq.a = a;
139 c734c0e9 2021-08-03 op op->v.cmp_eq.b = b;
145 c734c0e9 2021-08-03 op op_cast(struct op *expr, int totype)
147 c734c0e9 2021-08-03 op struct op *op;
149 c734c0e9 2021-08-03 op op = newop(OP_CAST);
150 c734c0e9 2021-08-03 op op->v.cast.expr = expr;
151 c734c0e9 2021-08-03 op op->v.cast.totype = totype;
157 c734c0e9 2021-08-03 op pp_val(struct value *val)
159 c734c0e9 2021-08-03 op switch (val->type) {
161 c734c0e9 2021-08-03 op printf("%s", val->v.str);
164 c734c0e9 2021-08-03 op printf("\"%s\"", val->v.str);
170 c734c0e9 2021-08-03 op printf("%"PRIu64, val->v.num);
173 c734c0e9 2021-08-03 op printf("<unknown value>");
179 c734c0e9 2021-08-03 op val_trueish(struct value *a)
181 c734c0e9 2021-08-03 op return a->type == V_NUM && a->v.num;
184 c734c0e9 2021-08-03 op static inline int
185 c734c0e9 2021-08-03 op val_isnum(struct value *a)
187 c734c0e9 2021-08-03 op return a->type == V_NUM
188 c734c0e9 2021-08-03 op || a->type == V_U8
189 c734c0e9 2021-08-03 op || a->type == V_U16
190 c734c0e9 2021-08-03 op || a->type == V_U32;
194 c734c0e9 2021-08-03 op val_eq(struct value *a, struct value *b)
196 c734c0e9 2021-08-03 op if (val_isnum(a) && val_isnum(b))
197 c734c0e9 2021-08-03 op return a->v.num == b->v.num;
199 c734c0e9 2021-08-03 op if (a->type != b->type)
202 c734c0e9 2021-08-03 op switch (a->type) {
205 c734c0e9 2021-08-03 op return !strcmp(a->v.str, b->v.str);
212 c734c0e9 2021-08-03 op pp_op(struct op *op)
214 c734c0e9 2021-08-03 op switch (op->type) {
215 c734c0e9 2021-08-03 op case OP_ASSIGN:
216 c734c0e9 2021-08-03 op printf("%s = ", op->v.assign.name);
217 c734c0e9 2021-08-03 op pp_op(op->v.assign.expr);
219 c734c0e9 2021-08-03 op case OP_ASSERT:
220 c734c0e9 2021-08-03 op printf("assert ");
221 c734c0e9 2021-08-03 op pp_op(op->v.assert);
223 c734c0e9 2021-08-03 op case OP_FUNCALL:
224 c734c0e9 2021-08-03 op printf("funcall()");
226 c734c0e9 2021-08-03 op case OP_LITERAL:
227 c734c0e9 2021-08-03 op pp_val(&op->v.literal);
230 c734c0e9 2021-08-03 op printf("%s", op->v.var);
232 c734c0e9 2021-08-03 op case OP_CAST:
233 c734c0e9 2021-08-03 op pp_op(op->v.cast.expr);
235 c734c0e9 2021-08-03 op switch (op->v.cast.totype) {
236 c734c0e9 2021-08-03 op case V_U8: printf("u8"); break;
237 c734c0e9 2021-08-03 op case V_U16: printf("u16"); break;
238 c734c0e9 2021-08-03 op case V_U32: printf("u32"); break;
239 c734c0e9 2021-08-03 op case V_STR: printf("str"); break;
240 c734c0e9 2021-08-03 op default: printf("???"); break;
243 c734c0e9 2021-08-03 op case OP_CMP_EQ:
244 c734c0e9 2021-08-03 op pp_op(op->v.cmp_eq.a);
245 c734c0e9 2021-08-03 op printf(" == ");
246 c734c0e9 2021-08-03 op pp_op(op->v.cmp_eq.b);
249 c734c0e9 2021-08-03 op printf(" ???[%d] ", op->type);
254 c734c0e9 2021-08-03 op pp_block(struct op *op)
256 c734c0e9 2021-08-03 op while (op != NULL) {
257 c734c0e9 2021-08-03 op printf("> ");
259 c734c0e9 2021-08-03 op printf("\n");
261 c734c0e9 2021-08-03 op op = op->next;
265 c734c0e9 2021-08-03 op static inline void
266 c734c0e9 2021-08-03 op popv(struct value *v)
268 c734c0e9 2021-08-03 op if (stackh == 0)
269 c734c0e9 2021-08-03 op errx(1, "can't pop the stack: underflow");
270 c734c0e9 2021-08-03 op memcpy(v, &vstack[--stackh], sizeof(*v));
273 c734c0e9 2021-08-03 op printf("popping "); pp_val(v); printf("\n");
277 c734c0e9 2021-08-03 op static inline void
278 c734c0e9 2021-08-03 op pushv(struct value *v)
280 c734c0e9 2021-08-03 op if (stackh == STACK_HEIGHT)
281 c734c0e9 2021-08-03 op errx(1, "can't push the stack: overflow");
284 c734c0e9 2021-08-03 op printf("pushing "); pp_val(v); printf("\n");
287 c734c0e9 2021-08-03 op memcpy(&vstack[stackh++], v, sizeof(*v));
290 c734c0e9 2021-08-03 op static inline void
291 c734c0e9 2021-08-03 op pushbool(int n)
293 c734c0e9 2021-08-03 op pushv(n ? &v_true : &v_false);
297 c734c0e9 2021-08-03 op eval(struct op *op)
299 c734c0e9 2021-08-03 op struct value a, b;
300 c734c0e9 2021-08-03 op struct proc *proc;
301 c734c0e9 2021-08-03 op struct op *t;
306 c734c0e9 2021-08-03 op printf("\n");
309 c734c0e9 2021-08-03 op switch (op->type) {
310 c734c0e9 2021-08-03 op case OP_ASSIGN:
311 c734c0e9 2021-08-03 op printf("TODO: assignment\n");
314 c734c0e9 2021-08-03 op case OP_ASSERT:
315 c734c0e9 2021-08-03 op if ((ret = eval(op->v.assert)) != TEST_PASSED)
318 c734c0e9 2021-08-03 op if (!val_trueish(&a)) {
319 c734c0e9 2021-08-03 op printf("assertion failed: ");
320 c734c0e9 2021-08-03 op pp_op(op->v.assert);
321 c734c0e9 2021-08-03 op printf("\n");
322 c734c0e9 2021-08-03 op return TEST_FAILED;
326 c734c0e9 2021-08-03 op case OP_FUNCALL:
327 c734c0e9 2021-08-03 op /* TODO: arity check! */
329 c734c0e9 2021-08-03 op for (i = 0; i < op->v.funcall.argc; ++i) {
330 c734c0e9 2021-08-03 op t = &op->v.funcall.argv[i];
331 c734c0e9 2021-08-03 op if ((ret = eval(t)) != TEST_PASSED)
335 c734c0e9 2021-08-03 op proc = op->v.funcall.proc;
336 c734c0e9 2021-08-03 op if (proc->nativefn != NULL)
337 c734c0e9 2021-08-03 op proc->nativefn(i);
338 c734c0e9 2021-08-03 op else if ((ret = eval(proc->body)) != TEST_PASSED)
342 c734c0e9 2021-08-03 op case OP_LITERAL:
343 c734c0e9 2021-08-03 op pushv(&op->v.literal);
347 c734c0e9 2021-08-03 op printf("TODO: load variable\n");
350 c734c0e9 2021-08-03 op case OP_CAST:
351 c734c0e9 2021-08-03 op printf("TODO: cast value\n");
354 c734c0e9 2021-08-03 op case OP_CMP_EQ:
355 c734c0e9 2021-08-03 op if ((ret = eval(op->v.cmp_eq.a)) != TEST_PASSED)
357 c734c0e9 2021-08-03 op if ((ret = eval(op->v.cmp_eq.b)) != TEST_PASSED)
362 c734c0e9 2021-08-03 op pushbool(val_eq(&a, &b));
370 c734c0e9 2021-08-03 op if (op->next)
371 c734c0e9 2021-08-03 op return eval(op->next);
372 c734c0e9 2021-08-03 op return TEST_PASSED;
376 c734c0e9 2021-08-03 op prepare_funcall(struct op *base)
378 c734c0e9 2021-08-03 op if (curr_argv != NULL)
379 c734c0e9 2021-08-03 op err(1, "can't funcall during funcall");
381 c734c0e9 2021-08-03 op curr_argv = base;
382 c734c0e9 2021-08-03 op curr_argc = 0;
386 c734c0e9 2021-08-03 op push_arg(struct op *op)
388 c734c0e9 2021-08-03 op curr_argv->next = op;
389 c734c0e9 2021-08-03 op curr_argv = op;
394 c734c0e9 2021-08-03 op op_funcall(struct proc *proc, struct op *base)
396 c734c0e9 2021-08-03 op struct op *op;
398 c734c0e9 2021-08-03 op op = newop(OP_FUNCALL);
399 c734c0e9 2021-08-03 op op->v.funcall.proc = proc;
400 c734c0e9 2021-08-03 op op->v.funcall.argv = base->next;
401 c734c0e9 2021-08-03 op op->v.funcall.argc = curr_argc;
403 c734c0e9 2021-08-03 op curr_argv = NULL;
409 c734c0e9 2021-08-03 op add_builtin_proc(const char *name, int (*fn)(int))
411 c734c0e9 2021-08-03 op struct proc *proc;
413 c734c0e9 2021-08-03 op proc = xcalloc(1, sizeof(*proc));
414 c734c0e9 2021-08-03 op proc->name = xstrdup(name);
415 c734c0e9 2021-08-03 op proc->nativefn = fn;
417 c734c0e9 2021-08-03 op TAILQ_INSERT_HEAD(&procs, proc, entry);
421 c734c0e9 2021-08-03 op prepare_proc(char *name)
423 c734c0e9 2021-08-03 op if (curr_proc != NULL)
424 c734c0e9 2021-08-03 op err(1, "can't recursively create a proc!");
426 c734c0e9 2021-08-03 op curr_proc = xcalloc(1, sizeof(*curr_proc));
427 c734c0e9 2021-08-03 op curr_proc->name = name;
429 c734c0e9 2021-08-03 op curr_argv = &curr_proc->tmp_args;
431 c734c0e9 2021-08-03 op curr_argv = NULL;
432 c734c0e9 2021-08-03 op curr_argc = 0;
436 c734c0e9 2021-08-03 op proc_setup_body(void)
438 c734c0e9 2021-08-03 op struct op *next, *op = curr_proc->tmp_args.next;
442 c734c0e9 2021-08-03 op while (op != NULL) {
443 c734c0e9 2021-08-03 op if (op->type != OP_VAR)
444 c734c0e9 2021-08-03 op errx(1, "invalid argument in proc definition: "
445 c734c0e9 2021-08-03 op "got type %d but want OP_VAR", op->type);
446 c734c0e9 2021-08-03 op assert(i < curr_argc && curr_argc < MAXWELEM);
447 c734c0e9 2021-08-03 op curr_proc->args[i] = xstrdup(op->v.var);
448 c734c0e9 2021-08-03 op next = op->next;
452 c734c0e9 2021-08-03 op curr_proc->minargs = curr_argc;
456 c734c0e9 2021-08-03 op proc_done(void)
458 c734c0e9 2021-08-03 op TAILQ_INSERT_HEAD(&procs, curr_proc, entry);
460 c734c0e9 2021-08-03 op curr_proc = NULL;
464 c734c0e9 2021-08-03 op block_push(struct op *op)
466 c734c0e9 2021-08-03 op if (curr_block == NULL) {
467 c734c0e9 2021-08-03 op curr_proc->body = op;
468 c734c0e9 2021-08-03 op curr_block = op;
470 c734c0e9 2021-08-03 op curr_block->next = op;
471 c734c0e9 2021-08-03 op curr_block = op;
475 c734c0e9 2021-08-03 op struct proc *
476 c734c0e9 2021-08-03 op proc_by_name(const char *name)
478 c734c0e9 2021-08-03 op struct proc *p;
480 c734c0e9 2021-08-03 op TAILQ_FOREACH(p, &procs, entry) {
481 c734c0e9 2021-08-03 op if (!strcmp(p->name, name))
489 c734c0e9 2021-08-03 op prepare_test(char *name, char *dir)
491 c734c0e9 2021-08-03 op assert(curr_test == NULL);
493 c734c0e9 2021-08-03 op prepare_proc(xstrdup("<test-internal>"));
495 c734c0e9 2021-08-03 op curr_test = xcalloc(1, sizeof(*curr_test));
496 c734c0e9 2021-08-03 op curr_test->name = name;
497 c734c0e9 2021-08-03 op curr_test->dir = dir;
498 c734c0e9 2021-08-03 op curr_test->proc = curr_proc;
502 c734c0e9 2021-08-03 op test_done(void)
504 c734c0e9 2021-08-03 op TAILQ_INSERT_HEAD(&tests, curr_test, entry);
505 c734c0e9 2021-08-03 op curr_test = NULL;
509 c734c0e9 2021-08-03 op builtin_dummy(int argc)
511 c734c0e9 2021-08-03 op printf("dummy! yay!\n");
516 c734c0e9 2021-08-03 op run_test(struct test *t)
519 c734c0e9 2021-08-03 op puts("=====================");
520 c734c0e9 2021-08-03 op pp_block(t->proc->body);
521 c734c0e9 2021-08-03 op puts("=====================");
524 c734c0e9 2021-08-03 op return eval(t->proc->body);
528 c734c0e9 2021-08-03 op main(int argc, char **argv)
530 c734c0e9 2021-08-03 op struct test *t;
531 c734c0e9 2021-08-03 op int i, passed = 0, failed = 0, skipped = 0;
533 c734c0e9 2021-08-03 op log_init(1, LOG_DAEMON);
534 c734c0e9 2021-08-03 op log_setverbose(1);
536 c734c0e9 2021-08-03 op add_builtin_proc("dummy", builtin_dummy);
538 c734c0e9 2021-08-03 op for (i = 1; i < argc; ++i)
539 c734c0e9 2021-08-03 op loadfile(argv[i]);
541 c734c0e9 2021-08-03 op TAILQ_FOREACH(t, &tests, entry) {
542 c734c0e9 2021-08-03 op switch (run_test(t)) {
543 c734c0e9 2021-08-03 op case TEST_PASSED: passed++; break;
544 c734c0e9 2021-08-03 op case TEST_FAILED: failed++; break;
545 c734c0e9 2021-08-03 op case TEST_SKIPPED: skipped++; break;
549 c734c0e9 2021-08-03 op printf("passed = %d\n", passed);
550 c734c0e9 2021-08-03 op printf("failed = %d\n", failed);
551 c734c0e9 2021-08-03 op printf("skipped = %d\n", skipped);
553 c734c0e9 2021-08-03 op return failed != 0;