summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--eval.c1
-rw-r--r--lib.c13
-rw-r--r--lib.h1
-rw-r--r--share/txr/stdlib/place.tl20
-rw-r--r--txr.160
6 files changed, 109 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 89cfac5f..bb996325 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
2015-07-22 Kaz Kylheku <kaz@kylheku.com>
+ Adding nthcdr as accessor.
+
+ * eval.c (eval_init): Register nthcdr function.
+
+ * lib.c (nthcdr): New function.
+
+ * lib.h (nthcdr): Declared.
+
+ * share/txr/stdlib/place.tl (nthcdr): New defplace.
+
+ * txr.1: Documented.
+
+2015-07-22 Kaz Kylheku <kaz@kylheku.com>
+
Improve bad argument diagnosis for place macros.
* eval.c (op_mac_param_bind): New static function.
diff --git a/eval.c b/eval.c
index 67ac400d..6450501f 100644
--- a/eval.c
+++ b/eval.c
@@ -4164,6 +4164,7 @@ void eval_init(void)
reg_fun(intern(lit("reverse"), user_package), func_n1(reverse));
reg_fun(intern(lit("ldiff"), user_package), func_n2(ldiff));
reg_fun(intern(lit("last"), user_package), func_n1(last));
+ reg_fun(intern(lit("nthcdr"), user_package), func_n2(nthcdr));
reg_fun(intern(lit("flatten"), user_package), func_n1(flatten));
reg_fun(intern(lit("flatten*"), user_package), func_n1(lazy_flatten));
reg_fun(intern(lit("tuples"), user_package), func_n3o(tuples, 2));
diff --git a/lib.c b/lib.c
index 4d0c901b..6a662fbc 100644
--- a/lib.c
+++ b/lib.c
@@ -498,6 +498,19 @@ val last(val list)
return nullocp(p) ? list : deref(p);
}
+val nthcdr(val pos, val list)
+{
+ cnum n = c_num(pos);
+
+ if (n < 0)
+ uw_throwf(error_s, lit("nthcdr: negative index ~s given"), pos, nao);
+
+ while (n-- > 0)
+ list = cdr(list);
+
+ return list;
+}
+
loc ltail(loc cons)
{
while (cdr(deref(cons)))
diff --git a/lib.h b/lib.h
index 7a37030a..caab6b2a 100644
--- a/lib.h
+++ b/lib.h
@@ -457,6 +457,7 @@ loc tail(val cons);
loc term(loc head);
loc lastcons(val list);
val last(val list);
+val nthcdr(val pos, val list);
loc ltail(loc cons);
val pop(val *plist);
val upop(val *plist, val *pundo);
diff --git a/share/txr/stdlib/place.tl b/share/txr/stdlib/place.tl
index e19caa2f..f086ce31 100644
--- a/share/txr/stdlib/place.tl
+++ b/share/txr/stdlib/place.tl
@@ -355,6 +355,26 @@
(prog1 (cdr ,tmp) (,csetter (car ,tmp))))))))
,body)))
+(defplace (nthcdr index list) body
+ (getter setter
+ (with-gensyms (index-sym sentinel-head-sym parent-cell-sym)
+ (if (place-form-p list)
+ (with-update-expander (lgetter lsetter) list nil
+ ^(rlet ((,index-sym ,index))
+ (let* ((,sentinel-head-sym (cons nil (,lgetter)))
+ (,parent-cell-sym (nthcdr ,index-sym ,sentinel-head-sym)))
+ (macrolet ((,getter () ^(cdr ,',parent-cell-sym))
+ (,setter (val)
+ ^(progn (sys:rplacd ,',parent-cell-sym ,val)
+ (,',lsetter (cdr ,',sentinel-head-sym)))))
+ ,body))))
+ ^(rlet ((,index-sym ,index))
+ (let* ((,parent-cell-sym (nthcdr (pred ,index-sym) ,list)))
+ (macrolet ((,getter () ^(cdr ,',parent-cell-sym))
+ (,setter (val)
+ ^(sys:rplacd ,',parent-cell-sym ,val)))
+ ,body)))))))
+
(defplace (vecref vector index :whole args) body
(getter setter
(with-gensyms (vec-sym ind-sym)
diff --git a/txr.1 b/txr.1
index dc02fd99..7afaa51a 100644
--- a/txr.1
+++ b/txr.1
@@ -14191,6 +14191,66 @@ then
.code nil
is returned.
+.coNP Accessor @ nthcdr
+.synb
+.mets (nthcdr < index << list )
+.mets (set (nthcdr < index << list ) << new-value )
+.syne
+.desc
+The
+.code nthcdr
+function retrieves the n-th cons cell of a list, indexed from zero.
+The
+.meta index
+parameter must be a non-negative integer. If
+.meta index
+specifies a nonexistent cons beyond the end of the list,
+then
+.code nthcdr
+yields nil.
+The following equivalences hold:
+
+.cblk
+ (nthcdr 0 list) <--> list
+ (nthcdr 1 list) <--> (cdr list)
+ (nthcdr 2 list) <--> (cddr list)
+.cble
+
+An
+.code nthcdr
+place designates the storage location which holds the n-th cell,
+as indicated by the value of
+.metn index .
+Indices beyond the last cell of
+.meta list
+do not designate a valid place.
+If
+.meta list
+is itself a place, then the zeroth index is permitted and the
+resulting place denotes
+.metn list .
+Storing a value to
+.cblk
+.meti (nthcdr < 0 << list)
+.cble
+overwrites
+.metn list .
+Otherwise if
+.meta list
+isn't a syntactic place, then the zeroth index does not designate a valid
+place;
+.meta index
+must have a positive value. A
+.code nthcdr
+place does not support deletion.
+
+.TP* "Dialect Note:"
+In Common Lisp,
+.code nthcdr
+is only a function, not an accessor;
+.code nthcdr
+forms do not denote places.
+
.coNP Accessors @, caar @, cadr @, cdar @, cddr ... @ cdddddr
.synb
.mets (caar << object )