Skip to content

Commit 277ab51

Browse files
committed
FIX: Parse rule fails when input is modified and so does not advance
resolves: Oldes/Rebol-issues#2452
1 parent e9b0bb1 commit 277ab51

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

src/core/u-parse.c

+18-5
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ enum parse_flags {
5656
PF_CHANGE,
5757
PF_RETURN,
5858
PF_WHILE,
59+
PF_ADVANCE, // used to report that although index was not changed, rule is suppose to advance
5960
};
6061

6162
#define MAX_PARSE_DEPTH 512
@@ -839,8 +840,8 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
839840
// #2269 - reset the position if we are not in the middle of any rule
840841
// don't allow code like: [copy x :pos integer!]
841842
if (flags != 0) Trap1(RE_PARSE_RULE, rules-1);
842-
begin = index;
843-
843+
begin = index;
844+
SET_FLAG(parse->flags, PF_ADVANCE);
844845
continue;
845846
}
846847

@@ -978,10 +979,20 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
978979
if (i != NOT_FOUND) {
979980
count++; // may overflow to negative
980981
if (count < 0) count = MAX_I32; // the forever case
982+
981983
// If input did not advance:
982-
if (i == index && !GET_FLAG(flags, PF_WHILE)) {
983-
if (count < mincount) index = NOT_FOUND; // was not enough
984-
break;
984+
if (i == index) {
985+
// check if there was processed some _modifying_ rule, which should advance
986+
// even if index was not changed (https://github.com/Oldes/Rebol-issues/issues/2452)
987+
if (GET_FLAG(parse->flags, PF_ADVANCE)) {
988+
// clear the state in case, that there are other rules to be processed
989+
// keep it in case that we were at the last one
990+
if(count < maxcount) CLR_FLAG(parse->flags, PF_ADVANCE);
991+
}
992+
else if (!GET_FLAG(flags, PF_WHILE)) {
993+
if (count < mincount) index = NOT_FOUND; // was not enough
994+
break;
995+
}
985996
}
986997
}
987998
//if (i >= series->tail) { // OLD check: no more input
@@ -1058,6 +1069,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
10581069
if (IS_PROTECT_SERIES(series)) Trap0(RE_PROTECTED);
10591070
Remove_Series(series, begin, count);
10601071
}
1072+
SET_FLAG(parse->flags, PF_ADVANCE);
10611073
index = begin;
10621074
}
10631075
if (flags & (1<<PF_INSERT | 1<<PF_CHANGE)) {
@@ -1090,6 +1102,7 @@ void Print_Parse_Index(REBCNT type, REBVAL *rules, REBSER *series, REBCNT index)
10901102
index = Modify_String(GET_FLAG(flags, PF_CHANGE) ? A_CHANGE : A_INSERT,
10911103
series, begin, item, cmd, count, 1);
10921104
}
1105+
SET_FLAG(parse->flags, PF_ADVANCE);
10931106
}
10941107
if (GET_FLAG(flags, PF_AND)) index = begin;
10951108
}

src/tests/units/_known-issues_.r3

-9
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,6 @@ Rebol [
3636
===end-group===
3737

3838

39-
===start-group=== "PARSE"
40-
--test-- "parse remove"
41-
--assert parse v: "yx" [some [remove #"y" | #"x"] ]
42-
--assert v = "x"
43-
--assert parse "yx" [copy v any [ remove #"y" | #"x" ] ]
44-
--assert v = "x"
45-
===end-group===
46-
47-
4839
===start-group=== "TIME"
4940
;@@ https://github.com/Oldes/Rebol-issues/issues/2416
5041
--test-- "time protect 1"

src/tests/units/parse-test.r3

+17-4
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,23 @@ Rebol [
113113

114114
===start-group=== "REMOVE"
115115
--test-- "remove"
116-
;--assert parse v: "yx" [some [remove #"y" | #"x"] ]
117-
;--assert v = "x"
118-
;--assert parse "yx" [copy v any [ remove #"y" | #"x" ] ]
119-
;--assert v = "x"
116+
;@@ https://github.com/Oldes/Rebol-issues/issues/2452
117+
--assert parse v: "yx" [some [remove #"y" | #"x"]]
118+
--assert v = "x"
119+
--assert parse "yx" [copy v any [ remove #"y" | #"x" ]]
120+
--assert v = "x"
121+
--assert parse v: "yx" [some [change #"y" "" | #"x"]]
122+
--assert v = "x"
123+
--assert parse v: "ab" [any [s: 1 skip e: (e: remove/part s e) :e | skip]]
124+
--assert empty? v
125+
; and also:
126+
lr: [s: #L integer! e: (s: remove/part s 2) :s]
127+
--assert parse v: [#L 1 "a" #L 2 "b"][some [lr | string!]]
128+
--assert v = ["a" "b"]
129+
--assert parse v: [#L 1 "a" #L 2 "b"][some [string! | lr]]
130+
--assert v = ["a" "b"]
131+
132+
--test-- "while .. remove"
120133
remove-any-y: [while [remove #"y" | #"x"]]
121134
--assert parse v: "" remove-any-y
122135
--assert parse v: "yx" remove-any-y

0 commit comments

Comments
 (0)