Skip to content

Commit

Permalink
remove lifetime from ParseError (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
suaviloquence committed Jul 26, 2024
1 parent ac3d8ba commit a4cb7ae
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 137 deletions.
159 changes: 89 additions & 70 deletions src/frontend/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{
ArgList, Ast, AstRef, Element, FilterList, Inline, Leaf, Qualifier, RValue, Selector,
SelectorCombinator, SelectorList, Statement, StatementList,
},
scanner::{Lexeme, Scanner, Token},
scanner::{Lexeme, Scanner, Span, Token},
};

#[derive(Debug)]
Expand All @@ -18,26 +18,50 @@ pub struct Parser<'a> {

#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ParseError<'a> {
pub enum ParseError {
UnexpectedToken {
expected: Vec<Token>,
got: Lexeme<'a>,
got: Token,
value: String,
span: Span,
},
}

impl<'a> fmt::Display for ParseError<'a> {
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnexpectedToken { expected, got } => {
write!(f, "Expected one of {expected:?}, got {got:?}")
Self::UnexpectedToken {
expected,
got,
span,
value,
} => {
write!(
f,
"Expected one of {expected:?}, got {got:?} '{value}' on line {}",
span.line
)
}
}
}
}

impl std::error::Error for ParseError<'_> {}
impl std::error::Error for ParseError {}

impl ParseError {
/// Helper function to construct the `ParseError::UnexpectedToken` variant
/// from a [`Lexeme`] and a [`Span`] and expected values.
pub fn unexpected(expected: Vec<Token>, lx: Lexeme<'_>, span: Span) -> Self {

Check warning on line 54 in src/frontend/parser.rs

View workflow job for this annotation

GitHub Actions / verify formatting and lints

this method could have a `#[must_use]` attribute
Self::UnexpectedToken {
expected,
got: lx.token,
value: lx.value.to_owned(),
span,
}
}
}

type Result<'a, T> = std::result::Result<T, ParseError<'a>>;
type Result<T> = std::result::Result<T, ParseError>;

impl<'a> Parser<'a> {
#[must_use]
Expand All @@ -48,7 +72,7 @@ impl<'a> Parser<'a> {
}
}

