rimu-value 0.2.0

A data structure template system.
Documentation
use rimu_ast::Expression;
use rimu_meta::{ErrorReport, Span};

use crate::{EnvironmentError, SerdeValue, SerdeValueObject};

#[derive(Debug, thiserror::Error, Clone, PartialEq)]
pub enum EvalError {
    #[error("{source}")]
    Environment {
        span: Span,
        #[source]
        source: EnvironmentError,
    },
    #[error("missing variable: {var}")]
    MissingVariable { span: Span, var: String },
    #[error("tried to call non-function: {expr}")]
    CallNonFunction { span: Span, expr: Expression },
    #[error("missing argument: {index}")]
    MissingArgument { span: Span, index: usize },
    #[error("type error, expected: {expected}, got: {got}")]
    TypeError {
        span: Span,
        expected: String,
        got: SerdeValue,
    },
    #[error("index out of bounds, index: {index}, length: {length}")]
    IndexOutOfBounds {
        container_span: Span,
        index_span: Span,
        index: isize,
        length: usize,
    },
    #[error("key error, key: {key}, object: {object:?}")]
    KeyNotFound {
        key_span: Span,
        key: String,
        object_span: Span,
        object: SerdeValueObject,
    },
    #[error("range start >= end, start: {start}, end: {end}")]
    RangeStartGreaterThanOrEqualToEnd {
        span: Span,
        start: usize,
        end: usize,
    },
    #[error("unterminated interpolation: {src}")]
    UnterminatedInterpolation { span: Span, src: String },
    #[error("cannot be interpolated into a string: {value}")]
    InvalidInterpolationValue { span: Span, value: SerdeValue },
    #[error("error expression")]
    ErrorExpression { span: Span },
}

impl From<EvalError> for ErrorReport {
    fn from(value: EvalError) -> Self {
        let (span, msg, labels, notes): (Span, &str, Vec<(Span, String)>, Vec<String>) = match value
        {
            EvalError::Environment { span, source } => (
                span.clone(),
                "Eval: Environment error",
                vec![(span.clone(), format!("{}", source))],
                vec![],
            ),
            EvalError::MissingVariable { span, var } => (
                span.clone(),
                "Eval: Missing variable",
                vec![(span.clone(), format!("Not in environment: {}", var))],
                vec![],
            ),
            EvalError::CallNonFunction { span, expr } => (
                span.clone(),
                "Eval: Tried to call non-function",
                vec![(span.clone(), format!("Not a function: {}", expr))],
                vec![],
            ),
            EvalError::MissingArgument { span, index } => (
                span.clone(),
                "Eval: Tried to call function without required argument",
                vec![(span.clone(), format!("Argument index: {}", index))],
                vec![],
            ),
            EvalError::TypeError {
                span,
                expected,
                got,
            } => (
                span.clone(),
                "Eval: Unexpected type",
                vec![(
                    span.clone(),
                    format!("Expected: {}, got: {}", expected, got),
                )],
                vec![],
            ),
            EvalError::IndexOutOfBounds {
                container_span,
                index,
                index_span,
                length,
            } => (
                container_span.clone().union(index_span.clone()),
                "Eval: Index out of bounds",
                vec![
                    (container_span.clone(), format!("Length: {}", length)),
                    (index_span.clone(), format!("Index: {}", index)),
                ],
                vec![],
            ),
            EvalError::KeyNotFound {
                key_span,
                key,
                object_span,
                object,
            } => (
                key_span.clone().union(object_span.clone()),
                "Eval: Key not found",
                vec![
                    (
                        object_span.clone(),
                        format!("Object: {}", SerdeValue::Object(object.clone())),
                    ),
                    (key_span.clone(), format!("Key: {}", key)),
                ],
                vec![],
            ),
            EvalError::RangeStartGreaterThanOrEqualToEnd { span, start, end } => (
                span.clone(),
                "Eval: Range start >= end",
                vec![(span.clone(), format!("{} >= {}", start, end))],
                vec![],
            ),
            EvalError::UnterminatedInterpolation { span, src } => (
                span.clone(),
                "Eval: Unterminated interpolation",
                vec![(span.clone(), format!("Source: {}", src))],
                vec![],
            ),
            EvalError::InvalidInterpolationValue { span, value } => (
                span.clone(),
                "Eval: Cannot be interpolated into a string",
                vec![(
                    span.clone(),
                    format!("Value cannot be interpolated into a string: {}", value),
                )],
                vec![],
            ),
            EvalError::ErrorExpression { span } => (
                span.clone(),
                "Eval: Expression error",
                vec![(span.clone(), "Error".to_string())],
                vec![],
            ),
        };

        ErrorReport {
            span,
            message: msg.into(),
            labels,
            notes,
        }
    }
}