Skip to content

Commit a84522c

Browse files
committed
FEAT: new PUT action for replacing the value following a key (in blocks and maps)
implements: metaeducation/rebol-issues#2392
1 parent 1a6bbce commit a84522c

File tree

5 files changed

+98
-1
lines changed

5 files changed

+98
-1
lines changed

src/boot/actions.r

+9-1
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,17 @@ take: action [
268268
/last {Take it from the tail end}
269269
]
270270

271+
put: action [
272+
{Replaces the value following a key, and returns the new value.}
273+
series [any-block! map!] {(modified)}
274+
key [scalar! any-string! any-word! binary!]
275+
value [any-type!] {The new value (returned)}
276+
/case {Perform a case-sensitive search (only on block so far!)}
277+
]
278+
271279
insert: action [
272280
{Inserts element(s); for series, returns just past the insert.}
273-
series [series! port! map! gob! object! bitset! port!] {At position (modified)}
281+
series [series! port! map! gob! object! bitset!] {At position (modified)}
274282
value [any-type!] {The value to insert}
275283
/part {Limits to a given length or position}
276284
length [number! series! pair!]

src/core/t-block.c

+20
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,7 @@ static struct {
608608
{
609609
REBVAL *value = D_ARG(1);
610610
REBVAL *arg = D_ARG(2);
611+
REBVAL *arg2;
611612
REBSER *ser;
612613
REBINT index;
613614
REBINT tail;
@@ -723,6 +724,25 @@ static struct {
723724
Remove_Series(ser, index, len);
724725
return R_RET;
725726

727+
case A_PUT:
728+
arg2 = D_ARG(3);
729+
args = D_REF(4) ? AM_FIND_CASE : 0;
730+
ret = Find_Block(ser, index, tail, arg, len, args, 1);
731+
if(ret != NOT_FOUND) {
732+
ret++;
733+
if (ret >= tail) {
734+
// when key is last value in the block
735+
Expand_Series(ser, tail, 1);
736+
}
737+
*BLK_SKIP(ser, ret) = *arg2;
738+
}
739+
else {
740+
Expand_Series(ser, tail, 2);
741+
*BLK_SKIP(ser, tail) = *arg;
742+
*BLK_SKIP(ser, tail+1) = *arg2;
743+
}
744+
return R_ARG3;
745+
726746
//-- Search:
727747

728748
case A_FIND:

src/core/t-map.c

+4
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@
503503
Append_Map(series, arg, Partial1(arg, D_ARG(AN_LENGTH)));
504504
break;
505505

506+
case A_PUT:
507+
Find_Entry(series, arg, D_ARG(3));
508+
return R_ARG3;
509+
506510
case A_POKE: // CHECK all pokes!!! to be sure they check args now !!!
507511
Find_Entry(series, arg, D_ARG(3));
508512
*D_RET = *D_ARG(3);

src/tests/units/map-test.r3

+19
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ Rebol [
3131

3232
===end-group===
3333

34+
===start-group=== "PUT"
35+
--test-- "PUT into map"
36+
m: map [a: 42]
37+
--assert "foo" = put m 'b "foo"
38+
--assert "baz" = put m 'a "baz"
39+
--assert "foo" = m/b
40+
--assert "baz" = m/a
41+
42+
--test-- "PUT into protected map"
43+
m: map [a: 42]
44+
protect m
45+
--assert error? err: try [put m 'b "foo"]
46+
--assert err/id = 'protected
47+
--assert error? err: try [put m 'a "baz"]
48+
--assert err/id = 'protected
49+
unprotect m
50+
51+
===end-group===
52+
3453
===start-group=== "reflection"
3554
m: make map! b: [a 1 b: 2 :c 3 'd 4 #e 5 /f 6 "a" 7 <b> 8 9 9 #"c" 10 a@b 11]
3655
--test-- "body of map"

src/tests/units/series-test.r3

+46
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,52 @@ Rebol [
112112

113113
===end-group===
114114

115+
===start-group=== "PUT"
116+
--test-- "PUT into BLOCK"
117+
v: [a 1 b 2 c]
118+
--assert 3 = put v 'a 3
119+
--assert 4 = put v 'b 4
120+
--assert 5 = put v 'c 5
121+
--assert 6 = put v 'd 6
122+
--assert v = [a 3 b 4 c 5 d 6]
123+
124+
--test-- "PUT into PAREN"
125+
v: quote (a 1 b 2 c)
126+
--assert 3 = put v 'a 3
127+
--assert 4 = put v 'b 4
128+
--assert 5 = put v 'c 5
129+
--assert 6 = put v 'd 6
130+
--assert v = quote (a 3 b 4 c 5 d 6)
131+
132+
--test-- "PUT into PATH"
133+
v: to path! [a 1 b 2 c]
134+
--assert 3 = put v 'a 3
135+
--assert 4 = put v 'b 4
136+
--assert 5 = put v 'c 5
137+
--assert 6 = put v 'd 6
138+
--assert v = 'a/3/b/4/c/5/d/6
139+
140+
--test-- "PUT/CASE words"
141+
v: [a 1 b 2]
142+
--assert 3 = put v 'a 3
143+
--assert 4 = put/case v quote :a 4
144+
--assert 5 = put/case v quote 'b 5
145+
--assert v = [a 3 b 2 :a 4 'b 5]
146+
147+
--test-- "PUT/CASE strings"
148+
v: ["a" 1 "b" 2]
149+
--assert 3 = put v "a" 3
150+
--assert 4 = put/case v "A" 4
151+
--assert 5 = put/case v "B" 5
152+
--assert v = ["a" 3 "b" 2 "A" 4 "B" 5]
153+
154+
--test-- "PUT on protected block"
155+
v: protect [a 1]
156+
--assert error? err: try [ put v 'a 2 ]
157+
--assert 'protected = err/id
158+
159+
===end-group===
160+
115161
===start-group=== "REMOVE"
116162
--test-- "remove-blk-1"
117163
a: [1 2 3]

0 commit comments

Comments
 (0)