pub fn parse(mut self) -> Result<'a, (Arena<Ast<'a>>, Option<AstRef<'a, StatementList<'a>>>)> {
pub fn parse(mut self) -> Result<(Arena<Ast<'a>>, Option<AstRef<'a, StatementList<'a>>>)> {

Check warning on line 75 in src/frontend/parser.rs

View workflow job for this annotation

GitHub Actions / verify formatting and lints

docs for function returning `Result` missing `# Errors` section
let r = match self.parse_statement_list() {
Ok(r) => r,
Err(e) => {
Expand All @@ -59,8 +83,8 @@ impl<'a> Parser<'a> {
Ok((self.arena, r))
}

pub fn parse_statement_list(&mut self) -> Result<'a, Option<AstRef<'a, StatementList<'a>>>> {
let lx = self.scanner.peek_non_whitespace();
pub fn parse_statement_list(&mut self) -> Result<Option<AstRef<'a, StatementList<'a>>>> {

Check warning on line 86 in src/frontend/parser.rs

View workflow job for this annotation

GitHub Actions / verify formatting and lints

docs for function returning `Result` missing `# Errors` section
let (_, lx) = self.scanner.peek_non_whitespace();

if lx.token == Token::Id {
let statement = self.parse_statement()?;
Expand All @@ -75,7 +99,7 @@ impl<'a> Parser<'a> {
}
}

fn parse_statement(&mut self) -> Result<'a, Statement<'a>> {
fn parse_statement(&mut self) -> Result<Statement<'a>> {
let id = self.try_eat(Token::Id)?.value;
self.try_eat(Token::Colon)?;
let value = self.parse_rvalue()?;
Expand All @@ -84,8 +108,8 @@ impl<'a> Parser<'a> {
Ok(Statement { id, value, filters })
}

fn parse_rvalue(&mut self) -> Result<'a, RValue<'a>> {
let lx = self.scanner.peek_non_whitespace();
fn parse_rvalue(&mut self) -> Result<RValue<'a>> {
let (_, lx) = self.scanner.peek_non_whitespace();

match lx.token {
Token::Id | Token::Less | Token::Dot | Token::Hash => {
Expand All @@ -95,9 +119,9 @@ impl<'a> Parser<'a> {
}
}

fn parse_leaf(&mut self) -> Result<'a, Leaf<'a>> {
fn parse_leaf(&mut self) -> Result<Leaf<'a>> {
self.scanner.peek_non_whitespace();
let lx = self.scanner.eat_token();
let (span, lx) = self.scanner.eat_token();
match lx.token {
Token::String => Ok(Leaf::String(parse_string_literal(lx.value))),
Token::Float => Ok(Leaf::Float(
Expand All @@ -108,29 +132,27 @@ impl<'a> Parser<'a> {
let id = self.try_eat(Token::Id)?.value;
Ok(Leaf::Var(id))
}
_ => Err(ParseError::UnexpectedToken {
expected: vec![Token::String, Token::Float, Token::Int, Token::Dollar],
got: lx,
}),
_ => Err(ParseError::unexpected(
vec![Token::String, Token::Float, Token::Int, Token::Dollar],
lx,
span,
)),
}
}

#[inline]
fn try_eat(&mut self, tk: Token) -> Result<'a, Lexeme<'a>> {
let lx = self.scanner.peek_non_whitespace();
fn try_eat(&mut self, tk: Token) -> Result<Lexeme<'a>> {
let (span, lx) = self.scanner.peek_non_whitespace();
self.scanner.eat_token();

if lx.token == tk {
Ok(lx)
} else {
Err(ParseError::UnexpectedToken {
expected: vec![tk],
got: lx,
})
Err(ParseError::unexpected(vec![tk], lx, span))
}
}

fn parse_element(&mut self) -> Result<'a, Element<'a>> {
fn parse_element(&mut self) -> Result<Element<'a>> {
let url = self.parse_maybe_url()?;
let selector_head = self.parse_selector()?;
let selectors = self.parse_selector_list()?;
Expand All @@ -152,44 +174,38 @@ impl<'a> Parser<'a> {
})
}

fn parse_maybe_url(&mut self) -> Result<'a, Option<Inline<'a>>> {
let lx = self.scanner.peek_non_whitespace();
fn parse_maybe_url(&mut self) -> Result<Option<Inline<'a>>> {
let (_, lx) = self.scanner.peek_non_whitespace();
if lx.token == Token::Less {
self.parse_inline().map(Some)
} else {
Ok(None)
}
}

fn parse_inline(&mut self) -> Result<'a, Inline<'a>> {
let lx = self.scanner.peek_non_whitespace();
if lx.token == Token::Less {
self.scanner.eat_token();
let value = self.parse_leaf()?;
let filters = self.parse_filter_list()?;
self.try_eat(Token::Greater)?;
Ok(Inline { value, filters })
} else {
Err(ParseError::UnexpectedToken {
expected: vec![Token::Less],
got: lx,
})
}
fn parse_inline(&mut self) -> Result<Inline<'a>> {
self.try_eat(Token::Less)?;
let value = self.parse_leaf()?;
let filters = self.parse_filter_list()?;
self.try_eat(Token::Greater)?;
Ok(Inline { value, filters })
}

fn parse_selector_list(&mut self) -> Result<'a, Option<AstRef<'a, SelectorList<'a>>>> {
let mut lx = self.scanner.peek_token();
if lx.token == Token::Whitespace {
fn parse_selector_list(&mut self) -> Result<Option<AstRef<'a, SelectorList<'a>>>> {
let mut item = self.scanner.peek_token();
if item.1.token == Token::Whitespace {
self.scanner.eat_token();
let next_lx = self.scanner.peek_non_whitespace();
let next = self.scanner.peek_non_whitespace();
// if the next lexeme after the whitespace doesn't signify a selector,
// the whitespace is not significant.
match next_lx.token {
match next.1.token {
Token::Id | Token::Hash | Token::Dot | Token::Star => (),
_ => lx = next_lx,
_ => item = next,
};
}

let (span, lx) = item;

let sel = match lx.token {
Token::BraceOpen | Token::ParenOpen => return Ok(None),
// invariant: peek_next_whitespace is one of Id | Hash | Dot | Star
Expand All @@ -211,8 +227,8 @@ impl<'a> Parser<'a> {
SelectorCombinator::And(self.parse_selector()?)
}
_ => {
return Err(ParseError::UnexpectedToken {
expected: vec![
return Err(ParseError::unexpected(
vec![
Token::Whitespace,
Token::Greater,
Token::Plus,
Expand All @@ -222,8 +238,9 @@ impl<'a> Parser<'a> {
Token::Id,
Token::Star,
],
got: lx,
})
lx,
span,
))
}
};

Expand All @@ -232,8 +249,8 @@ impl<'a> Parser<'a> {
Ok(Some(self.arena.insert_variant(itm)))
}

fn parse_selector(&mut self) -> Result<'a, Selector<'a>> {
let lx = self.scanner.peek_non_whitespace();
fn parse_selector(&mut self) -> Result<Selector<'a>> {
let (span, lx) = self.scanner.peek_non_whitespace();
match lx.token {
Token::Dot => {
self.scanner.eat_token();
Expand All @@ -251,15 +268,16 @@ impl<'a> Parser<'a> {
self.scanner.eat_token();
Ok(Selector::Any)
}
_ => Err(ParseError::UnexpectedToken {
expected: vec![Token::Dot, Token::Hash, Token::Id, Token::Star],
got: lx,
}),
_ => Err(ParseError::unexpected(
vec![Token::Dot, Token::Hash, Token::Id, Token::Star],
lx,
span,
)),
}
}

fn parse_filter_list(&mut self) -> Result<'a, Option<AstRef<'a, FilterList<'a>>>> {
let lx = self.scanner.peek_non_whitespace();
fn parse_filter_list(&mut self) -> Result<Option<AstRef<'a, FilterList<'a>>>> {
let (_, lx) = self.scanner.peek_non_whitespace();
if lx.token == Token::Pipe {
self.scanner.eat_token();
let id = self.try_eat(Token::Id)?.value;
Expand All @@ -277,16 +295,16 @@ impl<'a> Parser<'a> {
}
}

fn parse_arg_list(&mut self) -> Result<'a, Option<AstRef<'a, ArgList<'a>>>> {
let lx = self.scanner.peek_non_whitespace();
fn parse_arg_list(&mut self) -> Result<Option<AstRef<'a, ArgList<'a>>>> {
let (span, lx) = self.scanner.peek_non_whitespace();
match lx.token {
Token::ParenClose => Ok(None),
Token::Id => {
let id = lx.value;
self.scanner.eat_token();
self.try_eat(Token::Colon)?;
let value = self.parse_leaf()?;
let next = match self.scanner.peek_non_whitespace().token {
let next = match self.scanner.peek_non_whitespace().1.token {
Token::Comma => {
self.scanner.eat_token();
self.parse_arg_list()?
Expand All @@ -297,15 +315,16 @@ impl<'a> Parser<'a> {
let r = self.arena.insert_variant(ArgList::new(id, value, next));
Ok(Some(r))
}
_ => Err(ParseError::UnexpectedToken {
expected: vec![Token::ParenClose, Token::Id],
got: lx,
}),
_ => Err(ParseError::unexpected(
vec![Token::ParenClose, Token::Id],
lx,
span,
)),
}
}

fn parse_qualifier(&mut self) -> Result<'a, Qualifier> {
let lx = self.scanner.peek_non_whitespace();
fn parse_qualifier(&mut self) -> Result<Qualifier> {

Check warning on line 326 in src/frontend/parser.rs

View workflow job for this annotation

GitHub Actions / verify formatting and lints

this function's return value is unnecessarily wrapped by `Result`
let (_, lx) = self.scanner.peek_non_whitespace();
Ok(match lx.token {
Token::Question => {
self.scanner.eat_token();
Expand Down
Loading

0 comments on commit a4cb7ae

Please sign in to comment.