Mercurial > repo
diff src/ploki/run.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ploki/run.c Fri Dec 20 22:18:50 2013 +0000 @@ -0,0 +1,458 @@ +#include "config.h" +#include "IO.h" +#include "Str.h" +#include "atechit.h" +#include "expr.h" +#include "hang.h" +#include "main.h" +#include "main_io.h" +#include "main_label.h" +#include "main_opt.h" +#include "run.h" +#include "stack.h" +#include "strhash.h" +#include "text.h" +#include "val.h" +#include "venus.h" +#include "xmalloc.h" +#include "zz.h" + +#include <ctype.h> +#include <errno.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <setjmp.h> + +struct Interp Interp; + +static void my_x_end(void) { + v_end(&Interp.arg); + v_end(&Interp.result); + + while (Interp.a.argc) { + --Interp.a.argc; + v_end(&Interp.a.argv[Interp.a.argc]); + } + xfree(Interp.a.argv); + + while (Interp.match.length) { + --Interp.match.length; + v_end(&Interp.match.matches[Interp.match.length]); + } + xfree(Interp.match.matches); + + xfree(Interp.m_start.index); + xfree(Interp.m_end.index); +} + +static void sp_nop(save_pair *sp) { + (void)sp; +} + +static void sp_writeback(save_pair *sp) { + v_set(sp->target, &sp->content); + v_end(&sp->content); +} + +ATTR_NORETURN +static void sp_error(const save_pair *x, const save_pair *y) { + (void)x; + (void)y; + NOTREACHED; +} + +stack_define(save_pair, extern, sp_nop, sp_writeback, sp_error) + +stack(save_pair) Saved; + +void stack_store(struct val *target, const struct val *value) { + save_pair *tos; + + stack_func(save_pair, pushnull)(&Saved); + tos = stack_func(save_pair, at)(&Saved, 0); + + tos->target = target; + v_iniset(&tos->content, target); + v_set(target, value); +} + +static void stack_store_del(struct val *target, struct val *value) { + stack_store(target, value); + v_delete(value); +} + +size_t depth_get(void) { + return stack_func(save_pair, size)(&Saved); +} + +void depth_restore(size_t n) { + assert(depth_get() >= n); + stack_func(save_pair, clear)(&Saved, depth_get() - n); +} + +struct val *execute(const struct op *op, struct val *arg) { + struct val *v; + const size_t curdepth = depth_get(); + + stack_store_del(&Interp.arg, arg); + + while (op) { + if (Opt.debug & DBG_OPS) { + fprintf(io_fp(Err), "op %d\n", op->type); + } + switch (op->type) { + case OP_NOP: + break; + + case OP_ASSIGN: + if (!op->arh.expr) { + eval_into(op->arg, &Interp.result); + } else { + switch (op->arh.expr->type) { + case varE: + eval_into(op->arg, op->arh.expr->v.val); + break; + + case varhashE: { + struct val *tmp; + eval_push(op->arg); + eval_push(op->arh.expr->right); + tmp = eval_pop(); + v = eval_pop(); + V_STR(tmp); + sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), v); + v_delete(tmp); + break; + } + + default: + NOTREACHED; + break; + } + } + break; + + case OP_CALL: + v = eval_expr(op->arg); + v = execute(op->arh.op, v); + v_set(&Interp.result, v); + v_delete(v); + break; + + case OP_CALL_BACK: { + struct op *tmp; + + v = eval_expr(op->arh.expr); + TOLABEL(v); + if (!(tmp = ve_findprev(&Venus, ko_str(v->ko), op->line))) { + v_delete(v); + hang(); + } + v_delete(v); + v = eval_expr(op->arg); + v = execute(tmp, v); + v_set(&Interp.result, v); + v_delete(v); + break; + } + + case OP_CALL_DYN: { + struct op *tmp; + + v = eval_expr(op->arg); + TOLABEL(v); + if (!(tmp = ve_findnext(&Venus, ko_str(v->ko), op->line))) { + v_delete(v); + hang(); + } + v_set_undef(v); + v = execute(tmp, v); + v_set(&Interp.result, v); + v_delete(v); + break; + } + + case OP_CLOSE: + v = eval_expr(op->arg); + if (V_EXT_P(v)) { + v_set_n(&Interp.result, io_close(v->magic.ext)); + } else { + v_set_n(&Interp.result, -1); + #ifdef EBADF + errno = EBADF; + #endif + } + v_delete(v); + break; + + case OP_EXIT: { + int tmp; + + v = eval_expr(op->arg); + V_NUM(v); + tmp = v->num >= 0.0 ? v->num + .5 : EXIT_FAILURE; + v_delete(v); + exit(tmp); + } + + case OP_FLUSH: + v = eval_expr(op->arg); + if (!V_EXT_P(v)) { + v_delete(v); + v_set_n(&Interp.result, EOF); + #ifdef EBADF + errno = EBADF; + #endif + break; + } + v_set_n(&Interp.result, io_flush(v->magic.ext)); + v_delete(v); + break; + + case OP_GOBACK: + v = eval_expr(op->arg); + TOLABEL(v); + if ((op = ve_findprev(&Venus, ko_str(v->ko), op->line))) { + v_delete(v); + continue; + } + v_delete(v); + hang(); + break; + + case OP_GOTO: + v = eval_expr(op->arg); + TOLABEL(v); + if ((op = ve_findnext(&Venus, ko_str(v->ko), op->line))) { + v_delete(v); + continue; + } + v_delete(v); + hang(); + break; + + case OP_ELSE: + case OP_HANG: + case OP_FI: + hang(); + break; + + case OP_IF: + v = eval_expr(op->arg); + if (v_true(v)) { + v_delete(v); + op = op->arh.op; + continue; + } + v_delete(v); + break; + + case OP_MODIFY: { + struct val *tmp = eval_expr(op->arg); + expr_pp(op->arh.expr->op, op->arh.expr->v.val, tmp); + v_delete(tmp); + break; + } + + case OP_PRINT: { + IO *fh; + + eval_push(op->arg); + if (!op->arh.expr) { + fh = io_incr(Out); + } else { + struct val *const tmp = eval_expr(op->arh.expr); + + if (V_EXT_P(tmp)) { + fh = io_incr(tmp->magic.ext); + } else { + v_delete(tmp); + v_delete(eval_pop()); + v_set_n(&Interp.result, -1); + #ifdef EBADF + errno = EBADF; + #endif + break; + } + v_delete(tmp); + } + v = eval_pop(); + V_STR(v); + v_set_n(&Interp.result, io_write_m(fh, ko_ptr(v->ko), ko_length(v->ko)) + 1u - 1.); + io_decr(fh); + v_delete(v); + break; + } + + case OP_PUTC: { + IO *fh; + + eval_push(op->arg); + if (!op->arh.expr) { + fh = io_incr(Out); + } else { + struct val *const tmp = eval_expr(op->arh.expr); + + if (V_EXT_P(tmp)) { + fh = io_incr(tmp->magic.ext); + } else { + v_delete(tmp); + v_delete(eval_pop()); + v_set_n(&Interp.result, -1); + #ifdef EBADF + errno = EBADF; + #endif + break; + } + v_delete(tmp); + } + v = eval_pop(); + V_NUM(v); + + v_set_n(&Interp.result, io_putc(fh, RINT(v->num))); + io_decr(fh); + v_delete(v); + break; + } + + case OP_RESET: + v = eval_expr(op->arg); + if (!V_EXT_P(v)) { + v_delete(v); + v_set_n(&Interp.result, EOF); + #ifdef EBADF + errno = EBADF; + #endif + break; + } + io_clearerr(v->magic.ext); + v_delete(v); + break; + + case OP_RETURN: + if (op->arg->type == unopE && op->arg->op == F_CALL) { + eval_into(op->arg->right, &Interp.arg); + op = op->arg->left.op; + continue; + } + v = eval_expr(op->arg); + depth_restore(curdepth); + return v; + + case OP_SET_VAL: + switch (op->arh.expr->type) { + case varE: + v_set(op->arh.expr->v.val, op->arg->v.val); + break; + + case varhashE: { + struct val *const tmp = eval_expr(op->arh.expr->right); + struct val *const val = v_undef(); + V_STR(tmp); + v_set(val, op->arg->v.val); + sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), val); + v_delete(tmp); + break; + } + + default: + NOTREACHED; + break; + } + break; + + case OP_SYSTEM: + v = eval_expr(op->arg); + V_STR(v); + v_set_n(&Interp.result, system(ko_szp(v->ko))); + v_delete(v); + break; + + case OP_TEMP: + eval_push(op->arg); + if (!op->arh.expr) { + v_delete(eval_pop()); + } else switch (op->arh.expr->type) { + case varE: + stack_store_del(op->arh.expr->v.val, eval_pop()); + break; + + case varhashE: { + struct val *addr; + struct val *const tmp = eval_expr(op->arh.expr->right); + v = eval_pop(); + V_STR(tmp); + if (!(addr = sh_get(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko)))) { + sh_put(op->arh.expr->v.hash, ko_ptr(tmp->ko), ko_length(tmp->ko), addr = v_undef()); + } + v_delete(tmp); + stack_store_del(addr, v); + break; + } + + default: + NOTREACHED; + } + break; + + case OP_THROW: + v = eval_expr(op->arg); + if (!depth_get()) { + V_STR(v); + if (ko_at(v->ko, ko_length(v->ko) - 1u) == '\n') { + io_write_m(Err, ko_ptr(v->ko), ko_length(v->ko)); + } else { + fprintf(io_fp(Err), "%s: uncaught exception: ", Prog); + io_write_m(Err, ko_ptr(v->ko), ko_length(v->ko)); + putc('\n', io_fp(Err)); + } + v_delete(v); + exit(EXIT_FAILURE); + } + v_set(&Interp.result, v); + v_delete(v); + longjmp(stack_func(t_context, at)(&Context, 0)->buf, 1); + break; + } + op = op->next; + } + + exit(0); +} + +static void cleanup(void) { + stack_func(save_pair, end)(&Saved); +} + +void run(const struct text *t, size_t argc, char **argv) { + int status; + struct val *result; + + v_init(&Interp.arg); + v_init(&Interp.result); + + Interp.a.argv = xmalloc(argc, sizeof *Interp.a.argv); + for (Interp.a.argc = 0; Interp.a.argc < argc; ++Interp.a.argc) { + struct val *const tmp = &Interp.a.argv[Interp.a.argc]; + v_init(tmp); + v_set_m(tmp, argv[Interp.a.argc], strlen(argv[Interp.a.argc])); + } + + Interp.match.matches = xmalloc(Interp.match.size = 2, sizeof *Interp.match.matches); + Interp.match.length = 0; + + Interp.m_start.index = xmalloc(Interp.m_start.size = 0, sizeof *Interp.m_start.index); + Interp.m_end.index = xmalloc(Interp.m_end.size = 0, sizeof *Interp.m_end.index); + + stack_func(save_pair, init)(&Saved); + atechit(cleanup); + atechit(my_x_end); + + result = execute(t->start[0], v_undef()); + V_NUM(result); + status = result->num >= 0.0 ? result->num + .5 : EXIT_FAILURE; + v_delete(result); + exit(status); +}