add remaining atomic term processing builtins, rename (=@=)/2 to variant/2, address issue #133

This commit is contained in:
Mark Thom
2019-04-30 20:55:53 -06:00
parent fb023c99c1
commit 3fd274c583
11 changed files with 246 additions and 110 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "scryer-prolog"
version = "0.8.76"
version = "0.8.77"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
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"

View File

@@ -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`

View File

@@ -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,
@@ -234,6 +230,7 @@ pub enum SystemClauseType {
TruncateLiftedHeapTo,
UnifyWithOccursCheck,
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
}

View File

@@ -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));
},

View File

@@ -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),

View File

@@ -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).

View File

@@ -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;
@@ -269,6 +269,38 @@ impl MachineState {
Ok(chars)
}
pub(super)
fn try_code_list(&self, addrs: Vec<Addr>) -> Result<Vec<u8>, 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 => {

View File

@@ -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 {
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)),

View File

@@ -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
};
@@ -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,
@@ -510,52 +556,14 @@ impl MachineState {
self.unify(a2, Addr::Con(Constant::Number(len)));
},
&SystemClauseType::CharsToNumber => {
let nx = self[temp_v!(2)].clone();
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))
}
@@ -578,6 +586,39 @@ impl MachineState {
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;
let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front);
@@ -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();

View File

@@ -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, "=@="),
}
}
}

View File

@@ -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.");
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).",