welly_parser/
parser.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
use super::{Tree, Location, Loc, Token, Stream};

/// A high-level wrapper around an input [`Stream`].
///
/// It handles errors, and tracks the [`Location`]s of the input `Token`s
/// that could form part of the next output `Token`. It also provides an
/// `unread()` method to pretend that you didn't read a `Token`.
pub struct Context<I: Stream> {
    /// The input [`Stream`].
    input: I,

    /// Non-error [`Token`]s to be returned before reading from [`input`],
    /// in reverse order.
    ///
    /// [`input`]: Self::input
    stack: Vec<Loc<Box<dyn Tree>>>,

    /// The [`Location`]s of [`Token`]s that have been read but not yet used to
    /// form an output.
    locs: Vec<Location>,
}

impl<I: Stream> Context<I> {
    pub fn new(input: I) -> Self {
        Self {input, stack: Vec::new(), locs: Vec::new()}
    }

    /// Returns the [`Location`] of the most recent [`Token`], and forgets it.
    pub fn pop(&mut self) -> Location {
        self.locs.pop().expect("No tokens have been read")
    }

    /// Returns the [`Location`] of the first [`Token`] returned by `read()`.
    pub fn first(&self) -> Location {
        *self.locs.first().expect("No tokens have been read")
    }

    /// Returns the [`Location`] of the last [`Token`] returned by `read()`.
    pub fn last(&self) -> Location {
        *self.locs.last().expect("No tokens have been read")
    }

    /// Annotate `t` with `last()`.
    pub fn locate<T>(&self, value: T) -> Loc<T> { Loc(value, self.last()) }

    /// Returns a [`Location`] containing all [`Token`]s `read()` so far, and
    /// forgets them.
    pub fn drain(&mut self) -> Location {
        let ret = Location {start: self.first().start, end: self.last().end};
        self.locs.clear();
        ret
    }

    /// Returns `self.stack.pop()` if possible, otherwise `self.input.read()`.
    fn read_inner(&mut self) -> Token {
        if let Some(Loc(t, loc)) = self.stack.pop() {
            Token::new(t, loc)
        } else {
            self.input.read()
        }
    }

    /// Read the next [`Token`] and internally record its [`Location`].
    ///
    /// - Ok(tree) - The parse [`Tree`] of the next `Token`.
    /// - Err(msg) - An error prevented parsing of the next `Token`.
    pub fn read_any(&mut self) -> Result<Box<dyn Tree>, String> {
        let token = self.read_inner();
        self.locs.push(token.location());
        token.result()
    }

    /// Read the next [`Token`] and internally record its [`Location`], but
    /// only if its parse [`Tree`] is of type `T`.
    ///
    /// - Ok(Some(tree)) - The next `Token`'s parse tree is of type `T`.
    /// - Ok(None) - The next `Token` is not a `T`. It has been `unread()`.
    /// - Err(message) - An error prevented parsing of the next `Token`.
    pub fn read<T: Tree>(&mut self) -> Result<Option<Box<T>>, String> {
        Ok(match self.read_any()?.downcast::<T>() {
            Ok(t) => Some(t),
            Err(t) => { self.unread(t); None },
        })
    }

    /// Read the next [`Token`] and internally record its [`Location`], but
    /// only if it `is_wanted`.
    /// - Ok(Some(tree)) - If `is_wanted(tree)`.
    /// - Ok(None) - The next `Token`'s parse tree is not a `T` or is unwanted.
    ///   It has been `unread()`.
    /// - Err(message) - An error prevented parsing of the next `Token`.
    pub fn read_if<T: Tree>(
        &mut self,
        is_wanted: impl FnOnce(&T) -> bool,
    ) -> Result<Option<Box<T>>, String> {
        Ok(self.read::<T>()?.and_then(
            |t| if is_wanted(&*t) { Some(t) } else { self.unread(t); None }
        ))
    }

    /// Pretend we haven't read the most recent [`Token`].
    ///
    /// `tree` must be the parse [`Tree`] of the most recent `Token`. It will
    /// be returned by the next call to `read()`.
    pub fn unread(&mut self, tree: Box<dyn Tree>) {
        let loc = self.pop();
        self.stack.push(Loc(tree, loc));
    }
}

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

/// Parse a [`Stream`].
pub trait Parse: Sized {
    /// Read input [`Tree`]s from `input` and try to make a single output tree.
    ///
    /// Special cases:
    /// - An unrecognised input tree should be passed on unchanged.
    ///   - In particular, [`EndOfFile`] should be passed on unchanged. It must
    ///     never be incorporated into a larger parse tree.
    /// - If this parser finds a parse error, abandon the current parse tree
    ///   and return `Err(message)`.
    /// - If `input` reports a parse error, abandon the current parse tree and
    ///   pass on the error unchanged.
    ///   - In particular, if `input` reports an incomplete file, pass it on.
    ///
    /// [`EndOfFile`]: super::EndOfFile
    fn parse(
        &self,
        input: &mut Context<impl Stream>,
    ) -> Result<Box<dyn Tree>, String>;

    /// Read [`Token`]s from `input` to make a [`Stream`] of output `Token`s.
    ///
    /// To make each output `Token`, the returned `Stream` calls
    /// [`parse()`] to make a [`Tree`], and annotates it with a [`Location`].
    ///
    /// [`parse()`]: Self::parse()
    fn parse_stream<I: Stream>(self, input: I) -> ParseStream<Self, I> {
        ParseStream {parse: self, input: Context::new(input)}
    }
}

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

/// The [`Stream`] returned by `Parse::parse_stream()`.
// TODO: Make private, using a newer version of Rust that supports RPIT.
pub struct ParseStream<P: Parse, I: Stream> {
    /// The parsing function.
    parse: P,

    /// The input stream.
    input: Context<I>,
}

impl<P: Parse, I: Stream> Stream for ParseStream<P, I> {
    fn read(&mut self) -> Token {
        let ret = self.parse.parse(&mut self.input);
        let last = self.input.last();
        let all = self.input.drain();
        let loc = if ret.is_ok() { all } else { last };
        Token(Loc(ret, loc))
    }
}