diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-10-31 06:49:22 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-10-31 06:49:22 -0700 |
commit | 4b4ef6dfcf12e1db846b26a3b812aa010360d62f (patch) | |
tree | a80e4d82757e2385fa731f4fc07beb362e41d7d9 /lib.c | |
parent | e7523b22158785bcd542f2abfe3a3e0d96b7b1ab (diff) | |
download | txr-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.c | 43 |
1 files changed, 34 insertions, 9 deletions
@@ -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)); |