Open epage opened 5 months ago
I want to parse something like Int[][]
, and the result should be DataType::Array(Box::new(DataType::Array(Box::new(DataType::Int))))
.
My current implementation (compile failed):
fn data_type_stateful<S>(input: &mut StatefulStream<S>) -> PResult<DataType>
where
S: TokenStream,
{
let init = data_type_stateful_inner(input)?;
repeat(0.., (Token::LBracket, Token::RBracket))
.fold(
move || init,
|mut acc, _| {
acc = DataType::Array(Box::new(acc));
acc
},
)
.parse_next(input)
}
The implementation can passed the compilation if init
impl FnOnce
, but I think another solution also works for me. How about make Init: Parser<Input, Result, Error>
?
I can use it like this:
fn data_type_stateful<S>(input: &mut StatefulStream<S>) -> PResult<DataType>
where
S: TokenStream,
{
repeat(0.., (Token::LBracket, Token::RBracket))
.fold_(
data_type_stateful_inner,
|mut acc, _| {
acc = DataType::Array(Box::new(acc));
acc
},
)
.parse_next(input)
}
It's even more elegant and more reasonable to combinator style.
For the trivial init value, they still can pass empty.value(vec![])
as init
, it's not much more complicated.
I'd like to contribute to that if any proposal is accepted.
So if I understand, you are wanting to initialize the state of your fold
from a previous parse result? I can see how it would be useful in your case but I'm unsure how well it generalizes. It would also violate one of our API guidelines which is that free functions contain grammar and fluent functions are for operating on the parsed result.
you are wanting to initialize the state of your fold from a previous parse result
Yes
I'm unsure how well it generalizes
How about add a new API? Although I can't find a good name for that except fold1
(BTW, similar API naming difficulties also exist in Haskell).
Current fold
can be a simple wrapper to fold1
with init arg |_input| Ok(init())
.
free functions contain grammar and fluent functions are for operating on the parsed result.
How to determine if a function is a free function or a fluent function? Why can't the init parameter be a fluent function? That also seems very reasonable.
https://github.com/TennyZhuang/winnow/commit/a6b1f04cbe9b39d218da5a121e610144ebf961b0
My implementation here, just for reference.
My understanding of the problem is: assume we have 2 parsers A and B, and we want to combine them in the following grammar: seq(A, repeat(..., B))
. For the repeat(..., B)
part we have the fold
to operate on the result. But there is no natural counterpart for seq(A, ...)
. We could only get the result tuple and work on it. @TennyZhuang's fold1
sounds like an abstraction for the seq(A, repeat(..., B))
pattern.
By embedding repeat(..., B)
inside the seq(A, repeat(..., B))
pattern, it implies we will not reuse the parser for repeat(..., B)
on other location, i.e. the parser will only be used once. And now it is guaranteed init
will only be called once, i.e. we can use FnOnce
for init
.
Mirroring rust-bakery/nom#1742 for consideration