summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-10-31 06:49:22 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-10-31 06:49:22 -0700
commit4b4ef6dfcf12e1db846b26a3b812aa010360d62f (patch)
treea80e4d82757e2385fa731f4fc07beb362e41d7d9 /lib.c
parente7523b22158785bcd542f2abfe3a3e0d96b7b1ab (diff)
downloadtxr-4b4ef6dfcf12e1db846b26a3b812aa010360d62f.tar.gz
txr-4b4ef6dfcf12e1db846b26a3b812aa010360d62f.tar.bz2
txr-4b4ef6dfcf12e1db846b26a3b812aa010360d62f.zip
Relax restrictions on dwim places.
No longer require the leftmost expression in a dwim place to itself be a place, except when the expression evaluates to a list, and the list is subject to an element deletion or a range operation. * eval.c (eval_init): Register dwim-set and dwim-del with one additional argument that the C functions now take. * lib.c (dwim_set, dwim_del): Take a new place_p argument which informs these functions whether the object they are operating on came from a syntactic place. The forbidden situations are diagnosed based on this flag: modification of the subrange of a list, or deletion of a list ref. Some error messages reworded. * lib.h (dwim_set, dwim_del): Declarations updated. * share/txr/stdlib/place.tl (defplace dwim): Produce a different update, clobber and delete expansion when the obj-place form isn't a place. In the non-place case, do not assign the result of the sys:dwim-set or sys:dwim-del operation back obj-place. Furthermore, pass a Boolean flag to sys:dwim-set and sys:dwim-del indicating which situation is the case: did the object argument come from a place or non-place. * txr.1: Documentation updated.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c43
1 files changed, 34 insertions, 9 deletions
diff --git a/lib.c b/lib.c
index 745a227a..05541f5d 100644
--- a/lib.c
+++ b/lib.c
@@ -8435,7 +8435,7 @@ val replace(val seq, val items, val from, val to)
}
}
-val dwim_set(val seq, varg vargs)
+val dwim_set(val place_p, val seq, varg vargs)
{
switch (type(seq)) {
case COBJ:
@@ -8459,8 +8459,10 @@ val dwim_set(val seq, varg vargs)
return seq;
}
- if (structp(seq))
- return funcall(method_args(seq, lambda_set_s, vargs));
+ if (structp(seq)) {
+ (void) funcall(method_args(seq, lambda_set_s, vargs));
+ return seq;
+ }
}
/* fallthrough */
default:
@@ -8468,7 +8470,7 @@ val dwim_set(val seq, varg vargs)
cnum index = 0;
val ind_range, newval;
if (!args_two_more(vargs, 0))
- uw_throwf(error_s, lit("dwim place assignment: missing required arguments"), nao);
+ uw_throwf(error_s, lit("index/range assignment: missing required arguments"), nao);
ind_range = args_get(vargs, &index);
newval = args_get(vargs, &index);
@@ -8477,10 +8479,14 @@ val dwim_set(val seq, varg vargs)
case CONS:
case LCONS:
case VEC:
+ if (!place_p && listp(seq))
+ goto notplace;
return replace(seq, newval, ind_range, colon_k);
case RNG:
{
range_bind (x, y, ind_range);
+ if (!place_p && listp(seq))
+ goto notplace;
return replace(seq, newval, x, y);
}
default:
@@ -8489,14 +8495,33 @@ val dwim_set(val seq, varg vargs)
}
}
}
+notplace:
+ uw_throwf(error_s, lit("range assignment: list form must be place"), nao);
}
-val dwim_del(val seq, val ind_range)
+val dwim_del(val place_p, val seq, val ind_range)
{
- if (hashp(seq)) {
- (void) remhash(seq, ind_range);
- return seq;
- } else if (rangep(ind_range)) {
+ switch (type(seq)) {
+ case NIL:
+ case CONS:
+ case LCONS:
+ if (!place_p)
+ uw_throwf(error_s, lit("index/range delete: list form must be place"),
+ nao);
+ break;
+ case COBJ:
+ if (seq->co.cls == hash_s) {
+ (void) remhash(seq, ind_range);
+ return seq;
+ }
+ if (structp(seq))
+ uw_throwf(error_s, lit("index/range delete: not supported for structs"),
+ nao);
+ default:
+ break;
+ }
+
+ if (rangep(ind_range)) {
return replace(seq, nil, from(ind_range), to(ind_range));
} else {
return replace(seq, nil, ind_range, succ(ind_range));