correct various bugs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.73"
|
||||
version = "0.8.74"
|
||||
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.23"
|
||||
prolog_parser = "0.8.24"
|
||||
readline_rs_compat = { version = "0.1.9", optional = true }
|
||||
ref_thread_local = "0.0.0"
|
||||
|
||||
|
||||
@@ -733,27 +733,31 @@ atom_length(Atom, Length) :-
|
||||
; throw(error(type_error(atom, Atom), atom_length/2)) % 8.16.1.3 b)
|
||||
).
|
||||
|
||||
no_var_in_list([]).
|
||||
no_var_in_list([X|Xs]) :- var(X), !, '$fail'.
|
||||
no_var_in_list([_|Xs]) :- nonvar(Xs), no_var_in_list(Xs).
|
||||
|
||||
atom_chars(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) -> true
|
||||
; throw(error(type_error(list, List), atom_chars/2))
|
||||
),
|
||||
( var(Atom) ->
|
||||
( var(List) -> throw(error(instantiation_error, atom_chars/2))
|
||||
; can_be_list(List, atom_chars/3), no_var_in_list(List) -> '$atom_chars'(Atom, List)
|
||||
( var(Tail) -> throw(error(instantiation_error, atom_chars/2))
|
||||
; ground(List), Tail == [] -> '$atom_chars'(Atom, List)
|
||||
; throw(error(instantiation_error, atom_chars/2))
|
||||
)
|
||||
; atom(Atom) -> '$atom_chars'(Atom, List)
|
||||
; atom(Atom) -> can_be_chars_or_vars(List, atom_chars/2), '$atom_chars'(Atom, List)
|
||||
; throw(error(type_error(atom, Atom), atom_chars/2))
|
||||
).
|
||||
|
||||
atom_codes(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) -> true
|
||||
; throw(error(type_error(list, List), atom_codes/2))
|
||||
),
|
||||
( var(Atom) ->
|
||||
( var(List) -> throw(error(instantiation_error, atom_codes/2))
|
||||
; can_be_list(List, atom_codes/3), no_var_in_list(List) -> '$atom_codes'(Atom, List)
|
||||
( var(Tail) -> throw(error(instantiation_error, atom_codes/2))
|
||||
; ground(List), Tail == [] -> '$atom_codes'(Atom, List)
|
||||
; throw(error(instantiation_error, atom_codes/2))
|
||||
)
|
||||
; atom(Atom) -> '$atom_codes'(Atom, List)
|
||||
; atom(Atom) -> can_be_codes_or_vars(List, atom_codes/2), '$atom_codes'(Atom, List)
|
||||
; throw(error(type_error(atom, Atom), atom_codes/2))
|
||||
).
|
||||
|
||||
@@ -789,16 +793,35 @@ must_be_number(N, PI) :-
|
||||
; throw(error(instantiation_error, PI))
|
||||
).
|
||||
|
||||
must_be_chars([], _).
|
||||
must_be_chars([C|Cs], PI) :-
|
||||
can_be_chars_or_vars(Cs, _) :- var(Cs), !.
|
||||
can_be_chars_or_vars(Cs, PI) :- chars_or_vars(Cs, PI).
|
||||
|
||||
chars_or_vars([], _).
|
||||
chars_or_vars([C|Cs], PI) :-
|
||||
( nonvar(C) ->
|
||||
( atom_length(C, 1) ->
|
||||
( nonvar(Cs) -> must_be_chars(Cs, PI)
|
||||
; false %% throw(error(type_error(list, Cs), PI))
|
||||
( catch(atom_length(C, 1), _, false) ->
|
||||
( nonvar(Cs) -> chars_or_vars(Cs, PI)
|
||||
; false
|
||||
)
|
||||
; throw(error(type_error(character, C), PI))
|
||||
)
|
||||
; must_be_chars(Cs, PI)
|
||||
; chars_or_vars(Cs, PI)
|
||||
).
|
||||
|
||||
can_be_codes_or_vars(Cs, _) :- var(Cs), !.
|
||||
can_be_codes_or_vars(Cs, PI) :- codes_or_vars(Cs, PI).
|
||||
|
||||
codes_or_vars([], _).
|
||||
codes_or_vars([C|Cs], PI) :-
|
||||
( nonvar(C) ->
|
||||
( catch(char_code(_, C), _, false) ->
|
||||
( nonvar(Cs) -> codes_or_vars(Cs, PI)
|
||||
; false
|
||||
)
|
||||
; integer(C) -> throw(error(representation_error(character_code), PI))
|
||||
; throw(error(type_error(integer, C), PI))
|
||||
)
|
||||
; codes_or_vars(Cs, PI)
|
||||
).
|
||||
|
||||
number_chars(N, Chs) :-
|
||||
@@ -810,7 +833,7 @@ number_chars(N, Chs) :-
|
||||
; must_be_number(N, number_chars/2),
|
||||
( var(Chs) -> true
|
||||
; can_be_list(Chs, number_chars/2)
|
||||
, must_be_chars(Chs, number_chars/2)
|
||||
, chars_or_vars(Chs, number_chars/2)
|
||||
),
|
||||
'$number_to_chars'(N, Chsx),
|
||||
Chsx = Chs
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::string_list::*;
|
||||
|
||||
use prolog::machine::machine_indices::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
@@ -273,6 +274,7 @@ pub(super) enum CycleSearchResult {
|
||||
NotList,
|
||||
PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
|
||||
ProperList(usize), // the list length.
|
||||
String(usize, StringList), // the number of elements iterated, the string tail.
|
||||
UntouchedList(usize) // the address of an uniterated Addr::Lis(address).
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +239,36 @@ pub struct MachineState {
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super)
|
||||
fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError>
|
||||
{
|
||||
let mut chars = String::new();
|
||||
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_chars() => {
|
||||
chars += s.borrow().as_str();
|
||||
|
||||
if iter.next().is_some() {
|
||||
return Err(MachineError::type_error(ValidType::Character, addr.clone()));
|
||||
}
|
||||
},
|
||||
&Addr::Con(Constant::Char(c)) =>
|
||||
chars.push(c),
|
||||
&Addr::Con(Constant::Atom(ref name, _))
|
||||
if name.as_str().len() == 1 => {
|
||||
chars += name.as_str();
|
||||
},
|
||||
_ =>
|
||||
return Err(MachineError::type_error(ValidType::Character, addr.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(chars)
|
||||
}
|
||||
|
||||
fn call_at_index(&mut self, arity: usize, p: usize)
|
||||
{
|
||||
self.cp.assign_if_local(self.p.clone() + 1);
|
||||
@@ -320,27 +350,6 @@ fn try_in_situ(machine_st: &mut MachineState, name: ClauseName, arity: usize,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn try_char_list(addrs: Vec<Addr>) -> Result<String, MachineError>
|
||||
{
|
||||
let mut chars = String::new();
|
||||
|
||||
for addr in addrs.iter() {
|
||||
match addr {
|
||||
&Addr::Con(Constant::Char(c)) =>
|
||||
chars.push(c),
|
||||
&Addr::Con(Constant::Atom(ref name, _))
|
||||
if name.as_str().len() == 1 => {
|
||||
chars += name.as_str();
|
||||
},
|
||||
_ =>
|
||||
return Err(MachineError::type_error(ValidType::Character, addr.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(chars)
|
||||
}
|
||||
|
||||
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
|
||||
|
||||
pub(crate) trait CallPolicy: Any {
|
||||
|
||||
@@ -1691,6 +1691,21 @@ impl MachineState {
|
||||
} else {
|
||||
self.fail = true;
|
||||
},
|
||||
Addr::Con(Constant::String(ref s))
|
||||
if self.flags.double_quotes.is_chars() && !s.is_empty() => {
|
||||
if n == 1 || n == 2 {
|
||||
let a3 = self[temp_v!(3)].clone();
|
||||
let h_a = if n == 1 {
|
||||
Addr::Con(Constant::Char(s.head().unwrap()))
|
||||
} else {
|
||||
Addr::Con(Constant::String(s.tail()))
|
||||
};
|
||||
|
||||
self.unify(a3, h_a);
|
||||
} else {
|
||||
self.fail = true;
|
||||
}
|
||||
},
|
||||
_ => // 8.5.2.3 d)
|
||||
return Err(self.error_form(MachineError::type_error(ValidType::Compound, term),
|
||||
stub))
|
||||
@@ -2089,6 +2104,11 @@ impl MachineState {
|
||||
match a1.clone() {
|
||||
Addr::DBRef(_) =>
|
||||
self.fail = true,
|
||||
Addr::Con(Constant::String(ref s))
|
||||
if self.flags.double_quotes.is_chars() && !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)
|
||||
},
|
||||
Addr::Con(_) =>
|
||||
self.try_functor_unify_components(a1, Addr::Con(integer!(0))),
|
||||
Addr::Str(o) =>
|
||||
@@ -2187,7 +2207,7 @@ impl MachineState {
|
||||
|
||||
match self.try_from_list(r, stub.clone()) {
|
||||
Ok(addrs) =>
|
||||
Ok(StringList::new(match try_char_list(addrs) {
|
||||
Ok(StringList::new(match self.try_char_list(addrs) {
|
||||
Ok(string) => string,
|
||||
Err(err) => {
|
||||
return Err(self.error_form(err, stub));
|
||||
@@ -2218,6 +2238,11 @@ impl MachineState {
|
||||
result.push(self.heap[hcp].as_addr(hcp));
|
||||
l = hcp + 1;
|
||||
},
|
||||
Addr::Con(Constant::String(ref s))
|
||||
if self.flags.double_quotes.is_chars() => {
|
||||
result.push(Addr::Con(Constant::String(s.clone())));
|
||||
break;
|
||||
},
|
||||
Addr::Con(Constant::EmptyList) =>
|
||||
break,
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
@@ -2229,11 +2254,13 @@ impl MachineState {
|
||||
_ =>
|
||||
return Err(self.error_form(MachineError::type_error(ValidType::List, a1),
|
||||
caller))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
},
|
||||
Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_chars() =>
|
||||
Ok(vec![Addr::Con(Constant::String(s.clone()))]),
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
Err(self.error_form(MachineError::instantiation_error(), caller)),
|
||||
Addr::Con(Constant::EmptyList) =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::*;
|
||||
use prolog_parser::string_list::*;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
|
||||
use prolog::clause_types::*;
|
||||
@@ -49,6 +50,9 @@ impl MachineState {
|
||||
Some(CycleSearchResult::ProperList(brent_st.steps)),
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) =>
|
||||
Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
|
||||
Addr::Con(Constant::String(ref s))
|
||||
if self.flags.double_quotes.is_chars() =>
|
||||
Some(CycleSearchResult::String(brent_st.steps, s.clone())),
|
||||
Addr::Lis(l) => {
|
||||
brent_st.hare = l + 1;
|
||||
brent_st.steps += 1;
|
||||
@@ -75,6 +79,9 @@ impl MachineState {
|
||||
Addr::Lis(offset) if max_steps > 0 => offset + 1,
|
||||
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() =>
|
||||
return CycleSearchResult::String(0, s.clone()),
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
@@ -97,6 +104,9 @@ impl MachineState {
|
||||
let hare = match addr {
|
||||
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() =>
|
||||
return CycleSearchResult::String(0, s.clone()),
|
||||
_ => return CycleSearchResult::NotList
|
||||
};
|
||||
|
||||
@@ -135,18 +145,35 @@ impl MachineState {
|
||||
self.unify(xs0, xs);
|
||||
},
|
||||
_ => {
|
||||
let search_result = if let Some(max_steps) = max_steps.to_isize() {
|
||||
if max_steps == -1 {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
let (max_steps, search_result) =
|
||||
if let Some(max_steps) = max_steps.to_isize() {
|
||||
(max_steps, if max_steps == -1 {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
} else {
|
||||
self.detect_cycles_with_max(max_steps as usize,
|
||||
self[temp_v!(3)].clone())
|
||||
})
|
||||
} else {
|
||||
self.detect_cycles_with_max(max_steps as usize,
|
||||
self[temp_v!(3)].clone())
|
||||
}
|
||||
} else {
|
||||
self.detect_cycles(self[temp_v!(3)].clone())
|
||||
};
|
||||
(-1, self.detect_cycles(self[temp_v!(3)].clone()))
|
||||
};
|
||||
|
||||
match search_result {
|
||||
CycleSearchResult::String(n, s) =>
|
||||
if max_steps == -1 {
|
||||
self.finalize_skip_max_list(n + s.len(),
|
||||
Addr::Con(Constant::EmptyList))
|
||||
} else {
|
||||
let i = max_steps.to_usize().unwrap() - n;
|
||||
|
||||
if s.len() < i {
|
||||
self.finalize_skip_max_list(n + s.len(),
|
||||
Addr::Con(Constant::EmptyList))
|
||||
} else {
|
||||
let s = StringList::new(s.char_span(i), s.is_expandable());
|
||||
self.finalize_skip_max_list(i + n,
|
||||
Addr::Con(Constant::String(s)))
|
||||
}
|
||||
},
|
||||
CycleSearchResult::UntouchedList(l) =>
|
||||
self.finalize_skip_max_list(0, Addr::Lis(l)),
|
||||
CycleSearchResult::EmptyList =>
|
||||
@@ -395,7 +422,7 @@ impl MachineState {
|
||||
match self.try_from_list(temp_v!(2), stub.clone()) {
|
||||
Err(e) => return Err(e),
|
||||
Ok(addrs) =>
|
||||
match try_char_list(addrs) {
|
||||
match self.try_char_list(addrs) {
|
||||
Ok(string) => {
|
||||
let chars = clause_name!(string, indices.atom_tbl);
|
||||
self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None)));
|
||||
@@ -453,7 +480,7 @@ impl MachineState {
|
||||
&Addr::Con(Constant::CharCode(c)) =>
|
||||
chars.push(c as char),
|
||||
_ => {
|
||||
let err = MachineError::representation_error(RepFlag::CharacterCode);
|
||||
let err = MachineError::type_error(ValidType::Integer, addr.clone());
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
}
|
||||
@@ -489,19 +516,19 @@ impl MachineState {
|
||||
match self.try_from_list(temp_v!(1), stub.clone()) {
|
||||
Err(e) => return Err(e),
|
||||
Ok(addrs) =>
|
||||
match try_char_list(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));
|
||||
@@ -521,7 +548,7 @@ impl MachineState {
|
||||
self.unify(nx, Addr::Con(Constant::CharCode(c))),
|
||||
_ => {
|
||||
let err = ParserError::ParseBigInt;
|
||||
|
||||
|
||||
let h = self.heap.h;
|
||||
let err = MachineError::syntax_error(h, err);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user