use roxmltree::Node; use std::cell::RefCell; use std::error::Error; use std::rc::Rc; use crate::error::{BadArgumentCount, MissingChild, Unnamed}; use crate::instruction::Instruction; use crate::interpreter::context::Context; use crate::interpreter::run::Run; use crate::util; #[derive(Clone, Debug)] pub struct Function { pub args: Vec, pub ins: Vec, } impl Function { pub fn run( &self, args: Vec, ctx: &mut Context, globals: &Context, ) -> Result, Box> { if args.len() != self.args.len() { Err(BadArgumentCount("function", args.len(), self.args.len()))? } self.args .iter() .zip(args) .for_each(|(p, a)| ctx.assign(p.clone(), a)); for i in self.ins.iter() { i.run(ctx, globals)?; } Ok(ctx.take(&String::from("__return"))) } pub fn from(fun: &Node<'_, '_>) -> Result> { Ok(Function { args: util::find_node(fun, "arguments") .ok_or(MissingChild("call", "arguments"))? .children() .filter(Node::is_element) .map(|n| n.attribute("name").map(String::from)) .collect::>>() .ok_or(Unnamed("argument"))?, ins: Instruction::from_children( util::find_node(fun, "body").ok_or(MissingChild("call", "body"))?, )?, }) } } type StdFn = fn(Vec) -> Result, Box>; #[derive(Clone, Debug)] pub enum Value { Integer(i64), Real(f64), String(String), Array(Rc>>), Function(Function), StdFunction(StdFn), } impl Value { pub fn to_bool(&self) -> bool { match self { Value::Integer(i) => *i != 0, Value::Real(f) => *f != 0.0, Value::String(s) => !s.is_empty(), Value::Array(v) => v.borrow().len() != 0, _ => true, } } }