#![doc(test(attr(deny(warnings))))]
pub mod ast;
pub mod dialects;
pub mod eval;
pub mod lexer;
pub mod parser;
mod print;
use winnow::prelude::*;
use winnow::stream::TokenSlice;
use crate::ast::ExpressionConstraint;
use crate::lexer::LexError;
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum ParseError {
#[error(transparent)]
Lex(#[from] LexError),
#[error("expected {expected} at byte {offset}, found {found}")]
Syntax {
offset: usize,
expected: String,
found: String,
},
}
impl ParseError {
#[must_use]
pub fn offset(&self) -> usize {
match self {
Self::Lex(error) => error.offset,
Self::Syntax { offset, .. } => *offset,
}
}
}
pub fn parse(input: &str) -> Result<ExpressionConstraint, ParseError> {
let tokens = lexer::lex(input)?;
parser::whole
.parse(TokenSlice::new(&tokens))
.map_err(|error| {
let index = error.offset();
let (offset, found) = tokens.get(index).map_or_else(
|| (input.len(), String::from("the end of the expression")),
|token| (token.span.start, format!("{:?}", token.text)),
);
ParseError::Syntax {
offset,
expected: String::from(
error
.inner()
.expected
.unwrap_or("a valid expression constraint"),
),
found,
}
})
}
impl std::str::FromStr for ExpressionConstraint {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse(s)
}
}