pub enum LeftAssoc<O, R> {
Binary {
lhs: Box<Self>,
op: O,
rhs: R,
},
Rhs(R),
}
Expand description
Helper type for parsing left-associative binary infix operators.
Prevents infinite left-recursion by parsing a stream of binary infix operators iteratively, then transforming the sequence of nodes into a left-leaning tree.
R
is the type of the right-hand side of the production, i.e., the sub-production at the next highest precedence level.O
is the type of the interleaved binary operator itself.
That is, a production in EBNF style would look like:
LeftAssoc = LeftAssoc O R
| R
Examples
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
enum AddOp {
Add(token::Add),
Sub(token::Sub),
}
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
enum MulOp {
Mul(token::Star),
Div(token::Div),
}
#[derive(PartialEq, Eq, Debug, Parse, ToTokens)]
enum Term {
Literal(Lit),
Variable(Ident),
Group(
#[parsel(recursive)]
Paren<Box<Expr>>
),
}
type Expr = LeftAssoc<
AddOp,
LeftAssoc<
MulOp,
Term
>
>;
let actual: Expr = parsel::parse_quote!{
10 - 2.99 + p / 42.0 - (q - -24.314) * -13
};
let expected = LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Rhs(LeftAssoc::Rhs(
Term::Literal(LitUint::from(10).into())
))),
op: AddOp::Sub(Default::default()),
rhs: LeftAssoc::Rhs(Term::Literal(
LitFloat::try_from(2.99).unwrap().into()
)),
}),
op: AddOp::Add(Default::default()),
rhs: LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Rhs(
Term::Variable(ident("p"))
)),
op: MulOp::Div(Default::default()),
rhs: Term::Literal(LitFloat::try_from(42.0).unwrap().into()),
},
}),
op: AddOp::Sub(Default::default()),
rhs: LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Rhs(
Term::Group(Paren::from(Box::new(
LeftAssoc::Binary {
lhs: Box::new(LeftAssoc::Rhs(LeftAssoc::Rhs(
Term::Variable(ident("q"))
))),
op: AddOp::Sub(Default::default()),
rhs: LeftAssoc::Rhs(Term::Literal(
LitFloat::try_from(-24.314).unwrap().into()
)),
}
)))
)),
op: MulOp::Mul(Default::default()),
rhs: Term::Literal(LitInt::from(-13).into()),
}
};
assert_eq!(actual, expected);
assert_eq!(actual.to_string(), expected.to_string());
assert_eq!(
expected.to_string(),
str::trim(r#"
10 - 2.99 + p / 42.0 - (
q - - 24.314
)
* - 13
"#),
);
Variants
Binary
Fields
lhs: Box<Self>
Left-hand side of the binary operation.
A left-associative binary infix operator was found.
Rhs(R)
No binary operator was found at this level of precedence, so simply forward to the next level.
Trait Implementations
sourceimpl<O, R> Parse for LeftAssoc<O, R>where
O: Parse,
R: Parse,
impl<O, R> Parse for LeftAssoc<O, R>where
O: Parse,
R: Parse,
fn parse(input: ParseStream<'_>) -> Result<Self>
sourceimpl<O: PartialEq, R: PartialEq> PartialEq<LeftAssoc<O, R>> for LeftAssoc<O, R>
impl<O: PartialEq, R: PartialEq> PartialEq<LeftAssoc<O, R>> for LeftAssoc<O, R>
sourceimpl<O, R> ToTokens for LeftAssoc<O, R>where
O: ToTokens,
R: ToTokens,
impl<O, R> ToTokens for LeftAssoc<O, R>where
O: ToTokens,
R: ToTokens,
sourcefn to_tokens(&self, tokens: &mut TokenStream)
fn to_tokens(&self, tokens: &mut TokenStream)
sourcefn to_token_stream(&self) -> TokenStream
fn to_token_stream(&self) -> TokenStream
sourcefn into_token_stream(self) -> TokenStreamwhere
Self: Sized,
fn into_token_stream(self) -> TokenStreamwhere
Self: Sized,
impl<O: Eq, R: Eq> Eq for LeftAssoc<O, R>
impl<O, R> StructuralEq for LeftAssoc<O, R>
impl<O, R> StructuralPartialEq for LeftAssoc<O, R>
Auto Trait Implementations
impl<O, R> RefUnwindSafe for LeftAssoc<O, R>where
O: RefUnwindSafe,
R: RefUnwindSafe,
impl<O, R> Send for LeftAssoc<O, R>where
O: Send,
R: Send,
impl<O, R> Sync for LeftAssoc<O, R>where
O: Sync,
R: Sync,
impl<O, R> Unpin for LeftAssoc<O, R>where
O: Unpin,
R: Unpin,
impl<O, R> UnwindSafe for LeftAssoc<O, R>where
O: UnwindSafe,
R: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
sourceimpl<T> Spanned for Twhere
T: Spanned + ?Sized,
impl<T> Spanned for Twhere
T: Spanned + ?Sized,
sourcefn span(&self) -> Span
fn span(&self) -> Span
Span
covering the complete contents of this syntax tree
node, or Span::call_site()
if this node is empty. Read moresourceimpl<T> SpannedExt for Twhere
T: Spanned + ?Sized,
impl<T> SpannedExt for Twhere
T: Spanned + ?Sized,
sourcefn byte_range(&self, source: &str) -> Range<usize>
fn byte_range(&self, source: &str) -> Range<usize>
TODO(H2CO3): a faster, less naive implementation would be great.
We should use the byte offset of start
to compute that of end
,
sparing the double scan of the source up until the start location.
let source = r#"
-3.667
1248 "string ű literal"
"wíőzs"
"#;
let tokens: Many<Lit> = source.parse()?;
assert_eq!(tokens.len(), 4);
assert_eq!(tokens[0].byte_range(source), 4..10);
assert_eq!(tokens[1].byte_range(source), 13..17);
assert_eq!(tokens[2].byte_range(source), 19..38);
assert_eq!(tokens[3].byte_range(source), 45..54);
sourcefn char_range(&self, source: &str) -> Range<usize>
fn char_range(&self, source: &str) -> Range<usize>
TODO(H2CO3): a faster, less naive implementation would be great.
We should use the char offset of start
to compute that of end
,
sparing the double scan of the source up until the start location.
let source = r#"
-3.667
1248 "string ű literal"
"wíőzs"
"#;
let tokens: Many<Lit> = source.parse()?;
assert_eq!(tokens.len(), 4);
assert_eq!(tokens[0].char_range(source), 4..10);
assert_eq!(tokens[1].char_range(source), 13..17);
assert_eq!(tokens[2].char_range(source), 19..37);
assert_eq!(tokens[3].char_range(source), 44..51);