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);
+}