use crate as extendr_api;
use crate::*;
pub fn global_var<K: Into<Robj>>(key: K) -> Result<Robj> {
let key = key.into();
global_env().find_var(key)?.eval_promise()
}
pub fn local_var<K: Into<Robj>>(key: K) -> Result<Robj> {
let key = key.into();
current_env().find_var(key)?.eval_promise()
}
pub fn global_function<K: Into<Robj>>(key: K) -> Result<Robj> {
let key = key.into();
global_env().find_function(key)
}
pub fn find_namespace<K: Into<Robj>>(key: K) -> Result<Environment> {
let key = key.into();
let res = single_threaded(|| call!(".getNamespace", key.clone()));
if let Ok(res) = res {
Ok(res.try_into()?)
} else {
Err(Error::NamespaceNotFound(key))
}
}
pub fn current_env() -> Environment {
unsafe { Robj::from_sexp(R_GetCurrentEnv()).try_into().unwrap() }
}
pub fn global_env() -> Environment {
unsafe { Robj::from_sexp(R_GlobalEnv).try_into().unwrap() }
}
pub fn empty_env() -> Environment {
unsafe { Robj::from_sexp(R_EmptyEnv).try_into().unwrap() }
}
#[cfg(use_r_newenv)]
pub fn new_env(parent: Environment, hash: bool, capacity: i32) -> Environment {
unsafe {
let env = R_NewEnv(parent.robj.get(), hash as i32, capacity);
Robj::from_sexp(env).try_into().unwrap()
}
}
#[cfg(not(use_r_newenv))]
pub fn new_env(parent: Environment, hash: bool, capacity: i32) -> Environment {
call!("new.env", hash, parent, capacity)
.unwrap()
.try_into()
.unwrap()
}
pub fn base_env() -> Environment {
unsafe { Robj::from_sexp(R_BaseEnv).try_into().unwrap() }
}
pub fn base_namespace() -> Environment {
unsafe { Robj::from_sexp(R_BaseNamespace).try_into().unwrap() }
}
pub fn namespace_registry() -> Environment {
unsafe { Robj::from_sexp(R_NamespaceRegistry).try_into().unwrap() }
}
pub fn srcref() -> Robj {
unsafe { Robj::from_sexp(R_Srcref) }
}
pub fn nil_value() -> Robj {
unsafe { Robj::from_sexp(R_NilValue) }
}
pub fn na_string() -> Robj {
unsafe { Robj::from_sexp(R_NaString) }
}
pub fn blank_string() -> Robj {
unsafe { Robj::from_sexp(R_BlankString) }
}
pub fn blank_scalar_string() -> Robj {
unsafe { Robj::from_sexp(R_BlankScalarString) }
}
pub fn parse(code: &str) -> Result<Expressions> {
single_threaded(|| unsafe {
use libR_sys::*;
let mut status = 0_u32;
let status_ptr = &mut status as *mut u32;
let codeobj: Robj = code.into();
let parsed = Robj::from_sexp(R_ParseVector(codeobj.get(), -1, status_ptr, R_NilValue));
match status {
1 => parsed.try_into(),
_ => Err(Error::ParseError(code.into())),
}
})
}
pub fn eval_string(code: &str) -> Result<Robj> {
single_threaded(|| {
let expr = parse(code)?;
let mut res = Robj::from(());
if let Some(expr) = expr.as_expressions() {
for lang in expr.values() {
res = lang.eval()?
}
}
Ok(res)
})
}
pub fn eval_string_with_params(code: &str, values: &[&Robj]) -> Result<Robj> {
single_threaded(|| {
let env = Environment::new_with_parent(global_env());
for (i, &v) in values.iter().enumerate() {
let key = Symbol::from_string(format!("param.{}", i));
env.set_local(key, v);
}
let expr = parse(code)?;
let mut res = Robj::from(());
if let Some(expr) = expr.as_expressions() {
for lang in expr.values() {
res = lang.eval_with_env(&env)?
}
}
Ok(res)
})
}
pub fn find_namespaced_function(name: &str) -> Result<Language> {
let mut iter = name.split("::");
match (iter.next(), iter.next(), iter.next()) {
(Some(key), None, None) => {
let gf = global_function(Symbol::from_string(key))?;
Ok(Language::from_values(&[gf]))
}
(Some(ns), Some(key), None) => {
let namespace = find_namespace(ns)?;
Ok(Language::from_values(&[
namespace.local(Symbol::from_string(key))?
]))
}
_ => Err(Error::NotFound(r!(name))),
}
}