I'm working on a little domain-specific language with proc-macros and syn, and there I want to parse a sequence of operators on the form
lhs + rsh => res
lhs - rsh => res
or
lhs += rsh
lhs -= rsh
and such.
I'm doing this using the syn
crate, implementing Parser
for the various structures I need. My thought was that I could parse these using a look-ahead after the first three tokens, with something like this:
let lookahead = input.lookahead1();
let lhs = input.parse()?;
let op = input.parse()?;
let rhs = input.parse()?;
// now, conditionally parse the res part of an operator
let res = if lookahead.peek(syn::token::FatArrow) {
input.parse::<syn::token::FatArrow>()?;
Some(input.parse()?)
} else { None };
The problem is that while syn::token::FatArrow
is the token for =>
when invoking parse
, it doesn't seem to be when invoking peek
.
// This says false
println!("do we see =>? {}", lookahead.peek(syn::token::FatArrow));
// this also says false
println!("do we see =>? {}", lookahead.peek(Token![=>]));
The parsing works fine, but if I can't look ahead, then I can't distinguish between the two cases. (Well, I can by forking the input stream and trying both rules, then replacing the stream with the one that worked, but that seems a bit dramatic when a peak at the next token, if only I knew how to, would solve the problem).
What am I doing wrong here? Do I need to call peek
with some other argument to match the token =>
?
There is a significance to when the Lookahead1
is created: it points to the location where the cursor was at the call to lookahead1()
. Lookahead1
is meant to use when you have a list of possible values, and you want to provide a nice error message when the value is invalid, listing all possible values. If you just want to peek the next token, use ParseBuffer::peek()
:
let res = if input.peek(syn::token::FatArrow) {
input.parse::<syn::token::FatArrow>()?;
Some(input.parse()?)
} else { None };