CalleeSave is designed to either be entered or exited, however as this parser can be let found (meaning we don't regenerate the instructions for it), if you recursively call a flatMap from within a flatMap and access the same CalleeSave instance, CalleeSave thinks we're leaving this scope so restores the outside registers which leads to undefined behaviour
Reproduction Steps
Write this code:
var x: Parsley[Unit] = pure(())
var death: Parsley[Unit] = 'x'.flatMap(_ => x)
x = death *> 1.makeRef(_=> pure('a'))
death.parse("xxx")
Expected behavior
This parser should return a failure with unexpected end of input but the scopes of the registers inside should still be consistent
(it's possible to write a recursive state like this that uses the state to end the infinite recursion but this is the simplest example I could find that shows the bug)
Additional context
Parsley Version: 5.0 staging
Scala Version: Both 2.13 and 3
Description
CalleeSave is designed to either be entered or exited, however as this parser can be let found (meaning we don't regenerate the instructions for it), if you recursively call a flatMap from within a flatMap and access the same CalleeSave instance, CalleeSave thinks we're leaving this scope so restores the outside registers which leads to undefined behaviour
Reproduction Steps
Write this code:
Expected behavior
This parser should return a failure with unexpected end of input but the scopes of the registers inside should still be consistent (it's possible to write a recursive state like this that uses the state to end the infinite recursion but this is the simplest example I could find that shows the bug)
Additional context
Parsley Version: 5.0 staging Scala Version: Both 2.13 and 3