use crate::prelude::*;
#[derive(Debug, Clone)]
pub enum Argument {
FunctionCall(FunctionCall, Span),
Atom(Atom, Span),
Variable(String, Span),
}
impl Argument {
pub fn eval(&self, state: &mut State) -> Result<Atom> {
if state.exit_unwind_value.is_some() {
return Ok(Atom::Null);
}
state.backtrace.push(self.span().clone());
if let Self::FunctionCall(call, _) = self {
state.current_doc_comment = Some(call.doc_comment.clone());
state.current_fn_name = Some(call.name.clone());
} else {
state.current_doc_comment = None;
state.current_fn_name = None;
}
let res = match self {
Self::FunctionCall(call, _) => call.eval(state),
Self::Atom(atom, _) => Ok(atom.clone()),
Self::Variable(var, _) => match state.storage.get(var) {
Some(value) => Ok(value.clone()),
None => raise!(state, "Name", "no variable named `{var}` found"),
},
};
state.backtrace.pop();
res
}
pub(crate) fn variable(&self, error_msg: &str, state: &State) -> Result<&str> {
match self {
Self::Variable(var, _) => Ok(var),
_ => raise!(state, "Argument", error_msg),
}
}
pub fn stringify(&self) -> String {
match self {
Self::Atom(atom, _) => atom.stringify(),
Self::FunctionCall(call, _) => call.stringify(),
Self::Variable(name, _) => name.clone(),
}
}
pub const fn span(&self) -> &Span {
match self {
Self::Atom(_, s) | Self::FunctionCall(_, s) | Self::Variable(_, s) => s,
}
}
}
macro_rules! argument_eval_as_methods {
($($method_name: ident: $variant:ident -> $ty:ty;)*) => {
impl Argument {
$(
pub fn $method_name(&self, state: &mut State) -> Result<$ty> {
match self.eval(state)? {
Atom::$variant(v) => Ok(v),
val => raise!(state, "Type", "{val} is not a {}", stringify!($variant)),
}
}
)*
}
};
}
impl Argument {
pub fn eval_as_string(&self, state: &mut State) -> Result<String> {
let val = self.eval(state)?;
match val.as_string() {
Some(s) => Ok(s),
None => raise!(state, "Type", "{val} is not a list of chars"),
}
}
pub(crate) fn eval_mode(&self, state: &mut State) -> i64 {
self.eval_int(state)
.expect("mode argument must be an integer")
}
}
argument_eval_as_methods! {
eval_int: Int -> i64;
eval_bool: Bool -> bool;
eval_char: Char -> char;
eval_list: List -> List;
eval_function: Function -> Function;
eval_object: Object -> Object;
}