regulus 0.0.14

A simple, interpreted language with very simple syntax and zero dependencies
Documentation
use crate::parsing::Span;
use std::{error, fmt, result};

#[derive(Debug, Clone)]
pub struct Exception {
    pub msg: String,
    pub error: String,
    pub backtrace: Vec<Span>,
}

impl Exception {
    /// Constructs an exception with the given error name and message,
    /// using the given span as the only backtrace entry.
    ///
    /// If you have a [`State`](crate::prelude::State) available,
    /// consider using [`State::raise`](crate::prelude::State::raise) instead.
    pub fn spanned(error: impl Into<String>, msg: impl Into<String>, span: &Span) -> Self {
        Self {
            msg: msg.into(),
            error: error.into(),
            backtrace: vec![span.clone()],
        }
    }

    /// Constructs an exception with the given error name, message and backtrace.
    ///
    /// If you have a [`State`](crate::prelude::State) available,
    /// consider using [`State::raise`](crate::prelude::State::raise) instead.
    pub fn with_trace(
        error: impl Into<String>,
        msg: impl Into<String>,
        backtrace: &[Span],
    ) -> Self {
        Self {
            msg: msg.into(),
            error: error.into(),
            backtrace: backtrace.to_vec(),
        }
    }
}

/// Creates an exception wrapped in an `Err` and returns it from the current function or closure.
///
/// The first argument is the current `State`, which is used to add a backtrace to the call.
/// The second argument is the kind of the exception, the third the message or format string.
/// Any further arguments are passed into the `format!` string.
#[macro_export]
macro_rules! raise {
    ($state: expr, $kind: expr, $string: literal) => {
        $crate::raise!($state, $kind, $string,)
    };
    ($state: expr, $kind: expr, $msg: expr) => {
        $crate::raise!($state, $kind, "{}", $msg)
    };
    ($state: expr, $kind: expr, $string: literal, $($fmt_args: expr),*) => {
        return Err(Exception::with_trace($kind, format!($string, $($fmt_args),*), &$state.backtrace))
    };
}

impl fmt::Display for Exception {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}Error: {}", self.error, self.msg)?;
        match self.backtrace.len() {
            0 => (),
            1 => {
                // in the case of a syntax error, the backtrace is just the error location
                write!(f, "\nat {}", self.backtrace[0])?;
            }
            _ => {
                // otherwise, the first entry is the meaningless implicit `_` wrapper
                for span in self.backtrace.iter().skip(1).rev() {
                    write!(f, "\nat {span}")?;
                }
            }
        }
        Ok(())
    }
}

impl error::Error for Exception {}

/// A shorthand alias for `Result<T, Exception>`.
pub type Result<T> = result::Result<T, Exception>;