]> git.proxmox.com Git - rustc.git/blobdiff - vendor/semver-parser/src/parser.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / vendor / semver-parser / src / parser.rs
diff --git a/vendor/semver-parser/src/parser.rs b/vendor/semver-parser/src/parser.rs
new file mode 100644 (file)
index 0000000..1e29b5a
--- /dev/null
@@ -0,0 +1,262 @@
+// 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