From 3fd274c583db1fc60bc17bd01978c9e36a306526 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 30 Apr 2019 20:55:53 -0600 Subject: [PATCH] add remaining atomic term processing builtins, rename (=@=)/2 to variant/2, address issue #133 --- Cargo.toml | 4 +- README.md | 3 +- src/prolog/clause_types.rs | 17 +-- src/prolog/indexing.rs | 2 +- src/prolog/lib/builtins.pl | 75 +++++++++++-- src/prolog/lib/non_iso.pl | 4 +- src/prolog/machine/machine_state.rs | 45 ++++++-- src/prolog/machine/machine_state_impl.rs | 14 ++- src/prolog/machine/system_calls.rs | 134 +++++++++++++++-------- src/prolog/write.rs | 2 - src/tests.rs | 56 +++++----- 11 files changed, 246 insertions(+), 110 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index baafadc6..7d570da4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "scryer-prolog" -version = "0.8.76" +version = "0.8.77" authors = ["Mark Thom "] repository = "https://github.com/mthom/scryer-prolog" description = "A modern Prolog implementation written mostly in Rust." @@ -14,7 +14,7 @@ cfg-if = "0.1.7" downcast = "0.10.0" num = "0.2" ordered-float = "0.5.0" -prolog_parser = "0.8.24" +prolog_parser = "0.8.26" readline_rs_compat = { version = "0.1.9", optional = true } ref_thread_local = "0.0.0" diff --git a/README.md b/README.md index 7c607860..0faa4411 100644 --- a/README.md +++ b/README.md @@ -141,8 +141,6 @@ The following predicates are built-in to Scryer. * `(@>=)/2` * `(@=<)/2` * `(@<)/2` -* `(=@=)/2` -* `(\=@=)/2` * `(\+)/1` * `(==)/2` * `(\==)/2` @@ -232,6 +230,7 @@ The following predicates are built-in to Scryer. * `user:goal_expansion/2` * `user:term_expansion/2` * `var/1` +* `variant/2` * `write/1` * `write_canonical/1` * `writeq/1` diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 5a88745e..f5c504df 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -33,10 +33,8 @@ impl CompareNumberQT { pub enum CompareTermQT { LessThan, LessThanOrEqual, - Equal, GreaterThanOrEqual, GreaterThan, - NotEqual, } impl CompareTermQT { @@ -46,8 +44,6 @@ impl CompareTermQT { CompareTermQT::LessThan => "@<", CompareTermQT::GreaterThanOrEqual => "@>=", CompareTermQT::LessThanOrEqual => "@=<", - CompareTermQT::NotEqual => "\\=@=", - CompareTermQT::Equal => "=@=" } } } @@ -116,8 +112,6 @@ ref_thread_local! { m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan))); m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual))); m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual))); - m.insert(("\\=@=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::NotEqual))); - m.insert(("=@=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::Equal))); m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)); m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm)); m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq)); @@ -166,6 +160,7 @@ pub enum SystemClauseType { ModuleAssertDynamicPredicateToBack, CharCode, CharsToNumber, + CodesToNumber, CheckCutPoint, CopyToLiftedHeap, DeleteAttribute, @@ -202,6 +197,7 @@ pub enum SystemClauseType { ModuleRetractClause, NoSuchPredicate, NumberToChars, + NumberToCodes, OpDeclaration, REPL(REPLCodePtr), ReadTerm, @@ -233,7 +229,8 @@ pub enum SystemClauseType { TermVariables, TruncateLiftedHeapTo, UnifyWithOccursCheck, - UnwindStack, + UnwindStack, + Variant, WriteTerm } @@ -251,6 +248,7 @@ impl SystemClauseType { &SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"), &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) => @@ -291,6 +289,7 @@ impl SystemClauseType { &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::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"), &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"), &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"), @@ -321,6 +320,7 @@ impl SystemClauseType { &SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"), &SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"), &SystemClauseType::UnwindStack => clause_name!("$unwind_stack"), + &SystemClauseType::Variant => clause_name!("$variant"), &SystemClauseType::WriteTerm => clause_name!("$write_term"), } } @@ -338,6 +338,7 @@ impl SystemClauseType { ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber), + ("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), @@ -374,6 +375,7 @@ impl SystemClauseType { ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic), ("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate), ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), + ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$op", 3) => Some(SystemClauseType::OpDeclaration), ("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings), ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), @@ -407,6 +409,7 @@ impl SystemClauseType { ("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo), ("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack), ("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck), + ("$variant", 2) => Some(SystemClauseType::Variant), ("$write_term", 4) => Some(SystemClauseType::WriteTerm), _ => None } diff --git a/src/prolog/indexing.rs b/src/prolog/indexing.rs index 128b40d6..4cba9d13 100644 --- a/src/prolog/indexing.rs +++ b/src/prolog/indexing.rs @@ -59,7 +59,7 @@ impl CodeOffsets { self.lists.push(Self::add_index(is_initial_index, index)); }, &Term::Constant(_, Constant::String(_)) - if self.flags.double_quotes.is_chars() => { // strings are lists in this case. + if !self.flags.double_quotes.is_atom() => { // strings are lists in this case. let is_initial_index = self.lists.is_empty(); self.lists.push(Self::add_index(is_initial_index, index)); }, diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index c9b89016..f1f986bf 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -10,16 +10,16 @@ (is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2, (>>)/2, (mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/2, (=:=)/2, (>=)/2, (=<)/2, (',')/2, (->)/2, (;)/2, (=..)/2, (==)/2, (\==)/2, - (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2, (:)/2, - abolish/1, asserta/1, assertz/1, atom_chars/2, atom_codes/2, + (@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (:)/2, abolish/1, asserta/1, + assertz/1, atom_chars/2, atom_codes/2, atom_concat/3, atom_length/2, bagof/3, catch/3, char_code/2, clause/2, current_op/3, current_predicate/1, current_prolog_flag/2, expand_goal/2, expand_term/2, false/0, findall/3, findall/4, - get_char/1, halt/0, number_chars/2, once/1, op/3, read_term/2, - repeat/0, retract/1, set_prolog_flag/2, setof/3, - subsumes_term/2, term_variables/2, throw/1, true/0, - unify_with_occurs_check/2, write/1, write_canonical/1, - write_term/2, writeq/1]). + get_char/1, halt/0, number_chars/2, number_codes/2, once/1, + op/3, read_term/2, repeat/0, retract/1, set_prolog_flag/2, + setof/3, sub_atom/5, subsumes_term/2, term_variables/2, + throw/1, true/0, unify_with_occurs_check/2, write/1, + write_canonical/1, write_term/2, writeq/1]). % module resolution operator. :- op(600, xfy, :). @@ -45,7 +45,7 @@ expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResu :- op(700, xfx, [>, <, =\=, =:=, >=, =<]). % term comparison. -:- op(700, xfx, [==, \==, @=<, @>=, @<, @>, =@=, \=@=]). +:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]). % the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY). max_arity(63). @@ -356,7 +356,7 @@ set_difference([], _, []) :- !. set_difference(Xs, [], Xs). group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- - V1 =@= V2, !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0). + non_iso:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, _, [], Pairs). group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :- @@ -762,6 +762,48 @@ atom_codes(Atom, List) :- ; throw(error(type_error(atom, Atom), atom_codes/2)) ). +atom_concat(Atom_1, Atom_2, Atom_12) :- + error:can_be(atom, Atom_1), + error:can_be(atom, Atom_2), + error:can_be(atom, Atom_12), + ( var(Atom_1) -> + ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) + ; atom_chars(Atom_12, Atom_12_Chars), + lists:append(BeforeChars, AfterChars, Atom_12_Chars), + atom_chars(Atom_1, BeforeChars), + atom_chars(Atom_2, AfterChars) + ) + ; var(Atom_2) -> + ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) + ; atom_chars(Atom_1, Atom_1_Chars), + atom_chars(Atom_12, Atom_12_Chars), + lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), + atom_chars(Atom_2, Atom_2_Chars) + ) + ; atom_chars(Atom_1, Atom_1_Chars), + atom_chars(Atom_2, Atom_2_Chars), + lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), + atom_chars(Atom_12, Atom_12_Chars) + ). + +sub_atom(Atom, Before, Length, After, Sub_atom) :- + error:must_be(atom, Atom), + error:can_be(atom, Sub_atom), + error:can_be(integer, Before), + error:can_be(integer, Length), + error:can_be(integer, After), + ( integer(Before), Before < 0 -> throw(error(domain_error(not_less_than_zero, Before), sub_atom/5)) + ; integer(Length), Length < 0 -> throw(error(domain_error(not_less_than_zero, Length), sub_atom/5)) + ; integer(After), After < 0 -> throw(error(domain_error(not_less_than_zero, After), sub_atom/5)) + ; atom_chars(Atom, AtomChars), + lists:append(BeforeChars, LengthAndAfterChars, AtomChars), + lists:append(LengthChars, AfterChars, LengthAndAfterChars), + '$skip_max_list'(Before, -1, BeforeChars, []), + '$skip_max_list'(Length, -1, LengthChars, []), + '$skip_max_list'(After, -1, AfterChars, []), + atom_chars(Sub_atom, LengthChars) + ). + char_code(Char, Code) :- ( var(Char) -> ( var(Code) -> throw(error(instantiation_error, char_code/2)) @@ -840,6 +882,21 @@ number_chars(N, Chs) :- Chsx = Chs ). +number_codes(N, Chs) :- + ( ground(Chs) + -> can_be_number(N, number_codes/2), + can_be_list(Chs, number_codes/2), + '$codes_to_number'(Chs, Nx), + Nx = N + ; must_be_number(N, number_codes/2), + ( var(Chs) -> true + ; can_be_list(Chs, number_codes/2) + , codes_or_vars(Chs, number_codes/2) + ), + '$number_to_codes'(N, Chsx), + Chsx = Chs + ). + subsumes_term(General, Specific) :- \+ \+ ( term_variables(Specific, SVs1), diff --git a/src/prolog/lib/non_iso.pl b/src/prolog/lib/non_iso.pl index f23c2d8e..9d4367fb 100644 --- a/src/prolog/lib/non_iso.pl +++ b/src/prolog/lib/non_iso.pl @@ -5,7 +5,7 @@ :- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2, call_with_inference_limit/3, forall/2, - setup_call_cleanup/3]). + setup_call_cleanup/3, variant/2]). forall(Generate, Test) :- \+ (Generate, \+ Test). @@ -110,3 +110,5 @@ call_with_inference_limit(_, _, R, Bb, B) :- ; '$remove_call_policy_check'(B), '$fail' ), '$erase_ball', '$call_with_default_policy'(handle_ile(B, Ball, R)). + +variant(X, Y) :- '$variant'(X, Y). diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 3994787c..50eb4c11 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -11,7 +11,7 @@ use prolog::machine::machine_errors::*; use prolog::machine::machine_indices::*; use prolog::machine::modules::*; use prolog::machine::or_stack::*; -use prolog::num::{BigInt, BigUint, Zero, One}; +use prolog::num::{BigInt, BigUint, One, ToPrimitive, Zero}; use prolog::read::PrologStream; use downcast::Any; @@ -244,7 +244,7 @@ impl MachineState { { let mut chars = String::new(); let mut iter = addrs.iter(); - + while let Some(addr) = iter.next() { match addr { &Addr::Con(Constant::String(ref s)) @@ -269,6 +269,38 @@ impl MachineState { Ok(chars) } + pub(super) + fn try_code_list(&self, addrs: Vec) -> Result, MachineError> + { + let mut codes = vec![]; + let mut iter = addrs.iter(); + + while let Some(addr) = iter.next() { + match addr { + &Addr::Con(Constant::String(ref s)) + if self.flags.double_quotes.is_codes() => { + codes.extend(s.borrow().chars().map(|c| c as u8)); + + if iter.next().is_some() { + return Err(MachineError::representation_error(RepFlag::CharacterCode)); + } + }, + &Addr::Con(Constant::CharCode(c)) => + codes.push(c), + &Addr::Con(Constant::Number(Number::Integer(ref n))) => + if let Some(c) = n.to_u8() { + codes.push(c); + } else { + return Err(MachineError::representation_error(RepFlag::CharacterCode)); + }, + _ => + return Err(MachineError::representation_error(RepFlag::CharacterCode)) + } + } + + Ok(codes) + } + fn call_at_index(&mut self, arity: usize, p: usize) { self.cp.assign_if_local(self.p.clone() + 1); @@ -596,14 +628,7 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::CompareTerm(qt) => { - match qt { - CompareTermQT::Equal => - machine_st.fail = machine_st.structural_eq_test(), - CompareTermQT::NotEqual => - machine_st.fail = !machine_st.structural_eq_test(), - _ => machine_st.compare_term(qt) - }; - + machine_st.compare_term(qt); return_from_clause!(machine_st.last_call, machine_st) }, &BuiltInClauseType::CyclicTerm => { diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 1b206b1a..bab156b4 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1815,11 +1815,15 @@ impl MachineState { self.fail = true; }, Addr::Con(Constant::String(ref s)) - if self.flags.double_quotes.is_chars() && !s.is_empty() => { + if !self.flags.double_quotes.is_atom() && !s.is_empty() => { if n == 1 || n == 2 { let a3 = self[temp_v!(3)].clone(); let h_a = if n == 1 { - Addr::Con(Constant::Char(s.head().unwrap())) + if self.flags.double_quotes.is_chars() { + Addr::Con(Constant::Char(s.head().unwrap())) + } else { + Addr::Con(Constant::CharCode(s.head().unwrap() as u8)) + } } else { Addr::Con(Constant::String(s.tail())) }; @@ -2228,7 +2232,7 @@ impl MachineState { Addr::DBRef(_) => self.fail = true, Addr::Con(Constant::String(ref s)) - if self.flags.double_quotes.is_chars() && !s.is_empty() => { + if !self.flags.double_quotes.is_atom() && !s.is_empty() => { let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir); self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc) }, @@ -2362,7 +2366,7 @@ impl MachineState { l = hcp + 1; }, Addr::Con(Constant::String(ref s)) - if self.flags.double_quotes.is_chars() => { + if !self.flags.double_quotes.is_atom() => { result.push(Addr::Con(Constant::String(s.clone()))); break; }, @@ -2382,7 +2386,7 @@ impl MachineState { Ok(result) }, - Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_chars() => + Addr::Con(Constant::String(ref s)) if !self.flags.double_quotes.is_atom() => Ok(vec![Addr::Con(Constant::String(s.clone()))]), Addr::HeapCell(_) | Addr::StackCell(..) => Err(self.error_form(MachineError::instantiation_error(), caller)), diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index f52a15e5..8230950c 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -80,7 +80,7 @@ impl MachineState { Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset), Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, Addr::Con(Constant::String(ref s)) - if self.flags.double_quotes.is_chars() => + if !self.flags.double_quotes.is_atom() => return CycleSearchResult::String(0, s.clone()), _ => return CycleSearchResult::NotList }; @@ -105,7 +105,7 @@ impl MachineState { Addr::Lis(offset) => offset + 1, Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList, Addr::Con(Constant::String(ref s)) - if self.flags.double_quotes.is_chars() => + if !self.flags.double_quotes.is_atom() => return CycleSearchResult::String(0, s.clone()), _ => return CycleSearchResult::NotList }; @@ -158,7 +158,7 @@ impl MachineState { }; match search_result { - CycleSearchResult::String(n, s) => + CycleSearchResult::String(n, s) => if max_steps == -1 { self.finalize_skip_max_list(n + s.len(), Addr::Con(Constant::EmptyList)) @@ -352,6 +352,52 @@ impl MachineState { } } + fn parse_number_from_string(&mut self, mut string: String, indices: &IndexStore, stub: MachineStub) + -> CallResult + { + let nx = self[temp_v!(2)].clone(); + + if let Some(c) = string.chars().last() { + if layout_char!(c) { + let err = ParserError::UnexpectedChar(c); + + let h = self.heap.h; + let err = MachineError::syntax_error(h, err); + + return Err(self.error_form(err, stub)); + } + } + + string.push('.'); + + let mut stream = parsing_stream(std::io::Cursor::new(string)); + let mut parser = Parser::new(&mut stream, indices.atom_tbl.clone(), + self.machine_flags()); + + match parser.read_term(composite_op!(&indices.op_dir)) { + Err(err) => { + let h = self.heap.h; + let err = MachineError::syntax_error(h, err); + + return Err(self.error_form(err, stub)); + }, + Ok(Term::Constant(_, Constant::Number(n))) => + self.unify(nx, Addr::Con(Constant::Number(n))), + Ok(Term::Constant(_, Constant::CharCode(c))) => + self.unify(nx, Addr::Con(Constant::CharCode(c))), + _ => { + let err = ParserError::ParseBigInt; + + let h = self.heap.h; + let err = MachineError::syntax_error(h, err); + + return Err(self.error_form(err, stub)); + } + } + + Ok(()) + } + pub(super) fn system_call(&mut self, ct: &SystemClauseType, indices: &mut IndexStore, @@ -509,53 +555,15 @@ impl MachineState { self.unify(a2, Addr::Con(Constant::Number(len))); }, - &SystemClauseType::CharsToNumber => { - let nx = self[temp_v!(2)].clone(); + &SystemClauseType::CharsToNumber => { let stub = MachineError::functor_stub(clause_name!("number_chars"), 2); match self.try_from_list(temp_v!(1), stub.clone()) { Err(e) => return Err(e), Ok(addrs) => match self.try_char_list(addrs) { - Ok(mut string) => { - if let Some(c) = string.chars().last() { - if layout_char!(c) { - let err = ParserError::UnexpectedChar(c); - - let h = self.heap.h; - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); - } - } - - string.push('.'); - - let mut stream = parsing_stream(std::io::Cursor::new(string)); - let mut parser = Parser::new(&mut stream, indices.atom_tbl.clone(), - self.machine_flags()); - - match parser.read_term(composite_op!(&indices.op_dir)) { - Err(err) => { - let h = self.heap.h; - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); - }, - Ok(Term::Constant(_, Constant::Number(n))) => - self.unify(nx, Addr::Con(Constant::Number(n))), - Ok(Term::Constant(_, Constant::CharCode(c))) => - self.unify(nx, Addr::Con(Constant::CharCode(c))), - _ => { - let err = ParserError::ParseBigInt; - - let h = self.heap.h; - let err = MachineError::syntax_error(h, err); - - return Err(self.error_form(err, stub)); - } - } - }, + Ok(string) => + self.parse_number_from_string(string, indices, stub)?, Err(err) => return Err(self.error_form(err, stub)) } @@ -577,6 +585,39 @@ impl MachineState { let char_list = Addr::HeapCell(self.heap.to_list(chars)); self.unify(char_list, chs); + }, + &SystemClauseType::NumberToCodes => { + let n = self[temp_v!(1)].clone(); + let chs = self[temp_v!(2)].clone(); + + let string = match self.store(self.deref(n)) { + Addr::Con(Constant::Number(Number::Float(OrderedFloat(n)))) => + format!("{0:<20?}", n), + Addr::Con(Constant::Number(Number::Integer(n))) => + n.to_string(), + _ => unreachable!() + }; + + let codes = string.trim().chars().map(|c| Addr::Con(Constant::CharCode(c as u8))); + let codes_list = Addr::HeapCell(self.heap.to_list(codes)); + + self.unify(codes_list, chs); + }, + &SystemClauseType::CodesToNumber => { + let stub = MachineError::functor_stub(clause_name!("number_codes"), 2); + + match self.try_from_list(temp_v!(1), stub.clone()) { + Err(e) => return Err(e), + Ok(addrs) => + match self.try_code_list(addrs) { + Ok(codes) => { + let string = codes.iter().map(|c| *c as char).collect(); + self.parse_number_from_string(string, indices, stub)? + }, + Err(err) => + return Err(self.error_form(err, stub)) + } + } }, &SystemClauseType::ModuleAssertDynamicPredicateToFront => { let p = self.cp; @@ -1600,7 +1641,10 @@ impl MachineState { self.unify_with_occurs_check(a1, a2); }, - &SystemClauseType::UnwindStack => self.unwind_stack(), + &SystemClauseType::UnwindStack => + self.unwind_stack(), + &SystemClauseType::Variant => + self.fail = self.structural_eq_test(), &SystemClauseType::WriteTerm => { let addr = self[temp_v!(1)].clone(); diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 7a4f193c..6a357ea3 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -127,8 +127,6 @@ impl fmt::Display for CompareTermQT { &CompareTermQT::GreaterThanOrEqual => write!(f, "@>="), &CompareTermQT::LessThan => write!(f, "@<"), &CompareTermQT::LessThanOrEqual => write!(f, "@<="), - &CompareTermQT::NotEqual => write!(f, "\\=@="), - &CompareTermQT::Equal => write!(f, "=@="), } } } diff --git a/src/tests.rs b/src/tests.rs index 03134dc5..338ff528 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1620,14 +1620,16 @@ fn test_queries_on_builtins() assert_prolog_success!(&mut wam, "1.0 @=< 1."); assert_prolog_success!(&mut wam, "1 @=< 1.0."); //TODO: currently this succeeds. make it fail. - assert_prolog_success!(&mut wam, "X =@= Y."); - assert_prolog_failure!(&mut wam, "f(X) =@= f(x)."); - assert_prolog_failure!(&mut wam, "X \\=@= X."); - assert_prolog_success!(&mut wam, "f(x) =@= f(x)."); - assert_prolog_failure!(&mut wam, "[X,Y,Z] =@= [V,W,V]."); - assert_prolog_success!(&mut wam, "[X,Y,Z] =@= [V,W,Z]."); - assert_prolog_success!(&mut wam, "[X,Y,X] =@= [V,W,V]."); - assert_prolog_success!(&mut wam, "g(B) = B,g(A) = A,A =@= B."); + 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]"]]); @@ -2193,15 +2195,17 @@ 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, "\"\" =@= []."); + assert_prolog_success!(&mut wam, "variant(\"\", [])."); assert_prolog_failure!(&mut wam, "\"\" == []."); assert_prolog_failure!(&mut wam, "\"abc\" == []."); - assert_prolog_success!(&mut wam, "\"abc\" =@= ['a', 'b', 'c']."); - assert_prolog_success!(&mut wam, "\"abc\" =@= ['a', 'b', c]."); - assert_prolog_success!(&mut wam, "\"abc\" =@= ['a', b, 'c']."); - assert_prolog_success!(&mut wam, "\"abc\" =@= [a, 'b', 'c']."); - assert_prolog_success!(&mut wam, "\"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_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']."); @@ -2209,21 +2213,21 @@ fn test_queries_on_string_lists() 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, "\"koen\" =@= [k, o, e, n]."); - assert_prolog_success!(&mut wam, "\"koen\" =@= \"koen\"."); + 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], 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\", X =@= Y."); - assert_prolog_success!(&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])."); @@ -2236,9 +2240,9 @@ fn test_queries_on_string_lists() submit(&mut wam, "matcher([a,b,c|X], X)."); - assert_prolog_success!(&mut wam, "matcher(\"abcdef\", X), X = [d,e,f|Y], Y =@= [], X = \"def\".", + 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], Y =@= [], X =@= \"def\".", + 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]"]]); @@ -2301,14 +2305,14 @@ fn test_queries_on_string_lists() 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], - X =@= 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."); + X == Z."); - assert_prolog_success!(&mut wam, "partial_string(\"abc\",X),X @> \"abc\"."); - assert_prolog_failure!(&mut wam, "partial_string(\"abc\",X),X \\=@= \"abc\"."); - assert_prolog_failure!(&mut wam, "partial_string(\"abc\",X),X @< \"abc\"."); + 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).", -- 2.54.0