Skip to main content

pest/
parser_state.rs

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//! The core functionality of parsing grammar.
11//! State of parser during the process of rules handling.
12
13use alloc::borrow::{Cow, ToOwned};
14use alloc::boxed::Box;
15use alloc::collections::BTreeSet;
16use alloc::rc::Rc;
17use alloc::string::String;
18use alloc::sync::Arc;
19use alloc::vec;
20use alloc::vec::Vec;
21use core::fmt::{Debug, Display, Formatter};
22use core::num::NonZeroUsize;
23use core::ops::Deref; // used in BorrowedOrRc.as_str
24use core::ops::Range;
25use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
26
27use crate::error::{Error, ErrorVariant};
28use crate::iterators::pairs::new;
29use crate::iterators::{pairs, QueueableToken};
30use crate::position::Position;
31use crate::span::Span;
32use crate::stack::Stack;
33use crate::RuleType;
34
35/// The current lookahead status of a [`ParserState`].
36///
37/// [`ParserState`]: struct.ParserState.html
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
39pub enum Lookahead {
40    /// The positive predicate, written as an ampersand &,
41    /// attempts to match its inner expression.
42    /// If the inner expression succeeds, parsing continues,
43    /// but at the same position as the predicate —
44    /// &foo ~ bar is thus a kind of "AND" statement:
45    /// "the input string must match foo AND bar".
46    /// If the inner expression fails,
47    /// the whole expression fails too.
48    Positive,
49    /// The negative predicate, written as an exclamation mark !,
50    /// attempts to match its inner expression.
51    /// If the inner expression fails, the predicate succeeds
52    /// and parsing continues at the same position as the predicate.
53    /// If the inner expression succeeds, the predicate fails —
54    /// !foo ~ bar is thus a kind of "NOT" statement:
55    /// "the input string must match bar but NOT foo".
56    Negative,
57    /// No lookahead (i.e. it will consume input).
58    None,
59}
60
61/// The current atomicity of a [`ParserState`].
62///
63/// [`ParserState`]: struct.ParserState.html
64#[derive(Clone, Copy, Debug, Eq, PartialEq)]
65pub enum Atomicity {
66    /// prevents implicit whitespace: inside an atomic rule,
67    /// the tilde ~ means "immediately followed by",
68    /// and repetition operators (asterisk * and plus sign +)
69    /// have no implicit separation. In addition, all other rules
70    /// called from an atomic rule are also treated as atomic.
71    /// (interior matching rules are silent)
72    Atomic,
73    /// The same as atomic, but inner tokens are produced as normal.
74    CompoundAtomic,
75    /// implicit whitespace is enabled
76    NonAtomic,
77}
78
79/// Type alias to simplify specifying the return value of chained closures.
80pub type ParseResult<S> = Result<S, S>;
81
82/// Match direction for the stack. Used in `PEEK[a..b]`/`stack_match_peek_slice`.
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
84pub enum MatchDir {
85    /// from the bottom to the top of the stack
86    BottomToTop,
87    /// from the top to the bottom of the stack
88    TopToBottom,
89}
90
91static CALL_LIMIT: AtomicUsize = AtomicUsize::new(0);
92
93/// Sets the maximum call limit for the parser state
94/// to prevent stack overflows or excessive execution times
95/// in some grammars.
96/// If set, the calls are tracked as a running total
97/// over all non-terminal rules that can nest closures
98/// (which are passed to transform the parser state).
99///
100/// # Arguments
101///
102/// * `limit` - The maximum number of calls. If None,
103///             the number of calls is unlimited.
104pub fn set_call_limit(limit: Option<NonZeroUsize>) {
105    CALL_LIMIT.store(limit.map(|f| f.get()).unwrap_or(0), Ordering::Relaxed);
106}
107
108static ERROR_DETAIL: AtomicBool = AtomicBool::new(false);
109
110/// Sets whether information for more error details
111/// should be collected. This is useful for debugging
112/// parser errors (as it leads to more comprehensive
113/// error messages), but it has a higher performance cost.
114/// (hence, it's off by default)
115///
116/// # Arguments
117///
118/// * `enabled` - Whether to enable the collection for
119///               more error details.
120pub fn set_error_detail(enabled: bool) {
121    ERROR_DETAIL.store(enabled, Ordering::Relaxed);
122}
123
124#[derive(Debug)]
125struct CallLimitTracker {
126    current_call_limit: Option<(usize, usize)>,
127}
128
129impl Default for CallLimitTracker {
130    fn default() -> Self {
131        let limit = CALL_LIMIT.load(Ordering::Relaxed);
132        let current_call_limit = if limit > 0 { Some((0, limit)) } else { None };
133        Self { current_call_limit }
134    }
135}
136
137impl CallLimitTracker {
138    fn limit_reached(&self) -> bool {
139        self.current_call_limit
140            .is_some_and(|(current, limit)| current >= limit)
141    }
142
143    fn increment_depth(&mut self) {
144        if let Some((current, _)) = &mut self.current_call_limit {
145            *current += 1;
146        }
147    }
148}
149
150/// Number of call stacks that may result from a sequence of rules parsing.
151const CALL_STACK_INITIAL_CAPACITY: usize = 20;
152/// Max (un)expected number of tokens that we may see on the parsing error position.
153const EXPECTED_TOKENS_INITIAL_CAPACITY: usize = 30;
154/// Max rule children number for which we'll extend calls stacks.
155///
156/// In case rule we're working with has too many children rules that failed in parsing,
157/// we don't want to store long stacks for all of them. If rule has more than this number
158/// of failed children, they all will be collapsed in a parent rule.
159const CALL_STACK_CHILDREN_THRESHOLD: usize = 4;
160
161/// Structure tracking errored parsing call (associated with specific `ParserState` function).
162#[derive(Debug, Hash, PartialEq, Eq, Clone, PartialOrd, Ord)]
163pub enum ParseAttempt<R> {
164    /// Call of `rule` errored.
165    Rule(R),
166    /// Call of token element (e.g., `match_string` or `match_insensitive`) errored.
167    /// Works as indicator of that leaf node is not a rule. In order to get the token value we
168    /// can address `ParseAttempts` `(un)expected_tokens`.
169    Token,
170}
171
172impl<R> ParseAttempt<R> {
173    pub fn get_rule(&self) -> Option<&R> {
174        match self {
175            ParseAttempt::Rule(r) => Some(r),
176            ParseAttempt::Token => None,
177        }
178    }
179}
180
181/// Rules call stack.
182/// Contains sequence of rule calls that resulted in new parsing attempt.
183#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
184pub struct RulesCallStack<R> {
185    /// Deepest rule caused a parsing error (ParseAttempt::Token transformed into a rule).
186    pub deepest: ParseAttempt<R>,
187    /// Most top rule covering `deepest`.
188    pub parent: Option<R>,
189}
190
191impl<R> RulesCallStack<R> {
192    fn new(deepest: ParseAttempt<R>) -> RulesCallStack<R> {
193        RulesCallStack {
194            deepest,
195            parent: None,
196        }
197    }
198}
199
200#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
201pub enum ParsingToken {
202    Sensitive { token: String },
203    Insensitive { token: String },
204    Range { start: char, end: char },
205    BuiltInRule,
206}
207
208impl Display for ParsingToken {
209    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
210        match self {
211            ParsingToken::Sensitive { token } => write!(f, "{token}"),
212            ParsingToken::Insensitive { token } => write!(f, "{}", token.to_uppercase()),
213            ParsingToken::Range { start, end } => write!(f, "{start}..{end}"),
214            ParsingToken::BuiltInRule => write!(f, "BUILTIN_RULE"),
215        }
216    }
217}
218/// A helper that provides efficient string handling without unnecessary copying.
219/// We use `Arc<String>` instead of `Cow<'i, str>` to avoid copying strings when cloning the `Owned` variant, since
220/// `Arc::clone` only increments a reference count. [SpanOrLiteral] needs to be [Send] and [Sync]`, so we use [Arc]
221/// instead of [Rc].
222///
223/// (We need to clone this struct to detach it from the `&self` borrow in [SpanOrLiteral::as_borrowed_or_rc], so that
224/// we can then call `self.match_string` (a `mut self` method).
225#[derive(Debug, Clone)]
226enum BorrowedOrArc<'i> {
227    Borrowed(&'i str),
228    Owned(Arc<String>),
229}
230
231/// A holder for a literal string, for use in `push_literal`. This is typically a `&'static str`, but is an owned
232/// `Rc<String>` for the pest vm.
233impl<'i> BorrowedOrArc<'i> {
234    fn as_str<'a: 'i>(&'a self) -> &'a str {
235        match self {
236            BorrowedOrArc::Borrowed(s) => s,
237            BorrowedOrArc::Owned(s) => s.deref(),
238        }
239    }
240}
241
242impl From<Cow<'static, str>> for BorrowedOrArc<'_> {
243    fn from(value: Cow<'static, str>) -> Self {
244        match value {
245            Cow::Borrowed(s) => Self::Borrowed(s),
246            Cow::Owned(s) => Self::Owned(Arc::new(s)),
247        }
248    }
249}
250
251#[derive(Debug, Clone)]
252enum SpanOrLiteral<'i> {
253    Span(Span<'i>),
254    Literal(BorrowedOrArc<'i>),
255}
256
257impl<'i> SpanOrLiteral<'i> {
258    #[inline]
259    fn as_borrowed_or_rc(&self) -> BorrowedOrArc<'i> {
260        match self {
261            Self::Span(s) => BorrowedOrArc::Borrowed(s.as_str()),
262            Self::Literal(s) => s.clone(),
263        }
264    }
265}
266
267/// Structure that tracks all the parsing attempts made on the max position.
268/// We want to give an error hint about parsing rules that succeeded
269/// at the farthest input position.
270/// The intuition is such rules will be most likely the query user initially wanted to write.
271#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
272pub struct ParseAttempts<R> {
273    /// Indicates whether the parsing attempts are tracked.
274    enabled: bool,
275    /// Vec of rule calls sequences awaiting tokens at the same `max_position`.
276    /// If there are several stacks in vec, it means all those rule stacks are "equal"
277    /// because their attempts occurred on the same position.
278    pub call_stacks: Vec<RulesCallStack<R>>,
279    /// Tokens that could be putted at `max_position`
280    /// in order to get a valid grammar query.
281    expected_tokens: Vec<ParsingToken>,
282    /// Tokens that we've prohibited to be putted at `max_position`
283    /// in order to get a valid grammar query.
284    unexpected_tokens: Vec<ParsingToken>,
285    /// Max position at which we were expecting to see one of `expected_tokens`.
286    pub max_position: usize,
287}
288
289impl<R: RuleType> ParseAttempts<R> {
290    /// Create new `ParseAttempts` instance with `call_stacks` and `expected_tokens`
291    /// initialized with capacity.
292    pub fn new() -> Self {
293        Self {
294            call_stacks: Vec::with_capacity(CALL_STACK_INITIAL_CAPACITY),
295            expected_tokens: Vec::with_capacity(EXPECTED_TOKENS_INITIAL_CAPACITY),
296            unexpected_tokens: Vec::with_capacity(EXPECTED_TOKENS_INITIAL_CAPACITY),
297            max_position: 0,
298            enabled: ERROR_DETAIL.load(Ordering::Relaxed),
299        }
300    }
301
302    /// Get number of currently present call stacks.
303    fn call_stacks_number(&self) -> usize {
304        self.call_stacks.len()
305    }
306
307    pub fn expected_tokens(&self) -> Vec<ParsingToken> {
308        self.expected_tokens
309            .iter()
310            .cloned()
311            .collect::<BTreeSet<_>>()
312            .into_iter()
313            .collect()
314    }
315
316    pub fn unexpected_tokens(&self) -> Vec<ParsingToken> {
317        self.unexpected_tokens
318            .iter()
319            .cloned()
320            .collect::<BTreeSet<_>>()
321            .into_iter()
322            .collect()
323    }
324
325    /// Retrieve call stacks.
326    pub fn call_stacks(&self) -> Vec<RulesCallStack<R>> {
327        self.call_stacks
328            .iter()
329            .cloned()
330            .collect::<BTreeSet<_>>()
331            .into_iter()
332            .collect()
333    }
334
335    /// In case we've tried to parse a rule, which start position is bigger than previous
336    /// `max_position` it means that we've advanced in our parsing and found better candidate.
337    ///
338    /// `start_index` is:
339    /// * Number of call stacks present in state at the moment current `rule` was called. The idea
340    ///   is that we'd like to update only those stacks that originated from the current `rule` and
341    ///   not from those that were called previously.
342    /// * 0 in case we've successfully parsed some token since the moment `rule` was called.
343    fn try_add_new_stack_rule(&mut self, rule: R, start_index: usize) {
344        let mut non_token_call_stacks = Vec::new();
345        let mut token_call_stack_met = false;
346        for call_stack in self.call_stacks.iter().skip(start_index) {
347            if matches!(call_stack.deepest, ParseAttempt::Token) {
348                token_call_stack_met = true;
349            } else {
350                non_token_call_stacks.push(call_stack.clone())
351            }
352        }
353        if token_call_stack_met && non_token_call_stacks.is_empty() {
354            // If `non_token_call_stacks` is not empty we wouldn't like to add a new standalone
355            // `RulesCallStack::new(ParseAttempt::Token)` (that will later be transformed into a
356            // rule) as soon as it doesn't give us any useful additional info.
357            non_token_call_stacks.push(RulesCallStack::new(ParseAttempt::Token));
358        }
359        self.call_stacks
360            .splice(start_index.., non_token_call_stacks);
361
362        let children_number_over_threshold =
363            self.call_stacks_number() - start_index >= CALL_STACK_CHILDREN_THRESHOLD;
364        if children_number_over_threshold {
365            self.call_stacks.truncate(start_index);
366            self.call_stacks
367                .push(RulesCallStack::new(ParseAttempt::Rule(rule)));
368        } else {
369            for call_stack in self.call_stacks.iter_mut().skip(start_index) {
370                if matches!(call_stack.deepest, ParseAttempt::Token) {
371                    call_stack.deepest = ParseAttempt::Rule(rule);
372                } else {
373                    call_stack.parent = Some(rule);
374                }
375            }
376        }
377    }
378
379    /// If `expected` flag is set to false, it means we've successfully parsed token being in the
380    /// state of negative lookahead and want to track `token` in the `unexpected_tokens`. Otherwise,
381    /// we want to track it the `expected_tokens`. Let's call chosen vec a `target_vec`.
382    ///
383    /// In case `position` is:
384    /// * Equal to `max_position`, add `token` to `target_vec`,
385    /// * Bigger than `max_position`, set `token` as the only new element of `target_vec`.
386    #[allow(clippy::comparison_chain)]
387    fn try_add_new_token(
388        &mut self,
389        token: ParsingToken,
390        start_position: usize,
391        position: usize,
392        negative_lookahead: bool,
393    ) {
394        let target_vec_push_token = |attempts: &mut ParseAttempts<R>| {
395            let target_vec = if negative_lookahead {
396                &mut attempts.unexpected_tokens
397            } else {
398                &mut attempts.expected_tokens
399            };
400            target_vec.push(token);
401        };
402
403        if position > self.max_position {
404            if negative_lookahead && start_position > self.max_position {
405                // We encountered a sequence under negative lookahead.
406                // We would like to track only first failed token in this sequence (which
407                // `start_position` should be equal to `self.max_position`).
408                return;
409            }
410            target_vec_push_token(self);
411
412            if negative_lookahead {
413                // In case of successful parsing of token under negative lookahead the only
414                // thing we'd like to do is to track the token in the `unexpected_tokens`.
415                return;
416            }
417            self.max_position = position;
418            self.expected_tokens.clear();
419            self.unexpected_tokens.clear();
420            self.call_stacks.clear();
421            self.call_stacks
422                .push(RulesCallStack::new(ParseAttempt::Token));
423        } else if position == self.max_position {
424            target_vec_push_token(self);
425            self.call_stacks
426                .push(RulesCallStack::new(ParseAttempt::Token));
427        }
428    }
429
430    /// Reset state in case we've successfully parsed some token in
431    /// `match_string` or `match_insensitive`.
432    fn nullify_expected_tokens(&mut self, new_max_position: usize) {
433        self.call_stacks.clear();
434        self.expected_tokens.clear();
435        self.unexpected_tokens.clear();
436        self.max_position = new_max_position;
437    }
438}
439
440impl<R: RuleType> Default for ParseAttempts<R> {
441    fn default() -> Self {
442        Self::new()
443    }
444}
445
446/// The complete state of a [`Parser`].
447///
448/// [`Parser`]: trait.Parser.html
449#[derive(Debug)]
450pub struct ParserState<'i, R: RuleType> {
451    /// Current position from which we try to apply some parser function.
452    /// Initially is 0.
453    /// E.g., we are parsing `create user 'Bobby'` query, we parsed "create" via `match_insensitive`
454    /// and switched our `position` from 0 to the length of "create".
455    ///
456    /// E.g., see `match_string` -> `self.position.match_string(string)` which updates `self.pos`.
457    position: Position<'i>,
458    /// Queue representing rules partially (`QueueableToken::Start`) and
459    /// totally (`QueueableToken::End`) parsed. When entering rule we put it in the queue in a state
460    /// of `Start` and after all its sublogic (subrules or strings) are parsed, we change it to
461    /// `End` state.
462    queue: Vec<QueueableToken<'i, R>>,
463    /// Status set in case specific lookahead logic is used in grammar.
464    /// See `Lookahead` for more information.
465    lookahead: Lookahead,
466    /// Rules that we HAVE expected, tried to parse, but failed.
467    pos_attempts: Vec<R>,
468    /// Rules that we have NOT expected, tried to parse, but failed.
469    neg_attempts: Vec<R>,
470    /// Max position in the query from which we've tried to parse some rule but failed.
471    attempt_pos: usize,
472    /// Current atomicity status. For more information see `Atomicity`.
473    atomicity: Atomicity,
474    /// Helper structure tracking `Stack` status (used in case grammar contains stack PUSH/POP
475    /// invocations).
476    stack: Stack<SpanOrLiteral<'i>>,
477    /// Used for setting max parser calls limit.
478    call_tracker: CallLimitTracker,
479    /// Together with tracking of `pos_attempts` and `attempt_pos`
480    /// as a pair of (list of rules that we've tried to parse but failed, max parsed position)
481    /// we track those rules (which we've tried to parse at the same max pos) at this helper struct.
482    ///
483    /// Note, that we may try to parse several rules on different positions. We want to track only
484    /// those rules, which attempt position is bigger, because we consider that it's nearer to the
485    /// query that user really wanted to pass.
486    ///
487    /// E.g. we have a query `create user "Bobby"` and two root rules:
488    /// * CreateUser  = { "create" ~ "user"  ~ Name }
489    /// * CreateTable = { "create" ~ "table" ~ Name }
490    /// * Name = { SOME_DEFINITION }
491    ///
492    /// While parsing the query we'll update tracker position to the start of "Bobby", because we'd
493    /// successfully parse "create" + "user" (and not "table").
494    parse_attempts: ParseAttempts<R>,
495}
496
497/// Creates a `ParserState` from a `&str`, supplying it to a closure `f`.
498///
499/// # Examples
500///
501/// ```
502/// # use pest;
503/// let input = "";
504/// pest::state::<(), _>(input, |s| Ok(s)).unwrap();
505/// ```
506#[allow(clippy::perf)]
507pub fn state<'i, R: RuleType, F>(input: &'i str, f: F) -> Result<pairs::Pairs<'i, R>, Error<R>>
508where
509    F: FnOnce(Box<ParserState<'i, R>>) -> ParseResult<Box<ParserState<'i, R>>>,
510{
511    let state = ParserState::new(input);
512
513    match f(state) {
514        Ok(state) => {
515            let len = state.queue.len();
516            Ok(new(Rc::new(state.queue), input, None, 0, len))
517        }
518        Err(mut state) => {
519            let variant = if state.reached_call_limit() {
520                ErrorVariant::CustomError {
521                    message: "call limit reached".to_owned(),
522                }
523            } else {
524                state.pos_attempts.sort();
525                state.pos_attempts.dedup();
526                state.neg_attempts.sort();
527                state.neg_attempts.dedup();
528                ErrorVariant::ParsingError {
529                    positives: state.pos_attempts.clone(),
530                    negatives: state.neg_attempts.clone(),
531                }
532            };
533
534            if state.parse_attempts.enabled {
535                Err(Error::new_from_pos_with_parsing_attempts(
536                    variant,
537                    Position::new_internal(input, state.attempt_pos),
538                    state.parse_attempts.clone(),
539                ))
540            } else {
541                Err(Error::new_from_pos(
542                    variant,
543                    Position::new_internal(input, state.attempt_pos),
544                ))
545            }
546        }
547    }
548}
549
550impl<'i, R: RuleType> ParserState<'i, R> {
551    /// Allocates a fresh `ParserState` object to the heap and returns the owned `Box`. This `Box`
552    /// will be passed from closure to closure based on the needs of the specified `Parser`.
553    ///
554    /// # Examples
555    ///
556    /// ```
557    /// # use pest;
558    /// let input = "";
559    /// let state: Box<pest::ParserState<&str>> = pest::ParserState::new(input);
560    /// ```
561    pub fn new(input: &'i str) -> Box<Self> {
562        Box::new(ParserState {
563            position: Position::from_start(input),
564            queue: vec![],
565            lookahead: Lookahead::None,
566            pos_attempts: vec![],
567            neg_attempts: vec![],
568            attempt_pos: 0,
569            atomicity: Atomicity::NonAtomic,
570            stack: Stack::new(),
571            call_tracker: Default::default(),
572            parse_attempts: ParseAttempts::new(),
573        })
574    }
575
576    /// Get all parse attempts after process of parsing is finished.
577    pub fn get_parse_attempts(&self) -> &ParseAttempts<R> {
578        &self.parse_attempts
579    }
580
581    /// Returns a reference to the current `Position` of the `ParserState`.
582    ///
583    /// # Examples
584    ///
585    /// ```
586    /// # use pest;
587    /// # #[allow(non_camel_case_types)]
588    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
589    /// enum Rule {
590    ///     ab
591    /// }
592    ///
593    /// let input = "ab";
594    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
595    /// let position = state.position();
596    /// assert_eq!(position.pos(), 0);
597    /// ```
598    pub fn position(&self) -> &Position<'i> {
599        &self.position
600    }
601
602    /// Returns the current atomicity of the `ParserState`.
603    ///
604    /// # Examples
605    ///
606    /// ```
607    /// # use pest;
608    /// # use pest::Atomicity;
609    /// # #[allow(non_camel_case_types)]
610    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
611    /// enum Rule {
612    ///     ab
613    /// }
614    ///
615    /// let input = "ab";
616    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
617    /// let atomicity = state.atomicity();
618    /// assert_eq!(atomicity, Atomicity::NonAtomic);
619    /// ```
620    pub fn atomicity(&self) -> Atomicity {
621        self.atomicity
622    }
623
624    #[inline]
625    fn inc_call_check_limit(mut self: Box<Self>) -> ParseResult<Box<Self>> {
626        if self.call_tracker.limit_reached() {
627            return Err(self);
628        }
629        self.call_tracker.increment_depth();
630        Ok(self)
631    }
632
633    #[inline]
634    fn reached_call_limit(&self) -> bool {
635        self.call_tracker.limit_reached()
636    }
637
638    /// Wrapper needed to generate tokens. This will associate the `R` type rule to the closure
639    /// meant to match the rule.
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// # use pest;
645    /// # #[allow(non_camel_case_types)]
646    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
647    /// enum Rule {
648    ///     a
649    /// }
650    ///
651    /// let input = "a";
652    /// let pairs: Vec<_> = pest::state(input, |state| {
653    ///     state.rule(Rule::a, |s| Ok(s))
654    /// }).unwrap().collect();
655    ///
656    /// assert_eq!(pairs.len(), 1);
657    /// ```
658    #[inline]
659    pub fn rule<F>(mut self: Box<Self>, rule: R, f: F) -> ParseResult<Box<Self>>
660    where
661        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
662    {
663        self = self.inc_call_check_limit()?;
664        // Position from which this `rule` starts parsing.
665        let actual_pos = self.position.pos();
666        // Remember index of the `self.queue` element that will be associated with this `rule`.
667        let index = self.queue.len();
668
669        let (pos_attempts_index, neg_attempts_index) = if actual_pos == self.attempt_pos {
670            (self.pos_attempts.len(), self.neg_attempts.len())
671        } else {
672            // Attempts have not been cleared yet since the attempt_pos is older.
673            (0, 0)
674        };
675
676        if self.lookahead == Lookahead::None && self.atomicity != Atomicity::Atomic {
677            // Pair's position will only be known after running the closure.
678            self.queue.push(QueueableToken::Start {
679                end_token_index: 0,
680                input_pos: actual_pos,
681            });
682        }
683
684        // Remember attempts number before `f` call.
685        // In `track` using this variable we can say, how many attempts were added
686        // during children rules traversal.
687        let attempts = self.attempts_at(actual_pos);
688        // Number of call stacks present in `self.parse_attempts` before `f` call.
689        // We need to remember this number only in case there wasn't found any farther attempt.
690        // E.g. we are handling rule, on start position of which may be tested two
691        // children rules. At the moment we'll return from `f` call below,
692        // there will be two more children rules in `self.parse_attempts` that we'll
693        // consider to be the children of current `rule`.
694        let mut remember_call_stacks_number = self.parse_attempts.call_stacks_number();
695        // Max parsing attempt position at the moment of `rule` handling.
696        // It case it's raised during children rules handling, it means
697        // we've made a parsing progress.
698        let remember_max_position = self.parse_attempts.max_position;
699
700        let result = f(self);
701
702        let mut try_add_rule_to_stack = |new_state: &mut Box<ParserState<'_, R>>| {
703            if new_state.parse_attempts.max_position > remember_max_position {
704                // It means that one of `match_string` or e.g. `match_insensitive` function calls
705                // have already erased `self.parse_attempts.call_stacks` and that previously
706                // remembered values are not valid anymore.
707                remember_call_stacks_number = 0;
708            }
709            if !matches!(new_state.atomicity, Atomicity::Atomic) {
710                new_state
711                    .parse_attempts
712                    .try_add_new_stack_rule(rule, remember_call_stacks_number);
713            }
714        };
715
716        match result {
717            Ok(mut new_state) => {
718                if new_state.lookahead == Lookahead::Negative {
719                    new_state.track(
720                        rule,
721                        actual_pos,
722                        pos_attempts_index,
723                        neg_attempts_index,
724                        attempts,
725                    );
726                }
727
728                if new_state.lookahead == Lookahead::None
729                    && new_state.atomicity != Atomicity::Atomic
730                {
731                    // Index of `QueueableToken::End` token added below
732                    // that corresponds to previously added `QueueableToken::Start` token.
733                    let new_index = new_state.queue.len();
734                    match new_state.queue[index] {
735                        QueueableToken::Start {
736                            ref mut end_token_index,
737                            ..
738                        } => *end_token_index = new_index,
739                        _ => unreachable!(),
740                    };
741
742                    let new_pos = new_state.position.pos();
743
744                    new_state.queue.push(QueueableToken::End {
745                        start_token_index: index,
746                        rule,
747                        tag: None,
748                        input_pos: new_pos,
749                    });
750                }
751
752                // Note, that we need to count positive parsing results too, because we can fail in
753                // optional rule call inside which may lie the farthest
754                // parsed token.
755                if new_state.parse_attempts.enabled {
756                    try_add_rule_to_stack(&mut new_state);
757                }
758                Ok(new_state)
759            }
760            Err(mut new_state) => {
761                if new_state.lookahead != Lookahead::Negative {
762                    new_state.track(
763                        rule,
764                        actual_pos,
765                        pos_attempts_index,
766                        neg_attempts_index,
767                        attempts,
768                    );
769                    if new_state.parse_attempts.enabled {
770                        try_add_rule_to_stack(&mut new_state);
771                    }
772                }
773
774                if new_state.lookahead == Lookahead::None
775                    && new_state.atomicity != Atomicity::Atomic
776                {
777                    new_state.queue.truncate(index);
778                }
779
780                Err(new_state)
781            }
782        }
783    }
784
785    /// Tag current node
786    ///
787    /// # Examples
788    ///
789    /// Try to recognize the one specified in a set of characters
790    ///
791    /// ```
792    /// use pest::{state, ParseResult, ParserState, iterators::Pair};
793    /// #[allow(non_camel_case_types)]
794    /// #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
795    /// enum Rule {
796    ///     character,
797    /// }
798    /// fn mark_c(state: Box<ParserState<Rule>>) -> ParseResult<Box<ParserState<Rule>>> {
799    ///     state.sequence(|state| {
800    ///         character(state)
801    ///             .and_then(|state| character(state))
802    ///             .and_then(|state| character(state))
803    ///             .and_then(|state| state.tag_node("c"))
804    ///             .and_then(|state| character(state))
805    ///     })
806    /// }
807    /// fn character(state: Box<ParserState<Rule>>) -> ParseResult<Box<ParserState<Rule>>> {
808    ///     state.rule(Rule::character, |state| state.match_range('a'..'z'))
809    /// }
810    ///
811    /// let input = "abcd";
812    /// let pairs = state(input, mark_c).unwrap();
813    /// // find all node tag as `c`
814    /// let find: Vec<Pair<Rule>> = pairs.filter(|s| s.as_node_tag() == Some("c")).collect();
815    /// assert_eq!(find[0].as_str(), "c")
816    /// ```
817    #[inline]
818    pub fn tag_node(mut self: Box<Self>, tag: &'i str) -> ParseResult<Box<Self>> {
819        if self.lookahead != Lookahead::None {
820            return Ok(self);
821        }
822        if let Some(QueueableToken::End { tag: old, .. }) = self.queue.last_mut() {
823            *old = Some(tag)
824        }
825        Ok(self)
826    }
827
828    /// Get number of allowed rules attempts + prohibited rules attempts.
829    fn attempts_at(&self, pos: usize) -> usize {
830        if self.attempt_pos == pos {
831            self.pos_attempts.len() + self.neg_attempts.len()
832        } else {
833            0
834        }
835    }
836
837    fn track(
838        &mut self,
839        rule: R,
840        pos: usize,
841        pos_attempts_index: usize,
842        neg_attempts_index: usize,
843        prev_attempts: usize,
844    ) {
845        if self.atomicity == Atomicity::Atomic {
846            return;
847        }
848
849        // If nested rules made no progress, there is no use to report them; it's only useful to
850        // track the current rule, the exception being when only one attempt has been made during
851        // the children rules.
852        let curr_attempts = self.attempts_at(pos);
853        if curr_attempts > prev_attempts && curr_attempts - prev_attempts == 1 {
854            return;
855        }
856
857        if pos == self.attempt_pos {
858            self.pos_attempts.truncate(pos_attempts_index);
859            self.neg_attempts.truncate(neg_attempts_index);
860        }
861
862        if pos > self.attempt_pos {
863            self.pos_attempts.clear();
864            self.neg_attempts.clear();
865            self.attempt_pos = pos;
866        }
867
868        let attempts = if self.lookahead != Lookahead::Negative {
869            &mut self.pos_attempts
870        } else {
871            &mut self.neg_attempts
872        };
873
874        if pos == self.attempt_pos {
875            attempts.push(rule);
876        }
877    }
878
879    /// Starts a sequence of transformations provided by `f` from the `Box<ParserState>`. Returns
880    /// the same `Result` returned by `f` in the case of an `Ok`, or `Err` with the current
881    /// `Box<ParserState>` otherwise.
882    ///
883    /// This method is useful to parse sequences that only match together which usually come in the
884    /// form of chained `Result`s with
885    /// [`Result::and_then`](https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then).
886    ///
887    ///
888    /// # Examples
889    ///
890    /// ```
891    /// # use pest;
892    /// # #[allow(non_camel_case_types)]
893    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
894    /// enum Rule {
895    ///     a
896    /// }
897    ///
898    /// let input = "a";
899    /// let pairs: Vec<_> = pest::state(input, |state| {
900    ///     state.sequence(|s| {
901    ///         s.rule(Rule::a, |s| Ok(s)).and_then(|s| {
902    ///             s.match_string("b")
903    ///         })
904    ///     }).or_else(|s| {
905    ///         Ok(s)
906    ///     })
907    /// }).unwrap().collect();
908    ///
909    /// assert_eq!(pairs.len(), 0);
910    /// ```
911    #[inline]
912    pub fn sequence<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
913    where
914        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
915    {
916        self = self.inc_call_check_limit()?;
917        let token_index = self.queue.len();
918        let initial_pos = self.position;
919
920        let result = f(self);
921
922        match result {
923            Ok(new_state) => Ok(new_state),
924            Err(mut new_state) => {
925                // Restore the initial position and truncate the token queue.
926                new_state.position = initial_pos;
927                new_state.queue.truncate(token_index);
928                Err(new_state)
929            }
930        }
931    }
932
933    /// Repeatedly applies the transformation provided by `f` from the `Box<ParserState>`. Returns
934    /// `Ok` with the updated `Box<ParserState>` returned by `f` wrapped up in an `Err`.
935    ///
936    /// # Examples
937    ///
938    /// ```
939    /// # use pest;
940    /// # #[allow(non_camel_case_types)]
941    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
942    /// enum Rule {
943    ///     ab
944    /// }
945    ///
946    /// let input = "aab";
947    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
948    /// let mut result = state.repeat(|s| {
949    ///     s.match_string("a")
950    /// });
951    /// assert!(result.is_ok());
952    /// assert_eq!(result.unwrap().position().pos(), 2);
953    ///
954    /// state = pest::ParserState::new(input);
955    /// result = state.repeat(|s| {
956    ///     s.match_string("b")
957    /// });
958    /// assert!(result.is_ok());
959    /// assert_eq!(result.unwrap().position().pos(), 0);
960    /// ```
961    #[inline]
962    pub fn repeat<F>(mut self: Box<Self>, mut f: F) -> ParseResult<Box<Self>>
963    where
964        F: FnMut(Box<Self>) -> ParseResult<Box<Self>>,
965    {
966        self = self.inc_call_check_limit()?;
967        let mut result = f(self);
968
969        loop {
970            match result {
971                Ok(state) => result = f(state),
972                Err(state) => return Ok(state),
973            };
974        }
975    }
976
977    /// Optionally applies the transformation provided by `f` from the `Box<ParserState>`. Returns
978    /// `Ok` with the updated `Box<ParserState>` returned by `f` regardless of the `Result`.
979    ///
980    /// # Examples
981    ///
982    /// ```
983    /// # use pest;
984    /// # #[allow(non_camel_case_types)]
985    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
986    /// enum Rule {
987    ///     ab
988    /// }
989    ///
990    /// let input = "ab";
991    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
992    /// let result = state.optional(|s| {
993    ///     s.match_string("ab")
994    /// });
995    /// assert!(result.is_ok());
996    ///
997    /// state = pest::ParserState::new(input);
998    /// let result = state.optional(|s| {
999    ///     s.match_string("ac")
1000    /// });
1001    /// assert!(result.is_ok());
1002    /// ```
1003    #[inline]
1004    pub fn optional<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
1005    where
1006        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1007    {
1008        self = self.inc_call_check_limit()?;
1009        match f(self) {
1010            Ok(state) | Err(state) => Ok(state),
1011        }
1012    }
1013
1014    /// Generic function to handle result of char/string/range parsing
1015    /// in order to track (un)expected tokens.
1016    fn handle_token_parse_result(
1017        &mut self,
1018        start_position: usize,
1019        token: ParsingToken,
1020        parse_succeeded: bool,
1021    ) {
1022        // New position after tracked parsed element for case of `parse_succeeded` is true.
1023        // Position of parsing failure otherwise.
1024        let current_pos = self.position.pos();
1025
1026        if parse_succeeded {
1027            if self.lookahead == Lookahead::Negative {
1028                self.parse_attempts
1029                    .try_add_new_token(token, start_position, current_pos, true);
1030            } else if current_pos > self.parse_attempts.max_position {
1031                self.parse_attempts.nullify_expected_tokens(current_pos);
1032            }
1033        } else if self.lookahead != Lookahead::Negative {
1034            self.parse_attempts
1035                .try_add_new_token(token, start_position, current_pos, false);
1036        }
1037    }
1038
1039    /// Attempts to match a single character based on a filter function. Returns `Ok` with the
1040    /// updated `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>`
1041    /// otherwise.
1042    ///
1043    /// # Examples
1044    ///
1045    /// ```
1046    /// # use pest;
1047    /// # #[allow(non_camel_case_types)]
1048    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1049    /// enum Rule {}
1050    ///
1051    /// let input = "ab";
1052    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1053    /// let result = state.match_char_by(|c| c.is_ascii());
1054    /// assert!(result.is_ok());
1055    /// assert_eq!(result.unwrap().position().pos(), 1);
1056    ///
1057    /// let input = "❤";
1058    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1059    /// let result = state.match_char_by(|c| c.is_ascii());
1060    /// assert!(result.is_err());
1061    /// assert_eq!(result.unwrap_err().position().pos(), 0);
1062    /// ```
1063    #[inline]
1064    pub fn match_char_by<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
1065    where
1066        F: FnOnce(char) -> bool,
1067    {
1068        let start_position = self.position.pos();
1069        let succeeded = self.position.match_char_by(f);
1070        if self.parse_attempts.enabled {
1071            let token = ParsingToken::BuiltInRule;
1072            self.handle_token_parse_result(start_position, token, succeeded);
1073        }
1074        if succeeded {
1075            Ok(self)
1076        } else {
1077            Err(self)
1078        }
1079    }
1080
1081    /// Attempts to match the given string. Returns `Ok` with the updated `Box<ParserState>` if
1082    /// successful, or `Err` with the updated `Box<ParserState>` otherwise.
1083    ///
1084    /// # Examples
1085    ///
1086    /// ```
1087    /// # use pest;
1088    /// # #[allow(non_camel_case_types)]
1089    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1090    /// enum Rule {}
1091    ///
1092    /// let input = "ab";
1093    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1094    /// let mut result = state.match_string("ab");
1095    /// assert!(result.is_ok());
1096    /// assert_eq!(result.unwrap().position().pos(), 2);
1097    ///
1098    /// state = pest::ParserState::new(input);
1099    /// result = state.match_string("ac");
1100    /// assert!(result.is_err());
1101    /// assert_eq!(result.unwrap_err().position().pos(), 0);
1102    /// ```
1103    #[inline]
1104    pub fn match_string(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
1105        let start_position = self.position.pos();
1106        let succeeded = self.position.match_string(string);
1107        if self.parse_attempts.enabled {
1108            let token = ParsingToken::Sensitive {
1109                token: String::from(string),
1110            };
1111            self.handle_token_parse_result(start_position, token, succeeded);
1112        }
1113        if succeeded {
1114            Ok(self)
1115        } else {
1116            Err(self)
1117        }
1118    }
1119
1120    /// Pushes the given literal to the stack, and always returns `Ok(Box<ParserState>)`.
1121    ///
1122    /// # Examples
1123    ///
1124    /// ```
1125    /// # use pest;
1126    /// # #[allow(non_camel_case_types)]
1127    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1128    /// enum Rule {}
1129    ///
1130    /// let input = "ab";
1131    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1132    ///
1133    /// let mut result = state.stack_push_literal("a");
1134    /// assert!(result.is_ok());
1135    /// assert_eq!(result.as_ref().unwrap().position().pos(), 0);
1136    ///
1137    /// let mut result = result.unwrap().stack_pop();
1138    /// assert!(result.is_ok());
1139    /// assert_eq!(result.unwrap().position().pos(), 1);
1140    /// ```
1141    #[inline]
1142    pub fn stack_push_literal(
1143        mut self: Box<Self>,
1144        string: impl Into<Cow<'static, str>>,
1145    ) -> ParseResult<Box<Self>> {
1146        // convert string into a Literal, and then into a BorrowedOrRc
1147        self.stack
1148            .push(SpanOrLiteral::Literal(string.into().into()));
1149        Ok(self)
1150    }
1151
1152    /// Attempts to case-insensitively match the given string. Returns `Ok` with the updated
1153    /// `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>` otherwise.
1154    ///
1155    /// # Examples
1156    ///
1157    /// ```
1158    /// # use pest;
1159    /// # #[allow(non_camel_case_types)]
1160    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1161    /// enum Rule {}
1162    ///
1163    /// let input = "ab";
1164    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1165    /// let mut result = state.match_insensitive("AB");
1166    /// assert!(result.is_ok());
1167    /// assert_eq!(result.unwrap().position().pos(), 2);
1168    ///
1169    /// state = pest::ParserState::new(input);
1170    /// result = state.match_insensitive("AC");
1171    /// assert!(result.is_err());
1172    /// assert_eq!(result.unwrap_err().position().pos(), 0);
1173    /// ```
1174    #[inline]
1175    pub fn match_insensitive(mut self: Box<Self>, string: &str) -> ParseResult<Box<Self>> {
1176        let start_position: usize = self.position().pos();
1177        let succeeded = self.position.match_insensitive(string);
1178        if self.parse_attempts.enabled {
1179            let token = ParsingToken::Insensitive {
1180                token: String::from(string),
1181            };
1182            self.handle_token_parse_result(start_position, token, succeeded);
1183        }
1184        if succeeded {
1185            Ok(self)
1186        } else {
1187            Err(self)
1188        }
1189    }
1190
1191    /// Attempts to match a single character from the given range. Returns `Ok` with the updated
1192    /// `Box<ParserState>` if successful, or `Err` with the updated `Box<ParserState>` otherwise.
1193    ///
1194    /// # Caution
1195    /// The provided `range` is interpreted as inclusive.
1196    ///
1197    /// # Examples
1198    ///
1199    /// ```
1200    /// # use pest;
1201    /// # #[allow(non_camel_case_types)]
1202    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1203    /// enum Rule {}
1204    ///
1205    /// let input = "ab";
1206    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1207    /// let mut result = state.match_range('a'..'z');
1208    /// assert!(result.is_ok());
1209    /// assert_eq!(result.unwrap().position().pos(), 1);
1210    ///
1211    /// state = pest::ParserState::new(input);
1212    /// result = state.match_range('A'..'Z');
1213    /// assert!(result.is_err());
1214    /// assert_eq!(result.unwrap_err().position().pos(), 0);
1215    /// ```
1216    #[inline]
1217    pub fn match_range(mut self: Box<Self>, range: Range<char>) -> ParseResult<Box<Self>> {
1218        let start_position = self.position().pos();
1219        let token = ParsingToken::Range {
1220            start: range.start,
1221            end: range.end,
1222        };
1223        let succeeded = self.position.match_range(range);
1224        if self.parse_attempts.enabled {
1225            self.handle_token_parse_result(start_position, token, succeeded);
1226        }
1227        if succeeded {
1228            Ok(self)
1229        } else {
1230            Err(self)
1231        }
1232    }
1233
1234    /// Attempts to skip `n` characters forward. Returns `Ok` with the updated `Box<ParserState>`
1235    /// if successful, or `Err` with the updated `Box<ParserState>` otherwise.
1236    ///
1237    /// # Examples
1238    ///
1239    /// ```
1240    /// # use pest;
1241    /// # #[allow(non_camel_case_types)]
1242    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1243    /// enum Rule {}
1244    ///
1245    /// let input = "ab";
1246    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1247    /// let mut result = state.skip(1);
1248    /// assert!(result.is_ok());
1249    /// assert_eq!(result.unwrap().position().pos(), 1);
1250    ///
1251    /// state = pest::ParserState::new(input);
1252    /// result = state.skip(3);
1253    /// assert!(result.is_err());
1254    /// assert_eq!(result.unwrap_err().position().pos(), 0);
1255    /// ```
1256    #[inline]
1257    pub fn skip(mut self: Box<Self>, n: usize) -> ParseResult<Box<Self>> {
1258        if self.position.skip(n) {
1259            Ok(self)
1260        } else {
1261            Err(self)
1262        }
1263    }
1264
1265    /// Attempts to skip forward until one of the given strings is found. Returns `Ok` with the
1266    /// updated `Box<ParserState>` whether or not one of the strings is found.
1267    ///
1268    /// # Examples
1269    ///
1270    /// ```
1271    /// # use pest;
1272    /// # #[allow(non_camel_case_types)]
1273    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1274    /// enum Rule {}
1275    ///
1276    /// let input = "abcd";
1277    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1278    /// let mut result = state.skip_until(&["c", "d"]);
1279    /// assert!(result.is_ok());
1280    /// assert_eq!(result.unwrap().position().pos(), 2);
1281    /// ```
1282    #[inline]
1283    pub fn skip_until(mut self: Box<Self>, strings: &[&str]) -> ParseResult<Box<Self>> {
1284        self.position.skip_until(strings);
1285        Ok(self)
1286    }
1287
1288    /// Attempts to match the start of the input. Returns `Ok` with the current `Box<ParserState>`
1289    /// if the parser has not yet advanced, or `Err` with the current `Box<ParserState>` otherwise.
1290    ///
1291    /// # Examples
1292    ///
1293    /// ```
1294    /// # use pest;
1295    /// # #[allow(non_camel_case_types)]
1296    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1297    /// enum Rule {}
1298    ///
1299    /// let input = "ab";
1300    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1301    /// let mut result = state.start_of_input();
1302    /// assert!(result.is_ok());
1303    ///
1304    /// state = pest::ParserState::new(input);
1305    /// state = state.match_string("ab").unwrap();
1306    /// result = state.start_of_input();
1307    /// assert!(result.is_err());
1308    /// ```
1309    #[inline]
1310    pub fn start_of_input(self: Box<Self>) -> ParseResult<Box<Self>> {
1311        if self.position.at_start() {
1312            Ok(self)
1313        } else {
1314            Err(self)
1315        }
1316    }
1317
1318    /// Attempts to match the end of the input. Returns `Ok` with the current `Box<ParserState>` if
1319    /// there is no input remaining, or `Err` with the current `Box<ParserState>` otherwise.
1320    ///
1321    /// # Examples
1322    ///
1323    /// ```
1324    /// # use pest;
1325    /// # #[allow(non_camel_case_types)]
1326    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1327    /// enum Rule {}
1328    ///
1329    /// let input = "ab";
1330    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1331    /// let mut result = state.end_of_input();
1332    /// assert!(result.is_err());
1333    ///
1334    /// state = pest::ParserState::new(input);
1335    /// state = state.match_string("ab").unwrap();
1336    /// result = state.end_of_input();
1337    /// assert!(result.is_ok());
1338    /// ```
1339    #[inline]
1340    pub fn end_of_input(self: Box<Self>) -> ParseResult<Box<Self>> {
1341        if self.position.at_end() {
1342            Ok(self)
1343        } else {
1344            Err(self)
1345        }
1346    }
1347
1348    /// Starts a lookahead transformation provided by `f` from the `Box<ParserState>`. It returns
1349    /// `Ok` with the current `Box<ParserState>` if `f` also returns an `Ok`, or `Err` with the current
1350    /// `Box<ParserState>` otherwise. If `is_positive` is `false`, it swaps the `Ok` and `Err`
1351    /// together, negating the `Result`.
1352    ///
1353    /// # Examples
1354    ///
1355    /// ```
1356    /// # use pest;
1357    /// # #[allow(non_camel_case_types)]
1358    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1359    /// enum Rule {
1360    ///     a
1361    /// }
1362    ///
1363    /// let input = "a";
1364    /// let pairs: Vec<_> = pest::state(input, |state| {
1365    ///     state.lookahead(true, |state| {
1366    ///         state.rule(Rule::a, |s| Ok(s))
1367    ///     })
1368    /// }).unwrap().collect();
1369    ///
1370    /// assert_eq!(pairs.len(), 0);
1371    /// ```
1372    #[inline]
1373    pub fn lookahead<F>(mut self: Box<Self>, is_positive: bool, f: F) -> ParseResult<Box<Self>>
1374    where
1375        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1376    {
1377        self = self.inc_call_check_limit()?;
1378        let initial_lookahead = self.lookahead;
1379
1380        self.lookahead = if is_positive {
1381            match initial_lookahead {
1382                Lookahead::None | Lookahead::Positive => Lookahead::Positive,
1383                Lookahead::Negative => Lookahead::Negative,
1384            }
1385        } else {
1386            match initial_lookahead {
1387                Lookahead::None | Lookahead::Positive => Lookahead::Negative,
1388                Lookahead::Negative => Lookahead::Positive,
1389            }
1390        };
1391
1392        let initial_pos = self.position;
1393
1394        let result = f(self.checkpoint());
1395
1396        let result_state = match result {
1397            Ok(mut new_state) => {
1398                new_state.position = initial_pos;
1399                new_state.lookahead = initial_lookahead;
1400                Ok(new_state.restore())
1401            }
1402            Err(mut new_state) => {
1403                new_state.position = initial_pos;
1404                new_state.lookahead = initial_lookahead;
1405                Err(new_state.restore())
1406            }
1407        };
1408
1409        if is_positive {
1410            result_state
1411        } else {
1412            match result_state {
1413                Ok(state) => Err(state),
1414                Err(state) => Ok(state),
1415            }
1416        }
1417    }
1418
1419    /// Transformation which stops `Token`s from being generated according to `is_atomic`.
1420    /// Used as wrapper over `rule` (or even another `atomic`) call.
1421    ///
1422    /// # Examples
1423    ///
1424    /// ```
1425    /// # use pest::{self, Atomicity};
1426    /// # #[allow(non_camel_case_types)]
1427    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1428    /// enum Rule {
1429    ///     a
1430    /// }
1431    ///
1432    /// let input = "a";
1433    /// let pairs: Vec<_> = pest::state(input, |state| {
1434    ///     state.atomic(Atomicity::Atomic, |s| {
1435    ///         s.rule(Rule::a, |s| Ok(s))
1436    ///     })
1437    /// }).unwrap().collect();
1438    ///
1439    /// assert_eq!(pairs.len(), 0);
1440    /// ```
1441    #[inline]
1442    pub fn atomic<F>(mut self: Box<Self>, atomicity: Atomicity, f: F) -> ParseResult<Box<Self>>
1443    where
1444        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1445    {
1446        self = self.inc_call_check_limit()?;
1447        // In case child parsing call is another `atomic` it will have its own atomicity status.
1448        let initial_atomicity = self.atomicity;
1449        // In case child atomicity is the same as we've demanded, we shouldn't do nothing.
1450        // E.g. we have the following rules:
1451        // * RootRule = @{ InnerRule }
1452        // * InnerRule = @{ ... }
1453        let should_toggle = self.atomicity != atomicity;
1454
1455        // Note that we take atomicity of the top rule and not of the leaf (inner).
1456        if should_toggle {
1457            self.atomicity = atomicity;
1458        }
1459
1460        let result = f(self);
1461
1462        match result {
1463            Ok(mut new_state) => {
1464                if should_toggle {
1465                    new_state.atomicity = initial_atomicity;
1466                }
1467                Ok(new_state)
1468            }
1469            Err(mut new_state) => {
1470                if should_toggle {
1471                    new_state.atomicity = initial_atomicity;
1472                }
1473                Err(new_state)
1474            }
1475        }
1476    }
1477
1478    /// Evaluates the result of closure `f` and pushes the span of the input consumed from before
1479    /// `f` is called to after `f` is called to the stack. Returns `Ok(Box<ParserState>)` if `f` is
1480    /// called successfully, or `Err(Box<ParserState>)` otherwise.
1481    ///
1482    /// # Examples
1483    ///
1484    /// ```
1485    /// # use pest;
1486    /// # #[allow(non_camel_case_types)]
1487    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1488    /// enum Rule {}
1489    ///
1490    /// let input = "ab";
1491    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1492    /// let mut result = state.stack_push(|state| state.match_string("a"));
1493    /// assert!(result.is_ok());
1494    /// assert_eq!(result.unwrap().position().pos(), 1);
1495    /// ```
1496    #[inline]
1497    pub fn stack_push<F>(mut self: Box<Self>, f: F) -> ParseResult<Box<Self>>
1498    where
1499        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1500    {
1501        self = self.inc_call_check_limit()?;
1502        let start = self.position;
1503
1504        let result = f(self);
1505
1506        match result {
1507            Ok(mut state) => {
1508                let end = state.position;
1509                state.stack.push(SpanOrLiteral::Span(start.span(&end)));
1510                Ok(state)
1511            }
1512            Err(state) => Err(state),
1513        }
1514    }
1515
1516    /// Peeks the top of the stack and attempts to match the string. Returns `Ok(Box<ParserState>)`
1517    /// if the string is matched successfully, or `Err(Box<ParserState>)` otherwise.
1518    ///
1519    /// # Panics
1520    ///
1521    /// Panics if the stack is empty.
1522    ///
1523    /// # Examples
1524    ///
1525    /// ```
1526    /// # use pest;
1527    /// # #[allow(non_camel_case_types)]
1528    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1529    /// enum Rule {}
1530    ///
1531    /// let input = "aa";
1532    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1533    /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
1534    ///     |state| state.stack_peek()
1535    /// );
1536    /// assert!(result.is_ok());
1537    /// assert_eq!(result.unwrap().position().pos(), 2);
1538    /// ```
1539    #[inline]
1540    pub fn stack_peek(self: Box<Self>) -> ParseResult<Box<Self>> {
1541        let string = self
1542            .stack
1543            .peek()
1544            .expect("peek was called on empty stack")
1545            .as_borrowed_or_rc();
1546        self.match_string(string.as_str())
1547    }
1548
1549    /// Pops the top of the stack and attempts to match the string. Returns `Ok(Box<ParserState>)`
1550    /// if the string is matched successfully, or `Err(Box<ParserState>)` otherwise.
1551    ///
1552    /// # Panics
1553    ///
1554    /// Panics if the stack is empty.
1555    ///
1556    /// # Examples
1557    ///
1558    /// ```
1559    /// # use pest;
1560    /// # #[allow(non_camel_case_types)]
1561    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1562    /// enum Rule {}
1563    ///
1564    /// let input = "aa";
1565    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1566    /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
1567    ///     |state| state.stack_pop()
1568    /// );
1569    /// assert!(result.is_ok());
1570    /// assert_eq!(result.unwrap().position().pos(), 2);
1571    /// ```
1572    #[inline]
1573    pub fn stack_pop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1574        let string = self
1575            .stack
1576            .pop()
1577            .expect("pop was called on empty stack")
1578            .as_borrowed_or_rc();
1579        self.match_string(string.as_str())
1580    }
1581
1582    /// Matches part of the state of the stack.
1583    ///
1584    /// # Examples
1585    ///
1586    /// ```
1587    /// # use pest::{self, MatchDir};
1588    /// # #[allow(non_camel_case_types)]
1589    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1590    /// enum Rule {}
1591    ///
1592    /// let input = "abcd cd cb";
1593    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1594    /// let mut result = state
1595    ///     .stack_push(|state| state.match_string("a"))
1596    ///     .and_then(|state| state.stack_push(|state| state.match_string("b")))
1597    ///     .and_then(|state| state.stack_push(|state| state.match_string("c")))
1598    ///     .and_then(|state| state.stack_push(|state| state.match_string("d")))
1599    ///     .and_then(|state| state.match_string(" "))
1600    ///     .and_then(|state| state.stack_match_peek_slice(2, None, MatchDir::BottomToTop))
1601    ///     .and_then(|state| state.match_string(" "))
1602    ///     .and_then(|state| state.stack_match_peek_slice(1, Some(-1), MatchDir::TopToBottom));
1603    /// assert!(result.is_ok());
1604    /// assert_eq!(result.unwrap().position().pos(), 10);
1605    /// ```
1606    #[inline]
1607    pub fn stack_match_peek_slice(
1608        mut self: Box<Self>,
1609        start: i32,
1610        end: Option<i32>,
1611        match_dir: MatchDir,
1612    ) -> ParseResult<Box<Self>> {
1613        let range = match constrain_idxs(start, end, self.stack.len()) {
1614            Some(r) => r,
1615            None => return Err(self),
1616        };
1617        // return true if an empty sequence is requested
1618        if range.end <= range.start {
1619            return Ok(self);
1620        }
1621
1622        let mut position = self.position;
1623        let result = {
1624            let mut iter_b2t = self.stack[range].iter();
1625            let matcher =
1626                |span: &SpanOrLiteral<'_>| position.match_string(span.as_borrowed_or_rc().as_str());
1627            match match_dir {
1628                MatchDir::BottomToTop => iter_b2t.all(matcher),
1629                MatchDir::TopToBottom => iter_b2t.rev().all(matcher),
1630            }
1631        };
1632        if result {
1633            self.position = position;
1634            Ok(self)
1635        } else {
1636            Err(self)
1637        }
1638    }
1639
1640    /// Matches the full state of the stack.
1641    ///
1642    /// # Examples
1643    ///
1644    /// ```
1645    /// # use pest;
1646    /// # #[allow(non_camel_case_types)]
1647    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1648    /// enum Rule {}
1649    ///
1650    /// let input = "abba";
1651    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1652    /// let mut result = state
1653    ///     .stack_push(|state| state.match_string("a"))
1654    ///     .and_then(|state| { state.stack_push(|state| state.match_string("b")) })
1655    ///     .and_then(|state| state.stack_match_peek());
1656    /// assert!(result.is_ok());
1657    /// assert_eq!(result.unwrap().position().pos(), 4);
1658    /// ```
1659    #[inline]
1660    pub fn stack_match_peek(self: Box<Self>) -> ParseResult<Box<Self>> {
1661        self.stack_match_peek_slice(0, None, MatchDir::TopToBottom)
1662    }
1663
1664    /// Matches the full state of the stack. This method will clear the stack as it evaluates.
1665    ///
1666    /// # Examples
1667    ///
1668    /// ```
1669    /// /// # use pest;
1670    /// # #[allow(non_camel_case_types)]
1671    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1672    /// enum Rule {}
1673    ///
1674    /// let input = "aaaa";
1675    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1676    /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(|state| {
1677    ///     state.stack_push(|state| state.match_string("a"))
1678    /// }).and_then(|state| state.stack_match_peek());
1679    /// assert!(result.is_ok());
1680    /// assert_eq!(result.unwrap().position().pos(), 4);
1681    /// ```
1682    #[inline]
1683    pub fn stack_match_pop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1684        let mut position = self.position;
1685        let mut result = true;
1686        while let Some(span) = self.stack.pop() {
1687            result = position.match_string(span.as_borrowed_or_rc().as_str());
1688            if !result {
1689                break;
1690            }
1691        }
1692
1693        if result {
1694            self.position = position;
1695            Ok(self)
1696        } else {
1697            Err(self)
1698        }
1699    }
1700
1701    /// Drops the top of the stack. Returns `Ok(Box<ParserState>)` if there was a value to drop, or
1702    /// `Err(Box<ParserState>)` otherwise.
1703    ///
1704    /// # Examples
1705    ///
1706    /// ```
1707    /// # use pest;
1708    /// # #[allow(non_camel_case_types)]
1709    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1710    /// enum Rule {}
1711    ///
1712    /// let input = "aa";
1713    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1714    /// let mut result = state.stack_push(|state| state.match_string("a")).and_then(
1715    ///     |state| state.stack_drop()
1716    /// );
1717    /// assert!(result.is_ok());
1718    /// assert_eq!(result.unwrap().position().pos(), 1);
1719    /// ```
1720    #[inline]
1721    pub fn stack_drop(mut self: Box<Self>) -> ParseResult<Box<Self>> {
1722        match self.stack.pop() {
1723            Some(_) => Ok(self),
1724            None => Err(self),
1725        }
1726    }
1727
1728    /// Restores the original state of the `ParserState` when `f` returns an `Err`. Currently,
1729    /// this method only restores the stack.
1730    ///
1731    /// # Examples
1732    ///
1733    /// ```
1734    /// # use pest;
1735    /// # #[allow(non_camel_case_types)]
1736    /// # #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1737    /// enum Rule {}
1738    ///
1739    /// let input = "ab";
1740    /// let mut state: Box<pest::ParserState<'_, Rule>> = pest::ParserState::new(input);
1741    /// let mut result = state.restore_on_err(|state| state.stack_push(|state|
1742    ///     state.match_string("a")).and_then(|state| state.match_string("a"))
1743    /// );
1744    ///
1745    /// assert!(result.is_err());
1746    ///
1747    /// // Since the the rule doesn't match, the "a" pushed to the stack will be removed.
1748    /// let catch_panic = std::panic::catch_unwind(|| result.unwrap_err().stack_pop());
1749    /// assert!(catch_panic.is_err());
1750    /// ```
1751    #[inline]
1752    pub fn restore_on_err<F>(self: Box<Self>, f: F) -> ParseResult<Box<Self>>
1753    where
1754        F: FnOnce(Box<Self>) -> ParseResult<Box<Self>>,
1755    {
1756        match f(self.checkpoint()) {
1757            Ok(state) => Ok(state.checkpoint_ok()),
1758            Err(state) => Err(state.restore()),
1759        }
1760    }
1761
1762    // Mark the current state as a checkpoint and return the `Box`.
1763    #[inline]
1764    pub(crate) fn checkpoint(mut self: Box<Self>) -> Box<Self> {
1765        self.stack.snapshot();
1766        self
1767    }
1768
1769    // The checkpoint was cleared successfully
1770    // so remove it without touching other stack state.
1771    #[inline]
1772    pub(crate) fn checkpoint_ok(mut self: Box<Self>) -> Box<Self> {
1773        self.stack.clear_snapshot();
1774        self
1775    }
1776
1777    // Restore the current state to the most recent checkpoint.
1778    #[inline]
1779    pub(crate) fn restore(mut self: Box<Self>) -> Box<Self> {
1780        self.stack.restore();
1781        self
1782    }
1783}
1784
1785/// Helper function used only in case stack operations (PUSH/POP) are used in grammar.
1786fn constrain_idxs(start: i32, end: Option<i32>, len: usize) -> Option<Range<usize>> {
1787    let start_norm = normalize_index(start, len)?;
1788    let end_norm = end.map_or(Some(len), |e| normalize_index(e, len))?;
1789    Some(start_norm..end_norm)
1790}
1791
1792/// `constrain_idxs` helper function.
1793/// Normalizes the index using its sequence’s length.
1794/// Returns `None` if the normalized index is OOB.
1795fn normalize_index(i: i32, len: usize) -> Option<usize> {
1796    if i > len as i32 {
1797        None
1798    } else if i >= 0 {
1799        Some(i as usize)
1800    } else {
1801        let real_i = len as i32 + i;
1802        if real_i >= 0 {
1803            Some(real_i as usize)
1804        } else {
1805            None
1806        }
1807    }
1808}
1809
1810#[cfg(test)]
1811mod test {
1812    use super::*;
1813
1814    #[test]
1815    fn normalize_index_pos() {
1816        assert_eq!(normalize_index(4, 6), Some(4));
1817        assert_eq!(normalize_index(5, 5), Some(5));
1818        assert_eq!(normalize_index(6, 3), None);
1819    }
1820
1821    #[test]
1822    fn normalize_index_neg() {
1823        assert_eq!(normalize_index(-4, 6), Some(2));
1824        assert_eq!(normalize_index(-5, 5), Some(0));
1825        assert_eq!(normalize_index(-6, 3), None);
1826    }
1827}