implement foldl'

This commit is contained in:
2026-05-07 21:35:29 +08:00
parent cfd2df5d0e
commit 3d07f89afe
5 changed files with 113 additions and 6 deletions
+96
View File
@@ -70,4 +70,100 @@ impl<'gc> Vm<'gc> {
reader.set_pc(PrimOpPhase::FilterCallPred.ip() as usize);
Step::Continue(())
}
// foldl' op nul list
//
// Stack layouts across phases:
// Entry: [op, nul, list]
// Empty: [op, nul]
// Call1: [op, list, idx, acc]
// Call2: [op, list, idx, acc, intermediate]
// Update: [op, list, idx, acc, result]
pub(crate) fn primop_foldl_strict_entry(
&mut self,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.force_slot(0, reader, mc)?;
let list_val = self.peek_forced(0);
let Some(list) = list_val.as_gc::<List>() else {
return self.finish_type_err(NixType::List, list_val.ty());
};
if list.inner.borrow().is_empty() {
let _ = self.pop(); // list
reader.set_pc(PrimOpPhase::FoldlStrictEmpty.ip() as usize);
return Step::Continue(());
}
let list_val = self.pop();
let nul_val = self.pop();
self.push(list_val);
self.push(Value::new_inline(0i32));
self.push(nul_val);
reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize);
Step::Continue(())
}
pub(crate) fn primop_foldl_strict_empty(
&mut self,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let nul = self.force_and_retry::<StrictValue>(reader, mc)?;
let _ = self.pop(); // op
self.return_from_primop(nul.relax(), reader)
}
pub(crate) fn primop_foldl_strict_call1(
&mut self,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
self.force_slot(3, reader, mc)?;
let op = self.peek_forced(3);
let acc = self.peek(0);
self.push(op.relax());
self.call(reader, mc, acc, PrimOpPhase::FoldlStrictCall2.ip() as usize)
}
pub(crate) fn primop_foldl_strict_call2(
&mut self,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
#[allow(clippy::unwrap_used)]
let idx = self.peek(2).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = self.peek_forced(3).as_gc::<List>().unwrap();
let elem = list.inner.borrow()[idx as usize];
self.call(
reader,
mc,
elem,
PrimOpPhase::FoldlStrictUpdate.ip() as usize,
)
}
pub(crate) fn primop_foldl_strict_update(
&mut self,
reader: &mut BytecodeReader<'_>,
_mc: &Mutation<'gc>,
) -> Step {
let result = self.pop();
self.replace(0, result);
#[allow(clippy::unwrap_used)]
let idx = self.peek(1).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = self.peek_forced(2).as_gc::<List>().unwrap();
let len = list.inner.borrow().len();
if (idx as usize) + 1 == len {
let acc = self.pop();
let _ = self.pop(); // idx
let _ = self.pop(); // list
let _ = self.pop(); // op
return self.return_from_primop(acc, reader);
}
self.replace(1, Value::new_inline(idx + 1));
reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize);
Step::Continue(())
}
}
+6
View File
@@ -41,6 +41,12 @@ impl<'gc> Vm<'gc> {
FilterCallPred => self.primop_filter_call_pred(reader, mc),
FilterCheck => self.primop_filter_check(reader, mc),
FoldlStrict => self.primop_foldl_strict_entry(reader, mc),
FoldlStrictEmpty => self.primop_foldl_strict_empty(reader, mc),
FoldlStrictCall1 => self.primop_foldl_strict_call1(reader, mc),
FoldlStrictCall2 => self.primop_foldl_strict_call2(reader, mc),
FoldlStrictUpdate => self.primop_foldl_strict_update(reader, mc),
ForceResultShallow => self.primop_force_result_shallow(ctx, reader, mc),
ForceResultShallowPush => self.primop_force_result_shallow_push(ctx, reader, mc),
ForceResultShallowLoop => self.primop_force_result_shallow_loop(reader, mc),