reproto_semver/
parser.rs

1//! Recursive-descent parser for semver ranges.
2//!
3//! The parsers is divided into a set of functions, each responsible for parsing a subset of the
4//! grammar.
5//!
6//! # Examples
7//!
8//! ```rust
9//! use reproto_semver::parser::Parser;
10//! use reproto_semver::range::Op;
11//!
12//! let mut p = Parser::new("^1").expect("a broken parser");
13//!
14//! assert_eq!(Ok(Op::Compatible), p.op());
15//! assert_eq!(Ok(Some(1)), p.component());
16//! ```
17//!
18//! Example parsing a range:
19//!
20//! ```rust
21//! use reproto_semver::parser::Parser;
22//! use reproto_semver::range::{Op, Predicate};
23//!
24//! let mut p = Parser::new("^1.0").expect("a broken parser");
25//!
26//! assert_eq!(Ok(Some(Predicate {
27//!     op: Op::Compatible,
28//!     major: 1,
29//!     minor: Some(0),
30//!     patch: None,
31//!     pre: vec![],
32//! })), p.predicate());
33//!
34//! let mut p = Parser::new("^*").expect("a broken parser");
35//!
36//! assert_eq!(Ok(None), p.predicate());
37//! ```
38
39use self::Error::*;
40use lexer::{self, Lexer, Token};
41use range::{Op, Predicate, Range, WildcardVersion};
42use std::error;
43use std::fmt;
44use std::mem;
45use version::{Identifier, Version};
46
47/// Evaluate if parser contains the given pattern as a separator, surrounded by whitespace.
48macro_rules! has_ws_separator {
49    ($slf:expr, $pat:pat) => {{
50        $slf.skip_whitespace()?;
51
52        match $slf.peek() {
53            $pat => {
54                // pop the separator.
55                $slf.pop()?;
56                // strip suffixing whitespace.
57                $slf.skip_whitespace()?;
58                true
59            }
60            _ => false,
61        }
62    }};
63}
64
65#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
66pub enum Error<'input> {
67    /// Needed more tokens for parsing, but none are available.
68    UnexpectedEnd,
69    /// Unexpected token.
70    UnexpectedToken(Token<'input>),
71    /// An error occurred in the lexer.
72    Lexer(lexer::Error),
73    /// More input available.
74    MoreInput(Vec<Token<'input>>),
75    /// Encountered empty predicate in a set of predicates.
76    EmptyPredicate,
77    /// Encountered an empty range.
78    EmptyRange,
79}
80
81impl<'input> fmt::Display for Error<'input> {
82    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
83        match *self {
84            UnexpectedEnd => write!(fmt, "unexpected end"),
85            UnexpectedToken(ref t) => write!(fmt, "unexpected token: {:?}", t),
86            Lexer(ref l) => write!(fmt, "lexer error: {}", l),
87            MoreInput(..) => write!(fmt, "more input"),
88            EmptyPredicate => write!(fmt, "empty predicate"),
89            EmptyRange => write!(fmt, "empty range"),
90        }
91    }
92}
93
94impl<'input> error::Error for Error<'input> {
95    fn description(&self) -> &str {
96        match *self {
97            UnexpectedEnd => "unexpected end",
98            UnexpectedToken(..) => "unexpected token",
99            Lexer(ref l) => l.description(),
100            MoreInput(..) => "more input",
101            EmptyPredicate => "empty predicate",
102            EmptyRange => "empty range",
103        }
104    }
105}
106
107impl<'input> From<lexer::Error> for Error<'input> {
108    fn from(value: lexer::Error) -> Self {
109        Error::Lexer(value)
110    }
111}
112
113/// impl for backwards compatibility.
114impl<'input> From<Error<'input>> for String {
115    fn from(value: Error<'input>) -> Self {
116        value.to_string()
117    }
118}
119
120/// A recursive-descent parser for parsing version requirements.
121pub struct Parser<'input> {
122    /// Source of token.
123    lexer: Lexer<'input>,
124    /// Lookaehead.
125    c1: Option<Token<'input>>,
126}
127
128impl<'input> Parser<'input> {
129    /// Construct a new parser for the given input.
130    pub fn new(input: &'input str) -> Result<Parser<'input>, Error<'input>> {
131        let mut lexer = Lexer::new(input);
132
133        let c1 = if let Some(c1) = lexer.next() {
134            Some(c1?)
135        } else {
136            None
137        };
138
139        Ok(Parser {
140            lexer: lexer,
141            c1: c1,
142        })
143    }
144
145    /// Pop one token.
146    #[inline(always)]
147    fn pop(&mut self) -> Result<Token<'input>, Error<'input>> {
148        let c1 = if let Some(c1) = self.lexer.next() {
149            Some(c1?)
150        } else {
151            None
152        };
153
154        mem::replace(&mut self.c1, c1).ok_or_else(|| UnexpectedEnd)
155    }
156
157    /// Peek one token.
158    #[inline(always)]
159    fn peek(&mut self) -> Option<&Token<'input>> {
160        self.c1.as_ref()
161    }
162
163    /// Skip whitespace if present.
164    fn skip_whitespace(&mut self) -> Result<(), Error<'input>> {
165        match self.peek() {
166            Some(&Token::Whitespace(_, _)) => self.pop().map(|_| ()),
167            _ => Ok(()),
168        }
169    }
170
171    /// Parse an optional comma separator, then if that is present a predicate.
172    pub fn comma_predicate(&mut self) -> Result<Option<Predicate>, Error<'input>> {
173        if !has_ws_separator!(self, Some(&Token::Comma)) {
174            return Ok(None);
175        }
176
177        if let Some(predicate) = self.predicate()? {
178            Ok(Some(predicate))
179        } else {
180            Err(EmptyPredicate)
181        }
182    }
183
184    /// Parse a single component.
185    ///
186    /// Returns `None` if the component is a wildcard.
187    pub fn component(&mut self) -> Result<Option<u64>, Error<'input>> {
188        match self.pop()? {
189            Token::Numeric(number) => Ok(Some(number)),
190            ref t if t.is_wildcard() => Ok(None),
191            tok => Err(UnexpectedToken(tok)),
192        }
193    }
194
195    /// Parse a single numeric.
196    pub fn numeric(&mut self) -> Result<u64, Error<'input>> {
197        match self.pop()? {
198            Token::Numeric(number) => Ok(number),
199            tok => Err(UnexpectedToken(tok)),
200        }
201    }
202
203    /// Optionally parse a dot, then a component.
204    ///
205    /// The second component of the tuple indicates if a wildcard has been encountered, and is
206    /// always `false` if the first component is `Some`.
207    ///
208    /// If a dot is not encountered, `(None, false)` is returned.
209    ///
210    /// If a wildcard is encountered, `(None, true)` is returned.
211    pub fn dot_component(&mut self) -> Result<(Option<u64>, bool), Error<'input>> {
212        match self.peek() {
213            Some(&Token::Dot) => {}
214            _ => return Ok((None, false)),
215        }
216
217        // pop the peeked dot.
218        self.pop()?;
219        self.component().map(|n| (n, n.is_none()))
220    }
221
222    /// Parse a dot, then a numeric.
223    pub fn dot_numeric(&mut self) -> Result<u64, Error<'input>> {
224        match self.pop()? {
225            Token::Dot => {}
226            tok => return Err(UnexpectedToken(tok)),
227        }
228
229        self.numeric()
230    }
231
232    /// Parse an string identifier.
233    ///
234    /// Like, `foo`, or `bar`.
235    pub fn identifier(&mut self) -> Result<Identifier, Error<'input>> {
236        let identifier = match self.pop()? {
237            Token::AlphaNumeric(identifier) => {
238                // TODO: Borrow?
239                Identifier::AlphaNumeric(identifier.to_string())
240            }
241            Token::Numeric(n) => Identifier::Numeric(n),
242            tok => return Err(UnexpectedToken(tok)),
243        };
244
245        Ok(identifier)
246    }
247
248    /// Parse all pre-release identifiers, separated by dots.
249    ///
250    /// Like, `abcdef.1234`.
251    fn pre(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
252        match self.peek() {
253            Some(&Token::Hyphen) => {}
254            _ => return Ok(vec![]),
255        }
256
257        // pop the peeked hyphen.
258        self.pop()?;
259        self.parts()
260    }
261
262    /// Parse a dot-separated set of identifiers.
263    fn parts(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
264        let mut parts = Vec::new();
265
266        parts.push(self.identifier()?);
267
268        loop {
269            match self.peek() {
270                Some(&Token::Dot) | Some(&Token::Hyphen) => {}
271                _ => break,
272            }
273
274            // pop the peeked hyphen.
275            self.pop()?;
276
277            parts.push(self.identifier()?);
278        }
279
280        Ok(parts)
281    }
282
283    /// Parse optional build metadata.
284    ///
285    /// Like, `` (empty), or `+abcdef`.
286    fn plus_build_metadata(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
287        match self.peek() {
288            Some(&Token::Plus) => {}
289            _ => return Ok(vec![]),
290        }
291
292        // pop the plus.
293        self.pop()?;
294        self.parts()
295    }
296
297    /// Optionally parse a single operator.
298    ///
299    /// Like, `~`, or `^`.
300    pub fn op(&mut self) -> Result<Op, Error<'input>> {
301        use self::Token::*;
302
303        let op = match self.peek() {
304            Some(&Eq) => Op::Ex,
305            Some(&Gt) => Op::Gt,
306            Some(&GtEq) => Op::GtEq,
307            Some(&Lt) => Op::Lt,
308            Some(&LtEq) => Op::LtEq,
309            Some(&Tilde) => Op::Tilde,
310            Some(&Caret) => Op::Compatible,
311            // default op
312            _ => return Ok(Op::Compatible),
313        };
314
315        // remove the matched token.
316        self.pop()?;
317        self.skip_whitespace()?;
318        Ok(op)
319    }
320
321    /// Parse a single predicate.
322    ///
323    /// Like, `^1`, or `>=2.0.0`.
324    pub fn predicate(&mut self) -> Result<Option<Predicate>, Error<'input>> {
325        // empty predicate, treated the same as wildcard.
326        if self.peek().is_none() {
327            return Ok(None);
328        }
329
330        let mut op = self.op()?;
331
332        let major = match self.component()? {
333            Some(major) => major,
334            None => return Ok(None),
335        };
336
337        let (minor, minor_wildcard) = self.dot_component()?;
338        let (patch, patch_wildcard) = self.dot_component()?;
339        let pre = self.pre()?;
340
341        // TODO: avoid illegal combinations, like `1.*.0`.
342        if minor_wildcard {
343            op = Op::Wildcard(WildcardVersion::Minor);
344        }
345
346        if patch_wildcard {
347            op = Op::Wildcard(WildcardVersion::Patch);
348        }
349
350        // ignore build metadata
351        self.plus_build_metadata()?;
352
353        Ok(Some(Predicate {
354            op: op,
355            major: major,
356            minor: minor,
357            patch: patch,
358            pre: pre,
359        }))
360    }
361
362    /// Parse a single range.
363    ///
364    /// Like, `^1.0` or `>=3.0.0, <4.0.0`.
365    pub fn range(&mut self) -> Result<Range, Error<'input>> {
366        let mut predicates = Vec::new();
367
368        if let Some(predicate) = self.predicate()? {
369            predicates.push(predicate);
370
371            while let Some(next) = self.comma_predicate()? {
372                predicates.push(next);
373            }
374        }
375
376        Ok(Range {
377            predicates: predicates,
378        })
379    }
380
381    /// Parse a version.
382    ///
383    /// Like, `1.0.0` or `3.0.0-beta.1`.
384    pub fn version(&mut self) -> Result<Version, Error<'input>> {
385        self.skip_whitespace()?;
386
387        let major = self.numeric()?;
388        let minor = self.dot_numeric()?;
389        let patch = self.dot_numeric()?;
390        let pre = self.pre()?;
391        let build = self.plus_build_metadata()?;
392
393        self.skip_whitespace()?;
394
395        Ok(Version {
396            major: major,
397            minor: minor,
398            patch: patch,
399            pre: pre,
400            build: build,
401        })
402    }
403
404    /// Check if we have reached the end of input.
405    pub fn is_eof(&mut self) -> bool {
406        self.c1.is_none()
407    }
408
409    /// Get the rest of the tokens in the parser.
410    ///
411    /// Useful for debugging.
412    #[allow(unused)]
413    pub fn tail(&mut self) -> Result<Vec<Token<'input>>, Error<'input>> {
414        let mut out = Vec::new();
415
416        if let Some(t) = self.c1.take() {
417            out.push(t);
418        }
419
420        while let Some(t) = self.lexer.next() {
421            out.push(t?);
422        }
423
424        Ok(out)
425    }
426}