summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c82
-rw-r--r--eval.h1
-rw-r--r--unwind.c28
-rw-r--r--unwind.h13
4 files changed, 108 insertions, 16 deletions
diff --git a/eval.c b/eval.c
index 62841f6e..9a635371 100644
--- a/eval.c
+++ b/eval.c
@@ -114,6 +114,21 @@ val make_env(val vbindings, val fbindings, val up_env)
return env;
}
+val copy_env(val oenv)
+{
+ type_check(oenv, ENV);
+
+ {
+ val nenv = make_obj();
+
+ nenv->e.type = ENV;
+ nenv->e.fbindings = copy_alist(oenv->e.fbindings);
+ nenv->e.vbindings = copy_alist(oenv->e.vbindings);
+ nenv->e.up_env = oenv->e.up_env;
+ return nenv;
+ }
+}
+
/*
* Wrapper for performance reasons: don't make make_env
* process default arguments.
@@ -448,12 +463,21 @@ static val abbrev_ctx(val ctx_form)
return lit("");
}
+static void copy_env_handler(mem_t *ptr, int parent)
+{
+ val *penv = coerce(val *, ptr);
+ *penv = copy_env(*penv);
+}
+
static val bind_args(val env, val params, struct args *args, val ctx_form)
{
val new_env = make_env(nil, nil, env);
val optargs = nil;
val special_list = nil;
cnum index = 0;
+ uw_frame_t uw_cc;
+
+ uw_push_cont_copy(&uw_cc, coerce(mem_t *, &new_env), copy_env_handler);
for (; args_more(args, index) && consp(params); params = cdr(params)) {
val param = car(params);
@@ -564,6 +588,8 @@ static val bind_args(val env, val params, struct args *args, val ctx_form)
}
+ uw_pop_frame(&uw_cc);
+
return new_env;
twocol:
eval_error(ctx_form, lit("~s: multiple colons in parameter list"),
@@ -750,6 +776,9 @@ static val bind_macro_params(val env, val menv, val params, val form,
val whole = form;
val optargs = nil;
val specials = nil;
+ uw_frame_t uw_cc;
+
+ uw_push_cont_copy(&uw_cc, coerce(mem_t *, &new_env), copy_env_handler);
if (consp(params)) {
val head = car(params);
@@ -825,7 +854,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
param, car(form),
loose_p, ctx_form);
if (!new_env)
- return nil;
+ goto nil_out;
}
} else {
err_sym = param;
@@ -838,7 +867,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
if (form) {
if (loose_p == colon_k)
- return nil;
+ goto nil_out;
eval_error(ctx_form, lit("~s: atom ~s not matched by parameter list"),
car(ctx_form), form, nao);
}
@@ -848,7 +877,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
eval_error(ctx_form, lit("~s: insufficient number of arguments"),
car(ctx_form), nao);
if (loose_p == colon_k)
- return nil;
+ goto nil_out;
}
noarg:
@@ -889,19 +918,25 @@ noarg:
goto nbind;
}
env_vbind_special(new_env, params, form, specials, ctx_form);
- return new_env;
+ goto out;
}
if (form) {
if (loose_p == colon_k)
- return nil;
+ goto nil_out;
eval_error(ctx_form,
lit("~s: extra form part ~s not matched by parameter list"),
car(ctx_form), form, nao);
}
+out:
+ uw_pop_frame(&uw_cc);
return new_env;
+nil_out:
+ uw_pop_frame(&uw_cc);
+ return nil;
+
nbind:
eval_error(ctx_form, lit("~s: ~s is not a bindable symbol"),
car(ctx_form), err_sym, nao);
@@ -1111,15 +1146,31 @@ static val op_unquote_error(val form, val env)
return second(form);
}
+struct bindings_helper_vars {
+ val de;
+ val ne;
+};
+
+static void copy_bh_env_handler(mem_t *ptr, int parent)
+{
+ struct bindings_helper_vars *pv = coerce(struct bindings_helper_vars *, ptr);
+ if (pv->de)
+ pv->de = copy_env(pv->de);
+ pv->ne = copy_env(pv->ne);
+}
static val bindings_helper(val vars, val env, val sequential,
val *env_out, val ret_new_bindings,
val ctx_form)
{
val iter;
- val de = if3(sequential, dyn_env, nil);
- val ne = if3(sequential, env, make_env(nil, nil, env));
+ struct bindings_helper_vars v;
list_collect_decl (new_bindings, ptail);
+ uw_frame_t uw_cc;
+ v.de = if3(sequential, dyn_env, nil);
+ v.ne = if3(sequential, env, make_env(nil, nil, env));
+
+ uw_push_cont_copy(&uw_cc, coerce(mem_t *, &v), copy_bh_env_handler);
for (iter = vars; iter; iter = cdr(iter)) {
val item = car(iter);
@@ -1127,33 +1178,36 @@ static val bindings_helper(val vars, val env, val sequential,
if (consp(item)) {
var = pop(&item);
- value = eval(pop(&item), if3(sequential, ne, env), ctx_form);
+ value = eval(pop(&item), if3(sequential, v.ne, env), ctx_form);
} else {
var = item;
}
if (var == special_s) {
val special = car(item);
- val binding = env_vbind(de = (de ? de : make_env(nil, nil, dyn_env)),
+ val binding = env_vbind(v.de = (v.de ? v.de
+ : make_env(nil, nil, dyn_env)),
special, value);
if (ret_new_bindings)
ptail = list_collect (ptail, binding);
} else if (bindable(var)) {
- val le = if3(sequential, make_env(nil, nil, ne), ne);
+ val le = if3(sequential, make_env(nil, nil, v.ne), v.ne);
val binding = env_vbind(le, var, value);
if (ret_new_bindings)
ptail = list_collect (ptail, binding);
- ne = le;
+ v.ne = le;
} else {
eval_error(ctx_form, lit("~s: ~s is not a bindable symbol"),
car(ctx_form), var, nao);
}
}
- if (de && de != dyn_env)
- dyn_env = de;
+ if (v.de && v.de != dyn_env)
+ dyn_env = v.de;
if (env_out)
- *env_out = ne;
+ *env_out = v.ne;
+
+ uw_pop_frame(&uw_cc);
return new_bindings;
}
diff --git a/eval.h b/eval.h
index cedaeeff..33d20816 100644
--- a/eval.h
+++ b/eval.h
@@ -31,6 +31,7 @@ extern val last_form_evaled, last_form_expanded;
noreturn val eval_error(val form, val fmt, ...);
val make_env(val fbindings, val vbindings, val up_env);
+val copy_env(val oenv);
val env_fbind(val env, val sym, val fun);
val env_vbind(val env, val sym, val obj);
val lookup_var(val env, val sym);
diff --git a/unwind.c b/unwind.c
index a3f63038..cf242b20 100644
--- a/unwind.c
+++ b/unwind.c
@@ -365,6 +365,17 @@ val uw_invoke_catch(val catch_frame, val sym, struct args *args)
abort();
}
+void uw_push_cont_copy(uw_frame_t *fr, mem_t *ptr,
+ void (*copy)(mem_t *ptr, int parent))
+{
+ memset(fr, 0, sizeof *fr);
+ fr->cp.type = UW_CONT_COPY;
+ fr->cp.ptr = ptr;
+ fr->cp.copy = copy;
+ fr->cp.up = uw_stack;
+ uw_stack = fr;
+}
+
val uw_block_return_proto(val tag, val result, val protocol)
{
uw_frame_t *ex;
@@ -705,6 +716,16 @@ static struct cobj_ops cont_ops = cobj_ops_init(eq,
cont_mark,
cobj_hash_op);
+static void call_copy_handlers(uw_frame_t *upto, int parent)
+{
+ uw_frame_t *fr;
+
+ for (fr = uw_stack; fr != 0 && fr != upto; fr = fr->uw.up) {
+ if (fr->uw.type == UW_CONT_COPY)
+ fr->cp.copy(fr->cp.ptr, parent);
+ }
+}
+
static val revive_cont(val dc, val arg)
{
const int frame_slack = 32 * sizeof (val);
@@ -754,6 +775,9 @@ static val revive_cont(val dc, val arg)
bug_unless (uw_stack->uw.type == UW_BLOCK);
+ if (arg != sys_cont_poison_s)
+ call_copy_handlers(&uw_blk, 0);
+
uw_stack->bl.result = arg;
uw_exit_point = if3(arg == sys_cont_poison_s, &uw_blk, uw_stack);
uw_unwind_to_exit_point();
@@ -802,8 +826,10 @@ static val capture_cont(val tag, val fun, uw_frame_t *block)
uw_block_end;
- if (cont_obj)
+ if (cont_obj) {
+ call_copy_handlers(block, 0);
result = funcall1(fun, func_f1(cont_obj, revive_cont));
+ }
return result;
}
diff --git a/unwind.h b/unwind.h
index 5fccabc0..518cd552 100644
--- a/unwind.h
+++ b/unwind.h
@@ -26,7 +26,8 @@
typedef union uw_frame uw_frame_t;
typedef enum uw_frtype {
- UW_BLOCK, UW_CAPTURED_BLOCK, UW_ENV, UW_CATCH, UW_HANDLE, UW_DBG
+ UW_BLOCK, UW_CAPTURED_BLOCK, UW_ENV, UW_CATCH, UW_HANDLE,
+ UW_CONT_COPY, UW_DBG
} uw_frtype_t;
struct uw_common {
@@ -70,6 +71,13 @@ struct uw_handler {
val fun;
};
+struct uw_cont_copy {
+ uw_frame_t *up;
+ uw_frtype_t type;
+ mem_t *ptr;
+ void (*copy)(mem_t *ptr, int parent);
+};
+
struct uw_debug {
uw_frame_t *up;
uw_frtype_t type;
@@ -88,6 +96,7 @@ union uw_frame {
struct uw_dynamic_env ev;
struct uw_catch ca;
struct uw_handler ha;
+ struct uw_cont_copy cp;
struct uw_debug db;
};
@@ -126,6 +135,8 @@ val uw_get_frames(void);
val uw_find_frame(val extype, val frtype);
val uw_invoke_catch(val catch_frame, val sym, struct args *);
val uw_capture_cont(val tag, val fun, val ctx_form);
+void uw_push_cont_copy(uw_frame_t *, mem_t *ptr,
+ void (*copy)(mem_t *ptr, int parent));
void uw_init(void);
void uw_late_init(void);