use crate::arena::*; use crate::atom_table::*; use crate::functor_macro::*; use crate::instructions::*; use crate::machine::arithmetic_ops::*; use crate::machine::machine_errors::*; use crate::machine::machine_state::*; use crate::machine::*; use crate::types::*; use fxhash::FxBuildHasher; macro_rules! step_or_fail { ($self:expr, $step_e:expr) => { if $self.fail { $self.backtrack(); } else { $step_e; } }; } macro_rules! try_or_throw { ($s:expr, $e:expr, $control:expr) => {{ match $e { Ok(val) => val, Err(msg) => { if !msg.is_empty() { $s.throw_exception(msg); } $s.backtrack(); $control; } } }}; } macro_rules! backtrack_on_resource_error { ($machine_st:expr, $val:expr, $control_expr:expr) => { step_or_resource_error!($machine_st, $val, { $machine_st.backtrack(); $control_expr; }) }; } macro_rules! increment_call_count { ($s:expr) => {{ if !$s.increment_call_count() { $s.backtrack(); continue; } }}; } macro_rules! try_or_throw_gen { ($s:expr, $e:expr) => {{ match $e { Ok(val) => val, Err(msg_fn) => { let e = msg_fn($s); $s.throw_exception(e); $s.backtrack(); return; } } }}; } macro_rules! push_cell { ($machine_st:expr, $cell:expr, $control_expr:expr) => {{ step_or_resource_error!($machine_st, $machine_st.heap.push_cell($cell), { $machine_st.backtrack(); $control_expr; }) }}; } impl MachineState { #[inline(always)] fn compare(&mut self) -> CallResult { let stub_gen = || functor_stub(atom!("compare"), 3); let a1 = self.store(self.deref(self.registers[1])); let a2 = self.registers[2]; let a3 = self.registers[3]; let check_atom = |machine_st: &mut MachineState, name: Atom, arity: usize| -> Result<(), MachineStub> { match name { atom!(">") | atom!("<") | atom!("=") if arity == 0 => Ok(()), _ => { let err = machine_st.domain_error(DomainErrorType::Order, a1); Err(machine_st.error_form(err, stub_gen())) } } }; read_heap_cell!(a1, (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); check_atom(self, name, arity)?; } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); check_atom(self, name, arity)?; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { } _ => { let err = self.type_error(ValidType::Atom, a1); return Err(self.error_form(err, stub_gen())); } ); let atom = match self.compare_term_test(a2, a3) { Some(Ordering::Greater) => { atom!(">") } Some(Ordering::Equal) => { atom!("=") } None | Some(Ordering::Less) => { atom!("<") } }; self.unify_atom(atom, a1); Ok(()) } pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { let old_h = self.heap.cell_len(); let a1 = self.registers[1]; let a2 = self.registers[2]; step_or_resource_error!(self, copy_term(CopyTerm::new(self), a1, attr_var_policy)); unify_fn!(*self, heap_loc_as_cell!(old_h), a2); } fn sort(&mut self) -> CallResult { self.check_sort_errors()?; let stub_gen = || functor_stub(atom!("sort"), 2); let mut list = self.try_from_list(self.registers[1], stub_gen)?; list.sort_unstable_by(|v1, v2| self.compare_term_test(*v1, *v2).unwrap_or(Ordering::Less)); list.dedup_by(|v1, v2| self.compare_term_test(*v1, *v2) == Some(Ordering::Equal)); let heap_addr = resource_error_call_result!( self, sized_iter_to_heap_list(&mut self.heap, list.len(), list.into_iter()) ); let target_addr = self.registers[2]; unify_fn!(*self, target_addr, heap_addr); Ok(()) } fn keysort(&mut self) -> CallResult { self.check_keysort_errors()?; let stub_gen = || functor_stub(atom!("keysort"), 2); let list = self.try_from_list(self.registers[1], stub_gen)?; let mut key_pairs = Vec::with_capacity(list.len()); for val in list { let (key, _) = self.key_val_pair(val)?; key_pairs.push((key, val)); } key_pairs.sort_by(|a1, a2| self.compare_term_test(a1.0, a2.0).unwrap_or(Ordering::Less)); let heap_addr = resource_error_call_result!( self, sized_iter_to_heap_list( &mut self.heap, key_pairs.len(), key_pairs.into_iter().map(|kp| kp.1), ) ); let target_addr = self.registers[2]; unify_fn!(*self, target_addr, heap_addr); Ok(()) } fn is(&mut self, r: RegType, at: ArithmeticTerm) -> CallResult { let n1 = self.store(self.deref(self[r])); match self.get_number(&at)? { Number::Fixnum(n) => self.unify_fixnum(n, n1), Number::Float(n) => { let n = float_alloc!(n.into_inner(), self.arena); self.unify_f64(n, n1) } Number::Integer(n) => self.unify_big_int(n, n1), Number::Rational(n) => self.unify_rational(n, n1), } Ok(()) } #[inline(always)] pub(crate) fn select_switch_on_term_index( &self, addr: HeapCellValue, v: IndexingCodePtr, c: IndexingCodePtr, l: IndexingCodePtr, s: IndexingCodePtr, ) -> IndexingCodePtr { read_heap_cell!(addr, (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => { v } (HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis) => { l } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint | HeapCellValueTag::F64Offset) => { c } (HeapCellValueTag::Atom, (_name, arity)) => { debug_assert!(arity == 0); c } (HeapCellValueTag::Str, st) => { let (name, arity) = cell_as_atom_cell!(self.heap[st]) .get_name_and_arity(); match (name, arity) { (atom!("."), 2) => l, (_, 0) => c, _ => s, } } (HeapCellValueTag::Cons, ptr) => { match ptr.get_tag() { ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => { c } _ => { IndexingCodePtr::Fail } } } _ => { unreachable!(); } ) } #[inline(always)] pub(crate) fn select_switch_on_structure_index( &self, addr: HeapCellValue, hm: &IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>, ) -> IndexingCodePtr { read_heap_cell!(addr, (HeapCellValueTag::Atom, (name, arity)) => { match hm.get(&(name, arity)) { Some(offset) => *offset, None => IndexingCodePtr::Fail, } } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); match hm.get(&(name, arity)) { Some(offset) => *offset, None => IndexingCodePtr::Fail, } } _ => { IndexingCodePtr::Fail } ) } fn check_for_interrupt(&mut self) { let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); match INTERRUPT.compare_exchange( interrupted, false, std::sync::atomic::Ordering::Relaxed, std::sync::atomic::Ordering::Relaxed, ) { Ok(interruption) => { if interruption { self.throw_interrupt_exception(); self.backtrack(); // We have extracted control over the Tokio runtime to the calling context for enabling library use case // (see https://github.com/mthom/scryer-prolog/pull/1880) // So we only have access to a runtime handle in here and can't shut it down. // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 // was not merged, I'm only deactivating it for now. //#[cfg(not(target_arch = "wasm32"))] //let runtime = tokio::runtime::Runtime::new().unwrap(); //#[cfg(target_arch = "wasm32")] //let runtime = tokio::runtime::Builder::new_current_thread() // .enable_all() // .build() // .unwrap(); //let old_runtime = tokio::runtime::Handle::current(); //old_runtime.shutdown_background(); } } Err(_) => unreachable!(), } } #[inline(always)] fn add_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let stub_gen = || functor_stub(atom!("is"), 2); let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!( self, try_numeric_result!(add(n1, n2, &mut self.arena), stub_gen) ); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn sub_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let stub_gen = || functor_stub(atom!("is"), 2); let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!( self, try_numeric_result!(sub(n1, n2, &mut self.arena), stub_gen) ); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn mul_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let stub_gen = || functor_stub(atom!("is"), 2); let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!( self, try_numeric_result!(mul(n1, n2, &mut self.arena), stub_gen) ); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn max_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, max(n1, n2)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn min_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, min(n1, n2)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn int_pow_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, int_pow(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn gcd_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, gcd(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn pow_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, pow(n1, n2, atom!("**"))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn rdiv_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let stub_gen = || functor_stub(atom!("(rdiv)"), 2); let r1 = try_or_throw!(self, self.get_rational(a1, stub_gen), return); let r2 = try_or_throw!(self, self.get_rational(a2, stub_gen), return); let value = Number::Rational(arena_alloc!( try_or_throw_gen!(self, rdiv(r1, r2)), &mut self.arena )); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn int_floor_div_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, int_floor_div(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn idiv_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, idiv(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn abs_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = abs(n1, &mut self.arena); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn sign_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n = try_or_throw!(self, self.get_number(a1), return); let value = n.sign(); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn neg_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = neg(n1, &mut self.arena); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn bitwise_complement_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = try_or_throw_gen!(self, bitwise_complement(n1, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn div_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, div(n1, n2)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn shr_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, shr(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn shl_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, shl(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn xor_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, xor(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn and_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, and(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn or_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, or(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn mod_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, modulus(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn rem_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = try_or_throw_gen!(self, remainder(n1, n2, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn cos_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, cos(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn sin_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, sin(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn tan_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, tan(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn sqrt_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, sqrt(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn log_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, log(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn exp_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, exp(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn acos_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, acos(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn asin_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, asin(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn atan_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, atan(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn atan2_instr(&mut self, a1: &ArithmeticTerm, a2: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let n2 = try_or_throw!(self, self.get_number(a2), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, atan2(n1, n2)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn float_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!(self, float(n1)))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn truncate_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = truncate(n1, &mut self.arena); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn round_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = try_or_throw_gen!(self, round(n1, &mut self.arena)); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn ceiling_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = ceiling(n1, &mut self.arena); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn floor_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = floor(n1, &mut self.arena); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn float_fractional_part_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!( self, float_fractional_part(n1) ))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn float_integer_part_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); let value = Number::Float(OrderedFloat(try_or_throw_gen!( self, float_integer_part(n1) ))); self.registers[t] = HeapCellValue::from((value, &mut self.arena)); self.p += 1; } #[inline(always)] fn plus_instr(&mut self, a1: &ArithmeticTerm, t: usize) { let n1 = try_or_throw!(self, self.get_number(a1), return); self.registers[t] = HeapCellValue::from((n1, &mut self.arena)); self.p += 1; } #[inline(always)] fn get_level_instr(&mut self, r: RegType) { let b0 = self.b0; self[r] = fixnum_as_cell!( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(b0 as i64) }.as_cutpoint() ); self.p += 1; } #[inline(always)] fn get_prev_level_instr(&mut self, r: RegType) { let prev_b = self.stack.index_or_frame(self.b).prelude.b; self[r] = fixnum_as_cell!( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(prev_b as i64) }.as_cutpoint() ); self.p += 1; } #[inline(always)] fn get_cut_point_instr(&mut self, r: RegType) { self[r] = fixnum_as_cell!( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(self.b as i64) }.as_cutpoint() ); self.p += 1; } #[inline(always)] fn get_constant_instr(&mut self, c: HeapCellValue, r: RegType) { unify!(self, self[r], c); step_or_fail!(self, self.p += 1); } #[inline(always)] fn get_list_instr(&mut self, r: RegType) { let deref_v = self.deref(self[r]); let store_v = self.store(deref_v); read_heap_cell!(store_v, (HeapCellValueTag::PStrLoc, h) => { self.s = HeapPtr::PStr(h); self.s_offset = 0; self.mode = MachineMode::Read; } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) .get_name_and_arity(); if name == atom!(".") && arity == 2 { self.s = HeapPtr::HeapCell(s+1); self.s_offset = 0; self.mode = MachineMode::Read; } else { self.backtrack(); return; } } (HeapCellValueTag::Lis, l) => { self.s = HeapPtr::HeapCell(l); self.s_offset = 0; self.mode = MachineMode::Read; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { let h = self.heap.cell_len(); push_cell!(self, list_loc_as_cell!(h+1), return); self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.mode = MachineMode::Write; } _ => { self.backtrack(); return; } ); self.p += 1; } #[inline(always)] fn get_partial_string_instr(&mut self, string: &str, r: RegType) { self.heap[0] = self[r]; let mut h = 0; let mut string_cursor = string; if self.heap[0].is_stack_var() { let cell = self.store(self.deref(self.heap[0])); if let Some(r) = cell.as_var() { let target_cell = backtrack_on_resource_error!( self, self.heap.allocate_pstr(string_cursor), return ); self.bind(r, target_cell); self.mode = MachineMode::Write; debug_assert!(!self.fail); self.p += 1; return; } self.heap[0] = cell; } while let Some(c) = string_cursor.chars().next() { read_heap_cell!(self.heap[h], (HeapCellValueTag::PStrLoc, pstr_loc) => { let heap_slice = &self.heap.as_slice()[pstr_loc ..]; match compare_pstr_slices(heap_slice, string_cursor.as_bytes()) { PStrSegmentCmpResult::Continue(v1, v2) => { // for v2, the value of a TailIndex mustn't ever be read // since string does not lie in the heap. match (v1, v2) { (PStrContinuable::TailIndex(tail_idx), PStrContinuable::TailIndex(_)) => { self.s = HeapPtr::HeapCell(tail_idx + cell_index!(pstr_loc)); self.s_offset = 0; self.mode = MachineMode::Read; break; } (PStrContinuable::TailIndex(tail_idx), PStrContinuable::PStrOffset(pos)) => { h = tail_idx + cell_index!(pstr_loc); string_cursor = &string_cursor[pos ..]; } (PStrContinuable::PStrOffset(pos), PStrContinuable::TailIndex(_)) => { self.s = HeapPtr::PStr(pstr_loc); self.s_offset = pos; self.mode = MachineMode::Read; break; } _ => unreachable!(), } } _ => { self.fail = true; break; } } } (HeapCellValueTag::Lis, l) => { let cell = self.store(self.deref(self.heap[l])); if let Some(d) = cell.as_char() { if c != d { self.fail = true; break; } } else if let Some(r) = cell.as_var() { self.bind(r, char_as_cell!(c)); } else { self.fail = true; } if self.fail { break; } else { h = l+1; string_cursor = &string_cursor[c.len_utf8() ..]; if string_cursor.is_empty() { self.s = HeapPtr::HeapCell(h); self.s_offset = 0; self.mode = MachineMode::Read; } } } (HeapCellValueTag::Str, s) => { let cell = self.store(self.deref(self.heap[s+1])); if let Some(d) = cell.as_char() { if c != d { self.fail = true; break; } } else if let Some(r) = cell.as_var() { self.bind(r, char_as_cell!(c)); } else { self.fail = true; break; } h = s+2; string_cursor = &string_cursor[c.len_utf8() ..]; if string_cursor.is_empty() { self.s = HeapPtr::HeapCell(h); self.s_offset = 0; self.mode = MachineMode::Read; } } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, v) => { if h == v { let target_cell = backtrack_on_resource_error!( self, self.heap.allocate_pstr(string_cursor), return ); self.bind( self.heap[h].as_var().unwrap(), target_cell, ); self.mode = MachineMode::Write; break; } else { h = v; } } _ => { self.fail = true; break; } ); } step_or_fail!(self, self.p += 1); } #[inline(always)] fn get_structure_instr(&mut self, name: Atom, arity: usize, r: RegType) { let deref_v = self.deref(self[r]); let store_v = self.store(deref_v); read_heap_cell!(store_v, (HeapCellValueTag::Str, a) => { read_heap_cell!(self.heap[a], (HeapCellValueTag::Atom, (result_name, result_arity)) => { if arity == result_arity && name == result_name { self.s = HeapPtr::HeapCell(a + 1); self.s_offset = 0; self.mode = MachineMode::Read; } else { self.backtrack(); return; } } _ => { unreachable!(); } ); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { let h = self.heap.cell_len(); push_cell!(self, str_loc_as_cell!(h+1), return); push_cell!(self, atom_as_cell!(name, arity), return); self.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.mode = MachineMode::Write; } _ => { self.backtrack(); return; } ); self.p += 1; } #[inline(always)] fn get_variable_instr(&mut self, norm: RegType, arg: usize) { self[norm] = self.registers[arg]; self.p += 1; } #[inline(always)] fn get_value_instr(&mut self, norm: RegType, arg: usize) { let norm_addr = self[norm]; let reg_addr = self.registers[arg]; unify_fn!(&mut *self, norm_addr, reg_addr); if self.fail { self.backtrack(); return; } self.p += 1; } #[inline(always)] fn unify_constant_instr(&mut self, v: HeapCellValue) { match self.mode { MachineMode::Read => { let (addr, s_offset_incr) = self.read_s(); unify!(self, addr, v); if self.fail { self.backtrack(); return; } else { self.s_offset += s_offset_incr; } } MachineMode::Write => { push_cell!(self, v, return); } } self.p += 1; } #[inline(always)] fn unify_local_value_instr(&mut self, r: RegType) { match self.mode { MachineMode::Read => { let reg_addr = self[r]; let (value, s_offset_incr) = self.read_s(); unify_fn!(&mut *self, reg_addr, value); if self.fail { self.backtrack(); return; } else { self.s_offset += s_offset_incr; } } MachineMode::Write => { let value = self.store(self.deref(self[r])); let h = self.heap.cell_len(); read_heap_cell!(value, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { let value = self.heap[hc]; push_cell!(self, value, return); self.s_offset += 1; } _ => { push_cell!(self, heap_loc_as_cell!(h), return); self.occurs_check.bind(self, Ref::heap_cell(h), value); } ); } } self.p += 1; } #[inline(always)] fn unify_variable_instr(&mut self, r: RegType) { match self.mode { MachineMode::Read => { let (value, s_offset_incr) = self.read_s(); self[r] = value; self.s_offset += s_offset_incr; } MachineMode::Write => { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); self[r] = heap_loc_as_cell!(h); } } self.p += 1; } #[inline(always)] fn unify_value_instr(&mut self, r: RegType) { match self.mode { MachineMode::Read => { let reg_addr = self[r]; let (value, s_offset_incr) = self.read_s(); unify_fn!(&mut *self, reg_addr, value); if self.fail { self.backtrack(); return; } else { self.s_offset += s_offset_incr; } } MachineMode::Write => { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); let addr = self.store(self[r]); self.occurs_check.bind(self, Ref::heap_cell(h), addr); // the former code of this match arm was: // let addr = self.store(self[reg]); // push_cell!(self, HeapCellValue::Addr(addr)); // the old code didn't perform the occurs // check when enabled and so it was changed to // the above, which is only slightly less // efficient when the occurs_check is disabled. } } self.p += 1; } #[inline(always)] fn unify_void_instr(&mut self, n: usize) { match self.mode { MachineMode::Read => match &self.s { HeapPtr::HeapCell(_) => self.s_offset += n, &HeapPtr::PStr(pstr_loc) => { debug_assert!(n <= 2); let mut char_iter = self.heap.char_iter(pstr_loc); // this only matters in the case that n == 1, but the case // analysis isn't worth doing since the effect is benign if n == // 2 self.s_offset += char_iter.next().unwrap().len_utf8(); } }, MachineMode::Write => { let h = self.heap.cell_len(); for i in h..h + n { push_cell!(self, heap_loc_as_cell!(i), return); } } } self.p += 1; } #[inline(always)] fn put_constant_instr(&mut self, cell: HeapCellValue, r: RegType) { self[r] = cell; self.p += 1; } #[inline(always)] fn put_list_instr(&mut self, r: RegType) { self[r] = list_loc_as_cell!(self.heap.cell_len()); self.p += 1; } #[inline(always)] fn put_partial_string_instr(&mut self, string: &str, r: RegType) { self[r] = backtrack_on_resource_error!(self, self.heap.allocate_pstr(string), return); self.p += 1; } #[inline(always)] fn put_structure_instr(&mut self, name: Atom, arity: usize, r: RegType) { let h = self.heap.cell_len(); push_cell!(self, atom_as_cell!(name, arity), return); self[r] = str_loc_as_cell!(h); self.p += 1; } #[inline(always)] fn put_unsafe_value_instr(&mut self, perm_slot: usize, arg: usize) { let s = stack_loc!(AndFrame, self.e, perm_slot); let addr = self.store(self.deref(stack_loc_as_cell!(s))); if addr.is_protected(self.e) { self.registers[arg] = addr; } else { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); self.occurs_check.bind(self, Ref::heap_cell(h), addr); self.registers[arg] = heap_loc_as_cell!(h); } self.p += 1; } #[inline(always)] fn put_value_instr(&mut self, norm: RegType, arg: usize) { self.registers[arg] = self[norm]; self.p += 1; } #[inline(always)] fn put_variable_instr(&mut self, norm: RegType, arg: usize) { match norm { RegType::Perm(n) => { self[norm] = stack_loc_as_cell!(AndFrame, self.e, n); self.registers[arg] = self[norm]; } RegType::Temp(_) => { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); self[norm] = heap_loc_as_cell!(h); self.registers[arg] = heap_loc_as_cell!(h); } } self.p += 1; } #[inline(always)] fn set_constant_instr(&mut self, c: HeapCellValue) { push_cell!(self, c, return); self.p += 1; } #[inline(always)] fn set_local_value_instr(&mut self, r: RegType) { let addr = self.deref(self[r]); let stored_v = self.store(addr); if stored_v.is_stack_var() { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); self.occurs_check.bind(self, Ref::heap_cell(h), stored_v); } else { push_cell!(self, stored_v, return); } self.p += 1; } #[inline(always)] fn set_variable_instr(&mut self, r: RegType) { let h = self.heap.cell_len(); push_cell!(self, heap_loc_as_cell!(h), return); self[r] = heap_loc_as_cell!(h); self.p += 1; } #[inline(always)] fn set_value_instr(&mut self, r: RegType) { let heap_val = self.store(self[r]); push_cell!(self, heap_val, return); self.p += 1; } #[inline(always)] fn set_void_instr(&mut self, n: usize) { let h = self.heap.cell_len(); for i in h..h + n { push_cell!(self, heap_loc_as_cell!(i), return); } self.p += 1; } } impl Machine { pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> { loop { match self.code[p] { Instruction::DynamicElse(birth, death, NextOrFail::Next(i)) => { if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; } else { return None; } } Instruction::DynamicElse(birth, death, NextOrFail::Fail(_)) => { if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, 0)); } else { return None; } } Instruction::DynamicInternalElse(birth, death, NextOrFail::Next(i)) => { if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, i)); } else if i > 0 { p += i; } else { return None; } } Instruction::DynamicInternalElse(birth, death, NextOrFail::Fail(_)) => { if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((p, 0)); } else { return None; } } Instruction::RevJmpBy(i) => { p -= i; } _ => { unreachable!(); } } } } pub(super) fn find_living_dynamic( &self, oi: u32, mut ii: u32, ) -> Option<(usize, u32, u32, bool)> { let p = self.machine_st.p; let indexed_choice_instrs = match &self.code[p] { Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] { IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => { indexed_choice_instrs } _ => unreachable!(), }, _ => unreachable!(), }; loop { match &indexed_choice_instrs.get(ii as usize) { Some(&offset) => match &self.code[p + offset - 1] { &Instruction::DynamicInternalElse(birth, death, next_or_fail) => { if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death { return Some((offset, oi, ii, next_or_fail.is_next())); } else { ii += 1; } } _ => unreachable!(), }, None => return None, } } } #[inline(always)] fn execute_switch_on_term(&mut self) { #[inline(always)] fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool { if let Instruction::DynamicInternalElse(..) = machine.code[p] { machine.machine_st.dynamic_mode = FirstOrNext::First; return true; } if let Instruction::DynamicInternalElse(birth, death, _) = machine.code[p - 1] { return birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death; } true } let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap(); let mut index = 0; let addr = match &indexing_lines[0] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => self .machine_st .store(self.machine_st.deref(self.machine_st.registers[arg])), _ => { unreachable!() } }; loop { match &indexing_lines[index] { &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { let offset = self .machine_st .select_switch_on_term_index(addr, v, c, l, s); match offset { IndexingCodePtr::Fail => { self.machine_st.fail = true; break; } IndexingCodePtr::DynamicExternal(o) => { // either points directly to a // DynamicInternalElse, or just ahead of // one. Or neither! let p = self.machine_st.p; if !dynamic_external_of_clause_is_valid(self, p + o) { self.machine_st.fail = true; } else { self.machine_st.p += o; } break; } IndexingCodePtr::External(o) => { self.machine_st.p += o; break; } IndexingCodePtr::Internal(o) => { index += o; } } } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { // let lit = self.machine_st.constant_to_literal(addr); let offset = match hm.get(&addr) { Some(offset) => *offset, _ => IndexingCodePtr::Fail, }; match offset { IndexingCodePtr::Fail => { self.machine_st.fail = true; break; } IndexingCodePtr::DynamicExternal(o) => { // either points directly to a // DynamicInternalElse, or just ahead of // one. Or neither! let p = self.machine_st.p; if !dynamic_external_of_clause_is_valid(self, p + o) { self.machine_st.fail = true; } else { self.machine_st.p += o; } break; } IndexingCodePtr::External(o) => { self.machine_st.p += o; break; } IndexingCodePtr::Internal(o) => { index += o; } } } IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => { let offset = self.machine_st.select_switch_on_structure_index(addr, hm); match offset { IndexingCodePtr::Fail => { self.machine_st.fail = true; break; } IndexingCodePtr::DynamicExternal(o) => { let p = self.machine_st.p; if !dynamic_external_of_clause_is_valid(self, p + o) { self.machine_st.fail = true; } else { self.machine_st.p += o; } break; } IndexingCodePtr::External(o) => { self.machine_st.p += o; break; } IndexingCodePtr::Internal(o) => { index += o; } } } &IndexingLine::IndexedChoice(_) => { self.machine_st.oip = index as u32; self.machine_st.iip = 0; break; } &IndexingLine::DynamicIndexedChoice(_) => { self.machine_st.dynamic_mode = FirstOrNext::First; self.machine_st.oip = index as u32; self.machine_st.iip = 0; break; } } } } fn verify_attr_dispatch_loop(&mut self) -> Option { let mut interrupt_counter = std::num::Wrapping(0u8); 'outer: loop { loop { interrupt_counter += 1; if interrupt_counter.0 == 0 { break; } match self.code[self.machine_st.p] { Instruction::BreakFromDispatchLoop => { break 'outer; } Instruction::GetLevel(r) => self.machine_st.get_level_instr(r), Instruction::GetPrevLevel(r) => self.machine_st.get_prev_level_instr(r), Instruction::GetCutPoint(r) => self.machine_st.get_cut_point_instr(r), Instruction::Deallocate => self.machine_st.deallocate(), Instruction::JmpByCall(offset) => { self.machine_st.p += offset; } Instruction::RevJmpBy(offset) => { self.machine_st.p -= offset; } Instruction::GetConstant(_, c, reg) => { self.machine_st.get_constant_instr(c, reg) } Instruction::GetList(_, reg) => self.machine_st.get_list_instr(reg), Instruction::GetPartialString(_, ref string, reg) => { self.machine_st.get_partial_string_instr(string, reg) } Instruction::GetStructure(_lvl, name, arity, reg) => { self.machine_st.get_structure_instr(name, arity, reg) } Instruction::GetVariable(norm, arg) => { self.machine_st.get_variable_instr(norm, arg) } Instruction::GetValue(norm, arg) => self.machine_st.get_value_instr(norm, arg), Instruction::UnifyConstant(v) => self.machine_st.unify_constant_instr(v), Instruction::UnifyLocalValue(reg) => { self.machine_st.unify_local_value_instr(reg) } Instruction::UnifyVariable(reg) => self.machine_st.unify_variable_instr(reg), Instruction::UnifyValue(reg) => self.machine_st.unify_value_instr(reg), Instruction::UnifyVoid(n) => self.machine_st.unify_void_instr(n), Instruction::PutConstant(_, cell, reg) => { self.machine_st.put_constant_instr(cell, reg) } Instruction::PutList(_, reg) => self.machine_st.put_list_instr(reg), Instruction::PutPartialString(_, ref string, reg) => { self.machine_st.put_partial_string_instr(string, reg) } Instruction::PutStructure(name, arity, reg) => { self.machine_st.put_structure_instr(name, arity, reg) } Instruction::PutUnsafeValue(perm_slot, arg) => { self.machine_st.put_unsafe_value_instr(perm_slot, arg) } Instruction::PutValue(norm, arg) => self.machine_st.put_value_instr(norm, arg), Instruction::PutVariable(norm, arg) => { self.machine_st.put_variable_instr(norm, arg) } Instruction::SetConstant(c) => self.machine_st.set_constant_instr(c), Instruction::SetLocalValue(reg) => self.machine_st.set_local_value_instr(reg), Instruction::SetVariable(reg) => self.machine_st.set_variable_instr(reg), Instruction::SetValue(reg) => self.machine_st.set_value_instr(reg), Instruction::SetVoid(n) => self.machine_st.set_void_instr(n), _ => return None, } } self.machine_st.check_for_interrupt(); } Some(std::process::ExitCode::SUCCESS) } pub(super) fn dispatch_loop(&mut self) -> std::process::ExitCode { let mut interrupt_counter = std::num::Wrapping(0u8); 'outer: loop { loop { interrupt_counter += 1; if interrupt_counter.0 == 0 { break; } let Some(inst) = self.code.get(self.machine_st.p) else { // a seperate function marked #[cold] to make the compiler/branch-predictor prefer the happy path handle_code_index_oob(self.code.len(), self.machine_st.p); }; match inst { &Instruction::BreakFromDispatchLoop => { break 'outer; } &Instruction::RunVerifyAttr => { self.machine_st.p = self.machine_st.attr_var_init.p; if self.code[self.machine_st.p].is_execute() { self.machine_st.p = self.machine_st.attr_var_init.cp; } else { self.machine_st.p += 1; self.machine_st.cp = self.machine_st.attr_var_init.cp; } if let Some(exit_code) = self.verify_attr_dispatch_loop() { return exit_code; } if matches!( self.code[self.machine_st.p], Instruction::RetryMeElse(_) | Instruction::TrustMe(_) | Instruction::DefaultRetryMeElse(_) | Instruction::DefaultTrustMe(_) | Instruction::DynamicElse(..) | Instruction::DynamicInternalElse(..) | Instruction::IndexingCode(_) ) { continue; } self.machine_st.attr_var_init.cp = self.machine_st.p; let (_, arity) = self.code[self.machine_st.p].to_name_and_arity(); self.run_verify_attr_interrupt(arity); } &Instruction::Add(ref a1, ref a2, t) => self.machine_st.add_instr(a1, a2, t), &Instruction::Sub(ref a1, ref a2, t) => self.machine_st.sub_instr(a1, a2, t), &Instruction::Mul(ref a1, ref a2, t) => self.machine_st.mul_instr(a1, a2, t), &Instruction::Max(ref a1, ref a2, t) => self.machine_st.max_instr(a1, a2, t), &Instruction::Min(ref a1, ref a2, t) => self.machine_st.min_instr(a1, a2, t), &Instruction::IntPow(ref a1, ref a2, t) => { self.machine_st.int_pow_instr(a1, a2, t) } &Instruction::Gcd(ref a1, ref a2, t) => self.machine_st.gcd_instr(a1, a2, t), &Instruction::Pow(ref a1, ref a2, t) => self.machine_st.pow_instr(a1, a2, t), &Instruction::RDiv(ref a1, ref a2, t) => self.machine_st.rdiv_instr(a1, a2, t), &Instruction::IntFloorDiv(ref a1, ref a2, t) => { self.machine_st.int_floor_div_instr(a1, a2, t) } &Instruction::IDiv(ref a1, ref a2, t) => self.machine_st.idiv_instr(a1, a2, t), &Instruction::Abs(ref a1, t) => self.machine_st.abs_instr(a1, t), &Instruction::Sign(ref a1, t) => self.machine_st.sign_instr(a1, t), &Instruction::Neg(ref a1, t) => self.machine_st.neg_instr(a1, t), &Instruction::BitwiseComplement(ref a1, t) => { self.machine_st.bitwise_complement_instr(a1, t) } &Instruction::Div(ref a1, ref a2, t) => self.machine_st.div_instr(a1, a2, t), &Instruction::Shr(ref a1, ref a2, t) => self.machine_st.shr_instr(a1, a2, t), &Instruction::Shl(ref a1, ref a2, t) => self.machine_st.shl_instr(a1, a2, t), &Instruction::Xor(ref a1, ref a2, t) => self.machine_st.xor_instr(a1, a2, t), &Instruction::And(ref a1, ref a2, t) => self.machine_st.and_instr(a1, a2, t), &Instruction::Or(ref a1, ref a2, t) => self.machine_st.or_instr(a1, a2, t), &Instruction::Mod(ref a1, ref a2, t) => self.machine_st.mod_instr(a1, a2, t), &Instruction::Rem(ref a1, ref a2, t) => self.machine_st.rem_instr(a1, a2, t), &Instruction::Cos(ref a1, t) => self.machine_st.cos_instr(a1, t), &Instruction::Sin(ref a1, t) => self.machine_st.sin_instr(a1, t), &Instruction::Tan(ref a1, t) => self.machine_st.tan_instr(a1, t), &Instruction::Sqrt(ref a1, t) => self.machine_st.sqrt_instr(a1, t), &Instruction::Log(ref a1, t) => self.machine_st.log_instr(a1, t), &Instruction::Exp(ref a1, t) => self.machine_st.exp_instr(a1, t), &Instruction::ACos(ref a1, t) => self.machine_st.acos_instr(a1, t), &Instruction::ASin(ref a1, t) => self.machine_st.asin_instr(a1, t), &Instruction::ATan(ref a1, t) => self.machine_st.atan_instr(a1, t), &Instruction::ATan2(ref a1, ref a2, t) => { self.machine_st.atan2_instr(a1, a2, t) } &Instruction::Float(ref a1, t) => self.machine_st.float_instr(a1, t), &Instruction::Truncate(ref a1, t) => self.machine_st.truncate_instr(a1, t), &Instruction::Round(ref a1, t) => self.machine_st.round_instr(a1, t), &Instruction::Ceiling(ref a1, t) => self.machine_st.ceiling_instr(a1, t), &Instruction::Floor(ref a1, t) => self.machine_st.floor_instr(a1, t), &Instruction::FloatFractionalPart(ref a1, t) => { self.machine_st.float_fractional_part_instr(a1, t) } &Instruction::FloatIntegerPart(ref a1, t) => { self.machine_st.float_integer_part_instr(a1, t) } &Instruction::Plus(ref a1, t) => self.machine_st.plus_instr(a1, t), &Instruction::GetLevel(r) => self.machine_st.get_level_instr(r), &Instruction::GetPrevLevel(r) => self.machine_st.get_prev_level_instr(r), &Instruction::GetCutPoint(r) => self.machine_st.get_cut_point_instr(r), &Instruction::Deallocate => self.machine_st.deallocate(), &Instruction::GetConstant(_, c, reg) => { self.machine_st.get_constant_instr(c, reg) } &Instruction::GetList(_, reg) => self.machine_st.get_list_instr(reg), &Instruction::GetPartialString(_, ref string, reg) => { self.machine_st.get_partial_string_instr(string, reg) } &Instruction::GetStructure(_lvl, name, arity, reg) => { self.machine_st.get_structure_instr(name, arity, reg) } &Instruction::GetVariable(norm, arg) => { self.machine_st.get_variable_instr(norm, arg) } &Instruction::GetValue(norm, arg) => self.machine_st.get_value_instr(norm, arg), &Instruction::UnifyConstant(v) => self.machine_st.unify_constant_instr(v), &Instruction::UnifyLocalValue(reg) => { self.machine_st.unify_local_value_instr(reg) } &Instruction::UnifyVariable(reg) => self.machine_st.unify_variable_instr(reg), &Instruction::UnifyValue(reg) => self.machine_st.unify_value_instr(reg), &Instruction::UnifyVoid(n) => self.machine_st.unify_void_instr(n), &Instruction::PutConstant(_, cell, reg) => { self.machine_st.put_constant_instr(cell, reg) } &Instruction::PutList(_, reg) => self.machine_st.put_list_instr(reg), &Instruction::PutPartialString(_, ref string, reg) => { self.machine_st.put_partial_string_instr(string, reg) } &Instruction::PutStructure(name, arity, reg) => { self.machine_st.put_structure_instr(name, arity, reg) } &Instruction::PutUnsafeValue(perm_slot, arg) => { self.machine_st.put_unsafe_value_instr(perm_slot, arg) } &Instruction::PutValue(norm, arg) => self.machine_st.put_value_instr(norm, arg), &Instruction::PutVariable(norm, arg) => { self.machine_st.put_variable_instr(norm, arg) } &Instruction::SetConstant(c) => self.machine_st.set_constant_instr(c), &Instruction::SetLocalValue(reg) => self.machine_st.set_local_value_instr(reg), &Instruction::SetVariable(reg) => self.machine_st.set_variable_instr(reg), &Instruction::SetValue(reg) => self.machine_st.set_value_instr(reg), &Instruction::SetVoid(n) => self.machine_st.set_void_instr(n), &Instruction::DynamicElse(..) => { if let FirstOrNext::First = self.machine_st.dynamic_mode { self.machine_st.cc = self.machine_st.global_clock; } let p = self.machine_st.p; match self.find_living_dynamic_else(p) { Some((p, next_i)) => { self.machine_st.p = p; self.machine_st.oip = 0; self.machine_st.iip = 0; match self.machine_st.dynamic_mode { FirstOrNext::First if next_i == 0 => { self.machine_st.p += 1; } FirstOrNext::First => { self.machine_st.cc = self.machine_st.global_clock; match self.find_living_dynamic_else(p + next_i) { Some(_) => { self.machine_st.registers [self.machine_st.num_of_args + 1] = fixnum_as_cell!(unsafe { /* FIXME this is not safe */ Fixnum::build_with_unchecked( self.machine_st.cc as i64, ) }); self.machine_st.num_of_args += 1; backtrack_on_resource_error!( self.machine_st, self.try_me_else(next_i), continue ); self.machine_st.num_of_args -= 1; } None => { self.machine_st.p += 1; } } } FirstOrNext::Next => { let n = self .machine_st .stack .index_or_frame(self.machine_st.b) .prelude .num_cells; self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, self.machine_st.b, n - 1)] .to_fixnum_or_cut_point_unchecked() } .get_num() as usize; if next_i > 0 { match self.find_living_dynamic_else(p + next_i) { Some(_) => { self.retry_me_else(next_i); } None => { self.trust_me(); } } } else { self.trust_me(); } increment_call_count!(self.machine_st); } } } None => { self.machine_st.fail = true; } } self.machine_st.dynamic_mode = FirstOrNext::Next; if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::DynamicInternalElse(..) => { let p = self.machine_st.p; match self.find_living_dynamic_else(p) { Some((p, next_i)) => { self.machine_st.p = p; self.machine_st.oip = 0; self.machine_st.iip = 0; match self.machine_st.dynamic_mode { FirstOrNext::First if next_i == 0 => { self.machine_st.p += 1; } FirstOrNext::First => { match self.find_living_dynamic_else(p + next_i) { Some(_) => { self.machine_st.registers [self.machine_st.num_of_args + 1] = fixnum_as_cell!( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked( self.machine_st.cc as i64, ) } ); self.machine_st.num_of_args += 1; backtrack_on_resource_error!( self.machine_st, self.try_me_else(next_i), continue ); self.machine_st.num_of_args -= 1; } None => { self.machine_st.p += 1; } } } FirstOrNext::Next => { let n = self .machine_st .stack .index_or_frame(self.machine_st.b) .prelude .num_cells; self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, self.machine_st.b, n - 1)] .to_fixnum_or_cut_point_unchecked() } .get_num() as usize; if next_i > 0 { match self.find_living_dynamic_else(p + next_i) { Some(_) => { self.retry_me_else(next_i); } None => { self.trust_me(); } } } else { self.trust_me(); } increment_call_count!(self.machine_st); } } } None => { self.machine_st.fail = true; } } self.machine_st.dynamic_mode = FirstOrNext::Next; if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::TryMeElse(offset) => { backtrack_on_resource_error!( self.machine_st, self.try_me_else(offset), continue ); } &Instruction::DefaultRetryMeElse(offset) => { self.retry_me_else(offset); } &Instruction::DefaultTrustMe(_) => { self.trust_me(); } &Instruction::RetryMeElse(offset) => { self.retry_me_else(offset); increment_call_count!(self.machine_st); } &Instruction::TrustMe(_) => { self.trust_me(); increment_call_count!(self.machine_st); } &Instruction::NeckCut => { self.machine_st.neck_cut(); self.machine_st.p += 1; } &Instruction::Cut(r) => { let value = self.machine_st[r]; self.machine_st.cut_body(value); if self.machine_st.fail { self.machine_st.backtrack(); continue; } if (self.machine_st.run_cleaners_fn)(self) { continue; } self.machine_st.p += 1; } &Instruction::CutPrev(r) => { let value = self.machine_st[r]; self.machine_st.cut_prev_body(value); if self.machine_st.fail { self.machine_st.backtrack(); continue; } if (self.machine_st.run_cleaners_fn)(self) { continue; } self.machine_st.p += 1; } &Instruction::Allocate(num_cells) => { backtrack_on_resource_error!( self.machine_st, self.machine_st.allocate(num_cells), continue ); } &Instruction::DefaultCallAcyclicTerm => { let addr = self.deref_register(1); if addr.is_ref() { self.machine_st.heap[0] = addr; if self.machine_st.is_cyclic_term(0) { self.machine_st.backtrack(); continue; } } self.machine_st.p += 1; } &Instruction::DefaultExecuteAcyclicTerm => { let addr = self.deref_register(1); if addr.is_ref() { self.machine_st.heap[0] = addr; if self.machine_st.is_cyclic_term(0) { self.machine_st.backtrack(); continue; } } self.machine_st.p = self.machine_st.cp; } &Instruction::DefaultCallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::DefaultCallCompare => { try_or_throw!(self.machine_st, self.machine_st.compare(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteCompare => { try_or_throw!(self.machine_st, self.machine_st.compare(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::DefaultCallTermGreaterThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } &Instruction::DefaultExecuteTermGreaterThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } &Instruction::DefaultCallTermLessThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } &Instruction::DefaultExecuteTermLessThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } &Instruction::DefaultCallTermGreaterThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::DefaultExecuteTermGreaterThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::DefaultCallTermLessThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Less | Ordering::Equal) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::DefaultExecuteTermLessThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Less | Ordering::Equal) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::DefaultCallCopyTerm => { self.machine_st.copy_term(AttrVarPolicy::DeepCopy); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteCopyTerm => { self.machine_st.copy_term(AttrVarPolicy::DeepCopy); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallTermEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { self.machine_st.p += 1; } } &Instruction::DefaultExecuteTermEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallGround => { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { self.machine_st.p += 1; } } &Instruction::DefaultExecuteGround => { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallFunctor => { try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteFunctor => { try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallTermNotEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.backtrack(); } else { self.machine_st.p += 1; } } &Instruction::DefaultExecuteTermNotEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallSort => { try_or_throw!(self.machine_st, self.machine_st.sort(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteSort => { try_or_throw!(self.machine_st, self.machine_st.sort(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::DefaultCallKeySort => { try_or_throw!(self.machine_st, self.machine_st.keysort(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteKeySort => { try_or_throw!(self.machine_st, self.machine_st.keysort(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::DefaultCallIs(r, at) => { try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::DefaultExecuteIs(r, at) => { try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } Instruction::DefaultCallGetNumber(at) => { try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } Instruction::DefaultExecuteGetNumber(at) => { try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallAcyclicTerm => { let addr = self.deref_register(1); if addr.is_ref() { self.machine_st.heap[0] = addr; if self.machine_st.is_cyclic_term(0) { self.machine_st.backtrack(); continue; } } increment_call_count!(self.machine_st); self.machine_st.p += 1; } &Instruction::ExecuteAcyclicTerm => { let addr = self.deref_register(1); if addr.is_ref() { self.machine_st.heap[0] = addr; if self.machine_st.is_cyclic_term(0) { self.machine_st.backtrack(); continue; } } increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } &Instruction::CallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallCompare => { try_or_throw!(self.machine_st, self.machine_st.compare(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteCompare => { try_or_throw!(self.machine_st, self.machine_st.compare(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallTermGreaterThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) { increment_call_count!(self.machine_st); self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } &Instruction::ExecuteTermGreaterThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Greater) = self.machine_st.compare_term_test(a1, a2) { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } &Instruction::CallTermLessThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) { increment_call_count!(self.machine_st); self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } &Instruction::ExecuteTermLessThan => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Less) = self.machine_st.compare_term_test(a1, a2) { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } &Instruction::CallTermGreaterThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteTermGreaterThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Greater | Ordering::Equal) => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::CallTermLessThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Less | Ordering::Equal) => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteTermLessThanOrEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; match self.machine_st.compare_term_test(a1, a2) { Some(Ordering::Less | Ordering::Equal) => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::CallCopyTerm => { self.machine_st.copy_term(AttrVarPolicy::DeepCopy); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteCopyTerm => { self.machine_st.copy_term(AttrVarPolicy::DeepCopy); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallTermEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteTermEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if self.machine_st.eq_test(a1, a2) { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallGround => { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteGround => { if self.machine_st.ground_test() { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallFunctor => { try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteFunctor => { try_or_throw!(self.machine_st, self.machine_st.try_functor(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallTermNotEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteTermNotEqual => { let a1 = self.machine_st.registers[1]; let a2 = self.machine_st.registers[2]; if let Some(Ordering::Equal) = self.machine_st.compare_term_test(a1, a2) { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallSort => { try_or_throw!(self.machine_st, self.machine_st.sort(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteSort => { try_or_throw!(self.machine_st, self.machine_st.sort(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallKeySort => { try_or_throw!(self.machine_st, self.machine_st.keysort(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteKeySort => { try_or_throw!(self.machine_st, self.machine_st.keysort(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallIs(r, at) => { try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } &Instruction::ExecuteIs(r, at) => { try_or_throw!(self.machine_st, self.machine_st.is(r, at), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } Instruction::CallGetNumber(at) => { try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } Instruction::ExecuteGetNumber(at) => { try_or_throw!(self.machine_st, self.machine_st.get_number(at), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } &Instruction::CallN(arity) => { let pred = self.machine_st.registers[1]; for i in 2..arity + 1 { self.machine_st.registers[i - 1] = self.machine_st.registers[i]; } self.machine_st.registers[arity] = pred; try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); } } &Instruction::ExecuteN(arity) => { let pred = self.machine_st.registers[1]; for i in 2..arity + 1 { self.machine_st.registers[i - 1] = self.machine_st.registers[i]; } self.machine_st.registers[arity] = pred; try_or_throw!( self.machine_st, self.execute_n(atom!("user"), arity), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); } } &Instruction::DefaultCallN(arity) => { let pred = self.machine_st.registers[1]; for i in 2..arity + 1 { self.machine_st.registers[i - 1] = self.machine_st.registers[i]; } self.machine_st.registers[arity] = pred; try_or_throw!(self.machine_st, self.call_n(atom!("user"), arity), continue); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::DefaultExecuteN(arity) => { let pred = self.machine_st.registers[1]; for i in 2..arity + 1 { self.machine_st.registers[i - 1] = self.machine_st.registers[i]; } self.machine_st.registers[arity] = pred; try_or_throw!( self.machine_st, self.execute_n(atom!("user"), arity), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } Instruction::CallNumberLessThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::ExecuteNumberLessThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::CallNumberEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::ExecuteNumberEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::CallNumberNotEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.backtrack(); } _ => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } } } Instruction::ExecuteNumberNotEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.backtrack(); } _ => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } } } Instruction::CallNumberGreaterThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::ExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::CallNumberGreaterThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::ExecuteNumberGreaterThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::CallNumberLessThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less => { increment_call_count!(self.machine_st); self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::ExecuteNumberLessThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less => { increment_call_count!(self.machine_st); self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultCallNumberLessThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultExecuteNumberLessThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less | Ordering::Equal => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultCallNumberNotEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.backtrack(); } _ => { self.machine_st.p += 1; } } } Instruction::DefaultExecuteNumberNotEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.backtrack(); } _ => { self.machine_st.p = self.machine_st.cp; } } } Instruction::DefaultCallNumberEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultExecuteNumberEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Equal => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultCallNumberGreaterThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater | Ordering::Equal => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultCallNumberGreaterThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultExecuteNumberGreaterThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Greater => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultCallNumberLessThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } Instruction::DefaultExecuteNumberLessThan(ref at_1, ref at_2) => { let n1 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_1), continue ); let n2 = try_or_throw!( self.machine_st, self.machine_st.get_number(at_2), continue ); match n1.cmp(&n2) { Ordering::Less => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } // &Instruction::CallIsAtom(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Atom, (_name, arity)) => { if arity == 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity == 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::ExecuteIsAtom(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Atom, (_name, arity)) => { if arity == 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity == 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::CallIsAtomic(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset | HeapCellValueTag::Cons) => { self.machine_st.p += 1; } (HeapCellValueTag::Atom, (_name, arity)) => { if arity == 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity == 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::ExecuteIsAtomic(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset | HeapCellValueTag::Cons) => { self.machine_st.p = self.machine_st.cp; } (HeapCellValueTag::Atom, (_name, arity)) => { if arity == 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity == 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::CallIsCompound(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr) => { self.machine_st.p += 1; } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity > 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Atom, (_name, arity)) => { if arity > 0 { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::ExecuteIsCompound(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr) => { self.machine_st.p = self.machine_st.cp; } (HeapCellValueTag::Str, s) => { let arity = cell_as_atom_cell!(self.machine_st.heap[s]) .get_arity(); if arity > 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } (HeapCellValueTag::Atom, (_name, arity)) => { if arity > 0 { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } ); } &Instruction::CallIsInteger(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(_) | Number::Integer(_)) => { self.machine_st.p += 1; } Ok(Number::Rational(n)) => { if n.denominator().is_one() { self.machine_st.p += 1; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteIsInteger(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(_) | Number::Integer(_)) => { self.machine_st.p = self.machine_st.cp; } Ok(Number::Rational(n)) => { if n.denominator().is_one() { self.machine_st.p = self.machine_st.cp; } else { self.machine_st.backtrack(); } } _ => { self.machine_st.backtrack(); } } } &Instruction::CallIsNumber(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(_) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteIsNumber(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(_) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::CallIsRational(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Cons, ptr) => { match_untyped_arena_ptr!(ptr, (ArenaHeaderTag::Rational | ArenaHeaderTag::Integer, _r) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } ); } (HeapCellValueTag::Fixnum) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } ); } &Instruction::ExecuteIsRational(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, (HeapCellValueTag::Cons, ptr) => { match_untyped_arena_ptr!(ptr, (ArenaHeaderTag::Rational | ArenaHeaderTag::Integer, _r) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } ); } (HeapCellValueTag::Fixnum) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } ); } &Instruction::CallIsFloat(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(_)) => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteIsFloat(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match Number::try_from((d, &self.machine_st.arena.f64_tbl)) { Ok(Number::Float(_)) => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::CallIsNonVar(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match d.get_tag() { HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar => { self.machine_st.backtrack(); } _ => { self.machine_st.p += 1; } } } &Instruction::ExecuteIsNonVar(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match d.get_tag() { HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar => { self.machine_st.backtrack(); } _ => { self.machine_st.p = self.machine_st.cp; } } } &Instruction::CallIsVar(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match d.get_tag() { HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar => { self.machine_st.p += 1; } _ => { self.machine_st.backtrack(); } } } &Instruction::ExecuteIsVar(r) => { let d = self .machine_st .store(self.machine_st.deref(self.machine_st[r])); match d.get_tag() { HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar => { self.machine_st.p = self.machine_st.cp; } _ => { self.machine_st.backtrack(); } } } &Instruction::CallNamed(arity, name, idx) => { let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_call(name, arity, idx), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); } } &Instruction::ExecuteNamed(arity, name, idx) => { let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!( self.machine_st, self.try_execute(name, arity, idx), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } else { increment_call_count!(self.machine_st); } } &Instruction::DefaultCallNamed(arity, name, idx) => { let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!(self.machine_st, self.try_call(name, arity, idx), continue); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::DefaultExecuteNamed(arity, name, idx) => { let idx = self.machine_st.arena.code_index_tbl.get_entry(idx.into()); try_or_throw!( self.machine_st, self.try_execute(name, arity, idx), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::JmpByCall(offset) => { self.machine_st.p += offset; } &Instruction::RevJmpBy(offset) => { self.machine_st.p -= offset; } &Instruction::Proceed => { self.machine_st.p = self.machine_st.cp; } Instruction::IndexingCode(ref indexing_lines) => { match &indexing_lines[self.machine_st.oip as usize] { IndexingLine::Indexing(_) => { self.execute_switch_on_term(); if self.machine_st.fail { self.machine_st.backtrack(); } } IndexingLine::IndexedChoice(ref indexed_choice) => { match indexed_choice[self.machine_st.iip as usize] { IndexedChoiceInstruction::Try(offset) => { backtrack_on_resource_error!( self.machine_st, self.indexed_try(offset), continue ); } IndexedChoiceInstruction::Retry(l) => { self.retry(l); increment_call_count!(self.machine_st); } IndexedChoiceInstruction::DefaultRetry(l) => { self.retry(l); } IndexedChoiceInstruction::Trust(l) => { self.trust(l); increment_call_count!(self.machine_st); } IndexedChoiceInstruction::DefaultTrust(l) => { self.trust(l); } } } IndexingLine::DynamicIndexedChoice(_) => { let p = self.machine_st.p; match self .find_living_dynamic(self.machine_st.oip, self.machine_st.iip) { Some((offset, oi, ii, is_next_clause)) => { self.machine_st.p = p; self.machine_st.oip = oi; self.machine_st.iip = ii; match self.machine_st.dynamic_mode { FirstOrNext::First if !is_next_clause => { self.machine_st.p = p + offset; } FirstOrNext::First => { // there's a leading DynamicElse that sets self.machine_st.cc. // self.machine_st.cc = self.machine_st.global_clock; // see that there is a following dynamic_else // clause so we avoid generating a choice // point in case there isn't. match self.find_living_dynamic(oi, ii + 1) { Some(_) => { self.machine_st.registers [self.machine_st.num_of_args + 1] = fixnum_as_cell!( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked( self.machine_st.cc as i64, ) } ); self.machine_st.num_of_args += 1; backtrack_on_resource_error!( self.machine_st, self.indexed_try(offset), continue ); self.machine_st.num_of_args -= 1; } None => { self.machine_st.p = p + offset; self.machine_st.oip = 0; self.machine_st.iip = 0; } } } FirstOrNext::Next => { let b = self.machine_st.b; let n = self .machine_st .stack .index_or_frame(b) .prelude .num_cells; self.machine_st.cc = unsafe { self.machine_st.stack [stack_loc!(OrFrame, b, n - 1)] .to_fixnum_or_cut_point_unchecked() } .get_num() as usize; if is_next_clause { match self.find_living_dynamic( self.machine_st.oip, self.machine_st.iip + 1, ) { // if we're executing the last instruction // of the internal block pointed to by // self.machine_st.iip, we want trust, not retry. // this is true iff ii + 1 < len. Some(_) => { self.retry(offset); increment_call_count!(self.machine_st); } _ => { self.trust(offset); increment_call_count!(self.machine_st); } } } else { self.trust(offset); increment_call_count!(self.machine_st); } } } } None => { self.machine_st.fail = true; } } self.machine_st.dynamic_mode = FirstOrNext::Next; if self.machine_st.fail { self.machine_st.backtrack(); } } } } // &Instruction::CallAtomChars => { self.atom_chars(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteAtomChars => { self.atom_chars(); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::CallAtomCodes => { try_or_throw!(self.machine_st, self.atom_codes(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p += 1; } } &Instruction::ExecuteAtomCodes => { try_or_throw!(self.machine_st, self.atom_codes(), continue); if self.machine_st.fail { self.machine_st.backtrack(); } else { self.machine_st.p = self.machine_st.cp; } } &Instruction::CallAtomLength => { self.atom_length(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteAtomLength => { self.atom_length(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallBindFromRegister => { self.bind_from_register(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteBindFromRegister => { self.bind_from_register(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallContinuation => { try_or_throw!(self.machine_st, self.call_continuation(false), continue); } &Instruction::ExecuteContinuation => { try_or_throw!(self.machine_st, self.call_continuation(true), continue); } &Instruction::CallCharCode => { try_or_throw!(self.machine_st, self.char_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCharCode => { try_or_throw!(self.machine_st, self.char_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCharType => { self.char_type(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCharType => { self.char_type(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCharsToNumber => { try_or_throw!(self.machine_st, self.chars_to_number(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCharsToNumber => { try_or_throw!(self.machine_st, self.chars_to_number(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCodesToNumber => { try_or_throw!(self.machine_st, self.codes_to_number(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCodesToNumber => { try_or_throw!(self.machine_st, self.codes_to_number(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCopyTermWithoutAttrVars => { self.copy_term_without_attr_vars(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCopyTermWithoutAttrVars => { self.copy_term_without_attr_vars(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCheckCutPoint => { self.check_cut_point(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCheckCutPoint => { self.check_cut_point(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallClose => { try_or_throw!(self.machine_st, self.close(), continue); self.machine_st.p += 1; } &Instruction::ExecuteClose => { try_or_throw!(self.machine_st, self.close(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallCopyToLiftedHeap => { self.copy_to_lifted_heap(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCopyToLiftedHeap => { self.copy_to_lifted_heap(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCreatePartialString => { self.create_partial_string(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCreatePartialString => { self.create_partial_string(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurrentHostname => { self.current_hostname(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCurrentHostname => { self.current_hostname(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurrentInput => { try_or_throw!(self.machine_st, self.current_input(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCurrentInput => { try_or_throw!(self.machine_st, self.current_input(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurrentOutput => { try_or_throw!(self.machine_st, self.current_output(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCurrentOutput => { try_or_throw!(self.machine_st, self.current_output(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDirectoryFiles => { try_or_throw!(self.machine_st, self.directory_files(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDirectoryFiles => { try_or_throw!(self.machine_st, self.directory_files(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFileSize => { self.file_size(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFileSize => { self.file_size(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFileExists => { self.file_exists(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFileExists => { self.file_exists(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDirectoryExists => { self.directory_exists(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDirectoryExists => { self.directory_exists(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDirectorySeparator => { self.directory_separator(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDirectorySeparator => { self.directory_separator(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallMakeDirectory => { self.make_directory(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteMakeDirectory => { self.make_directory(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallMakeDirectoryPath => { self.make_directory_path(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteMakeDirectoryPath => { self.make_directory_path(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDeleteFile => { self.delete_file(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDeleteFile => { self.delete_file(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallRenameFile => { self.rename_file(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteRenameFile => { self.rename_file(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFileCopy => { self.file_copy(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFileCopy => { self.file_copy(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallWorkingDirectory => { try_or_throw!(self.machine_st, self.working_directory(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteWorkingDirectory => { try_or_throw!(self.machine_st, self.working_directory(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDeleteDirectory => { self.delete_directory(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDeleteDirectory => { self.delete_directory(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPathCanonical => { try_or_throw!(self.machine_st, self.path_canonical(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePathCanonical => { try_or_throw!(self.machine_st, self.path_canonical(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFileTime => { self.file_time(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFileTime => { self.file_time(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDynamicModuleResolution(arity) => { let (module_name, key) = try_or_throw!( self.machine_st, self.dynamic_module_resolution(arity - 2), continue ); try_or_throw!( self.machine_st, self.call_clause(module_name, key), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::ExecuteDynamicModuleResolution(arity) => { let (module_name, key) = try_or_throw!( self.machine_st, self.dynamic_module_resolution(arity - 2), continue ); try_or_throw!( self.machine_st, self.execute_clause(module_name, key), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::CallFetchGlobalVar => { self.fetch_global_var(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFetchGlobalVar => { self.fetch_global_var(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFirstStream => { self.first_stream(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFirstStream => { self.first_stream(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFlushOutput => { try_or_throw!(self.machine_st, self.flush_output(), continue); self.machine_st.p += 1; } &Instruction::ExecuteFlushOutput => { try_or_throw!(self.machine_st, self.flush_output(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallGetByte => { try_or_throw!(self.machine_st, self.get_byte(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetByte => { try_or_throw!(self.machine_st, self.get_byte(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetChar => { try_or_throw!(self.machine_st, self.get_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetChar => { try_or_throw!(self.machine_st, self.get_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetNChars => { try_or_throw!(self.machine_st, self.get_n_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetNChars => { try_or_throw!(self.machine_st, self.get_n_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetCode => { try_or_throw!(self.machine_st, self.get_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetCode => { try_or_throw!(self.machine_st, self.get_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetSingleChar => { try_or_throw!(self.machine_st, self.get_single_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetSingleChar => { try_or_throw!(self.machine_st, self.get_single_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff => { self.truncate_if_no_lifted_heap_growth_diff(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff => { self.truncate_if_no_lifted_heap_growth_diff(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_growth(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_growth(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetAttributedVariableList => { self.get_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetAttributedVariableList => { self.get_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetAttrVarQueueDelimiter => { self.get_attr_var_queue_delimiter(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetAttrVarQueueDelimiter => { self.get_attr_var_queue_delimiter(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetAttrVarQueueBeyond => { self.get_attr_var_queue_beyond(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetAttrVarQueueBeyond => { self.get_attr_var_queue_beyond(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetBValue => { self.get_b_value(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetBValue => { self.get_b_value(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetContinuationChunk => { self.get_continuation_chunk(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetContinuationChunk => { self.get_continuation_chunk(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLookupDBRef => { self.lookup_db_ref(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLookupDBRef => { self.lookup_db_ref(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetNextOpDBRef => { self.get_next_op_db_ref(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetNextOpDBRef => { self.get_next_op_db_ref(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallIsPartialString => { self.is_partial_string(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteIsPartialString => { self.is_partial_string(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHalt | &Instruction::ExecuteHalt => { return self.halt(); } &Instruction::CallGetLiftedHeapFromOffset => { self.get_lifted_heap_from_offset(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetLiftedHeapFromOffset => { self.get_lifted_heap_from_offset(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetLiftedHeapFromOffsetDiff => { self.get_lifted_heap_from_offset_diff(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetLiftedHeapFromOffsetDiff => { self.get_lifted_heap_from_offset_diff(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetSCCCleaner => { self.get_scc_cleaner(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetSCCCleaner => { self.get_scc_cleaner(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHeadIsDynamic => { self.head_is_dynamic(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHeadIsDynamic => { self.head_is_dynamic(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInstallSCCCleaner => { self.install_scc_cleaner(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInstallSCCCleaner => { self.install_scc_cleaner(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInstallInferenceCounter => { try_or_throw!(self.machine_st, self.install_inference_counter(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInstallInferenceCounter => { try_or_throw!(self.machine_st, self.install_inference_counter(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInferenceCount => { let global_count = self.machine_st.cwil.global_count; self.inference_count(self.machine_st.registers[1], global_count); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInferenceCount => { let global_count = self.machine_st.cwil.global_count; self.inference_count(self.machine_st.registers[1], global_count); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLiftedHeapLength => { self.lifted_heap_length(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLiftedHeapLength => { self.lifted_heap_length(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadLibraryAsStream => { try_or_throw!(self.machine_st, self.load_library_as_stream(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadLibraryAsStream => { try_or_throw!(self.machine_st, self.load_library_as_stream(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallModuleExists => { self.module_exists(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteModuleExists => { self.module_exists(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallNextEP => { self.next_ep(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteNextEP => { self.next_ep(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallNoSuchPredicate => { try_or_throw!(self.machine_st, self.no_such_predicate(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteNoSuchPredicate => { try_or_throw!(self.machine_st, self.no_such_predicate(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallNumberToChars => { self.number_to_chars(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteNumberToChars => { self.number_to_chars(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallNumberToCodes => { self.number_to_codes(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteNumberToCodes => { self.number_to_codes(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallOpDeclaration => { try_or_throw!(self.machine_st, self.op_declaration(), continue); self.machine_st.p += 1; } &Instruction::ExecuteOpDeclaration => { try_or_throw!(self.machine_st, self.op_declaration(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallOpen => { try_or_throw!(self.machine_st, self.open(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteOpen => { try_or_throw!(self.machine_st, self.open(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetStreamOptions => { try_or_throw!(self.machine_st, self.set_stream_options(), continue); self.machine_st.p += 1; } &Instruction::ExecuteSetStreamOptions => { try_or_throw!(self.machine_st, self.set_stream_options(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallNextStream => { self.next_stream(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteNextStream => { self.next_stream(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPartialStringTail => { self.partial_string_tail(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePartialStringTail => { self.partial_string_tail(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPeekByte => { try_or_throw!(self.machine_st, self.peek_byte(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePeekByte => { try_or_throw!(self.machine_st, self.peek_byte(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPeekChar => { try_or_throw!(self.machine_st, self.peek_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePeekChar => { try_or_throw!(self.machine_st, self.peek_char(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPeekCode => { try_or_throw!(self.machine_st, self.peek_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePeekCode => { try_or_throw!(self.machine_st, self.peek_code(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPointsToContinuationResetMarker => { self.points_to_continuation_reset_marker(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePointsToContinuationResetMarker => { self.points_to_continuation_reset_marker(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPutByte => { try_or_throw!(self.machine_st, self.put_byte(), continue); self.machine_st.p += 1; } &Instruction::ExecutePutByte => { try_or_throw!(self.machine_st, self.put_byte(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPutChar => { try_or_throw!(self.machine_st, self.put_char(), continue); self.machine_st.p += 1; } &Instruction::ExecutePutChar => { try_or_throw!(self.machine_st, self.put_char(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPutChars => { try_or_throw!(self.machine_st, self.put_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePutChars => { try_or_throw!(self.machine_st, self.put_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPutCode => { try_or_throw!(self.machine_st, self.put_code(), continue); self.machine_st.p += 1; } &Instruction::ExecutePutCode => { try_or_throw!(self.machine_st, self.put_code(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallReadQueryTerm => { try_or_throw!(self.machine_st, self.read_query_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteReadQueryTerm => { try_or_throw!(self.machine_st, self.read_query_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallReadTerm => { try_or_throw!(self.machine_st, self.read_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteReadTerm => { try_or_throw!(self.machine_st, self.read_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallRedoAttrVarBinding => { self.redo_attr_var_binding(); self.machine_st.p += 1; } &Instruction::ExecuteRedoAttrVarBinding => { self.redo_attr_var_binding(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallRemoveCallPolicyCheck => { self.remove_call_policy_check(); self.machine_st.p += 1; } &Instruction::ExecuteRemoveCallPolicyCheck => { self.remove_call_policy_check(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallRemoveInferenceCounter => { self.remove_inference_counter(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteRemoveInferenceCounter => { self.remove_inference_counter(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallResetContinuationMarker => { self.reset_continuation_marker(); self.machine_st.p += 1; } &Instruction::ExecuteResetContinuationMarker => { self.reset_continuation_marker(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallRestoreCutPolicy => { self.restore_cut_policy(); self.machine_st.p += 1; } &Instruction::ExecuteRestoreCutPolicy => { self.restore_cut_policy(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSetCutPoint(r) => { if !self.set_cut_point(r) { step_or_fail!(self.machine_st, self.machine_st.p += 1); } } &Instruction::ExecuteSetCutPoint(r) => { let cp = self.machine_st.cp; if !self.set_cut_point(r) { step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } else { // run_cleaners in set_cut_point calls call_by_index. // replace the effect of call_by_index with that // of execute_by_index here. self.machine_st.cp = cp; } } &Instruction::CallSetInput => { try_or_throw!(self.machine_st, self.set_input(), continue); self.machine_st.p += 1; } &Instruction::ExecuteSetInput => { try_or_throw!(self.machine_st, self.set_input(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSetOutput => { try_or_throw!(self.machine_st, self.set_output(), continue); self.machine_st.p += 1; } &Instruction::ExecuteSetOutput => { try_or_throw!(self.machine_st, self.set_output(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallStoreBacktrackableGlobalVar => { self.store_backtrackable_global_var(); self.machine_st.p += 1; } &Instruction::ExecuteStoreBacktrackableGlobalVar => { self.store_backtrackable_global_var(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallStoreGlobalVar => { self.store_global_var(); self.machine_st.p += 1; } &Instruction::ExecuteStoreGlobalVar => { self.store_global_var(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallStreamProperty => { try_or_throw!(self.machine_st, self.stream_property(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteStreamProperty => { try_or_throw!(self.machine_st, self.stream_property(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetStreamPosition => { try_or_throw!(self.machine_st, self.set_stream_position(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetStreamPosition => { try_or_throw!(self.machine_st, self.set_stream_position(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInferenceLevel => { self.inference_level(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInferenceLevel => { self.inference_level(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCleanUpBlock => { self.clean_up_block(); self.machine_st.p += 1; } &Instruction::ExecuteCleanUpBlock => { self.clean_up_block(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallFail | &Instruction::ExecuteFail => { self.machine_st.backtrack(); } &Instruction::CallGetBall => { self.get_ball(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetBall => { self.get_ball(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetCurrentBlock => { self.get_current_block(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetCurrentBlock => { self.get_current_block(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetCurrentSCCBlock => { self.get_current_scc_block(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetCurrentSCCBlock => { self.get_current_scc_block(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetCutPoint => { self.get_cut_point(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetCutPoint => { self.get_cut_point(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetDoubleQuotes => { self.get_double_quotes(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetDoubleQuotes => { self.get_double_quotes(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetUnknown => { self.get_unknown(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetUnknown => { self.get_unknown(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInstallNewBlock => { self.machine_st .install_new_block(self.machine_st.registers[1]); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInstallNewBlock => { self.machine_st .install_new_block(self.machine_st.registers[1]); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallRandomInteger => { self.random_integer(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteRandomInteger => { self.random_integer(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallMaybe => { self.maybe(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteMaybe => { self.maybe(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCpuNow => { self.cpu_now(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCpuNow => { self.cpu_now(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDeterministicLengthRundown => { try_or_throw!(self.machine_st, self.det_length_rundown(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDeterministicLengthRundown => { try_or_throw!(self.machine_st, self.det_length_rundown(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHttpOpen => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHttpOpen => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHttpListen => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_listen(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHttpListen => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_listen(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHttpAccept => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_accept(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHttpAccept => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_accept(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallHttpAnswer => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_answer(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHttpAnswer => { #[cfg(feature = "http")] try_or_throw!(self.machine_st, self.http_answer(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadForeignLib => { try_or_throw!(self.machine_st, self.load_foreign_lib(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadForeignLib => { try_or_throw!(self.machine_st, self.load_foreign_lib(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallForeignCall => { try_or_throw!(self.machine_st, self.foreign_call(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteForeignCall => { try_or_throw!(self.machine_st, self.foreign_call(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDefineForeignStruct => { try_or_throw!(self.machine_st, self.define_foreign_struct(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDefineForeignStruct => { try_or_throw!(self.machine_st, self.define_foreign_struct(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFfiAllocate => { try_or_throw!(self.machine_st, self.ffi_allocate(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFfiAllocate => { try_or_throw!(self.machine_st, self.ffi_allocate(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFfiReadPtr => { try_or_throw!(self.machine_st, self.ffi_read_ptr(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFfiReadPtr => { try_or_throw!(self.machine_st, self.ffi_read_ptr(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFfiDeallocate => { try_or_throw!(self.machine_st, self.ffi_deallocate(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFfiDeallocate => { try_or_throw!(self.machine_st, self.ffi_deallocate(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallJsEval => { try_or_throw!(self.machine_st, self.js_eval(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteJsEval => { try_or_throw!(self.machine_st, self.js_eval(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallArgv => { try_or_throw!(self.machine_st, self.argv(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteArgv => { try_or_throw!(self.machine_st, self.argv(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurrentTime => { self.current_time(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCurrentTime => { self.current_time(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallQuotedToken => { self.quoted_token(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteQuotedToken => { self.quoted_token(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallReadFromChars => { try_or_throw!(self.machine_st, self.read_from_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteReadFromChars => { try_or_throw!(self.machine_st, self.read_from_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallReadTermFromChars => { try_or_throw!(self.machine_st, self.read_term_from_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteReadTermFromChars => { try_or_throw!(self.machine_st, self.read_term_from_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallResetBlock => { self.reset_block(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteResetBlock => { self.reset_block(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallResetSCCBlock => { self.reset_scc_block(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteResetSCCBlock => { self.reset_scc_block(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallReturnFromVerifyAttr | &Instruction::ExecuteReturnFromVerifyAttr => { self.return_from_verify_attr(); } &Instruction::CallSetBall => { self.set_ball(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetBall => { self.set_ball(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPushBallStack => { self.push_ball_stack(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePushBallStack => { self.push_ball_stack(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPopBallStack => { self.pop_ball_stack(); self.machine_st.p += 1; } &Instruction::ExecutePopBallStack => { self.pop_ball_stack(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPopFromBallStack => { self.pop_from_ball_stack(); self.machine_st.p += 1; } &Instruction::ExecutePopFromBallStack => { self.pop_from_ball_stack(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSetCutPointByDefault(r) => { self.set_cut_point_by_default(r); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetCutPointByDefault(r) => { self.set_cut_point_by_default(r); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetDoubleQuotes => { self.set_double_quotes(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetDoubleQuotes => { self.set_double_quotes(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetUnknown => { self.set_unknown(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetUnknown => { self.set_unknown(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetSeed => { self.set_seed(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSetSeed => { self.set_seed(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSkipMaxList => { try_or_throw!(self.machine_st, self.machine_st.skip_max_list(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSkipMaxList => { try_or_throw!(self.machine_st, self.machine_st.skip_max_list(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSleep => { self.sleep(); self.machine_st.p += 1; } &Instruction::ExecuteSleep => { self.sleep(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSocketClientOpen => { try_or_throw!(self.machine_st, self.socket_client_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSocketClientOpen => { try_or_throw!(self.machine_st, self.socket_client_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSocketServerOpen => { try_or_throw!(self.machine_st, self.socket_server_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSocketServerOpen => { try_or_throw!(self.machine_st, self.socket_server_open(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSocketServerAccept => { try_or_throw!(self.machine_st, self.socket_server_accept(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteSocketServerAccept => { try_or_throw!(self.machine_st, self.socket_server_accept(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSocketServerClose => { try_or_throw!(self.machine_st, self.socket_server_close(), continue); self.machine_st.p += 1; } &Instruction::ExecuteSocketServerClose => { try_or_throw!(self.machine_st, self.socket_server_close(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallTLSAcceptClient => { #[cfg(feature = "tls")] try_or_throw!(self.machine_st, self.tls_accept_client(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTLSAcceptClient => { #[cfg(feature = "tls")] try_or_throw!(self.machine_st, self.tls_accept_client(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTLSClientConnect => { #[cfg(feature = "tls")] try_or_throw!(self.machine_st, self.tls_client_connect(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTLSClientConnect => { #[cfg(feature = "tls")] try_or_throw!(self.machine_st, self.tls_client_connect(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSucceed => { self.machine_st.p += 1; } &Instruction::ExecuteSucceed => { self.machine_st.p = self.machine_st.cp; } &Instruction::CallTermAttributedVariables => { self.term_attributed_variables(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTermAttributedVariables => { self.term_attributed_variables(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTermVariables => { self.term_variables(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTermVariables => { self.term_variables(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTermVariablesUnderMaxDepth => { self.term_variables_under_max_depth(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteTermVariablesUnderMaxDepth => { self.term_variables_under_max_depth(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallTruncateLiftedHeapTo => { self.truncate_lifted_heap_to(); self.machine_st.p += 1; } &Instruction::ExecuteTruncateLiftedHeapTo => { self.truncate_lifted_heap_to(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallUnifyWithOccursCheck => { self.unify_with_occurs_check(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteUnifyWithOccursCheck => { self.unify_with_occurs_check(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallUnwindEnvironments => { if !self.unwind_environments() { self.machine_st.p += 1; } } &Instruction::ExecuteUnwindEnvironments => { if !self.unwind_environments() { self.machine_st.p = self.machine_st.cp; } } &Instruction::CallUnwindStack | &Instruction::ExecuteUnwindStack => { self.machine_st.unwind_stack(); self.machine_st.backtrack(); } &Instruction::CallWAMInstructions => { try_or_throw!(self.machine_st, self.wam_instructions(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteWAMInstructions => { try_or_throw!(self.machine_st, self.wam_instructions(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInlinedInstructions => { self.inlined_instructions(); self.machine_st.p += 1; } &Instruction::ExecuteInlinedInstructions => { self.inlined_instructions(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallWriteTerm => { try_or_throw!(self.machine_st, self.write_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteWriteTerm => { try_or_throw!(self.machine_st, self.write_term(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallWriteTermToChars => { try_or_throw!(self.machine_st, self.write_term_to_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteWriteTermToChars => { try_or_throw!(self.machine_st, self.write_term_to_chars(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallScryerPrologVersion => { self.scryer_prolog_version(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteScryerPrologVersion => { self.scryer_prolog_version(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoRandomByte => { self.crypto_random_byte(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoRandomByte => { self.crypto_random_byte(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoDataHash => { self.crypto_data_hash(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoDataHash => { self.crypto_data_hash(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoHMAC => { self.crypto_hmac(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoHMAC => { self.crypto_hmac(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoDataHKDF => { self.crypto_data_hkdf(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoDataHKDF => { self.crypto_data_hkdf(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoPasswordHash => { self.crypto_password_hash(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoPasswordHash => { self.crypto_password_hash(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } #[cfg(feature = "crypto-full")] &Instruction::CallCryptoDataEncrypt => { self.crypto_data_encrypt(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } #[cfg(feature = "crypto-full")] &Instruction::ExecuteCryptoDataEncrypt => { self.crypto_data_encrypt(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } #[cfg(feature = "crypto-full")] &Instruction::CallCryptoDataDecrypt => { self.crypto_data_decrypt(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } #[cfg(feature = "crypto-full")] &Instruction::ExecuteCryptoDataDecrypt => { self.crypto_data_decrypt(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallBeta => { self.beta(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteBeta => { self.beta(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallBetaI => { self.betai(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteBetaI => { self.betai(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInvBetaI => { self.invbetai(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInvBetaI => { self.invbetai(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGamma => { self.gamma(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGamma => { self.gamma(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLnGamma => { self.ln_gamma(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLnGamma => { self.ln_gamma(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGammP => { self.gammp(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGammP => { self.gammp(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInvGammP => { self.invgammp(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInvGammP => { self.invgammp(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGammQ => { self.gammq(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGammQ => { self.gammq(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallErf => { self.erf(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteErf => { self.erf(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallErfc => { self.erfc(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteErfc => { self.erfc(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInvErf => { self.inverf(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInvErf => { self.inverf(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInvErfc => { self.inverfc(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInvErfc => { self.inverfc(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCryptoCurveScalarMult => { self.crypto_curve_scalar_mult(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCryptoCurveScalarMult => { self.crypto_curve_scalar_mult(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallEd25519SignRaw => { self.ed25519_sign_raw(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteEd25519SignRaw => { self.ed25519_sign_raw(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallEd25519VerifyRaw => { self.ed25519_verify_raw(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteEd25519VerifyRaw => { self.ed25519_verify_raw(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallEd25519SeedToPublicKey => { self.ed25519_seed_to_public_key(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteEd25519SeedToPublicKey => { self.ed25519_seed_to_public_key(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCurve25519ScalarMult => { self.curve25519_scalar_mult(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCurve25519ScalarMult => { self.curve25519_scalar_mult(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFirstNonOctet => { self.first_non_octet(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteFirstNonOctet => { self.first_non_octet(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadHTML => { backtrack_on_resource_error!(self.machine_st, self.load_html(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadHTML => { backtrack_on_resource_error!(self.machine_st, self.load_html(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadXML => { backtrack_on_resource_error!(self.machine_st, self.load_xml(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadXML => { backtrack_on_resource_error!(self.machine_st, self.load_xml(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetEnv => { self.get_env(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetEnv => { self.get_env(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetEnv => { self.set_env(); self.machine_st.p += 1; } &Instruction::ExecuteSetEnv => { self.set_env(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallUnsetEnv => { self.unset_env(); self.machine_st.p += 1; } &Instruction::ExecuteUnsetEnv => { self.unset_env(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallShell => { self.shell(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteShell => { self.shell(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallProcessCreate => { try_or_throw!(self.machine_st, self.process_create(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteProcessCreate => { try_or_throw!(self.machine_st, self.process_create(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallProcessId => { try_or_throw!(self.machine_st, self.process_id(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteProcessId => { try_or_throw!(self.machine_st, self.process_id(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallProcessWait => { try_or_throw!(self.machine_st, self.process_wait(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteProcessWait => { try_or_throw!(self.machine_st, self.process_wait(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallProcessKill => { try_or_throw!(self.machine_st, self.process_kill(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteProcessKill => { try_or_throw!(self.machine_st, self.process_kill(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallProcessRelease => { try_or_throw!(self.machine_st, self.process_release(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteProcessRelease => { try_or_throw!(self.machine_st, self.process_release(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPid => { self.pid(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePid => { self.pid(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCharsBase64 => { try_or_throw!(self.machine_st, self.chars_base64(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCharsBase64 => { try_or_throw!(self.machine_st, self.chars_base64(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDevourWhitespace => { try_or_throw!(self.machine_st, self.devour_whitespace(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDevourWhitespace => { try_or_throw!(self.machine_st, self.devour_whitespace(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallIsSTOEnabled => { self.is_sto_enabled(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteIsSTOEnabled => { self.is_sto_enabled(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallSetSTOAsUnify => { self.set_sto_as_unify(); self.machine_st.p += 1; } &Instruction::ExecuteSetSTOAsUnify => { self.set_sto_as_unify(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSetNSTOAsUnify => { self.set_nsto_as_unify(); self.machine_st.p += 1; } &Instruction::ExecuteSetNSTOAsUnify => { self.set_nsto_as_unify(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallSetSTOWithErrorAsUnify => { self.set_sto_with_error_as_unify(); self.machine_st.p += 1; } &Instruction::ExecuteSetSTOWithErrorAsUnify => { self.set_sto_with_error_as_unify(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallHomeDirectory => { self.home_directory(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteHomeDirectory => { self.home_directory(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDebugHook => { self.debug_hook(); self.machine_st.p += 1; } &Instruction::ExecuteDebugHook => { self.debug_hook(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPopCount => { self.pop_count(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePopCount => { self.pop_count(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallAddDiscontiguousPredicate => { try_or_throw!( self.machine_st, self.add_discontiguous_predicate(), continue ); self.machine_st.p += 1; } &Instruction::ExecuteAddDiscontiguousPredicate => { try_or_throw!( self.machine_st, self.add_discontiguous_predicate(), continue ); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddDynamicPredicate => { try_or_throw!(self.machine_st, self.add_dynamic_predicate(), continue); self.machine_st.p += 1; } &Instruction::ExecuteAddDynamicPredicate => { try_or_throw!(self.machine_st, self.add_dynamic_predicate(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddMultifilePredicate => { try_or_throw!(self.machine_st, self.add_multifile_predicate(), continue); self.machine_st.p += 1; } &Instruction::ExecuteAddMultifilePredicate => { try_or_throw!(self.machine_st, self.add_multifile_predicate(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddGoalExpansionClause => { try_or_throw!(self.machine_st, self.add_goal_expansion_clause(), continue); self.machine_st.p += 1; } &Instruction::ExecuteAddGoalExpansionClause => { try_or_throw!(self.machine_st, self.add_goal_expansion_clause(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddTermExpansionClause => { try_or_throw!(self.machine_st, self.add_term_expansion_clause(), continue); self.machine_st.p += 1; } &Instruction::ExecuteAddTermExpansionClause => { try_or_throw!(self.machine_st, self.add_term_expansion_clause(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddInSituFilenameModule => { try_or_throw!( self.machine_st, self.add_in_situ_filename_module(), continue ); self.machine_st.p += 1; } &Instruction::ExecuteAddInSituFilenameModule => { try_or_throw!( self.machine_st, self.add_in_situ_filename_module(), continue ); self.machine_st.p = self.machine_st.cp; } &Instruction::CallClauseToEvacuable => { try_or_throw!(self.machine_st, self.clause_to_evacuable(), continue); self.machine_st.p += 1; } &Instruction::ExecuteClauseToEvacuable => { try_or_throw!(self.machine_st, self.clause_to_evacuable(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallScopedClauseToEvacuable => { try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable(), continue); self.machine_st.p += 1; } &Instruction::ExecuteScopedClauseToEvacuable => { try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallConcludeLoad => { try_or_throw!(self.machine_st, self.conclude_load(), continue); self.machine_st.p += 1; } &Instruction::ExecuteConcludeLoad => { try_or_throw!(self.machine_st, self.conclude_load(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallDeclareModule => { try_or_throw!(self.machine_st, self.declare_module(), continue); self.machine_st.p += 1; } &Instruction::ExecuteDeclareModule => { try_or_throw!(self.machine_st, self.declare_module(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallLoadCompiledLibrary => { try_or_throw!(self.machine_st, self.load_compiled_library(), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadCompiledLibrary => { try_or_throw!(self.machine_st, self.load_compiled_library(), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadContextSource => { self.load_context_source(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadContextSource => { self.load_context_source(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadContextFile => { self.load_context_file(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadContextFile => { self.load_context_file(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadContextDirectory => { self.load_context_directory(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadContextDirectory => { self.load_context_directory(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadContextModule => { self.load_context_module(self.deref_register(1)); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadContextModule => { self.load_context_module(self.deref_register(1)); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadContextStream => { self.load_context_stream(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteLoadContextStream => { self.load_context_stream(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPopLoadContext => { self.pop_load_context(); self.machine_st.p += 1; } &Instruction::ExecutePopLoadContext => { self.pop_load_context(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPopLoadStatePayload => { self.pop_load_state_payload(); self.machine_st.p += 1; } &Instruction::ExecutePopLoadStatePayload => { self.pop_load_state_payload(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPushLoadContext => { try_or_throw!(self.machine_st, self.push_load_context(), continue); self.machine_st.p += 1; } &Instruction::ExecutePushLoadContext => { try_or_throw!(self.machine_st, self.push_load_context(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPushLoadStatePayload => { self.push_load_state_payload(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePushLoadStatePayload => { self.push_load_state_payload(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallUseModule => { try_or_throw!(self.machine_st, self.use_module(), continue); self.machine_st.p += 1; } &Instruction::ExecuteUseModule => { try_or_throw!(self.machine_st, self.use_module(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallBuiltInProperty => { let key = self.machine_st.read_predicate_key( self.machine_st.registers[1], self.machine_st.registers[2], ); self.machine_st.fail = !self.indices.builtin_property(key); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteBuiltInProperty => { let key = self.machine_st.read_predicate_key( self.machine_st.registers[1], self.machine_st.registers[2], ); self.machine_st.fail = !self.indices.builtin_property(key); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallMetaPredicateProperty => { self.meta_predicate_property(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteMetaPredicateProperty => { self.meta_predicate_property(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallMultifileProperty => { self.multifile_property(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteMultifileProperty => { self.multifile_property(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDiscontiguousProperty => { self.discontiguous_property(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDiscontiguousProperty => { self.discontiguous_property(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDynamicProperty => { self.dynamic_property(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDynamicProperty => { self.dynamic_property(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallAbolishClause => { try_or_throw!(self.machine_st, self.abolish_clause(), continue); self.machine_st.p += 1; } &Instruction::ExecuteAbolishClause => { try_or_throw!(self.machine_st, self.abolish_clause(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAsserta => { try_or_throw!( self.machine_st, self.compile_assert(AppendOrPrepend::Prepend), continue ); self.machine_st.p += 1; } &Instruction::ExecuteAsserta => { try_or_throw!( self.machine_st, self.compile_assert(AppendOrPrepend::Prepend), continue ); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAssertz => { try_or_throw!( self.machine_st, self.compile_assert(AppendOrPrepend::Append), continue ); self.machine_st.p += 1; } &Instruction::ExecuteAssertz => { try_or_throw!( self.machine_st, self.compile_assert(AppendOrPrepend::Append), continue ); self.machine_st.p = self.machine_st.cp; } &Instruction::CallRetract => { try_or_throw!(self.machine_st, self.retract_clause(), continue); self.machine_st.p += 1; } &Instruction::ExecuteRetract => { try_or_throw!(self.machine_st, self.retract_clause(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallIsConsistentWithTermQueue => { try_or_throw!( self.machine_st, self.is_consistent_with_term_queue(), continue ); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteIsConsistentWithTermQueue => { try_or_throw!( self.machine_st, self.is_consistent_with_term_queue(), continue ); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::CallFlushTermQueue => { try_or_throw!(self.machine_st, self.flush_term_queue(), continue); self.machine_st.p += 1; } &Instruction::ExecuteFlushTermQueue => { try_or_throw!(self.machine_st, self.flush_term_queue(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallRemoveModuleExports => { try_or_throw!(self.machine_st, self.remove_module_exports(), continue); self.machine_st.p += 1; } &Instruction::ExecuteRemoveModuleExports => { try_or_throw!(self.machine_st, self.remove_module_exports(), continue); self.machine_st.p = self.machine_st.cp; } &Instruction::CallAddNonCountedBacktracking => { try_or_throw!( self.machine_st, self.add_non_counted_backtracking(), continue ); self.machine_st.p += 1; } &Instruction::ExecuteAddNonCountedBacktracking => { try_or_throw!( self.machine_st, self.add_non_counted_backtracking(), continue ); self.machine_st.p = self.machine_st.cp; } &Instruction::CallPredicateDefined => { self.machine_st.fail = !self.predicate_defined(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePredicateDefined => { self.machine_st.fail = !self.predicate_defined(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallStripModule => { self.strip_module(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteStripModule => { self.strip_module(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPrepareCallClause(arity) => { try_or_throw!(self.machine_st, self.prepare_call_clause(arity), continue); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePrepareCallClause(arity) => { try_or_throw!(self.machine_st, self.prepare_call_clause(arity), continue); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCompileInlineOrExpandedGoal => { try_or_throw!( self.machine_st, self.compile_inline_or_expanded_goal(), continue ); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteCompileInlineOrExpandedGoal => { try_or_throw!( self.machine_st, self.compile_inline_or_expanded_goal(), continue ); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallIsExpandedOrInlined => { self.machine_st.fail = !self.is_expanded_or_inlined(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteIsExpandedOrInlined => { self.machine_st.fail = !self.is_expanded_or_inlined(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallFastCallN(arity) => { let call_at_index = |wam: &mut Machine, name, arity, ptr| wam.try_call(name, arity, ptr); try_or_throw!( self.machine_st, self.fast_call(arity, call_at_index), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::ExecuteFastCallN(arity) => { let call_at_index = |wam: &mut Machine, name, arity, ptr| wam.try_execute(name, arity, ptr); try_or_throw!( self.machine_st, self.fast_call(arity, call_at_index), continue ); if self.machine_st.fail { self.machine_st.backtrack(); } } &Instruction::CallGetClauseP => { let module_name = cell_as_atom!(self.deref_register(3)); let (n, p) = self.get_clause_p(module_name); let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); let mut writer = Heap::functor_writer(functor!(atom!("-"), [fixnum(n), fixnum(p)])); let str_cell = backtrack_on_resource_error!( &mut self.machine_st, writer(&mut self.machine_st.heap), continue ); let r = r.as_var().unwrap(); self.machine_st.bind(r, str_cell); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetClauseP => { let module_name = cell_as_atom!(self.deref_register(3)); let (n, p) = self.get_clause_p(module_name); let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); let mut writer = Heap::functor_writer(functor!(atom!("-"), [fixnum(n), fixnum(p)])); let str_cell = backtrack_on_resource_error!( &mut self.machine_st, writer(&mut self.machine_st.heap), continue ); let r = r.as_var().unwrap(); self.machine_st.bind(r, str_cell); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInvokeClauseAtP => { let key_cell = self.machine_st.registers[1]; let key = self.machine_st.name_and_arity_from_heap(key_cell).unwrap(); let l = self.machine_st.registers[3]; let l = self.machine_st.store(self.machine_st.deref(l)); let l = match Number::try_from((l, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(l)) => l.get_num() as usize, _ => unreachable!(), }; let p = self.machine_st.registers[4]; let p = self.machine_st.store(self.machine_st.deref(p)); let p = match Number::try_from((p, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(p)) => p.get_num() as usize, _ => unreachable!(), }; let module_name = cell_as_atom!(self.deref_register(6)); let compilation_target = match module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; let skeleton = self .indices .get_predicate_skeleton_mut(&compilation_target, &key) .unwrap(); if let Some(n) = skeleton.target_pos_of_clause_clause_loc(l) { let r = self .machine_st .store(self.machine_st.deref(self.machine_st.registers[5])); self.machine_st.unify_fixnum( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(n as i64) }, r, ); } self.machine_st.call_at_index(2, p); } &Instruction::ExecuteInvokeClauseAtP => { let key_cell = self.machine_st.registers[1]; let key = self.machine_st.name_and_arity_from_heap(key_cell).unwrap(); let l = self.machine_st.registers[3]; let l = self.machine_st.store(self.machine_st.deref(l)); let l = match Number::try_from((l, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(l)) => l.get_num() as usize, _ => unreachable!(), }; let p = self.machine_st.registers[4]; let p = self.machine_st.store(self.machine_st.deref(p)); let p = match Number::try_from((p, &self.machine_st.arena.f64_tbl)) { Ok(Number::Fixnum(p)) => p.get_num() as usize, _ => unreachable!(), }; let module_name = cell_as_atom!(self.deref_register(6)); let compilation_target = match module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(module_name), }; let skeleton = self .indices .get_predicate_skeleton_mut(&compilation_target, &key) .unwrap(); if let Some(n) = skeleton.target_pos_of_clause_clause_loc(l) { let r = self .machine_st .store(self.machine_st.deref(self.machine_st.registers[5])); self.machine_st.unify_fixnum( /* FIXME this is not safe */ unsafe { Fixnum::build_with_unchecked(n as i64) }, r, ); } self.machine_st.execute_at_index(2, p); } &Instruction::CallGetFromAttributedVarList => { self.get_from_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetFromAttributedVarList => { self.get_from_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPutToAttributedVarList => { self.put_to_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecutePutToAttributedVarList => { self.put_to_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDeleteFromAttributedVarList => { self.delete_from_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteDeleteFromAttributedVarList => { self.delete_from_attributed_variable_list(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallDeleteAllAttributesFromVar => { self.delete_all_attributes_from_var(); self.machine_st.p += 1; } &Instruction::ExecuteDeleteAllAttributesFromVar => { self.delete_all_attributes_from_var(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallUnattributedVar => { self.machine_st.unattributed_var(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteUnattributedVar => { self.machine_st.unattributed_var(); self.machine_st.p = self.machine_st.cp; } &Instruction::CallGetDBRefs => { self.get_db_refs(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteGetDBRefs => { self.get_db_refs(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } &Instruction::CallInferenceLimitExceeded => { self.inference_limit_exceeded(); step_or_fail!(self.machine_st, self.machine_st.p += 1); } &Instruction::ExecuteInferenceLimitExceeded => { self.inference_limit_exceeded(); step_or_fail!(self.machine_st, self.machine_st.p = self.machine_st.cp); } } } self.machine_st.check_for_interrupt(); } std::process::ExitCode::SUCCESS } } #[cold] // this is a seperate function so that we can annotate it as cold #[track_caller] fn handle_code_index_oob(code_len: usize, p: usize) -> ! { panic!("code pointer p = {p} is oob for code area of size {code_len}"); }