]>
git.proxmox.com Git - rustc.git/blob - vendor/pest/src/prec_climber.rs
1 // pest. The Elegant Parser
2 // Copyright (c) 2018 DragoČ™ Tiselice
4 // Licensed under the Apache License, Version 2.0
5 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6 // license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. All files in the project carrying such notice may not be copied,
8 // modified, or distributed except according to those terms.
10 //! A `mod` containing constructs useful in infix operator parsing with the precedence climbing
13 use std
::collections
::HashMap
;
14 use std
::iter
::Peekable
;
20 /// An `enum` describing an `Operator`'s associativity.
21 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
23 /// Left `Operator` associativity
25 /// Right `Operator` associativity
29 /// A `struct` defining an infix operator used in [`PrecClimber`](struct.PrecClimber.html).
31 pub struct Operator
<R
: RuleType
> {
34 next
: Option
<Box
<Operator
<R
>>>
37 impl<R
: RuleType
> Operator
<R
> {
38 /// Creates a new `Operator` from a `Rule` and `Assoc`.
43 /// # use pest::prec_climber::{Assoc, Operator};
44 /// # #[allow(non_camel_case_types)]
45 /// # #[allow(dead_code)]
46 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
51 /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Right);
53 pub fn new(rule
: R
, assoc
: Assoc
) -> Operator
<R
> {
62 impl<R
: RuleType
> BitOr
for Operator
<R
> {
65 fn bitor(mut self, rhs
: Self) -> Self {
66 fn assign_next
<R
: RuleType
>(op
: &mut Operator
<R
>, next
: Operator
<R
>) {
67 if let Some(ref mut child
) = op
.next
{
68 assign_next(child
, next
);
70 op
.next
= Some(Box
::new(next
));
74 assign_next(&mut self, rhs
);
79 /// A `struct` useful in order to perform [precedence climbing][1] on infix expressions contained in
80 /// a [`Pairs`](../iterators/struct.Pairs.html). The token pairs contained in the `Pairs` should
81 /// start with a *primary* pair and then alternate between an *operator* and a *primary*.
83 /// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method
85 pub struct PrecClimber
<R
: RuleType
> {
86 ops
: HashMap
<R
, (u32, Assoc
)>
89 impl<R
: RuleType
> PrecClimber
<R
> {
90 /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the
91 /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need
92 /// to be chained with `|` between them.
97 /// # use pest::prec_climber::{Assoc, Operator, PrecClimber};
98 /// # #[allow(non_camel_case_types)]
99 /// # #[allow(dead_code)]
100 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
108 /// PrecClimber::new(vec![
109 /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left),
110 /// Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left),
111 /// Operator::new(Rule::power, Assoc::Right)
114 pub fn new(ops
: Vec
<Operator
<R
>>) -> PrecClimber
<R
> {
115 let ops
= ops
.into_iter()
117 .fold(HashMap
::new(), |mut map
, (op
, prec
)| {
118 let mut next
= Some(op
);
120 while let Some(op
) = next
.take() {
127 map
.insert(rule
, (prec
, assoc
));
128 next
= op_next
.map(|op
| *op
);
139 /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce.
140 /// *Primary* pairs are mapped with `primary` and then reduced to one single result with
145 /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*,
146 /// *primary* order is not respected.
151 /// let primary = |pair| {
152 /// consume(pair, climber)
154 /// let infix = |lhs: i32, op: Pair<Rule>, rhs: i32| {
155 /// match op.rule() {
156 /// Rule::plus => lhs + rhs,
157 /// Rule::minus => lhs - rhs,
158 /// Rule::times => lhs * rhs,
159 /// Rule::divide => lhs / rhs,
160 /// Rule::power => lhs.pow(rhs as u32),
161 /// _ => unreachable!()
165 /// let result = climber.climb(pairs, primary, infix);
167 pub fn climb
<'i
, P
, F
, G
, T
>(&self, mut pairs
: P
, mut primary
: F
, mut infix
: G
) -> T
169 P
: Iterator
<Item
= Pair
<'i
, R
>>,
170 F
: FnMut(Pair
<'i
, R
>) -> T
,
171 G
: FnMut(T
, Pair
<'i
, R
>, T
) -> T
176 .expect("precedence climbing requires a non-empty Pairs")
178 self.climb_rec(lhs
, 0, &mut pairs
.peekable(), &mut primary
, &mut infix
)
181 fn climb_rec
<'i
, P
, F
, G
, T
>(
185 pairs
: &mut Peekable
<P
>,
190 P
: Iterator
<Item
= Pair
<'i
, R
>>,
191 F
: FnMut(Pair
<'i
, R
>) -> T
,
192 G
: FnMut(T
, Pair
<'i
, R
>, T
) -> T
194 while pairs
.peek().is_some() {
195 let rule
= pairs
.peek().unwrap().as_rule();
196 if let Some(&(prec
, _
)) = self.ops
.get(&rule
) {
197 if prec
>= min_prec
{
198 let op
= pairs
.next().unwrap();
199 let mut rhs
= primary(pairs
.next().expect(
200 "infix operator must be followed by \
201 a primary expression"
204 while pairs
.peek().is_some() {
205 let rule
= pairs
.peek().unwrap().as_rule();
206 if let Some(&(new_prec
, assoc
)) = self.ops
.get(&rule
) {
207 if new_prec
> prec
|| assoc
== Assoc
::Right
&& new_prec
== prec
{
208 rhs
= self.climb_rec(rhs
, new_prec
, pairs
, primary
, infix
);
217 lhs
= infix(lhs
, op
, rhs
);