summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--lib.c36
-rw-r--r--txr.134
3 files changed, 75 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index be0057a5..c2547c5e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-01-21 Kaz Kylheku <kaz@kylheku.com>
+
+ * lib.c (car, cdr, ldiff): Extend to handle vectors and strings.
+ Thereby, numerous previously list-only operations in TXR Lisp
+ now magically handle strings and vectors.
+
+ * txr.1: Documented.
+
2014-01-20 Kaz Kylheku <kaz@kylheku.com>
* lib.c (broken_down_time_list): New static function.
diff --git a/lib.c b/lib.c
index cbc50869..6e162c22 100644
--- a/lib.c
+++ b/lib.c
@@ -203,6 +203,16 @@ val car(val cons)
cons->lc.func = nil;
return cons->lc.car;
}
+ case VEC:
+ if (zerop(cons->v.vec[vec_length]))
+ return nil;
+ return cons->v.vec[0];
+ case STR:
+ case LIT:
+ case LSTR:
+ if (zerop(length_str(cons)))
+ return nil;
+ return chr_str(cons, zero);
default:
type_mismatch(lit("~s is not a cons"), cons, nao);
}
@@ -223,6 +233,13 @@ val cdr(val cons)
cons->lc.func = nil;
return cons->lc.cdr;
}
+ case VEC:
+ case STR:
+ case LIT:
+ case LSTR:
+ if (le(length(cons), one))
+ return nil;
+ return sub(cons, one, t);
default:
type_mismatch(lit("~s is not a cons"), cons, nao);
}
@@ -611,9 +628,22 @@ val ldiff(val list1, val list2)
{
list_collect_decl (out, ptail);
- while (list1 && list1 != list2) {
- list_collect (ptail, car(list1));
- list1 = cdr(list1);
+ switch (type(list2)) {
+ case STR:
+ case LIT:
+ case LSTR:
+ case VEC:
+ while (list1 && !equal(list1, list2)) {
+ list_collect (ptail, car(list1));
+ list1 = cdr(list1);
+ }
+ break;
+ default:
+ while (list1 && list1 != list2) {
+ list_collect (ptail, car(list1));
+ list1 = cdr(list1);
+ }
+ break;
}
return out;
diff --git a/txr.1 b/txr.1
index 22c6615a..2e499bef 100644
--- a/txr.1
+++ b/txr.1
@@ -5003,6 +5003,40 @@ In TXR Lisp, the / character can occur in symbol names, and the / token
is a symbol. Therefore the /regex/ syntax is absent, replaced with the
#/regex/ syntax.
+.SS Generalization of List Accessors car and cdr
+
+In ancient Lisp in the 1960's, it was not possible to apply the operations
+car and cdr to the nil symbol (empty list), because it is not a cons cell. In
+the InterLisp dialect, this restriction was lifted: these operations were
+extended to accept nil (and return nil). The convention was adopted in
+other Lisp dialects and in Common Lisp. Thus there exists an object which
+is not a cons, yet which takes car and cdr.
+
+In TXR Lisp, this concept is extended further. For the sake of convenience,
+the operations car and cdr, are extended to work with strings and vectors:
+
+ (cdr "") -> nil
+ (car "") -> nil
+
+ (car "abc") -> #\ea
+ (cdr "abc") -> "bc"
+
+ (cdr #(1 2 3)) -> #(2 3)
+ (car #(1 2 3)) -> 1
+
+The ldiff function is also extended in a special way. When the right parameter
+is a string or vector, then it uses the equal equality test rather than eq
+for detecting the tail of the list.
+
+ (ldiff "abcd" "cd") -> (#\ea #\eb)
+
+The ldiff operation starts with "abcd" and repeatedly applies cdr to produce
+"bcd" and "cd", until the suffix is equal to the second argument: (equal "cd"
+"cd") yields true.
+
+Operations based on car, cdr and ldiff, such as keep-if and remq extend to
+strings and vectors.
+
.SH CONTROL FLOW AND SEQUENCING
When the first element of a compound expression is an operator symbol,