metaborg / stratego

Apache License 2.0
10 stars 7 forks source link

strategolib `while` strategy is implemented recursively #34

Closed molenzwiebel closed 2 years ago

molenzwiebel commented 2 years ago

Describe the bug

while(c, s) is implemented as follows:

while(c, s) = 
    try(c; s; while(c, s))

In both the jar and ctree formats, this manifests as a recursive strategy that will eventually blow the stack if ran for enough iterations.

This is very misleading, because the while name suggests a correspondence to the while (x) y; construct from imperative functions, which obviously does not blow the stack.

There is no technical need for while to be recursive. It could probably be implemented in terms of repeat, which is already natively implemented using an actual while loop (although the crude infinite loop detection in repeat may not be appropriate for a while loop).

I ran into this issue while working on an interpreter for a CPS language in Stratego, which absolutely needs non-recursive iteration primitives. For now, I've moved to using repeat, but while should probably not be recursive even if repeat exists.

Versions As far as I can tell, this has been the case since the very first version of while in strategolib.

To Reproduce

For example:

test = !1; while(!(<id>, 1000000); lt, !(<id>, 1); addi)

Should throw a nice StackOverflowError after a couple thousand iterations.

Observed behaviour

Stack overflows.

Expected behaviour

Works fine.

Apanatshka commented 2 years ago

I'm not sure whether to call this a bug, expected behaviour in a functional-ish language, an indirect feature request for tail call optimisation, or what. I think it makes sense to use repeat for now since that has an external implementation in Java with a loop. I'll see if I can redefine strategies in strategy/iteration in strategolib in terms of repeat, at least for Stratego 2.

Apanatshka commented 2 years ago

Fixed in 56204ae21f6e22fe9b76d35bd2ace37ac9e03602