use std::fmt;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct EvaluationOptions: i32 {
const NONE = 0;
const DO_NOT_ALTER_VALUES = 1;
const ALLOW_EMPTY_EXPRESSION = 2;
const ALLOW_INDEXING_EMPTY_ARRAYS = 4;
const CREATE_NON_EXISTENT_VARIABLES = 8;
const FOR_ERROR_CHECKING = 16;
const IGNORE_NO_VALIDATION_DIRECTIVE = 32;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ExpressionError {
pub description: String,
pub start: i32,
pub end: i32,
}
impl ExpressionError {
pub(crate) const fn new(description: String, start: i32, end: i32) -> Self {
Self {
description,
start,
end,
}
}
#[must_use]
pub fn span<'text>(&self, expression: &'text str) -> Option<&'text str> {
let start = usize::try_from(self.start).ok()?;
let end = usize::try_from(self.end).ok()?;
expression.get(start..end)
}
}
impl fmt::Display for ExpressionError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{} (characters {} to {})",
self.description, self.start, self.end
)
}
}
impl std::error::Error for ExpressionError {}
#[cfg(test)]
mod tests {
use super::{EvaluationOptions, ExpressionError};
#[test]
fn an_error_locates_itself_in_the_expression_it_came_from() {
let error = ExpressionError::new("undefined variable".to_owned(), 7, 13);
assert_eq!(error.span("Locals.absent + 1"), Some("absent"));
}
#[test]
fn an_error_out_of_range_reports_no_span() {
let error = ExpressionError::new("bad".to_owned(), 4, 99);
assert_eq!(error.span("abc"), None);
}
#[test]
fn the_default_evaluation_is_no_options() {
assert_eq!(EvaluationOptions::default().bits(), 0);
}
}