welly_parser/
bracket.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! Welly's bracket matcher.

use super::{Tree, EndOfFile, Location, Token, Stream};

pub const MISSING_OPEN: &'static str = "Unmatched close bracket";
pub const MISSING_CLOSE: &'static str = "Unmatched open bracket";

// ----------------------------------------------------------------------------

/// A sequence of [`Token`]s enclosed in round brackets.
///
/// The contents should be comma-separated [`Expr`]s, but we allow anything,
/// including errors.
///
/// [`Expr`]: super::welly::Expr
#[derive(Debug)]
pub struct Round(pub Vec<Token>);

impl Round {
    pub fn new(contents: Vec<Token>) -> Box<Self> { Box::new(Self(contents)) }
}

impl Tree for Round {}

/// A sequence of [`Token`]s enclosed in square brackets.
///
/// The contents should be comma-separated [`Expr`]s, but we allow anything,
/// including errors.
///
/// [`Expr`]: super::welly::Expr
#[derive(Debug)]
pub struct Square(pub Vec<Token>);

impl Square {
    pub fn new(contents: Vec<Token>) -> Box<Self> { Box::new(Self(contents)) }
}

impl Tree for Square {}

/// A sequence of [`Token`]s enclosed in curly brackets.
///
/// The contents should be [`Stmt`]s, but we allow anything, including errors.
///
/// [`Stmt`]: super::welly::Stmt
#[derive(Debug)]
pub struct Brace(pub Vec<Token>);

impl Brace {
    pub fn new(contents: Vec<Token>) -> Box<Self> { Box::new(Self(contents)) }
}

impl Tree for Brace {}

// ----------------------------------------------------------------------------

/// A [`Stream`] that matches nested brackets.
///
/// Note that this is not a [`Parse`] implementation, because it is recursive.
///
/// [`Parse`]: super::Parse
pub struct Brackets<F, I> {
    open: char,
    close: char,
    new_bracket: F,
    input: I,
    depth: usize
}

impl<
    F: Fn(Vec<Token>) -> Box<dyn Tree>,
    I: Stream,
> Brackets<F, I> {
    /// Construct a [`Brackets`].
    /// - open - the [`char`] used to open a bracket.
    /// - close - the [`char`] used to close a bracket.
    /// - new_bracket - turns bracket contents into a bracket value.
    ///   The bracket contents are read from `Self`.
    /// - input - a [`Stream`] that contains [`char`]s.
    pub fn new(open: char, close: char, new_bracket: F, input: I) -> Self {
        Self {open, close, new_bracket, input, depth: 0}
    }

    /// Returns the bracket starting at `open`.
    fn parse_bracket(&mut self, open_loc: Location) -> Token {
        let mut contents: Vec<Token> = Vec::new();
        loop {
            let token = self.read();
            if token.is_incomplete() { return token; }
            if token == EndOfFile { return Token::new_err(MISSING_CLOSE, open_loc); }
            if token == self.close {
                let close_loc = token.location();
                let bracket = (&self.new_bracket)(contents);
                return Token::new(bracket, Location {start: open_loc.start, end: close_loc.end});
            }
            contents.push(token);
        }
    }
}

impl<
    F: Fn(Vec<Token>) -> Box<dyn Tree>,
    I: Stream,
> Stream for Brackets<F, I> {
    fn read(&mut self) -> Token {
        let token = self.input.read();
        if token == self.open {
            self.depth += 1;
            return self.parse_bracket(token.location());
        }
        if token == self.close {
            if self.depth == 0 {
                return Token::new_err(MISSING_OPEN, token.location());
            }
            self.depth -= 1;
        }
        token
    }
}

// ----------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use crate::{Characters};
    use super::*;

    #[test]
    fn some_brackets() {
        let mut parser = Brackets::new(
            '(',
            ')',
            |contents| Box::new(Round(contents)),
            Brackets::new(
                '{',
                '}',
                |contents| Box::new(Brace(contents)),
                Characters::new("(a{b}(cd)){}", true)
            )
        );
        let mut contents1 = parser.read().unwrap::<Round>().0.into_iter();
        assert_eq!(contents1.read(), 'a');
        let mut contents2 = contents1.read().unwrap::<Brace>().0.into_iter();
        assert_eq!(contents2.read(), 'b');
        assert_eq!(contents2.read(), EndOfFile);
        let mut contents2 = contents1.read().unwrap::<Round>().0.into_iter();
        assert_eq!(contents2.read(), 'c');
        assert_eq!(contents2.read(), 'd');
        assert_eq!(contents2.read(), EndOfFile);
        assert_eq!(contents1.read(), EndOfFile);
        let mut contents1 = parser.read().unwrap::<Brace>().0.into_iter();
        assert_eq!(contents1.read(), EndOfFile);
        assert_eq!(parser.read(), EndOfFile);
    }

    #[test]
    fn inside_out() {
        /// Pretend this is a parser for a complicated grammar.
        fn noop(parser: impl Stream) -> impl Stream { parser }

        /// Wrap 'parser' in a [`Round`] parser.
        fn round(parser: impl Stream) -> impl Stream {
            noop(Brackets::new('(', ')', |contents| {
                let contents = noop(contents.into_iter()).read_all();
                Box::new(Round(contents))
            }, parser))
        }

        /// Wrap 'parser' in a [`Square`] parser.
        fn square(parser: impl Stream) -> impl Stream {
            round(Brackets::new('[', ']', |contents| {
                let contents = round(contents.into_iter()).read_all();
                Box::new(Square(contents))
            }, parser))
        }

        /// Wrap 'parser' in a [`Brace`] parser.
        fn brace(parser: impl Stream) -> impl Stream {
            square(Brackets::new('{', '}', |contents| {
                let contents = square(contents.into_iter()).read_all();
                Box::new(Brace(contents))
            }, parser))
        }

        let mut parser = brace(Characters::new("a{b[c(d(e[f{g}]))]}", true));
        assert_eq!(parser.read(), 'a');
        let mut contents1 = parser.read().unwrap::<Brace>().0.into_iter();
        assert_eq!(contents1.read(), 'b');
        let mut contents2 = contents1.read().unwrap::<Square>().0.into_iter();
        assert_eq!(contents2.read(), 'c');
        let mut contents3 = contents2.read().unwrap::<Round>().0.into_iter();
        assert_eq!(contents3.read(), 'd');
        let mut contents4 = contents3.read().unwrap::<Round>().0.into_iter();
        assert_eq!(contents4.read(), 'e');
        let mut contents5 = contents4.read().unwrap::<Square>().0.into_iter();
        assert_eq!(contents5.read(), 'f');
        let mut contents6 = contents5.read().unwrap::<Brace>().0.into_iter();
        assert_eq!(contents6.read(), 'g');
        assert_eq!(contents6.read(), EndOfFile);
        assert_eq!(contents5.read(), EndOfFile);
        assert_eq!(contents4.read(), EndOfFile);
        assert_eq!(contents3.read(), EndOfFile);
        assert_eq!(contents2.read(), EndOfFile);
        assert_eq!(contents1.read(), EndOfFile);
        assert_eq!(parser.read(), EndOfFile);
    }
}