summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-01-01 15:55:58 -0800
committerKaz Kylheku <kaz@kylheku.com>2018-01-01 15:55:58 -0800
commit79a90b980192de7410a7e688e1c831f7878f8714 (patch)
tree8aaf9ce2e0a0fb6d79c36d3cc2c117039f2a6390
parent900597a05d48be775bfb0e504e3179062806ff02 (diff)
downloadtxr-79a90b980192de7410a7e688e1c831f7878f8714.tar.gz
txr-79a90b980192de7410a7e688e1c831f7878f8714.tar.bz2
txr-79a90b980192de7410a7e688e1c831f7878f8714.zip
sub and replace redirect to structure methods.
* lib.c (replace_obj): New static function. (sub): Handle struct case via lambda method. (replace): Handle struct case via replace_obj. * txr.1: Documented. * tests/012/aseq.tl (add): The lambda method now has to handle a range argument. One test case uses the last function, which for non-lists relies on sub, which now calls the lambda method if the object has one.
-rw-r--r--lib.c41
-rw-r--r--tests/012/aseq.tl5
-rw-r--r--txr.181
3 files changed, 121 insertions, 6 deletions
diff --git a/lib.c b/lib.c
index 53680144..55eba5f1 100644
--- a/lib.c
+++ b/lib.c
@@ -7235,6 +7235,29 @@ val replace_vec(val vec_in, val items, val from, val to)
return vec_in;
}
+static val replace_obj(val obj, val items, val from, val to)
+{
+ val self = lit("replace");
+ val lambda_set_meth = maybe_slot(obj, lambda_set_s);
+
+ if (!lambda_set_meth)
+ uw_throwf(error_s, lit("~a: object ~s lacks ~s method"),
+ self, obj, lambda_set_s, nao);
+
+ if (listp(from)) {
+ if (!missingp(to))
+ uw_throwf(error_s,
+ lit("~a: to-arg not applicable when from-arg is a list"),
+ self, nao);
+
+ (void) funcall3(slot(obj, lambda_set_s), obj, from, items);
+ } else {
+ (void) funcall3(slot(obj, lambda_set_s), obj, rcons(from, to), items);
+ }
+
+ return obj;
+}
+
val cat_vec(val list)
{
ucnum total = 0;
@@ -9793,11 +9816,6 @@ val sub(val seq, val from, val to)
switch (type(seq)) {
case NIL:
return nil;
- case COBJ:
- if (seq->co.cls == carray_s)
- return carray_sub(seq, from, to);
- seq = nullify(seq);
- /* fallthrough */
case CONS:
case LCONS:
return sub_list(seq, from, to);
@@ -9807,6 +9825,17 @@ val sub(val seq, val from, val to)
return sub_str(seq, from, to);
case VEC:
return sub_vec(seq, from, to);
+ case COBJ:
+ if (seq->co.cls == carray_s)
+ return carray_sub(seq, from, to);
+ if (structp(seq)) {
+ val lambda_meth = maybe_slot(seq, lambda_s);
+ if (lambda_meth)
+ return funcall2(lambda_meth, seq, rcons(from, to));
+ seq = nullify(seq);
+ return sub_list(seq, from, to);
+ }
+ /* fallthrough */
default:
type_mismatch(lit("sub: ~s is not a sequence"), seq, nao);
}
@@ -9894,6 +9923,8 @@ val replace(val seq, val items, val from, val to)
case COBJ:
if (seq->co.cls == carray_s)
return carray_replace(seq, items, from, to);
+ if (obj_struct_p(seq))
+ return replace_obj(seq, items, from, to);
/* fallthrough */
default:
type_mismatch(lit("replace: ~s is not a sequence"), seq, nao);
diff --git a/tests/012/aseq.tl b/tests/012/aseq.tl
index fc6cf76b..dfb20118 100644
--- a/tests/012/aseq.tl
+++ b/tests/012/aseq.tl
@@ -5,7 +5,10 @@
(:method cdr (me) (if (cdr me.list) (new (add me.n (cdr me.list)))))
(:method car (me) (+ me.n (car me.list)))
(:method nullify (me) (if me.list me))
- (:method lambda (me i) (+ me.n (ref me.list i))))
+ (:method lambda (me i)
+ (if (rangep i)
+ (mapcar (op + me.n) [me.list i])
+ (+ me.n (ref me.list i)))))
(defvarl o (new (add 3 (range 10 100 10))))
diff --git a/txr.1 b/txr.1
index 38655096..83e7c41f 100644
--- a/txr.1
+++ b/txr.1
@@ -25961,6 +25961,32 @@ is a
object, then the function behaves like
.codn carray-sub .
+If
+.meta sequence
+is a structure, it must support the
+.code lambda
+method. The
+.code sub
+operation is transformed into a call to the
+.code lambda
+method according to the following equivalence:
+
+.cblk
+ (sub o from to) <--> o.(lambda (rcons from to))
+ (sub o : to) <--> o.(lambda (rcons : to))
+ (sub o from) <--> o.(lambda (rcons from :))
+ (sub o) <--> o.(lambda (rcons : :))
+.cble
+
+That is to say, the
+.meta from
+and
+.code to
+arguments are converted to range object. If either argument
+is missing, the symbol
+.code :
+is used for the corresponding element of the range.
+
When a
.code sub
form is used as a syntactic place, that place denotes a slice of
@@ -26107,6 +26133,61 @@ object, then
behaves like
.codn carray-replace .
+If
+.meta sequence
+is a structure, then the structure must support the
+.code lambda-set
+method. The
+.code replace
+operation is translated into a call of the
+.code lambda-set
+method according to the following equivalences:
+
+.cblk
+ (replace o items from to)
+ <--> o.(lambda-set (rcons from to) items)
+
+ (replace o items index-list)
+ <--> o.(lambda-set index-list items)
+.cble
+
+Thus, the
+.meta from
+and
+.meta to
+arguments are converted to single range object,
+whereas an
+.meta index-list
+is passed as-is.
+It is an error if a
+.code to
+argument is given, and
+.code from
+is a list; the situation is diagnosed. If either
+.code from
+or
+.code to
+are omitted, the range object contains the
+.code :
+symbol in the corresponding place:
+
+.cblk
+ (replace o items from)
+ <--> o.(lambda-set (rcons from :) items)
+
+ (replace o items : to)
+ <--> o.(lambda-set (rcons : to) items)
+
+ (replace o items)
+ <--> o.(lambda-set (rcons : :) items)
+.cble
+
+It is the responsibility of the object's
+.code lambda-set
+method to implement semantics consistent with the
+description of
+.codn replace .
+
.coNP Function @ take
.synb
.mets (take < count << sequence )