diff --git a/Cargo.toml b/Cargo.toml index fdb62942..e3aea95a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.115" +version = "0.8.116" authors = ["Mark Thom "] build = "build.rs" repository = "https://github.com/mthom/scryer-prolog" diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index cd1dd14b..8f67177d 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -162,8 +162,7 @@ pub enum SystemClauseType { AtomChars, AtomCodes, AtomLength, - ModuleAssertDynamicPredicateToFront, - ModuleAssertDynamicPredicateToBack, + CallAttributeGoals, CharCode, CharsToNumber, CodesToNumber, @@ -176,6 +175,7 @@ pub enum SystemClauseType { EnqueueAttributedVar, ExpandGoal, ExpandTerm, + FetchAttributeGoals, FetchGlobalVar, FetchGlobalVarWithOffset, GetChar, @@ -200,6 +200,8 @@ pub enum SystemClauseType { InstallSCCCleaner, InstallInferenceCounter, LiftedHeapLength, + ModuleAssertDynamicPredicateToFront, + ModuleAssertDynamicPredicateToBack, ModuleOf, ModuleRetractClause, NoSuchPredicate, @@ -229,8 +231,8 @@ pub enum SystemClauseType { GetDoubleQuotes, InstallNewBlock, Maybe, + RawInputReadChar, ResetBlock, - ReturnFromAttributeGoals, ReturnFromVerifyAttr, SetBall, SetCutPointByDefault(RegType), @@ -257,20 +259,12 @@ impl SystemClauseType { &SystemClauseType::AtomChars => clause_name!("$atom_chars"), &SystemClauseType::AtomCodes => clause_name!("$atom_codes"), &SystemClauseType::AtomLength => clause_name!("$atom_length"), - &SystemClauseType::ModuleAssertDynamicPredicateToFront => { - clause_name!("$module_asserta") - } - &SystemClauseType::ModuleAssertDynamicPredicateToBack => { - clause_name!("$module_assertz") - } + &SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"), &SystemClauseType::CharCode => clause_name!("$char_code"), &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"), &SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), - &SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) => { - clause_name!("$submit_query_and_print_results") - } &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { clause_name!("$use_qualified_module") @@ -289,6 +283,7 @@ impl SystemClauseType { &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), &SystemClauseType::ExpandTerm => clause_name!("$expand_term"), &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"), + &SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"), &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), &SystemClauseType::FetchGlobalVarWithOffset => { clause_name!("$fetch_global_var_with_offset") @@ -327,11 +322,18 @@ impl SystemClauseType { } &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"), &SystemClauseType::Maybe => clause_name!("maybe"), + &SystemClauseType::ModuleAssertDynamicPredicateToFront => { + clause_name!("$module_asserta") + } + &SystemClauseType::ModuleAssertDynamicPredicateToBack => { + clause_name!("$module_assertz") + } &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), &SystemClauseType::ModuleOf => clause_name!("$module_of"), &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), &SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"), + &SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"), &SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), @@ -357,9 +359,6 @@ impl SystemClauseType { &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"), &SystemClauseType::RetractClause => clause_name!("$retract_clause"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"), - &SystemClauseType::ReturnFromAttributeGoals => { - clause_name!("$return_from_attribute_goals") - } &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), &SystemClauseType::SetBall => clause_name!("$set_ball"), &SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"), @@ -387,6 +386,7 @@ impl SystemClauseType { ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), + ("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), @@ -404,6 +404,7 @@ impl SystemClauseType { ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar), ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), + ("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_char", 1) => Some(SystemClauseType::GetChar), @@ -449,13 +450,13 @@ impl SystemClauseType { ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), + ("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar), ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), ("$read_term", 2) => Some(SystemClauseType::ReadTerm), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), ("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset), ("$retract_clause", 4) => Some(SystemClauseType::RetractClause), - ("$return_from_attribute_goals", 0) => Some(SystemClauseType::ReturnFromAttributeGoals), ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr), ("$set_ball", 1) => Some(SystemClauseType::SetBall), ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), @@ -464,9 +465,6 @@ impl SystemClauseType { ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList), ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar), ("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset), - ("$submit_query_and_print_results", 2) => Some(SystemClauseType::REPL( - REPLCodePtr::SubmitQueryAndPrintResults, - )), ("$term_variables", 2) => Some(SystemClauseType::TermVariables), ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo), ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack), diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 2e79f261..9011827a 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -625,6 +625,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { iter.stack().last().cloned().and_then(|addr| { let addr = self.machine_st.store(self.machine_st.deref(addr)); + if let Some(var) = self.var_names.get(&addr) { + self.heap_locs.insert(addr.clone(), Rc::new(var.clone())); + } + match self.heap_locs.get(&addr).cloned() { Some(var) => { if !self.printed_vars.contains(&addr) { diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index 75a7d893..ef919e55 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -364,14 +364,6 @@ pub enum ControlInstruction { } impl ControlInstruction { - pub fn is_jump_instr(&self) -> bool { - match self { - &ControlInstruction::CallClause(..) => true, - &ControlInstruction::JmpBy(..) => true, - _ => false, - } - } - pub fn to_functor(&self) -> MachineStub { match self { &ControlInstruction::Allocate(num_frames) => { diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 5c350a2f..8c018fcb 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -150,7 +150,8 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)). ','(!, Atom, B) :- Atom == !, '$set_cp'(B). ','(!, G, B) :- '$set_cp'(B), G. ','(G, CF, B) :- compound(CF), - '$call_with_default_policy'(CF = ','(G1, G2)), !, G, + '$call_with_default_policy'(CF = ','(G1, G2)), + !, G, '$call_with_default_policy'(comma_errors(G1, G2, B)). ','(G, Atom, B) :- Atom == !, !, G, '$set_cp'(B). ','(G1, G2, _) :- G1, G2. @@ -567,7 +568,7 @@ first_match_index([Clause0 | Clauses], Clause1, N0, N) :- ; N0 = N, Clause0 = Clause1 ). -retract_clauses([Clause|Clauses0], Head, Body, Name, Arity) :- +retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :- functor(VarHead, Name, Arity), findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses1), first_match_index(Clauses1, (Head :- Body), 0, N), @@ -575,7 +576,7 @@ retract_clauses([Clause|Clauses0], Head, Body, Name, Arity) :- ; true ), '$retract_clause'(Name, Arity, N, Clauses1). -retract_clauses([_|Clauses0], Head, Body, Name, Arity) :- +retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :- retract_clauses(Clauses0, Head, Body, Name, Arity). call_retract(Head, Body, Name, Arity) :- diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 9c73c2f6..2b435f1a 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -1,7 +1,5 @@ use crate::prolog::machine::*; -use indexmap::IndexSet; - use std::vec::IntoIter; pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl"); @@ -101,35 +99,6 @@ impl MachineState { attr_vars.into_iter() } - fn populate_project_attr_lists(&mut self) -> (Addr, Addr) { - let mut query_vars = IndexSet::new(); - let attr_vars = self.gather_attr_vars_created_since(0); - - for (_, addr) in self.heap_locs.iter() { - let iter = self.acyclic_pre_order_iter(addr.clone()); - - for value in iter { - match value { - HeapCellValue::Addr(Addr::HeapCell(h)) => { - query_vars.insert(Addr::HeapCell(h)); - } - HeapCellValue::Addr(Addr::StackCell(fr, sc)) => { - query_vars.insert(Addr::StackCell(fr, sc)); - } - HeapCellValue::Addr(Addr::AttrVar(h)) => { - query_vars.insert(Addr::AttrVar(h)); - } - _ => {} - }; - } - } - - let query_var_list = Addr::HeapCell(self.heap.to_list(query_vars.into_iter())); - let attr_var_list = Addr::HeapCell(self.heap.to_list(attr_vars)); - - (query_var_list, attr_var_list) - } - pub(super) fn verify_attr_interrupt(&mut self, p: usize) { self.allocate(self.num_of_args + 2); @@ -149,57 +118,4 @@ impl MachineState { self.b0 = self.b; self.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); } - - fn print_attribute_goals_string(&mut self, op_dir: &OpDir) -> String { - let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); - - if attr_goals.is_empty() { - return String::from(""); - } - - attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); - self.term_dedup(&mut attr_goals); - - let mut output = PrinterOutputter::new(); - - for goal_addr in attr_goals { - let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output); - printer.see_all_locs(); - - printer.numbervars = false; - printer.quoted = true; - - output = printer.print(goal_addr); - output.append(", "); - } - - // cut trailing ", " - let output_len = output.len(); - output.truncate(output_len - 2); - - output.result() - } -} - -impl Machine { - pub fn attribute_goals(&mut self) -> String { - let p = self.machine_st.attr_var_init.project_attrs_loc; - let (query_vars, attr_vars) = self.machine_st.populate_project_attr_lists(); - - self.machine_st.allocate(0); - - self.machine_st[temp_v!(1)] = query_vars; - self.machine_st[temp_v!(2)] = attr_vars; - - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - self.machine_st.query_stepper( - &mut self.indices, - &mut self.policies, - &mut self.code_repo, - &mut readline::input_stream(), - ); - - self.machine_st - .print_attribute_goals_string(&self.indices.op_dir) - } } diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index 3b1f22aa..90063786 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -243,40 +243,6 @@ fn compile_query( Ok((code, cg.take_vars())) } -fn compile_decl( - wam: &mut Machine, - compiler: &mut ListingCompiler, - decl: Declaration, -) -> Result { - let flags = wam.machine_flags(); - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - - compiler.process_decl(decl, wam, &mut indices, flags)?; - - Ok(indices) -} - -pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession { - match packet { - TopLevelPacket::Query(terms, queue) => { - match compile_query(terms, queue, wam.machine_flags()) { - Ok((code, vars)) => wam.submit_query(code, vars), - Err(e) => EvalSession::from(e), - } - } - TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => { - let mut compiler = ListingCompiler::new(&wam.code_repo, false, clause_name!("user")); - let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl)); - - try_eval_session!(wam.check_toplevel_code(&indices)); - add_toplevel_code(wam, vec![], indices); - - EvalSession::EntrySuccess - } - _ => EvalSession::from(SessionError::UserPrompt), - } -} - fn add_hooks_to_mockup( code_repo: &mut CodeRepo, hook: CompileTimeHook, diff --git a/src/prolog/machine/dynamic_database.rs b/src/prolog/machine/dynamic_database.rs index 7ca996f8..17caf908 100644 --- a/src/prolog/machine/dynamic_database.rs +++ b/src/prolog/machine/dynamic_database.rs @@ -30,7 +30,7 @@ impl Machine { match module.as_str() { "user" => compile_user_module(self, src, true, user_src), - _ => compile_into_module(self, module, src, name) + _ => compile_into_module(self, module, src, name) } } None => compile_user_module(self, src, true, user_src), @@ -76,16 +76,27 @@ impl Machine { output.result() } + fn make_undefined(&mut self, name: ClauseName, arity: usize) { + if let Some(idx) = self.indices.code_dir.get(&(name, arity)) { + set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user")); + } + } + + fn make_undefined_in_module(&mut self, module_name: ClauseName, name: ClauseName, arity: usize) { + if let Some(idx) = self.indices.code_dir.get(&(name, arity)) { + if idx.module_name() == module_name { + set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user")); + } + } + } + fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) { let (name, arity) = self.get_predicate_key(name, arity); - if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) { - set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user")); - } + self.make_undefined(name.clone(), arity); self.indices.remove_code_index((name.clone(), arity)); - self.indices - .remove_clause_subsection(name.owning_module(), name, arity); + self.indices.remove_clause_subsection(name.owning_module(), name, arity); } fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) { @@ -106,15 +117,10 @@ impl Machine { _ => unreachable!(), }; - if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) { - if idx.module_name() == module_name { - set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user")); - } - } + self.make_undefined_in_module(module_name.clone(), name.clone(), arity); self.indices.remove_code_index((name.clone(), arity)); - self.indices - .remove_clause_subsection(module_name, name, arity); + self.indices.remove_clause_subsection(module_name, name, arity); } fn handle_eval_result_from_dynamic_compile( @@ -210,6 +216,10 @@ impl Machine { let mut addrs = VecDeque::from(addrs); addrs.remove(index); + if addrs.is_empty() { + self.make_undefined(name.clone(), arity); + } + self.print_new_dynamic_clause(addrs, name.clone(), arity) } Err(err) => return self.machine_st.throw_exception(err), @@ -239,6 +249,10 @@ impl Machine { let mut addrs = VecDeque::from(addrs); addrs.remove(index); + if addrs.is_empty() { + self.make_undefined(name.clone(), arity); + } + self.print_new_dynamic_clause(addrs, name.clone(), arity) } Err(err) => return self.machine_st.throw_exception(err), diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index fe648303..6ef4ed9f 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -537,15 +537,11 @@ pub enum SessionError { NamelessEntry, OpIsInfixAndPostFix(ClauseName), ParserError(ParserError), - UserPrompt, } pub enum EvalSession { EntrySuccess, Error(SessionError), - InitialQuerySuccess(AllocVarDict), - QueryFailure, - SubsequentQuerySuccess, } impl From for EvalSession { diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index df8a3141..a6c32597 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -300,7 +300,6 @@ pub enum DynamicTransactionType { #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] pub enum REPLCodePtr { CompileBatch, - SubmitQueryAndPrintResults, UseModule, UseQualifiedModule, UseModuleFromFile, @@ -468,13 +467,7 @@ pub struct IndexStore { pub(super) op_dir: OpDir, } -impl IndexStore { - pub fn reset_global_variable_offsets(&mut self) { - for (_, ref mut offset) in self.global_variables.values_mut() { - *offset = None; - } - } - +impl IndexStore { pub fn predicate_exists( &self, name: ClauseName, diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 95ced490..43447666 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -316,7 +316,7 @@ impl MachineState { Ok(codes) } - fn call_at_index(&mut self, arity: usize, p: usize) { + pub(super) fn call_at_index(&mut self, arity: usize, p: usize) { self.cp.assign_if_local(self.p.clone() + 1); self.num_of_args = arity; self.b0 = self.b; diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 4d1918db..90ddcb54 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -6,7 +6,6 @@ use crate::prolog::arithmetic::*; use crate::prolog::clause_types::*; use crate::prolog::forms::*; use crate::prolog::heap_iter::*; -use crate::prolog::heap_print::*; use crate::prolog::instructions::*; use crate::prolog::machine::INTERRUPT; use crate::prolog::machine::attributed_variables::*; @@ -26,7 +25,6 @@ use indexmap::{IndexMap, IndexSet}; use std::cmp::{max, min, Ordering}; use std::f64; use std::mem; -use std::rc::Rc; macro_rules! try_numeric_result { ($s: ident, $e: expr, $caller: expr) => {{ @@ -190,39 +188,6 @@ impl MachineState { } } - pub(super) fn print_var_eq( - &self, - var: Rc, - addr: Addr, - op_dir: &OpDir, - mut output: Outputter, - ) -> Outputter - where - Outputter: HCValueOutputter, - { - let orig_len = output.len(); - - output.begin_new_var(); - - output.append(var.as_str()); - output.append(" = "); - - let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output); - - printer.numbervars = false; - printer.quoted = true; - - let mut output = printer.print(addr); - - let bad_ending = format!("= {}", &var); - - if output.ends_with(&bad_ending) { - output.truncate(orig_len); - } - - output - } - pub(super) fn unify_strings( &mut self, pdl: &mut Vec, diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 7eef9b8f..e71bd826 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -2,13 +2,11 @@ use prolog_parser::ast::*; use prolog_parser::tabled_rc::*; use crate::prolog::clause_types::*; -use crate::prolog::fixtures::*; use crate::prolog::forms::*; use crate::prolog::heap_print::*; use crate::prolog::instructions::*; use crate::prolog::machine::heap::Heap; use crate::prolog::read::*; -use crate::prolog::write::{next_keypress, ContinueResult}; mod attributed_variables; pub(super) mod code_repo; @@ -35,21 +33,18 @@ use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; use crate::prolog::machine::modules::*; -use crate::prolog::machine::toplevel::stream_to_toplevel; use crate::prolog::read::PrologStream; use indexmap::IndexMap; use std::collections::VecDeque; use std::fs::File; -use std::io::{stdout, Read, Write}; +use std::io::Read; use std::mem; use std::ops::Index; use std::rc::Rc; use std::sync::atomic::AtomicBool; -use termion::raw::IntoRawMode; - pub struct MachinePolicies { call_policy: Box, cut_policy: Box, @@ -197,10 +192,23 @@ impl Machine { } } - fn compile_top_level(&mut self) { + fn compile_top_level(&mut self) -> Result<(), SessionError> + { self.toplevel_idx = self.code_repo.code.len(); compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()), true, clause_name!("toplevel.pl")); + + if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) { + self.indices.use_module( + &mut self.code_repo, + self.machine_st.flags, + &module, + )?; + + Ok(self.indices.insert_module(module)) + } else { + Err(SessionError::ModuleNotFound) + } } fn compile_scryerrc(&mut self) { @@ -231,14 +239,14 @@ impl Machine { pub fn run_init_code(&mut self, code: Code) -> bool { let old_machine_st = self.sink_to_snapshot(); - self.machine_st.reset(); + self.machine_st.reset(); self.code_repo.cached_query = code; - self.run_query(&AllocVarDict::new()); + self.run_query(); let result = self.machine_st.fail; self.absorb_snapshot(old_machine_st); - + !result } @@ -260,7 +268,7 @@ impl Machine { self.machine_st[temp_v!(1)] = list_addr; self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx)); - self.run_query(&AllocVarDict::new()); + self.run_query(); } pub fn new(prolog_stream: PrologStream) -> Self { @@ -295,7 +303,10 @@ impl Machine { compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true, clause_name!("si")); - wam.compile_top_level(); + if wam.compile_top_level().is_err() { + panic!("Loading '$toplevel' module failed"); + } + wam.compile_scryerrc(); wam @@ -377,17 +388,6 @@ impl Machine { self.code_repo.code.extend(code.into_iter()); } - pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession { - self.code_repo.cached_query = code; - self.run_query(&alloc_locs); - - if self.machine_st.fail { - EvalSession::QueryFailure - } else { - EvalSession::InitialQuerySuccess(alloc_locs) - } - } - fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { let h = self.machine_st.heap.h; @@ -465,10 +465,10 @@ impl Machine { if !module.is_impromptu_module { self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?; } - + Ok(self.indices.insert_module(module)) }); - + self.code_repo.cached_query = cached_query; if let Err(e) = result { @@ -536,62 +536,6 @@ impl Machine { self.throw_session_error(e, (clause_name!("repl"), 0)); } } - REPLCodePtr::SubmitQueryAndPrintResults => { - let term = self.machine_st[temp_v!(1)].clone(); - let stub = MachineError::functor_stub(clause_name!("repl"), 0); - - let s = match self.machine_st.try_from_list(temp_v!(2), stub) { - Ok(addrs) => { - let mut var_dict = HeapVarDict::new(); - - for addr in addrs { - match addr { - Addr::Str(s) => { - let var_atom = match self.machine_st.heap[s + 1].as_addr(s + 1) - { - Addr::Con(Constant::Atom(var_atom, _)) => { - Rc::new(var_atom.to_string()) - } - _ => unreachable!(), - }; - - let var_addr = self.machine_st.heap[s + 2].as_addr(s + 2); - var_dict.insert(var_atom, var_addr); - } - _ => unreachable!(), - }; - } - - self.machine_st.heap_locs = var_dict; - let term_output = self.machine_st.print_query(term, &self.indices.op_dir); - - term_output.result() - } - Err(err_stub) => { - self.machine_st.throw_exception(err_stub); - return; - } - }; - - let stream = parsing_stream(s.as_bytes()); - let snapshot = self.sink_to_snapshot(); - let policies = mem::replace(&mut self.policies, MachinePolicies::new()); - - self.machine_st.reset(); - self.machine_st.heap = mem::replace( - &mut self.inner_heap, - Heap::with_capacity(0), - ); - - let result = match stream_to_toplevel(stream, self) { - Ok(packet) => compile_term(self, packet), - Err(e) => EvalSession::from(e), - }; - - self.handle_eval_session(result, snapshot); - self.indices.reset_global_variable_offsets(); - self.policies = policies; - } REPLCodePtr::UseModule => self.use_module(ModuleSource::Library), REPLCodePtr::UseModuleFromFile => @@ -607,7 +551,7 @@ impl Machine { fn sink_to_snapshot(&mut self) -> MachineState { let mut snapshot = MachineState::with_capacity(0); - + snapshot.hb = self.machine_st.hb; snapshot.e = self.machine_st.e; snapshot.b = self.machine_st.b; @@ -615,6 +559,12 @@ impl Machine { snapshot.s = self.machine_st.s; snapshot.tr = self.machine_st.tr; snapshot.pstr_tr = self.machine_st.pstr_tr; + snapshot.p = self.machine_st.p.clone(); + snapshot.cp = self.machine_st.cp; + snapshot.attr_var_init = mem::replace( + &mut self.machine_st.attr_var_init, + AttrVarInitializer::new(0, 0) + ); snapshot.num_of_args = self.machine_st.num_of_args; snapshot.fail = self.machine_st.fail; @@ -627,12 +577,13 @@ impl Machine { snapshot.block = self.machine_st.block; snapshot.ball = self.machine_st.ball.take(); + snapshot.heap_locs = mem::replace(&mut self.machine_st.heap_locs, IndexMap::new()); snapshot.lifted_heap = mem::replace(&mut self.machine_st.lifted_heap, vec![]); snapshot } - fn absorb_snapshot(&mut self, mut snapshot: MachineState) { + fn absorb_snapshot(&mut self, mut snapshot: MachineState) { self.machine_st.hb = snapshot.hb; self.machine_st.e = snapshot.e; self.machine_st.b = snapshot.b; @@ -640,6 +591,9 @@ impl Machine { self.machine_st.s = snapshot.s; self.machine_st.tr = snapshot.tr; self.machine_st.pstr_tr = snapshot.pstr_tr; + self.machine_st.p = snapshot.p; + self.machine_st.cp = snapshot.cp; + self.machine_st.attr_var_init = snapshot.attr_var_init; self.machine_st.num_of_args = snapshot.num_of_args; self.machine_st.fail = snapshot.fail; @@ -656,160 +610,15 @@ impl Machine { self.machine_st.block = snapshot.block; self.machine_st.ball = snapshot.ball.take(); + self.machine_st.heap_locs = mem::replace(&mut snapshot.heap_locs, IndexMap::new()); self.machine_st.lifted_heap = mem::replace(&mut snapshot.lifted_heap, vec![]); } - fn propagate_exception_to_toplevel(&mut self, snapshot: MachineState) { - let ball = self.machine_st.ball.take(); - - self.absorb_snapshot(snapshot); - self.machine_st.ball = ball; - - let h = self.machine_st.heap.h; - let stub = self.machine_st.ball.copy_and_align(h); - - self.machine_st.throw_exception(stub); - - return; - } - - fn handle_eval_session(&mut self, result: EvalSession, snapshot: MachineState) { - match result { - EvalSession::InitialQuerySuccess(alloc_locs) => loop { - let bindings = { - let output = PrinterOutputter::new(); - self.toplevel_heap_view(output).result() - }; - - let attr_goals = self.attribute_goals(); - - if !(self.machine_st.b > 0) { - if bindings.is_empty() { - let space = if requires_space(&attr_goals, ".") { - " " - } else { - "" - }; - - if !attr_goals.is_empty() { - println!("{}{}.", attr_goals, space); - } else { - println!("true."); - } - - self.absorb_snapshot(snapshot); - return; - } - } else if bindings.is_empty() && attr_goals.is_empty() { - print!("true"); - stdout().flush().unwrap(); - } - - if !attr_goals.is_empty() { - if bindings.is_empty() { - print!("{}", attr_goals); - } else { - print!("{}, {}", bindings, attr_goals); - } - } else if !bindings.is_empty() { - print!("{}", bindings); - } - - if self.machine_st.b > 0 { - let keypress = { - let mut raw_stdout = stdout().into_raw_mode().unwrap(); - raw_stdout.flush().unwrap(); - next_keypress() - }; - - let result = match keypress { - ContinueResult::ContinueQuery => { - print!(" ;\n"); - self.continue_query(&alloc_locs) - } - ContinueResult::Conclude => { - print!(" ...\n"); - self.absorb_snapshot(snapshot); - return; - } - }; - - match result { - EvalSession::QueryFailure => { - if self.machine_st.ball.stub.len() > 0 { - self.propagate_exception_to_toplevel(snapshot); - return; - } else { - print!("false.\n"); - self.absorb_snapshot(snapshot); - return; - } - } - EvalSession::Error(err) => { - self.absorb_snapshot(snapshot); - self.throw_session_error(err, (clause_name!("repl"), 0)); - return; - } - _ => {} - } - } else { - if bindings.is_empty() && attr_goals.is_empty() { - print!("true.\n"); - } else { - let space = if !attr_goals.is_empty() { - if requires_space(&attr_goals, ".") { - " " - } else { - "" - } - } else { - if requires_space(&bindings, ".") { - " " - } else { - "" - } - }; - - print!("{}.\n", space); - } - - break; - } - }, - EvalSession::Error(err) => { - self.absorb_snapshot(snapshot); - self.throw_session_error(err, (clause_name!("repl"), 0)); - return; - } - EvalSession::QueryFailure => - if self.machine_st.ball.stub.len() > 0 { - return self.propagate_exception_to_toplevel(snapshot); - } else { - println!("false."); - }, - _ => println!("true.") - } - - self.absorb_snapshot(snapshot); - } - - pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) { + pub(super) fn run_query(&mut self) { self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query()); let end_ptr = CodePtr::Local(self.machine_st.cp); while self.machine_st.p < end_ptr { - if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.machine_st.p { - match &self.code_repo[LocalCodePtr::TopLevel(cn, p)] { - &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => { - self.machine_st.record_var_places(cn, alloc_locs); - cn += 1; - } - _ => {} - } - - self.machine_st.p = top_level_code_ptr!(cn, p); - } - self.machine_st.query_stepper( &mut self.indices, &mut self.policies, @@ -828,63 +637,18 @@ impl Machine { self.dynamic_transaction(trans_type, p); if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p { - if self.machine_st.heap_locs.is_empty() { - self.machine_st.record_var_places(0, alloc_locs); - } - self.code_repo.cached_query = cached_query; break; } self.code_repo.cached_query = cached_query; } - _ => { - if self.machine_st.heap_locs.is_empty() { - self.machine_st.record_var_places(0, alloc_locs); - } - - break; - } + _ => + break }; } } - pub fn continue_query(&mut self, alloc_locs: &AllocVarDict) -> EvalSession { - if self.machine_st.b > 0 { - let b = self.machine_st.b; - self.machine_st.p = self.machine_st.stack.index_or_frame(b).prelude.bp.clone(); - - if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p { - self.machine_st.fail = true; - return EvalSession::QueryFailure; - } - - self.run_query(alloc_locs); - - if self.machine_st.fail { - EvalSession::QueryFailure - } else { - EvalSession::SubsequentQuerySuccess - } - } else { - EvalSession::QueryFailure - } - } - - pub fn toplevel_heap_view(&self, mut output: Outputter) -> Outputter - where - Outputter: HCValueOutputter, - { - for (var, addr) in self.machine_st.heap_locs.iter() { - let addr = self.machine_st.store(self.machine_st.deref(addr.clone())); - output = self - .machine_st - .print_var_eq(var.clone(), addr, &self.indices.op_dir, output); - } - - output - } - #[cfg(test)] pub fn test_heap_view(&self, mut output: Outputter) -> Outputter where @@ -904,56 +668,6 @@ impl Machine { } impl MachineState { - fn record_var_places(&mut self, chunk_num: usize, alloc_locs: &AllocVarDict) { - for (var, var_data) in alloc_locs { - match var_data { - &VarData::Perm(p) if p > 0 => { - if !self.heap_locs.contains_key(var) { - let e = self.e; - let r = var_data.as_reg_type().reg_num(); - let addr = self.stack.index_and_frame(e)[r].clone(); - - self.heap_locs.insert(var.clone(), addr); - } - } - &VarData::Temp(cn, _, _) if cn == chunk_num => { - let r = var_data.as_reg_type(); - - if r.reg_num() != 0 { - let addr = self[r].clone(); - self.heap_locs.insert(var.clone(), addr); - } - } - _ => {} - } - } - } - - fn print_query(&mut self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter { - let flags = self.flags; - - let mut output = { - self.flags = MachineFlags { - double_quotes: DoubleQuotes::Atom, - }; - - let output = PrinterOutputter::new(); - let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output); - - printer.quoted = true; - printer.numbervars = false; - printer.drop_toplevel_spec(); - - printer.see_all_locs(); - printer.print(addr) - }; - - self.flags = flags; - - output.append("."); - output - } - fn dispatch_instr( &mut self, instr: &Line, diff --git a/src/prolog/machine/project_attributes.pl b/src/prolog/machine/project_attributes.pl index 3b399f98..7349bdf5 100644 --- a/src/prolog/machine/project_attributes.pl +++ b/src/prolog/machine/project_attributes.pl @@ -1,10 +1,9 @@ -driver(QueryVars, AttrVars) :- +'$attribute_goals_driver'(QueryVars, AttrVars) :- gather_modules(AttrVars, Modules0, _), sort(Modules0, Modules), call_project_attributes(Modules, QueryVars, AttrVars), call_attribute_goals(Modules, call_query_var_goals, QueryVars), - call_attribute_goals(Modules, call_attr_var_goals, AttrVars), - '$return_from_attribute_goals'. + call_attribute_goals(Modules, call_attr_var_goals, AttrVars). enqueue_goals(Goals0) :- nonvar(Goals0), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 6fa315f4..c8b841c3 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -22,11 +22,34 @@ use crate::ref_thread_local::RefThreadLocal; use indexmap::{IndexMap, IndexSet}; use std::collections::VecDeque; -use std::io::{stdout, Write}; +use std::io::{stdin, stdout, Write}; use std::iter::once; use std::mem; use std::rc::Rc; +use crate::termion::event::Key; +use crate::termion::input::TermRead; +use crate::termion::raw::IntoRawMode; + +pub enum ContinueResult { + ContinueQuery, + Conclude, +} + +pub fn next_keypress() -> ContinueResult { + let stdin = stdin(); + + for c in stdin.keys() { + match c.unwrap() { + Key::Char(' ') | Key::Char(';') => return ContinueResult::ContinueQuery, + Key::Char('.') => return ContinueResult::Conclude, + _ => {} + } + } + + ContinueResult::Conclude +} + struct BrentAlgState { hare: usize, tortoise: usize, @@ -716,6 +739,17 @@ impl MachineState { self.unify(a2, Addr::Con(Constant::Integer(len))); } + &SystemClauseType::CallAttributeGoals => { + let p = self.attr_var_init.project_attrs_loc; + + if self.last_call { + self.execute_at_index(2, p); + } else { + self.call_at_index(2, p); + } + + return Ok(()); + } &SystemClauseType::CharsToNumber => { let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); @@ -1329,6 +1363,17 @@ impl MachineState { &SystemClauseType::TruncateIfNoLiftedHeapGrowth => { self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList)) } + &SystemClauseType::FetchAttributeGoals => { + let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + + attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2)); + self.term_dedup(&mut attr_goals); + + let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter())); + let target = self[temp_v!(1)].clone(); + + self.unify(attr_goals, target); + } &SystemClauseType::GetAttributedVariableList => { let attr_var = self.store(self.deref(self[temp_v!(1)].clone())); let attr_var_list = match attr_var { @@ -1370,6 +1415,18 @@ impl MachineState { self.unify(var_list_addr, list_addr); } + Addr::Con(Constant::Integer(n)) => { + if let Some(b) = n.to_usize() { + 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); + } else { + self.fail = true; + } + } _ => self.fail = true, } } @@ -1685,11 +1742,6 @@ impl MachineState { 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.stack.index_and_frame(e).prelude.univ_prelude.num_cells; @@ -1839,6 +1891,21 @@ impl MachineState { &SystemClauseType::InstallNewBlock => { self.install_new_block(temp_v!(1)); } + &SystemClauseType::RawInputReadChar => { + let keypress = { + let mut raw_stdout = stdout().into_raw_mode().unwrap(); + raw_stdout.flush().unwrap(); + next_keypress() + }; + + let c = match keypress { + ContinueResult::ContinueQuery => ';', + ContinueResult::Conclude => '.' + }; + + let target = self[temp_v!(1)].clone(); + self.unify(Addr::Con(Constant::Char(c)), target); + } &SystemClauseType::ReadQueryTerm => { readline::set_prompt(true); let result = self.read_term(current_input_stream, indices); diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index d2bc1362..1c45b49e 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -136,11 +136,6 @@ impl<'a, R: Read> TermStream<'a, R> { pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> { mem::replace(&mut self.top_level_terms, vec![]) } - - #[inline] - pub fn add_to_top(&mut self, buf: &str) { - self.parser.add_to_top(buf); - } #[inline] pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) { diff --git a/src/prolog/machine/toplevel.rs b/src/prolog/machine/toplevel.rs index c54e0515..542dd131 100644 --- a/src/prolog/machine/toplevel.rs +++ b/src/prolog/machine/toplevel.rs @@ -303,13 +303,6 @@ fn is_consistent(tl: &TopLevel, clauses: &Vec) -> bool { } } -fn deque_to_packet(head: TopLevel, deque: VecDeque) -> TopLevelPacket { - match head { - TopLevel::Query(query) => TopLevelPacket::Query(query, deque), - tl => TopLevelPacket::Decl(tl, deque), - } -} - fn merge_clauses(tls: &mut VecDeque) -> Result { let mut clauses: Vec = vec![]; @@ -496,11 +489,6 @@ fn setup_declaration<'a, 'b, 'c, R: Read>( } } -pub enum TopLevelPacket { - Query(Vec, VecDeque), - Decl(TopLevel, VecDeque), -} - struct RelationWorker { flags: MachineFlags, dynamic_clauses: Vec<(Term, Term)>, // Head, Body. @@ -902,39 +890,6 @@ impl RelationWorker { } } -pub fn stream_to_toplevel( - mut buffer: ParsingStream, - wam: &mut Machine, -) -> Result { - let flags = wam.machine_flags(); - let mut term_stream = TermStream::new( - &mut buffer, - wam.indices.atom_tbl(), - wam.machine_flags(), - wam, - ); - - term_stream.add_to_top("?- "); - - let term = term_stream.read_term(&OpDir::new())?; - let mut code_dir = CodeDir::new(); - - let line_num = term_stream.line_num(); - let col_num = term_stream.col_num(); - - let mut rel_worker = RelationWorker::new(flags, line_num, col_num); - let mut indices = CompositeIndices::new( - &mut term_stream, - IndexSource::TermStream, - Some(IndexSource::Local(&mut code_dir)) - ); - - let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?; - let queue = rel_worker.parse_queue(&mut indices)?; - - Ok(deque_to_packet(tl, queue)) -} - pub type DynamicClauseMap = IndexMap<(ClauseName, usize), Vec<(Term, Term)>>; pub struct TopLevelBatchWorker<'a, R: Read> { diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index ec17b8e1..0db02999 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -262,12 +262,6 @@ macro_rules! put_constant { }; } -macro_rules! top_level_code_ptr { - ($p:expr, $q_sz:expr) => { - CodePtr::Local(LocalCodePtr::TopLevel($p, $q_sz)) - }; -} - macro_rules! get_level_and_unify { ($r: expr) => { Line::Cut(CutInstruction::GetLevelAndUnify($r)) diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 26b5a862..f9eba5dd 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -1,8 +1,4 @@ -/* - * inserting the modules should not result in the insertion of - * code. this is because they're already loaded by this point -- see - * Machine::new. -*/ +:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2]). :- use_module(library(lists)). :- use_module(library(si)). @@ -40,6 +36,75 @@ '$submit_query_and_print_results'(Term, VarList), !. +'$submit_query_and_print_results'(Term0, VarList) :- + ( expand_goals(Term0, Term) -> true + ; Term = Term0 + ), + ( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), ! + ; write('false.'), nl + ). + +'$write_goal'(G, VarList) :- + ( G = (Var = Value) -> + write(Var), + write(' = '), + write_term(Value, [quoted(true), variable_names(VarList)]) + ; G == [] -> + write('true') + ; write_term(G, [quoted(true), variable_names(VarList)]) + ). + +'$write_eq'((G1, G2), VarList) :- + !, + '$write_goal'(G1, VarList), + write(', '), + '$write_eq'(G2, VarList). +'$write_eq'(G, VarList) :- + '$write_goal'(G, VarList). + +'$write_eqs_and_read_input'(B, VarList) :- + sort(VarList, SortedVarList), + '$get_b_value'(B0), + '$gather_goals'(SortedVarList, VarList, Goals), + ( B0 == B -> + ( Goals == [] -> + write('true.'), nl + ; thread_goals(Goals, ThreadedGoals, (',')), + '$write_eq'(ThreadedGoals, VarList), + write(' .'), + nl + ) + ; repeat, + thread_goals(Goals, ThreadedGoals, (',')), + '$write_eq'(ThreadedGoals, VarList), + '$raw_input_read_char'(C), + ( C == (';'), !, + write(' ;'), nl, false + ; C == ('.'), !, + write(' ...'), nl + ) + ). + +'$gather_query_vars'([_ = Var | Vars], QueryVars) :- + ( var(Var) -> + QueryVars = [Var | QueryVars1], + '$gather_query_vars'(Vars, QueryVars1) + ; '$gather_query_vars'(Vars, QueryVars) + ). +'$gather_query_vars'([], []). + +'$gather_goals'([], VarList, Goals) :- + '$get_attr_var_queue_beyond'(0, AttrVars), + '$gather_query_vars'(VarList, QueryVars), + '$call_attribute_goals'(QueryVars, AttrVars), + '$fetch_attribute_goals'(Goals). +'$gather_goals'([Var = Value | Pairs], VarList, Goals) :- + ( nonvar(Value) -> + Goals = [Var = Value | Goals0], + '$gather_goals'(Pairs, VarList, Goals0) + ; '$gather_goals'(Pairs, VarList, Goals) + ). + '$print_exception'(E) :- write_term('caught: ', [quoted(false)]), writeq(E), @@ -102,40 +167,50 @@ user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :- expand_goals(Goals, ExpandedGoals), Goals \== ExpandedGoals. -expand_goals(Goals, ExpandedGoals) :- - nonvar(Goals), +expand_goals(UnexpandedGoals, ExpandedGoals) :- + nonvar(UnexpandedGoals), var(ExpandedGoals), + ( expand_goal(UnexpandedGoals, Goals) -> true + ; Goals = UnexpandedGoals + ), ( Goals = (Goal0, Goals0) -> ( expand_goal(Goal0, Goal1) -> Expanded = true, expand_goals(Goals0, Goals1), - thread_goals(Goal1, ExpandedGoals, Goals1) + thread_goals(Goal1, ExpandedGoals, Goals1, (',')) ; expand_goals(Goals0, Goals1), ExpandedGoals = (Goal0, Goals1) ) - ; expand_goal(Goals, ExpandedGoals0) -> - thread_goals(ExpandedGoals0, ExpandedGoals) + ; Goals = (Goals0 -> Goals1) -> + expand_goals(Goals0, ExpandedGoals0), + expand_goals(Goals1, ExpandedGoals1), + ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1) + ; Goals = (Goals0 ; Goals1) -> + expand_goals(Goals0, ExpandedGoals0), + expand_goals(Goals1, ExpandedGoals1), + ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1) + ; thread_goals(Goals, ExpandedGoals, (',')) ; Goals = ExpandedGoals ). -thread_goals(Goals0, Goals1, Hole) :- +thread_goals(Goals0, Goals1, Hole, Functor) :- nonvar(Goals0), ( Goals0 = [G | Gs] -> ( Gs == [] -> - Goals1 = (G, Hole) - ; Goals1 = (G, Goals2), - thread_goals(Gs, Goals2, Hole) + Goals1 =.. [Functor, G, Hole] + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Hole, Functor) ) - ; Goals1 = (Goals0, Hole) + ; Goals1 =.. [Functor, Goals0, Hole] ). -thread_goals(Goals0, Goals1) :- +thread_goals(Goals0, Goals1, Functor) :- nonvar(Goals0), ( Goals0 = [G | Gs] -> ( Gs = [] -> Goals1 = G - ; Goals1 = (G, Goals2), - thread_goals(Gs, Goals2) + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Functor) ) ; Goals1 = Goals0 ). diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 03a884c8..2d552522 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -4,11 +4,7 @@ use crate::prolog::instructions::*; use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_indices::*; -use termion::event::Key; -use termion::input::TermRead; - use std::fmt; -use std::io::stdin; impl fmt::Display for LocalCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -29,10 +25,8 @@ impl fmt::Display for LocalCodePtr { impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - REPLCodePtr::CompileBatch => write!(f, "REPLCodePtr::CompileBatch"), - REPLCodePtr::SubmitQueryAndPrintResults => { - write!(f, "REPLCodePtr::SubmitQueryAndPrintResults") - } + REPLCodePtr::CompileBatch => + write!(f, "REPLCodePtr::CompileBatch"), REPLCodePtr::UseModule => write!(f, "REPLCodePtr::UseModule"), REPLCodePtr::UseQualifiedModule => @@ -275,7 +269,6 @@ impl fmt::Display for SessionError { write!(f, "the predicate head is not an atom or clause.") } &SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()), - &SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt"), } } } @@ -422,22 +415,3 @@ impl fmt::Display for Level { } } } - -pub enum ContinueResult { - ContinueQuery, - Conclude, -} - -pub fn next_keypress() -> ContinueResult { - let stdin = stdin(); - - for c in stdin.keys() { - match c.unwrap() { - Key::Char(' ') | Key::Char(';') => return ContinueResult::ContinueQuery, - Key::Char('.') => return ContinueResult::Conclude, - _ => {} - } - } - - ContinueResult::Conclude -} diff --git a/src/tests.rs b/src/tests.rs deleted file mode 100644 index 32d0a21c..00000000 --- a/src/tests.rs +++ /dev/null @@ -1,3542 +0,0 @@ -use prolog_parser::ast::{ClauseName, parsing_stream}; - -use crate::prolog::heap_print::*; -use crate::prolog::machine::compile::*; -use crate::prolog::machine::machine_errors::*; -use crate::prolog::machine::machine_indices::*; -use crate::prolog::machine::toplevel::*; -use crate::prolog::machine::*; -use crate::prolog::read::readline; - -use indexmap::IndexSet; - -use std::mem::swap; -use std::ops::{Range, RangeFrom}; - -pub struct TestOutputter { - results: Vec>, - contents: IndexSet, - focus: String, -} - -impl TestOutputter { - fn cache(&mut self) { - self.begin_new_var(); - - let mut contents = IndexSet::new(); - swap(&mut contents, &mut self.contents); - - self.results.push(contents); - } -} - -impl HCValueOutputter for TestOutputter { - type Output = Vec>; - - fn new() -> Self { - TestOutputter { - results: vec![], - contents: IndexSet::new(), - focus: String::new(), - } - } - - fn append(&mut self, focus: &str) { - self.focus += focus; - } - - fn push_char(&mut self, c: char) { - self.focus.push(c); - } - - fn begin_new_var(&mut self) { - if !self.focus.is_empty() { - let mut focus = String::new(); - swap(&mut focus, &mut self.focus); - - self.contents.insert(focus); - } - } - - fn insert(&mut self, idx: usize, c: char) { - self.focus.insert(idx, c); - } - - fn result(self) -> Self::Output { - self.results - } - - fn ends_with(&self, s: &str) -> bool { - self.focus.ends_with(s) - } - - fn len(&self) -> usize { - self.focus.len() - } - - fn truncate(&mut self, len: usize) { - self.focus.truncate(len); - } - - fn range(&self, index: Range) -> &str { - &self.focus.as_str()[index] - } - - fn range_from(&self, index: RangeFrom) -> &str { - &self.focus.as_str()[index] - } -} - -pub fn collect_test_output(wam: &mut Machine, alloc_locs: AllocVarDict) -> Vec> { - let mut output = TestOutputter::new(); - - output = wam.test_heap_view(output); - output.cache(); - - while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs) { - output = wam.test_heap_view(output); - output.cache(); - } - - output.result() -} - -pub fn collect_test_output_with_limit( - wam: &mut Machine, - alloc_locs: AllocVarDict, - limit: usize, -) -> Vec> { - let mut output = TestOutputter::new(); - - output = wam.test_heap_view(output); - output.cache(); - - let mut count = 1; - - if count == limit { - return output.result(); - } - - while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs) { - output = wam.test_heap_view(output); - output.cache(); - - count += 1; - - if count == limit { - break; - } - } - - output.result() -} - -#[allow(dead_code)] -pub fn submit(wam: &mut Machine, buffer: &str) -> bool { - wam.reset(); - - match submit_code(wam, buffer) { - EvalSession::InitialQuerySuccess(_) - | EvalSession::EntrySuccess - | EvalSession::SubsequentQuerySuccess => true, - _ => false, - } -} - -#[allow(dead_code)] -pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec>) -> bool { - wam.reset(); - - match stream_to_toplevel(parsing_stream(buffer.as_bytes()), wam) { - Ok(term) => match compile_term(wam, term) { - EvalSession::InitialQuerySuccess(alloc_locs) => { - result == collect_test_output(wam, alloc_locs) - } - EvalSession::EntrySuccess => true, - _ => false, - }, - Err(_) => panic!("syntax error"), - } -} - -#[allow(dead_code)] -pub fn submit_query_without_results(wam: &mut Machine, buffer: &str) -> bool { - wam.reset(); - - match stream_to_toplevel(parsing_stream(buffer.as_bytes()), wam) { - Ok(term) => match compile_term(wam, term) { - EvalSession::InitialQuerySuccess(..) | EvalSession::EntrySuccess => true, - _ => false, - }, - Err(_) => panic!("syntax error"), - } -} - -#[allow(dead_code)] -pub fn submit_query_with_limit( - wam: &mut Machine, - buffer: &str, - result: Vec>, - limit: usize, -) -> bool { - wam.reset(); - - match stream_to_toplevel(parsing_stream(buffer.as_bytes()), wam) { - Ok(term) => match compile_term(wam, term) { - EvalSession::InitialQuerySuccess(alloc_locs) => { - result == collect_test_output_with_limit(wam, alloc_locs, limit) - } - EvalSession::EntrySuccess => true, - _ => false, - }, - Err(_) => panic!("syntax_error"), - } -} - -#[allow(dead_code)] -pub fn submit_code(wam: &mut Machine, buf: &str) -> EvalSession { - compile_user_module(wam, parsing_stream(buf.as_bytes()), true, clause_name!("tests")) -} - -#[allow(unused_macros)] -macro_rules! expand_strs { - ($arr:expr) => { - $arr.into_iter().map(|s| String::from(*s)).collect() - }; -} - -#[allow(unused_macros)] -macro_rules! assert_prolog_success_with_limit { - ($wam:expr, $buf:expr, [$($res:expr),*], $limit:expr) => ( - assert!(submit_query_with_limit($wam, $buf, vec![$(expand_strs!($res)),*], $limit)) - ) -} - -#[allow(unused_macros)] -macro_rules! assert_prolog_failure { - ($wam: expr, $buf: expr) => { - assert_eq!(submit_query_without_results($wam, $buf), false) - }; -} - -#[allow(unused_macros)] -macro_rules! assert_prolog_success { - ($wam:expr, $query:expr, [$($res:expr),*]) => ( - assert!(submit_query($wam, $query, vec![$(expand_strs!($res)),*])) - ); - ($wam:expr, $buf:expr) => ( - assert_eq!(submit_query_without_results($wam, $buf), true) - ) -} -/* -#[test] -fn test_queries_on_facts() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "p(Z, Z)."); - submit(&mut wam, "clouds(are, nice)."); - - assert_prolog_success!(&mut wam, "p(Z, Z).", [["Z = _0"]]); - assert_prolog_success!(&mut wam, "p(Z, z).", [["Z = z"]]); - assert_prolog_success!(&mut wam, "p(Z, w).", [["Z = w"]]); - - assert_prolog_failure!(&mut wam, "p(z, w)."); - - assert_prolog_success!(&mut wam, "p(w, w)."); - - assert_prolog_failure!(&mut wam, "clouds(Z, Z)."); - - assert_prolog_success!(&mut wam, "clouds(are, Z).", [["Z = nice"]]); - assert_prolog_success!(&mut wam, "clouds(Z, nice).", [["Z = are"]]); - - submit(&mut wam, "p(Z, h(Z, W), f(W))."); - - assert_prolog_failure!(&mut wam, "p(z, h(z, z), f(w))."); - assert_prolog_success!(&mut wam, "p(z, h(z, w), f(w))."); - assert_prolog_success!(&mut wam, "p(z, h(z, W), f(w)).", [["W = w"]]); - assert_prolog_success!(&mut wam, "p(Z, h(Z, w), f(Z)).", [["Z = w"]]); - assert_prolog_failure!(&mut wam, "p(z, h(Z, w), f(Z))."); - - submit(&mut wam, "p(f(X), h(Y, f(a)), Y)."); - - assert_prolog_success!( - &mut wam, - "p(Z, h(Z, W), f(W)).", - [["W = f(a)", "Z = f(f(a))"]] - ); -} - -#[test] -fn test_queries_on_rules() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y)."); - submit(&mut wam, "q(q, s)."); - submit(&mut wam, "r(s, t)."); - - assert_prolog_success!(&mut wam, "p(X, Y).", [["Y = t", "X = q"]]); - assert_prolog_success!(&mut wam, "p(q, t)."); - assert_prolog_failure!(&mut wam, "p(t, q)."); - assert_prolog_success!(&mut wam, "p(q, T).", [["T = t"]]); - assert_prolog_failure!(&mut wam, "p(t, t)."); - - submit(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T)."); - submit(&mut wam, "q(f(f(X)), r)."); - - assert_prolog_success!(&mut wam, "p(X, Y).", [["X = _0", "Y = _1"]]); - - submit(&mut wam, "q(f(f(x)), r)."); - - assert_prolog_success!(&mut wam, "p(X, Y).", [["X = x", "Y = _1"]]); - - submit(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y)."); - submit(&mut wam, "q(s, t)."); - submit(&mut wam, "r(X, Y) :- r(a)."); - submit(&mut wam, "r(a)."); - - assert_prolog_success!(&mut wam, "p(X, Y).", [["X = s", "Y = t"]]); - assert_prolog_failure!(&mut wam, "p(t, S)."); - assert_prolog_success!(&mut wam, "p(s, T).", [["T = t"]]); - assert_prolog_success!(&mut wam, "p(S, t).", [["S = s"]]); - - submit(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y)."); - submit(&mut wam, "q(X, Y)."); - - assert_prolog_success!( - &mut wam, - "p(f(X, Y, Z), g(b), h).", - [["Z = _3", "Y = g(b)", "X = f(a)"]] - ); - assert_prolog_failure!(&mut wam, "p(f(X, g(Y), Z), g(Z), X)."); - assert_prolog_success!( - &mut wam, - "p(f(X, g(Y), Z), g(Z), h).", - [["Z = b", "Y = b", "X = f(a)"]] - ); - assert_prolog_success!( - &mut wam, - "p(Z, Y, X).", - [["X = h", "Y = g(b)", "Z = f(f(a),g(b),_7)"]] - ); - assert_prolog_success!( - &mut wam, - "p(f(X, Y, Z), Y, h).", - [["Y = g(b)", "Z = _3", "X = f(a)"]] - ); - - submit(&mut wam, "p(_, f(_, Y, _)) :- h(Y)."); - submit(&mut wam, "h(y)."); - - assert_prolog_success!(&mut wam, "p(_, f(_, Y, _)).", [["Y = y"]]); - assert_prolog_success!(&mut wam, "p(_, f(_, y, _))."); - assert_prolog_failure!(&mut wam, "p(_, f(_, z, _))."); -} - -#[test] -fn test_queries_on_predicates() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "p(X, a). p(b, X)."); - - assert_prolog_success!(&mut wam, "p(x, Y).", [["Y = a"]]); - assert_prolog_success!( - &mut wam, - "p(X, a).", - [ - ["X = _0"], // 1st case - ["X = b"] - ] - ); // 2nd case. - assert_prolog_success!( - &mut wam, - "p(b, X).", - [ - ["X = a"], // 1st case - ["X = _0"] - ] - ); // 2nd case. - assert_prolog_success!(&mut wam, "p(X, X).", [["X = a"], ["X = b"]]); - assert_prolog_success!(&mut wam, "p(b, a)."); - assert_prolog_failure!(&mut wam, "p(a, b)."); - - submit(&mut wam, "p(X, Y, a). p(X, a, Y). p(X, Y, a)."); - - assert_prolog_success!(&mut wam, "p(c, d, X).", [["X = a"], ["X = a"]]); - assert_prolog_success!(&mut wam, "p(a, a, a)."); - assert_prolog_failure!(&mut wam, "p(b, c, d)."); - - submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X)."); - - assert_prolog_success!(&mut wam, "p(X, Y).", [["X = _0", "Y = a"]]); - assert_prolog_success!(&mut wam, "p(x, a)."); - assert_prolog_success!(&mut wam, "p(X, a).", [["X = _0"]]); - assert_prolog_failure!(&mut wam, "p(X, b)."); - - submit(&mut wam, "q(z)."); - - assert_prolog_success_with_limit!(&mut wam, "p(X, b).", [["X = a"], ["X = a"], ["X = a"]], 3); - assert_prolog_success!(&mut wam, "p(x, a)."); - assert_prolog_success_with_limit!( - &mut wam, - "p(X, Y).", - [ - ["X = _0", "Y = a"], - ["Y = _1", "X = a"], - ["Y = _1", "X = a"] - ], - 3 - ); - - submit(&mut wam, "p(X, a). p(X, Y) :- q(Y), p(X, X)."); - - assert_prolog_success_with_limit!( - &mut wam, - "p(X, Y).", - [["X = _0", "Y = a"], ["Y = z", "X = a"]], - 2 - ); - assert_prolog_failure!(&mut wam, "p(X, b)."); - - submit(&mut wam, "p(a, z). p(X, Y) :- q(Y), p(X, Y)."); - - assert_prolog_success_with_limit!( - &mut wam, - "p(X, Y).", - [["X = a", "Y = z"], ["X = a", "Y = z"]], - 2 - ); - - assert_prolog_success_with_limit!(&mut wam, "p(X, z).", [["X = a"], ["X = a"]], 2); - assert_prolog_success!(&mut wam, "p(a, z)."); - assert_prolog_success_with_limit!(&mut wam, "p(a, X).", [["X = z"], ["X = z"]], 2); - assert_prolog_failure!(&mut wam, "p(b, a)."); - - submit( - &mut wam, - "p(X, Y, Z) :- q(X), r(Y), s(Z). - p(a, b, Z) :- q(Z).", - ); - - submit(&mut wam, "q(x)."); - submit(&mut wam, "r(y)."); - submit(&mut wam, "s(z)."); - - assert_prolog_success!( - &mut wam, - "p(X, Y, Z).", - [["Y = y", "X = x", "Z = z"], ["Y = b", "X = a", "Z = x"]] - ); - assert_prolog_failure!(&mut wam, "p(a, b, c)."); - assert_prolog_success!(&mut wam, "p(a, b, C).", [["C = x"]]); - - submit(&mut wam, "p(X) :- r(X)."); - submit(&mut wam, "r(X) :- s(X, t). r(X) :- t(X, u)."); - - submit(&mut wam, "s(x, t)."); - submit(&mut wam, "t(y, u)."); - - assert_prolog_success!(&mut wam, "p(X).", [["X = x"], ["X = y"]]); - assert_prolog_success!(&mut wam, "p(x)."); - assert_prolog_success!(&mut wam, "p(y)."); - assert_prolog_failure!(&mut wam, "p(z)."); - - submit( - &mut wam, - "p(f(f(X)), h(W), Y) :- g(W), h(W), f(X). - p(X, Y, Z) :- h(Y), g(W), z(Z).", - ); - submit(&mut wam, "g(f(X)) :- z(X). g(X) :- h(X)."); - submit(&mut wam, "h(w). h(x). h(z)."); - submit(&mut wam, "f(s)."); - submit(&mut wam, "z(Z)."); - - assert_prolog_success!( - &mut wam, - "p(X, Y, Z).", - [ - ["Y = h(w)", "X = f(f(s))", "Z = _2"], - ["Y = h(x)", "X = f(f(s))", "Z = _2"], - ["Y = h(z)", "X = f(f(s))", "Z = _2"], - ["Y = w", "Z = _2", "X = _0"], - ["Y = w", "Z = _2", "X = _0"], - ["Y = w", "Z = _2", "X = _0"], - ["Y = w", "Z = _2", "X = _0"], - ["Y = x", "Z = _2", "X = _0"], - ["Y = x", "Z = _2", "X = _0"], - ["Y = x", "Z = _2", "X = _0"], - ["Y = x", "Z = _2", "X = _0"], - ["Y = z", "Z = _2", "X = _0"], - ["Y = z", "Z = _2", "X = _0"], - ["Y = z", "Z = _2", "X = _0"], - ["Y = z", "Z = _2", "X = _0"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, X, Z).", - [ - ["Z = _1", "X = w"], - ["Z = _1", "X = w"], - ["Z = _1", "X = w"], - ["Z = _1", "X = w"], - ["Z = _1", "X = x"], - ["Z = _1", "X = x"], - ["Z = _1", "X = x"], - ["Z = _1", "X = x"], - ["Z = _1", "X = z"], - ["Z = _1", "X = z"], - ["Z = _1", "X = z"], - ["Z = _1", "X = z"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(f(f(Z)), Y, Z).", - [ - ["Y = h(w)", "Z = s"], - ["Y = h(x)", "Z = s"], - ["Y = h(z)", "Z = s"], - ["Y = w", "Z = _1"], - ["Y = w", "Z = _1"], - ["Y = w", "Z = _1"], - ["Y = w", "Z = _1"], - ["Y = x", "Z = _1"], - ["Y = x", "Z = _1"], - ["Y = x", "Z = _1"], - ["Y = x", "Z = _1"], - ["Y = z", "Z = _1"], - ["Y = z", "Z = _1"], - ["Y = z", "Z = _1"], - ["Y = z", "Z = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, X, X).", - [ - ["X = w"], - ["X = w"], - ["X = w"], - ["X = w"], - ["X = x"], - ["X = x"], - ["X = x"], - ["X = x"], - ["X = z"], - ["X = z"], - ["X = z"], - ["X = z"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y, X).", - [ - ["Y = h(w)", "X = f(f(s))"], - ["Y = h(x)", "X = f(f(s))"], - ["Y = h(z)", "X = f(f(s))"], - ["Y = w", "X = _0"], - ["Y = w", "X = _0"], - ["Y = w", "X = _0"], - ["Y = w", "X = _0"], - ["Y = x", "X = _0"], - ["Y = x", "X = _0"], - ["Y = x", "X = _0"], - ["Y = x", "X = _0"], - ["Y = z", "X = _0"], - ["Y = z", "X = _0"], - ["Y = z", "X = _0"], - ["Y = z", "X = _0"] - ] - ); - assert_prolog_failure!(&mut wam, "p(f(f(X)), h(f(X)), Y)."); - - submit(&mut wam, "p(X) :- f(Y), g(Y), i(X, Y)."); - submit(&mut wam, "g(f(a)). g(f(b)). g(f(c))."); - submit(&mut wam, "f(f(a)). f(f(b)). f(f(c))."); - submit(&mut wam, "i(X, X)."); - - assert_prolog_success!( - &mut wam, - "p(X).", - [["X = f(a)"], ["X = f(b)"], ["X = f(c)"]] - ); - - submit(&mut wam, "p(X) :- f(f(Y)), g(Y, f(Y)), i(X, f(Y))."); - submit(&mut wam, "g(Y, f(Y)) :- g(f(Y))."); - - assert_prolog_success!( - &mut wam, - "p(X).", - [["X = f(a)"], ["X = f(b)"], ["X = f(c)"]] - ); -} - -#[test] -fn test_queries_on_cuts() { - let mut wam = Machine::new(readline::input_stream()); - - // test shallow cuts. - submit( - &mut wam, - "memberchk(X, [X|_]) :- !. - memberchk(X, [_|Xs]) :- memberchk(X, Xs).", - ); - - assert_prolog_success!(&mut wam, "memberchk(X, [a,b,c]).", [["X = a"]]); - assert_prolog_success!( - &mut wam, - "memberchk([X,X], [a,b,c,[d,e],[d,d]]).", - [["X = d"]] - ); - assert_prolog_success!( - &mut wam, - "memberchk([X,X], [a,b,c,[D,d],[e,e]]).", - [["X = d", "D = d"]] - ); - assert_prolog_failure!(&mut wam, "memberchk([X,X], [a,b,c,[e,d],[f,e]])."); - assert_prolog_failure!(&mut wam, "memberchk([X,X,Y], [a,b,c,[e,d],[f,e]])."); - assert_prolog_success!( - &mut wam, - "memberchk([X,X,Y], [a,b,c,[e,e,d],[f,e]]).", - [["X = e", "Y = d"]] - ); - - // test deep cuts. - submit(&mut wam, "commit :- a, !."); - - assert_prolog_failure!(&mut wam, "commit."); - - submit(&mut wam, "a."); - - assert_prolog_success!(&mut wam, "commit."); - - submit(&mut wam, "commit(X) :- a(X), !."); - - assert_prolog_failure!(&mut wam, "commit(X)."); - - submit(&mut wam, "a(x)."); - - assert_prolog_success!(&mut wam, "commit(X).", [["X = x"]]); - - submit(&mut wam, "a :- b, !, c. a :- d."); - - assert_prolog_failure!(&mut wam, "a."); - - submit(&mut wam, "b."); - - assert_prolog_failure!(&mut wam, "a."); - - submit(&mut wam, "d."); - - // we've committed to the first clause since the query on b - // succeeds, so we expect failure here. - assert_prolog_failure!(&mut wam, "a."); - - submit(&mut wam, "c."); - - assert_prolog_success!(&mut wam, "a."); - - submit(&mut wam, "a(X) :- b, !, c(X). a(X) :- d(X)."); - - assert_prolog_failure!(&mut wam, "a(X)."); - - submit(&mut wam, "c(c)."); - submit(&mut wam, "d(d)."); - - assert_prolog_success!(&mut wam, "a(X).", [["X = c"]]); - - submit(&mut wam, "b."); - - assert_prolog_success!(&mut wam, "a(X).", [["X = c"]]); -} - -#[test] -fn test_queries_on_lists() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "p([Z, W])."); - - assert_prolog_success!(&mut wam, "p([Z, Z]).", [["Z = _0"]]); - assert_prolog_failure!(&mut wam, "p([Z, W, Y])."); - assert_prolog_success!(&mut wam, "p([Z | W]).", [["Z = _0", "W = [_3]"]]); - assert_prolog_success!(&mut wam, "p([Z | [Z]]).", [["Z = _0"]]); - assert_prolog_success!(&mut wam, "p([Z | [W]]).", [["Z = _2", "W = _0"]]); - assert_prolog_failure!(&mut wam, "p([Z | []])."); - - submit(&mut wam, "p([Z, Z])."); - - assert_prolog_success!(&mut wam, "p([Z, Z]).", [["Z = _0"]]); - assert_prolog_failure!(&mut wam, "p([Z, W, Y])."); - assert_prolog_success!(&mut wam, "p([Z | W]).", [["Z = _0", "W = [_0]"]]); - assert_prolog_success!(&mut wam, "p([Z | [Z]]).", [["Z = _0"]]); - assert_prolog_success!(&mut wam, "p([Z | [W]]).", [["Z = _0", "W = _0"]]); - assert_prolog_failure!(&mut wam, "p([Z | []])."); - - submit(&mut wam, "p([Z])."); - - assert_prolog_failure!(&mut wam, "p([Z, Z])."); - assert_prolog_failure!(&mut wam, "p([Z, W, Y])."); - assert_prolog_success!(&mut wam, "p([Z | W]).", [["W = []", "Z = _0"]]); - assert_prolog_failure!(&mut wam, "p([Z | [Z]])."); - assert_prolog_failure!(&mut wam, "p([Z | [W]])."); - assert_prolog_success!(&mut wam, "p([Z | []]).", [["Z = _0"]]); - - submit( - &mut wam, - "member(X, [X|_]). - member(X, [_|Xs]) :- member(X, Xs).", - ); - - assert_prolog_failure!(&mut wam, "member(a, [c, [X, Y]])."); - assert_prolog_failure!(&mut wam, "member(c, [a, [X, Y]])."); - assert_prolog_success!(&mut wam, "member(a, [a, [X, Y]]).", [["X = _2", "Y = _0"]]); - - assert_prolog_success!( - &mut wam, - "member(a, [X, Y, Z]).", - [ - ["Y = _2", "X = a", "Z = _0"], - ["Y = a", "X = _4", "Z = _0"], - ["Y = _2", "X = _4", "Z = a"] - ] - ); - - assert_prolog_success!( - &mut wam, - "member([X, X], [a, [X, Y]]).", - [["X = _0", "Y = _0"]] - ); - assert_prolog_success!( - &mut wam, - "member([X, X], [a, [b, c], [b, b], [Z, x], [d, f]]).", - [["Z = _14", "X = b"], ["Z = x", "X = x"]] - ); - assert_prolog_failure!( - &mut wam, - "member([X, X], [a, [b, c], [b, d], [foo, x], [d, f]])." - ); - assert_prolog_success!( - &mut wam, - "member([X, Y], [a, [b, c], [b, b], [Z, x], [d, f]]).", - [ - ["X = b", "Y = c", "Z = _14"], - ["X = b", "Y = b", "Z = _14"], - ["X = _2", "Y = x", "Z = _2"], - ["X = d", "Y = f", "Z = _14"] - ] - ); - assert_prolog_failure!( - &mut wam, - "member([X, Y, Y], [a, [b, c], [b, b], [Z, x], [d, f]])." - ); - assert_prolog_failure!( - &mut wam, - "member([X, Y, Z], [a, [b, c], [b, b], [Z, x], [d, f]])." - ); -} - -#[test] -fn test_queries_on_conjuctive_queries() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "p(a, b)."); - submit(&mut wam, "q(b, c)."); - - assert_prolog_success!(&mut wam, "p(X, Y), q(Y, Z).", [["X = a", "Z = c", "Y = b"]]); - assert_prolog_failure!(&mut wam, "p(X, Y), q(Y, X)."); - - submit(&mut wam, "p(a, [f(g(X))])."); - submit(&mut wam, "q(Y, c)."); - - assert_prolog_success!( - &mut wam, - "p(X, Y), q(Y, Z).", - [["Y = [f(g(_9))]", "X = a", "Z = c"]] - ); - assert_prolog_failure!(&mut wam, "p(X, Y), q(Y, X)."); - - submit( - &mut wam, - "member(X, [X|_]). - member(X, [_|Xs]) :- member(X, Xs).", - ); - - assert_prolog_success!( - &mut wam, - "member(X, [a,b,c]), member(X, [a,b,c]).", - [["X = a"], ["X = b"], ["X = c"]] - ); - assert_prolog_success!( - &mut wam, - "member(X, [a,b,c]), member(X, [b,c]).", - [["X = b"], ["X = c"]] - ); - assert_prolog_success!(&mut wam, "member(X, [a,c]), member(X, [b,c]).", [["X = c"]]); - assert_prolog_success!( - &mut wam, - "member(X, [a,b,c,d]), !, member(X, [a,d]).", - [["X = a"]] - ); - assert_prolog_failure!(&mut wam, "member(X, [a,b,c,d]), !, member(X, [e])."); - assert_prolog_success!( - &mut wam, - "member([X,X],[a,b,c,[d,d],[e,d]]), - member(X, [a,b,c,d,e,f,g]), - member(Y, [X, a, b, c, d]).", - [ - ["X = d", "Y = d"], - ["X = d", "Y = a"], - ["X = d", "Y = b"], - ["X = d", "Y = c"], - ["X = d", "Y = d"] - ] - ); - - submit(&mut wam, "p(a, [f(g(X))]). p(X, c) :- c."); - submit(&mut wam, "c."); - submit(&mut wam, "q(Y, c)."); - - assert_prolog_success!( - &mut wam, - "p(X, Y), q(Y, Z).", - [ - ["X = a", "Z = c", "Y = [f(g(_9))]"], - ["X = _0", "Z = c", "Y = c"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y), !, q(Y, Z).", - [["Z = c", "Y = [f(g(_9))]", "X = a"]] - ); - - submit( - &mut wam, - "q([f(g(x))], Z). q([f(g(y))], Y). q([f(g(z))], a).", - ); - - assert_prolog_success!( - &mut wam, - "p(X, Y), q(Y, Z).", - [ - ["Z = _11", "X = a", "Y = [f(g(x))]"], - ["Z = _11", "X = a", "Y = [f(g(y))]"], - ["Z = a", "X = a", "Y = [f(g(z))]"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y), !, q(Y, Z).", - [ - ["X = a", "Y = [f(g(x))]", "Z = _11"], - ["X = a", "Y = [f(g(y))]", "Z = _11"], - ["X = a", "Y = [f(g(z))]", "Z = a"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y), !, q(Y, X).", - [ - ["X = a", "Y = [f(g(x))]"], - ["X = a", "Y = [f(g(y))]"], - ["X = a", "Y = [f(g(z))]"] - ] - ); - - submit( - &mut wam, - "p(X, [f(g(x))]). p(X, [f(g(y))]). p(X, [f(g(z))]).", - ); - - assert_prolog_failure!(&mut wam, "q(f(X), Y), p(X, Y)."); - assert_prolog_success!( - &mut wam, - "q(X, Y), p(X, Y).", - [ - ["Y = [f(g(x))]", "X = [f(g(x))]"], - ["Y = [f(g(y))]", "X = [f(g(x))]"], - ["Y = [f(g(z))]", "X = [f(g(x))]"], - ["Y = [f(g(x))]", "X = [f(g(y))]"], - ["Y = [f(g(y))]", "X = [f(g(y))]"], - ["Y = [f(g(z))]", "X = [f(g(y))]"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y), q(X, Y).", - [ - ["Y = [f(g(x))]", "X = [f(g(x))]"], - ["Y = [f(g(x))]", "X = [f(g(y))]"], - ["Y = [f(g(y))]", "X = [f(g(x))]"], - ["Y = [f(g(y))]", "X = [f(g(y))]"], - ["Y = [f(g(z))]", "X = [f(g(x))]"], - ["Y = [f(g(z))]", "X = [f(g(y))]"] - ] - ); - assert_prolog_success!( - &mut wam, - "p(X, Y), q(Y, X).", - [ - ["Y = [f(g(x))]", "X = _10"], - ["Y = [f(g(y))]", "X = _10"], - ["Y = [f(g(z))]", "X = a"] - ] - ); - assert_prolog_success!( - &mut wam, - "q(X, Y), p(Y, X).", - [ - ["Y = _9", "X = [f(g(x))]"], - ["Y = _9", "X = [f(g(y))]"], - ["Y = a", "X = [f(g(z))]"] - ] - ); -} - -#[test] -fn test_queries_on_call_n() { - let mut wam = Machine::new(readline::input_stream()); - - submit( - &mut wam, - "maplist(_, []). - maplist(P, [X|Xs]) :- call(P, X), maplist(P, Xs).", - ); - submit(&mut wam, "f(a). f(b). f(c)."); - - assert_prolog_success!( - &mut wam, - "maplist(f, [X,Y,Z]).", - [ - ["X = a", "Y = a", "Z = a"], - ["X = a", "Y = a", "Z = b"], - ["X = a", "Y = a", "Z = c"], - ["X = a", "Y = b", "Z = a"], - ["X = a", "Y = b", "Z = b"], - ["X = a", "Y = b", "Z = c"], - ["X = a", "Y = c", "Z = a"], - ["X = a", "Y = c", "Z = b"], - ["X = a", "Y = c", "Z = c"], - ["X = b", "Y = a", "Z = a"], - ["X = b", "Y = a", "Z = b"], - ["X = b", "Y = a", "Z = c"], - ["X = b", "Y = b", "Z = a"], - ["X = b", "Y = b", "Z = b"], - ["X = b", "Y = b", "Z = c"], - ["X = b", "Y = c", "Z = a"], - ["X = b", "Y = c", "Z = b"], - ["X = b", "Y = c", "Z = c"], - ["X = c", "Y = a", "Z = a"], - ["X = c", "Y = a", "Z = b"], - ["X = c", "Y = a", "Z = c"], - ["X = c", "Y = b", "Z = a"], - ["X = c", "Y = b", "Z = b"], - ["X = c", "Y = b", "Z = c"], - ["X = c", "Y = c", "Z = a"], - ["X = c", "Y = c", "Z = b"], - ["X = c", "Y = c", "Z = c"] - ] - ); - - assert_prolog_success!( - &mut wam, - "maplist(f, [a,Y,Z]).", - [ - ["Y = a", "Z = a"], - ["Y = a", "Z = b"], - ["Y = a", "Z = c"], - ["Y = b", "Z = a"], - ["Y = b", "Z = b"], - ["Y = b", "Z = c"], - ["Y = c", "Z = a"], - ["Y = c", "Z = b"], - ["Y = c", "Z = c"] - ] - ); - - assert_prolog_success!( - &mut wam, - "maplist(f, [X,a,b]).", - [["X = a"], ["X = b"], ["X = c"]] - ); - assert_prolog_success!(&mut wam, "maplist(f, [c,a,b])."); - assert_prolog_failure!(&mut wam, "maplist(f, [d,e,f])."); - assert_prolog_success!(&mut wam, "maplist(f, [])."); - assert_prolog_failure!(&mut wam, "maplist(f(X), [a,b,c])."); - - submit(&mut wam, "f(X) :- call(X), call(X)."); - submit(&mut wam, "p(x). p(y)."); - - assert_prolog_failure!(&mut wam, "f(p)."); - assert_prolog_success!(&mut wam, "f(p(X)).", [["X = x"], ["X = y"]]); - assert_prolog_success!(&mut wam, "f(p(x))."); - assert_prolog_failure!(&mut wam, "f(p(w))."); - assert_prolog_failure!(&mut wam, "f(p(X, Y))."); - - submit(&mut wam, "f(P) :- call(P, X), call(P, Y)."); - - assert_prolog_success!(&mut wam, "f(p)."); - assert_prolog_failure!(&mut wam, "f(non_existent)."); - - submit(&mut wam, "f(P, X, Y) :- call(P, X), call(P, Y)."); - - assert_prolog_success!( - &mut wam, - "f(p, X, Y).", - [ - ["Y = x", "X = x"], - ["Y = y", "X = x"], - ["Y = x", "X = y"], - ["Y = y", "X = y"] - ] - ); - assert_prolog_success!(&mut wam, "f(p, x, Y).", [["Y = x"], ["Y = y"]]); - assert_prolog_success!(&mut wam, "f(p, X, y).", [["X = x"], ["X = y"]]); - assert_prolog_success!(&mut wam, "f(p, x, y)."); - assert_prolog_failure!(&mut wam, "f(p, X, z)."); - assert_prolog_failure!(&mut wam, "f(p, z, Y)."); - - assert_prolog_success!(&mut wam, "call(p, X).", [["X = x"], ["X = y"]]); - assert_prolog_success!(&mut wam, "call(p, x)."); - assert_prolog_success!(&mut wam, "call(p, y)."); - assert_prolog_failure!(&mut wam, "call(p, z)."); - - submit(&mut wam, "r(f(X)) :- p(X). r(g(Y)) :- p(Y)."); - - assert_prolog_success!( - &mut wam, - "f(r, X, Y).", - [ - ["X = f(x)", "Y = f(x)"], - ["X = f(x)", "Y = f(y)"], - ["X = f(x)", "Y = g(x)"], - ["X = f(x)", "Y = g(y)"], - ["X = f(y)", "Y = f(x)"], - ["X = f(y)", "Y = f(y)"], - ["X = f(y)", "Y = g(x)"], - ["X = f(y)", "Y = g(y)"], - ["X = g(x)", "Y = f(x)"], - ["X = g(x)", "Y = f(y)"], - ["X = g(x)", "Y = g(x)"], - ["X = g(x)", "Y = g(y)"], - ["X = g(y)", "Y = f(x)"], - ["X = g(y)", "Y = f(y)"], - ["X = g(y)", "Y = g(x)"], - ["X = g(y)", "Y = g(y)"] - ] - ); - assert_prolog_success!( - &mut wam, - "f(r, X, X).", - [["X = f(x)"], ["X = f(y)"], ["X = g(x)"], ["X = g(y)"]] - ); - assert_prolog_success!( - &mut wam, - "f(r, f(X), g(Y)).", - [ - ["X = x", "Y = x"], - ["X = x", "Y = y"], - ["X = y", "Y = x"], - ["X = y", "Y = y"] - ] - ); - assert_prolog_failure!(&mut wam, "f(r, j(X), h(Y))."); - - submit(&mut wam, "p(one, one). p(one, two). p(two, two)."); - - assert_prolog_success!( - &mut wam, - "f(p(one), X, Y).", - [ - ["X = one", "Y = one"], - ["X = one", "Y = two"], - ["X = two", "Y = one"], - ["X = two", "Y = two"] - ] - ); - assert_prolog_success!(&mut wam, "f(p(one), X, X).", [["X = one"], ["X = two"]]); - assert_prolog_success!(&mut wam, "f(p(one), one, Y).", [["Y = one"], ["Y = two"]]); - assert_prolog_success!(&mut wam, "f(p(one), one, two)."); - assert_prolog_failure!(&mut wam, "f(p(one), one, three)."); - - assert_prolog_failure!(&mut wam, "f(p(two), one, two)."); - assert_prolog_failure!(&mut wam, "f(p(two), two, one)."); - assert_prolog_success!(&mut wam, "f(p(two), two, two)."); - assert_prolog_failure!(&mut wam, "f(p(two), two, three)."); - - assert_prolog_failure!(&mut wam, "f(p(three), X, Y)."); - assert_prolog_failure!(&mut wam, "f(p(three), X, X)."); - assert_prolog_failure!(&mut wam, "f(p(three), one, Y)."); - assert_prolog_failure!(&mut wam, "f(p(three), one, two)."); - assert_prolog_failure!(&mut wam, "f(p(three), one, three)."); - - submit(&mut wam, "f(P, X) :- call(P, X)."); - - assert_prolog_success!(&mut wam, "f(p(one), one)."); - assert_prolog_success!(&mut wam, "f(p(two), two)."); - assert_prolog_failure!(&mut wam, "f(p(two), one)."); - assert_prolog_failure!(&mut wam, "f(p(three), one)."); - assert_prolog_failure!(&mut wam, "f(p(one), three)."); - assert_prolog_failure!(&mut wam, "f(p(two), three)."); - - submit(&mut wam, "p(f(g(X)), compound, [lists,are,good])."); - - assert_prolog_success!( - &mut wam, - "call(p(f(g(X))),Y,Z).", - [["Y = compound", "Z = [lists,are,good]", "X = _3"]] - ); - - submit( - &mut wam, - "david_lynch(coffee). - david_lynch(pie). - david_lynch(kyle(Film)) :- kyle(Film).", - ); - - submit( - &mut wam, - "kyle(dune). - kyle(blue_velvet). - kyle(showgirls). - kyle(flintstones).", - ); - - assert_prolog_success!( - &mut wam, - "call(david_lynch,X).", - [ - ["X = coffee"], - ["X = pie"], - ["X = kyle(dune)"], - ["X = kyle(blue_velvet)"], - ["X = kyle(showgirls)"], - ["X = kyle(flintstones)"] - ] - ); - assert_prolog_success!( - &mut wam, - "call(david_lynch,kyle(Film)).", - [ - ["Film = dune"], - ["Film = blue_velvet"], - ["Film = showgirls"], - ["Film = flintstones"] - ] - ); - assert_prolog_failure!(&mut wam, "call(david_lynch,kyle(Film),_)."); - - submit(&mut wam, "call_mult(P,X) :- call(call(P),X)."); - - assert_prolog_success!( - &mut wam, - "call_mult(p(X),Y).", - [ - ["Y = one", "X = one"], - ["Y = two", "X = one"], - ["Y = two", "X = two"] - ] - ); - assert_prolog_success!(&mut wam, "call_mult(p(X),X).", [["X = one"], ["X = two"]]); - assert_prolog_success!(&mut wam, "call_mult(p(one),X).", [["X = one"], ["X = two"]]); - assert_prolog_success!(&mut wam, "call_mult(p(X),one).", [["X = one"]]); - - assert_prolog_failure!(&mut wam, "call_mult(p(two),one)."); - assert_prolog_success!(&mut wam, "call_mult(p(two),two)."); - - assert_prolog_success!( - &mut wam, - "call(call(p(one)),X),call(call(p(two)),two).", - [["X = one"], ["X = two"]] - ); - assert_prolog_success!( - &mut wam, - "call(call(p(one,X))),call(call(p(two,two))).", - [["X = one"], ["X = two"]] - ); - assert_prolog_failure!(&mut wam, "call(call(p(one)),X),call(call(p(two)),one)."); - assert_prolog_success!( - &mut wam, - "call(call(p(X)),X),call(call(p(Y)),Y).", - [ - ["X = one", "Y = one"], - ["X = one", "Y = two"], - ["X = two", "Y = one"], - ["X = two", "Y = two"] - ] - ); - assert_prolog_success!( - &mut wam, - "call(call(p(X)),Y),call(call(p(Y)),X).", - [["X = one", "Y = one"], ["X = two", "Y = two"]] - ); - assert_prolog_success!( - &mut wam, - "call(call(p),X,Y),call(call(call(p)),X,Y).", - [ - ["X = one", "Y = one"], - ["Y = two", "X = one"], - ["Y = two", "X = two"] - ] - ); - assert_prolog_success!( - &mut wam, - "call(call(p),X,Y),call(call(call(p(X))),Y).", - [ - ["X = one", "Y = one"], - ["Y = two", "X = one"], - ["Y = two", "X = two"] - ] - ); - assert_prolog_failure!(&mut wam, "call(call(p),X,Y),call(call(call(p(X))),X,Y)."); - assert_prolog_success!( - &mut wam, - "call(call(p),X,Y),call(call(call(p(X))),X).", - [ - ["X = one", "Y = one"], - ["Y = two", "X = one"], - ["Y = two", "X = two"] - ] - ); - - submit(&mut wam, "f(call(f,undefined)). f(undefined)."); - submit(&mut wam, "call_var(P) :- P."); - - assert_prolog_success!(&mut wam, "f(X),call_var(X).", [["X = call(f,undefined)"]]); - assert_prolog_success!( - &mut wam, - "f(call(f,Q)),call_var(call(f,Q)).", - [["Q = undefined"]] - ); - assert_prolog_failure!(&mut wam, "call_var(call(undefined,Q))."); - - assert_prolog_failure!(&mut wam, "call(call)."); - assert_prolog_failure!(&mut wam, "call(call(call))."); - assert_prolog_failure!(&mut wam, "call(call(call(call)))."); - assert_prolog_failure!(&mut wam, "call(call(call(call(call))))."); - assert_prolog_failure!(&mut wam, "call(call(call(call(call(call)))))."); - assert_prolog_success!( - &mut wam, - "call(call(call(call(call(call(p(X))))))).", - [["X = x"], ["X = y"]] - ); -} - */ - -#[test] -fn test_queries_on_arithmetic() { - let mut wam = Machine::new(readline::input_stream()); - - assert_prolog_success!(&mut wam, "X is 1, X is X.", [["X = 1"]]); - assert_prolog_failure!(&mut wam, "X is 1, X is X + 1."); - assert_prolog_success!(&mut wam, "X is 1, X is X + 0.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is 1, X is X * 1.", [["X = 1"]]); - assert_prolog_failure!(&mut wam, "X is 1, X is X * 2."); - - assert_prolog_failure!(&mut wam, "X is 1 + a."); - assert_prolog_failure!(&mut wam, "X is 1 + Y."); - assert_prolog_success!( - &mut wam, - "Y is 2 + 2 - 2, X is 1 + Y, X = 3.", - [["X = 3", "Y = 2"]] - ); - assert_prolog_failure!(&mut wam, "Y is 2 + 2 - 2, X is 1 + Y, X = 2."); - - assert_prolog_success!(&mut wam, "6 is 6."); - assert_prolog_success!(&mut wam, "6 is 3 + 3."); - assert_prolog_success!(&mut wam, "6 is 3 * 2."); - assert_prolog_failure!(&mut wam, "7 is 3 * 2."); - assert_prolog_failure!(&mut wam, "7 is 3.5 * 2."); - assert_prolog_success!(&mut wam, "7.0 is 3.5 * 2."); - assert_prolog_success!(&mut wam, "7.0 is 14 / 2."); - assert_prolog_failure!(&mut wam, "4.666 is 14.0 / 3."); - assert_prolog_success!(&mut wam, "4.0 is 8.0 / 2."); - - submit(&mut wam, "f(X) :- X is 5 // 0."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", - [["E = zero_divisor", "X = _1"]] - ); - - submit(&mut wam, "f(X) :- X is (5 rdiv 1) / 0."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", - [["E = zero_divisor", "X = _1"]] - ); - - submit(&mut wam, "f(X) :- X is 5.0 / 0."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), error(evaluation_error(E), _), true), E = zero_divisor.", - [["E = zero_divisor", "X = _1"]] - ); - - assert_prolog_success!( - &mut wam, - "X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z is X+Y.", - [["Y = 4", "X = 4", "Z = 8"]] - ); - - assert_prolog_success!( - &mut wam, - "X is ((3 + 4) // 2) + 2 - 1 // 1, Y is 2+2, Z = 8, Y is 4.", - [["Y = 4", "X = 4", "Z = 8"]] - ); - - assert_prolog_success!( - &mut wam, - "X is (3 rdiv 4) / 2, Y is 3 rdiv 8.", - [["X = 0.375", "Y = 3/8"]] - ); - - assert_prolog_success!(&mut wam, "X is 10 xor -4, X is -10.", [["X = -10"]]); - assert_prolog_success!(&mut wam, "X is 4 xor -7, X is -3.", [["X = -3"]]); - assert_prolog_success!(&mut wam, "X is 10 xor 5 + 55, X = 70.", [["X = 70"]]); - - assert_prolog_success!(&mut wam, "X is 10 rem -3, X = 1.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is 10 mod -3, X is -2.", [["X = -2"]]); - - assert_prolog_success!(&mut wam, "call(is, X, 3 + 4).", [["X = 7"]]); - - assert_prolog_success!( - &mut wam, - "Y is 3 + 3, call(is, X, Y + 4).", - [["Y = 6", "X = 10"]] - ); - assert_prolog_success!(&mut wam, "call(is, X, 3 + 4.5).", [["X = 7.5"]]); - assert_prolog_success!( - &mut wam, - "X is 2 rdiv 3, call(is, Y, X*X).", - [["X = 2/3", "Y = 4/9"]] - ); - - assert_prolog_failure!(&mut wam, "call(>, 3, 3 + 3)."); - assert_prolog_failure!(&mut wam, "X is 3 + 3, call(>, 3, X)."); - - assert_prolog_success!(&mut wam, "X is 3 + 3, call(<, 3, X).", [["X = 6"]]); - assert_prolog_success!(&mut wam, "X is 3 + 3, X =:= 3 + 3.", [["X = 6"]]); - - assert_prolog_success!( - &mut wam, - "catch(call(is, X, 3 // 0), error(E, _), true).", - [["X = _5", "E = evaluation_error(zero_divisor)"]] - ); - - assert_prolog_success!( - &mut wam, - "catch(call(is, X, 3 // 3), _, true).", - [["X = 1"]] - ); - - submit( - &mut wam, - "f(X, Sum) :- ( integer(X) -> Sum is X + X * X + 3 ; - var(X) -> Sum = 1, X = 1 ).", - ); - - assert_prolog_success!(&mut wam, "f(X, Sum).", [["X = 1", "Sum = 1"]]); - assert_prolog_success!(&mut wam, "f(5, Sum).", [["Sum = 33"]]); - assert_prolog_success!(&mut wam, "f(5, 33)."); - assert_prolog_failure!(&mut wam, "f(5, 32)."); - - // exponentiation. - - // the ~ operators tests whether |X - Y| <= 1/10000... - // or whatever degree of approximation used by Newton's method in rational_pow. - submit(&mut wam, ":- op(900, xfx, ~)."); - submit(&mut wam, "X ~ Y :- abs(X - Y) =< 1 rdiv 10000."); - - assert_prolog_success!(&mut wam, "X is 3 ** 3.", [["X = 27"]]); - assert_prolog_success!(&mut wam, "X is 3 ** 0.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is 3 ** -0.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is 3 ** 1.", [["X = 3"]]); - assert_prolog_success!(&mut wam, "X is (-3) ** 3.", [["X = -27"]]); - assert_prolog_success!(&mut wam, "X is (-3) ** 0.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is (-3) ** -0.", [["X = 1"]]); - assert_prolog_success!(&mut wam, "X is (-3) ** 1.", [["X = -3"]]); - // assert_prolog_success!(&mut wam, "X is (1 rdiv 27) ** -3, X ~ 19683."); - // assert_prolog_success!(&mut wam, "X is (-1 rdiv 27) ** -3, X ~ -19683."); - - assert_prolog_success!(&mut wam, "X is 0.0 ** 0.", [["X = 1"]]); - assert_prolog_success!( - &mut wam, - "catch(_ is 0.0 ** -2342, error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - assert_prolog_success!(&mut wam, "X is 0.0 ** 2342.", [["X = 0"]]); - - assert_prolog_success!( - &mut wam, - "catch(_ is (-3) ** (1 rdiv 2), error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(_ is (-3/2) ** (1 rdiv 2), error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(_ is (-3 rdiv 2) ** (1 rdiv 4), error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(_ is (-3 rdiv 2) ** (-1 rdiv 4), error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(_ is 0 ** (-5 rdiv 4), error(E, _), true).", - [["E = evaluation_error(undefined)"]] - ); - - assert_prolog_success!(&mut wam, "X is 3 ** (1 rdiv 3), Y is X ** 3, Y ~ 3."); - // assert_prolog_success!(&mut wam, "X is (-3) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); - // assert_prolog_failure!(&mut wam, "X is (-5) ** (1 rdiv 3), Y is X ** 3, Y ~ -3."); - assert_prolog_success!(&mut wam, "X is 5 ** (1 rdiv 3), Y is X ** 3, Y ~ 5."); - assert_prolog_success!( - &mut wam, - "X is (1 rdiv 3) ** 0.5, Y is X ** 2, 1 rdiv 3 ~ Y." - ); - - // assert_prolog_success!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ -1 rdiv 5."); - // assert_prolog_failure!(&mut wam, "X is (-5) ** (-1 rdiv 3), Y is X ** 3, Y ~ 1 rdiv 5."); - - assert_prolog_success!(&mut wam, "X is (0 rdiv 5) ** 5.", [["X = 0"]]); - assert_prolog_success!(&mut wam, "X is (-0 rdiv 5) ** 5.", [["X = 0"]]); - assert_prolog_success!(&mut wam, "X is (0 rdiv 5) ** 0.", [["X = 1.0"]]); - assert_prolog_success!( - &mut wam, - "catch(_ is (0 rdiv 0) ** 5, error(E, _), true).", - [["E = evaluation_error(zero_divisor)"]] - ); -} -/* -#[test] -fn test_queries_on_exceptions() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, "f(a). f(_) :- throw(stuff)."); - submit(&mut wam, "handle(stuff)."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), E, handle(E)).", - [["E = _2", "X = a"], ["E = stuff", "X = _1"]] - ); - - submit(&mut wam, "f(a). f(X) :- g(X)."); - submit(&mut wam, "g(x). g(y). g(z)."); - submit(&mut wam, "handle(x). handle(y)."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), X, handle(X)).", - [["X = a"], ["X = x"], ["X = y"], ["X = z"]] - ); - assert_prolog_success!(&mut wam, "catch(f(a), _, handle(X)).", [["X = _4"]]); - assert_prolog_failure!(&mut wam, "catch(f(b), _, handle(X))."); - - submit(&mut wam, "g(x). g(X) :- throw(x)."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), x, handle(X)).", - [["X = a"], ["X = x"], ["X = x"], ["X = y"]] - ); - assert_prolog_success!( - &mut wam, - "catch(f(X), x, handle(z)).", - [["X = a"], ["X = x"]] - ); - assert_prolog_success!(&mut wam, "catch(f(z), x, handle(x))."); - assert_prolog_success!(&mut wam, "catch(f(z), x, handle(y))."); - assert_prolog_failure!(&mut wam, "catch(f(z), x, handle(z))."); - - submit(&mut wam, "f(X) :- throw(stuff)."); - submit(&mut wam, "handle(stuff). handle(other_stuff)."); - - // the first 3 cases should deterministically succeed. - assert_prolog_success!( - &mut wam, - "catch(f(X), E, handle(E)).", - [["X = _1", "E = stuff"]] - ); - assert_prolog_success!( - &mut wam, - "catch(f(X), E, handle(stuff)).", - [["X = _1", "E = stuff"]] - ); - assert_prolog_success!( - &mut wam, - "catch(f(X), E, handle(other_stuff)).", - [["X = _1", "E = stuff"]] - ); - assert_prolog_failure!(&mut wam, "catch(f(X), E, handle(not_stuff))."); - - submit(&mut wam, "f(success). f(X) :- catch(g(X), E, handle(E))."); - submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X)."); - submit(&mut wam, "handle(x). handle(y). handle(z)."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), E, E).", - [ - ["X = success", "E = _2"], - ["X = g_success", "E = _2"], - ["X = g_success_2", "E = _2"], - ["X = _1", "E = _2"], - ["X = _1", "E = _2"], - ["X = _1", "E = _2"] - ] - ); - assert_prolog_failure!(&mut wam, "catch(f(fail), _, _)."); - assert_prolog_success!(&mut wam, "catch(f(x), _, _)."); - assert_prolog_success!(&mut wam, "catch(f(y), _, _)."); - assert_prolog_success!(&mut wam, "catch(f(z), _, _)."); - - submit(&mut wam, "f(success). f(E) :- catch(g(E), E, handle(E))."); - submit(&mut wam, "g(g_success). g(g_success_2). g(X) :- throw(X)."); - submit( - &mut wam, - "handle(x). handle(y). handle(z). handle(v) :- throw(X).", - ); - - assert_prolog_success!( - &mut wam, - "catch(f(X), E, E).", - [ - ["X = success", "E = _2"], - ["X = g_success", "E = _2"], - ["X = g_success_2", "E = _2"], - ["X = x", "E = _2"], - ["X = y", "E = _2"], - ["X = z", "E = _2"] - ] - ); - - submit( - &mut wam, - "handle(x). handle(y). handle(z). handle(v) :- throw(handle_top(X)).", - ); - submit(&mut wam, "handle_top(an_error_1). handle_top(an_error_2)."); - - assert_prolog_success!( - &mut wam, - "catch(f(X), E, E).", - [ - ["X = success", "E = _2"], - ["X = g_success", "E = _2"], - ["X = g_success_2", "E = _2"], - ["X = x", "E = _2"], - ["X = y", "E = _2"], - ["X = z", "E = _2"], - ["X = _1", "E = handle_top(an_error_1)"], - ["X = _1", "E = handle_top(an_error_2)"] - ] - ); - - submit( - &mut wam, - "handle(x). handle(y). handle(z). handle(v) :- throw(X).", - ); - - assert_prolog_success!( - &mut wam, - "catch(f(X), E, handle_top(E)).", - [ - ["X = success", "E = _2"], - ["X = g_success", "E = _2"], - ["X = g_success_2", "E = _2"], - ["X = x", "E = _2"], - ["X = y", "E = _2"], - ["X = z", "E = _2"], - ["E = an_error_1", "X = _1"], - ["E = an_error_2", "X = _1"] - ] - ); -} - -#[test] -fn test_queries_on_skip_max_list() { - let mut wam = Machine::new(readline::input_stream()); - - // test on proper and empty lists. - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,5,[],Xs).", - [["Xs = []", "N = 0"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,5,[a,b,c],Xs).", - [["Xs = []", "N = 3"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,2,[a,b,c],Xs).", - [["Xs = [c]", "N = 2"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,3,[a,b,c],Xs).", - [["Xs = []", "N = 3"]] - ); - - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,0,[],Xs).", - [["Xs = []", "N = 0"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,0,[a,b,c],Xs).", - [["Xs = [a,b,c]", "N = 0"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,0,[a,b,c],Xs).", - [["Xs = [a,b,c]", "N = 0"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,0,[a,b,c],Xs).", - [["Xs = [a,b,c]", "N = 0"]] - ); - - assert_prolog_failure!(&mut wam, "'$skip_max_list'(4,0,[],Xs)."); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(3,0,[a,b,c],Xs)."); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(2,0,[a,b,c],Xs)."); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(1,0,[a,b,c],Xs)."); - - assert_prolog_success!(&mut wam, "'$skip_max_list'(0,5,[],Xs).", [["Xs = []"]]); - assert_prolog_success!(&mut wam, "'$skip_max_list'(3,5,[a,b,c],Xs).", [["Xs = []"]]); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(2,2,[a,b,c],Xs).", - [["Xs = [c]"]] - ); - assert_prolog_success!(&mut wam, "'$skip_max_list'(3,3,[a,b,c],Xs).", [["Xs = []"]]); - - // tests on proper and empty lists with no max. - - // test on proper and empty lists. - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,-1,[],Xs).", - [["Xs = []", "N = 0"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,-1,[a,b,c],Xs).", - [["Xs = []", "N = 3"]] - ); - - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,-1,[],Xs).", - [["Xs = []", "N = 0"]] - ); - - assert_prolog_failure!(&mut wam, "'$skip_max_list'(4,-1,[],Xs)."); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(3,-1,[a,b,c],Xs).", - [["Xs = []"]] - ); - - assert_prolog_success!(&mut wam, "'$skip_max_list'(0,-1,[],Xs).", [["Xs = []"]]); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(3,-1,[a,b,c],Xs).", - [["Xs = []"]] - ); - - // tests on partial lists. - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(3,4,[a,b,c|X],Xs0).", - [["X = _1", "Xs0 = _1"]] - ); - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(3,3,[a,b,c|X],Xs0).", - [["X = _1", "Xs0 = _1"]] - ); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(3,2,[a,b,c|X],Xs0)."); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(3,1,[a,b,c|X],Xs0)."); - assert_prolog_failure!(&mut wam, "'$skip_max_list'(3,0,[a,b,c|X],Xs0)."); - - // tests on cyclic lists. - assert_prolog_failure!(&mut wam, "Xs = [a,b|Xs],'$skip_max_list'(3,5,X,Xs0)."); - assert_prolog_failure!( - &mut wam, - "X = [a,b|Y],Y = [c,d|X],'$skip_max_list'(4,5,X,Xs0)." - ); - assert_prolog_failure!( - &mut wam, - "X = [a,b|Y],Y = [c,d|X],'$skip_max_list'(4,3,X,Xs0)." - ); - - // tests on non lists. - assert_prolog_success!( - &mut wam, - "'$skip_max_list'(N,9,non_list,Xs).", - [["Xs = non_list", "N = 0"]] - ); -} - -#[test] -fn test_queries_on_conditionals() { - let mut wam = Machine::new(readline::input_stream()); - - submit( - &mut wam, - "test(A) :- ( A =:= 2 -> writeq(\"A is 2\") - ; A =:= 3 -> writeq(\"A is 3\") - ; A = \"not 2 or 3\" - ).", - ); - - assert_prolog_success!( - &mut wam, - "catch(test(A), error(instantiation_error, _), true)." - ); - assert_prolog_success!(&mut wam, "A = 2, test(A).", [["A = 2"]]); - assert_prolog_success!( - &mut wam, - "A = 3, test(A), B = 3, test(B).", - [["A = 3", "B = 3"]] - ); - - submit(&mut wam, "f(a). f(b)."); - submit(&mut wam, "g(1). g(2). g(3)."); - - submit( - &mut wam, - "typed_dispatch(X) :- ( var(X) -> f(X) - ; integer(X) -> g(X) - ; atomic(X)).", - ); - - assert_prolog_success!(&mut wam, "typed_dispatch(X).", [["X = a"], ["X = b"]]); - assert_prolog_success!(&mut wam, "typed_dispatch(a)."); - assert_prolog_success!(&mut wam, "typed_dispatch(b)."); - assert_prolog_success!(&mut wam, "typed_dispatch(c)."); - assert_prolog_success!(&mut wam, "typed_dispatch(1)."); - assert_prolog_success!(&mut wam, "typed_dispatch(2)."); - assert_prolog_success!(&mut wam, "typed_dispatch(3)."); - assert_prolog_failure!(&mut wam, "typed_dispatch(4)."); - assert_prolog_failure!(&mut wam, "typed_dispatch(5)."); - assert_prolog_failure!(&mut wam, "typed_dispatch(compound(term))."); - - submit(&mut wam, "f(a). f(b). f(compound(term))."); - submit( - &mut wam, - "g(X, Y) :- f(X), (atomic(X) -> X = a ; X = a ; X = compound(Y)).", - ); - - assert_prolog_success!( - &mut wam, - "g(X, Y).", - [["Y = _1", "X = a"], ["Y = term", "X = compound(term)"]] - ); - - assert_prolog_success!(&mut wam, "g(X, X).", [["X = a"]]); - assert_prolog_success!(&mut wam, "g(compound(X), X).", [["X = term"]]); - assert_prolog_success!(&mut wam, "g(X, term).", [["X = a"], ["X = compound(term)"]]); - assert_prolog_success!(&mut wam, "g(a, _)."); - assert_prolog_success!(&mut wam, "g(X, _), X = a.", [["X = a"]]); - - submit( - &mut wam, - "g(X) :- var(X) -> (var(X) -> X is 3 + 3 ; X = not_6).", - ); - - assert_prolog_success!(&mut wam, "g(X).", [["X = 6"]]); - assert_prolog_failure!(&mut wam, "g(1)."); - assert_prolog_failure!(&mut wam, "g(6)."); - assert_prolog_failure!(&mut wam, "g(not_6)."); - - assert_prolog_success!(&mut wam, "f(X), (g(Y), !).", [["X = a", "Y = 6"]]); - - submit( - &mut wam, - "test(X, [X]) :- (atomic(X) -> true ; throw(type_error(atomic_expected, X))). - test(_, _).", - ); - - assert_prolog_success!( - &mut wam, - "catch(test(a, [a]), type_error(E), true).", - [["E = _6"], ["E = _6"]] - ); - - assert_prolog_success!( - &mut wam, - "f(X), call(->, atomic(X), true).", - [["X = a"], ["X = b"]] - ); -} - -#[test] -fn test_queries_on_modules() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(lists))."); - - submit_code( - &mut wam, - " -:- module(my_lists, [local_member/2, reverse/2]). -:- use_module(library(lists), [member/2]). - -local_member(X, Xs) :- member(X, Xs). - -reverse(Xs, Ys) :- lists:reverse(Xs, Ys).", - ); - - assert_prolog_success!(&mut wam, "my_lists:local_member(1, [1,2,3])."); - assert_prolog_success!(&mut wam, "my_lists:reverse([a,b,c], [c,b,a])."); - - submit_code( - &mut wam, - " -:- module(my_lists_2, [local_member/2]). -:- use_module(library(my_lists), [local_member/2]).", - ); - - assert_prolog_success!(&mut wam, "my_lists_2:local_member(1, [1,2,3])."); - assert_prolog_success!( - &mut wam, - "catch(local_member(X, Xs), error(E, _), true).", - [[ - "X = _1", - "E = existence_error(procedure,local_member/2)", - "Xs = _2" - ]] - ); - - submit( - &mut wam, - ":- use_module(library(lists), [reverse/2]).", - ); - - assert_prolog_success!( - &mut wam, - "catch(member(_, _), error(existence_error(procedure, P), _), true).", - [["P = member/2"]] - ); - assert_prolog_success!(&mut wam, "reverse(_, _)."); - - submit(&mut wam, ":- use_module(library(lists), [])."); - - assert_prolog_success!( - &mut wam, - "catch(reverse(_, _), error(existence_error(procedure, P), _), true).", - [["P = reverse/2"]] - ); -} - -#[test] -fn test_queries_on_builtins() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(lists))."); - - assert_prolog_failure!(&mut wam, "atom(X)."); - assert_prolog_success!(&mut wam, "atom(a)."); - assert_prolog_failure!(&mut wam, "atom(\"string\")."); - assert_prolog_success!(&mut wam, "atom([])."); - assert_prolog_failure!(&mut wam, "atom(1)."); - assert_prolog_failure!(&mut wam, "atom(0)."); - assert_prolog_failure!(&mut wam, "atom(0.0)."); - assert_prolog_failure!(&mut wam, "atom([a,b,c])."); - assert_prolog_failure!(&mut wam, "atom(atop(the_trees))."); - - assert_prolog_failure!(&mut wam, "atomic(X)."); - assert_prolog_success!(&mut wam, "atomic(a)."); - assert_prolog_success!(&mut wam, "atomic(\"string\")."); - assert_prolog_success!(&mut wam, "atomic([])."); - assert_prolog_success!(&mut wam, "atomic(1)."); - assert_prolog_success!(&mut wam, "atomic(0)."); - assert_prolog_success!(&mut wam, "atomic(0.0)."); - assert_prolog_failure!(&mut wam, "atomic([a,b,c])."); - assert_prolog_failure!(&mut wam, "atomic(atop(the_trees))."); - - assert_prolog_success!(&mut wam, "var(X), X = 3, atomic(X).", [["X = 3"]]); - assert_prolog_failure!(&mut wam, "var(X), X = 3, var(X)."); - - assert_prolog_success!(&mut wam, "arg(1, f(a,b,c,d), Arg).", [["Arg = a"]]); - assert_prolog_success!(&mut wam, "arg(2, f(a,b,c,d), Arg).", [["Arg = b"]]); - assert_prolog_success!(&mut wam, "arg(3, f(a,b,c,d), Arg).", [["Arg = c"]]); - assert_prolog_success!(&mut wam, "arg(4, f(a,b,c,d), Arg).", [["Arg = d"]]); - - assert_prolog_success!( - &mut wam, - "catch(arg(N, f, Arg), error(E, _), true).", - [["E = instantiation_error", "Arg = _3", "N = _1"]] - ); - - assert_prolog_failure!(&mut wam, "arg(N, f(arg, arg, arg), not_arg)."); - assert_prolog_failure!(&mut wam, "arg(1, f(arg, not_arg, not_arg), not_arg)."); - assert_prolog_success!(&mut wam, "arg(2, f(arg, not_arg, not_arg), not_arg)."); - assert_prolog_success!(&mut wam, "arg(3, f(arg, not_arg, not_arg), not_arg)."); - - assert_prolog_success!( - &mut wam, - "functor(f(a,b,c), F, Arity).", - [["F = f", "Arity = 3"]] - ); - - assert_prolog_success!(&mut wam, "functor(f(a,b,c), F, N).", [["F = f", "N = 3"]]); - assert_prolog_failure!(&mut wam, "functor(f(a,b,c), g, N)."); - assert_prolog_success!(&mut wam, "functor(f(a,b,c), F, 3).", [["F = f"]]); - assert_prolog_failure!(&mut wam, "functor(f(a,b,c), F, 4)."); - assert_prolog_failure!(&mut wam, "functor(f(a,b,c), g, 3)."); - - assert_prolog_success!(&mut wam, "functor(F, f, 0).", [["F = f"]]); - - assert_prolog_success!(&mut wam, "functor(Func,f,3).", [["Func = f(_2,_3,_4)"]]); - assert_prolog_success!(&mut wam, "functor(Func,f,4).", [["Func = f(_2,_3,_4,_5)"]]); - - assert_prolog_success!( - &mut wam, - "catch(functor(F,\"sdf\",3),error(E,_),true).", - [["E = type_error(atom,[s,d,f])", "F = _1"]] - ); - assert_prolog_success!( - &mut wam, - "catch(functor(Func,F,3),error(E,_),true).", - [["E = instantiation_error", "Func = _1", "F = _2"]] - ); - assert_prolog_success!( - &mut wam, - "catch(functor(Func,f,N),error(E,_),true).", - [["E = instantiation_error", "Func = _1", "N = _3"]] - ); - assert_prolog_failure!(&mut wam, "catch(functor(Func,f,N),error(E,_),false)."); - - assert_prolog_success!(&mut wam, "X is 3,call(integer,X)."); - assert_prolog_failure!(&mut wam, "X is 3 + 3.5,call(integer,X)."); - assert_prolog_success!(&mut wam, "X is 3 + 3.5,\\+ call(integer,X)."); - assert_prolog_success!(&mut wam, "X is 3 + 3.5,\\+ integer(X)."); - - assert_prolog_success!(&mut wam, "Func =.. [atom].", [["Func = atom"]]); - assert_prolog_success!(&mut wam, "Func =.. [\"sdf\"].", [["Func = [s,d,f]"]]); - assert_prolog_success!(&mut wam, "Func =.. [1].", [["Func = 1"]]); - assert_prolog_success!( - &mut wam, - "catch(Func =.. [1,2],error(type_error(atom,1),_),true)." - ); - assert_prolog_success!(&mut wam, "f(1,2,3) =.. List.", [["List = [f,1,2,3]"]]); - assert_prolog_success!(&mut wam, "f(1,2,3) =.. [f,1,2,3]."); - assert_prolog_failure!(&mut wam, "f(1,2,3) =.. [f,1]."); - assert_prolog_failure!(&mut wam, "f(1,2,3) =.. [g,1,2,3]."); - assert_prolog_success!( - &mut wam, - "f(1,2,3) =.. [f,X,Y,Z].", - [["X = 1", "Y = 2", "Z = 3"]] - ); - - assert_prolog_success!(&mut wam, "length([a,b,c],N).", [["N = 3"]]); - assert_prolog_success_with_limit!( - &mut wam, - "length(Xs,N).", - [ - ["N = 0", "Xs = []"], - ["N = 1", "Xs = [_4]"], - ["N = 2", "Xs = [_4,_8]"], - ["N = 3", "Xs = [_4,_8,_12]"], - ["N = 4", "Xs = [_4,_8,_12,_16]"], - ["N = 5", "Xs = [_4,_8,_12,_16,_20]"] - ], - 6 - ); - - assert_prolog_success!(&mut wam, "length(Xs,3).", [["Xs = [_5,_9,_13]"]]); - assert_prolog_success!(&mut wam, "length([],N).", [["N = 0"]]); - assert_prolog_success!(&mut wam, "length(Xs,0).", [["Xs = []"]]); - assert_prolog_success!(&mut wam, "length([a,b,[a,b,c]],3)."); - assert_prolog_failure!(&mut wam, "length([a,b,[a,b,c]],2)."); - assert_prolog_success!( - &mut wam, - "catch(length(a,[]),error(E,_),true).", - [["E = type_error(integer,[])"]] - ); - - assert_prolog_success!( - &mut wam, - "copy_term([1,2,3],[X,Y,Z]).", - [["Z = 3", "Y = 2", "X = 1"]] - ); - assert_prolog_success!( - &mut wam, - "copy_term(f(X,[a],Z),f(X,Y,Z)).", - [["X = _3", "Y = [a]", "Z = _5"]] - ); - assert_prolog_failure!(&mut wam, "copy_term(g(X),f(X))."); - assert_prolog_success!(&mut wam, "copy_term(f(X),f(X)).", [["X = _1"]]); - assert_prolog_success!( - &mut wam, - "copy_term([[[[X,Y],Y],X]],Term).", - [["Term = [[[[_22,_26],_26],_22]]", "X = _2", "Y = _0"]] - ); - assert_prolog_success!( - &mut wam, - "copy_term([X,[Y,[X]]],Term).", - [["Term = [_12,[_16,[_12]]]", "X = _0", "Y = _4"]] - ); - - // test copy_term on cyclic terms. - assert_prolog_failure!(&mut wam, "X = g(X,Y),Y = f(X),copy_term(Y,g(Z))."); - assert_prolog_success!( - &mut wam, - "X = g(X,Y),Y = f(X),copy_term(Y,f(Z)).", - [["Y = f(g(X,Y))", "X = g(X,f(X))", "Z = g(Z,f(Z))"]] - ); - assert_prolog_success!( - &mut wam, - "X = g(X,Y),Y = f(X),copy_term(Y,V).", - [[ - "V = f(g(g(g(...,V),V),V))", - "X = g(X,f(X))", - "Y = f(g(X,Y))" - ]] - ); - assert_prolog_success!( - &mut wam, - "f(Y,Y,[X,a,[],Y]) = Term,copy_term(Term,NewTerm).", - [[ - "NewTerm = f(_16,_16,[_19,a,[],_16])", - "Term = f(_0,Y,[_6,a,[],Y])", - "X = _6", - "Y = _0" - ]] - ); - - assert_prolog_success!(&mut wam, "float(3.14159269)."); - assert_prolog_failure!(&mut wam, "float(3)."); - assert_prolog_failure!(&mut wam, "float(\"sdfsa\")."); - assert_prolog_failure!(&mut wam, "float(atom)."); - assert_prolog_failure!(&mut wam, "float(structure(functor))."); - assert_prolog_failure!(&mut wam, "float([1,2,3])."); - assert_prolog_failure!(&mut wam, "float([1,2,X])."); - assert_prolog_failure!(&mut wam, "X is 3 rdiv 4,float(X)."); - - assert_prolog_success!(&mut wam, "X is 3 rdiv 4,rational(X)."); - assert_prolog_failure!(&mut wam, "rational(3)."); - assert_prolog_failure!(&mut wam, "rational(f(X))."); - assert_prolog_failure!(&mut wam, "rational(\"sdfsa\")."); - assert_prolog_failure!(&mut wam, "rational(atom)."); - assert_prolog_failure!(&mut wam, "rational(structure(functor))."); - assert_prolog_failure!(&mut wam, "rational([1,2,3])."); - assert_prolog_failure!(&mut wam, "rational([1,2,X])."); - - assert_prolog_success!(&mut wam, "compound(functor(compound))."); - assert_prolog_success!(&mut wam, "compound(f(X))."); - assert_prolog_success!(&mut wam, "compound([1,2,3])."); - assert_prolog_failure!(&mut wam, "compound([])."); - assert_prolog_failure!(&mut wam, "compound(3.14159269)."); - assert_prolog_failure!(&mut wam, "compound(3)."); - assert_prolog_failure!(&mut wam, "compound(\"sdfsa\")."); - assert_prolog_failure!(&mut wam, "compound(atom)."); - - assert_prolog_failure!(&mut wam, "string(functor(string))."); - assert_prolog_failure!(&mut wam, "string(3.14159269)."); - assert_prolog_failure!(&mut wam, "string(3)."); - assert_prolog_failure!(&mut wam, "string(f(X))."); - assert_prolog_success!(&mut wam, "string(\"sdfsa\")."); - assert_prolog_failure!(&mut wam, "string(atom)."); - assert_prolog_failure!(&mut wam, "string([1,2,3])."); - assert_prolog_failure!(&mut wam, "string([1,2,X])."); - - assert_prolog_success!(&mut wam, "X = nonvar,nonvar(X)."); - assert_prolog_failure!(&mut wam, "nonvar(X)."); - assert_prolog_success!(&mut wam, "nonvar(f(X))."); - assert_prolog_success!(&mut wam, "nonvar(functor(nonvar))."); - assert_prolog_success!(&mut wam, "nonvar(3.14159269)."); - assert_prolog_success!(&mut wam, "nonvar(3)."); - assert_prolog_success!(&mut wam, "nonvar(\"sdfsa\")."); - assert_prolog_success!(&mut wam, "nonvar(atom)."); - assert_prolog_success!(&mut wam, "nonvar([1,2,3])."); - assert_prolog_success!(&mut wam, "nonvar([1,2,X])."); - - assert_prolog_success!(&mut wam, "A = f(A),ground(f(f(A))),ground(f(A)),ground(A)."); - assert_prolog_failure!(&mut wam, "B = f(A),ground(B)."); - assert_prolog_failure!(&mut wam, "B = f(A),ground(A)."); - - assert_prolog_success!( - &mut wam, - "ground(x),ground(f(x)),X = f(x),ground(g(f(X),[a,b]))." - ); - - assert_prolog_success!(&mut wam, "A = f(A),g(A,B) == g(f(A),B)."); - assert_prolog_failure!(&mut wam, "A = f(A),g(A,B) == g(f(A),b)."); - assert_prolog_failure!(&mut wam, "A == B."); - assert_prolog_failure!(&mut wam, "A == 12.1."); - assert_prolog_success!(&mut wam, "X = x,f(X,x) == f(x,X)."); - - assert_prolog_failure!(&mut wam, "A = f(A),g(A,B) \\== g(f(A),B)."); - assert_prolog_success!(&mut wam, "A = f(A),g(A,B) \\== g(f(A),b)."); - assert_prolog_success!(&mut wam, "A \\== B."); - assert_prolog_success!(&mut wam, "A \\== 12.1."); - assert_prolog_failure!(&mut wam, "X = x,f(X,x) \\== f(x,X)."); - - assert_prolog_success!(&mut wam, "X @=< Y."); - assert_prolog_failure!(&mut wam, "X @>= Y."); - assert_prolog_failure!(&mut wam, "X @> Y."); - assert_prolog_success!(&mut wam, "X @>= X."); - assert_prolog_failure!(&mut wam, "atom @=< \"string\"."); - assert_prolog_success!(&mut wam, "atom @=< atom."); - assert_prolog_failure!(&mut wam, "atom @=< aaa."); - assert_prolog_success!(&mut wam, "atom @>= \"string\"."); - assert_prolog_success!(&mut wam, "X is 3 + 3,X @>= Y."); - assert_prolog_success!(&mut wam, "f(X) @>= f(X)."); - assert_prolog_success!(&mut wam, "f(X) @>= a."); - assert_prolog_failure!(&mut wam, "f(X) @=< a."); - assert_prolog_success!(&mut wam, "[1,2] @=< [1,2]."); - assert_prolog_failure!(&mut wam, "[1,2,3] @=< [1,2]."); - assert_prolog_success!(&mut wam, "[] @=< [1,2]."); - assert_prolog_failure!(&mut wam, "[] @< 1."); - assert_prolog_failure!(&mut wam, "[] @< \"string\"."); - assert_prolog_failure!(&mut wam, "[] @< atom."); - assert_prolog_success!(&mut wam, "atom @< []."); - assert_prolog_success!(&mut wam, "1.1 @< 1."); - assert_prolog_success!(&mut wam, "1.0 @=< 1."); - assert_prolog_success!(&mut wam, "1 @=< 1.0."); - - submit(&mut wam, ":- use_module(library(non_iso))."); - - assert_prolog_success!(&mut wam, "variant(X, Y)."); - assert_prolog_failure!(&mut wam, "variant(f(X), f(x))."); - assert_prolog_success!(&mut wam, "variant(X, X)."); - assert_prolog_success!(&mut wam, "variant(f(x), f(x))."); - assert_prolog_failure!(&mut wam, "variant([X,Y,Z], [V,W,V])."); - assert_prolog_success!(&mut wam, "variant([X,Y,Z], [V,W,Z])."); - assert_prolog_success!(&mut wam, "variant([X,Y,X], [V,W,V])."); - assert_prolog_success!(&mut wam, "g(B) = B, g(A) = A, variant(A, B)."); - - assert_prolog_success!( - &mut wam, - "keysort([1-1,1-1],Sorted).", - [["Sorted = [1-1,1-1]"]] - ); - assert_prolog_success!( - &mut wam, - "keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted).", - [["Sorted = [1-a,1-z,1-a,2-99,2-44,3-f(_7)]"]] - ); - assert_prolog_success!(&mut wam, "keysort([X-1,1-1],[2-1,1-1]).", [["X = 2"]]); - - assert_prolog_failure!(&mut wam, "Pairs = [a-a|Pairs],keysort(Pairs,_)."); - assert_prolog_success!( - &mut wam, - "Pairs = [a-a|Pairs],catch(keysort(Pairs,_),error(E,_),true).", - [[ - "E = type_error(list,[a-a,a-a,a-a|...])", - "Pairs = [a-a|Pairs]" - ]] - ); - - assert_prolog_success!(&mut wam, "keysort([],L).", [["L = []"]]); - assert_prolog_success!( - &mut wam, - "catch(keysort([a|_],_),error(E,_),true).", - [["E = instantiation_error"]] - ); - assert_prolog_success!( - &mut wam, - "catch(keysort([],[a|a]),error(Pat,_),true).", - [["Pat = type_error(list,[a|a])"]] - ); - assert_prolog_success!( - &mut wam, - "catch(keysort(_,_),error(E,_),true).", - [["E = type_error(list,_16)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(keysort([a-1],[_|b]),error(E,_),true).", - [["E = type_error(list,[_27|b])"]] - ); - assert_prolog_success!( - &mut wam, - "catch(keysort([a-1],[a-b,c-d,a]),error(E,_),true).", - [["E = type_error(pair,a)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(keysort([a],[a-b]),error(E,_),true).", - [["E = type_error(pair,a)"]] - ); - - assert_prolog_success!( - &mut wam, - "catch(sort([a|_],_),error(E,_),true).", - [["E = instantiation_error"]] - ); - assert_prolog_success!( - &mut wam, - "catch(sort([],[a|a]),error(Pat,_),true).", - [["Pat = type_error(list,[a|a])"]] - ); - assert_prolog_success!(&mut wam, "sort([],L).", [["L = []"]]); - assert_prolog_success!( - &mut wam, - "catch(sort(_,[]),error(E,_),true).", - [["E = type_error(list,_16)"]] - ); - assert_prolog_success!( - &mut wam, - "catch(sort([a,b,c],not_a_list),error(E,_),true).", - [["E = type_error(list,not_a_list)"]] - ); - - assert_prolog_success!( - &mut wam, - "call(((G = 2 ; fail),B=3,!)).", - [["G = 2", "B = 3"]] - ); - - assert_prolog_success!(&mut wam, "call_with_inference_limit((setup_call_cleanup(S=1,(G=2;fail),writeq(S+G>B)),B=3,!),135,R).", - [["G = 2","B = 3","R = !","S = 1"]]); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit((setup_call_cleanup(S=1,(G=2;fail),writeq(S+G>B)),B=3,!),10,R).", - [[ - "S = _1", - "G = _4", - "B = _14", - "R = inference_limit_exceeded" - ]] - ); - - assert_prolog_success!(&mut wam, "X = '\\033\\'.", [["X = '\\x1b\\'"]]); - - assert_prolog_success!(&mut wam, "X = '\\n'.", [["X = '\\n'"]]); - assert_prolog_success!(&mut wam, "X = '\\b'.", [["X = '\\b'"]]); - assert_prolog_success!(&mut wam, "X = '\\v'.", [["X = '\\v'"]]); - assert_prolog_success!(&mut wam, "X = '\\a'.", [["X = '\\a'"]]); - assert_prolog_success!(&mut wam, "X = '\\f'.", [["X = '\\f'"]]); - assert_prolog_success!( - &mut wam, - "X = '\\b\\r\\f\\t\\n'.", - [["X = '\\b\\r\\f\\t\\n'"]] - ); - - assert_prolog_success!(&mut wam, "(- (1)) = -(1)."); - assert_prolog_success!(&mut wam, "(- -1) = -(-1)."); - - assert_prolog_success!(&mut wam, "X = ((*)=(*)).", [["X = ((*)=(*))"]]); - assert_prolog_success!( - &mut wam, - "X = [.,.(.,.,.)].", - [["X = ['.','.'('.','.','.')]"]] - ); - assert_prolog_success!(&mut wam, "X = a+(b*c).", [["X = a+b*c"]]); - assert_prolog_success!(&mut wam, "X = a*(b+c).", [["X = a*(b+c)"]]); - assert_prolog_success!(&mut wam, "X = [:-,-].", [["X = [:-,-]"]]); - assert_prolog_success!(&mut wam, "X = a*(b+c).", [["X = a*(b+c)"]]); - assert_prolog_success!(&mut wam, "X = (-)-(-).", [["X = (-)-(-)"]]); - assert_prolog_success!(&mut wam, "X = ((:-):-(:-)).", [["X = ((:-):-(:-))"]]); - assert_prolog_success!(&mut wam, "X = (a:-b,c).", [["X = (a:-b,c)"]]); - assert_prolog_success!(&mut wam, "X = f((f:-a,b,c)).", [["X = f((f:-a,b,c))"]]); - assert_prolog_success!(&mut wam, "X = f((f:-a,(b,c))).", [["X = f((f:-a,b,c))"]]); - assert_prolog_success!(&mut wam, "X = f((a,b,c)).", [["X = f((a,b,c))"]]); - assert_prolog_success!(&mut wam, "X = f((a,(b,c))).", [["X = f((a,b,c))"]]); - assert_prolog_success!(&mut wam, "X = f(((a,b),c)).", [["X = f(((a,b),c))"]]); - assert_prolog_success!(&mut wam, "X = f(((a,b),(c,d))).", [["X = f(((a,b),c,d))"]]); - - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 2),S).", - [["S = [1,2]", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "findall(X+Y,(X = 1),S).", - [["S = [1+_36]", "X = _1", "Y = _2"]] - ); - assert_prolog_success!(&mut wam, "findall(X,false,S).", [["S = []", "X = _0"]]); - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 1),S).", - [["S = [1,1]", "X = _0"]] - ); - assert_prolog_failure!(&mut wam, "findall(X,(X = 2 ; X = 1),[1,2])."); - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 2),[X,Y]).", - [["X = 1", "Y = 2"]] - ); - assert_prolog_success!( - &mut wam, - "catch(findall(X,4,S),error(type_error(callable,4),_),true).", - [["S = _3", "X = _1"]] - ); - - assert_prolog_success!( - &mut wam, - "bagof(X,(X=Y; X=Z),S).", - [["S = [_3,_6]", "X = _0", "Y = _3", "Z = _6"]] - ); - assert_prolog_success!(&mut wam, "bagof(X,(X=1 ; X = 2),X).", [["X = [1,2]"]]); - assert_prolog_success!( - &mut wam, - "bagof(X,(X=1 ; X = 2),S).", - [["S = [1,2]", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "bagof(1,(Y=1 ; Y=2),L).", - [["L = [1]", "Y = 1"], ["L = [1]", "Y = 2"]] - ); - - submit(&mut wam, "b(1,1). b(1,1). b(1,2). b(2,1). b(2,2). b(2,2)."); - - assert_prolog_success!( - &mut wam, - "bagof(X,b(X,Y),L).", - [ - ["L = [1,Y,2]", "X = _0", "Y = 1"], - ["L = [1,2,Y]", "X = _0", "Y = 2"] - ] - ); - - assert_prolog_success!( - &mut wam, - "bagof(X,(X=Y; X=Z; Y=1),L).", - [ - ["L = [_3,_6]", "X = _0", "Y = _3", "Z = _6"], - ["L = [_112]", "X = _0", "Y = 1", "Z = _6"] - ] - ); - - submit(&mut wam, "a(1,f(_)). a(2,f(_))."); - - assert_prolog_success!( - &mut wam, - "bagof(X,a(X,Y),L).", - [["L = [1,2]", "X = _0", "Y = f(_78)"]] - ); - - assert_prolog_success!( - &mut wam, - "setof(X,(X = 1 ; X = 2),S).", - [["S = [1,2]", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "setof(X,(X=Y ; X=Z),S).", - [["S = [_3,_6]", "X = _0", "Y = _3", "Z = _6"]] - ); - assert_prolog_failure!(&mut wam, "setof(X,false,S)."); - assert_prolog_success!( - &mut wam, - "setof(1,(Y=1 ; Y=2),L).", - [["L = [1]", "Y = 1"], ["L = [1]", "Y = 2"]] - ); - assert_prolog_success!( - &mut wam, - "setof(X,(X=Y; X=Z; Y=1),L).", - [ - ["L = [_3,_6]", "X = _0", "Y = _3", "Z = _6"], - ["L = [_112]", "Y = 1", "X = _0", "Y = 1", "Z = _6"] - ] - ); - assert_prolog_failure!( - &mut wam, - "setof(X,member(X,[f(U,b),f(V,c)]),[f(a,c),f(a,b)])." - ); - assert_prolog_success!( - &mut wam, - "setof(X,member(X,[f(U,b),f(V,c)]),[f(a,b),f(a,c)]).", - [["U = a", "V = a", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "setof(X,member(X,[V,U,f(U),f(V)]),L).", - [["L = [_2,_4,f(U),f(V)]", "U = _2", "V = _4", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "setof(X,member(X,[V,U,f(U),f(V)]),[a,b,f(a),f(b)]).", - [["U = a", "V = b", "X = _0"]] - ); - - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 2),S0,S1).", - [["S0 = [1,2|_11]", "S1 = _11", "X = _0"]] - ); - assert_prolog_success!( - &mut wam, - "findall(X+Y,(X = 1),S0,S1).", - [["S0 = [1+_44|_7]", "S1 = _7", "X = _1", "Y = _2"]] - ); - assert_prolog_success!(&mut wam, "findall(X,false,S,_).", [["S = []", "X = _0"]]); - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 1),S0,S1).", - [["S0 = [1,1|_11]", "S1 = _11", "X = _0"]] - ); - assert_prolog_failure!(&mut wam, "findall(X,(X = 2 ; X = 1),[1,2|S],S)."); - assert_prolog_success!( - &mut wam, - "findall(X,(X = 1 ; X = 2),[X,Y|S],S).", - [["S = _11", "X = 1", "Y = 2"]] - ); - assert_prolog_success!( - &mut wam, - "catch(findall(X,4,S0,S1),error(type_error(callable,4),_),true).", - [["S0 = _3", "S1 = _4", "X = _1"]] - ); - - // bagof & setof with existential variables. - assert_prolog_success!( - &mut wam, - "bagof(X,Y^((X = 1,Y = 1; (X = 2,Y = 2))),S).", - [["S = [1,2]", "X = _0", "Y = _5"]] - ); - assert_prolog_success!( - &mut wam, - "bagof(X,Y^((X = 1 ; Y = 1) ; (X = 2,Y = 2)),S).", - [["S = [1,_126,2]", "X = _0", "Y = _5"]] - ); - - assert_prolog_success!( - &mut wam, - "setof(X,Y^((X = 1,Y = 1; (X = 2,Y = 2))),S).", - [["S = [1,2]", "X = _0", "Y = _5"]] - ); - assert_prolog_success!( - &mut wam, - "setof(X,Y^((X = 1 ; Y = 1) ; (X = 2,Y = 2)),S).", - [["S = [_126,1,2]", "X = _0", "Y = _5"]] - ); - - assert_prolog_failure!(&mut wam, "forall(true,false)."); - assert_prolog_success!(&mut wam, "forall(false,true)."); - assert_prolog_success!( - &mut wam, - "catch(forall(_,true),error(instantiation_error,_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(forall(true,_),error(instantiation_error,_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(forall(1,true),error(type_error(callable,1),_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(forall(true,1),error(type_error(callable,1),_),true)." - ); - - submit( - &mut wam, - " -:- dynamic(cat/0). -cat. - -:- dynamic(dog/0). -dog :- true. - -elk(X) :- moose(X). - -:- dynamic(legs/2). -legs(A,6) :- insect(A). -legs(A,7) :- A,call(A). - -:- dynamic(insect/1). -insect(ant). -insect(bee).", - ); - - assert_prolog_success!(&mut wam, "clause(cat,true)."); - assert_prolog_success!(&mut wam, "clause(dog,true)."); - assert_prolog_success!( - &mut wam, - "clause(legs(I,6),Body).", - [["I = _1", "Body = insect(_1)"]] - ); - assert_prolog_success!( - &mut wam, - "clause(legs(C,7),Body).", - [["C = _1", "Body = (_1,call(C))"]] - ); - assert_prolog_success!( - &mut wam, - "clause(insect(I),T).", - [["I = ant", "T = true"], ["I = bee", "T = true"]] - ); - assert_prolog_failure!(&mut wam, "clause(x,Body)."); - assert_prolog_success!( - &mut wam, - "catch(clause(_,_),error(instantiation_error,_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(clause(4,_),error(type_error(callable,4),_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(clause(elk(N),_),error(permission_error(access,private_procedure,elk/1),_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch(clause(atom(N),_),error(permission_error(access,private_procedure,atom/1),_),true)." - ); - - assert_prolog_success!(&mut wam, "asserta(legs(octopus,8))."); - assert_prolog_success!(&mut wam, "asserta( (legs(A,4) :- animal(A)) )."); - assert_prolog_success!(&mut wam, "asserta( (foo(X) :- X,call(X)) )."); - assert_prolog_success!( - &mut wam, - "catch(asserta(_),error(instantiation_error,_),true)." - ); - assert_prolog_failure!(&mut wam, "asserta(_)."); - assert_prolog_success!( - &mut wam, - "catch(asserta(4),error(type_error(callable,4),_),true)." - ); - assert_prolog_failure!(&mut wam, "asserta(4)."); - assert_prolog_success!( - &mut wam, - "catch(asserta( (foo :- 4) ),error(type_error(callable,4),_),true)." - ); - assert_prolog_failure!(&mut wam, "asserta( (foo :- 4) )."); - assert_prolog_success!(&mut wam, "catch(asserta( (atom(_) :- true) ),error(permission_error(modify,static_procedure,atom/1),_),true)."); - assert_prolog_failure!(&mut wam, "asserta( (atom(_) :- true) )."); - - submit( - &mut wam, - " -:- dynamic(cat/0). -cat. - -:- dynamic(dog/0). -dog :- true. - -elk(X) :- moose(X). - -:- dynamic(legs/2). -legs(A,6) :- insect(A). -legs(A,7) :- A,call(A). - -:- dynamic(insect/1). -insect(ant). -insect(bee).", - ); - - assert_prolog_success!(&mut wam, "assertz(legs(octopus,8))."); - assert_prolog_success!(&mut wam, "assertz( (legs(A,4) :- animal(A)) )."); - assert_prolog_success!(&mut wam, "assertz( (foo(X) :- X,call(X)) )."); - assert_prolog_success!( - &mut wam, - "catch(assertz(_),error(instantiation_error,_),true)." - ); - assert_prolog_failure!(&mut wam, "assertz(_)."); - assert_prolog_success!( - &mut wam, - "catch(assertz(4),error(type_error(callable,4),_),true)." - ); - assert_prolog_failure!(&mut wam, "assertz(4)."); - assert_prolog_success!( - &mut wam, - "catch(assertz( (foo :- 4) ),error(type_error(callable,4),_),true)." - ); - assert_prolog_failure!(&mut wam, "assertz( (foo :- 4) )."); - assert_prolog_success!(&mut wam, "catch(assertz( (atom(_) :- true) ),error(permission_error(modify,static_procedure,atom/1),_),true)."); - assert_prolog_failure!(&mut wam, "assertz( (atom(_) :- true) )."); - - submit( - &mut wam, - " -:- dynamic(legs/2). -legs(A,4) :- animal(A). -legs(octopus,8). -legs(A,6) :- insect(A). -legs(spider,8). -legs(B,2) :- bird(B). - -:- dynamic(insect/1). -insect(ant). -insect(bee). - -:- dynamic(foo/1). -foo(X) :- call(X),call(X). -foo(X) :- call(X) -> call(X).", - ); - - assert_prolog_success!(&mut wam, "retract(legs(octopus,8))."); - assert_prolog_failure!(&mut wam, "retract(legs(spider,6))."); - assert_prolog_success!( - &mut wam, - "retract( (legs(X,2) :- T) ).", - [["X = _1", "T = bird(_1)"]] - ); - assert_prolog_success!( - &mut wam, - "retract( (legs(X,Y) :- Z) ).", - [ - ["X = _1", "Y = 4", "Z = animal(_1)"], - ["X = _1", "Y = 6", "Z = insect(_1)"], - ["X = spider", "Y = 8", "Z = true"] - ] - ); - assert_prolog_failure!(&mut wam, "retract( (legs(X,Y) :- Z) )."); - assert_prolog_success!(&mut wam, "retract(insect(I)).", [["I = ant"], ["I = bee"]]); - assert_prolog_success!( - &mut wam, - "retract(( foo(A) :- A,call(A) )).", - [["A = call(A)"]] - ); - assert_prolog_success!(&mut wam, "foo(atom(atom))."); - assert_prolog_success!( - &mut wam, - "retract(( foo(C) :- A -> B )).", - [["A = call(_1)", "B = call(_1)", "C = _1"]] - ); - assert_prolog_failure!(&mut wam, "retract( (X :- in_eec(Y)) )."); - assert_prolog_success!( - &mut wam, - "catch(retract( (X :- in_eec(Y)) ),error(instantiation_error,_),true)." - ); - assert_prolog_failure!(&mut wam, "retract( (4 :- X) )."); - assert_prolog_success!( - &mut wam, - "catch(retract( (4 :- X) ),error(type_error(callable,4),_),true)." - ); - assert_prolog_failure!(&mut wam, "retract( (atom(X) :- X == '[]') )."); - assert_prolog_success!(&mut wam, "catch(retract( (atom(X) :- X == '[]') ),error(permission_error(modify,static_procedure,atom/1),_),true)."); - - /* This example shows why machine::compile::localize_self_calls is necessary. */ - submit( - &mut wam, - " -:- dynamic(p/1). - -p(a). -p(b). -p(c) :- p(d). -p(d).", - ); - - assert_prolog_success!( - &mut wam, - "p(X),retract(p(_)).", - [["X = a"], ["X = a"], ["X = a"]] - ); - - submit( - &mut wam, - " -:- dynamic(foo/1). -foo(X) :- call(X),call(X). -foo(X) :- call(X) -> call(X).", - ); - - assert_prolog_success!(&mut wam, "abolish(foo/2)."); - assert_prolog_failure!(&mut wam, "abolish(foo/_)."); - assert_prolog_success!( - &mut wam, - "catch(abolish(foo/_),error(instantiation_error,abolish/1),true)." - ); - assert_prolog_failure!(&mut wam, "abolish(foo)."); - assert_prolog_success!( - &mut wam, - "catch(abolish(foo),error(type_error(predicate_indicator,foo),abolish/1),true)." - ); - assert_prolog_failure!(&mut wam, "abolish(foo(_))."); - assert_prolog_success!( - &mut wam, - "catch(abolish(foo(_)),error(type_error(predicate_indicator,foo(_)),abolish/1),true)." - ); - assert_prolog_failure!(&mut wam, "abolish(abolish/1)."); - assert_prolog_success!(&mut wam, "catch(abolish(abolish/1),error(permission_error(modify,static_procedure,abolish/1),abolish/1),true)."); - - assert_prolog_success!( - &mut wam, - "atom_length('enchanted evening',N).", - [["N = 17"]] - ); - assert_prolog_success!( - &mut wam, - r"atom_length('enchanted\ - evening',N).", - [["N = 17"]] - ); - assert_prolog_success!(&mut wam, "atom_length('',N).", [["N = 0"]]); - assert_prolog_failure!(&mut wam, "atom_length('scarlet',5)."); - assert_prolog_success!( - &mut wam, - "catch((atom_length(Atom,4),false),error(instantiation_error,_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch((atom_length(1.23,4),false),error(type_error(atom,1.23),_),true)." - ); - assert_prolog_success!( - &mut wam, - "catch((atom_length(atom,'4'),false),error(type_error(integer,'4'),_),true)." - ); -} - -#[test] -fn test_queries_on_setup_call_cleanup() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(non_iso))."); - - // Test examples from the ISO Prolog page for setup_call_catch. - assert_prolog_failure!(&mut wam, "setup_call_cleanup(false, _, _)."); - assert_prolog_success!( - &mut wam, - "catch(setup_call_cleanup(true, throw(unthrown), _), error(instantiation_error, _), true)." - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(true, true, (true ; throw(x)))." - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(true, X = 1, X = 2).", - [["X = 1"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(true, true, X = 2).", - [["X = 2"]] - ); - assert_prolog_success!( - &mut wam, - "catch(setup_call_cleanup(true, X=true, X), error(E, _), true).", - [["E = instantiation_error", "X = _1"]] - ); - assert_prolog_success!( - &mut wam, - "catch(setup_call_cleanup(X=throw(ex), true, X), E, true).", - [["E = ex", "X = _3"]] - ); - assert_prolog_success!(&mut wam, "setup_call_cleanup(true, true, false)."); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S = 1, G = 2, C = 3).", - [["S = 1", "G = 2", "C = 3"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup((S=1;S=2), G=3, C=4).", - [["S = 1", "G = 3", "C = 4"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1, G=2, writeq(S+G)).", - [["S = 1", "G = 2"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1, (G=2;G=3), writeq(S+G)).", - [["S = 1", "G = 2"], ["S = 1", "G = 3"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1, G=2, writeq(S+G>A+B)), A=3, B=4.", - [["S = 1", "G = 2", "A = 3", "B = 4"]] - ); - assert_prolog_success!( - &mut wam, - "catch(setup_call_cleanup(S=1, (G=2;G=3,throw(x)), writeq(S+G)), E, true).", - [["S = 1", "G = 2", "E = _26"], ["G = _4", "E = x", "S = _1"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1, (G=2;G=3),writeq(S+G>B)), B=4, !.", - [["S = 1", "B = 4", "G = 2"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1,G=2,writeq(S+G>B)),B=3,!.", - [["S = 1", "G = 2", "B = 3"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1,(G=2;false),writeq(S+G>B)),B=3,!.", - [["S = 1", "G = 2", "B = 3"]] - ); - assert_prolog_success!( - &mut wam, - "setup_call_cleanup(S=1,(G=2;S=2),writeq(S+G>B)), B=3, !.", - [["S = 1", "B = 3", "G = 2"]] - ); - assert_prolog_failure!( - &mut wam, - "setup_call_cleanup(S=1,(G=2;G=3), writeq(S+G>B)), B=4, !, throw(x)." - ); - - assert_prolog_success!( - &mut wam, - "catch(setup_call_cleanup(true,throw(goal),throw(cl)), Pat, true).", - [["Pat = goal"]] - ); - assert_prolog_success!( - &mut wam, - "catch(( setup_call_cleanup(true,(G=1;G=2),throw(cl)), throw(cont)), Pat, true).", - [["Pat = cont", "G = _1"]] - ); - - // fails here. - assert_prolog_success!(&mut wam, - "setup_call_cleanup(true, (X=1;X=2), writeq(a)), setup_call_cleanup(true,(Y=1;Y=2),writeq(b)), !.", - [["Y = 1", "X = 1"]]); -} - -#[test] -fn test_queries_on_call_with_inference_limit() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(non_iso))."); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(throw(error), 0, R).", - [["R = inference_limit_exceeded"]] - ); - assert_prolog_success!( - &mut wam, - "catch(call_with_inference_limit(throw(error), 1, R), error, true)." - ); - - assert_prolog_failure!(&mut wam, "call_with_inference_limit(g(X), 5, R)."); - - submit(&mut wam, "g(1). g(2). g(3). g(4). g(5)."); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 5, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = !", "X = 5"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 5, R), call(true).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = !", "X = 5"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 2, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 3, R1), - call_with_inference_limit(g(X), 5, R2).", - [ - ["X = 1", "R1 = true", "R2 = !"], - ["X = 2", "R1 = true", "R2 = !"], - ["X = 3", "R1 = true", "R2 = !"], - ["X = 4", "R1 = true", "R2 = !"], - ["X = 5", "R1 = !", "R2 = !"] - ] - ); - - submit(&mut wam, "f(X) :- call_with_inference_limit(g(X), 5, _)."); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X), 7, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = !", "X = 5"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X), 6, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X), 4, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X), 3, R).", - [ - ["R = true", "X = 1"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X), 2, R).", - [["R = inference_limit_exceeded", "X = _1"]] - ); - - submit(&mut wam, "e(X) :- call_with_inference_limit(f(X), 10, _)."); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(e(X), 10, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = !", "X = 5"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(e(X), 8, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(e(X), 6, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(e(X), 5, R).", - [ - ["R = true", "X = 1"], - ["R = inference_limit_exceeded", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(e(X), 4, R).", - [["R = inference_limit_exceeded", "X = _1"]] - ); - - submit( - &mut wam, - "f(X, R) :- call_with_inference_limit(g(X), 5, R).", - ); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X, R), 4, S).", - [ - ["S = true", "X = 1", "R = true"], - ["S = true", "X = 2", "R = true"], - ["S = inference_limit_exceeded", "X = _1", "R = _2"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X, R), 8, R).", - [ - ["R = true", "X = 1"], - ["R = true", "X = 2"], - ["R = true", "X = 3"], - ["R = true", "X = 4"], - ["R = !", "X = 5"] - ] - ); - - submit(&mut wam, "g(1). g(2). g(3). g(4). g(5). g(6)."); - - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(f(X, R), 8, S).", - [ - ["R = true", "X = 1", "S = true"], - ["R = true", "X = 2", "S = true"], - ["R = true", "X = 3", "S = true"], - ["R = true", "X = 4", "S = true"], - ["R = true", "X = 5", "S = true"], - ["R = inference_limit_exceeded", "S = !", "X = _1"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 2, R), call_with_inference_limit(g(X), 1, S).", - [ - ["R = true", "X = 1", "S = !"], - ["R = true", "X = 2", "S = !"], - ["R = true", "X = 3", "S = !"], - ["R = true", "X = 4", "S = !"], - ["R = true", "X = 5", "S = !"], - ["R = !", "X = 6", "S = !"] - ] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 2, R), call_with_inference_limit(g(X), 1, R).", - [["R = !", "X = 6"]] - ); - assert_prolog_success!( - &mut wam, - "call_with_inference_limit(g(X), 1, R), call_with_inference_limit(g(X), 1, R).", - [["R = inference_limit_exceeded", "X = _1"]] - ); -} - -#[test] -fn test_queries_on_dcgs() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(dcgs))."); - - // test case by YeGoblynQueene from hacker news. - submit_code( - &mut wam, - " ability(destroy, X) --> destroy(X). - destroy(X) --> [destroy], target(X). - target(X) --> [target], permanent(X). - permanent(X) --> [creature], creature(X). - permanent(X) --> [artifact], artifact(X). - permanent(X) --> [land], land(X). - spell(X) --> [sorcery], sorcery(X). - spell(X) --> [instant], instant(X). - - creature('Llanowar Elves') --> []. - artifact('Ankh of Mishra') --> []. - land('Mountain') --> []. - % etc permanents - sorcery('Duress') --> []. - instant('Lightning Bolt') --> [].", - ); - - assert_prolog_success!( - &mut wam, - "phrase(ability(destroy, X), P).", - [ - ["P = [destroy,target,creature]", "X = 'Llanowar Elves'"], - ["P = [destroy,target,artifact]", "X = 'Ankh of Mishra'"], - ["P = [destroy,target,land]", "X = 'Mountain'"] - ] - ); -} - -#[test] -fn test_queries_on_string_lists() { - let mut wam = Machine::new(readline::input_stream()); - - submit(&mut wam, ":- use_module(library(non_iso))."); - - // double_quotes is chars by default. - assert_prolog_success!(&mut wam, "variant(\"\", [])."); - assert_prolog_success!(&mut wam, "\"\" == []."); - assert_prolog_failure!(&mut wam, "\"abc\" == []."); - assert_prolog_success!(&mut wam, "variant(\"abc\", ['a', 'b', 'c'])."); - assert_prolog_success!(&mut wam, "variant(\"abc\", ['a', 'b', c])."); - assert_prolog_success!(&mut wam, "variant(\"abc\", ['a', b, 'c'])."); - assert_prolog_success!(&mut wam, "variant(\"abc\", [a, 'b', 'c'])."); - assert_prolog_success!(&mut wam, "variant(\"abc\", [a, 'b', c])."); - assert_prolog_failure!(&mut wam, "\"abc\" == ['a', 'b', 'c']."); - assert_prolog_failure!(&mut wam, "\"abc\" == ['a', 'b', c]."); - assert_prolog_failure!(&mut wam, "\"abc\" == ['a', b, 'c']."); - assert_prolog_failure!(&mut wam, "\"abc\" == [a, 'b', 'c']."); - assert_prolog_failure!(&mut wam, "\"abc\" == [a, 'b', c]."); - assert_prolog_failure!(&mut wam, "\"koen\" == [k, o, e, n]."); - assert_prolog_success!(&mut wam, "\"koen\" = [k, o, e, n]."); - assert_prolog_success!(&mut wam, "variant(\"koen\", [k, o, e, n])."); - assert_prolog_success!(&mut wam, "variant(\"koen\", \"koen\")."); - assert_prolog_success!(&mut wam, "\"koen\" = [k, o | X].", [["X = [e,n]"]]); - assert_prolog_success!( - &mut wam, - "\"koen\" = [k, o | X], X = \"en\".", - [["X = [e,n]"]] - ); - assert_prolog_failure!(&mut wam, "\"koen\" = [k, o | X], X == \"en\"."); - assert_prolog_success!( - &mut wam, - "\"koen\" = [k, o | X], variant(X, \"en\").", - [["X = [e,n]"]] - ); - - assert_prolog_failure!(&mut wam, "X = \"abc\", Y = \"abc\", X == Y."); - assert_prolog_failure!( - &mut wam, - "partial_string(\"abc\", X), partial_string(\"abc\", Y), X == Y." - ); - - assert_prolog_success!(&mut wam, "X = \"abc\", Y = \"abc\", variant(X, Y)."); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), partial_string(\"abc\", Y), variant(X, Y)." - ); - - submit(&mut wam, "matcher([a,b,c|X], ['d','e','f'|X])."); - - assert_prolog_success!(&mut wam, "matcher(\"abcdef\", \"defdef\")."); - assert_prolog_failure!(&mut wam, "matcher(\"abcdef\", \"defdff\")."); - - assert_prolog_success!( - &mut wam, - "matcher([X, Y, Z | W], [A, B, C | W]).", - [["A = d", "B = e", "C = f", "W = _1", "X = a", "Y = b", "Z = c"]] - ); - assert_prolog_failure!(&mut wam, "matcher([X, Y, Z | W], [X, B, C | W])."); - - submit(&mut wam, "matcher([a,b,c|X], X)."); - - assert_prolog_success!( - &mut wam, - "matcher(\"abcdef\", X), X = [d,e,f|Y], variant(Y, []), X = \"def\".", - [["X = [d,e,f]", "Y = []"]] - ); - assert_prolog_success!( - &mut wam, - "matcher(\"abcdef\", X), X = [d,e,f|Y], variant(Y, []), variant(X, \"def\").", - [["X = [d,e,f]", "Y = []"]] - ); - assert_prolog_success!( - &mut wam, - "X = ['a', 'b', 'c' | \"def\"].", - [["X = [a,b,c,d,e,f]"]] - ); - - assert_prolog_success!(&mut wam, "X = [a,b,c|\"abc\"].", [["X = [a,b,c,a,b,c]"]]); - - assert_prolog_success!(&mut wam, "set_prolog_flag(double_quotes, atom)."); - - assert_prolog_success!(&mut wam, "matcher(X, Y).", [["X = [a,b,c|_1]", "Y = _1"]]); - assert_prolog_failure!(&mut wam, "matcher(\"abcdef\", Y)."); - - assert_prolog_success!(&mut wam, "set_prolog_flag(double_quotes, chars)."); - - assert_prolog_success!( - &mut wam, - "X = \"abc\", X = ['a' | Y], set_prolog_flag(double_quotes, atom).", - [["X = \"abc\"", "Y = \"bc\""]] - ); - - // partial strings. - assert_prolog_success!(&mut wam, "set_prolog_flag(double_quotes, chars)."); - - assert_prolog_failure!(&mut wam, "Y = 5, partial_string(\"abc\", Y)."); - assert_prolog_success!(&mut wam, "partial_string(\"abc\", X).", [["X = [a,b,c|_]"]]); - - assert_prolog_failure!( - &mut wam, - "partial_string(\"abc\", X), partial_string(\"abc\", Y), matcher(X, V), - matcher(Y, Z), V = Z." - ); - - submit(&mut wam, "matcher([a, b, c | X], X)."); - - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y).", - [["X = [a,b,c|_]", "Y = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y), Y = \"def\".", - [["X = [a,b,c,d,e,f]", "Y = [d,e,f]"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y), \"def\" = Y.", - [["X = [a,b,c,d,e,f]", "Y = [d,e,f]"]] - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y).", - [["X = [a,b,c,d,e,f|_]", "Y = [d,e,f|_]"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y), partial_string(\"def\", Y), - Y = \"defghijkl\".", - [["X = [a,b,c,d,e,f,g,h,i,j,k,l]", "Y = [d,e,f,g,h,i,j,k,l]"]] - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\", X), matcher(X, Y), Y = [d, e, f | G].", - [["X = [a,b,c,d,e,f|_]", "Y = [d,e,f|_]", "G = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),matcher(X,Y),[d,e,f | G] = Y.", - [["X = [a,b,c,d,e,f|_]", "Y = [d,e,f|_]", "G = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),matcher(X,Y),Y = [d,e,f | G], G = \"ghi\".", - [[ - "X = [a,b,c,d,e,f,g,h,i]", - "Y = [d,e,f,g,h,i]", - "G = [g,h,i]" - ]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),matcher(X,Y),Y = [d,e,f | G], - is_partial_string(Y),G = \"ghi\".", - [[ - "X = [a,b,c,d,e,f,g,h,i]", - "Y = [d,e,f,g,h,i]", - "G = [g,h,i]" - ]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),matcher(X,Y),Y = [d,e,f | G], - is_partial_string(Y),is_partial_string(G),G = \"ghi\".", - [[ - "X = [a,b,c,d,e,f,g,h,i]", - "Y = [d,e,f,g,h,i]", - "G = [g,h,i]" - ]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),partial_string(\"ababc\",Y),Y = [a,b|Z], - variant(X, Z).", - [["X = [a,b,c|_]", "Y = [a,b,a,b,c|_]", "Z = [a,b,c|_]"]] - ); - assert_prolog_failure!( - &mut wam, - "partial_string(\"abc\",X),partial_string(\"ababc\",Y),Y = [a,b|Z], - X == Z." - ); - - assert_prolog_success!(&mut wam, "partial_string(\"abc\",X), X @> \"abc\"."); - assert_prolog_failure!( - &mut wam, - "partial_string(\"abc\",X), \\+ variant(X, \"abc\")." - ); - assert_prolog_failure!(&mut wam, "partial_string(\"abc\",X), X @< \"abc\"."); - - assert_prolog_success!( - &mut wam, - "partial_string(\"ab\",X),matcher(X,Y),Y = [a,b|V], - matcher(Y,Z),is_partial_string(Y).", - [["V = [c|_]", "X = [a,b,c,a,b,c|_]", "Y = [a,b,c|_]", "Z = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y).", - [["X = [a,b,c|_]", "Y = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y),is_partial_string(Y).", - [["X = [a,b,c|_]", "Y = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y),Y = \"def\".", - [["X = [a,b,c,d,e,f]", "Y = [d,e,f]"]] - ); - - submit( - &mut wam, - "matcher([a,b,c|X],X). - matcher([a,b,d|X],X).", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"ab\",X),matcher(X,Y).", - [["X = [a,b,c|_]", "Y = _"], ["X = [a,b,d|_]", "Y = _"]] - ); - - submit( - &mut wam, - "matcher([a,b,c,d|X],X). - matcher([a,c,d|X],X).", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"ab\",X),matcher(X,Y).", - [["X = [a,b,c,d|_]", "Y = _"]] - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y).", - [["X = [a,b,c,d|_]", "Y = _"], ["X = [a,c,d|_]", "Y = _"]] - ); - - submit( - &mut wam, - "matcher([a,b,c,d|X],X). - matcher([a,c,d|X],X). - matcher([a,e,f|X],X).", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y).", - [ - ["X = [a,b,c,d|_]", "Y = _"], - ["X = [a,c,d|_]", "Y = _"], - ["X = [a,e,f|_]", "Y = _"] - ] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y),Y = \" t\".", - [ - ["X = [a,b,c,d,' ',t]", "Y = [' ',t]"], - ["X = [a,c,d,' ',t]", "Y = [' ',t]"], - ["X = [a,e,f,' ',t]", "Y = [' ',t]"] - ] - ); - - submit( - &mut wam, - "matcher([a,b,c|X],X) :- X = []. - matcher([a,b,c|X],X).", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),matcher(X,Y).", - [["X = [a,b,c]", "Y = []"], ["X = [a,b,c|_]", "Y = _"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y).", - [["X = [a,b,c]", "Y = []"], ["X = [a,b,c|_]", "Y = _"]] - ); - - assert_prolog_failure!( - &mut wam, - "partial_string(\"abc\",X),partial_string(\"bc\",Y),X = [a|Y]." - ); - - submit( - &mut wam, - "matcher([a|X],X) :- matcher2(X,_). - matcher([b|X],X) :- matcher2(X,_). - - matcher2([c|X],X). - matcher2([d|X],X).", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"\",X),matcher(X,Y).", - [ - ["X = [a,c|_]", "Y = [c|_]"], - ["X = [a,d|_]", "Y = [d|_]"], - ["X = [b,c|_]", "Y = [c|_]"], - ["X = [b,d|_]", "Y = [d|_]"] - ] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"a\",X),matcher(X,Y).", - [["X = [a,c|_]", "Y = [c|_]"], ["X = [a,d|_]", "Y = [d|_]"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"b\",X),matcher(X,Y).", - [["X = [b,c|_]", "Y = [c|_]"], ["X = [b,d|_]", "Y = [d|_]"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"bc\",X),matcher(X,Y).", - [["X = [b,c|_]", "Y = [c|_]"]] - ); - - submit( - &mut wam, - "f(\"appendy jones\"). - f(\"appendy smithers jones\"). - f(\"appendy o'toole\").", - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"appendy\",X),f(X).", - [ - ["X = [a,p,p,e,n,d,y,' ',j,o,n,e,s]"], - ["X = [a,p,p,e,n,d,y,' ',s,m,i,t,h,e,r,s,' ',j,o,n,e,s]"], - ["X = [a,p,p,e,n,d,y,' ',o,'\\'',t,o,o,l,e]"] - ] - ); - - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),partial_string(\"abcdef\",X).", - [["X = [a,b,c,d,e,f|_]"]] - ); - assert_prolog_success!( - &mut wam, - "partial_string(\"abc\",X),partial_string(\"abcdef\",X),X = \"abcdef\".", - [["X = [a,b,c,d,e,f]"]] - ); -} - -#[test] -fn test_queries_on_attributed_variables() { - let mut wam = Machine::new(readline::input_stream()); - - submit( - &mut wam, - " -:- module(my_mod, []). -:- use_module(library(atts)). - -:- attribute dif/1, frozen/1.", - ); - - assert_prolog_success!( - &mut wam, - "( put_atts(V, my_mod, dif(1)) ; put_atts(V, my_mod, dif(2)) ), get_atts(V, my_mod, L).", - [["L = [dif(1)]", "V = _10"], ["L = [dif(2)]", "V = _10"]] - ); - - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, frozen(a)), - ( put_atts(V, my_mod, dif(1)) - ; put_atts(V, my_mod, -frozen(a)), put_atts(V, my_mod, dif(2)) - ; put_atts(V, my_mod, dif(different)) ), - get_atts(V, my_mod, Ls).", - [ - ["Ls = [frozen(a),dif(1)]", "V = _10"], - ["Ls = [dif(2)]", "V = _10"], - ["Ls = [frozen(a),dif(different)]", "V = _10"] - ] - ); - - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a)]), - ( put_atts(V, my_mod, -dif(2)); put_atts(V, my_mod, -frozen(A)) ), - get_atts(V, my_mod, L).", - [ - ["A = _71", "L = [frozen(a)]", "V = _25"], - ["A = _71", "L = [dif(2)]", "V = _25"] - ] - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a), frozen(b)]), - ( put_atts(V, my_mod, -dif(2)) ; put_atts(V, my_mod, -frozen(A)) ), - get_atts(V, my_mod, L).", - [ - ["A = _111", "L = [frozen(b)]", "V = _29"], - ["A = _111", "L = [dif(2)]", "V = _29"] - ] - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a), frozen(b)]), - get_atts(V, my_mod, -dif(1))." - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a), frozen(b)]), - get_atts(V, my_mod, -dif(3))." - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a), frozen(b)]), - get_atts(V, my_mod, dif(X)).", - [["X = 2", "V = _29"]] - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), dif(2), frozen(a), frozen(b)]), - put_atts(V, my_mod, -dif(A)), get_atts(V, my_mod, Ls).", - [["A = _112", "Ls = [frozen(b)]", "V = _29"]] - ); - assert_prolog_success!( - &mut wam, - "put_atts(V, my_mod, [dif(1), frozen(a), dif(2), frozen(b)]), - put_atts(V, my_mod, -dif(A)), get_atts(V, my_mod, Ls).", - [["A = _114", "Ls = [frozen(b)]", "V = _29"]] - ); - - submit( - &mut wam, - ":- use_module('src/prolog/examples/minatotask.pl').", - ); - - assert_prolog_failure!( - &mut wam, - "ZDD = ( X -> b(true) ; ( Y -> b(true) ; b(false) ) ), - Vs = [X,Y], - variables_set_zdd(Vs, ZDD), - Vs = [1,1]." - ); - assert_prolog_success!( - &mut wam, - "ZDD = ( X -> b(true) ; ( Y -> b(true) ; b(false) ) ), - Vs = [X,Y], - variables_set_zdd(Vs, ZDD), - X = 1.", - [[ - "X = 1", - "Y = 0", - "Vs = [1,0]", - "ZDD = (1->b(true);0->b(true);b(false))" - ]] - ); - assert_prolog_success!( - &mut wam, - "ZDD = ( X -> b(true) ; ( Y -> b(true) ; b(false) ) ), - Vs = [X,Y], - variables_set_zdd(Vs, ZDD), - X = 0.", - [[ - "Vs = [0,_58]", - "X = 0", - "Y = _58", - "ZDD = (0->b(true);_58->b(true);b(false))" - ]] - ); -} -*/ diff --git a/src/tests/builtins.pl b/src/tests/builtins.pl new file mode 100644 index 00000000..47d1e509 --- /dev/null +++ b/src/tests/builtins.pl @@ -0,0 +1,64 @@ + +:- use_module(library(lists)). + +test_queries_on_builtins :- + \+ atom(_), + atom(a), + \+ atom("string"), + atom([]), + \+ atom(1), + \+ atom(0), + \+ atom(0.0), + \+ atom([a,b,c]), + \+ atom(atop(the_trees)), + \+ atomic(_), + atomic(a), + atomic("string"), + atomic([]), + atomic(1), + atomic(0), + atomic(0.0), + \+ atomic([a,b,c]), + \+ atomic(atop(the_trees)), + ( var(X), X = 3, atomic(X) ), + \+ ( var(X), X = 3, var(X) ), + arg(1, f(a,b,c,d), a), + arg(2, f(a,b,c,d), b), + arg(3, f(a,b,c,d), c), + arg(4, f(a,b,c,d), d), + catch(arg(_, f, _), error(instantiation_error, _), true), + \+ arg(1, f(arg, not_arg, not_arg), not_arg), + arg(2, f(arg, not_arg, not_arg), not_arg), + arg(3, f(arg, not_arg, not_arg), not_arg), + functor(f(a,b,c), f, 3), + catch(functor(_,"sdf",3),error(type_error(atom,[s,d,f]),_),true), + f(1,2,3) =.. [f,1,2,3], + length([a,b,c], 3), + copy_term([[[[X,Y],Y],X]],[[[[Z,V],V],Z]]), + \+ ( X = g(X,Y), Y = f(X), copy_term(Y,g(Z)) ), + (X = g(X,Y), Y = f(X), copy_term(Y,f(Z))), + float(3.14159269), + \+ float(3), + \+ float("sdfsa"), + \+ float(structure(functor)), + \+ float([1,2,3]), + \+ float([1,2,_]), + \+ (X is 3 rdiv 4, float(X)), + ( X is 3 rdiv 4, rational(X) ), + \+ rational(3), + \+ rational(f(_)), + \+ rational("sdfa"), + \+ rational(atom), + \+ rational(structure(f)), + \+ rational([1,2,3]), + \+ rational([1,2,_]), + compound(functor(compound)), + compound(f(_)), + compound([1,2,3]), + \+ compound([]), + \+ compound(3.14159269), + \+ compound(3), + \+ compound("sdfsa"), + \+ compound(atom). + +:- initialization(test_queries_on_builtins). diff --git a/src/tests/facts.pl b/src/tests/facts.pl new file mode 100644 index 00000000..7c33ac7e --- /dev/null +++ b/src/tests/facts.pl @@ -0,0 +1,26 @@ +:- dynamic(p/2). +:- dynamic(p/3). + +p(Z, Z). +clouds(are, nice). +p(Z, h(Z, W), f(W)). + +test_queries_on_facts :- + findall(Z, p(Z, Z), [Z]), + findall(Z, p(Z, z), [z]), + findall(Z, p(Z, w), [w]), + \+ p(z, w), + p(w, w), + \+ clouds(Z, Z), + findall(Z, clouds(are, Z), [nice]), + \+ p(z, h(z, z), f(w)), + p(z, h(z, w), f(w)), + findall(W, p(z, h(z, W), f(w)), [w]), + findall(Z, p(Z, h(Z, w), f(Z)), [w]), + \+ p(z, h(Z, w), f(Z)), + retract(p(_,_,_)), + assertz(p(Z, h(Z, W), f(W))), + p(f(f(a)), h(f(f(a)), f(a)), f(f(a))), + retract(p(Z, h(Z, W), f(W))). + +:- initialization(test_queries_on_facts). diff --git a/src/tests/predicates.pl b/src/tests/predicates.pl new file mode 100644 index 00000000..27249766 --- /dev/null +++ b/src/tests/predicates.pl @@ -0,0 +1,37 @@ + +:- dynamic(p/2). +:- dynamic(p/3). + +:- dynamic(q/1). + +p(_, a). +p(b, _). + +test_queries_on_predicates :- + findall(Y, p(x, Y), [a]), + findall(X, p(X, a), [_,b]), + findall(X, p(b, X), [a,_]), + findall(X, p(X, X), [a,b]), + p(b, a), + \+ p(a, b), + retract(p(_,a)), + retract(p(b,_)), + assertz(p(_, _,a)), + assertz(p(_,a,_)), + assertz(p(_,_,a)), + findall(X, p(c,d,X), [a,a]), + findall(X, p(a,a,a), [a,a,a]), + \+ p(b,c,d), + findall(., retract(p(_,_,_)), _), + assertz(p(_, a)), + assertz(q(z)), + findall(Y, p(_,Y), [a]), + p(x,a), + p(_,a), + \+ p(_,b), + assertz((p(X, Y) :- q(Z), p(X, X))), + once(p(X,b)), + retract((p(X, Y) :- q(Z), p(X, X))), + retract(q(z)). + +:- initialization(test_queries_on_predicates). diff --git a/src/tests/rules.pl b/src/tests/rules.pl new file mode 100644 index 00000000..2931d6f6 --- /dev/null +++ b/src/tests/rules.pl @@ -0,0 +1,55 @@ +:- dynamic(p/3). +:- dynamic(p/2). +:- dynamic(q/2). +:- dynamic(r/2). +:- dynamic(r/1). +:- dynamic(h/1). + +p(X, Y) :- q(X, Z), r(Z, Y). +q(q, s). +r(s, t). + +test_queries_on_rules :- + findall([X,Y], p(X, Y), [[q, t]]), + p(q, t), + \+ p(t, q), + findall(T, p(q, T), [t]), + \+ p(t, t), + retract((p(X,Y) :- q(X,Z), r(Z, Y))), + retract(q(_,_)), + assertz((p(X,_) :- q(f(f(X)), _), r(_, _))), + assertz(q(f(f(X)), r)), + p(_,_), + retract(q(_,_)), + assertz(q(f(f(x)), r)), + findall(X, p(X,_), [x]), + retract((p(X,_) :- q(f(f(X)), _), r(_, _))), + retract(q(_,_)), + assertz((p(X, Y) :- q(X, Y), r(X, Y))), + assertz(q(s, t)), + retract(r(_,_)), + assertz((r(X, Y) :- r(a))), + assertz(r(a)), + findall([X,Y], p(X, Y), [[s,t]]), + \+ p(t, _), + findall(T, p(s, T), [t]), + findall(S, p(S, t), [s]), + assertz((p(f(f(a), g(b), X), g(b), h) :- q(X, Y))), + retract(q(_,_)), + assertz(q(_,_)), + findall([X,Y,Z], p(f(X, Y, Z), g(b), h), [[f(a), g(b), _]]), + \+ p(f(X, g(_), Z), g(Z), X), + findall([X,Y,Z], p(f(X, g(Y), Z), g(Z), h), [[f(a), b, b]]), + findall([X,Y,Z], p(Z, Y, X), [[h, g(b), f(f(a),g(b),_)]]), + findall([X,Y,Z], p(f(X, Y, Z), Y, h), [[f(a), g(b), _]]), + retract((p(X, Y) :- q(X, Y), r(X, Y))), + retract((p(f(f(a), g(b), X), g(b), h) :- q(X, _))), + assertz((p(_, f(_, Y, _)) :- h(Y))), + assertz(h(y)), + findall(Y, p(_, f(_, Y, _)), [y]). + p(_, f(_, y, _)), + \+ p(_, f(_, z, _)), + retract((p(_, f(_, Y, _)) :- h(Y))). + +:- initialization(test_queries_on_rules). +