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] [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"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 => {

View File

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

View File

@@ -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();

View File

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

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