2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 static struct procs procs = TAILQ_HEAD_INITIALIZER(procs);
33 static struct tests tests = TAILQ_HEAD_INITIALIZER(tests);
35 static struct opstacks blocks = TAILQ_HEAD_INITIALIZER(blocks);
36 static struct opstacks args = TAILQ_HEAD_INITIALIZER(args);
38 #define STACK_HEIGHT 16
39 static struct value vstack[STACK_HEIGHT];
42 static struct value v_false = {.type = V_NUM, .v = {.num = 0}};
43 static struct value v_true = {.type = V_NUM, .v = {.num = 1}};
45 static inline struct opstack *
46 pushstack(struct opstacks *stack)
50 ops = xcalloc(1, sizeof(*ops));
51 TAILQ_INSERT_HEAD(stack, ops, entry);
55 static inline struct opstack *
56 peek(struct opstacks *stack)
58 if (TAILQ_EMPTY(stack))
59 errx(1, "%s: args underflow", __func__);
61 return TAILQ_FIRST(stack);
64 static inline struct op *
65 finalize(struct opstacks *stack, int *argc)
70 if (TAILQ_EMPTY(stack))
71 errx(1, "%s: args underflow", __func__);
74 TAILQ_REMOVE(&args, ops, entry);
85 push(struct opstacks *stack, struct op *op)
90 if (ops->last == NULL) {
102 global_set(char *sym, struct op *op)
104 assert(op->type == OP_LITERAL);
112 op = xcalloc(1, sizeof(*op));
119 free_op(struct op *op)
121 /* TODO: probably more... */
126 op_assign(char *sym, struct op *expr)
130 op = newop(OP_ASSIGN);
131 op->v.assign.name = sym;
132 op->v.assign.expr = expr;
138 op_assert(struct op *expr)
142 op = newop(OP_ASSERT);
160 op_lit_str(char *str)
164 op = newop(OP_LITERAL);
165 op->v.literal.type = V_NUM;
166 op->v.literal.v.str = str;
172 op_lit_num(uint64_t n)
176 op = newop(OP_LITERAL);
177 op->v.literal.type = V_NUM;
178 op->v.literal.v.num = n;
184 op_cmp_eq(struct op *a, struct op *b)
188 op = newop(OP_CMP_EQ);
196 op_cast(struct op *expr, int totype)
201 op->v.cast.expr = expr;
202 op->v.cast.totype = totype;
208 ppf_val(FILE *f, struct value *val)
212 fprintf(f, "%s", val->v.str);
215 fprintf(f, "\"%s\"", val->v.str);
221 fprintf(f, "%"PRIu64, val->v.num);
224 fprintf(f, "<unknown value>");
230 pp_val(struct value *val)
232 ppf_val(stdout, val);
236 val_trueish(struct value *a)
238 return a->type == V_NUM && a->v.num;
242 val_isnum(struct value *a)
244 return a->type == V_NUM
251 val_eq(struct value *a, struct value *b)
253 if (val_isnum(a) && val_isnum(b))
254 return a->v.num == b->v.num;
256 if (a->type != b->type)
262 return !strcmp(a->v.str, b->v.str);
268 static inline const char *
269 pp_totype(int totype)
272 * Not all of these are valid cast type thought, including
273 * every possibility only to aid debugging.
276 case V_STR: return "str";
277 case V_SYM: return "sym";
278 case V_NUM: return "num";
279 case V_QID: return "qid";
280 case V_U8: return "u8";
281 case V_U16: return "u16";
282 case V_U32: return "u32";
283 default: return "unknown";
288 val_cast(struct value *a, int totype)
292 #define NUMCAST(v, totype, max) do { \
294 fprintf(stderr, "Can't cast %"PRIu64 \
295 " to %s\n", v, pp_totype(totype)); \
303 fprintf(stderr, "Can't cast ");
305 fprintf(stderr, " to type %s\n", pp_totype(totype));
311 case V_U8: NUMCAST(v, totype, UINT8_MAX);
312 case V_U16: NUMCAST(v, totype, UINT16_MAX);
313 case V_U32: NUMCAST(v, totype, UINT32_MAX);
315 fprintf(stderr, "Can't cast %"PRIu64" to %s\n",
316 v, pp_totype(totype));
328 printf("%s = ", op->v.assign.name);
329 pp_op(op->v.assign.expr);
339 pp_val(&op->v.literal);
342 printf("%s", op->v.var);
345 pp_op(op->v.cast.expr);
347 switch (op->v.cast.totype) {
348 case V_U8: printf("u8"); break;
349 case V_U16: printf("u16"); break;
350 case V_U32: printf("u32"); break;
351 case V_STR: printf("str"); break;
352 default: printf("???"); break;
356 pp_op(op->v.cmp_eq.a);
358 pp_op(op->v.cmp_eq.b);
361 printf(" ???[%d] ", op->type);
366 pp_block(struct op *op)
378 popv(struct value *v)
381 errx(1, "can't pop the stack: underflow");
382 memcpy(v, &vstack[--stackh], sizeof(*v));
385 printf("popping "); pp_val(v); printf("\n");
390 pushv(struct value *v)
392 if (stackh == STACK_HEIGHT)
393 errx(1, "can't push the stack: overflow");
396 printf("pushing "); pp_val(v); printf("\n");
399 memcpy(&vstack[stackh++], v, sizeof(*v));
405 pushv(n ? &v_true : &v_false);
423 printf("TODO: assignment\n");
427 if ((ret = eval(op->v.assert)) != EVAL_OK)
430 if (!val_trueish(&a)) {
431 printf("assertion failed: ");
439 /* TODO: arity check! */
441 for (i = 0; i < op->v.funcall.argc; ++i) {
442 t = &op->v.funcall.argv[i];
443 if ((ret = eval(t)) != EVAL_OK)
447 proc = op->v.funcall.proc;
448 if (proc->nativefn != NULL)
450 else if ((ret = eval(proc->body)) != EVAL_OK)
455 pushv(&op->v.literal);
459 printf("TODO: load variable\n");
463 if ((ret = eval(op->v.cast.expr)) != EVAL_OK)
466 if ((ret = val_cast(&a, op->v.cast.totype)) != EVAL_OK)
472 if ((ret = eval(op->v.cmp_eq.a)) != EVAL_OK)
474 if ((ret = eval(op->v.cmp_eq.b)) != EVAL_OK)
479 pushbool(val_eq(&a, &b));
484 fprintf(stderr, "invalid op, aborting.\n");
489 return eval(op->next);
494 prepare_funcall(void)
500 push_arg(struct op *op)
506 op_funcall(struct proc *proc)
508 struct op *op, *argv;
511 argv = finalize(&args, &argc);
513 op = newop(OP_FUNCALL);
514 op->v.funcall.proc = proc;
515 op->v.funcall.argv = argv;
516 op->v.funcall.argc = argc;
522 add_builtin_proc(const char *name, int (*fn)(int))
526 proc = xcalloc(1, sizeof(*proc));
527 proc->name = xstrdup(name);
530 TAILQ_INSERT_HEAD(&procs, proc, entry);
540 proc_setup_body(void)
542 struct opstack *argv;
547 for (i = 0, op = argv->base.next; op != NULL; i++) {
549 * TODO: should free the whole list but.., we're gonna
550 * exit real soon(tm)!
552 if (op->type != OP_VAR)
558 assert(i == argv->counter);
564 proc_done(char *name)
567 struct op *op, *next, *argv, *body;
570 argv = finalize(&args, &argc);
571 body = finalize(&blocks, NULL);
573 proc = xcalloc(1, sizeof(*proc));
575 proc->minargs = argc;
577 for (i = 0, op = argv; op != NULL; ++i) {
578 proc->args[i] = xstrdup(op->v.var);
588 TAILQ_INSERT_HEAD(&procs, proc, entry);
592 block_push(struct op *op)
598 proc_by_name(const char *name)
602 TAILQ_FOREACH(p, &procs, entry) {
603 if (!strcmp(p->name, name))
617 test_done(char *name, char *dir)
621 test = xcalloc(1, sizeof(*test));
624 test->body = finalize(&blocks, NULL);
626 if (TAILQ_EMPTY(&tests))
627 TAILQ_INSERT_HEAD(&tests, test, entry);
629 TAILQ_INSERT_TAIL(&tests, test, entry);
633 builtin_dummy(int argc)
635 printf("dummy! yay!\n");
640 run_test(struct test *t)
643 puts("=====================");
645 puts("=====================");
648 return eval(t->body);
652 main(int argc, char **argv)
655 int i, passed = 0, failed = 0, skipped = 0;
657 log_init(1, LOG_DAEMON);
660 add_builtin_proc("dummy", builtin_dummy);
662 for (i = 1; i < argc; ++i)
666 TAILQ_FOREACH(t, &tests, entry) {
667 printf("===> running test \"%s\"... ", t->name);
670 switch (run_test(t)) {
677 /* we've already printed the failure */
681 printf("skipped!\n");
689 printf("passed %d/%d\n", passed, i);
690 printf("failed %d\n", failed);
691 printf("skipped %d\n", skipped);