This commit is contained in:
Mark Thom
2019-04-27 00:40:00 -06:00
parent 7bda7c5bf3
commit 531d8b3352
7 changed files with 74 additions and 49 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.67" version = "0.8.68"
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."

View File

@@ -137,6 +137,7 @@ impl<'a> HCPreOrderIterator<'a> {
fn char_to_string(c: char) -> String { fn char_to_string(c: char) -> String {
match c { match c {
'\'' => "\\'".to_string(),
'\n' => "\\n".to_string(), '\n' => "\\n".to_string(),
'\r' => "\\r".to_string(), '\r' => "\\r".to_string(),
'\t' => "\\t".to_string(), '\t' => "\\t".to_string(),

View File

@@ -320,6 +320,26 @@ 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) type CallResult = Result<(), Vec<HeapCellValue>>;
pub(crate) trait CallPolicy: Any { pub(crate) trait CallPolicy: Any {
@@ -635,15 +655,11 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::PartialString => { &BuiltInClauseType::PartialString => {
let a1 = machine_st[temp_v!(1)].clone(); let mut s = machine_st.try_string_list(temp_v!(1))?;
let a2 = machine_st[temp_v!(2)].clone(); let a2 = machine_st[temp_v!(2)].clone();
if let Addr::Con(Constant::String(s)) = a1 { s.set_expandable(true);
s.set_expandable(true); machine_st.write_constant_to_var(a2, Constant::String(s));
machine_st.write_constant_to_var(a2, Constant::String(s));
} else {
machine_st.fail = true;
}
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
}, },

View File

@@ -2165,6 +2165,29 @@ impl MachineState {
*list = result; *list = result;
} }
pub(super)
fn try_string_list(&self, r: RegType) -> Result<StringList, MachineStub> {
let a1 = self[r].clone();
let a1 = self.store(self.deref(a1));
if let Addr::Con(Constant::String(s)) = a1 {
return Ok(s);
} else {
let stub = MachineError::functor_stub(clause_name!("partial_string"), 2);
match self.try_from_list(r, stub.clone()) {
Ok(addrs) =>
Ok(StringList::new(match try_char_list(addrs) {
Ok(string) => string,
Err(err) => {
return Err(self.error_form(err, stub));
}
}, false)),
Err(err) => return Err(err)
}
}
}
pub(super) pub(super)
fn try_from_list(&self, r: RegType, caller: MachineStub) -> Result<Vec<Addr>, MachineStub> fn try_from_list(&self, r: RegType, caller: MachineStub) -> Result<Vec<Addr>, MachineStub>
{ {

View File

@@ -9,7 +9,7 @@ use prolog::machine::copier::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use prolog::machine::machine_state::*; use prolog::machine::machine_state::*;
use prolog::machine::toplevel::to_op_decl; use prolog::machine::toplevel::{to_op_decl};
use prolog::num::{FromPrimitive, ToPrimitive, Zero}; use prolog::num::{FromPrimitive, ToPrimitive, Zero};
use prolog::num::bigint::{BigInt}; use prolog::num::bigint::{BigInt};
use prolog::read::{PrologStream, readline}; use prolog::read::{PrologStream, readline};
@@ -35,7 +35,7 @@ impl BrentAlgState {
} }
} }
impl MachineState { impl MachineState {
// a step in Brent's algorithm. // a step in Brent's algorithm.
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult> fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
{ {
@@ -393,28 +393,15 @@ impl MachineState {
match self.try_from_list(temp_v!(2), stub.clone()) { match self.try_from_list(temp_v!(2), stub.clone()) {
Err(e) => return Err(e), Err(e) => return Err(e),
Ok(addrs) => { Ok(addrs) =>
let mut chars = String::new(); match try_char_list(addrs) {
Ok(string) => {
for addr in addrs.iter() { let chars = clause_name!(string, indices.atom_tbl);
match addr { self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None)));
&Addr::Con(Constant::Char(c)) => },
chars.push(c), Err(err) =>
&Addr::Con(Constant::Atom(ref name, _)) return Err(self.error_form(err, stub))
if name.as_str().len() == 1 => { }
chars += name.as_str();
},
_ => {
let err = MachineError::type_error(ValidType::Character,
addr.clone());
return Err(self.error_form(err, stub));
}
}
}
let chars = clause_name!(chars, indices.atom_tbl);
self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None)));
}
} }
}, },
_ => unreachable!() _ => unreachable!()

View File

@@ -390,13 +390,15 @@ pub enum TopLevelPacket {
} }
struct RelationWorker { struct RelationWorker {
flags: MachineFlags,
dynamic_clauses: Vec<(Term, Term)>, // Head, Body. dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
queue: VecDeque<VecDeque<Term>>, queue: VecDeque<VecDeque<Term>>,
} }
impl RelationWorker { impl RelationWorker {
fn new() -> Self { fn new(flags: MachineFlags) -> Self {
RelationWorker { dynamic_clauses: vec![], RelationWorker { dynamic_clauses: vec![],
flags,
queue: VecDeque::new() } queue: VecDeque::new() }
} }
@@ -538,14 +540,8 @@ impl RelationWorker {
Err(ParserError::InadmissibleQueryTerm) Err(ParserError::InadmissibleQueryTerm)
}, },
("partial_string", 2) => { ("partial_string", 2) => {
if let Term::Constant(_, Constant::String(_)) = *terms[0].clone() { let ct = ClauseType::BuiltIn(BuiltInClauseType::PartialString);
if let Term::Var(..) = *terms[1].clone() { return Ok(QueryTerm::Clause(Cell::default(), ct, terms, false));
let ct = ClauseType::BuiltIn(BuiltInClauseType::PartialString);
return Ok(QueryTerm::Clause(Cell::default(), ct, terms, false));
}
}
Err(ParserError::InadmissibleQueryTerm)
}, },
_ => { _ => {
let ct = indices.get_clause_type(name, terms.len(), fixity); let ct = indices.get_clause_type(name, terms.len(), fixity);
@@ -768,11 +764,11 @@ impl RelationWorker {
} }
} }
fn term_to_toplevel<R>(term_stream: &mut TermStream<R>, code_dir: &mut CodeDir, term: Term) fn term_to_toplevel<R>(term_stream: &mut TermStream<R>, code_dir: &mut CodeDir, term: Term, flags: MachineFlags)
-> Result<(TopLevel, RelationWorker), ParserError> -> Result<(TopLevel, RelationWorker), ParserError>
where R: Read where R: Read
{ {
let mut rel_worker = RelationWorker::new(); let mut rel_worker = RelationWorker::new(flags);
let mut indices = composite_indices!(false, term_stream.indices, code_dir); let mut indices = composite_indices!(false, term_stream.indices, code_dir);
let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?; let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
@@ -784,6 +780,7 @@ pub
fn stream_to_toplevel<R: Read>(mut buffer: ParsingStream<R>, wam: &mut Machine) fn stream_to_toplevel<R: Read>(mut buffer: ParsingStream<R>, wam: &mut Machine)
-> Result<TopLevelPacket, SessionError> -> Result<TopLevelPacket, SessionError>
{ {
let flags = wam.machine_flags();
let mut term_stream = TermStream::new(&mut buffer, wam.indices.atom_tbl(), let mut term_stream = TermStream::new(&mut buffer, wam.indices.atom_tbl(),
wam.machine_flags(), &mut wam.indices, wam.machine_flags(), &mut wam.indices,
&mut wam.policies, &mut wam.code_repo); &mut wam.policies, &mut wam.code_repo);
@@ -791,9 +788,9 @@ fn stream_to_toplevel<R: Read>(mut buffer: ParsingStream<R>, wam: &mut Machine)
term_stream.add_to_top("?- "); term_stream.add_to_top("?- ");
let term = term_stream.read_term(&OpDir::new())?; let term = term_stream.read_term(&OpDir::new())?;
let mut code_dir = CodeDir::new(); let mut code_dir = CodeDir::new();
let (tl, mut rel_worker) = term_to_toplevel(&mut term_stream, &mut code_dir, term)?; let (tl, mut rel_worker) = term_to_toplevel(&mut term_stream, &mut code_dir, term, flags)?;
rel_worker.expand_queue_contents(&mut term_stream, &OpDir::new())?; rel_worker.expand_queue_contents(&mut term_stream, &OpDir::new())?;
let mut indices = composite_indices!(false, term_stream.indices, &mut code_dir); let mut indices = composite_indices!(false, term_stream.indices, &mut code_dir);
@@ -823,7 +820,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
indices, policies, code_repo); indices, policies, code_repo);
TopLevelBatchWorker { term_stream, TopLevelBatchWorker { term_stream,
rel_worker: RelationWorker::new(), rel_worker: RelationWorker::new(flags),
results: vec![], results: vec![],
dynamic_clause_map: HashMap::new(), dynamic_clause_map: HashMap::new(),
in_module: false } in_module: false }
@@ -832,7 +829,7 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
fn try_term_to_tl(&self, indices: &mut IndexStore, term: Term) fn try_term_to_tl(&self, indices: &mut IndexStore, term: Term)
-> Result<(TopLevel, RelationWorker), SessionError> -> Result<(TopLevel, RelationWorker), SessionError>
{ {
let mut new_rel_worker = RelationWorker::new(); let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags);
let mut indices = composite_indices!(self.in_module, indices, let mut indices = composite_indices!(self.in_module, indices,
&self.term_stream.indices.code_dir); &self.term_stream.indices.code_dir);
@@ -877,7 +874,8 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
} }
} }
pub fn consume(&mut self, indices: &mut IndexStore) -> Result<Option<Declaration>, SessionError> pub fn consume(&mut self, indices: &mut IndexStore)
-> Result<Option<Declaration>, SessionError>
{ {
let mut preds = vec![]; let mut preds = vec![];

View File

@@ -2391,7 +2391,7 @@ fn test_queries_on_string_lists()
assert_prolog_success!(&mut wam, "partial_string(\"appendy\", X), f(X).", assert_prolog_success!(&mut wam, "partial_string(\"appendy\", X), f(X).",
[["X = [a, p, p, e, n, d, y, ' ', j, o, n, e, s]"], [["X = [a, p, p, e, n, d, y, ' ', j, o, n, e, s]"],
["X = [a, p, p, e, n, d, y, ' ', s, m, i, t, h, e, r, s, ' ', j, o, n, e, s]"], ["X = [a, p, p, e, n, d, y, ' ', s, m, i, t, h, e, r, s, ' ', j, o, n, e, s]"],
["X = [a, p, p, e, n, d, y, ' ', o, ''', t, o, o, l, e]"]]); ["X = [a, p, p, e, n, d, y, ' ', o, '\\'', t, o, o, l, e]"]]);
assert_prolog_success!(&mut wam, "partial_string(\"abc\", X), partial_string(\"abcdef\", X).", assert_prolog_success!(&mut wam, "partial_string(\"abc\", X), partial_string(\"abcdef\", X).",
[["X = [a, b, c, d, e, f | _]"]]); [["X = [a, b, c, d, e, f | _]"]]);