use std::{collections::BTreeMap, ops::Deref};
use crate::{lang::SError, Library, SDataRef, SDoc, SFunc, SVal};
#[derive(Default, Debug)]
pub struct FunctionLibrary;
impl FunctionLibrary {
pub fn operate(&self, pid: &str, doc: &mut SDoc, name: &str, dref: &SDataRef, parameters: &mut Vec<SVal>) -> Result<SVal, SError> {
match name {
"name" => {
let func: &SFunc = dref.data(&doc.graph).unwrap().get_data().unwrap();
Ok(SVal::String(func.name.clone()))
},
"parameters" => {
let func: &SFunc = dref.data(&doc.graph).unwrap().get_data().unwrap();
let mut params = Vec::new();
for param in &func.params {
params.push(SVal::Tuple(vec![SVal::String(param.name.clone()), SVal::String(param.ptype.type_of())]));
}
Ok(SVal::Array(params))
},
"returnType" => {
let func: &SFunc = dref.data(&doc.graph).unwrap().get_data().unwrap();
Ok(SVal::String(func.rtype.type_of()))
},
"hasAttribute" => {
if parameters.len() < 1 {
return Err(SError::func(pid, &doc, "hasAttribute", "attribute str argument not found"));
}
let func: &SFunc = dref.data(&doc.graph).unwrap().get_data().unwrap();
Ok(SVal::Bool(func.attributes.contains_key(¶meters[0].to_string())))
},
"attributes" => {
let func: &SFunc = dref.data(&doc.graph).unwrap().get_data().unwrap();
let mut attrs = BTreeMap::new();
for (key, value) in &func.attributes {
attrs.insert(SVal::String(key.clone()), value.clone());
}
Ok(SVal::Map(attrs))
},
"object" => {
let data = dref.data(&doc.graph).unwrap();
for node in &data.nodes {
return Ok(SVal::Object(node.clone()));
}
Ok(SVal::Null)
},
"objects" => {
let data = dref.data(&doc.graph).unwrap();
let mut objs = Vec::new();
for node in &data.nodes {
objs.push(SVal::Object(node.clone()));
}
Ok(SVal::Array(objs))
},
"call" => {
SFunc::call(dref, pid, doc, parameters.drain(..).collect(), true)
},
_ => {
Err(SError::func(pid, &doc, "NotFound", &format!("{} is not a function in the Function Library", name)))
}
}
}
}
impl Library for FunctionLibrary {
fn scope(&self) -> String {
"Function".to_string()
}
fn call(&self, pid: &str, doc: &mut SDoc, name: &str, parameters: &mut Vec<SVal>) -> Result<SVal, SError> {
if parameters.len() > 0 {
match name {
"toString" => {
return Ok(SVal::String(parameters[0].print(doc)));
},
"or" => {
for param in parameters.drain(..) {
if !param.is_empty() {
return Ok(param);
}
}
return Ok(SVal::Null);
},
_ => {}
}
let mut params;
if parameters.len() > 1 {
params = parameters.drain(1..).collect();
} else {
params = Vec::new();
}
match ¶meters[0] {
SVal::FnPtr(data) => {
return self.operate(pid, doc, name, data, &mut params);
},
SVal::Boxed(val) => {
let val = val.lock().unwrap();
let val = val.deref();
match val {
SVal::FnPtr(data) => {
return self.operate(pid, doc, name, data, &mut params);
},
_ => {
return Err(SError::func(pid, &doc, "InvalidArgument", "function (fn) argument not found"));
}
}
},
_ => {
return Err(SError::func(pid, &doc, "InvalidArgument", "function (fn) argument not found"));
}
}
} else {
return Err(SError::func(pid, &doc, "InvalidArgument", "function (fn) argument not found"));
}
}
}