implement any & all
This commit is contained in:
@@ -130,8 +130,15 @@ pub enum PrimOpPhase {
|
||||
Abort,
|
||||
Add,
|
||||
AddErrorContext,
|
||||
|
||||
All,
|
||||
AllCallPred,
|
||||
AllCheck,
|
||||
|
||||
Any,
|
||||
AnyCallPred,
|
||||
AnyCheck,
|
||||
|
||||
AppendContext,
|
||||
AttrNames,
|
||||
AttrValues,
|
||||
|
||||
@@ -33,6 +33,14 @@ pub fn dispatch_primop<'gc, M: Machine<'gc>>(
|
||||
match phase {
|
||||
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),
|
||||
DeepSeqPush => deep_seq_push(m, reader, mc),
|
||||
DeepSeqLoop => deep_seq_loop(m, reader, mc),
|
||||
|
||||
@@ -16,6 +16,7 @@ pub fn filter_force_list<'gc, M: Machine<'gc>>(
|
||||
};
|
||||
if list.inner.borrow().is_empty() {
|
||||
let val = m.pop();
|
||||
let _pred = m.pop();
|
||||
return m.return_from_primop(val, reader);
|
||||
}
|
||||
// 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);
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -258,13 +258,13 @@ impl<'gc> crate::Vm<'gc> {
|
||||
return Ok(());
|
||||
}
|
||||
// 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> {
|
||||
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>() {
|
||||
Some(NixNum::Int(*gc_i))
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user