--- /dev/null
+// this is only for parsing versions now\r
+\r
+use std::fmt;\r
+use std::mem;\r
+\r
+use self::Error::*;\r
+use crate::lexer::{self, Lexer, Token};\r
+use crate::version::{Identifier, Version};\r
+\r
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]\r
+pub enum Error<'input> {\r
+ /// Needed more tokens for parsing, but none are available.\r
+ UnexpectedEnd,\r
+ /// Unexpected token.\r
+ UnexpectedToken(Token<'input>),\r
+ /// An error occurred in the lexer.\r
+ Lexer(lexer::Error),\r
+ /// More input available.\r
+ MoreInput(Vec<Token<'input>>),\r
+ /// Encountered empty predicate in a set of predicates.\r
+ EmptyPredicate,\r
+ /// Encountered an empty range.\r
+ EmptyRange,\r
+}\r
+\r
+impl<'input> From<lexer::Error> for Error<'input> {\r
+ fn from(value: lexer::Error) -> Self {\r
+ Error::Lexer(value)\r
+ }\r
+}\r
+\r
+impl<'input> fmt::Display for Error<'input> {\r
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {\r
+ use self::Error::*;\r
+\r
+ match *self {\r
+ UnexpectedEnd => write!(fmt, "expected more input"),\r
+ UnexpectedToken(ref token) => write!(fmt, "encountered unexpected token: {:?}", token),\r
+ Lexer(ref error) => write!(fmt, "lexer error: {:?}", error),\r
+ MoreInput(ref tokens) => write!(fmt, "expected end of input, but got: {:?}", tokens),\r
+ EmptyPredicate => write!(fmt, "encountered empty predicate"),\r
+ EmptyRange => write!(fmt, "encountered empty range"),\r
+ }\r
+ }\r
+}\r
+\r
+/// impl for backwards compatibility.\r
+impl<'input> From<Error<'input>> for String {\r
+ fn from(value: Error<'input>) -> Self {\r
+ value.to_string()\r
+ }\r
+}\r
+\r
+/// A recursive-descent parser for parsing version requirements.\r
+pub struct Parser<'input> {\r
+ /// Source of token.\r
+ lexer: Lexer<'input>,\r
+ /// Lookaehead.\r
+ c1: Option<Token<'input>>,\r
+}\r
+\r
+impl<'input> Parser<'input> {\r
+ /// Construct a new parser for the given input.\r
+ pub fn new(input: &'input str) -> Result<Parser<'input>, Error<'input>> {\r
+ let mut lexer = Lexer::new(input);\r
+\r
+ let c1 = if let Some(c1) = lexer.next() {\r
+ Some(c1?)\r
+ } else {\r
+ None\r
+ };\r
+\r
+ Ok(Parser { lexer, c1 })\r
+ }\r
+\r
+ /// Pop one token.\r
+ #[inline(always)]\r
+ fn pop(&mut self) -> Result<Token<'input>, Error<'input>> {\r
+ let c1 = if let Some(c1) = self.lexer.next() {\r
+ Some(c1?)\r
+ } else {\r
+ None\r
+ };\r
+\r
+ mem::replace(&mut self.c1, c1).ok_or_else(|| UnexpectedEnd)\r
+ }\r
+\r
+ /// Peek one token.\r
+ #[inline(always)]\r
+ fn peek(&mut self) -> Option<&Token<'input>> {\r
+ self.c1.as_ref()\r
+ }\r
+\r
+ /// Skip whitespace if present.\r
+ fn skip_whitespace(&mut self) -> Result<(), Error<'input>> {\r
+ match self.peek() {\r
+ Some(&Token::Whitespace(_, _)) => self.pop().map(|_| ()),\r
+ _ => Ok(()),\r
+ }\r
+ }\r
+\r
+ /// Parse a single component.\r
+ ///\r
+ /// Returns `None` if the component is a wildcard.\r
+ pub fn component(&mut self) -> Result<Option<u64>, Error<'input>> {\r
+ match self.pop()? {\r
+ Token::Numeric(number) => Ok(Some(number)),\r
+ ref t if t.is_wildcard() => Ok(None),\r
+ tok => Err(UnexpectedToken(tok)),\r
+ }\r
+ }\r
+\r
+ /// Parse a single numeric.\r
+ pub fn numeric(&mut self) -> Result<u64, Error<'input>> {\r
+ match self.pop()? {\r
+ Token::Numeric(number) => Ok(number),\r
+ tok => Err(UnexpectedToken(tok)),\r
+ }\r
+ }\r
+\r
+ /// Optionally parse a dot, then a component.\r
+ ///\r
+ /// The second component of the tuple indicates if a wildcard has been encountered, and is\r
+ /// always `false` if the first component is `Some`.\r
+ ///\r
+ /// If a dot is not encountered, `(None, false)` is returned.\r
+ ///\r
+ /// If a wildcard is encountered, `(None, true)` is returned.\r
+ pub fn dot_component(&mut self) -> Result<(Option<u64>, bool), Error<'input>> {\r
+ match self.peek() {\r
+ Some(&Token::Dot) => {}\r
+ _ => return Ok((None, false)),\r
+ }\r
+\r
+ // pop the peeked dot.\r
+ self.pop()?;\r
+ self.component().map(|n| (n, n.is_none()))\r
+ }\r
+\r
+ /// Parse a dot, then a numeric.\r
+ pub fn dot_numeric(&mut self) -> Result<u64, Error<'input>> {\r
+ match self.pop()? {\r
+ Token::Dot => {}\r
+ tok => return Err(UnexpectedToken(tok)),\r
+ }\r
+\r
+ self.numeric()\r
+ }\r
+\r
+ /// Parse an string identifier.\r
+ ///\r
+ /// Like, `foo`, or `bar`, or `beta-1`.\r
+ pub fn identifier(&mut self) -> Result<Identifier, Error<'input>> {\r
+ let identifier = match self.pop()? {\r
+ Token::AlphaNumeric(identifier) => {\r
+ // TODO: Borrow?\r
+ Identifier::AlphaNumeric(identifier.to_string())\r
+ }\r
+ Token::Numeric(n) => Identifier::Numeric(n),\r
+ tok => return Err(UnexpectedToken(tok)),\r
+ };\r
+\r
+ if let Some(&Token::Hyphen) = self.peek() {\r
+ // pop the peeked hyphen\r
+ self.pop()?;\r
+ // concat with any following identifiers\r
+ Ok(identifier\r
+ .concat("-")\r
+ .concat(&self.identifier()?.to_string()))\r
+ } else {\r
+ Ok(identifier)\r
+ }\r
+ }\r
+\r
+ /// Parse all pre-release identifiers, separated by dots.\r
+ ///\r
+ /// Like, `abcdef.1234`.\r
+ fn pre(&mut self) -> Result<Vec<Identifier>, Error<'input>> {\r
+ match self.peek() {\r
+ Some(&Token::Hyphen) => {}\r
+ _ => return Ok(vec![]),\r
+ }\r
+\r
+ // pop the peeked hyphen.\r
+ self.pop()?;\r
+ self.parts()\r
+ }\r
+\r
+ /// Parse a dot-separated set of identifiers.\r
+ fn parts(&mut self) -> Result<Vec<Identifier>, Error<'input>> {\r
+ let mut parts = Vec::new();\r
+\r
+ parts.push(self.identifier()?);\r
+\r
+ while let Some(&Token::Dot) = self.peek() {\r
+ self.pop()?;\r
+\r
+ parts.push(self.identifier()?);\r
+ }\r
+\r
+ Ok(parts)\r
+ }\r
+\r
+ /// Parse optional build metadata.\r
+ ///\r
+ /// Like, `` (empty), or `+abcdef`.\r
+ fn plus_build_metadata(&mut self) -> Result<Vec<Identifier>, Error<'input>> {\r
+ match self.peek() {\r
+ Some(&Token::Plus) => {}\r
+ _ => return Ok(vec![]),\r
+ }\r
+\r
+ // pop the plus.\r
+ self.pop()?;\r
+ self.parts()\r
+ }\r
+\r
+ /// Parse a version.\r
+ ///\r
+ /// Like, `1.0.0` or `3.0.0-beta.1`.\r
+ pub fn version(&mut self) -> Result<Version, Error<'input>> {\r
+ self.skip_whitespace()?;\r
+\r
+ let major = self.numeric()?;\r
+ let minor = self.dot_numeric()?;\r
+ let patch = self.dot_numeric()?;\r
+ let pre = self.pre()?;\r
+ let build = self.plus_build_metadata()?;\r
+\r
+ self.skip_whitespace()?;\r
+\r
+ Ok(Version {\r
+ major,\r
+ minor,\r
+ patch,\r
+ pre,\r
+ build,\r
+ })\r
+ }\r
+\r
+ /// Check if we have reached the end of input.\r
+ pub fn is_eof(&mut self) -> bool {\r
+ self.c1.is_none()\r
+ }\r
+\r
+ /// Get the rest of the tokens in the parser.\r
+ ///\r
+ /// Useful for debugging.\r
+ pub fn tail(&mut self) -> Result<Vec<Token<'input>>, Error<'input>> {\r
+ let mut out = Vec::new();\r
+\r
+ if let Some(t) = self.c1.take() {\r
+ out.push(t);\r
+ }\r
+\r
+ while let Some(t) = self.lexer.next() {\r
+ out.push(t?);\r
+ }\r
+\r
+ Ok(out)\r
+ }\r
+}\r