use prolog_parser::ast::*; use prolog_parser::parser::*; use prolog_parser::string_list::*; use prolog_parser::tabled_rc::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; use crate::prolog::heap_print::*; use crate::prolog::instructions::*; use crate::prolog::machine::code_repo::CodeRepo; use crate::prolog::machine::copier::*; use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; use crate::prolog::machine::toplevel::to_op_decl; use crate::prolog::ordered_float::OrderedFloat; use crate::prolog::read::{readline, PrologStream}; use crate::prolog::rug::Integer; use crate::ref_thread_local::RefThreadLocal; use indexmap::{IndexMap, IndexSet}; use std::collections::VecDeque; use std::io::{stdout, Write}; use std::iter::once; use std::mem; use std::rc::Rc; struct BrentAlgState { hare: usize, tortoise: usize, power: usize, steps: usize, } impl BrentAlgState { fn new(hare: usize) -> Self { BrentAlgState { hare, tortoise: hare, power: 2, steps: 1, } } } fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque, after_idx: &mut usize) { for (idx, instr) in code[*after_idx..].iter().enumerate() { match instr { &Line::Choice(ChoiceInstruction::TrustMe) | &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => { *after_idx += idx; return; } &Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => { jmp_offsets.push_back(*after_idx + idx + offset) } _ => {} } } } fn is_builtin_predicate(name: &ClauseName) -> bool { let in_builtins = name.owning_module().as_str() == "builtins"; let hidden_name = name.as_str().starts_with("$"); in_builtins || hidden_name } impl MachineState { // a step in Brent's algorithm. fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option { match self.heap[brent_st.hare].clone() { HeapCellValue::NamedStr(..) => Some(CycleSearchResult::NotList), HeapCellValue::Addr(addr) => match self.store(self.deref(addr)) { Addr::Con(Constant::EmptyList) => { Some(CycleSearchResult::ProperList(brent_st.steps)) } Addr::HeapCell(_) | Addr::StackCell(..) => Some(CycleSearchResult::PartialList( brent_st.steps, brent_st.hare, )), Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_chars() => { Some(CycleSearchResult::String(brent_st.steps, s.clone())) } Addr::Lis(l) => { brent_st.hare = l + 1; brent_st.steps += 1; if brent_st.tortoise == brent_st.hare { return Some(CycleSearchResult::NotList); } else if brent_st.steps == brent_st.power { brent_st.tortoise = brent_st.hare; brent_st.power <<= 1; } None } _ => Some(CycleSearchResult::NotList), }, } } pub(super) fn detect_cycles_with_max(&self, max_steps: usize, addr: Addr) -> CycleSearchResult { let addr = self.store(self.deref(addr)); let hare = match addr { Addr::Lis(offset) if max_steps > 0 => offset + 1, Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset), Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, Addr::Con(Constant::String(ref s)) if !self.flags.double_quotes.is_atom() => { return CycleSearchResult::String(0, s.clone()) } _ => return CycleSearchResult::NotList, }; let mut brent_st = BrentAlgState::new(hare); loop { if brent_st.steps == max_steps { return CycleSearchResult::PartialList(brent_st.steps, brent_st.hare); } if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } pub(super) fn detect_cycles(&self, addr: Addr) -> CycleSearchResult { let addr = self.store(self.deref(addr)); let hare = match addr { Addr::Lis(offset) => offset + 1, Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, Addr::Con(Constant::String(ref s)) if !self.flags.double_quotes.is_atom() => { return CycleSearchResult::String(0, s.clone()) } _ => return CycleSearchResult::NotList, }; let mut brent_st = BrentAlgState::new(hare); loop { if let Some(result) = self.brents_alg_step(&mut brent_st) { return result; } } } fn finalize_skip_max_list(&mut self, n: usize, addr: Addr) { let target_n = self[temp_v!(1)].clone(); self.unify(Addr::Con(Constant::Integer(Integer::from(n))), target_n); if !self.fail { let xs = self[temp_v!(4)].clone(); self.unify(addr, xs); } } pub(super) fn skip_max_list(&mut self) -> CallResult { let max_steps = self.store(self.deref(self[temp_v!(2)].clone())); match max_steps { Addr::Con(Constant::Integer(ref max_steps)) => { if max_steps.to_isize().map(|i| i >= -1).unwrap_or(false) { let n = self.store(self.deref(self[temp_v!(1)].clone())); match n { Addr::Con(Constant::Integer(ref n)) if n == &0 => { let xs0 = self[temp_v!(3)].clone(); let xs = self[temp_v!(4)].clone(); self.unify(xs0, xs); } _ => { let (max_steps, search_result) = if let Some(max_steps) = max_steps.to_isize() { ( max_steps, if max_steps == -1 { self.detect_cycles(self[temp_v!(3)].clone()) } else { self.detect_cycles_with_max( max_steps as usize, self[temp_v!(3)].clone(), ) }, ) } else { (-1, self.detect_cycles(self[temp_v!(3)].clone())) }; match search_result { CycleSearchResult::String(n, s) => { if max_steps == -1 { self.finalize_skip_max_list( n + s.len(), Addr::Con(Constant::EmptyList), ) } else { let i = (max_steps as usize) - n; if s.len() < i { self.finalize_skip_max_list( n + s.len(), Addr::Con(Constant::EmptyList), ) } else { let s = StringList::new(s.char_span(i), s.is_expandable()); self.finalize_skip_max_list( i + n, Addr::Con(Constant::String(s)), ) } } } CycleSearchResult::UntouchedList(l) => { self.finalize_skip_max_list(0, Addr::Lis(l)) } CycleSearchResult::EmptyList => { self.finalize_skip_max_list(0, Addr::Con(Constant::EmptyList)) } CycleSearchResult::PartialList(n, hc) => { self.finalize_skip_max_list(n, Addr::HeapCell(hc)) } CycleSearchResult::ProperList(n) => { self.finalize_skip_max_list(n, Addr::Con(Constant::EmptyList)) } CycleSearchResult::NotList => { let xs0 = self[temp_v!(3)].clone(); self.finalize_skip_max_list(0, xs0); } } } } } else { self.fail = true; } } Addr::HeapCell(_) | Addr::StackCell(..) => { let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); return Err(self.error_form(MachineError::instantiation_error(), stub)); } addr => { let stub = MachineError::functor_stub(clause_name!("$skip_max_list"), 4); return Err( self.error_form(MachineError::type_error(ValidType::Integer, addr), stub) ); } }; Ok(()) } fn read_term(&mut self, current_input_stream: &mut PrologStream, indices: &mut IndexStore) -> CallResult { match self.read( current_input_stream, indices.atom_tbl.clone(), &indices.op_dir, ) { Ok(term_write_result) => { let a1 = self[temp_v!(1)].clone(); self.unify(Addr::HeapCell(term_write_result.heap_loc), a1); if self.fail { return Ok(()); } let mut list_of_var_eqs = vec![]; for (var, binding) in term_write_result.var_dict.into_iter().rev() { let var_atom = clause_name!(var.to_string(), indices.atom_tbl); let var_atom = Constant::Atom(var_atom, None); let h = self.heap.h; let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom))); self.heap.push(HeapCellValue::Addr(binding)); list_of_var_eqs.push(Addr::Str(h)); } let a2 = self[temp_v!(2)].clone(); let list_offset = Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); Ok(self.unify(list_offset, a2)) } Err(err) => { if let ParserError::UnexpectedEOF = err { std::process::exit(0); } // reset the input stream after an input failure. *current_input_stream = readline::input_stream(); let h = self.heap.h; let syntax_error = MachineError::syntax_error(h, err); let stub = MachineError::functor_stub(clause_name!("read_term"), 2); Err(self.error_form(syntax_error, stub)) } } } #[inline] fn install_new_block(&mut self, r: RegType) -> usize { self.block = self.b; let c = Constant::Usize(self.block); let addr = self[r].clone(); self.write_constant_to_var(addr, c); self.block } fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: Addr) -> usize { let threshold = self.lifted_heap.len() - lh_offset; let mut copy_ball_term = CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut self.lifted_heap); copy_ball_term.push(HeapCellValue::Addr(Addr::Lis(threshold + 1))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 3))); copy_ball_term.push(HeapCellValue::Addr(Addr::HeapCell(threshold + 2))); copy_term(copy_ball_term, copy_target); threshold + lh_offset + 2 } fn repl_redirect(&mut self, repl_code_ptr: REPLCodePtr) -> CallResult { let p = if self.last_call { self.cp } else { self.p.local() + 1 }; Ok(self.p = CodePtr::REPL(repl_code_ptr, p)) } fn truncate_if_no_lifted_heap_diff(&mut self, addr_constr: AddrConstr) where AddrConstr: Fn(usize) -> Addr, { match self.store(self.deref(self[temp_v!(1)].clone())) { Addr::Con(Constant::Usize(lh_offset)) => { if lh_offset >= self.lifted_heap.len() { self.lifted_heap.truncate(lh_offset); } else { let threshold = self.lifted_heap.len() - lh_offset; self.lifted_heap .push(HeapCellValue::Addr(addr_constr(threshold))); } } _ => self.fail = true, } } fn get_next_db_ref(&mut self, indices: &IndexStore, db_ref: &DBRef) { match db_ref { &DBRef::NamedPred(ref name, arity, _) => { let key = (name.clone(), arity); let mut iter = indices.code_dir.range(key..).skip(1); while let Some(((name, arity), idx)) = iter.next() { if idx.is_undefined() { self.fail = true; return; } if is_builtin_predicate(&name) { continue; } let a2 = self[temp_v!(2)].clone(); if let Some(r) = a2.as_var() { let spec = get_clause_spec(name.clone(), *arity, composite_op!(&indices.op_dir)); self.bind(r, Addr::DBRef(DBRef::NamedPred(name.clone(), *arity, spec))); return; } } self.fail = true; } &DBRef::Op(_, spec, ref name, ref op_dir, _) => { let fixity = match spec { XF | YF => Fixity::Post, FX | FY => Fixity::Pre, _ => Fixity::In, }; let key = OrderedOpDirKey(name.clone(), fixity); match op_dir.range(key..).skip(1).next() { Some((OrderedOpDirKey(name, _), (priority, spec))) => { let a2 = self[temp_v!(2)].clone(); if let Some(r) = a2.as_var() { self.bind( r, Addr::DBRef(DBRef::Op( *priority, *spec, name.clone(), op_dir.clone(), SharedOpDesc::new(*priority, *spec), )), ); } else { self.fail = true; } } None => self.fail = true, } } } } fn int_to_char_code( &mut self, n: &Integer, stub: &'static str, arity: usize, ) -> Result { if let Some(c) = n.to_u8() { Ok(c) } else { let stub = MachineError::functor_stub(clause_name!(stub), arity); let err = MachineError::representation_error(RepFlag::CharacterCode); let err = self.error_form(err, stub); Err(err) } } fn parse_number_from_string( &mut self, mut string: String, indices: &IndexStore, stub: MachineStub, ) -> CallResult { let nx = self[temp_v!(2)].clone(); if let Some(c) = string.chars().last() { if layout_char!(c) { let (line_num, col_num) = string.chars().fold((0, 0), |(line_num, col_num), c| { if new_line_char!(c) { (1 + line_num, 0) } else { (line_num, col_num + 1) } }); let err = ParserError::UnexpectedChar(c, line_num, col_num); let h = self.heap.h; let err = MachineError::syntax_error(h, err); return Err(self.error_form(err, stub)); } } string.push('.'); let mut stream = parsing_stream(std::io::Cursor::new(string)); let mut parser = Parser::new(&mut stream, indices.atom_tbl.clone(), self.machine_flags()); match parser.read_term(composite_op!(&indices.op_dir)) { Err(err) => { let h = self.heap.h; let err = MachineError::syntax_error(h, err); return Err(self.error_form(err, stub)); } Ok(Term::Constant(_, Constant::Rational(n))) => { self.unify(nx, Addr::Con(Constant::Rational(n))) } Ok(Term::Constant(_, Constant::Float(n))) => { self.unify(nx, Addr::Con(Constant::Float(n))) } Ok(Term::Constant(_, Constant::Integer(n))) => { self.unify(nx, Addr::Con(Constant::Integer(n))) } Ok(Term::Constant(_, Constant::CharCode(c))) => { self.unify(nx, Addr::Con(Constant::CharCode(c))) } _ => { let err = ParserError::ParseBigInt(0, 0); let h = self.heap.h; let err = MachineError::syntax_error(h, err); return Err(self.error_form(err, stub)); } } Ok(()) } fn create_instruction_functors(&mut self, code: &Code, first_idx: usize) -> Vec { let mut queue = VecDeque::new(); let mut functors = vec![]; let mut h = self.heap.h; queue.push_back(first_idx); while let Some(first_idx) = queue.pop_front() { let mut last_idx = first_idx; loop { match &code[last_idx] { &Line::Choice(ChoiceInstruction::TryMeElse(..)) | &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => { last_idx += 1; scan_for_trust_me(code, &mut queue, &mut last_idx); } &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { queue.push_back(last_idx + offset); last_idx += 1; } &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => { queue.push_back(last_idx + offset); break; } &Line::Control(ControlInstruction::Proceed) | &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => break, _ => last_idx += 1, }; } for instr in &code[first_idx..last_idx + 1] { let section = instr.to_functor(h); functors.push(Addr::HeapCell(h)); h += section.len(); self.heap.extend(section.into_iter()); } } functors } pub(super) fn system_call( &mut self, ct: &SystemClauseType, code_repo: &CodeRepo, indices: &mut IndexStore, call_policy: &mut Box, cut_policy: &mut Box, current_input_stream: &mut PrologStream, ) -> CallResult { match ct { &SystemClauseType::AbolishClause => { let p = self.cp; let trans_type = DynamicTransactionType::Abolish; self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::AbolishModuleClause => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleAbolish; self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::AssertDynamicPredicateToFront => { let p = self.cp; let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front); self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::AssertDynamicPredicateToBack => { let p = self.cp; let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back); self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::AtomChars => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { Addr::Con(Constant::Char(c)) => { let iter = once(Addr::Con(Constant::Char(c))); let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)].clone(); self.unify(a2, list_of_chars); } Addr::Con(Constant::Atom(name, _)) => { let iter = name.as_str().chars().map(|c| Addr::Con(Constant::Char(c))); let list_of_chars = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)].clone(); self.unify(a2, list_of_chars); } Addr::Con(Constant::EmptyList) => { let a2 = self[temp_v!(2)].clone(); let chars = vec![ Addr::Con(Constant::Char('[')), Addr::Con(Constant::Char(']')), ]; let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); self.unify(a2, list_of_chars); } ref addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("atom_chars"), 2); match self.try_from_list(temp_v!(2), stub.clone()) { Err(e) => return Err(e), Ok(addrs) => match self.try_char_list(addrs) { Ok(string) => { let chars = clause_name!(string, indices.atom_tbl); self.unify( addr.clone(), Addr::Con(Constant::Atom(chars, None)), ); } Err(err) => return Err(self.error_form(err, stub)), }, } } _ => unreachable!(), }; } &SystemClauseType::AtomCodes => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { Addr::Con(Constant::Char(c)) => { let iter = once(Addr::Con(Constant::CharCode(c as u8))); let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)].clone(); self.unify(a2, list_of_codes); } Addr::Con(Constant::Atom(name, _)) => { let iter = name .as_str() .chars() .map(|c| Addr::Con(Constant::CharCode(c as u8))); let list_of_codes = Addr::HeapCell(self.heap.to_list(iter)); let a2 = self[temp_v!(2)].clone(); self.unify(a2, list_of_codes); } Addr::Con(Constant::EmptyList) => { let a2 = self[temp_v!(2)].clone(); let chars = vec![ Addr::Con(Constant::CharCode('[' as u8)), Addr::Con(Constant::CharCode(']' as u8)), ]; let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter())); self.unify(a2, list_of_codes); } ref addr if addr.is_ref() => { let stub = MachineError::functor_stub(clause_name!("atom_codes"), 2); match self.try_from_list(temp_v!(2), stub.clone()) { Err(e) => return Err(e), Ok(addrs) => { let mut chars = String::new(); for addr in addrs.iter() { match addr { &Addr::Con(Constant::Integer(ref n)) => { let c = self.int_to_char_code(&n, "atom_codes", 2)?; chars.push(c as char); } &Addr::Con(Constant::CharCode(c)) => chars.push(c as char), _ => { let err = MachineError::type_error( ValidType::Integer, addr.clone(), ); return Err(self.error_form(err, stub)); } } } let chars = clause_name!(chars, indices.atom_tbl); self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None))); } } } _ => unreachable!(), }; } &SystemClauseType::AtomLength => { let a1 = self[temp_v!(1)].clone(); let atom = match self.store(self.deref(a1)) { Addr::Con(Constant::Atom(name, _)) => name, Addr::Con(Constant::EmptyList) => clause_name!("[]"), Addr::Con(Constant::Char(c)) => clause_name!(c.to_string(), indices.atom_tbl), _ => unreachable!(), }; let len = Integer::from(atom.as_str().len()); let a2 = self[temp_v!(2)].clone(); self.unify(a2, Addr::Con(Constant::Integer(len))); } &SystemClauseType::CharsToNumber => { let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); match self.try_from_list(temp_v!(1), stub.clone()) { Err(e) => return Err(e), Ok(addrs) => match self.try_char_list(addrs) { Ok(string) => self.parse_number_from_string(string, indices, stub)?, Err(err) => return Err(self.error_form(err, stub)), }, } } &SystemClauseType::NumberToChars => { let n = self[temp_v!(1)].clone(); let chs = self[temp_v!(2)].clone(); let string = match self.store(self.deref(n)) { Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), Addr::Con(Constant::Integer(n)) => n.to_string(), _ => unreachable!(), }; let chars = string.trim().chars().map(|c| Addr::Con(Constant::Char(c))); let char_list = Addr::HeapCell(self.heap.to_list(chars)); self.unify(char_list, chs); } &SystemClauseType::NumberToCodes => { let n = self[temp_v!(1)].clone(); let chs = self[temp_v!(2)].clone(); let string = match self.store(self.deref(n)) { Addr::Con(Constant::Float(OrderedFloat(n))) => format!("{0:<20?}", n), Addr::Con(Constant::Integer(n)) => n.to_string(), _ => unreachable!(), }; let codes = string .trim() .chars() .map(|c| Addr::Con(Constant::CharCode(c as u8))); let codes_list = Addr::HeapCell(self.heap.to_list(codes)); self.unify(codes_list, chs); } &SystemClauseType::CodesToNumber => { let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); match self.try_from_list(temp_v!(1), stub.clone()) { Err(e) => return Err(e), Ok(addrs) => match self.try_code_list(addrs) { Ok(codes) => { let string = codes.iter().map(|c| *c as char).collect(); self.parse_number_from_string(string, indices, stub)? } Err(err) => return Err(self.error_form(err, stub)), }, } } &SystemClauseType::ModuleAssertDynamicPredicateToFront => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front); self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::ModuleAssertDynamicPredicateToBack => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Back); self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::LiftedHeapLength => { let a1 = self[temp_v!(1)].clone(); let lh_len = Addr::Con(Constant::Usize(self.lifted_heap.len())); self.unify(a1, lh_len); } &SystemClauseType::CharCode => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { Addr::Con(Constant::Atom(name, _)) => { let c = name.as_str().chars().next().unwrap(); let a2 = self[temp_v!(2)].clone(); self.unify(Addr::Con(Constant::CharCode(c as u8)), a2); } Addr::Con(Constant::Char(c)) => { let a2 = self[temp_v!(2)].clone(); self.unify(Addr::Con(Constant::CharCode(c as u8)), a2); } ref addr if addr.is_ref() => { let a2 = self[temp_v!(2)].clone(); match self.store(self.deref(a2)) { Addr::Con(Constant::CharCode(code)) => { self.unify(Addr::Con(Constant::Char(code as char)), addr.clone()) } Addr::Con(Constant::Integer(n)) => { let c = self.int_to_char_code(&n, "char_code", 2)?; self.unify(Addr::Con(Constant::Char(c as char)), addr.clone()); } _ => self.fail = true, }; } _ => unreachable!(), }; } &SystemClauseType::CheckCutPoint => { let addr = self.store(self.deref(self[temp_v!(1)].clone())); match addr { Addr::Con(Constant::Usize(old_b)) if self.b <= old_b + 2 => {} _ => self.fail = true, }; } &SystemClauseType::FetchGlobalVar => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; let addr = self[temp_v!(2)].clone(); match indices.global_variables.get_mut(&key) { Some((ref mut ball, None)) => { let h = self.heap.h; let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); self.unify(addr, Addr::HeapCell(h)); } Some((_, Some(h))) => { self.unify(addr, Addr::HeapCell(*h)) } None => self.fail = true, }; } &SystemClauseType::FetchGlobalVarWithOffset => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; let addr = self[temp_v!(2)].clone(); match indices.global_variables.get_mut(&key) { Some((ref mut ball, ref mut offset @ None)) => { let h = self.heap.h; let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); self.unify(addr, Addr::HeapCell(h)); *offset = Some(h); } Some((_, Some(h))) => { let offset = self[temp_v!(3)].clone(); self.unify(offset, Addr::Con(Constant::Usize(*h))); if !self.fail { self.unify(addr, Addr::HeapCell(*h)); } } None => { self.fail = true } }; } &SystemClauseType::GetChar => { let result = current_input_stream.next(); let a1 = self[temp_v!(1)].clone(); match result { Some(Ok(b)) => self.unify(Addr::Con(Constant::Char(b as char)), a1), Some(Err(_)) => { let end_of_file = clause_name!("end_of_file"); self.unify(a1, Addr::Con(Constant::Atom(end_of_file, None))); } None => { let stub = MachineError::functor_stub(clause_name!("get_char"), 1); let err = MachineError::representation_error(RepFlag::Character); let err = self.error_form(err, stub); return Err(err); } } } &SystemClauseType::GetModuleClause => { let module = self[temp_v!(3)].clone(); let head = self[temp_v!(1)].clone(); let module = match self.store(self.deref(module)) { Addr::Con(Constant::Atom(module, _)) => module, _ => { self.fail = true; return Ok(()); } }; let subsection = match self.store(self.deref(head)) { Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(arity, name, ..) => { indices.get_clause_subsection(module, name, arity) } _ => unreachable!(), }, Addr::Con(Constant::Atom(name, _)) => { indices.get_clause_subsection(module, name, 0) } _ => unreachable!(), }; match subsection { Some(dynamic_predicate_info) => { self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p); return Ok(()); } None => self.fail = true, } } &SystemClauseType::ModuleHeadIsDynamic => { let module = self[temp_v!(2)].clone(); let head = self[temp_v!(1)].clone(); let module = match self.store(self.deref(module)) { Addr::Con(Constant::Atom(module, _)) => module, _ => { self.fail = true; return Ok(()); } }; self.fail = !match self.store(self.deref(head)) { Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(arity, name, ..) => { indices.get_clause_subsection(module, name, arity).is_some() } _ => unreachable!(), }, Addr::Con(Constant::Atom(name, _)) => { indices.get_clause_subsection(module, name, 0).is_some() } _ => unreachable!(), }; } &SystemClauseType::HeadIsDynamic => { let head = self[temp_v!(1)].clone(); self.fail = !match self.store(self.deref(head)) { Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(arity, name, ..) => indices .get_clause_subsection(name.owning_module(), name, arity) .is_some(), _ => unreachable!(), }, Addr::Con(Constant::Atom(name, _)) => indices .get_clause_subsection(name.owning_module(), name, 0) .is_some(), _ => unreachable!(), }; } &SystemClauseType::CopyToLiftedHeap => { match self.store(self.deref(self[temp_v!(1)].clone())) { Addr::Con(Constant::Usize(lh_offset)) => { let copy_target = self[temp_v!(2)].clone(); let old_threshold = self.copy_findall_solution(lh_offset, copy_target); let new_threshold = self.lifted_heap.len() - lh_offset; self.lifted_heap[old_threshold] = HeapCellValue::Addr(Addr::HeapCell(new_threshold)); for index in old_threshold + 1..self.lifted_heap.len() { match &mut self.lifted_heap[index] { &mut HeapCellValue::Addr(ref mut addr) => { *addr -= self.heap.len() + lh_offset } _ => {} } } } _ => self.fail = true, } } &SystemClauseType::DeleteAttribute => { let ls0 = self.store(self.deref(self[temp_v!(1)].clone())); if let Addr::Lis(l1) = ls0 { if let Addr::Lis(l2) = self.store(self.deref(Addr::HeapCell(l1 + 1))) { let old_addr = self.heap[l1 + 1].as_addr(l1 + 1); let tail = self.store(self.deref(Addr::HeapCell(l2 + 1))); let tail = if tail.is_ref() { Addr::HeapCell(l1 + 1) } else { tail }; let trail_ref = match old_addr { Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h), Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l), _ => unreachable!() }; self.heap[l1 + 1] = HeapCellValue::Addr(tail); self.trail(trail_ref); } } } &SystemClauseType::DeleteHeadAttribute => { let addr = self.store(self.deref(self[temp_v!(1)].clone())); match addr { Addr::AttrVar(h) => { let addr = self.heap[h + 1].as_addr(h + 1).clone(); let addr = self.store(self.deref(addr)); match addr { Addr::Lis(l) => { let tail = self.store(self.deref(Addr::HeapCell(l + 1))); let tail = if tail.is_ref() { Addr::HeapCell(h + 1) } else { tail }; self.heap[h + 1] = HeapCellValue::Addr(tail); self.trail(TrailRef::AttrVarListLink(h + 1, l)); } _ => unreachable!(), } } _ => unreachable!(), } } &SystemClauseType::DynamicModuleResolution => { let module_name = self.store(self.deref(self[temp_v!(1)].clone())); if let Addr::Con(Constant::Atom(module_name, _)) = module_name { match self.store(self.deref(self[temp_v!(2)].clone())) { Addr::Str(a) => { if let HeapCellValue::NamedStr(arity, name, _) = self.heap[a].clone() { for i in 1..arity + 1 { self.registers[i] = self.heap[a + i].as_addr(a + i); } return self.module_lookup( indices, (name, arity), module_name, true, ); } } Addr::Con(Constant::Atom(name, _)) => { return self.module_lookup(indices, (name, 0), module_name, true) } addr => { let stub = MachineError::functor_stub(clause_name!("(:)"), 2); let type_error = MachineError::type_error(ValidType::Callable, addr); let type_error = self.error_form(type_error, stub); return Err(type_error); } } }; } &SystemClauseType::EnqueueAttributeGoal => { let addr = self[temp_v!(1)].clone(); self.attr_var_init.attribute_goals.push(addr); } &SystemClauseType::EnqueueAttributedVar => { let addr = self[temp_v!(1)].clone(); match self.store(self.deref(addr)) { Addr::AttrVar(h) => self.attr_var_init.attr_var_queue.push(h), _ => {} } } &SystemClauseType::ExpandGoal => { self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)); return Ok(()); } &SystemClauseType::ExpandTerm => { self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0)); return Ok(()); } &SystemClauseType::GetNextDBRef => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { let mut iter = indices.code_dir.iter(); while let Some(((name, arity), _)) = iter.next() { if is_builtin_predicate(&name) { continue; } let spec = get_clause_spec( name.clone(), *arity, composite_op!(&indices.op_dir), ); let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); let r = addr.as_var().unwrap(); self.bind(r, Addr::DBRef(db_ref)); return return_from_clause!(self.last_call, self); } self.fail = true; } Addr::DBRef(DBRef::Op(..)) => self.fail = true, Addr::DBRef(ref db_ref) => self.get_next_db_ref(&indices, db_ref), _ => { self.fail = true; } }; } &SystemClauseType::GetNextOpDBRef => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { addr @ Addr::HeapCell(_) | addr @ Addr::StackCell(..) | addr @ Addr::AttrVar(_) => { let mut unossified_op_dir = OssifiedOpDir::new(); unossified_op_dir.extend(indices.op_dir.iter().filter_map( |(key, op_dir_val)| { let (name, fixity) = key.clone(); let prec = op_dir_val.shared_op_desc().prec(); if prec == 0 { return None; } let assoc = op_dir_val.shared_op_desc().assoc(); Some((OrderedOpDirKey(name, fixity), (prec, assoc))) }, )); let ossified_op_dir = Rc::new(unossified_op_dir); match ossified_op_dir.iter().next() { Some((OrderedOpDirKey(name, _), (priority, spec))) => { let db_ref = DBRef::Op( *priority, *spec, name.clone(), ossified_op_dir.clone(), SharedOpDesc::new(*priority, *spec), ); let r = addr.as_var().unwrap(); self.bind(r, Addr::DBRef(db_ref)); } None => { self.fail = true; return Ok(()); } } } Addr::DBRef(DBRef::NamedPred(..)) => self.fail = true, Addr::DBRef(ref db_ref) => self.get_next_db_ref(&indices, db_ref), _ => { self.fail = true; } } } &SystemClauseType::LookupDBRef => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { Addr::DBRef(db_ref) => match db_ref { DBRef::NamedPred(name, arity, spec) => { let a2 = self[temp_v!(2)].clone(); let a3 = self[temp_v!(3)].clone(); let arity = Integer::from(arity); self.unify(a2, Addr::Con(Constant::Atom(name, spec))); if !self.fail { self.unify(a3, Addr::Con(Constant::Integer(arity))); } } _ => self.fail = true, }, _ => self.fail = true, } } &SystemClauseType::LookupOpDBRef => { let a1 = self[temp_v!(1)].clone(); match self.store(self.deref(a1)) { Addr::DBRef(db_ref) => match db_ref { DBRef::Op(priority, spec, name, _, shared_op_desc) => { let prec = self[temp_v!(2)].clone(); let specifier = self[temp_v!(3)].clone(); let op = self[temp_v!(4)].clone(); let spec = match spec { FX => "fx", FY => "fy", XF => "xf", YF => "yf", XFX => "xfx", XFY => "xfy", YFX => "yfx", _ => { self.fail = true; return Ok(()); } }; let a2 = Integer::from(priority); let a3 = Addr::Con(Constant::Atom(clause_name!(spec), None)); let a4 = Addr::Con(Constant::Atom(name, Some(shared_op_desc))); self.unify(Addr::Con(Constant::Integer(a2)), prec); if !self.fail { self.unify(a3, specifier); } if !self.fail { self.unify(a4, op); } } _ => self.fail = true, }, _ => self.fail = true, } } &SystemClauseType::Maybe => { let result = { let mut rand = RANDOM_STATE.borrow_mut(); if rand.bits(1) == 0 { true } else { false } }; self.fail = result; } &SystemClauseType::OpDeclaration => { let priority = self[temp_v!(1)].clone(); let specifier = self[temp_v!(2)].clone(); let op = self[temp_v!(3)].clone(); let priority = match self.store(self.deref(priority)) { Addr::Con(Constant::Integer(n)) => n.to_usize().unwrap(), _ => unreachable!(), }; let specifier = match self.store(self.deref(specifier)) { Addr::Con(Constant::Atom(name, _)) => name, _ => unreachable!(), }; let op = match self.store(self.deref(op)) { Addr::Con(Constant::Atom(name, _)) => name, Addr::Con(Constant::Char(c)) => clause_name!(c.to_string(), indices.atom_tbl), _ => unreachable!(), }; let module = op.owning_module(); let result = to_op_decl(priority, specifier.as_str(), op) .map_err(SessionError::from) .and_then(|op_decl| { if op_decl.0 == 0 { Ok(op_decl.remove(&mut indices.op_dir)) } else { let spec = get_desc(op_decl.name(), composite_op!(&indices.op_dir)); op_decl.submit(module, spec, &mut indices.op_dir) } }); match result { Ok(()) => {} Err(e) => { // 8.14.3.3 l) let e = MachineError::session_error(self.heap.h, e); let stub = MachineError::functor_stub(clause_name!("op"), 3); let permission_error = self.error_form(e, stub); return Err(permission_error); } }; } &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => { self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) } &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } &SystemClauseType::GetAttributedVariableList => { let attr_var = self.store(self.deref(self[temp_v!(1)].clone())); let attr_var_list = match attr_var { Addr::AttrVar(h) => h + 1, attr_var @ Addr::HeapCell(_) | attr_var @ Addr::StackCell(..) => { // create an AttrVar in the heap. let h = self.heap.h; self.heap.push(HeapCellValue::Addr(Addr::AttrVar(h))); self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h + 1))); self.bind(Ref::AttrVar(h), attr_var); h + 1 } _ => { self.fail = true; return Ok(()); } }; let list_addr = self[temp_v!(2)].clone(); self.unify(Addr::HeapCell(attr_var_list), list_addr); } &SystemClauseType::GetAttrVarQueueDelimiter => { let addr = self[temp_v!(1)].clone(); let value = Addr::Con(Constant::Usize(self.attr_var_init.attr_var_queue.len())); self.unify(addr, value); } &SystemClauseType::GetAttrVarQueueBeyond => { let addr = self[temp_v!(1)].clone(); match self.store(self.deref(addr)) { Addr::Con(Constant::Usize(b)) => { let iter = self.gather_attr_vars_created_since(b); let var_list_addr = Addr::HeapCell(self.heap.to_list(iter)); let list_addr = self[temp_v!(2)].clone(); self.unify(var_list_addr, list_addr); } _ => self.fail = true, } } &SystemClauseType::GetLiftedHeapFromOffsetDiff => { let lh_offset = self[temp_v!(1)].clone(); match self.store(self.deref(lh_offset)) { Addr::Con(Constant::Usize(lh_offset)) => { if lh_offset >= self.lifted_heap.len() { let solutions = self[temp_v!(2)].clone(); let diff = self[temp_v!(3)].clone(); self.unify(solutions, Addr::Con(Constant::EmptyList)); self.unify(diff, Addr::Con(Constant::EmptyList)); } else { let h = self.heap.h; for index in lh_offset..self.lifted_heap.len() { match self.lifted_heap[index].clone() { HeapCellValue::Addr(addr) => { self.heap.push(HeapCellValue::Addr(addr + h)) } value => self.heap.push(value), } } if let Some(HeapCellValue::Addr(addr)) = self.heap.last().cloned() { let diff = self[temp_v!(3)].clone(); self.unify(diff, addr); } self.lifted_heap.truncate(lh_offset); let solutions = self[temp_v!(2)].clone(); self.unify(Addr::HeapCell(h), solutions); } } _ => self.fail = true, } } &SystemClauseType::GetLiftedHeapFromOffset => { let lh_offset = self[temp_v!(1)].clone(); match self.store(self.deref(lh_offset)) { Addr::Con(Constant::Usize(lh_offset)) => { if lh_offset >= self.lifted_heap.len() { let solutions = self[temp_v!(2)].clone(); self.unify(solutions, Addr::Con(Constant::EmptyList)); } else { let h = self.heap.h; for index in lh_offset..self.lifted_heap.len() { match self.lifted_heap[index].clone() { HeapCellValue::Addr(addr) => { self.heap.push(HeapCellValue::Addr(addr + h)) } value => self.heap.push(value), } } self.lifted_heap.truncate(lh_offset); let solutions = self[temp_v!(2)].clone(); self.unify(Addr::HeapCell(h), solutions); } } _ => self.fail = true, } } &SystemClauseType::GetDoubleQuotes => { let a1 = self[temp_v!(1)].clone(); match self.flags.double_quotes { DoubleQuotes::Chars => self.unify(a1, Addr::Con(atom!("chars"))), DoubleQuotes::Atom => self.unify(a1, Addr::Con(atom!("atom"))), DoubleQuotes::Codes => self.unify(a1, Addr::Con(atom!("codes"))), } } &SystemClauseType::GetSCCCleaner => { let dest = self[temp_v!(1)].clone(); match cut_policy.downcast_mut::().ok() { Some(sgc_policy) => { if let Some((addr, b_cutoff, prev_b)) = sgc_policy.pop_cont_pt() { if self.b <= b_cutoff + 1 { self.block = prev_b; if let Some(r) = dest.as_var() { self.bind(r, addr.clone()); return return_from_clause!(self.last_call, self); } } else { sgc_policy.push_cont_pt(addr, b_cutoff, prev_b); } } } None => panic!("expected SCCCutPolicy trait object."), }; self.fail = true; } &SystemClauseType::Halt => std::process::exit(0), &SystemClauseType::InstallSCCCleaner => { let addr = self[temp_v!(1)].clone(); let b = self.b; let prev_block = self.block; if cut_policy.downcast_ref::().is_err() { let (r_c_w_h, r_c_wo_h) = indices.get_cleaner_sites(); *cut_policy = Box::new(SCCCutPolicy::new(r_c_w_h, r_c_wo_h)); } match cut_policy.downcast_mut::().ok() { Some(cut_policy) => { self.install_new_block(temp_v!(2)); cut_policy.push_cont_pt(addr, b, prev_block); } None => panic!( "install_cleaner: should have installed \\ SCCCutPolicy." ), }; } &SystemClauseType::InstallInferenceCounter => { // A1 = B, A2 = L let a1 = self.store(self.deref(self[temp_v!(1)].clone())); let a2 = self.store(self.deref(self[temp_v!(2)].clone())); if call_policy.downcast_ref::().is_err() { CWILCallPolicy::new_in_place(call_policy); } match (a1, a2.clone()) { (Addr::Con(Constant::Usize(bp)), Addr::Con(Constant::Integer(n))) => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { let count = call_policy.add_limit(n, bp); let count = Addr::Con(Constant::Integer(count.clone())); let a3 = self[temp_v!(3)].clone(); self.unify(a3, count); } None => panic!( "install_inference_counter: should have installed \\ CWILCallPolicy." ), } } _ => { let stub = MachineError::functor_stub( clause_name!("call_with_inference_limit"), 3, ); let type_error = self.error_form(MachineError::type_error(ValidType::Integer, a2), stub); self.throw_exception(type_error) } }; } &SystemClauseType::ModuleOf => { let module = self.store(self.deref(self[temp_v!(2)].clone())); match module { Addr::Con(Constant::Atom(name, _)) => { let module = Addr::Con(Constant::Atom(name.owning_module(), None)); let target = self[temp_v!(1)].clone(); self.unify(target, module); } Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(_, name, ..) => { let module = Addr::Con(Constant::Atom(name.owning_module(), None)); let target = self[temp_v!(1)].clone(); self.unify(target, module); } _ => self.fail = true, }, _ => self.fail = true, }; } &SystemClauseType::NoSuchPredicate => { let head = self[temp_v!(1)].clone(); self.fail = match self.store(self.deref(head)) { Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(arity, name, op_spec) => { let module = name.owning_module(); indices.predicate_exists(name, module, arity, op_spec) } _ => unreachable!(), }, Addr::Con(Constant::Atom(name, spec)) => { let module = name.owning_module(); let spec = fetch_atom_op_spec(name.clone(), spec, &indices.op_dir); indices.predicate_exists(name, module, 0, spec) } head => { let err = MachineError::type_error(ValidType::Callable, head); let stub = MachineError::functor_stub(clause_name!("clause"), 2); return Err(self.error_form(err, stub)); } }; } &SystemClauseType::RedoAttrVarBindings => { let bindings = mem::replace(&mut self.attr_var_init.bindings, vec![]); for (h, addr) in bindings { self.heap[h] = HeapCellValue::Addr(addr); } } &SystemClauseType::ResetGlobalVarAtKey => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; indices.global_variables.swap_remove(&key); } &SystemClauseType::ResetGlobalVarAtOffset => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; let value = self[temp_v!(2)].clone(); let mut ball = Ball::new(); let h = self.heap.h; ball.boundary = h; copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, ); let offset = self[temp_v!(3)].clone(); match self.store(self.deref(offset)) { Addr::Con(Constant::Usize(offset)) => { indices.global_variables.insert(key, (ball, Some(offset))) } _ => { indices.global_variables.insert(key, (ball, None)) } }; }, &SystemClauseType::RemoveCallPolicyCheck => { let restore_default = match call_policy.downcast_mut::().ok() { Some(call_policy) => { let a1 = self.store(self.deref(self[temp_v!(1)].clone())); if let Addr::Con(Constant::Usize(bp)) = a1 { if call_policy.is_empty() && bp == self.b { Some(call_policy.into_inner()) } else { None } } else { panic!("remove_call_policy_check: expected Usize in A1."); } } None => panic!( "remove_call_policy_check: requires \\ CWILCallPolicy." ), }; if let Some(new_policy) = restore_default { *call_policy = new_policy; } } &SystemClauseType::RemoveInferenceCounter => { match call_policy.downcast_mut::().ok() { Some(call_policy) => { let a1 = self.store(self.deref(self[temp_v!(1)].clone())); if let Addr::Con(Constant::Usize(bp)) = a1 { let count = call_policy.remove_limit(bp); let count = Addr::Con(Constant::Integer(count.clone())); let a2 = self[temp_v!(2)].clone(); self.unify(a2, count); } else { panic!("remove_inference_counter: expected Usize in A1."); } } None => panic!( "remove_inference_counter: requires \\ CWILCallPolicy." ), } } &SystemClauseType::REPL(repl_code_ptr) => return self.repl_redirect(repl_code_ptr), &SystemClauseType::ModuleRetractClause => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleRetract; self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::RetractClause => { let p = self.cp; let trans_type = DynamicTransactionType::Retract; self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } &SystemClauseType::ReturnFromAttributeGoals => { self.deallocate(); self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0)); return Ok(()); } &SystemClauseType::ReturnFromVerifyAttr => { let e = self.e; let frame_len = self.and_stack[e].len(); for i in 1..frame_len - 1 { self[RegType::Temp(i)] = self.and_stack[e][i].clone(); } if let &Addr::Con(Constant::Usize(b0)) = &self.and_stack[e][frame_len - 1] { self.b0 = b0; } if let &Addr::Con(Constant::Usize(num_of_args)) = &self.and_stack[e][frame_len] { self.num_of_args = num_of_args; } self.deallocate(); self.p = CodePtr::Local(self.and_stack[e].interrupt_cp); return Ok(()); } &SystemClauseType::RestoreCutPolicy => { let restore_default = if let Ok(cut_policy) = cut_policy.downcast_ref::() { cut_policy.out_of_cont_pts() } else { false }; if restore_default { *cut_policy = Box::new(DefaultCutPolicy {}); } } &SystemClauseType::SetCutPoint(r) => { if cut_policy.cut(self, r) { return Ok(()); } } &SystemClauseType::SetCutPointByDefault(r) => deref_cut(self, r), &SystemClauseType::SetDoubleQuotes => match self[temp_v!(1)].clone() { Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "chars" => { self.flags.double_quotes = DoubleQuotes::Chars } Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "atom" => { self.flags.double_quotes = DoubleQuotes::Atom } Addr::Con(Constant::Atom(ref atom, _)) if atom.as_str() == "codes" => { self.flags.double_quotes = DoubleQuotes::Codes } _ => self.fail = true, }, &SystemClauseType::InferenceLevel => { let a1 = self[temp_v!(1)].clone(); let a2 = self.store(self.deref(self[temp_v!(2)].clone())); match a2 { Addr::Con(Constant::Usize(bp)) => { if self.b <= bp + 1 { let a2 = Addr::Con(atom!("!")); self.unify(a1, a2); } else { let a2 = Addr::Con(atom!("true")); self.unify(a1, a2); } } _ => self.fail = true, }; } &SystemClauseType::CleanUpBlock => { let nb = self.store(self.deref(self[temp_v!(1)].clone())); match nb { Addr::Con(Constant::Usize(nb)) => { let b = self.b - 1; if nb > 0 && self.or_stack[b].b == nb { self.b = self.or_stack[nb - 1].b; self.or_stack.truncate(self.b); } } _ => self.fail = true, }; } &SystemClauseType::EraseBall => self.ball.reset(), &SystemClauseType::Fail => self.fail = true, &SystemClauseType::GetBall => { let addr = self.store(self.deref(self[temp_v!(1)].clone())); let h = self.heap.h; if self.ball.stub.len() > 0 { let stub = self.ball.copy_and_align(h); self.heap.append(stub); } else { self.fail = true; return Ok(()); } let ball = self.heap[h].as_addr(h); match addr.as_var() { Some(r) => self.bind(r, ball), _ => self.fail = true, }; } &SystemClauseType::GetCurrentBlock => { let c = Constant::Usize(self.block); let addr = self[temp_v!(1)].clone(); self.write_constant_to_var(addr, c); } &SystemClauseType::GetBValue => { let a1 = self[temp_v!(1)].clone(); let a2 = Addr::Con(Constant::Usize(self.b)); self.unify(a1, a2); } &SystemClauseType::GetClause => { let head = self[temp_v!(1)].clone(); let subsection = match self.store(self.deref(head)) { Addr::Str(s) => match self.heap[s].clone() { HeapCellValue::NamedStr(arity, name, ..) => { indices.get_clause_subsection(name.owning_module(), name, arity) } _ => unreachable!(), }, Addr::Con(Constant::Atom(name, _)) => { indices.get_clause_subsection(name.owning_module(), name, 0) } _ => unreachable!(), }; match subsection { Some(dynamic_predicate_info) => { self.execute_at_index(2, dynamic_predicate_info.clauses_subsection_p); return Ok(()); } _ => unreachable!(), } } &SystemClauseType::GetCutPoint => { let a1 = self[temp_v!(1)].clone(); let a2 = Addr::Con(Constant::Usize(self.b0)); self.unify(a1, a2); } &SystemClauseType::InstallNewBlock => { self.install_new_block(temp_v!(1)); } &SystemClauseType::ReadQueryTerm => { readline::set_prompt(true); let result = self.read_term(current_input_stream, indices); readline::set_prompt(false); let _ = result?; } &SystemClauseType::ReadTerm => { readline::set_prompt(false); self.read_term(current_input_stream, indices)?; }, &SystemClauseType::ResetBlock => { let addr = self.deref(self[temp_v!(1)].clone()); self.reset_block(addr); } &SystemClauseType::SetBall => self.set_ball(), &SystemClauseType::SetSeed => { let seed = self.store(self.deref(self[temp_v!(1)].clone())); let seed = match seed { Addr::Con(Constant::Integer(n)) => n, Addr::Con(Constant::CharCode(c)) => Integer::from(c), Addr::Con(Constant::Rational(r)) => { if r.denom() == &1 { r.numer().clone() } else { self.fail = true; return Ok(()); } } _ => { self.fail = true; return Ok(()); } }; let mut rand = RANDOM_STATE.borrow_mut(); rand.seed(&seed); } &SystemClauseType::SkipMaxList => if let Err(err) = self.skip_max_list() { return Err(err); }, &SystemClauseType::StoreGlobalVar => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; let value = self[temp_v!(2)].clone(); let mut ball = Ball::new(); ball.boundary = self.heap.h; copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value, ); indices.global_variables.insert(key, (ball, None)); } &SystemClauseType::StoreGlobalVarWithOffset => { let key = self[temp_v!(1)].clone(); let key = match self.store(self.deref(key)) { Addr::Con(Constant::Atom(atom, _)) => atom, _ => unreachable!(), }; let value = self[temp_v!(2)].clone(); let mut ball = Ball::new(); let h = self.heap.h; ball.boundary = h; copy_term( CopyBallTerm::new(&mut self.and_stack, &mut self.heap, &mut ball.stub), value.clone(), ); let stub = ball.copy_and_align(h); self.heap.extend(stub.into_iter()); indices.global_variables.insert(key, (ball, Some(h))); self.unify(value, Addr::HeapCell(h)); } &SystemClauseType::Succeed => {} &SystemClauseType::TermVariables => { let a1 = self[temp_v!(1)].clone(); let mut seen_vars = IndexSet::new(); for item in self.acyclic_pre_order_iter(a1) { match item { HeapCellValue::Addr(addr) => { if addr.is_ref() { seen_vars.insert(addr); } } _ => {} } } let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter())); let a2 = self[temp_v!(2)].clone(); self.unify(a2, outcome); } &SystemClauseType::TruncateLiftedHeapTo => { match self.store(self.deref(self[temp_v!(1)].clone())) { Addr::Con(Constant::Usize(lh_offset)) => self.lifted_heap.truncate(lh_offset), _ => self.fail = true, } } &SystemClauseType::UnifyWithOccursCheck => { let a1 = self[temp_v!(1)].clone(); let a2 = self[temp_v!(2)].clone(); self.unify_with_occurs_check(a1, a2); } &SystemClauseType::UnwindStack => self.unwind_stack(), &SystemClauseType::Variant => self.fail = self.structural_eq_test(), &SystemClauseType::WAMInstructions => { let name = self[temp_v!(1)].clone(); let arity = self[temp_v!(2)].clone(); let name = match self.store(self.deref(name)) { Addr::Con(Constant::Atom(name, _)) => name, _ => unreachable!(), }; let arity = match self.store(self.deref(arity)) { Addr::Con(Constant::Integer(n)) => n, _ => unreachable!(), }; let first_idx = match indices .code_dir .get(&(name.clone(), arity.to_usize().unwrap())) { Some(ref idx) => { if let Some(idx) = idx.local() { idx } else { let arity = arity.to_usize().unwrap(); let stub = MachineError::functor_stub(name.clone(), arity); let h = self.heap.h; let err = MachineError::existence_error( h, ExistenceError::Procedure(name, arity), ); let err = self.error_form(err, stub); self.throw_exception(err); return Ok(()); } } None => { let arity = arity.to_usize().unwrap(); let stub = MachineError::functor_stub(name.clone(), arity); let h = self.heap.h; let err = MachineError::existence_error( h, ExistenceError::Procedure(name, arity), ); let err = self.error_form(err, stub); self.throw_exception(err); return Ok(()); } }; let functors = self.create_instruction_functors(&code_repo.code, first_idx); let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter())); let listing_var = self[temp_v!(3)].clone(); self.unify(listing, listing_var); } &SystemClauseType::WriteTerm => { let addr = self[temp_v!(1)].clone(); let ignore_ops = self.store(self.deref(self[temp_v!(2)].clone())); let numbervars = self.store(self.deref(self[temp_v!(3)].clone())); let quoted = self.store(self.deref(self[temp_v!(4)].clone())); let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new()); if let &Addr::Con(Constant::Atom(ref name, ..)) = &ignore_ops { printer.ignore_ops = name.as_str() == "true"; } if let &Addr::Con(Constant::Atom(ref name, ..)) = &numbervars { printer.numbervars = name.as_str() == "true"; } if let &Addr::Con(Constant::Atom(ref name, ..)) = "ed { printer.quoted = name.as_str() == "true"; } let stub = MachineError::functor_stub(clause_name!("write_term"), 2); match self.try_from_list(temp_v!(5), stub.clone()) { Ok(addrs) => { let mut var_names: IndexMap = IndexMap::new(); for addr in addrs { match addr { Addr::Str(s) => match &self.heap[s] { &HeapCellValue::NamedStr(2, ref name, _) if name.as_str() == "=" => { let atom = self.heap[s + 1].as_addr(s + 1); let var = self.heap[s + 2].as_addr(s + 2); let atom = match self.store(self.deref(atom)) { Addr::Con(Constant::Atom(atom, _)) => atom.to_string(), Addr::Con(Constant::Char(c)) => c.to_string(), _ => unreachable!(), }; let var = self.store(self.deref(var)); if var_names.contains_key(&var) { continue; } var_names.insert(var, atom); } _ => unreachable!(), }, _ => unreachable!(), } } printer.var_names = var_names; } Err(err) => return Err(err), } let output = printer.print(addr); print!("{}", output.result()); stdout().flush().unwrap(); } }; return_from_clause!(self.last_call, self) } }