summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-10-06 11:02:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2011-10-06 11:02:23 -0700
commitb9746b4840d0f38042773bbc097286dd02857e18 (patch)
treeebe73725ef28da213ad71957e9cc42c18745150b
parent9ea10a1408eb1cd63bd38f0367428b2b57b57b97 (diff)
downloadtxr-b9746b4840d0f38042773bbc097286dd02857e18.tar.gz
txr-b9746b4840d0f38042773bbc097286dd02857e18.tar.bz2
txr-b9746b4840d0f38042773bbc097286dd02857e18.zip
* lib.c (funcall3, curry_123_2): New functions.
(do_curry_123_2): New static function. * lib.h (funcall3, curry_123_2): Declared. * match.c (subst_vars): Bugfix: throw error on unbound variable instead of ignoring the situation. This bug caused unbound variables in quasiliterals to be silently ignored. (eval_form): Function changed to three argument form, so that it takes a line number for reporting errors. Restructured to catch the new unbound variable exception from subst_vars, and re-throw it with a line number. Also, throws exception now instead of returning nil if itself it detets an unbound variable. Uses of eval_form no longer have to test the return value for nil, but just assume it worked. (match_lines): Currying calls to eval form updated to use curry_123_2. Test of eval return value eliminated. In function calls, eval isn't used for reducing symbol arguments to values, because it now throws in the unbound case, and it's not worth setting up a catch for this. Instead, assoc is used directly.
-rw-r--r--ChangeLog23
-rw-r--r--lib.c24
-rw-r--r--lib.h2
-rw-r--r--match.c95
4 files changed, 94 insertions, 50 deletions
diff --git a/ChangeLog b/ChangeLog
index a8714a2c..d5540534 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2011-10-06 Kaz Kylheku <kaz@kylheku.com>
+
+ * lib.c (funcall3, curry_123_2): New functions.
+ (do_curry_123_2): New static function.
+
+ * lib.h (funcall3, curry_123_2): Declared.
+
+ * match.c (subst_vars): Bugfix: throw error on unbound variable instead
+ of ignoring the situation. This bug caused unbound variables in
+ quasiliterals to be silently ignored.
+ (eval_form): Function changed to three argument form, so that
+ it takes a line number for reporting errors. Restructured to catch
+ the new unbound variable exception from subst_vars, and re-throw
+ it with a line number. Also, throws exception now instead of returning
+ nil if itself it detets an unbound variable. Uses of eval_form
+ no longer have to test the return value for nil, but just assume
+ it worked.
+ (match_lines): Currying calls to eval form updated to use
+ curry_123_2. Test of eval return value eliminated. In function
+ calls, eval isn't used for reducing symbol arguments to values,
+ because it now throws in the unbound case, and it's not worth
+ setting up a catch for this. Instead, assoc is used directly.
+
2011-10-05 Kaz Kylheku <kaz@kylheku.com>
* match.c (match_files): In function calls, the deletion of
diff --git a/lib.c b/lib.c
index 52208ce6..b53e8fd3 100644
--- a/lib.c
+++ b/lib.c
@@ -1446,6 +1446,21 @@ val funcall2(val fun, val arg1, val arg2)
}
}
+val funcall3(val fun, val arg1, val arg2, val arg3)
+{
+ type_check(fun, FUN);
+
+ switch (fun->f.functype) {
+ case F3:
+ return fun->f.f.f3(fun->f.env, arg1, arg2, arg3);
+ case N3:
+ return fun->f.f.n3(arg1, arg2, arg3);
+ default:
+ uw_throwf(error_s, lit("funcall3: wrong number of arguments"));
+ }
+}
+
+
val reduce_left(val fun, val list, val init, val key)
{
if (!key)
@@ -1477,6 +1492,15 @@ val bind2other(val fun2, val arg2)
return func_f1(cons(fun2, arg2), do_bind2other);
}
+static val do_curry_123_2(val fcons, val arg2)
+{
+ return funcall3(car(fcons), car(cdr(fcons)), arg2, cdr(cdr(fcons)));
+}
+
+val curry_123_2(val fun3, val arg1, val arg3)
+{
+ return func_f1(cons(fun3, cons(arg1, arg3)), do_curry_123_2);
+}
static val do_chain(val fun1_list, val arg)
{
diff --git a/lib.h b/lib.h
index 0d55701f..302f8b35 100644
--- a/lib.h
+++ b/lib.h
@@ -352,9 +352,11 @@ val apply(val fun, val arglist);
val funcall(val fun);
val funcall1(val fun, val arg);
val funcall2(val fun, val arg1, val arg2);
+val funcall3(val fun, val arg1, val arg2, val arg3);
val reduce_left(val fun, val list, val init, val key);
val bind2(val fun2, val arg);
val bind2other(val fun2, val arg2);
+val curry_123_2(val fun3, val arg1, val arg3);
val chain(val first_fun, ...);
val andf(val first_fun, ...);
val vector(val alloc);
diff --git a/match.c b/match.c
index 94ede32d..a00288e5 100644
--- a/match.c
+++ b/match.c
@@ -790,7 +790,8 @@ static val subst_vars(val spec, val bindings, val filter)
spec = cons(filter_string(filter, cdr(pair)), rest(spec));
continue;
}
- /* TODO: handle unbound variable */
+ uw_throwf(query_error_s, lit("unbound variable ~a"),
+ sym, nao);
} else if (first(elem) == quasi_s) {
val nested = subst_vars(rest(elem), bindings, filter);
list_collect_append(iter, nested);
@@ -811,29 +812,44 @@ static val subst_vars(val spec, val bindings, val filter)
return out;
}
-static val eval_form(val form, val bindings)
+static val eval_form(val lineno, val form, val bindings)
{
- if (!form) {
- return cons(t, form);
- } else if (bindable(form)) {
- return assoc(bindings, form);
- } else if (consp(form)) {
- if (car(form) == quasi_s) {
- return cons(t, cat_str(subst_vars(rest(form), bindings, nil), nil));
- } else if (regexp(car(form))) {
- return cons(t, form);
+ val ret = nil;
+
+ uw_catch_begin (cons(query_error_s, nil), exc_sym, exc);
+ {
+ if (!form) {
+ ret = cons(t, form);
+ } else if (bindable(form)) {
+ ret = assoc(bindings, form);
+ } else if (consp(form)) {
+ if (car(form) == quasi_s) {
+ ret = cons(t, cat_str(subst_vars(rest(form), bindings, nil), nil));
+ } else if (regexp(car(form))) {
+ ret = cons(t, form);
+ } else {
+ val subforms = mapcar(curry_123_2(func_n3(eval_form),
+ lineno, bindings), form);
+
+ if (all_satisfy(subforms, identity_f, nil))
+ ret = cons(t, mapcar(func_n1(cdr), subforms));
+ }
+ } else if (stringp(form)) {
+ ret = cons(t, form);
} else {
- val subforms = mapcar(bind2other(func_n2(eval_form), bindings), form);
+ ret = cons(t, form);
+ }
- if (all_satisfy(subforms, identity_f, nil))
- return cons(t, mapcar(func_n1(cdr), subforms));
- return nil;
+ uw_catch (exc_sym, exc) {
+ sem_error(lineno, lit("~a"), exc, nao);
}
- } if (stringp(form)) {
- return cons(t, form);
}
+ uw_catch_end;
+
+ if (!ret)
+ sem_error(lineno, lit("unbound variable in form ~s"), form, nao);
- return cons(t, form);
+ return ret;
}
enum fpip_close { fpip_fclose, fpip_pclose, fpip_closedir };
@@ -1225,8 +1241,8 @@ repeat_spec_same_data:
} else if (sym == freeform_s) {
val args = rest(first_spec);
val vals = mapcar(func_n1(cdr),
- mapcar(bind2other(func_n2(eval_form),
- bindings), args));
+ mapcar(curry_123_2(func_n3(eval_form),
+ spec_linenum, bindings), args));
if ((spec = rest(spec)) == nil) {
sem_error(spec_linenum,
@@ -1324,13 +1340,9 @@ repeat_spec_same_data:
}
{
- val eval = eval_form(arg, bindings);
+ val eval = eval_form(spec_linenum, arg, bindings);
val str = cdr(eval);
- if (!eval)
- sem_error(spec_linenum, lit("next: unbound variable in form ~a"),
- first(source), nao);
-
if (eq(second(source), nothrow_k)) {
if (str) {
files = cons(cons(nothrow_k, str), files);
@@ -1685,11 +1697,7 @@ repeat_spec_same_data:
val arg = first(args);
if (arg) {
- val arg_eval = eval_form(arg, bindings);
-
- if (!arg_eval)
- sem_error(spec_linenum, lit("~a: unbound variable in form ~s"),
- sym, arg, nao);
+ val arg_eval = eval_form(spec_linenum, arg, bindings);
if (merged)
merged = weird_merge(merged, cdr(arg_eval));
@@ -1708,11 +1716,7 @@ repeat_spec_same_data:
val args = rest(first_spec);
val pattern = first(args);
val form = second(args);
- val val = eval_form(form, bindings);
-
- if (!val)
- sem_error(spec_linenum, lit("bind: unbound variable on right side"),
- nao);
+ val val = eval_form(spec_linenum, form, bindings);
bindings = dest_bind(bindings, pattern, cdr(val));
@@ -1763,12 +1767,7 @@ repeat_spec_same_data:
sem_error(spec_linenum, lit("material after :nothrow in output"), nao);
} else if (!keywordp(first(dest_spec))) {
val form = first(dest_spec);
- val val = eval_form(form, bindings);
-
- if (!val)
- sem_error(spec_linenum,
- lit("output: unbound variable in form ~a"), form, nao);
-
+ val val = eval_form(spec_linenum, form, bindings);
dest = or2(cdr(val), dest);
pop(&dest_spec);
}
@@ -1978,8 +1977,8 @@ repeat_spec_same_data:
sem_error(spec_linenum, lit("throw: ~a is not a type symbol"),
type, nao);
{
- val values = mapcar(bind2other(func_n2(eval_form), bindings),
- args);
+ val values = mapcar(curry_123_2(func_n3(eval_form),
+ spec_linenum, bindings), args);
uw_throw(type, values);
}
} else if (sym == deffilter_s) {
@@ -2039,8 +2038,8 @@ repeat_spec_same_data:
val param = car(piter);
val arg = car(aiter);
- if (arg && symbolp(arg)) {
- val val = eval_form(arg, bindings);
+ if (arg && bindable(arg)) {
+ val val = assoc(bindings, arg);
if (val) {
bindings_cp = acons_new(bindings_cp,
param,
@@ -2050,11 +2049,7 @@ repeat_spec_same_data:
ub_p_a_pairs = cons(cons(param, arg), ub_p_a_pairs);
}
} else {
- val val = eval_form(arg, bindings);
- if (!val)
- sem_error(spec_linenum,
- lit("unbound variable in function argument form"),
- nao);
+ val val = eval_form(spec_linenum, arg, bindings);
bindings_cp = acons_new(bindings_cp, param, cdr(val));
}
}