1 // pest. The Elegant Parser 2 // Copyright (c) 2018 Dragoș Tiselice 3 // 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. 9 10 //! Constructs useful in infix operator parsing with the precedence climbing method. 11 12 use alloc::borrow::Cow; 13 use alloc::boxed::Box; 14 use alloc::vec::Vec; 15 use core::iter::Peekable; 16 use core::ops::BitOr; 17 18 use crate::iterators::Pair; 19 use crate::RuleType; 20 21 /// Macro for more convenient const fn definition of `prec_climber::PrecClimber`. 22 /// 23 /// # Examples 24 /// 25 /// ``` 26 /// # use pest::prec_climber::{Assoc, PrecClimber}; 27 /// # use pest::prec_climber; 28 /// # #[allow(non_camel_case_types)] 29 /// # #[allow(dead_code)] 30 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 31 /// # enum Rule { 32 /// # plus, 33 /// # minus, 34 /// # times, 35 /// # divide, 36 /// # power 37 /// # } 38 /// static CLIMBER: PrecClimber<Rule> = prec_climber![ 39 /// L plus | minus, 40 /// L times | divide, 41 /// R power, 42 /// ]; 43 /// ``` 44 #[cfg(feature = "const_prec_climber")] 45 #[macro_export] 46 macro_rules! prec_climber { 47 ( 48 $( $assoc:ident $rule:ident $( | $rules:ident )* ),+ $(,)? 49 ) => {{ 50 prec_climber!( 51 @precedences { 1u32 } 52 $( [ $rule $( $rules )* ] )* 53 ); 54 55 $crate::prec_climber::PrecClimber::new_const( 56 prec_climber!( 57 @array 58 $( $assoc $rule $(, $assoc $rules )* ),* 59 ) 60 ) 61 }}; 62 63 ( @assoc L ) => { $crate::prec_climber::Assoc::Left }; 64 ( @assoc R ) => { $crate::prec_climber::Assoc::Right }; 65 66 ( 67 @array 68 $( 69 $assoc:ident $rule:ident 70 ),* 71 ) => { 72 &[ 73 $( 74 ( 75 Rule::$rule, 76 $rule, 77 prec_climber!( @assoc $assoc ), 78 ) 79 ),* 80 ] 81 }; 82 83 ( 84 @precedences { $precedence:expr } 85 ) => {}; 86 87 ( 88 @precedences { $precedence:expr } 89 [ $( $rule:ident )* ] 90 $( [ $( $rules:ident )* ] )* 91 ) => { 92 $( 93 #[allow(non_upper_case_globals)] 94 const $rule: u32 = $precedence; 95 )* 96 prec_climber!( 97 @precedences { 1u32 + $precedence } 98 $( [ $( $rules )* ] )* 99 ); 100 }; 101 } 102 103 /// Associativity of an [`Operator`]. 104 /// 105 /// [`Operator`]: struct.Operator.html 106 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 107 pub enum Assoc { 108 /// Left `Operator` associativity 109 Left, 110 /// Right `Operator` associativity 111 Right, 112 } 113 114 /// Infix operator used in [`PrecClimber`]. 115 /// 116 /// [`PrecClimber`]: struct.PrecClimber.html 117 #[derive(Debug)] 118 pub struct Operator<R: RuleType> { 119 rule: R, 120 assoc: Assoc, 121 next: Option<Box<Operator<R>>>, 122 } 123 124 impl<R: RuleType> Operator<R> { 125 /// Creates a new `Operator` from a `Rule` and `Assoc`. 126 /// 127 /// # Examples 128 /// 129 /// ``` 130 /// # use pest::prec_climber::{Assoc, Operator}; 131 /// # #[allow(non_camel_case_types)] 132 /// # #[allow(dead_code)] 133 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 134 /// # enum Rule { 135 /// # plus, 136 /// # minus 137 /// # } 138 /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Right); 139 /// ``` new(rule: R, assoc: Assoc) -> Operator<R>140 pub fn new(rule: R, assoc: Assoc) -> Operator<R> { 141 Operator { 142 rule, 143 assoc, 144 next: None, 145 } 146 } 147 } 148 149 impl<R: RuleType> BitOr for Operator<R> { 150 type Output = Self; 151 bitor(mut self, rhs: Self) -> Self152 fn bitor(mut self, rhs: Self) -> Self { 153 fn assign_next<R: RuleType>(op: &mut Operator<R>, next: Operator<R>) { 154 if let Some(ref mut child) = op.next { 155 assign_next(child, next); 156 } else { 157 op.next = Some(Box::new(next)); 158 } 159 } 160 161 assign_next(&mut self, rhs); 162 self 163 } 164 } 165 166 /// List of operators and precedences, which can perform [precedence climbing][1] on infix 167 /// expressions contained in a [`Pairs`]. The token pairs contained in the `Pairs` should start 168 /// with a *primary* pair and then alternate between an *operator* and a *primary*. 169 /// 170 /// [1]: https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method 171 /// [`Pairs`]: ../iterators/struct.Pairs.html 172 #[derive(Debug)] 173 pub struct PrecClimber<R: Clone + 'static> { 174 ops: Cow<'static, [(R, u32, Assoc)]>, 175 } 176 177 #[cfg(feature = "const_prec_climber")] 178 impl<R: Clone + 'static> PrecClimber<R> { 179 /// Creates a new `PrecClimber` directly from a static slice of 180 /// `(rule: Rule, precedence: u32, associativity: Assoc)` tuples. 181 /// 182 /// Precedence starts from `1`. Entries don't have to be ordered in any way, but it's easier to read when 183 /// sorted. 184 /// 185 /// # Examples 186 /// 187 /// ``` 188 /// # use pest::prec_climber::{Assoc, PrecClimber}; 189 /// # #[allow(non_camel_case_types)] 190 /// # #[allow(dead_code)] 191 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 192 /// # enum Rule { 193 /// # plus, 194 /// # minus, 195 /// # times, 196 /// # divide, 197 /// # power 198 /// # } 199 /// static CLIMBER: PrecClimber<Rule> = PrecClimber::new_const(&[ 200 /// (Rule::plus, 1, Assoc::Left), (Rule::minus, 1, Assoc::Left), 201 /// (Rule::times, 2, Assoc::Left), (Rule::divide, 2, Assoc::Left), 202 /// (Rule::power, 3, Assoc::Right) 203 /// ]); 204 /// ``` new_const(ops: &'static [(R, u32, Assoc)]) -> PrecClimber<R>205 pub const fn new_const(ops: &'static [(R, u32, Assoc)]) -> PrecClimber<R> { 206 PrecClimber { 207 ops: Cow::Borrowed(ops), 208 } 209 } 210 } 211 212 impl<R: RuleType> PrecClimber<R> { 213 // find matching operator by `rule` get(&self, rule: &R) -> Option<(u32, Assoc)>214 fn get(&self, rule: &R) -> Option<(u32, Assoc)> { 215 self.ops 216 .iter() 217 .find(|(r, _, _)| r == rule) 218 .map(|(_, precedence, assoc)| (*precedence, *assoc)) 219 } 220 221 /// Creates a new `PrecClimber` from the `Operator`s contained in `ops`. Every entry in the 222 /// `Vec` has precedence *index + 1*. In order to have operators with same precedence, they need 223 /// to be chained with `|` between them. 224 /// 225 /// # Examples 226 /// 227 /// ``` 228 /// # use pest::prec_climber::{Assoc, Operator, PrecClimber}; 229 /// # #[allow(non_camel_case_types)] 230 /// # #[allow(dead_code)] 231 /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] 232 /// # enum Rule { 233 /// # plus, 234 /// # minus, 235 /// # times, 236 /// # divide, 237 /// # power 238 /// # } 239 /// PrecClimber::new(vec![ 240 /// Operator::new(Rule::plus, Assoc::Left) | Operator::new(Rule::minus, Assoc::Left), 241 /// Operator::new(Rule::times, Assoc::Left) | Operator::new(Rule::divide, Assoc::Left), 242 /// Operator::new(Rule::power, Assoc::Right) 243 /// ]); 244 /// ``` new(ops: Vec<Operator<R>>) -> PrecClimber<R>245 pub fn new(ops: Vec<Operator<R>>) -> PrecClimber<R> { 246 let ops = ops 247 .into_iter() 248 .zip(1..) 249 .fold(Vec::new(), |mut vec, (op, prec)| { 250 let mut next = Some(op); 251 252 while let Some(op) = next.take() { 253 let Operator { 254 rule, 255 assoc, 256 next: op_next, 257 } = op; 258 259 vec.push((rule, prec, assoc)); 260 next = op_next.map(|op| *op); 261 } 262 263 vec 264 }); 265 266 PrecClimber { 267 ops: Cow::Owned(ops), 268 } 269 } 270 271 /// Performs the precedence climbing algorithm on the `pairs` in a similar manner to map-reduce. 272 /// *Primary* pairs are mapped with `primary` and then reduced to one single result with 273 /// `infix`. 274 /// 275 /// # Panics 276 /// 277 /// Panics will occur when `pairs` is empty or when the alternating *primary*, *operator*, 278 /// *primary* order is not respected. 279 /// 280 /// # Examples 281 /// 282 /// ```ignore 283 /// let primary = |pair| { 284 /// consume(pair, climber) 285 /// }; 286 /// let infix = |lhs: i32, op: Pair<Rule>, rhs: i32| { 287 /// match op.rule() { 288 /// Rule::plus => lhs + rhs, 289 /// Rule::minus => lhs - rhs, 290 /// Rule::times => lhs * rhs, 291 /// Rule::divide => lhs / rhs, 292 /// Rule::power => lhs.pow(rhs as u32), 293 /// _ => unreachable!() 294 /// } 295 /// }; 296 /// 297 /// let result = climber.climb(pairs, primary, infix); 298 /// ``` climb<'i, P, F, G, T>(&self, mut pairs: P, mut primary: F, mut infix: G) -> T where P: Iterator<Item = Pair<'i, R>>, F: FnMut(Pair<'i, R>) -> T, G: FnMut(T, Pair<'i, R>, T) -> T,299 pub fn climb<'i, P, F, G, T>(&self, mut pairs: P, mut primary: F, mut infix: G) -> T 300 where 301 P: Iterator<Item = Pair<'i, R>>, 302 F: FnMut(Pair<'i, R>) -> T, 303 G: FnMut(T, Pair<'i, R>, T) -> T, 304 { 305 let lhs = primary( 306 pairs 307 .next() 308 .expect("precedence climbing requires a non-empty Pairs"), 309 ); 310 self.climb_rec(lhs, 0, &mut pairs.peekable(), &mut primary, &mut infix) 311 } 312 climb_rec<'i, P, F, G, T>( &self, mut lhs: T, min_prec: u32, pairs: &mut Peekable<P>, primary: &mut F, infix: &mut G, ) -> T where P: Iterator<Item = Pair<'i, R>>, F: FnMut(Pair<'i, R>) -> T, G: FnMut(T, Pair<'i, R>, T) -> T,313 fn climb_rec<'i, P, F, G, T>( 314 &self, 315 mut lhs: T, 316 min_prec: u32, 317 pairs: &mut Peekable<P>, 318 primary: &mut F, 319 infix: &mut G, 320 ) -> T 321 where 322 P: Iterator<Item = Pair<'i, R>>, 323 F: FnMut(Pair<'i, R>) -> T, 324 G: FnMut(T, Pair<'i, R>, T) -> T, 325 { 326 while pairs.peek().is_some() { 327 let rule = pairs.peek().unwrap().as_rule(); 328 if let Some((prec, _)) = self.get(&rule) { 329 if prec >= min_prec { 330 let op = pairs.next().unwrap(); 331 let mut rhs = primary(pairs.next().expect( 332 "infix operator must be followed by \ 333 a primary expression", 334 )); 335 336 while pairs.peek().is_some() { 337 let rule = pairs.peek().unwrap().as_rule(); 338 if let Some((new_prec, assoc)) = self.get(&rule) { 339 if new_prec > prec || assoc == Assoc::Right && new_prec == prec { 340 rhs = self.climb_rec(rhs, new_prec, pairs, primary, infix); 341 } else { 342 break; 343 } 344 } else { 345 break; 346 } 347 } 348 349 lhs = infix(lhs, op, rhs); 350 } else { 351 break; 352 } 353 } else { 354 break; 355 } 356 } 357 358 lhs 359 } 360 } 361