Open tari opened 2 years ago
I'd generally avoid implementing Parser
manually as the addition of partial parsing complicates manual implementations quite a bit. Instead use combine::parser(|i| ...)
if you need a manual function implementation.
If you still need a manual implementation I would copy paste from an implementation in the combine
repository as it seems that just implementing parse_stream
does not work, but parse_lazy
does work.
impl<Input, P> Parser<Input> for Satisfy<Input, P>
where
Input: Stream,
P: FnMut(Input::Token) -> bool,
{
type Output = Input::Token;
type PartialState = ();
#[inline]
fn parse_lazy(&mut self, input: &mut Input) -> ParseResult<Self::Output, Input::Error> {
satisfy_impl(input, |c| {
if (self.predicate)(c.clone()) {
Some(c)
} else {
None
}
})
}
}
I can confirm that simply changing my impl to implement parse_lazy
instead of parse_stream
fixes the issue I was seeing.
That suggests to me that the Parser
documentation should be changed to suggest that implementers implement parse_lazy
only, rather than either of that or parse_stream
. Would that be reasonable, or is there something else that means sometimes users could want to implement parse_stream
?
I encountered a similar issue. We should at least update the document.
I've implemented a recursive descent parser via the precedence climbing method using Combine, but it seems prone to unbounded mutual recursion somewhere in undocumented methods of the
Parser
impl.The parser itself looks something like this:
I find that in some formulations this gets stuck calling
parse_first
,parse_partial
andparse_lazy
on theParser
without end (until the stack overflows) as illustrated by this stack trace (most recent call first) taken from whereparse
is called before things go wrong:According to the documentation it seems like implementing
parse_stream
alone is fine, andparse_partial
/parse_first
are not documented so I don't understand what they're meant to be doing or why they end up mutually recursing.When I previously had this problem in
parse_terminal
I was able to work around it (for reasons I don't understand) by wrapping the recursive call in a wrapper function. Whereas this sort of thing exhibited the same problem described here:wrapping it in
parser
and explicitly callingparse_stream
did not: