cas_parser/parser/ast/helper/
surrounded.rs

1use cas_error::Error;
2use crate::parser::{
3    token::pair::Pair,
4    Parse,
5    Parser,
6};
7use std::marker::PhantomData;
8
9/// Represents a value that is surrounded by two tokens.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Surrounded<'source, P, T>
12where
13    P: Pair,
14{
15    /// The opening token that was parsed.
16    pub open: P::Open<'source>,
17
18    /// The value.
19    pub value: T,
20
21    /// The closing token that was parsed.
22    pub close: P::Close<'source>,
23
24    /// Marker type to allow using `P` as a type parameter.
25    pair: PhantomData<P>,
26}
27
28impl<'source, P, T> Parse<'source> for Surrounded<'source, P, T>
29where
30    P: Parse<'source> + Pair,
31    T: Parse<'source>,
32{
33    fn std_parse(
34        input: &mut Parser<'source>,
35        recoverable_errors: &mut Vec<Error>
36    ) -> Result<Self, Vec<Error>> {
37        let open = input.try_parse().forward_errors(recoverable_errors)?;
38
39        // clone the input so we can scan forward without affecting the original input
40        let mut input_ahead = input.clone();
41
42        // scan forward for the corresponding end token
43        // if we don't find it, do not attempt to parse the inner value
44        let mut depth = 1;
45        while depth > 0 {
46            let token = input_ahead.next_token()
47                .map_err(|eof| vec![eof])?;
48
49            if token.kind == P::OPEN {
50                depth += 1;
51            } else if token.kind == P::CLOSE {
52                depth -= 1;
53            }
54
55            if depth == 0 {
56                break;
57            }
58        }
59
60        // exiting the loop means that there is indeed a corresponding end token
61        let value = input.try_parse().forward_errors(recoverable_errors)?;
62
63        // if this fails, there's probably extraneous tokens between the value and the end token
64        let close = input.try_parse().forward_errors(recoverable_errors)?;
65
66        Ok(Self { open, value, close, pair: PhantomData })
67    }
68}