add remaining atomic term processing builtins, rename (=@=)/2 to variant/2, address issue #133
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.76"
|
version = "0.8.77"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
repository = "https://github.com/mthom/scryer-prolog"
|
repository = "https://github.com/mthom/scryer-prolog"
|
||||||
description = "A modern Prolog implementation written mostly in Rust."
|
description = "A modern Prolog implementation written mostly in Rust."
|
||||||
@@ -14,7 +14,7 @@ cfg-if = "0.1.7"
|
|||||||
downcast = "0.10.0"
|
downcast = "0.10.0"
|
||||||
num = "0.2"
|
num = "0.2"
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = "0.8.24"
|
prolog_parser = "0.8.26"
|
||||||
readline_rs_compat = { version = "0.1.9", optional = true }
|
readline_rs_compat = { version = "0.1.9", optional = true }
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
|
|
||||||
|
|||||||
@@ -141,8 +141,6 @@ The following predicates are built-in to Scryer.
|
|||||||
* `(@>=)/2`
|
* `(@>=)/2`
|
||||||
* `(@=<)/2`
|
* `(@=<)/2`
|
||||||
* `(@<)/2`
|
* `(@<)/2`
|
||||||
* `(=@=)/2`
|
|
||||||
* `(\=@=)/2`
|
|
||||||
* `(\+)/1`
|
* `(\+)/1`
|
||||||
* `(==)/2`
|
* `(==)/2`
|
||||||
* `(\==)/2`
|
* `(\==)/2`
|
||||||
@@ -232,6 +230,7 @@ The following predicates are built-in to Scryer.
|
|||||||
* `user:goal_expansion/2`
|
* `user:goal_expansion/2`
|
||||||
* `user:term_expansion/2`
|
* `user:term_expansion/2`
|
||||||
* `var/1`
|
* `var/1`
|
||||||
|
* `variant/2`
|
||||||
* `write/1`
|
* `write/1`
|
||||||
* `write_canonical/1`
|
* `write_canonical/1`
|
||||||
* `writeq/1`
|
* `writeq/1`
|
||||||
|
|||||||
@@ -33,10 +33,8 @@ impl CompareNumberQT {
|
|||||||
pub enum CompareTermQT {
|
pub enum CompareTermQT {
|
||||||
LessThan,
|
LessThan,
|
||||||
LessThanOrEqual,
|
LessThanOrEqual,
|
||||||
Equal,
|
|
||||||
GreaterThanOrEqual,
|
GreaterThanOrEqual,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
NotEqual,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompareTermQT {
|
impl CompareTermQT {
|
||||||
@@ -46,8 +44,6 @@ impl CompareTermQT {
|
|||||||
CompareTermQT::LessThan => "@<",
|
CompareTermQT::LessThan => "@<",
|
||||||
CompareTermQT::GreaterThanOrEqual => "@>=",
|
CompareTermQT::GreaterThanOrEqual => "@>=",
|
||||||
CompareTermQT::LessThanOrEqual => "@=<",
|
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::LessThan)));
|
||||||
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
|
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::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(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
|
||||||
m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm));
|
m.insert(("cyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::CyclicTerm));
|
||||||
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
||||||
@@ -166,6 +160,7 @@ pub enum SystemClauseType {
|
|||||||
ModuleAssertDynamicPredicateToBack,
|
ModuleAssertDynamicPredicateToBack,
|
||||||
CharCode,
|
CharCode,
|
||||||
CharsToNumber,
|
CharsToNumber,
|
||||||
|
CodesToNumber,
|
||||||
CheckCutPoint,
|
CheckCutPoint,
|
||||||
CopyToLiftedHeap,
|
CopyToLiftedHeap,
|
||||||
DeleteAttribute,
|
DeleteAttribute,
|
||||||
@@ -202,6 +197,7 @@ pub enum SystemClauseType {
|
|||||||
ModuleRetractClause,
|
ModuleRetractClause,
|
||||||
NoSuchPredicate,
|
NoSuchPredicate,
|
||||||
NumberToChars,
|
NumberToChars,
|
||||||
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
ReadTerm,
|
ReadTerm,
|
||||||
@@ -233,7 +229,8 @@ pub enum SystemClauseType {
|
|||||||
TermVariables,
|
TermVariables,
|
||||||
TruncateLiftedHeapTo,
|
TruncateLiftedHeapTo,
|
||||||
UnifyWithOccursCheck,
|
UnifyWithOccursCheck,
|
||||||
UnwindStack,
|
UnwindStack,
|
||||||
|
Variant,
|
||||||
WriteTerm
|
WriteTerm
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +248,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
|
&SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
|
||||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||||
|
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) =>
|
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) =>
|
||||||
@@ -291,6 +289,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||||
@@ -321,6 +320,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
||||||
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
||||||
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
||||||
|
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||||
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,6 +338,7 @@ impl SystemClauseType {
|
|||||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||||
|
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||||
@@ -374,6 +375,7 @@ impl SystemClauseType {
|
|||||||
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
|
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
|
||||||
("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
|
("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
|
||||||
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
||||||
|
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
||||||
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
||||||
("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings),
|
("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings),
|
||||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||||
@@ -407,6 +409,7 @@ impl SystemClauseType {
|
|||||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||||
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
||||||
|
("$variant", 2) => Some(SystemClauseType::Variant),
|
||||||
("$write_term", 4) => Some(SystemClauseType::WriteTerm),
|
("$write_term", 4) => Some(SystemClauseType::WriteTerm),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ impl CodeOffsets {
|
|||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
self.lists.push(Self::add_index(is_initial_index, index));
|
||||||
},
|
},
|
||||||
&Term::Constant(_, Constant::String(_))
|
&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();
|
let is_initial_index = self.lists.is_empty();
|
||||||
self.lists.push(Self::add_index(is_initial_index, index));
|
self.lists.push(Self::add_index(is_initial_index, index));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,16 +10,16 @@
|
|||||||
(is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2, (>>)/2,
|
(is)/2, (xor)/2, (div)/2, (//)/2, (rdiv)/2, (<<)/2, (>>)/2,
|
||||||
(mod)/2, (rem)/2, (>)/2, (<)/2, (=\=)/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,
|
||||||
(@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (=@=)/2, (\=@=)/2, (:)/2,
|
(@=<)/2, (@>=)/2, (@<)/2, (@>)/2, (:)/2, abolish/1, asserta/1,
|
||||||
abolish/1, asserta/1, assertz/1, atom_chars/2, atom_codes/2,
|
assertz/1, atom_chars/2, atom_codes/2, atom_concat/3,
|
||||||
atom_length/2, bagof/3, catch/3, char_code/2, clause/2,
|
atom_length/2, bagof/3, catch/3, char_code/2, clause/2,
|
||||||
current_op/3, current_predicate/1, current_prolog_flag/2,
|
current_op/3, current_predicate/1, current_prolog_flag/2,
|
||||||
expand_goal/2, expand_term/2, false/0, findall/3, findall/4,
|
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,
|
get_char/1, halt/0, number_chars/2, number_codes/2, once/1,
|
||||||
repeat/0, retract/1, set_prolog_flag/2, setof/3,
|
op/3, read_term/2, repeat/0, retract/1, set_prolog_flag/2,
|
||||||
subsumes_term/2, term_variables/2, throw/1, true/0,
|
setof/3, sub_atom/5, subsumes_term/2, term_variables/2,
|
||||||
unify_with_occurs_check/2, write/1, write_canonical/1,
|
throw/1, true/0, unify_with_occurs_check/2, write/1,
|
||||||
write_term/2, writeq/1]).
|
write_canonical/1, write_term/2, writeq/1]).
|
||||||
|
|
||||||
% module resolution operator.
|
% module resolution operator.
|
||||||
:- op(600, xfy, :).
|
:- op(600, xfy, :).
|
||||||
@@ -45,7 +45,7 @@ expand_op_list([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResu
|
|||||||
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
:- op(700, xfx, [>, <, =\=, =:=, >=, =<]).
|
||||||
|
|
||||||
% term comparison.
|
% term comparison.
|
||||||
:- op(700, xfx, [==, \==, @=<, @>=, @<, @>, =@=, \=@=]).
|
:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]).
|
||||||
|
|
||||||
% the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY).
|
% the maximum arity flag. needs to be replaced with current_prolog_flag(max_arity, MAX_ARITY).
|
||||||
max_arity(63).
|
max_arity(63).
|
||||||
@@ -356,7 +356,7 @@ set_difference([], _, []) :- !.
|
|||||||
set_difference(Xs, [], Xs).
|
set_difference(Xs, [], Xs).
|
||||||
|
|
||||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
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_variant(Pairs, _, [], Pairs).
|
||||||
|
|
||||||
group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :-
|
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))
|
; 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) :-
|
char_code(Char, Code) :-
|
||||||
( var(Char) ->
|
( var(Char) ->
|
||||||
( var(Code) -> throw(error(instantiation_error, char_code/2))
|
( var(Code) -> throw(error(instantiation_error, char_code/2))
|
||||||
@@ -840,6 +882,21 @@ number_chars(N, Chs) :-
|
|||||||
Chsx = 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) :-
|
subsumes_term(General, Specific) :-
|
||||||
\+ \+ (
|
\+ \+ (
|
||||||
term_variables(Specific, SVs1),
|
term_variables(Specific, SVs1),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
|
||||||
call_with_inference_limit/3, forall/2,
|
call_with_inference_limit/3, forall/2,
|
||||||
setup_call_cleanup/3]).
|
setup_call_cleanup/3, variant/2]).
|
||||||
|
|
||||||
forall(Generate, Test) :-
|
forall(Generate, Test) :-
|
||||||
\+ (Generate, \+ Test).
|
\+ (Generate, \+ Test).
|
||||||
@@ -110,3 +110,5 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
|||||||
; '$remove_call_policy_check'(B), '$fail' ),
|
; '$remove_call_policy_check'(B), '$fail' ),
|
||||||
'$erase_ball',
|
'$erase_ball',
|
||||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||||
|
|
||||||
|
variant(X, Y) :- '$variant'(X, Y).
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use prolog::machine::machine_errors::*;
|
|||||||
use prolog::machine::machine_indices::*;
|
use prolog::machine::machine_indices::*;
|
||||||
use prolog::machine::modules::*;
|
use prolog::machine::modules::*;
|
||||||
use prolog::machine::or_stack::*;
|
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 prolog::read::PrologStream;
|
||||||
|
|
||||||
use downcast::Any;
|
use downcast::Any;
|
||||||
@@ -244,7 +244,7 @@ impl MachineState {
|
|||||||
{
|
{
|
||||||
let mut chars = String::new();
|
let mut chars = String::new();
|
||||||
let mut iter = addrs.iter();
|
let mut iter = addrs.iter();
|
||||||
|
|
||||||
while let Some(addr) = iter.next() {
|
while let Some(addr) = iter.next() {
|
||||||
match addr {
|
match addr {
|
||||||
&Addr::Con(Constant::String(ref s))
|
&Addr::Con(Constant::String(ref s))
|
||||||
@@ -269,6 +269,38 @@ impl MachineState {
|
|||||||
Ok(chars)
|
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)
|
fn call_at_index(&mut self, arity: usize, p: usize)
|
||||||
{
|
{
|
||||||
self.cp.assign_if_local(self.p.clone() + 1);
|
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)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
},
|
},
|
||||||
&BuiltInClauseType::CompareTerm(qt) => {
|
&BuiltInClauseType::CompareTerm(qt) => {
|
||||||
match qt {
|
machine_st.compare_term(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)
|
|
||||||
};
|
|
||||||
|
|
||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
},
|
},
|
||||||
&BuiltInClauseType::CyclicTerm => {
|
&BuiltInClauseType::CyclicTerm => {
|
||||||
|
|||||||
@@ -1815,11 +1815,15 @@ impl MachineState {
|
|||||||
self.fail = true;
|
self.fail = true;
|
||||||
},
|
},
|
||||||
Addr::Con(Constant::String(ref s))
|
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 {
|
if n == 1 || n == 2 {
|
||||||
let a3 = self[temp_v!(3)].clone();
|
let a3 = self[temp_v!(3)].clone();
|
||||||
let h_a = if n == 1 {
|
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 {
|
} else {
|
||||||
Addr::Con(Constant::String(s.tail()))
|
Addr::Con(Constant::String(s.tail()))
|
||||||
};
|
};
|
||||||
@@ -2228,7 +2232,7 @@ impl MachineState {
|
|||||||
Addr::DBRef(_) =>
|
Addr::DBRef(_) =>
|
||||||
self.fail = true,
|
self.fail = true,
|
||||||
Addr::Con(Constant::String(ref s))
|
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);
|
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)
|
self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc)
|
||||||
},
|
},
|
||||||
@@ -2362,7 +2366,7 @@ impl MachineState {
|
|||||||
l = hcp + 1;
|
l = hcp + 1;
|
||||||
},
|
},
|
||||||
Addr::Con(Constant::String(ref s))
|
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())));
|
result.push(Addr::Con(Constant::String(s.clone())));
|
||||||
break;
|
break;
|
||||||
},
|
},
|
||||||
@@ -2382,7 +2386,7 @@ impl MachineState {
|
|||||||
|
|
||||||
Ok(result)
|
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()))]),
|
Ok(vec![Addr::Con(Constant::String(s.clone()))]),
|
||||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||||
Err(self.error_form(MachineError::instantiation_error(), caller)),
|
Err(self.error_form(MachineError::instantiation_error(), caller)),
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ impl MachineState {
|
|||||||
Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
|
Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
|
||||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||||
Addr::Con(Constant::String(ref s))
|
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::String(0, s.clone()),
|
||||||
_ => return CycleSearchResult::NotList
|
_ => return CycleSearchResult::NotList
|
||||||
};
|
};
|
||||||
@@ -105,7 +105,7 @@ impl MachineState {
|
|||||||
Addr::Lis(offset) => offset + 1,
|
Addr::Lis(offset) => offset + 1,
|
||||||
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
|
||||||
Addr::Con(Constant::String(ref s))
|
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::String(0, s.clone()),
|
||||||
_ => return CycleSearchResult::NotList
|
_ => return CycleSearchResult::NotList
|
||||||
};
|
};
|
||||||
@@ -158,7 +158,7 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match search_result {
|
match search_result {
|
||||||
CycleSearchResult::String(n, s) =>
|
CycleSearchResult::String(n, s) =>
|
||||||
if max_steps == -1 {
|
if max_steps == -1 {
|
||||||
self.finalize_skip_max_list(n + s.len(),
|
self.finalize_skip_max_list(n + s.len(),
|
||||||
Addr::Con(Constant::EmptyList))
|
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,
|
pub(super) fn system_call(&mut self,
|
||||||
ct: &SystemClauseType,
|
ct: &SystemClauseType,
|
||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
@@ -509,53 +555,15 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(a2, Addr::Con(Constant::Number(len)));
|
self.unify(a2, Addr::Con(Constant::Number(len)));
|
||||||
},
|
},
|
||||||
&SystemClauseType::CharsToNumber => {
|
&SystemClauseType::CharsToNumber => {
|
||||||
let nx = self[temp_v!(2)].clone();
|
|
||||||
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
||||||
|
|
||||||
match self.try_from_list(temp_v!(1), stub.clone()) {
|
match self.try_from_list(temp_v!(1), stub.clone()) {
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
Ok(addrs) =>
|
Ok(addrs) =>
|
||||||
match self.try_char_list(addrs) {
|
match self.try_char_list(addrs) {
|
||||||
Ok(mut string) => {
|
Ok(string) =>
|
||||||
if let Some(c) = string.chars().last() {
|
self.parse_number_from_string(string, indices, stub)?,
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) =>
|
Err(err) =>
|
||||||
return Err(self.error_form(err, stub))
|
return Err(self.error_form(err, stub))
|
||||||
}
|
}
|
||||||
@@ -577,6 +585,39 @@ impl MachineState {
|
|||||||
let char_list = Addr::HeapCell(self.heap.to_list(chars));
|
let char_list = Addr::HeapCell(self.heap.to_list(chars));
|
||||||
|
|
||||||
self.unify(char_list, chs);
|
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 => {
|
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
||||||
let p = self.cp;
|
let p = self.cp;
|
||||||
@@ -1600,7 +1641,10 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify_with_occurs_check(a1, a2);
|
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 => {
|
&SystemClauseType::WriteTerm => {
|
||||||
let addr = self[temp_v!(1)].clone();
|
let addr = self[temp_v!(1)].clone();
|
||||||
|
|
||||||
|
|||||||
@@ -127,8 +127,6 @@ impl fmt::Display for CompareTermQT {
|
|||||||
&CompareTermQT::GreaterThanOrEqual => write!(f, "@>="),
|
&CompareTermQT::GreaterThanOrEqual => write!(f, "@>="),
|
||||||
&CompareTermQT::LessThan => write!(f, "@<"),
|
&CompareTermQT::LessThan => write!(f, "@<"),
|
||||||
&CompareTermQT::LessThanOrEqual => write!(f, "@<="),
|
&CompareTermQT::LessThanOrEqual => write!(f, "@<="),
|
||||||
&CompareTermQT::NotEqual => write!(f, "\\=@="),
|
|
||||||
&CompareTermQT::Equal => write!(f, "=@="),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
src/tests.rs
56
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.0 @=< 1.");
|
||||||
assert_prolog_success!(&mut wam, "1 @=< 1.0."); //TODO: currently this succeeds. make it fail.
|
assert_prolog_success!(&mut wam, "1 @=< 1.0."); //TODO: currently this succeeds. make it fail.
|
||||||
|
|
||||||
assert_prolog_success!(&mut wam, "X =@= Y.");
|
submit(&mut wam, ":- use_module(library(non_iso)).");
|
||||||
assert_prolog_failure!(&mut wam, "f(X) =@= f(x).");
|
|
||||||
assert_prolog_failure!(&mut wam, "X \\=@= X.");
|
assert_prolog_success!(&mut wam, "variant(X, Y).");
|
||||||
assert_prolog_success!(&mut wam, "f(x) =@= f(x).");
|
assert_prolog_failure!(&mut wam, "variant(f(X), f(x)).");
|
||||||
assert_prolog_failure!(&mut wam, "[X,Y,Z] =@= [V,W,V].");
|
assert_prolog_success!(&mut wam, "variant(X, X).");
|
||||||
assert_prolog_success!(&mut wam, "[X,Y,Z] =@= [V,W,Z].");
|
assert_prolog_success!(&mut wam, "variant(f(x), f(x)).");
|
||||||
assert_prolog_success!(&mut wam, "[X,Y,X] =@= [V,W,V].");
|
assert_prolog_failure!(&mut wam, "variant([X,Y,Z], [V,W,V]).");
|
||||||
assert_prolog_success!(&mut wam, "g(B) = B,g(A) = A,A =@= B.");
|
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).",
|
assert_prolog_success!(&mut wam, "keysort([1-1,1-1],Sorted).",
|
||||||
[["Sorted = [1-1,1-1]"]]);
|
[["Sorted = [1-1,1-1]"]]);
|
||||||
@@ -2193,15 +2195,17 @@ fn test_queries_on_string_lists()
|
|||||||
{
|
{
|
||||||
let mut wam = Machine::new(readline::input_stream());
|
let mut wam = Machine::new(readline::input_stream());
|
||||||
|
|
||||||
|
submit(&mut wam, ":- use_module(library(non_iso)).");
|
||||||
|
|
||||||
// double_quotes is chars by default.
|
// 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, "\"\" == [].");
|
||||||
assert_prolog_failure!(&mut wam, "\"abc\" == [].");
|
assert_prolog_failure!(&mut wam, "\"abc\" == [].");
|
||||||
assert_prolog_success!(&mut wam, "\"abc\" =@= ['a', 'b', 'c'].");
|
assert_prolog_success!(&mut wam, "variant(\"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, "\"abc\" =@= ['a', b, 'c'].");
|
assert_prolog_success!(&mut wam, "variant(\"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, "\"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, "\"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, "\"abc\" == [a, 'b', c].");
|
||||||
assert_prolog_failure!(&mut wam, "\"koen\" == [k, o, e, n].");
|
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\" =@= [k, o, e, n].");
|
assert_prolog_success!(&mut wam, "variant(\"koen\", [k, o, e, n]).");
|
||||||
assert_prolog_success!(&mut wam, "\"koen\" =@= \"koen\".");
|
assert_prolog_success!(&mut wam, "variant(\"koen\", \"koen\").");
|
||||||
assert_prolog_success!(&mut wam, "\"koen\" = [k, o | X].",
|
assert_prolog_success!(&mut wam, "\"koen\" = [k, o | X].",
|
||||||
[["X = [e,n]"]]);
|
[["X = [e,n]"]]);
|
||||||
assert_prolog_success!(&mut wam, "\"koen\" = [k, o | X], X = \"en\".",
|
assert_prolog_success!(&mut wam, "\"koen\" = [k, o | X], X = \"en\".",
|
||||||
[["X = [e,n]"]]);
|
[["X = [e,n]"]]);
|
||||||
assert_prolog_failure!(&mut wam, "\"koen\" = [k, o | X], X == \"en\".");
|
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]"]]);
|
[["X = [e,n]"]]);
|
||||||
|
|
||||||
assert_prolog_failure!(&mut wam, "X = \"abc\", Y = \"abc\", X == Y.");
|
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_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, "X = \"abc\", Y = \"abc\", variant(X, Y).");
|
||||||
assert_prolog_success!(&mut wam, "partial_string(\"abc\", X), partial_string(\"abc\", Y), 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]).");
|
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).");
|
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 = []"]]);
|
[["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 = []"]]);
|
[["X = [d,e,f]", "Y = []"]]);
|
||||||
assert_prolog_success!(&mut wam, "X = ['a', 'b', 'c' | \"def\"].",
|
assert_prolog_success!(&mut wam, "X = ['a', 'b', 'c' | \"def\"].",
|
||||||
[["X = [a,b,c,d,e,f]"]]);
|
[["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\".",
|
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]"]]);
|
[["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],
|
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|_]"]]);
|
[["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],
|
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_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), \\+ variant(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(\"ab\",X),matcher(X,Y),Y = [a,b|V],
|
assert_prolog_success!(&mut wam, "partial_string(\"ab\",X),matcher(X,Y),Y = [a,b|V],
|
||||||
matcher(Y,Z),is_partial_string(Y).",
|
matcher(Y,Z),is_partial_string(Y).",
|
||||||
|
|||||||
Reference in New Issue
Block a user