mod builtin;
pub mod eval;
pub mod token;
pub mod value;
pub use builtin::BUILTIN_FUNCTIONS;
pub use builtin::ERR_SYMBOL;
pub use builtin::FALSE_SYMBOL;
pub use builtin::MODULE_NAME_ENV;
pub use builtin::MODULE_PATH_ENV;
pub use builtin::OK_SYMBOL;
pub use builtin::TRUE_SYMBOL;
use crate::{builtin::ENV_ARGS_ENV, value::Value};
pub type Dict = rustc_hash::FxHashMap<std::sync::Arc<str>, std::sync::Arc<Value>>;
#[derive(Debug)]
pub struct Scope {
pub store: parking_lot::RwLock<Dict>,
pub parent: Option<Environment>,
}
pub type Environment = std::sync::Arc<Scope>;
pub const INIT_STACK_SIZE: usize = 8 * 1024 * 1024;
pub fn init_environment(env_args: Option<Value>) -> Environment {
let mut store = Dict::default();
for &func in BUILTIN_FUNCTIONS.iter() {
store.insert(
std::sync::Arc::from(func),
std::sync::Arc::new(Value::Builtin(func)),
);
}
store.insert(
MODULE_PATH_ENV.clone(),
std::sync::Arc::new(Value::Object(MODULE_PATH_ENV.clone(), Box::default())),
);
if let Some(val) = env_args
&& let Value::List(_) = val
{
store.insert(ENV_ARGS_ENV.clone(), std::sync::Arc::new(val));
}
std::sync::Arc::new(Scope {
store: parking_lot::RwLock::new(store),
parent: None,
})
}
pub fn read_from_environment(env: &Environment, key: &str) -> Option<std::sync::Arc<Value>> {
let mut current = env;
loop {
if let Some(val) = current.store.upgradable_read().get(key) {
return Some(val.clone());
}
match ¤t.parent {
Some(parent) => {
current = parent;
}
None => {
return None;
}
}
}
}
pub fn find_define_environment(env: &Environment, key: &str) -> Option<Environment> {
let mut current = env;
loop {
if current.store.upgradable_read().contains_key(key) {
return Some(current.clone());
}
match current.parent.as_ref() {
Some(parent) => {
current = parent;
}
None => {
return None;
}
}
}
}
pub fn is_number_eq(n1: f64, n2: f64) -> bool { (n1 == n2) || (n1 - n2).abs() <= n1.abs().max(n2.abs()) * f64::EPSILON }
pub fn is_invalid_symbol(sym: &std::sync::Arc<str>) -> bool {
sym.as_ref() == ENV_ARGS_ENV.as_ref()
|| sym.as_ref() == MODULE_NAME_ENV.as_ref()
|| sym.as_ref() == MODULE_PATH_ENV.as_ref()
|| BUILTIN_FUNCTIONS.contains(&sym.as_ref())
}
pub fn expand_tilde(path: std::sync::Arc<str>) -> Result<std::path::PathBuf, std::sync::Arc<str>> {
match path.strip_prefix("~/") {
Some(rest) => std::env::home_dir()
.ok_or_else(|| {
std::sync::Arc::from(
concat!(
"Error[ksl::expand_tilde]: ",
"Failed to get user home directory path."
)
.to_string(),
)
})
.map(|p| p.join(rest)),
None => Ok(std::path::PathBuf::from(path.as_ref())),
}
}