implement ForceMode

This commit is contained in:
2026-03-30 18:23:21 +08:00
parent e82369695c
commit dc96e63b7c
2 changed files with 227 additions and 17 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ use rnix::TextRange;
use string_interner::Symbol as _; use string_interner::Symbol as _;
use crate::ir::{ArgId, Attr, BinOpKind, Ir, Param, RawIrRef, StringId, ThunkId, UnOpKind}; use crate::ir::{ArgId, Attr, BinOpKind, Ir, Param, RawIrRef, StringId, ThunkId, UnOpKind};
use crate::runtime::{BUILTINS, BuiltinId}; use crate::runtime::BUILTINS;
use crate::runtime::value::{Null, PrimOp, StaticValue}; use crate::runtime::value::{Null, PrimOp, StaticValue};
pub struct InstructionPtr(pub(crate) usize); pub struct InstructionPtr(pub(crate) usize);
+226 -16
View File
@@ -32,9 +32,10 @@ impl From<Box<Error>> for VmError {
} }
} }
#[derive(Collect, Clone, Copy, Debug, PartialEq, Eq)] #[derive(Collect, Clone, Copy, Debug, PartialEq, Eq, Default)]
#[collect(require_static)] #[collect(require_static)]
pub(super) enum ForceMode { pub(super) enum ForceMode {
#[default]
AsIs, AsIs,
Shallow, Shallow,
Deep, Deep,
@@ -1208,9 +1209,10 @@ impl Runtime {
pub(super) fn run( pub(super) fn run(
&mut self, &mut self,
ip: InstructionPtr, ip: InstructionPtr,
_mode: ForceMode, mode: ForceMode,
) -> Result<crate::value::Value> { ) -> Result<crate::value::Value> {
self.pc = ip.0; self.pc = ip.0;
self.force_mode = mode;
self.arena.mutate_root(|mc, root| { self.arena.mutate_root(|mc, root| {
if root.current_env.is_none() { if root.current_env.is_none() {
root.current_env = Some(Gc::new(mc, RefLock::new(Env::empty()))); root.current_env = Some(Gc::new(mc, RefLock::new(Env::empty())));
@@ -1255,7 +1257,7 @@ impl Runtime {
}); });
} }
pub(super) fn force_tos(&mut self) { pub(super) fn force_tos(&mut self) -> Action {
loop { loop {
let run = self.arena.mutate_root(|_mc, root| { let run = self.arena.mutate_root(|_mc, root| {
let thunk = root let thunk = root
@@ -1287,14 +1289,16 @@ impl Runtime {
} }
}); });
if !run { if !run {
return; return Action::Continue;
} }
loop { loop {
self.check_gc(); self.check_gc();
match self.execute_one() { match self.execute_one() {
Action::Continue => (), Action::Continue => (),
Action::Return => break, Action::Return => break,
Action::Done(_) => unreachable!(), // FIXME: poison thunk
Action::Done(err @ Err(_)) => return Action::Done(err),
Action::Done(Ok(_)) => unreachable!(),
} }
} }
self.arena.mutate_root(|mc, root| { self.arena.mutate_root(|mc, root| {
@@ -1305,7 +1309,7 @@ impl Runtime {
*thunk.borrow_mut(mc) = ThunkState::Evaluated(val); *thunk.borrow_mut(mc) = ThunkState::Evaluated(val);
} }
*thunk = val; *thunk = val;
}) });
} }
} }
@@ -1331,21 +1335,227 @@ impl Runtime {
pub(super) fn handle_return(&mut self) -> Action { pub(super) fn handle_return(&mut self) -> Action {
self.force_tos(); self.force_tos();
self.arena.mutate_root(|_, root| { let done= self.arena.mutate_root(|_, root| {
let Some(frame) = root.frames.pop() else { let Some(frame) = root.frames.pop() else {
// FIXME: ForceMode return true;
root.current_env = None;
return Action::Done(Ok(convert_value(
root.stack.pop().expect("what the heck"),
&self.strings,
)));
}; };
self.pc = frame.pc; self.pc = frame.pc;
root.current_env = Some(frame.env); root.current_env = Some(frame.env);
false
});
if !done {
return Action::Return;
}
match self.force_mode {
ForceMode::AsIs => (),
ForceMode::Shallow => {
if let done @ Action::Done(_) = self.force_tos_shallow() {
return done
}
}
ForceMode::Deep => {
if let done @ Action::Done(_) = self.force_tos_shallow() {
return done
}
}
}
let val = self.arena.mutate_root(|_, root| {
root.current_env = None;
convert_value(
root.stack.pop().expect("stack underflow"),
&self.strings,
)
});
Action::Done(Ok(val))
}
Action::Return pub(super) fn force_tos_shallow(&mut self) -> Action {
}) if let err @ Action::Done(Err(_)) = self.force_tos() {
return err;
}
let (is_list, is_attrs) = self.arena.mutate_root(|_, root| {
let tos = *root.stack.tos().expect("stack underflow");
(tos.as_gc::<List<'_>>().is_some(), tos.as_gc::<AttrSet<'_>>().is_some())
});
if is_list {
let len = self.arena.mutate_root(|_, root| {
let list = root.pop_stack().as_gc::<List<'_>>().unwrap();
for &item in list.inner.iter() {
root.temp_stack.push(item);
}
list.inner.len()
});
let eval_base = self.arena.mutate_root(|_, root| root.temp_stack.len());
for i in 0..len {
self.arena.mutate_root(|_, root| {
let item = root.temp_stack[eval_base - len + i];
root.push_stack(item);
});
if let err @ Action::Done(Err(_)) = self.force_tos() {
self.arena.mutate_root(|_, root| root.temp_stack.truncate(eval_base - len));
return err;
}
self.arena.mutate_root(|_, root| {
let eval_item = root.pop_stack();
root.temp_stack[eval_base - len + i] = eval_item;
});
}
self.arena.mutate_root(|mc, root| {
let items: SmallVec<[Value; 4]> = root.temp_stack[eval_base - len..eval_base].iter().copied().collect();
root.temp_stack.truncate(eval_base - len);
// Reconstruct List
let new_list = Gc::new(mc, List { inner: items });
root.push_stack(Value::new_gc(new_list));
});
} else if is_attrs {
let len = self.arena.mutate_root(|_, root| {
let attrs = root.pop_stack().as_gc::<AttrSet<'_>>().unwrap();
for &(key, item) in attrs.iter() {
root.temp_stack.push(Value::new_inline(key));
root.temp_stack.push(item);
}
attrs.len()
});
let eval_base = self.arena.mutate_root(|_, root| root.temp_stack.len());
for i in 0..len {
self.arena.mutate_root(|_, root| {
let item = root.temp_stack[eval_base - len * 2 + i * 2 + 1];
root.push_stack(item);
});
if let err @ Action::Done(Err(_)) = self.force_tos() {
self.arena.mutate_root(|_, root| root.temp_stack.truncate(eval_base - len * 2));
return err;
}
self.arena.mutate_root(|_, root| {
let eval_item = root.pop_stack();
root.temp_stack[eval_base - len * 2 + i * 2 + 1] = eval_item;
});
}
self.arena.mutate_root(|mc, root| {
let mut kv = SmallVec::with_capacity(len);
let mut i = eval_base - len * 2;
while i < eval_base {
let key = root.temp_stack[i].as_inline::<StringId>().unwrap();
let val = root.temp_stack[i + 1];
kv.push((key, val));
i += 2;
}
kv.sort_by_key(|(k, _)| *k);
root.temp_stack.truncate(eval_base - len * 2);
let new_attrs = Gc::new(mc, unsafe { AttrSet::from_sorted_unchecked(kv) });
root.push_stack(Value::new_gc(new_attrs));
});
}
Action::Continue
}
pub(super) fn force_tos_deep(&mut self) -> Action {
if let err @ Action::Done(Err(_)) = self.force_tos() {
return err;
}
let (is_list, is_attrs) = self.arena.mutate_root(|_, root| {
let tos = *root.stack.tos().expect("stack underflow");
(tos.as_gc::<List<'_>>().is_some(), tos.as_gc::<AttrSet<'_>>().is_some())
});
if is_list {
let len = self.arena.mutate_root(|_, root| {
let list = root.pop_stack().as_gc::<List<'_>>().unwrap();
for &item in list.inner.iter() {
root.temp_stack.push(item);
}
list.inner.len()
});
let eval_base = self.arena.mutate_root(|_, root| root.temp_stack.len());
for i in 0..len {
self.arena.mutate_root(|_, root| {
let item = root.temp_stack[eval_base - len + i];
root.push_stack(item);
});
if let err @ Action::Done(Err(_)) = self.force_tos_deep() {
self.arena.mutate_root(|_, root| root.temp_stack.truncate(eval_base - len));
return err;
}
self.arena.mutate_root(|_, root| {
let eval_item = root.pop_stack();
root.temp_stack[eval_base - len + i] = eval_item;
});
}
self.arena.mutate_root(|mc, root| {
let items: SmallVec<[Value; 4]> = root.temp_stack[eval_base - len..eval_base].iter().copied().collect();
root.temp_stack.truncate(eval_base - len);
let new_list = Gc::new(mc, List { inner: items });
root.push_stack(Value::new_gc(new_list));
});
} else if is_attrs {
let len = self.arena.mutate_root(|_, root| {
let attrs = root.pop_stack().as_gc::<AttrSet<'_>>().unwrap();
for &(key, item) in attrs.iter() {
root.temp_stack.push(Value::new_inline(key));
root.temp_stack.push(item);
}
attrs.len()
});
let eval_base = self.arena.mutate_root(|_, root| root.temp_stack.len());
for i in 0..len {
self.arena.mutate_root(|_, root| {
let item = root.temp_stack[eval_base - len * 2 + i * 2 + 1];
root.push_stack(item);
});
if let err @ Action::Done(Err(_)) = self.force_tos_deep() {
self.arena.mutate_root(|_, root| root.temp_stack.truncate(eval_base - len * 2));
return err;
}
self.arena.mutate_root(|_, root| {
let eval_item = root.pop_stack();
root.temp_stack[eval_base - len * 2 + i * 2 + 1] = eval_item;
});
}
self.arena.mutate_root(|mc, root| {
let mut kv = SmallVec::with_capacity(len);
let mut i = eval_base - len * 2;
while i < eval_base {
let key = root.temp_stack[i].as_inline::<StringId>().unwrap();
let val = root.temp_stack[i + 1];
kv.push((key, val));
i += 2;
}
kv.sort_by_key(|(k, _)| *k);
root.temp_stack.truncate(eval_base - len * 2);
let new_attrs = Gc::new(mc, unsafe { AttrSet::from_sorted_unchecked(kv) });
root.push_stack(Value::new_gc(new_attrs));
});
}
Action::Continue
} }
fn handle_vm_error(&mut self, e: VmError) -> Action { fn handle_vm_error(&mut self, e: VmError) -> Action {