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 any [] 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 any [:(...)]. 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 any [:(...)] and any :(...), because the first evaluates the group on each pass while the second evaluates just once.)

...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.

I posted my remarks on the issue....that I think this should be the true purpose of the WHILE vs ANY distinction. ANY and SOME will break on END, but a while won't. So it's actually a: [while b] to be an iterative equivalent of the recursive a: [b a |], with ANY and SOME having the historical behavior.

So WHILE actually has a reason to exist, after all. Who knew. :slight_smile:

1 Like