implement any & all
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user