1 // this is only for parsing versions now
2 
3 use std::fmt;
4 use std::mem;
5 
6 use self::Error::*;
7 use crate::lexer::{self, Lexer, Token};
8 use crate::version::{Identifier, Version};
9 
10 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
11 pub enum Error<'input> {
12     /// Needed more tokens for parsing, but none are available.
13     UnexpectedEnd,
14     /// Unexpected token.
15     UnexpectedToken(Token<'input>),
16     /// An error occurred in the lexer.
17     Lexer(lexer::Error),
18     /// More input available.
19     MoreInput(Vec<Token<'input>>),
20     /// Encountered empty predicate in a set of predicates.
21     EmptyPredicate,
22     /// Encountered an empty range.
23     EmptyRange,
24 }
25 
26 impl<'input> From<lexer::Error> for Error<'input> {
from(value: lexer::Error) -> Self27     fn from(value: lexer::Error) -> Self {
28         Error::Lexer(value)
29     }
30 }
31 
32 impl<'input> fmt::Display for Error<'input> {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result33     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
34         use self::Error::*;
35 
36         match *self {
37             UnexpectedEnd => write!(fmt, "expected more input"),
38             UnexpectedToken(ref token) => write!(fmt, "encountered unexpected token: {:?}", token),
39             Lexer(ref error) => write!(fmt, "lexer error: {:?}", error),
40             MoreInput(ref tokens) => write!(fmt, "expected end of input, but got: {:?}", tokens),
41             EmptyPredicate => write!(fmt, "encountered empty predicate"),
42             EmptyRange => write!(fmt, "encountered empty range"),
43         }
44     }
45 }
46 
47 /// impl for backwards compatibility.
48 impl<'input> From<Error<'input>> for String {
from(value: Error<'input>) -> Self49     fn from(value: Error<'input>) -> Self {
50         value.to_string()
51     }
52 }
53 
54 /// A recursive-descent parser for parsing version requirements.
55 pub struct Parser<'input> {
56     /// Source of token.
57     lexer: Lexer<'input>,
58     /// Lookaehead.
59     c1: Option<Token<'input>>,
60 }
61 
62 impl<'input> Parser<'input> {
63     /// Construct a new parser for the given input.
new(input: &'input str) -> Result<Parser<'input>, Error<'input>>64     pub fn new(input: &'input str) -> Result<Parser<'input>, Error<'input>> {
65         let mut lexer = Lexer::new(input);
66 
67         let c1 = if let Some(c1) = lexer.next() {
68             Some(c1?)
69         } else {
70             None
71         };
72 
73         Ok(Parser { lexer, c1 })
74     }
75 
76     /// Pop one token.
77     #[inline(always)]
pop(&mut self) -> Result<Token<'input>, Error<'input>>78     fn pop(&mut self) -> Result<Token<'input>, Error<'input>> {
79         let c1 = if let Some(c1) = self.lexer.next() {
80             Some(c1?)
81         } else {
82             None
83         };
84 
85         mem::replace(&mut self.c1, c1).ok_or_else(|| UnexpectedEnd)
86     }
87 
88     /// Peek one token.
89     #[inline(always)]
peek(&mut self) -> Option<&Token<'input>>90     fn peek(&mut self) -> Option<&Token<'input>> {
91         self.c1.as_ref()
92     }
93 
94     /// Skip whitespace if present.
skip_whitespace(&mut self) -> Result<(), Error<'input>>95     fn skip_whitespace(&mut self) -> Result<(), Error<'input>> {
96         match self.peek() {
97             Some(&Token::Whitespace(_, _)) => self.pop().map(|_| ()),
98             _ => Ok(()),
99         }
100     }
101 
102     /// Parse a single component.
103     ///
104     /// Returns `None` if the component is a wildcard.
component(&mut self) -> Result<Option<u64>, Error<'input>>105     pub fn component(&mut self) -> Result<Option<u64>, Error<'input>> {
106         match self.pop()? {
107             Token::Numeric(number) => Ok(Some(number)),
108             ref t if t.is_wildcard() => Ok(None),
109             tok => Err(UnexpectedToken(tok)),
110         }
111     }
112 
113     /// Parse a single numeric.
numeric(&mut self) -> Result<u64, Error<'input>>114     pub fn numeric(&mut self) -> Result<u64, Error<'input>> {
115         match self.pop()? {
116             Token::Numeric(number) => Ok(number),
117             tok => Err(UnexpectedToken(tok)),
118         }
119     }
120 
121     /// Optionally parse a dot, then a component.
122     ///
123     /// The second component of the tuple indicates if a wildcard has been encountered, and is
124     /// always `false` if the first component is `Some`.
125     ///
126     /// If a dot is not encountered, `(None, false)` is returned.
127     ///
128     /// If a wildcard is encountered, `(None, true)` is returned.
dot_component(&mut self) -> Result<(Option<u64>, bool), Error<'input>>129     pub fn dot_component(&mut self) -> Result<(Option<u64>, bool), Error<'input>> {
130         match self.peek() {
131             Some(&Token::Dot) => {}
132             _ => return Ok((None, false)),
133         }
134 
135         // pop the peeked dot.
136         self.pop()?;
137         self.component().map(|n| (n, n.is_none()))
138     }
139 
140     /// Parse a dot, then a numeric.
dot_numeric(&mut self) -> Result<u64, Error<'input>>141     pub fn dot_numeric(&mut self) -> Result<u64, Error<'input>> {
142         match self.pop()? {
143             Token::Dot => {}
144             tok => return Err(UnexpectedToken(tok)),
145         }
146 
147         self.numeric()
148     }
149 
150     /// Parse an string identifier.
151     ///
152     /// Like, `foo`, or `bar`, or `beta-1`.
identifier(&mut self) -> Result<Identifier, Error<'input>>153     pub fn identifier(&mut self) -> Result<Identifier, Error<'input>> {
154         let identifier = match self.pop()? {
155             Token::AlphaNumeric(identifier) => {
156                 // TODO: Borrow?
157                 Identifier::AlphaNumeric(identifier.to_string())
158             }
159             Token::Numeric(n) => Identifier::Numeric(n),
160             tok => return Err(UnexpectedToken(tok)),
161         };
162 
163         if let Some(&Token::Hyphen) = self.peek() {
164             // pop the peeked hyphen
165             self.pop()?;
166             // concat with any following identifiers
167             Ok(identifier
168                 .concat("-")
169                 .concat(&self.identifier()?.to_string()))
170         } else {
171             Ok(identifier)
172         }
173     }
174 
175     /// Parse all pre-release identifiers, separated by dots.
176     ///
177     /// Like, `abcdef.1234`.
pre(&mut self) -> Result<Vec<Identifier>, Error<'input>>178     fn pre(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
179         match self.peek() {
180             Some(&Token::Hyphen) => {}
181             _ => return Ok(vec![]),
182         }
183 
184         // pop the peeked hyphen.
185         self.pop()?;
186         self.parts()
187     }
188 
189     /// Parse a dot-separated set of identifiers.
parts(&mut self) -> Result<Vec<Identifier>, Error<'input>>190     fn parts(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
191         let mut parts = Vec::new();
192 
193         parts.push(self.identifier()?);
194 
195         while let Some(&Token::Dot) = self.peek() {
196             self.pop()?;
197 
198             parts.push(self.identifier()?);
199         }
200 
201         Ok(parts)
202     }
203 
204     /// Parse optional build metadata.
205     ///
206     /// Like, `` (empty), or `+abcdef`.
plus_build_metadata(&mut self) -> Result<Vec<Identifier>, Error<'input>>207     fn plus_build_metadata(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
208         match self.peek() {
209             Some(&Token::Plus) => {}
210             _ => return Ok(vec![]),
211         }
212 
213         // pop the plus.
214         self.pop()?;
215         self.parts()
216     }
217 
218     /// Parse a version.
219     ///
220     /// Like, `1.0.0` or `3.0.0-beta.1`.
version(&mut self) -> Result<Version, Error<'input>>221     pub fn version(&mut self) -> Result<Version, Error<'input>> {
222         self.skip_whitespace()?;
223 
224         let major = self.numeric()?;
225         let minor = self.dot_numeric()?;
226         let patch = self.dot_numeric()?;
227         let pre = self.pre()?;
228         let build = self.plus_build_metadata()?;
229 
230         self.skip_whitespace()?;
231 
232         Ok(Version {
233             major,
234             minor,
235             patch,
236             pre,
237             build,
238         })
239     }
240 
241     /// Check if we have reached the end of input.
is_eof(&mut self) -> bool242     pub fn is_eof(&mut self) -> bool {
243         self.c1.is_none()
244     }
245 
246     /// Get the rest of the tokens in the parser.
247     ///
248     /// Useful for debugging.
tail(&mut self) -> Result<Vec<Token<'input>>, Error<'input>>249     pub fn tail(&mut self) -> Result<Vec<Token<'input>>, Error<'input>> {
250         let mut out = Vec::new();
251 
252         if let Some(t) = self.c1.take() {
253             out.push(t);
254         }
255 
256         while let Some(t) = self.lexer.next() {
257             out.push(t?);
258         }
259 
260         Ok(out)
261     }
262 }
263