talc/talc-lang/src/exception.rs

106 lines
2.4 KiB
Rust

use std::{rc::Rc, collections::HashMap, cell::RefCell, fmt::Display};
use crate::{value::{HashValue, Value}, symbol::{SYM_DATA, SYM_MSG, SYM_TYPE}, symbol::Symbol};
pub type Result<T> = std::result::Result<T, Exception>;
#[derive(Clone, Debug)]
pub struct Exception {
pub ty: Symbol,
pub msg: Option<Rc<str>>,
pub data: Option<Value>,
}
impl Exception {
pub fn new(ty: Symbol) -> Self {
Self { ty, msg: None, data: None }
}
pub fn new_with_msg(ty: Symbol, msg: Rc<str>) -> Self {
Self { ty, msg: Some(msg), data: None }
}
pub fn new_with_data(ty: Symbol, data: Value) -> Self {
Self { ty, msg: None, data: Some(data) }
}
pub fn new_with_msg_data(ty: Symbol, msg: Rc<str>, data: Value) -> Self {
Self { ty, msg: Some(msg), data: Some(data) }
}
pub fn from_table(table: &Rc<RefCell<HashMap<HashValue, Value>>>) -> Option<Self> {
let table = table.borrow();
let ty = table.get(&(*SYM_TYPE).into())?;
if let Value::Symbol(ty) = ty {
let data = table.get(&(*SYM_DATA).into()).cloned();
let msg = table.get(&(*SYM_MSG).into());
match msg {
None => Some(Self {
ty: *ty,
data,
msg: None,
}),
Some(Value::String(msg)) => Some(Self {
ty: *ty,
data,
msg: Some(msg.clone()),
}),
Some(_) => None,
}
} else {
None
}
}
pub fn to_table(self) -> Rc<RefCell<HashMap<HashValue, Value>>> {
let mut table = HashMap::new();
table.insert((*SYM_TYPE).into(), self.ty.into());
if let Some(msg) = self.msg {
table.insert((*SYM_MSG).into(), Value::String(msg));
}
if let Some(data) = self.data {
table.insert((*SYM_DATA).into(), data);
}
Rc::new(RefCell::new(table))
}
}
impl Display for Exception {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(msg) = &self.msg {
write!(f, "{}: {}", self.ty.name(), msg)
} else {
write!(f, "{}", self.ty.name())
}
}
}
#[macro_export]
macro_rules! exception {
($exc_ty:expr, $fstr:literal, $($arg:expr),*) => {
$crate::exception::Exception::new_with_msg(
$exc_ty,
format!($fstr, $($arg),*).into()
)
};
($exc_ty:expr, $fstr:literal) => {
$crate::exception::exception!($exc_ty, $fstr,)
};
($exc_ty:expr) => {
$crate::exception::Exception::new($exc_ty)
};
}
pub use exception;
#[macro_export]
macro_rules! throw {
($($args:tt)*) => {
return Err($crate::exception::exception!($($args)*))
};
}
pub use throw;