noa_parser/acceptor.rs
1use crate::errors::{ParseError, ParseResult};
2use crate::scanner::Scanner;
3use crate::visitor::Visitor;
4
5/// A type that wraps a `Scanner` and holds a successfully accepted value.
6///
7/// When a value is successfully accepted, the `Acceptor` stores the value in its
8/// `data` field and returns itself. If a value is not accepted, the `Acceptor`
9/// rewinds the scanner to the previous position and returns itself.
10///
11/// # Type Parameters
12///
13/// * `T` - The type of the data to scan.
14/// * `V` - The type of the value to accept.
15/// * `'a` - The lifetime of the data to scan.
16/// * `'b` - The lifetime of the acceptor.
17#[derive(Debug)]
18pub struct Acceptor<'a, 'b, T, V> {
19 /// The accepted value, if any.
20 data: Option<V>,
21 /// The scanner to use when consuming input.
22 scanner: &'b mut Scanner<'a, T>,
23}
24
25impl<'a, 'b, T, V> Acceptor<'a, 'b, T, V> {
26 /// Create a new acceptor.
27 ///
28 /// # Arguments
29 ///
30 /// * `scanner` - The scanner to use when consuming input.
31 ///
32 /// # Returns
33 ///
34 /// A new acceptor that uses the given scanner.
35 pub fn new(scanner: &'b mut Scanner<'a, T>) -> Acceptor<'a, 'b, T, V> {
36 Acceptor {
37 data: None,
38 scanner,
39 }
40 }
41}
42
43impl<'a, T, V> Acceptor<'a, '_, T, V> {
44 /// Attempt to accept a `U` using the given `transformer`, and rewind the scanner
45 /// and return the current acceptor if it fails.
46 ///
47 /// # Arguments
48 ///
49 /// * `transformer` - A function that takes a `U` and returns a `ParseResult<V>`.
50 ///
51 /// # Returns
52 ///
53 /// If the `U` is successfully accepted and the `transformer` returns `Ok`, returns
54 /// the current acceptor with the resulting value in `data`. If the `U` is not
55 /// successfully accepted, returns the current acceptor with the current position
56 /// of the scanner rewound to the position at which the `U` was attempted, and
57 /// `data` is left `None`.
58 pub fn try_or<U: Visitor<'a, T>, F>(mut self, transformer: F) -> ParseResult<Self>
59 where
60 F: Fn(U) -> V,
61 {
62 let cursor = self.scanner.current_position();
63 // Propagate the data
64 if self.data.is_some() {
65 return Ok(self);
66 }
67
68 match U::accept(self.scanner) {
69 Ok(found) => {
70 self.data = Some(transformer(found));
71 }
72 Err(ParseError::UnexpectedToken) => {
73 self.scanner.jump_to(cursor);
74 }
75 Err(err) => {
76 return Err(err);
77 }
78 }
79
80 Ok(self)
81 }
82
83 /// Consume the acceptor and return the `V` that was accepted if the acceptor was
84 /// successful.
85 ///
86 /// # Returns
87 ///
88 /// If the acceptor was successful (i.e., `data` is `Some`), returns the `V` that
89 /// was accepted. Otherwise, returns `None`.
90 pub fn finish(self) -> Option<V> {
91 self.data
92 }
93}