Skip to content

Commit 9d919b6

Browse files
committed
FEAT: implemented collect set parse's command
related to: Oldes/Rebol-issues#2471
1 parent 8d3e132 commit 9d919b6

File tree

2 files changed

+75
-28
lines changed

2 files changed

+75
-28
lines changed

src/core/u-parse.c

+41-17
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
** Module: u-parse.c
2424
** Summary: parse dialect interpreter
2525
** Section: utility
26-
** Author: Carl Sassenrath
26+
** Author: Carl Sassenrath, Oldes
2727
** Notes:
2828
**
2929
***********************************************************************/
@@ -41,6 +41,7 @@ typedef struct reb_parse_collect {
4141
REBVAL *result;
4242
REBSER *block;
4343
REBINT depth;
44+
REBFLG flags;
4445
} REB_PARSE_COLLECT;
4546

4647
typedef struct reb_parse {
@@ -70,6 +71,10 @@ enum parse_flags {
7071
PF_PICK,
7172
};
7273

74+
enum collect_flags {
75+
CF_ROOT_SET, // that the root collect block was SET to a word, so return parse's result (logic) instead
76+
};
77+
7378
#define MAX_PARSE_DEPTH 512
7479

7580
// Returns SYMBOL or 0 if not a command:
@@ -777,6 +782,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
777782
REBFLG flags;
778783
REBCNT cmd;
779784
REBSER *blk;
785+
REB_PARSE_COLLECT *collect = parse->collect;
780786
//REBVAL *rule_head = rules;
781787

782788
CHECK_STACK(&flags);
@@ -870,26 +876,46 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
870876
case SYM_COLLECT:
871877
if (IS_END(rules))
872878
Trap1(RE_PARSE_END, rules - 1);
873-
//printf("COLLECT start %i\n", parse->collect->depth);
879+
//printf("COLLECT start %i\n", collect->depth);
874880
// reserve a new value on stack
875881
DS_PUSH_NONE;
876-
if (parse->collect->block == NULL) {
882+
883+
if (collect->block == NULL) {
877884
// --- FIRST collect -------------------------
878885
// allocate the resulting block on the stack, so it is GC safe
879886
Set_Series(REB_BLOCK, DS_TOP, Make_Block(2));
880-
parse->collect->result = DS_TOP;
881-
parse->collect->block = VAL_SERIES(DS_TOP);
887+
collect->result = DS_TOP;
888+
collect->block = VAL_SERIES(DS_TOP);
882889
} else {
883890
// --- SUBSEQUENT collect ---------------------
884891
// store current block on stack
885-
Set_Series(REB_BLOCK, DS_TOP, parse->collect->block);
892+
Set_Series(REB_BLOCK, DS_TOP, collect->block);
886893
// do not allocate a new one, until it is needed, else
887894
// there could be unwanted empty blocks like in case:
888895
// parse [1][collect some [collect keep integer!]]
889-
parse->collect->block = NULL;
896+
collect->block = NULL;
890897
}
891898
SET_FLAG(flags, PF_COLLECT);
892-
parse->collect->depth++;
899+
900+
if (IS_WORD(rules) && VAL_SYM_CANON(rules) == SYM_SET) {
901+
rules++;
902+
if (!(IS_WORD(rules) || IS_SET_WORD(rules)))
903+
Trap1(RE_PARSE_VARIABLE, rules);
904+
if (collect->block == NULL) {
905+
// the block was not allocated yet, but we need it now!
906+
val = Append_Value(VAL_SERIES(DS_TOP));
907+
Set_Series(REB_BLOCK, val, Make_Block(2));
908+
// and mark it for use
909+
collect->block = VAL_SERIES(val);
910+
}
911+
if (collect->depth == 0) {
912+
SET_FLAG(collect->flags, CF_ROOT_SET);
913+
}
914+
915+
Set_Var_Series(rules, REB_BLOCK, collect->block, 0);
916+
rules++;
917+
}
918+
collect->depth++;
893919
continue;
894920

895921
case SYM_KEEP:
@@ -1086,7 +1112,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
10861112
val = BLK_SKIP(series, index);
10871113
i = (
10881114
(ANY_BINSTR(val) || ANY_BLOCK(val))
1089-
&& (Parse_Series(val, VAL_BLK_DATA(item), parse->flags, depth+1, &parse->collect) == VAL_TAIL(val))
1115+
&& (Parse_Series(val, VAL_BLK_DATA(item), parse->flags, depth+1, &collect) == VAL_TAIL(val))
10901116
) ? index+1 : NOT_FOUND;
10911117
break;
10921118
#ifdef USE_DO_PARSE_RULE
@@ -1216,7 +1242,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
12161242
}
12171243
if (GET_FLAG(flags, PF_KEEP)) {
12181244
if (ser && GET_FLAG(flags, PF_COPY)) {
1219-
val = Append_Value(parse->collect->block);
1245+
val = Append_Value(collect->block);
12201246
if (IS_BLOCK_INPUT(parse)) {
12211247
Set_Block(val, ser);
12221248
}
@@ -1238,9 +1264,9 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
12381264
// COLLECT ends
12391265
// get the previous target block from the stack and use it
12401266
val = DS_POP;
1241-
parse->collect->block = VAL_SERIES(val);
1242-
parse->collect->depth--;
1243-
//printf("COLLECT done %i\n", parse->collect->depth);
1267+
collect->block = VAL_SERIES(val);
1268+
collect->depth--;
1269+
//printf("COLLECT done %i\n", collect->depth);
12441270
}
12451271

12461272
if (GET_FLAG(flags, PF_RETURN)) {
@@ -1512,12 +1538,10 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
15121538
Throw_Error(VAL_ERR_OBJECT(DS_RETURN));
15131539
}
15141540
SET_STATE(state, Saved_State);
1515-
collect.depth = 0;
1516-
collect.result = NULL;
1517-
collect.block = NULL;
1541+
CLEARS(&collect);
15181542

15191543
n = Parse_Series(val, VAL_BLK_DATA(arg), (opts & PF_CASE) ? AM_FIND_CASE : 0, 0, &collect);
1520-
if (collect.result) {
1544+
if (collect.result && !GET_FLAG(collect.flags, CF_ROOT_SET)) {
15211545
*D_RET = *collect.result;
15221546
}
15231547
else {

src/tests/units/parse-test.r3

+34-11
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,23 @@ Rebol [
194194
--assert [3] = parse [1][collect [integer! keep (1 + 2)]]
195195
--assert [3 "A"] = parse [1][collect [integer! keep (1 + 2) keep ("A")]]
196196

197-
--test-- "block collect set (Red specific)"
198-
;@@ Not yet implemented!
199-
;- Sets a given word to a block of collected values.
200-
; a: none --assert all [parse [] [collect set a []] a = []]
201-
; a: none --assert all [parse [1] [collect set a [keep skip]] a = [1]]
197+
--test-- "block collect set"
198+
a: none --assert all [#[true] = parse [ ] [collect set a []] a = []]
199+
a: none --assert all [#[true] = parse [1] [collect set a [keep skip]] a = [1]]
200+
a: none --assert all [#[false] = parse [1 2] [collect set a [keep skip]] a = [1]]
201+
a: none --assert all [
202+
[[1]] = parse [1] [collect [collect set a keep skip]]
203+
a = [1]
204+
]
205+
a: none --assert all [
206+
#[true] = parse [1] [collect set a [collect set a keep skip]]
207+
a = [1]
208+
]
209+
a: b: none --assert all [
210+
#[true] = parse [1] [collect set a [collect set b keep skip]]
211+
a = [[1]]
212+
b = [1]
213+
]
202214

203215
--test-- "block collect into"
204216
;@@ Not yet implemented!
@@ -257,12 +269,23 @@ Rebol [
257269
--assert [#{0102}] = parse #{0102} [collect [keep 2 skip]]
258270
--assert [1 2] = parse #{0102} [collect [keep pick 2 skip]]
259271

260-
--test-- "string collect set (Red specific)"
261-
;@@ Not yet implemented!
262-
;- Sets a given word to a block of collected values.
263-
; a: none --assert all [parse "" [collect set a []] a = []]
264-
; a: none --assert all [parse "1" [collect set a [keep skip]] a = [#"1"]]
265-
272+
--test-- "string collect set"
273+
a: none --assert all [#[true] = parse "" [collect set a []] a = []]
274+
a: none --assert all [#[true] = parse "1" [collect set a [keep skip]] a = [#"1"]]
275+
a: none --assert all [#[false] = parse "12" [collect set a [keep skip]] a = [#"1"]]
276+
a: none --assert all [
277+
[[#"1"]] = parse "1" [collect [collect set a keep skip]]
278+
a = [#"1"]
279+
]
280+
a: none --assert all [
281+
#[true] = parse "1" [collect set a [collect set a keep skip]]
282+
a = [#"1"]
283+
]
284+
a: b: none --assert all [
285+
#[true] = parse "1" [collect set a [collect set b keep skip]]
286+
a = [[#"1"]]
287+
b = [#"1"]
288+
]
266289
--test-- "string collect into"
267290
;@@ Not yet implemented!
268291
;- Inserts collected values into a series referred by a word, resets series' index to the head.

0 commit comments

Comments
 (0)