summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog33
-rw-r--r--lib.c88
-rw-r--r--lib.h7
-rw-r--r--match.c18
4 files changed, 112 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index a215393d..553f3b26 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,36 @@
+2011-10-04 Kaz Kylheku <kaz@kylheku.com>
+
+ Bugfixes to the semantics of binding environments, which
+ were broken in the face of deletions (local, forget).
+ For some stupid reason, I had written a destructive routine for
+ removing elements from an association list, and used it
+ as the basis for the local and forget directives.
+
+ * lib.c (eq_f, car_f): New variables.
+ (identity_tramp, equal_tramp): Obsolete functions removed.
+ (apply): Broken function disabled at run time.
+ (funcall, funcall1, funcall2): Throw meaningful error instead
+ of aborting.
+ (alist_remove_test): New static function.
+ (alist_remove, alist_remove1): Rewritten to be functional
+ rather than destructive.
+ (alist_nremove, alist_nremove1): Destructive functions,
+ using previous implementations of alist and alist_nremove.
+ (do_sort): Recurses directly rather than via sort. That was
+ probably why this helper was introduced!
+ (find, set_diff): New functions.
+ (obj_init): gc-protect new variables eq_f and car_f, and initialize
+ them. Initializations for equal_f and identity_f changed to
+ use equal and identity directly, without the obsolete wrappers.
+
+ * lib.h (eq_f, car_f, alist_nremove, alist_nremove1,
+ find, set_diff): Declared.
+
+ * match.c (match_line): Use set_diff to determine what bindings
+ are new, rather than ldiff and ldiff-like logic which break when
+ the new bindings do not share structure with the old.
+ (match_files): Likewise.
+
2011-10-03 Kaz Kylheku <kaz@kylheku.com>
* txr.1: Starte dodcumenting the forgotten merge directive.
diff --git a/lib.c b/lib.c
index 29e661d2..9ed67c57 100644
--- a/lib.c
+++ b/lib.c
@@ -71,8 +71,7 @@ val null_string;
val nil_string;
val null_list;
-val identity_f;
-val equal_f;
+val identity_f, equal_f, eq_f, car_f;
val prog_string;
@@ -83,14 +82,6 @@ val identity(val obj)
return obj;
}
-static val identity_tramp(val env, val obj)
-{
- (void) env;
- return identity(obj);
-}
-
-static val equal_tramp(val env, val , val );
-
static val code2type(int code)
{
switch ((type_t) code) {
@@ -559,12 +550,6 @@ val cobj_equal_op(val left, val right)
return eq(left, right);
}
-static val equal_tramp(val env, val left, val right)
-{
- (void) env;
- return equal(left, right);
-}
-
mem_t *chk_malloc(size_t size)
{
mem_t *ptr = (mem_t *) malloc(size);
@@ -1379,6 +1364,8 @@ val apply(val fun, val arglist)
{
val arg[4], *p = arg;
+ internal_error("apply is broken crap: fix before using");
+
type_check (fun, FUN);
type_assert (listp(arglist),
@@ -1427,7 +1414,7 @@ val funcall(val fun)
case N0:
return fun->f.f.n0();
default:
- abort();
+ uw_throwf(error_s, lit("funcall: wrong number of arguments"));
}
}
@@ -1441,7 +1428,7 @@ val funcall1(val fun, val arg)
case N1:
return fun->f.f.n1(arg);
default:
- abort();
+ uw_throwf(error_s, lit("funcall1: wrong number of arguments"));
}
}
@@ -1455,7 +1442,7 @@ val funcall2(val fun, val arg1, val arg2)
case N2:
return fun->f.f.n2(arg1, arg2);
default:
- abort();
+ uw_throwf(error_s, lit("funcall2: wrong number of arguments"));
}
}
@@ -1906,8 +1893,23 @@ val *acons_new_l(val *list, val key, val *new_p)
}
}
+static val alist_remove_test(val item, val key)
+{
+ return eq(car(item), key);
+}
+
val alist_remove(val list, val keys)
{
+ return set_diff(list, keys, func_n2(alist_remove_test), nil);
+}
+
+val alist_remove1(val list, val key)
+{
+ return alist_remove(list, cons(key, nil));
+}
+
+val alist_nremove(val list, val keys)
+{
val *plist = &list;
while (*plist) {
@@ -1920,7 +1922,7 @@ val alist_remove(val list, val keys)
return list;
}
-val alist_remove1(val list, val key)
+val alist_nremove1(val list, val key)
{
val *plist = &list;
@@ -2033,8 +2035,8 @@ static val do_sort(val list, val lessfun, val keyfun)
list2 = cdr(bisect);
*cdr_l(bisect) = nil;
- return merge(sort(list, lessfun, keyfun),
- sort(list2, lessfun, keyfun),
+ return merge(do_sort(list, lessfun, keyfun),
+ do_sort(list2, lessfun, keyfun),
lessfun, keyfun);
}
}
@@ -2047,6 +2049,40 @@ val sort(val list, val lessfun, val keyfun)
return do_sort(list, lessfun, keyfun);
}
+val find(val list, val key, val testfun, val keyfun)
+{
+ for (; list; list = cdr(list)) {
+ val item = car(list);
+ val list_key = funcall1(keyfun, item);
+
+ if (funcall2(testfun, key, list_key))
+ return item;
+ }
+
+ return nil;
+}
+
+val set_diff(val list1, val list2, val testfun, val keyfun)
+{
+ list_collect_decl (out, ptail);
+
+ if (!keyfun)
+ keyfun = identity_f;
+
+ if (!testfun)
+ testfun = equal_f;
+
+ for (; list1; list1 = cdr(list1)) {
+ val item = car(list1);
+ val list1_key = funcall1(keyfun, item);
+
+ if (!find(list2, list1_key, testfun, keyfun))
+ list_collect (ptail, item);
+ }
+
+ return out;
+}
+
static void obj_init(void)
{
/*
@@ -2057,7 +2093,7 @@ static void obj_init(void)
protect(&packages, &system_package, &keyword_package,
&user_package, &null_string, &nil_string,
- &null_list, &equal_f,
+ &null_list, &equal_f, &eq_f, &car_f,
&identity_f, &prog_string,
(val *) 0);
@@ -2157,8 +2193,10 @@ static void obj_init(void)
args_k = intern(lit("args"), keyword_package);
nothrow_k = intern(lit("nothrow"), keyword_package);
- equal_f = func_f2(nil, equal_tramp);
- identity_f = func_f1(nil, identity_tramp);
+ equal_f = func_n2(equal);
+ eq_f = func_n2(eq);
+ identity_f = func_n1(identity);
+ car_f = func_n1(car);
prog_string = string(progname);
}
diff --git a/lib.h b/lib.h
index cf397751..6dd743f9 100644
--- a/lib.h
+++ b/lib.h
@@ -237,8 +237,7 @@ extern val nothrow_k, args_k;
extern val null_string;
extern val null_list; /* (nil) */
-extern val identity_f;
-extern val equal_f;
+extern val identity_f, equal_f, eq_f, car_f;
extern const wchar_t *progname;
extern val prog_string;
@@ -381,6 +380,8 @@ val acons_new(val list, val key, val value);
val *acons_new_l(val *list, val key, val *new_p);
val alist_remove(val list, val keys);
val alist_remove1(val list, val key);
+val alist_nremove(val list, val keys);
+val alist_nremove1(val list, val key);
val copy_cons(val cons);
val copy_alist(val list);
val mapcar(val fun, val list);
@@ -388,6 +389,8 @@ val mapcon(val fun, val list);
val mappend(val fun, val list);
val merge(val list1, val list2, val lessfun, val keyfun);
val sort(val list, val lessfun, val keyfun);
+val find(val list, val key, val testfun, val keyfun);
+val set_diff(val list1, val list2, val testfun, val keyfun);
void obj_print(val obj, val stream);
void obj_pprint(val obj, val stream);
diff --git a/match.c b/match.c
index 592685f3..75e3bb0f 100644
--- a/match.c
+++ b/match.c
@@ -519,7 +519,8 @@ static val match_line(val bindings, val specline, val dataline,
if (until_pos) {
LOG_MATCH("until/last", until_pos);
if (sym == last_s) {
- last_bindings = ldiff(until_last_bindings, new_bindings);
+ last_bindings = set_diff(until_last_bindings,
+ new_bindings, eq_f, car_f);
pos = until_pos;
}
break;
@@ -529,10 +530,11 @@ static val match_line(val bindings, val specline, val dataline,
}
if (new_pos) {
+ val strictly_new_bindings = set_diff(new_bindings,
+ bindings, eq_f, car_f);
LOG_MATCH("coll", new_pos);
- for (iter = new_bindings; iter && iter != bindings;
- iter = cdr(iter))
+ for (iter = strictly_new_bindings; iter; iter = cdr(iter))
{
val binding = car(iter);
val existing = assoc(bindings_coll, car(binding));
@@ -1541,8 +1543,8 @@ repeat_spec_same_data:
first(files), num(data_lineno), nao);
/* Until discards bindings and position, last keeps them. */
if (sym == last_s) {
- last_bindings = ldiff(until_last_bindings, new_bindings);
-
+ last_bindings = set_diff(until_last_bindings,
+ new_bindings, eq_f, car_f);
if (success == t) {
data = t;
} else {
@@ -1556,11 +1558,13 @@ repeat_spec_same_data:
}
if (success) {
+ val strictly_new_bindings = set_diff(new_bindings,
+ bindings, eq_f, car_f);
+
debuglf(spec_linenum, lit("collect matched ~a:~a"),
first(files), num(data_lineno), nao);
- for (iter = new_bindings; iter && iter != bindings;
- iter = cdr(iter))
+ for (iter = strictly_new_bindings; iter; iter = cdr(iter))
{
val binding = car(iter);
val existing = assoc(bindings_coll, car(binding));