use pest::iterators::Pair;
use pest::iterators::Pairs;
use pest::Parser;
use pest_derive::*;
use std::fmt;
#[derive(Parser)]
#[grammar = "grammar.pest"]
struct Grammar;
pub type ParserResult<'p, T> = Result<T, Error<'p>>;
#[derive(Debug, PartialEq)]
pub enum Error<'p> {
Parser(pest::error::Error<Rule>),
Pair(Pair<'p, Rule>),
}
impl<'p> fmt::Display for Error<'p> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Parser(error) => write!(formatter, "{}", error),
Error::Pair(pair) => {
let message = match pair.as_rule() {
Rule::error_block_not_terminated => "Unterminated ruleset",
_ => "Unexpected error",
};
let start = pair.as_span().start_pos();
let line = start.line_of();
let (line_no, col_no) = start.line_col();
let line_no_len = format!("{}", line_no).len();
let mut spacing = String::new();
for _ in 0..line_no_len {
spacing.push(' ');
}
write!(
formatter,
" {line_no:indent$} ┊ {line}\n {spacing:col_no$}│\n {spacing:col_no$}╰ {message} at {line_no}:{col_no}",
spacing = spacing,
indent = spacing.len(),
col_no = col_no,
line_no = line_no,
line = line,
message = message,
)
}
}
}
}
impl<'p> From<Pair<'p, Rule>> for Error<'p> {
fn from(pair: Pair<'p, Rule>) -> Self {
Error::Pair(pair)
}
}
fn parse<'p>(rule: Rule, input: &'p str) -> ParserResult<Pairs<'p, Rule>> {
match Grammar::parse(rule, input) {
Ok(pairs) => Ok(pairs),
Err(error) => Err(Error::Parser(error)),
}
}
pub fn parse_animation<'p>(animation: &'p str) -> ParserResult<Pairs<'p, Rule>> {
parse(Rule::animation, animation)
}
pub fn parse_stylesheet<'p>(stylesheet: &'p str) -> ParserResult<Pairs<'p, Rule>> {
parse(Rule::stylesheet, stylesheet)
}
pub fn parse_selector<'p>(selector: &'p str) -> ParserResult<Pairs<'p, Rule>> {
parse(Rule::selector, selector)
}