use std::collections::HashMap;
use gc::{Gc, Trace};
use context::Context;
use symbol::Symbol;
use value::Value;
#[derive(Clone, Debug, Finalize)]
pub enum GcVoid {}
unsafe impl Trace for GcVoid {
unsafe_empty_trace!();
}
pub fn as_list<C: 'static + Context>(val: Gc<Value<C>>) -> Option<Vec<Gc<Value<C>>>> {
let mut out = Vec::new();
let mut val: &Value<C> = &*val;
while let &Value::Cons(ref h, ref t, _) = val {
out.push(h.clone());
val = t;
}
if let &Value::Nil(_) = val {
Some(out)
} else {
None
}
}
pub fn as_list_meta<C: 'static + Context>(
val: Gc<Value<C>>,
) -> Option<Vec<(Gc<Value<C>>, C::ValueMeta)>> {
let mut out = Vec::new();
let mut val: &Value<C> = &*val;
while let &Value::Cons(ref h, ref t, ref m) = val {
out.push((h.clone(), m.clone()));
val = t;
}
if let &Value::Nil(_) = val {
Some(out)
} else {
None
}
}
pub fn as_shl<C: 'static + Context>(val: Gc<Value<C>>) -> Option<(Symbol, Vec<Gc<Value<C>>>)> {
if let Value::Cons(ref h, ref t, _) = *val {
if let Value::Symbol(sym, _) = **h {
as_list(t.clone()).map(|t| (sym, t))
} else {
None
}
} else {
None
}
}
pub fn as_sym_list<C: 'static + Context>(val: Gc<Value<C>>) -> Option<Vec<Symbol>> {
let mut out = Vec::new();
for val in try_opt!(as_list(val)) {
if let &Value::Symbol(s, _) = &*val {
out.push(s);
} else {
return None;
}
}
Some(out)
}
pub fn from_assoc<C: 'static + Context>(
val: Gc<Value<C>>,
) -> Option<HashMap<Symbol, Gc<Value<C>>>> {
let list = try_opt!(as_list(val));
let mut map = HashMap::new();
for val in list {
match *val {
Value::Cons(ref h, ref t, _) => {
match **h {
Value::Symbol(s, _) => map.insert(s, t.clone()),
_ => return None,
}
}
_ => return None,
};
}
Some(map)
}
pub fn from_list_meta<C: 'static + Context>(
mut vec: Vec<(Gc<Value<C>>, C::ValueMeta)>,
) -> Gc<Value<C>> {
let mut out = Gc::new(Value::Nil(C::ValueMeta::default()));
while let Some((val, meta)) = vec.pop() {
out = Gc::new(Value::Cons(val, out, meta));
}
out
}
pub fn is_internal(import_path: Symbol) -> bool {
let s = import_path.as_str();
s == "std/prelude" || s.starts_with("std/internal/prelude/")
}
pub fn is_shl<C: 'static + Context>(sym: Symbol, val: Gc<Value<C>>) -> bool {
if let Value::Cons(ref h, _, _) = *val {
if let Value::Symbol(s, _) = **h {
s == sym
} else {
false
}
} else {
false
}
}
pub fn to_assoc<'a, C, I>(map: I) -> Gc<Value<C>>
where
C: 'static + Context,
I: IntoIterator<Item = (&'a Symbol, &'a Gc<Value<C>>)>,
{
let mut list = vec![];
for (&k, v) in map {
let k = Gc::new(Value::Symbol(k, Default::default()));
let v = v.clone();
list.push(Gc::new(Value::Cons(k, v, Default::default())));
}
Value::list(list, Default::default())
}