ForceMode
This commit is contained in:
+37
-6
@@ -13,7 +13,7 @@ use fix_common::StringId;
|
||||
use fix_error::{Error, Result, Source};
|
||||
use gc_arena::arena::CollectionPhase;
|
||||
use gc_arena::{Arena, Collect, Gc, Mutation, RefLock, Rootable};
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use num_enum::TryFromPrimitive;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
@@ -115,6 +115,16 @@ impl<T: VmRuntimeCtx> VmRuntimeCtxExt for T {
|
||||
}
|
||||
|
||||
fn convert_value(&self, val: Value) -> fix_common::Value {
|
||||
self.convert_value_with_seen(val, &mut HashSet::new())
|
||||
}
|
||||
}
|
||||
|
||||
trait ConvertValueWithSeen: VmRuntimeCtx {
|
||||
fn convert_value_with_seen(&self, val: Value, seen: &mut HashSet<u64>) -> fix_common::Value;
|
||||
}
|
||||
|
||||
impl<T: VmRuntimeCtx> ConvertValueWithSeen for T {
|
||||
fn convert_value_with_seen(&self, val: Value, seen: &mut HashSet<u64>) -> fix_common::Value {
|
||||
use fix_common::Value;
|
||||
if let Some(i) = val.as_inline::<i32>() {
|
||||
Value::Int(i as i64)
|
||||
@@ -132,26 +142,44 @@ impl<T: VmRuntimeCtx> VmRuntimeCtxExt for T {
|
||||
} else if let Some(ns) = val.as_gc::<NixString>() {
|
||||
Value::String(ns.as_str().to_owned())
|
||||
} else if let Some(attrs) = val.as_gc::<AttrSet>() {
|
||||
let bits = val.to_bits();
|
||||
if attrs.is_empty() {
|
||||
return Value::AttrSet(Default::default());
|
||||
}
|
||||
if !seen.insert(bits) {
|
||||
return Value::Repeated;
|
||||
}
|
||||
let mut map = std::collections::BTreeMap::new();
|
||||
for &(key, val) in attrs.iter() {
|
||||
let key = self.resolve_string(key).to_owned();
|
||||
let converted = self.convert_value(val);
|
||||
let converted = self.convert_value_with_seen(val, seen);
|
||||
map.insert(fix_common::Symbol::from(key), converted);
|
||||
}
|
||||
Value::AttrSet(fix_common::AttrSet::new(map))
|
||||
} else if let Some(list) = val.as_gc::<List>() {
|
||||
let bits = val.to_bits();
|
||||
if list.inner.borrow().is_empty() {
|
||||
return Value::List(Default::default());
|
||||
}
|
||||
if !seen.insert(bits) {
|
||||
return Value::Repeated;
|
||||
}
|
||||
let items: Vec<_> = list
|
||||
.inner
|
||||
.borrow()
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|v| self.convert_value(v))
|
||||
.map(|v| self.convert_value_with_seen(v, seen))
|
||||
.collect();
|
||||
Value::List(fix_common::List::new(items))
|
||||
} else if val.is::<Closure>() {
|
||||
Value::Func
|
||||
} else if val.is::<Thunk>() {
|
||||
Value::Thunk
|
||||
} else if let Some(thunk) = val.as_gc::<Thunk>() {
|
||||
if let ThunkState::Evaluated(v) = *thunk.borrow() {
|
||||
self.convert_value_with_seen(v.relax(), seen)
|
||||
} else {
|
||||
Value::Thunk
|
||||
}
|
||||
} else if let Some(primop) = val.as_inline::<PrimOp>() {
|
||||
let name = fix_builtins::BUILTINS[primop.id as usize].0;
|
||||
Value::PrimOp(name.strip_prefix("__").unwrap_or(name))
|
||||
@@ -278,7 +306,10 @@ fn init_builtins<'gc>(mc: &Mutation<'gc>, ctx: &mut impl VmRuntimeCtx) -> Value<
|
||||
entries.sort_by_key(|(k, _)| *k);
|
||||
|
||||
let builtins_set = Gc::new(mc, AttrSet::from_sorted_unchecked(entries));
|
||||
Value::new_gc(builtins_set)
|
||||
let builtins_value = Value::new_gc(builtins_set);
|
||||
*self_ref_thunk.borrow_mut(mc) =
|
||||
ThunkState::Evaluated(builtins_value.restrict().expect("builtins is not a thunk"));
|
||||
builtins_value
|
||||
}
|
||||
|
||||
impl<'gc> Vm<'gc> {
|
||||
|
||||
Reference in New Issue
Block a user