implement any & all

This commit is contained in:
2026-05-18 18:24:32 +08:00
parent b420a950a3
commit 9412c319f9
4 changed files with 136 additions and 2 deletions
+7
View File
@@ -130,8 +130,15 @@ pub enum PrimOpPhase {
Abort, Abort,
Add, Add,
AddErrorContext, AddErrorContext,
All, All,
AllCallPred,
AllCheck,
Any, Any,
AnyCallPred,
AnyCheck,
AppendContext, AppendContext,
AttrNames, AttrNames,
AttrValues, AttrValues,
+8
View File
@@ -33,6 +33,14 @@ pub fn dispatch_primop<'gc, M: Machine<'gc>>(
match phase { match phase {
Abort => abort(m, ctx, reader, mc), Abort => abort(m, ctx, reader, mc),
All => all_entry(m, reader, mc),
AllCallPred => all_call_pred(m, reader, mc),
AllCheck => all_check(m, reader, mc),
Any => any_entry(m, reader, mc),
AnyCallPred => any_call_pred(m, reader, mc),
AnyCheck => any_check(m, reader, mc),
DeepSeq => deep_seq_force_top(m, reader, mc), DeepSeq => deep_seq_force_top(m, reader, mc),
DeepSeqPush => deep_seq_push(m, reader, mc), DeepSeqPush => deep_seq_push(m, reader, mc),
DeepSeqLoop => deep_seq_loop(m, reader, mc), DeepSeqLoop => deep_seq_loop(m, reader, mc),
+119
View File
@@ -16,6 +16,7 @@ pub fn filter_force_list<'gc, M: Machine<'gc>>(
}; };
if list.inner.borrow().is_empty() { if list.inner.borrow().is_empty() {
let val = m.pop(); let val = m.pop();
let _pred = m.pop();
return m.return_from_primop(val, reader); return m.return_from_primop(val, reader);
} }
// prepare stack layout: [ pred list idx acc ] // prepare stack layout: [ pred list idx acc ]
@@ -164,3 +165,121 @@ pub fn foldl_strict_update<'gc, M: Machine<'gc>>(
reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize); reader.set_pc(PrimOpPhase::FoldlStrictCall1.ip() as usize);
Step::Continue(()) Step::Continue(())
} }
pub fn all_entry<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
m.force_slot(0, reader, mc)?;
let list = match m.peek_forced(0).expect_gc::<List>() {
Ok(list) => list,
Err(got) => return m.finish_type_err(NixType::List, got),
};
// FIXME: force callable
m.force_slot(1, reader, mc)?;
if list.inner.borrow().is_empty() {
let _list = m.pop();
let _pred = m.pop();
return m.return_from_primop(Value::new_inline(true), reader);
}
// prepare stack layout: [ pred list idx ]
m.push(Value::new_inline(0));
reader.set_pc(PrimOpPhase::AllCallPred.ip() as usize);
Step::Continue(())
}
pub fn all_call_pred<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let pred = m.peek_forced(2);
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let elem = m.peek_forced(1).as_gc::<List>().unwrap().inner.borrow()[idx as usize];
m.push(pred.relax());
m.call(reader, mc, elem, PrimOpPhase::AllCheck.ip() as usize)
}
pub fn all_check<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let ret = m.force_and_retry::<bool>(reader, mc)?;
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(1).as_gc::<List>().unwrap();
let list = list.inner.borrow();
if idx as usize == list.len() - 1 || !ret {
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // pred
return m.return_from_primop(Value::new_inline(ret), reader);
}
m.replace(0, Value::new_inline(idx + 1));
reader.set_pc(PrimOpPhase::AllCallPred.ip() as usize);
Step::Continue(())
}
pub fn any_entry<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
m.force_slot(0, reader, mc)?;
let list = match m.peek_forced(0).expect_gc::<List>() {
Ok(list) => list,
Err(got) => return m.finish_type_err(NixType::List, got),
};
// FIXME: force callable
m.force_slot(1, reader, mc)?;
if list.inner.borrow().is_empty() {
let _list = m.pop();
let _pred = m.pop();
return m.return_from_primop(Value::new_inline(false), reader);
}
// prepare stack layout: [ pred list idx ]
m.push(Value::new_inline(0));
reader.set_pc(PrimOpPhase::AnyCallPred.ip() as usize);
Step::Continue(())
}
pub fn any_call_pred<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let pred = m.peek_forced(2);
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let elem = m.peek_forced(1).as_gc::<List>().unwrap().inner.borrow()[idx as usize];
m.push(pred.relax());
m.call(reader, mc, elem, PrimOpPhase::AnyCheck.ip() as usize)
}
pub fn any_check<'gc, M: Machine<'gc>>(
m: &mut M,
reader: &mut BytecodeReader<'_>,
mc: &Mutation<'gc>,
) -> Step {
let ret = m.force_and_retry::<bool>(reader, mc)?;
#[allow(clippy::unwrap_used)]
let idx = m.peek(0).as_inline::<i32>().unwrap();
#[allow(clippy::unwrap_used)]
let list = m.peek_forced(1).as_gc::<List>().unwrap();
let list = list.inner.borrow();
if idx as usize == list.len() - 1 || ret {
let _ = m.pop(); // idx
let _ = m.pop(); // list
let _ = m.pop(); // pred
return m.return_from_primop(Value::new_inline(ret), reader);
}
m.replace(0, Value::new_inline(idx + 1));
reader.set_pc(PrimOpPhase::AnyCallPred.ip() as usize);
Step::Continue(())
}
+2 -2
View File
@@ -258,13 +258,13 @@ impl<'gc> crate::Vm<'gc> {
return Ok(()); return Ok(());
} }
// TODO: compare other types // TODO: compare other types
Err(crate::vm_err("cannot compare these types")) Err(crate::vm_err(format!("cannot compare {} with {}", lhs.ty(), rhs.ty())))
} }
} }
pub(crate) fn get_num(val: StrictValue<'_>) -> Option<NixNum> { pub(crate) fn get_num(val: StrictValue<'_>) -> Option<NixNum> {
if let Some(i) = val.as_inline::<i32>() { if let Some(i) = val.as_inline::<i32>() {
Some(NixNum::Int(i as i64)) Some(NixNum::Int(i64::from(i)))
} else if let Some(gc_i) = val.as_gc::<i64>() { } else if let Some(gc_i) = val.as_gc::<i64>() {
Some(NixNum::Int(*gc_i)) Some(NixNum::Int(*gc_i))
} else { } else {