PARSE's Advancement Rule - Bad?

The following behavior in Red seems pretty reasonable, doesn't it?

red>> str: "aaa"
== "aaa"

red>> parse str [any [remove "a"]]
== true

red>> str
== ""

So why doesn't R3-Alpha do the same?

r3-alpha>> str: "aaa"
== "aaa"

r3-alpha>> parse str [any [remove "a"]]
== false

r3-alpha>> str
== "aa"

Believe it or not, this was by design. The concept is that if a rule doesn't advance the index, it isn't considered "successful":

I am not a fan. A successful rule is one that matched. The REMOVE matched.

While the REMOVE works in Red, it seems there's still some infinite-loop-avoidance through an advancement in the rules:

red>> parse "a" [any [ahead "a"]]
== false

I'm not sure where to draw the line. Personally I'd think that should be an infinite loop. Last I checked, this is a language where infinite loops are possible in a general sense, and it's counter-intuitive to me to see mystery behaviors trying to avoid them

Not excusing this avoidance in any way, but Parse has a checkered past with infinite loops.

Consider in Rebol 2 the difference hitting ESCAPE while performing the following:

parse "" [any []] ; unbreakable infinite loop
parse "" [any [()]] ; breakable infinite loop

This perhaps explains the reluctance to allow unfettered looping. On initial inspection, R3Alpha eventually returns TRUE for parse "" [while []]β€”it may be the unbreakable nature of Parse loops were already mitigated(?).

1 Like


Well that has has been recently addressed, so in Ren-C you can break a forever [] (now CYCLE). You'd be able to break an infinite looping PARSE, too.

[] is a match on any input. And I'd like some [] to be an infinite loop.

I mention in my linked post that sometimes decaying to infinite loops is a feature...and here it certainly can be. Consider some [:(...)]. It may be that on one iteration it evaluates to null and hence vaporizes. But on the next pass it might evaluate to a rule which splices.

(Curiously, there's a difference between some [:(...)] and some :(...), because the first evaluates the group on each pass while the second evaluates just once. To understand why, see "When should parse rules notice changes?")

...and with that...I'm convinced...

The progress rule is bad mojo. Let's toss it.

1 Like

Bad cancellation may have played a role, but I found out what the actual reason was:

Ladislav wanted a: [any b] to be an iterative equivalent of the recursive a: [b a |] Then, he wanted this to produce i = 3:

a: [a |]
parse "" [(i: 0) 3 [["a" |] (i: i + 1)] end]

If you mix all that in with the desire to have any [... | end] not be an infinite loop, something has to give somewhere. But I think the "no progress" rule is the wrong answer.

Ren-C solves this with an explicit FURTHER combinator, that you can use if you want to insist that a rule makes progress. And in reality, many common cases are handled by the new WHILE via while [not <end>] [...].

It seems like the right answer to me!

1 Like