use std::fmt;
use std::mem;
use self::Error::*;
use crate::lexer::{self, Lexer, Token};
use crate::version::{Identifier, Version};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Error<'input> {
UnexpectedEnd,
UnexpectedToken(Token<'input>),
Lexer(lexer::Error),
MoreInput(Vec<Token<'input>>),
EmptyPredicate,
EmptyRange,
}
impl<'input> From<lexer::Error> for Error<'input> {
fn from(value: lexer::Error) -> Self {
Error::Lexer(value)
}
}
impl<'input> fmt::Display for Error<'input> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match *self {
UnexpectedEnd => write!(fmt, "expected more input"),
UnexpectedToken(ref token) => write!(fmt, "encountered unexpected token: {:?}", token),
Lexer(ref error) => write!(fmt, "lexer error: {:?}", error),
MoreInput(ref tokens) => write!(fmt, "expected end of input, but got: {:?}", tokens),
EmptyPredicate => write!(fmt, "encountered empty predicate"),
EmptyRange => write!(fmt, "encountered empty range"),
}
}
}
impl<'input> From<Error<'input>> for String {
fn from(value: Error<'input>) -> Self {
value.to_string()
}
}
pub struct Parser<'input> {
lexer: Lexer<'input>,
c1: Option<Token<'input>>,
}
impl<'input> Parser<'input> {
pub fn new(input: &'input str) -> Result<Parser<'input>, Error<'input>> {
let mut lexer = Lexer::new(input);
let c1 = if let Some(c1) = lexer.next() {
Some(c1?)
} else {
None
};
Ok(Parser { lexer, c1 })
}
#[inline(always)]
fn pop(&mut self) -> Result<Token<'input>, Error<'input>> {
let c1 = if let Some(c1) = self.lexer.next() {
Some(c1?)
} else {
None
};
mem::replace(&mut self.c1, c1).ok_or_else(|| UnexpectedEnd)
}
#[inline(always)]
fn peek(&mut self) -> Option<&Token<'input>> {
self.c1.as_ref()
}
fn skip_whitespace(&mut self) -> Result<(), Error<'input>> {
match self.peek() {
Some(&Token::Whitespace(_, _)) => self.pop().map(|_| ()),
_ => Ok(()),
}
}
pub fn component(&mut self) -> Result<Option<u64>, Error<'input>> {
match self.pop()? {
Token::Numeric(number) => Ok(Some(number)),
ref t if t.is_wildcard() => Ok(None),
tok => Err(UnexpectedToken(tok)),
}
}
pub fn numeric(&mut self) -> Result<u64, Error<'input>> {
match self.pop()? {
Token::Numeric(number) => Ok(number),
tok => Err(UnexpectedToken(tok)),
}
}
pub fn dot_component(&mut self) -> Result<(Option<u64>, bool), Error<'input>> {
match self.peek() {
Some(&Token::Dot) => {}
_ => return Ok((None, false)),
}
self.pop()?;
self.component().map(|n| (n, n.is_none()))
}
pub fn dot_numeric(&mut self) -> Result<u64, Error<'input>> {
match self.pop()? {
Token::Dot => {}
tok => return Err(UnexpectedToken(tok)),
}
self.numeric()
}
pub fn identifier(&mut self) -> Result<Identifier, Error<'input>> {
self.bounded_identifier(0)
}
fn bounded_identifier(&mut self, count: u32) -> Result<Identifier, Error<'input>> {
if count > 255 {
panic!("Cannot have more than 255 identifiers");
}
let identifier = match self.pop()? {
Token::AlphaNumeric(identifier) => {
Identifier::AlphaNumeric(identifier.to_string())
}
Token::Numeric(n) => Identifier::Numeric(n),
tok => return Err(UnexpectedToken(tok)),
};
if let Some(&Token::Hyphen) = self.peek() {
self.pop()?;
Ok(identifier
.concat("-")
.concat(&self.bounded_identifier(count + 1)?.to_string()))
} else {
Ok(identifier)
}
}
fn pre(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
match self.peek() {
Some(&Token::Hyphen) => {}
_ => return Ok(vec![]),
}
self.pop()?;
self.parts()
}
fn parts(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
let mut parts = Vec::new();
parts.push(self.identifier()?);
while let Some(&Token::Dot) = self.peek() {
self.pop()?;
parts.push(self.identifier()?);
}
Ok(parts)
}
fn plus_build_metadata(&mut self) -> Result<Vec<Identifier>, Error<'input>> {
match self.peek() {
Some(&Token::Plus) => {}
_ => return Ok(vec![]),
}
self.pop()?;
self.parts()
}
pub fn version(&mut self) -> Result<Version, Error<'input>> {
self.skip_whitespace()?;
let major = self.numeric()?;
let minor = self.dot_numeric()?;
let patch = self.dot_numeric()?;
let pre = self.pre()?;
let build = self.plus_build_metadata()?;
self.skip_whitespace()?;
Ok(Version {
major,
minor,
patch,
pre,
build,
})
}
pub fn is_eof(&mut self) -> bool {
self.c1.is_none()
}
pub fn tail(&mut self) -> Result<Vec<Token<'input>>, Error<'input>> {
let mut out = Vec::new();
if let Some(t) = self.c1.take() {
out.push(t);
}
while let Some(t) = self.lexer.next() {
out.push(t?);
}
Ok(out)
}
}
#[cfg(test)]
mod tests {
use crate::version::parse;
#[test]
#[should_panic(expected = "Cannot have more than 255 identifiers")]
fn fuzz_0001() {
let version = std::fs::read_to_string("tests/fixtures/fuzz-0001.txt").expect("should be able to read version from file");
parse(&version).ok();
}
}