use miette::{Diagnostic, NamedSource, SourceSpan};
use pest::error::{Error, ErrorVariant};
use thiserror::Error;
use crate::parser::Rule;
#[derive(Error, Diagnostic, Debug)]
pub enum PolentaError {
#[error(transparent)]
#[diagnostic(transparent)]
InterpreterError(#[from] InterpreterError),
#[error(transparent)]
#[diagnostic(transparent)]
ParserError(#[from] ParserError),
}
#[derive(Error, Debug, Diagnostic)]
pub enum InterpreterError {
#[error("Unknown Identifier: {0}")]
UnknownIdentifier(String),
#[error("Division by Zero")]
DivisionByZero,
#[help("Asserted expression must be non-zero.")]
#[error("Assertion Failed")]
AssertionFailed,
#[help("Exponent and evaluation point must be constant (degree 0) polynomials.")]
#[error("Expected Constant Polynomial")]
ExpectedConstant,
}
#[derive(Error, Debug, Diagnostic)]
#[error("Syntax Error")]
pub struct ParserError {
#[source_code]
src: NamedSource<String>,
#[label]
problem: SourceSpan,
#[help]
help: String,
}
pub(crate) fn pest_error_to_miette_error(err: Error<Rule>) -> ParserError {
let (start, length) = match err.line_col {
pest::error::LineColLocation::Pos((_, col)) => (col - 1, 1),
pest::error::LineColLocation::Span((_, col_s), (_, col_e)) => {
(col_s - 1, col_e - col_s + 1)
}
};
let help = match &err.variant {
ErrorVariant::CustomError { message } => message.into(),
ErrorVariant::ParsingError {
positives,
negatives,
} => {
format!("Expected one of {:?}, got {:?}", positives, negatives)
}
};
let miette_error = ParserError {
src: NamedSource::new("input", err.line().to_string()).with_language("Rust"),
problem: SourceSpan::new(start.into(), length),
help,
};
miette_error
}