perplex_runtime/
lib.rs

1// Copyright (c) 2018 Fabian Schuiki
2
3//! A collection of facilities required by perplex-generated parsers.
4
5#![deny(missing_docs)]
6
7/// A parser that can be passed to generated states.
8///
9/// The code generator emits a list of state and goto functions which are
10/// generic over the parser passed to them. This trait describes the minimal set
11/// of functionality that such a parser must support.
12pub trait Parser {
13    /// The type of terminals the parser emits.
14    type Terminal;
15    /// The type of nonterminals the parser emits. This is likely an enum over
16    /// all nonterminals generated automatically.
17    type Nonterminal;
18
19    /// Peek at the next terminal in the sequence without shifting it.
20    #[inline(always)]
21    fn peek(&mut self) -> &Self::Terminal;
22
23    /// Push the next terminal onto the stack.
24    ///
25    /// This function is called by shift actions in the parser.
26    #[inline(always)]
27    fn shift(&mut self, state_fn: fn(&mut Self), goto_fn: fn(&mut Self, Self::Nonterminal));
28
29    /// Push a nonterminal onto the stack.
30    ///
31    /// This function is called after a reduce action in the parser.
32    #[inline(always)]
33    fn goto(
34        &mut self,
35        nonterminal: Self::Nonterminal,
36        state_fn: fn(&mut Self),
37        goto_fn: fn(&mut Self, Self::Nonterminal),
38    );
39
40    /// Reduce the tail of the stack to a nonterminal.
41    ///
42    /// The parser should split the last `length` symbols off the stack and call
43    /// the given function `f` with them as argument. This function is called by
44    /// the parser to initiate a reduction.
45    #[inline(always)]
46    fn reduce<F: Fn(Vec<Symbol<Self::Terminal, Self::Nonterminal>>) -> Self::Nonterminal>(
47        &mut self,
48        length: usize,
49        f: F,
50    );
51
52    /// Accept the last symbol on the stack as the parse result.
53    ///
54    /// Called by the parser when it has finished parsing the root rule.
55    fn accept(&mut self);
56}
57
58/// A symbol on the parse stack.
59///
60/// Generic over the type of terminal `T` and nonterminal `NT`.
61#[allow(missing_docs)]
62pub enum Symbol<T, NT> {
63    Terminal(T),
64    Nonterminal(NT),
65}
66
67impl<T, NT> Symbol<T, NT> {
68    /// Return the terminal wrapped in this symbol.
69    ///
70    /// Panics if the symbol is not a terminal.
71    #[inline(always)]
72    pub fn unwrap_terminal(self) -> T {
73        match self {
74            Symbol::Terminal(x) => x,
75            _ => panic!("symbol is not a terminal"),
76        }
77    }
78
79    /// Return the nonterminal wrapped in this symbol.
80    ///
81    /// Panics if the symbol is not a nonterminal.
82    #[inline(always)]
83    pub fn unwrap_nonterminal(self) -> NT {
84        match self {
85            Symbol::Nonterminal(x) => x,
86            _ => panic!("symbol is not a nonterminal"),
87        }
88    }
89}
90
91/// A description of a parser's state space.
92pub trait StateSpace {
93    /// The type of terminals the parser emits.
94    type Terminal;
95    /// The type of nonterminals the parser emits.
96    type Nonterminal;
97    /// The type of the reduction produce by the root rule.
98    type Root;
99
100    /// Return the root state function.
101    fn root_state_fn<P: Parser<Terminal = Self::Terminal, Nonterminal = Self::Nonterminal>>(
102) -> fn(&mut P);
103
104    /// Return the root goto function.
105    fn root_goto_fn<P: Parser<Terminal = Self::Terminal, Nonterminal = Self::Nonterminal>>(
106) -> fn(&mut P, Self::Nonterminal);
107}
108
109/// A parser state machine.
110///
111/// This struct implements the parse stack and driver for the parser. It is
112/// generic over the means by which terminals arrive at the input.
113pub struct ParserMachine<I: ParserInput, S: StateSpace> {
114    input: I,
115    result: Option<S::Nonterminal>,
116    stack: Vec<StackEntry<I, S>>,
117}
118
119/// An entry on the parser stack.
120///
121/// Associates a terminal or nonterminal with a state/goto function pair. These
122/// are used to drive the parser forward.
123struct StackEntry<I: ParserInput, S: StateSpace> {
124    symbol: Symbol<S::Terminal, S::Nonterminal>,
125    state_fn: fn(&mut ParserMachine<I, S>),
126    goto_fn: fn(&mut ParserMachine<I, S>, S::Nonterminal),
127}
128
129impl<I: ParserInput<Item = S::Terminal>, S: StateSpace> ParserMachine<I, S> {
130    /// Create a new parser state machine.
131    pub fn new(input: I) -> ParserMachine<I, S> {
132        ParserMachine {
133            input: input,
134            result: None,
135            stack: Vec::new(),
136        }
137    }
138
139    fn step(&mut self) {
140        if self.result.is_some() {
141            return;
142        }
143        let state_fn = self.stack
144            .last()
145            .map(|e| e.state_fn)
146            .unwrap_or(S::root_state_fn());
147        state_fn(self);
148    }
149
150    /// Run the parser to completion.
151    pub fn run(mut self) -> S::Nonterminal {
152        while self.result.is_none() {
153            self.step()
154        }
155        self.result.unwrap()
156    }
157}
158
159impl<I: Iterator, S: StateSpace<Terminal = Option<I::Item>>> ParserMachine<IterInput<I>, S> {
160    /// Create a new parser state machine from an iterator.
161    pub fn from_iter(input: I) -> ParserMachine<IterInput<I>, S> {
162        ParserMachine::new(IterInput::new(input))
163    }
164}
165
166impl<I, S> Parser for ParserMachine<I, S>
167where
168    I: ParserInput<Item = S::Terminal>,
169    S: StateSpace,
170{
171    type Terminal = S::Terminal;
172    type Nonterminal = S::Nonterminal;
173
174    fn peek(&mut self) -> &S::Terminal {
175        self.input.peek()
176    }
177
178    fn shift(&mut self, state_fn: fn(&mut Self), goto_fn: fn(&mut Self, S::Nonterminal)) {
179        let terminal = self.input.next();
180        self.stack.push(StackEntry {
181            symbol: Symbol::Terminal(terminal),
182            state_fn: state_fn,
183            goto_fn: goto_fn,
184        });
185    }
186
187    fn goto(
188        &mut self,
189        nonterminal: S::Nonterminal,
190        state_fn: fn(&mut Self),
191        goto_fn: fn(&mut Self, S::Nonterminal),
192    ) {
193        self.stack.push(StackEntry {
194            symbol: Symbol::Nonterminal(nonterminal),
195            state_fn: state_fn,
196            goto_fn: goto_fn,
197        });
198    }
199
200    fn reduce<F: Fn(Vec<Symbol<S::Terminal, S::Nonterminal>>) -> S::Nonterminal>(
201        &mut self,
202        length: usize,
203        f: F,
204    ) {
205        let at = self.stack.len() - length;
206        let args = self.stack.drain(at..).map(|e| e.symbol).collect();
207        let goto_fn = self.stack
208            .last()
209            .map(|e| e.goto_fn)
210            .unwrap_or(S::root_goto_fn());
211        let nonterminal = f(args);
212        goto_fn(self, nonterminal);
213    }
214
215    fn accept(&mut self) {
216        self.result = Some(self.stack.pop().unwrap().symbol.unwrap_nonterminal());
217    }
218}
219
220/// An stream of tokens that can be used as parser input.
221pub trait ParserInput {
222    /// The token type produced by the stream.
223    type Item;
224
225    /// Peek at the next item in the stream.
226    #[inline(always)]
227    fn peek(&mut self) -> &Self::Item;
228
229    /// Consume the next item in the stream.
230    #[inline(always)]
231    fn next(&mut self) -> Self::Item;
232
233    /// Returns the end-of-stream marker.
234    ///
235    /// The stream will continue to produce this marker once reaching the end.
236    /// Code calling peek() or next() must compare the result to this marker to
237    /// dedect the end of the input.
238    #[inline(always)]
239    fn marker() -> Self::Item;
240}
241
242/// A wrapper for using iterators as parser input.
243pub struct IterInput<I: Iterator> {
244    iter: I,
245    peek: Option<I::Item>,
246}
247
248impl<I: Iterator> IterInput<I> {
249    /// Create a new iterator input.
250    pub fn new(mut iter: I) -> IterInput<I> {
251        IterInput {
252            peek: iter.next(),
253            iter: iter,
254        }
255    }
256}
257
258impl<I: Iterator> ParserInput for IterInput<I> {
259    type Item = Option<I::Item>;
260
261    fn peek(&mut self) -> &Self::Item {
262        &self.peek
263    }
264
265    fn next(&mut self) -> Self::Item {
266        std::mem::replace(&mut self.peek, self.iter.next())
267    }
268
269    fn marker() -> Self::Item {
270        None
271    }
272}