read from streams.

This commit is contained in:
Mark Thom
2019-04-13 18:40:17 -06:00
parent ed17867be0
commit ae90554378
25 changed files with 1657 additions and 1318 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.51" version = "0.8.52"
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,8 +14,8 @@ 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.18" prolog_parser = { version = "0.8.19", path = "../prolog_parser" }
readline_rs_compat = { version = "0.1.7", optional = true } readline_rs_compat = { version = "0.1.8", path = "../readline.rs", optional = true }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
[dependencies.termion] [dependencies.termion]

View File

@@ -14,59 +14,16 @@ extern crate termion;
mod prolog; mod prolog;
use prolog::machine::*; use prolog::machine::*;
use prolog::machine::compile::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::machine::toplevel::string_to_toplevel;
use prolog::read::*; use prolog::read::*;
use prolog::write::*;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
fn prolog_repl() {
let mut wam = Machine::new();
loop {
#[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Single);
match toplevel_read_line() {
Ok(Input::TermString(buffer)) => {
let result = match string_to_toplevel(buffer.as_bytes(), &mut wam) {
Ok(packet) => compile_term(&mut wam, packet),
Err(e) => EvalSession::from(e)
};
print(&mut wam, result)
},
Ok(Input::Batch) => {
#[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Multi);
let src = match readline::read_batch("") {
Ok(src) => src,
Err(e) => {
println!("{}", e);
continue;
}
};
let result = compile_user_module(&mut wam, &src[0 ..]);
print(&mut wam, result);
},
Ok(Input::Clear) => {
wam.clear();
continue;
},
Err(e) => print(&mut wam, EvalSession::from(e))
};
wam.reset();
}
}
fn main() { fn main() {
#[cfg(feature = "readline_rs_compat")] #[cfg(feature = "readline_rs_compat")]
readline::readline_initialize(); readline::readline_initialize();
prolog_repl();
let mut wam = Machine::new(readline::input_stream());
wam.run_toplevel();
} }

View File

@@ -201,6 +201,8 @@ pub enum SystemClauseType {
ModuleRetractClause, ModuleRetractClause,
NoSuchPredicate, NoSuchPredicate,
OpDeclaration, OpDeclaration,
REPL(REPLCodePtr),
ReadTerm,
RedoAttrVarBindings, RedoAttrVarBindings,
RemoveCallPolicyCheck, RemoveCallPolicyCheck,
RemoveInferenceCounter, RemoveInferenceCounter,
@@ -246,6 +248,9 @@ 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::CheckCutPoint => clause_name!("$check_cp"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) =>
clause_name!("$submit_query_and_print_results"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"), &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -296,6 +301,7 @@ impl SystemClauseType {
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"), &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"), &SystemClauseType::RetractClause => clause_name!("$retract_clause"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"),
@@ -326,6 +332,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),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
@@ -375,6 +382,7 @@ impl SystemClauseType {
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock), ("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint), ("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
("$retract_clause", 4) => Some(SystemClauseType::RetractClause), ("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
@@ -385,6 +393,8 @@ impl SystemClauseType {
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes), ("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList), ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar), ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
("$submit_query_and_print_results", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults)),
("$term_variables", 2) => Some(SystemClauseType::TermVariables), ("$term_variables", 2) => Some(SystemClauseType::TermVariables),
("$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),

View File

@@ -398,6 +398,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
printer printer
} }
pub fn drop_toplevel_spec(&mut self) {
self.toplevel_spec = None;
}
#[inline] #[inline]
pub fn see_all_locs(&mut self) { pub fn see_all_locs(&mut self) {
for key in self.heap_locs.keys().cloned() { for key in self.heap_locs.keys().cloned() {

View File

@@ -12,7 +12,7 @@
char_code/2, clause/2, current_predicate/1, current_op/3, char_code/2, clause/2, current_predicate/1, current_op/3,
current_prolog_flag/2, expand_goal/2, expand_term/2, current_prolog_flag/2, expand_goal/2, expand_term/2,
findall/3, findall/4, get_char/1, halt/0, once/1, op/3, findall/3, findall/4, get_char/1, halt/0, once/1, op/3,
repeat/0, retract/1, set_prolog_flag/2, setof/3, read_term/2, repeat/0, retract/1, set_prolog_flag/2, setof/3,
setup_call_cleanup/3, term_variables/2, throw/1, true/0, setup_call_cleanup/3, term_variables/2, throw/1, true/0,
false/0, write/1, write_canonical/1, writeq/1, write_term/2]). false/0, write/1, write_canonical/1, writeq/1, write_term/2]).
@@ -231,10 +231,23 @@ inst_member_or([X|Xs], Y, _) :-
; throw(instantiation_error) ). % 8.14.2.3 b) ; throw(instantiation_error) ). % 8.14.2.3 b)
inst_member_or([], Y, Y). inst_member_or([], Y, Y).
%% TODO: complete the predicate! Most read options are missing.
read_term(Term, Options) :-
'$skip_max_list'(_, -1, Options, Options0),
( Options0 == [] -> true
; var(Options0) -> throw(error(instantiation_error, read_term/2)) % 8.14.1.3 b)
; throw(error(type_error(list, Options), read_term/2)) % 8.14.1.3 d)
),
( Options = [variable_names(VarList)] -> '$read_term'(Term, VarList)
; Options = [] -> read(Term)
; false
).
write_term(Term, Options) :- write_term(Term, Options) :-
'$skip_max_list'(_, -1, Options, Options0), '$skip_max_list'(_, -1, Options, Options0),
( Options0 == [] -> true ( Options0 == [] -> true
; throw(error(type_error(list, Options), write_term/2)) ), % 8.14.2.3 c) ; throw(error(type_error(list, Options), write_term/2))
), % 8.14.2.3 c)
inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)), inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
inst_member_or(Options, numbervars(NumberVars), numbervars(false)), inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
inst_member_or(Options, quoted(Quoted), quoted(false)), inst_member_or(Options, quoted(Quoted), quoted(false)),

View File

@@ -1,16 +1,13 @@
:- module(dif, [dif/2]). :- module(dif, [dif/2]).
:- use_module(library(atts)). :- use_module(library(atts)).
:- use_module(library(ordsets)).
:- attribute dif/1. :- attribute dif/1.
put_dif_att(Var, X, Y) :- put_dif_att(Var, X, Y) :-
( get_atts(Var, +dif(Z)) -> ( get_atts(Var, +dif(Z)) ->
ord_add_element(Z, X \== Y, NewZ), sort([X \== Y | Z], NewZ),
( Z == NewZ -> true put_atts(Var, +dif(NewZ))
; put_atts(Var, +dif(NewZ))
)
; put_atts(Var, +dif([X \== Y])) ; put_atts(Var, +dif([X \== Y]))
). ).

View File

@@ -1,5 +1,6 @@
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::vec::Vec; use std::vec::Vec;
@@ -8,7 +9,7 @@ pub struct Frame {
pub global_index: usize, pub global_index: usize,
pub e: usize, pub e: usize,
pub cp: LocalCodePtr, pub cp: LocalCodePtr,
pub special_form_cp: LocalCodePtr, pub interrupt_cp: LocalCodePtr,
perms: Vec<Addr> perms: Vec<Addr>
} }
@@ -18,7 +19,7 @@ impl Frame {
global_index, global_index,
e: e, e: e,
cp: cp, cp: cp,
special_form_cp: LocalCodePtr::default(), interrupt_cp: LocalCodePtr::default(),
perms: (1 .. n+1).map(|i| Addr::StackCell(fr, i)).collect() perms: (1 .. n+1).map(|i| Addr::StackCell(fr, i)).collect()
} }
} }
@@ -36,6 +37,11 @@ impl AndStack {
AndStack(Vec::new()) AndStack(Vec::new())
} }
#[inline]
pub(crate) fn take(&mut self) -> Self {
AndStack(mem::replace(&mut self.0, vec![]))
}
pub fn push(&mut self, global_index: usize, e: usize, cp: LocalCodePtr, n: usize) { pub fn push(&mut self, global_index: usize, e: usize, cp: LocalCodePtr, n: usize) {
let len = self.0.len(); let len = self.0.len();
self.0.push(Frame::new(global_index, len, e, cp, n)); self.0.push(Frame::new(global_index, len, e, cp, n));

View File

@@ -57,14 +57,6 @@ impl MachineState {
(var_list_addr, value_list_addr) (var_list_addr, value_list_addr)
} }
pub(super)
fn calculate_register_threshold(&self) -> usize {
/* for all we know, all registers might be valid when we
* return from the verify_attributes interrupt. we currently
* lack a more precise way of determining this. */
MAX_ARITY
}
fn verify_attributes(&mut self) fn verify_attributes(&mut self)
{ {
for (h, _) in &self.attr_var_init.bindings { for (h, _) in &self.attr_var_init.bindings {
@@ -122,17 +114,17 @@ impl MachineState {
pub(super) pub(super)
fn verify_attr_interrupt(&mut self, p: usize) { fn verify_attr_interrupt(&mut self, p: usize) {
let rs = self.calculate_register_threshold(); let rs = MAX_ARITY;
// store temp vars in perm vars slots along with // store temp vars in perm vars slots along with self.b0 and
// self.b0 and self.num_of_args. why self.bo? if we return to a // self.num_of_args. why self.b0? if we return to a NeckCut
// NeckCut after finishing the interrupt, it won't // after finishing the interrupt, it won't work correctly if
// work correctly if self.b == self.b0. we must // self.b == self.b0. we must change it back when we return,
// change it back when we return, as if nothing happened. // as if nothing happened.
self.allocate(rs + 2); self.allocate(rs + 2);
let e = self.e; let e = self.e;
self.and_stack[e].special_form_cp = self.attr_var_init.cp; self.and_stack[e].interrupt_cp = self.attr_var_init.cp;
for i in 1 .. rs + 1 { for i in 1 .. rs + 1 {
self.and_stack[e][i] = self[RegType::Temp(i)].clone(); self.and_stack[e][i] = self[RegType::Temp(i)].clone();
@@ -193,7 +185,8 @@ impl Machine {
self.machine_st[temp_v!(2)] = attr_vars; self.machine_st[temp_v!(2)] = attr_vars;
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo); self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo,
&mut readline::input_stream());
self.machine_st.print_attribute_goals_string(var_dict) self.machine_st.print_attribute_goals_string(var_dict)
} }

View File

@@ -105,6 +105,8 @@ impl CodeRepo {
Some(RefOrOwned::Borrowed(&self.in_situ_code[p])), Some(RefOrOwned::Borrowed(&self.in_situ_code[p])),
&CodePtr::Local(LocalCodePtr::DirEntry(p)) => &CodePtr::Local(LocalCodePtr::DirEntry(p)) =>
Some(RefOrOwned::Borrowed(&self.code[p])), Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::REPL(..) =>
None,
&CodePtr::BuiltInClause(ref built_in, _) => { &CodePtr::BuiltInClause(ref built_in, _) => {
let call_clause = call_clause!(ClauseType::BuiltIn(built_in.clone()), let call_clause = call_clause!(ClauseType::BuiltIn(built_in.clone()),
built_in.arity(), built_in.arity(),

View File

@@ -123,6 +123,7 @@ fn compile_query(terms: Vec<QueryTerm>, queue: VecDeque<TopLevel>, flags: Machin
let mut code = try!(cg.compile_query(&terms)); let mut code = try!(cg.compile_query(&terms));
compile_appendix(&mut code, &queue, false, flags)?; compile_appendix(&mut code, &queue, false, flags)?;
Ok((code, cg.take_vars())) Ok((code, cg.take_vars()))
} }
@@ -214,7 +215,8 @@ fn setup_module_expansions(wam: &mut Machine, module_name: ClauseName)
} }
pub(super) pub(super)
fn compile_into_module<R: Read>(wam: &mut Machine, module_name: ClauseName, src: R, name: ClauseName) fn compile_into_module<R: Read>(wam: &mut Machine, module_name: ClauseName,
src: ParsingStream<R>, name: ClauseName)
-> EvalSession -> EvalSession
{ {
let mut indices = default_index_store!(wam.atom_tbl_of(&name)); let mut indices = default_index_store!(wam.atom_tbl_of(&name));
@@ -232,7 +234,8 @@ fn compile_into_module<R: Read>(wam: &mut Machine, module_name: ClauseName, src:
} }
fn compile_into_module_impl<R: Read>(wam: &mut Machine, compiler: &mut ListingCompiler, fn compile_into_module_impl<R: Read>(wam: &mut Machine, compiler: &mut ListingCompiler,
module_name: ClauseName, src: R, mut indices: IndexStore) module_name: ClauseName, src: ParsingStream<R>,
mut indices: IndexStore)
-> Result<(), SessionError> -> Result<(), SessionError>
{ {
setup_module_expansions(wam, module_name.clone()); setup_module_expansions(wam, module_name.clone());
@@ -597,12 +600,13 @@ impl ListingCompiler {
} }
pub(crate) pub(crate)
fn gather_items<R: Read>(&mut self, wam: &mut Machine, src: R, indices: &mut IndexStore) fn gather_items<R: Read>(&mut self, wam: &mut Machine, mut src: ParsingStream<R>,
indices: &mut IndexStore)
-> Result<GatherResult, SessionError> -> Result<GatherResult, SessionError>
{ {
let flags = wam.machine_flags(); let flags = wam.machine_flags();
let atom_tbl = indices.atom_tbl.clone(); let atom_tbl = indices.atom_tbl.clone();
let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, let mut worker = TopLevelBatchWorker::new(&mut src, atom_tbl.clone(), flags,
&mut wam.indices, &mut wam.policies, &mut wam.indices, &mut wam.policies,
&mut wam.code_repo); &mut wam.code_repo);
@@ -649,8 +653,8 @@ impl ListingCompiler {
} }
} }
fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src: R, fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine,
mut indices: IndexStore) src: ParsingStream<R>, mut indices: IndexStore)
-> EvalSession -> EvalSession
{ {
let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices)); let mut results = try_eval_session!(compiler.gather_items(wam, src, &mut indices));
@@ -693,7 +697,8 @@ fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src:
/* This is a truncated version of compile_user_module, used for /* This is a truncated version of compile_user_module, used for
compiling code composing special forms, ie. the code that calls compiling code composing special forms, ie. the code that calls
M:verify_attributes on attributed variables. */ M:verify_attributes on attributed variables. */
pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code, SessionError> pub fn compile_special_form<R: Read>(wam: &mut Machine, src: ParsingStream<R>)
-> Result<Code, SessionError>
{ {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, clause_name!("builtins"), &mut indices)?; setup_indices(wam, clause_name!("builtins"), &mut indices)?;
@@ -705,7 +710,9 @@ pub fn compile_special_form<R: Read>(wam: &mut Machine, src: R) -> Result<Code,
} }
#[inline] #[inline]
pub fn compile_listing<R: Read>(wam: &mut Machine, src: R, indices: IndexStore) -> EvalSession pub
fn compile_listing<R: Read>(wam: &mut Machine, src: ParsingStream<R>, indices: IndexStore)
-> EvalSession
{ {
let mut compiler = ListingCompiler::new(&wam.code_repo); let mut compiler = ListingCompiler::new(&wam.code_repo);
@@ -733,7 +740,7 @@ fn setup_indices(wam: &mut Machine, module: ClauseName, indices: &mut IndexStore
} }
} }
pub fn compile_user_module<R: Read>(wam: &mut Machine, src: R) -> EvalSession { pub fn compile_user_module<R: Read>(wam: &mut Machine, src: ParsingStream<R>) -> EvalSession {
let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices)); try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
compile_listing(wam, src, indices) compile_listing(wam, src, indices)

View File

@@ -17,7 +17,8 @@ impl Machine {
} }
} }
fn compile_into_machine<R: Read>(&mut self, src: R, name: ClauseName, arity: usize) -> EvalSession fn compile_into_machine<R: Read>(&mut self, src: ParsingStream<R>, name: ClauseName, arity: usize)
-> EvalSession
{ {
match name.owning_module().as_str() { match name.owning_module().as_str() {
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() { "user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
@@ -118,7 +119,7 @@ impl Machine {
{ {
let machine_st = mem::replace(&mut self.machine_st, MachineState::new()); let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
let result = self.compile_into_machine(pred_str.as_bytes(), name, arity); let result = self.compile_into_machine(parsing_stream(pred_str.as_bytes()), name, arity);
self.machine_st = machine_st; self.machine_st = machine_st;
if let EvalSession::Error(err) = result { if let EvalSession::Error(err) = result {

View File

@@ -2,6 +2,7 @@ use prolog_parser::ast::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
pub struct Heap { pub struct Heap {
@@ -21,6 +22,17 @@ impl Heap {
self.h += 1; self.h += 1;
} }
#[inline]
pub(crate) fn take(&mut self) -> Self {
let h = self.h;
self.h = 0;
Heap {
heap: mem::replace(&mut self.heap, vec![]),
h
}
}
#[inline] #[inline]
pub fn truncate(&mut self, h: usize) { pub fn truncate(&mut self, h: usize) {
self.h = h; self.h = h;

View File

@@ -385,8 +385,6 @@ pub enum SessionError {
NamelessEntry, NamelessEntry,
OpIsInfixAndPostFix(ClauseName), OpIsInfixAndPostFix(ClauseName),
ParserError(ParserError), ParserError(ParserError),
QueryFailure,
QueryFailureWithException(ClauseName),
UserPrompt UserPrompt
} }
@@ -394,6 +392,7 @@ pub enum EvalSession {
EntrySuccess, EntrySuccess,
Error(SessionError), Error(SessionError),
InitialQuerySuccess(AllocVarDict, HeapVarDict), InitialQuerySuccess(AllocVarDict, HeapVarDict),
QueryFailure,
SubsequentQuerySuccess, SubsequentQuerySuccess,
} }

View File

@@ -124,6 +124,24 @@ impl Add<usize> for Addr {
} }
} }
impl Sub<i64> for Addr {
type Output = Addr;
fn sub(self, rhs: i64) -> Self::Output {
if rhs < 0 {
match self {
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
_ => self
}
} else {
self.sub(rhs as usize)
}
}
}
impl Sub<usize> for Addr { impl Sub<usize> for Addr {
type Output = Addr; type Output = Addr;
@@ -260,12 +278,19 @@ pub enum DynamicTransactionType {
Retract // dynamic index of the clause to remove. Retract // dynamic index of the clause to remove.
} }
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum REPLCodePtr {
CompileBatch,
SubmitQueryAndPrintResults
}
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum CodePtr { pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr), // arity, local. CallN(usize, LocalCodePtr), // arity, local.
Local(LocalCodePtr), Local(LocalCodePtr),
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
} }
@@ -276,7 +301,8 @@ impl CodePtr {
| &CodePtr::CallN(_, ref local) | &CodePtr::CallN(_, ref local)
| &CodePtr::Local(ref local) => local.clone(), | &CodePtr::Local(ref local) => local.clone(),
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
&CodePtr::DynamicTransaction(_, p) => p &CodePtr::REPL(_, p)
| &CodePtr::DynamicTransaction(_, p) => p
} }
} }
} }
@@ -367,7 +393,8 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
p @ CodePtr::VerifyAttrInterrupt(_) p @ CodePtr::REPL(..)
| p @ CodePtr::VerifyAttrInterrupt(_)
| p @ CodePtr::DynamicTransaction(..) => p, | p @ CodePtr::DynamicTransaction(..) => p,
CodePtr::Local(local) => CodePtr::Local(local + rhs), CodePtr::Local(local) => CodePtr::Local(local + rhs),
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs) CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs)
@@ -475,6 +502,7 @@ impl IndexStore {
in_situ_code_dir: InSituCodeDir::new(), in_situ_code_dir: InSituCodeDir::new(),
op_dir: default_op_dir(), op_dir: default_op_dir(),
modules: ModuleDir::new(), modules: ModuleDir::new(),
// parsing_stream: readline::parsing_stream(String::new())
} }
} }

View File

@@ -12,12 +12,13 @@ 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, Zero, One};
use prolog::read::{PrologStream, readline};
use downcast::Any; use downcast::Any;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::io::{Write, stdin, stdout}; use std::io::{Write, stdout};
use std::mem::swap; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::rc::Rc; use std::rc::Rc;
@@ -35,6 +36,16 @@ impl Ball {
self.boundary = 0; self.boundary = 0;
self.stub.clear(); self.stub.clear();
} }
pub(super) fn take(&mut self) -> Ball {
let boundary = self.boundary;
self.boundary = 0;
Ball {
boundary,
stub: mem::replace(&mut self.stub, vec![])
}
}
} }
pub(super) struct CopyTerm<'a> { pub(super) struct CopyTerm<'a> {
@@ -518,7 +529,7 @@ pub(crate) trait CallPolicy: Any {
} }
fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
indices: &mut IndexStore) indices: &mut IndexStore, parsing_stream: &mut PrologStream)
-> CallResult -> CallResult
{ {
match ct { match ct {
@@ -572,10 +583,12 @@ pub(crate) trait CallPolicy: Any {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
}, },
&BuiltInClauseType::Read => { &BuiltInClauseType::Read => {
match machine_st.read(stdin(), indices.atom_tbl.clone(), &indices.op_dir) { readline::toggle_prompt(false);
match machine_st.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) {
Ok(offset) => { Ok(offset) => {
let addr = machine_st[temp_v!(1)].clone(); let addr = machine_st[temp_v!(1)].clone();
machine_st.unify(addr, Addr::HeapCell(offset)); machine_st.unify(addr, Addr::HeapCell(offset.heap_loc));
}, },
Err(e) => { Err(e) => {
let h = machine_st.heap.h; let h = machine_st.heap.h;
@@ -695,7 +708,8 @@ pub(crate) trait CallPolicy: Any {
Ok(()) Ok(())
} }
fn call_n(&mut self, machine_st: &mut MachineState, arity: usize, indices: &mut IndexStore) fn call_n(&mut self, machine_st: &mut MachineState, arity: usize, indices: &mut IndexStore,
parsing_stream: &mut PrologStream)
-> CallResult -> CallResult
{ {
if let Some((name, arity)) = machine_st.setup_call_n(arity) { if let Some((name, arity)) = machine_st.setup_call_n(arity) {
@@ -711,7 +725,7 @@ pub(crate) trait CallPolicy: Any {
}, },
ClauseType::BuiltIn(built_in) => { ClauseType::BuiltIn(built_in) => {
machine_st.setup_built_in_call(built_in.clone()); machine_st.setup_built_in_call(built_in.clone());
self.call_builtin(machine_st, &built_in, indices)?; self.call_builtin(machine_st, &built_in, indices, parsing_stream)?;
}, },
ClauseType::Inlined(inlined) => { ClauseType::Inlined(inlined) => {
machine_st.execute_inlined(&inlined); machine_st.execute_inlined(&inlined);
@@ -781,17 +795,18 @@ impl CallPolicy for CWILCallPolicy {
} }
fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
indices: &mut IndexStore) indices: &mut IndexStore, parsing_stream: &mut PrologStream)
-> CallResult -> CallResult
{ {
self.prev_policy.call_builtin(machine_st, ct, indices)?; self.prev_policy.call_builtin(machine_st, ct, indices, parsing_stream)?;
self.increment(machine_st) self.increment(machine_st)
} }
fn call_n(&mut self, machine_st: &mut MachineState, arity: usize, indices: &mut IndexStore) fn call_n(&mut self, machine_st: &mut MachineState, arity: usize, indices: &mut IndexStore,
parsing_stream: &mut PrologStream)
-> CallResult -> CallResult
{ {
self.prev_policy.call_n(machine_st, arity, indices)?; self.prev_policy.call_n(machine_st, arity, indices, parsing_stream)?;
self.increment(machine_st) self.increment(machine_st)
} }
} }
@@ -813,7 +828,7 @@ impl CWILCallPolicy {
pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>) pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>)
{ {
let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {}); let mut prev_policy: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
swap(&mut prev_policy, policy); mem::swap(&mut prev_policy, policy);
let new_policy = CWILCallPolicy { prev_policy, let new_policy = CWILCallPolicy { prev_policy,
count: BigUint::zero(), count: BigUint::zero(),
@@ -870,7 +885,7 @@ impl CWILCallPolicy {
pub(crate) fn into_inner(&mut self) -> Box<CallPolicy> { pub(crate) fn into_inner(&mut self) -> Box<CallPolicy> {
let mut new_inner: Box<CallPolicy> = Box::new(DefaultCallPolicy {}); let mut new_inner: Box<CallPolicy> = Box::new(DefaultCallPolicy {});
swap(&mut self.prev_policy, &mut new_inner); mem::swap(&mut self.prev_policy, &mut new_inner);
new_inner new_inner
} }
} }

View File

@@ -17,9 +17,11 @@ use prolog::machine::machine_state::*;
use prolog::num::{Integer, Signed, ToPrimitive, One, Zero}; use prolog::num::{Integer, Signed, ToPrimitive, One, Zero};
use prolog::num::bigint::{BigInt, BigUint}; use prolog::num::bigint::{BigInt, BigUint};
use prolog::num::rational::Ratio; use prolog::num::rational::Ratio;
use prolog::read::PrologStream;
use std::cmp::{max, Ordering}; use std::cmp::{max, Ordering};
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::mem;
use std::rc::Rc; use std::rc::Rc;
macro_rules! try_or_fail { macro_rules! try_or_fail {
@@ -65,6 +67,36 @@ impl MachineState {
} }
} }
pub(crate) fn with_capacity(capacity: usize) -> Self {
MachineState {
s: 0,
p: CodePtr::default(),
b: 0,
b0: 0,
e: 0,
num_of_args: 0,
cp: LocalCodePtr::default(),
attr_var_init: AttrVarInitializer::new(0, 0),
fail: false,
heap: Heap::with_capacity(capacity),
mode: MachineMode::Write,
and_stack: AndStack::new(),
or_stack: OrStack::new(),
registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used.
trail: vec![],
pstr_trail: vec![],
pstr_tr: 0,
tr: 0,
hb: 0,
block: 0,
ball: Ball::new(),
lifted_heap: Vec::with_capacity(capacity),
interms: vec![Number::default(); 0],
last_call: false,
flags: MachineFlags::default()
}
}
#[allow(dead_code)] #[allow(dead_code)]
pub fn print_heap(&self) { pub fn print_heap(&self) {
for h in 0 .. self.heap.h { for h in 0 .. self.heap.h {
@@ -182,19 +214,6 @@ impl MachineState {
output output
} }
pub(super)
fn print_exception<Outputter>(&self, addr: Addr, var_dict: &HeapVarDict, output: Outputter)
-> Outputter
where Outputter: HCValueOutputter
{
let mut printer = HCPrinter::from_heap_locs(&self, output, var_dict);
printer.see_all_locs();
printer.quoted = true;
printer.print(addr)
}
pub(super) pub(super)
fn unify_strings(&mut self, pdl: &mut Vec<Addr>, s1: &mut StringList, s2: &mut StringList) -> bool fn unify_strings(&mut self, pdl: &mut Vec<Addr>, s1: &mut StringList, s2: &mut StringList) -> bool
{ {
@@ -1546,27 +1565,24 @@ impl MachineState {
self.fail = true; self.fail = true;
} }
fn heap_ball_boundary_diff(&self) -> usize { fn heap_ball_boundary_diff(&self) -> i64 {
if self.ball.boundary > self.heap.h { self.ball.boundary as i64 - self.heap.h as i64
self.ball.boundary - self.heap.h
} else {
self.heap.h - self.ball.boundary
}
} }
pub(super) fn copy_and_align_ball_to_heap(&mut self, from: usize) -> usize { pub(super) fn copy_and_align_ball(&self) -> MachineStub {
let diff = self.heap_ball_boundary_diff(); let diff = self.heap_ball_boundary_diff();
let mut stub = vec![];
for index in from .. self.ball.stub.len() { for index in 0 .. self.ball.stub.len() {
let heap_value = self.ball.stub[index].clone(); let heap_value = self.ball.stub[index].clone();
self.heap.push(match heap_value { stub.push(match heap_value {
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff), HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
_ => heap_value _ => heap_value
}); });
} }
diff stub
} }
pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool { pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool {
@@ -2363,6 +2379,7 @@ impl MachineState {
fn handle_call_clause(&mut self, indices: &mut IndexStore, fn handle_call_clause(&mut self, indices: &mut IndexStore,
call_policy: &mut Box<CallPolicy>, call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>, cut_policy: &mut Box<CutPolicy>,
parsing_stream: &mut PrologStream,
ct: &ClauseType, ct: &ClauseType,
arity: usize, arity: usize,
lco: bool, lco: bool,
@@ -2379,9 +2396,9 @@ impl MachineState {
match ct { match ct {
&ClauseType::BuiltIn(ref ct) => &ClauseType::BuiltIn(ref ct) =>
try_or_fail!(self, call_policy.call_builtin(self, ct, indices)), try_or_fail!(self, call_policy.call_builtin(self, ct, indices, parsing_stream)),
&ClauseType::CallN => &ClauseType::CallN =>
try_or_fail!(self, call_policy.call_n(self, arity, indices)), try_or_fail!(self, call_policy.call_n(self, arity, indices, parsing_stream)),
&ClauseType::Hook(ref hook) => &ClauseType::Hook(ref hook) =>
try_or_fail!(self, call_policy.compile_hook(self, hook)), try_or_fail!(self, call_policy.compile_hook(self, hook)),
&ClauseType::Inlined(ref ct) => { &ClauseType::Inlined(ref ct) => {
@@ -2395,13 +2412,15 @@ impl MachineState {
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(), try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
indices)), indices)),
&ClauseType::System(ref ct) => &ClauseType::System(ref ct) =>
try_or_fail!(self, self.system_call(ct, indices, call_policy, cut_policy)) try_or_fail!(self, self.system_call(ct, indices, call_policy, cut_policy,
parsing_stream))
}; };
} }
pub(super) fn execute_ctrl_instr(&mut self, indices: &mut IndexStore, pub(super) fn execute_ctrl_instr(&mut self, indices: &mut IndexStore,
call_policy: &mut Box<CallPolicy>, call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>, cut_policy: &mut Box<CutPolicy>,
parsing_stream: &mut PrologStream,
instr: &ControlInstruction) instr: &ControlInstruction)
{ {
match instr { match instr {
@@ -2409,7 +2428,8 @@ impl MachineState {
self.allocate(num_cells), self.allocate(num_cells),
&ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) =>
self.handle_call_clause(indices, call_policy, cut_policy, self.handle_call_clause(indices, call_policy, cut_policy,
ct, arity, lco, use_default_cp), parsing_stream, ct, arity, lco,
use_default_cp),
&ControlInstruction::Deallocate => self.deallocate(), &ControlInstruction::Deallocate => self.deallocate(),
&ControlInstruction::JmpBy(arity, offset, _, lco) => { &ControlInstruction::JmpBy(arity, offset, _, lco) => {
if !lco { if !lco {
@@ -2569,4 +2589,58 @@ impl MachineState {
self.ball.reset(); self.ball.reset();
self.lifted_heap.clear(); self.lifted_heap.clear();
} }
pub(super)
fn sink_to_snapshot(&mut self) -> MachineState {
let mut snapshot = MachineState::with_capacity(0);
snapshot.hb = self.hb;
snapshot.e = self.e;
snapshot.b = self.b;
snapshot.b0 = self.b0;
snapshot.s = self.s;
snapshot.tr = self.tr;
snapshot.pstr_tr = self.pstr_tr;
snapshot.num_of_args = self.num_of_args;
snapshot.fail = self.fail;
snapshot.trail = mem::replace(&mut self.trail, vec![]);
snapshot.pstr_trail = mem::replace(&mut self.pstr_trail, vec![]);
snapshot.heap = self.heap.take();
snapshot.mode = self.mode;
snapshot.and_stack = self.and_stack.take();
snapshot.or_stack = self.or_stack.take();
snapshot.registers = mem::replace(&mut self.registers, vec![]);
snapshot.block = self.block;
snapshot.ball = self.ball.take();
snapshot.lifted_heap = mem::replace(&mut self.lifted_heap, vec![]);
snapshot
}
pub(super)
fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
self.hb = snapshot.hb;
self.e = snapshot.e;
self.b = snapshot.b;
self.b0 = snapshot.b0;
self.s = snapshot.s;
self.tr = snapshot.tr;
self.pstr_tr = snapshot.pstr_tr;
self.num_of_args = snapshot.num_of_args;
self.fail = snapshot.fail;
self.trail = mem::replace(&mut snapshot.trail, vec![]);
self.pstr_trail = mem::replace(&mut snapshot.pstr_trail, vec![]);
self.heap = snapshot.heap.take();
self.mode = snapshot.mode;
self.and_stack = snapshot.and_stack.take();
self.or_stack = snapshot.or_stack.take();
self.registers = mem::replace(&mut snapshot.registers, vec![]);
self.block = snapshot.block;
self.ball = snapshot.ball.take();
self.lifted_heap = mem::replace(&mut snapshot.lifted_heap, vec![]);
}
} }

View File

@@ -6,6 +6,8 @@ use prolog::fixtures::*;
use prolog::forms::*; use prolog::forms::*;
use prolog::heap_print::*; use prolog::heap_print::*;
use prolog::instructions::*; use prolog::instructions::*;
use prolog::read::*;
use prolog::write::{ContinueResult, next_keypress};
pub mod machine_indices; pub mod machine_indices;
pub mod heap; pub mod heap;
@@ -32,12 +34,17 @@ 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::modules::*; use prolog::machine::modules::*;
use prolog::machine::toplevel::stream_to_toplevel;
use prolog::read::PrologStream;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::io::{Read, Write, stdout};
use std::mem; use std::mem;
use std::ops::Index; use std::ops::Index;
use std::rc::Rc; use std::rc::Rc;
use termion::raw::{IntoRawMode};
pub struct MachinePolicies { pub struct MachinePolicies {
call_policy: Box<CallPolicy>, call_policy: Box<CallPolicy>,
cut_policy: Box<CutPolicy>, cut_policy: Box<CutPolicy>,
@@ -57,7 +64,9 @@ pub struct Machine {
pub(super) machine_st: MachineState, pub(super) machine_st: MachineState,
pub(super) policies: MachinePolicies, pub(super) policies: MachinePolicies,
pub(super) indices: IndexStore, pub(super) indices: IndexStore,
pub(super) code_repo: CodeRepo pub(super) code_repo: CodeRepo,
pub(super) toplevel_idx: usize,
pub(super) prolog_stream: ParsingStream<Box<Read>>
} }
impl Index<LocalCodePtr> for CodeRepo { impl Index<LocalCodePtr> for CodeRepo {
@@ -157,9 +166,11 @@ static REIF: &str = include_str!("../lib/reif.pl");
static ASSOC: &str = include_str!("../lib/assoc.pl"); static ASSOC: &str = include_str!("../lib/assoc.pl");
static ORDSETS: &str = include_str!("../lib/ordsets.pl"); static ORDSETS: &str = include_str!("../lib/ordsets.pl");
static TOPLEVEL: &str = include_str!("../toplevel.pl");
impl Machine { impl Machine {
fn compile_special_forms(&mut self) { fn compile_special_forms(&mut self) {
match compile_special_form(self, VERIFY_ATTRS.as_bytes()) { match compile_special_form(self, parsing_stream(VERIFY_ATTRS.as_bytes())) {
Ok(code) => { Ok(code) => {
self.machine_st.attr_var_init.verify_attrs_loc = self.code_repo.code.len(); self.machine_st.attr_var_init.verify_attrs_loc = self.code_repo.code.len();
self.code_repo.code.extend(code.into_iter()); self.code_repo.code.extend(code.into_iter());
@@ -167,7 +178,7 @@ impl Machine {
Err(_) => panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS") Err(_) => panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS")
} }
match compile_special_form(self, PROJECT_ATTRS.as_bytes()) { match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes())) {
Ok(code) => { Ok(code) => {
self.machine_st.attr_var_init.project_attrs_loc = self.code_repo.code.len(); self.machine_st.attr_var_init.project_attrs_loc = self.code_repo.code.len();
self.code_repo.code.extend(code.into_iter()); self.code_repo.code.extend(code.into_iter());
@@ -176,37 +187,57 @@ impl Machine {
} }
} }
fn compile_libraries(&mut self) { fn compile_top_level(&mut self) {
compile_user_module(self, NON_ISO.as_bytes()); self.toplevel_idx = self.code_repo.code.len();
compile_user_module(self, LISTS.as_bytes()); compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()));
compile_user_module(self, QUEUES.as_bytes());
compile_user_module(self, ERROR.as_bytes());
compile_user_module(self, BETWEEN.as_bytes());
compile_user_module(self, TERMS.as_bytes());
compile_user_module(self, DCGS.as_bytes());
compile_user_module(self, ATTS.as_bytes());
compile_user_module(self, ORDSETS.as_bytes());
compile_user_module(self, DIF.as_bytes());
compile_user_module(self, FREEZE.as_bytes());
compile_user_module(self, REIF.as_bytes());
compile_user_module(self, ASSOC.as_bytes());
} }
pub fn new() -> Self { fn compile_libraries(&mut self) {
compile_user_module(self, parsing_stream(NON_ISO.as_bytes()));
compile_user_module(self, parsing_stream(LISTS.as_bytes()));
compile_user_module(self, parsing_stream(QUEUES.as_bytes()));
compile_user_module(self, parsing_stream(ERROR.as_bytes()));
compile_user_module(self, parsing_stream(BETWEEN.as_bytes()));
compile_user_module(self, parsing_stream(TERMS.as_bytes()));
compile_user_module(self, parsing_stream(DCGS.as_bytes()));
compile_user_module(self, parsing_stream(ATTS.as_bytes()));
compile_user_module(self, parsing_stream(ORDSETS.as_bytes()));
compile_user_module(self, parsing_stream(DIF.as_bytes()));
compile_user_module(self, parsing_stream(FREEZE.as_bytes()));
compile_user_module(self, parsing_stream(REIF.as_bytes()));
compile_user_module(self, parsing_stream(ASSOC.as_bytes()));
}
#[cfg(test)]
pub fn reset(&mut self) {
self.prolog_stream = readline::input_stream();
self.policies.cut_policy = Box::new(DefaultCutPolicy {});
self.machine_st.reset();
}
pub fn run_toplevel(&mut self) {
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
self.run_query(&AllocVarDict::new(), &mut HeapVarDict::new());
}
pub fn new(prolog_stream: PrologStream) -> Self {
let mut wam = Machine { let mut wam = Machine {
machine_st: MachineState::new(), machine_st: MachineState::new(),
policies: MachinePolicies::new(), policies: MachinePolicies::new(),
indices: IndexStore::new(), indices: IndexStore::new(),
code_repo: CodeRepo::new() code_repo: CodeRepo::new(),
toplevel_idx: 0,
prolog_stream
}; };
let atom_tbl = wam.indices.atom_tbl.clone(); let atom_tbl = wam.indices.atom_tbl.clone();
compile_listing(&mut wam, BUILTINS.as_bytes(), compile_listing(&mut wam, parsing_stream(BUILTINS.as_bytes()),
default_index_store!(atom_tbl.clone())); default_index_store!(atom_tbl.clone()));
wam.compile_libraries(); wam.compile_libraries();
wam.compile_special_forms(); wam.compile_special_forms();
wam.compile_top_level();
wam wam
} }
@@ -283,33 +314,15 @@ impl Machine {
self.code_repo.code.extend(code.into_iter()); self.code_repo.code.extend(code.into_iter());
} }
fn fail(&mut self) -> EvalSession
{
if self.machine_st.ball.stub.len() > 0 {
let h = self.machine_st.heap.h;
self.machine_st.copy_and_align_ball_to_heap(0);
let err_str = self.machine_st.print_exception(Addr::HeapCell(h),
&HeapVarDict::new(),
PrinterOutputter::new())
.result();
let err_str = clause_name!(err_str, self.indices.atom_tbl());
EvalSession::from(SessionError::QueryFailureWithException(err_str))
} else {
EvalSession::from(SessionError::QueryFailure)
}
}
pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession
{ {
let mut heap_locs = HashMap::new(); let mut heap_locs = HeapVarDict::new();
self.code_repo.cached_query = code; self.code_repo.cached_query = code;
self.run_query(&alloc_locs, &mut heap_locs); self.run_query(&alloc_locs, &mut heap_locs);
if self.machine_st.fail { if self.machine_st.fail {
self.fail() EvalSession::QueryFailure
} else { } else {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
} }
@@ -341,6 +354,194 @@ impl Machine {
} }
} }
pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
let h = self.machine_st.heap.h;
let err = MachineError::session_error(h, err);
let stub = MachineError::functor_stub(key.0, key.1);
let err = self.machine_st.error_form(err, stub);
self.machine_st.throw_exception(err);
return;
}
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr)
{
match code_ptr {
REPLCodePtr::CompileBatch => {
#[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Multi);
let src = match readline::read_batch("") {
Ok(src) => src,
Err(e) => {
self.throw_session_error(e, (clause_name!("repl"), 0));
return;
}
};
#[cfg(feature = "readline_rs_compat")]
readline::set_line_mode(readline::LineMode::Single);
match compile_user_module(self, parsing_stream(&src[0 ..])) {
EvalSession::Error(e) =>
self.throw_session_error(e, (clause_name!("repl"), 0)),
_ => {}
};
},
REPLCodePtr::SubmitQueryAndPrintResults => {
let term = self.machine_st[temp_v!(1)].clone();
let stub = MachineError::functor_stub(clause_name!("repl"), 0);
let s = match self.machine_st.try_from_list(temp_v!(2), stub) {
Ok(addrs) => {
let mut var_dict = HeapVarDict::new();
for addr in addrs {
match addr {
Addr::Str(s) => {
let var_atom = match self.machine_st.heap[s+1].as_addr(s+1) {
Addr::Con(Constant::Atom(var_atom, _)) =>
Rc::new(var_atom.to_string()),
_ => unreachable!()
};
let var_addr = self.machine_st.heap[s+2].as_addr(s+2);
var_dict.insert(var_atom, var_addr);
},
_ => unreachable!()
};
}
let term_output = self.machine_st.print_with_locs(term, &var_dict);
term_output.result()
},
Err(err_stub) => {
self.machine_st.throw_exception(err_stub);
return;
}
};
let stream = parsing_stream(s.as_bytes());
let snapshot = self.machine_st.sink_to_snapshot();
self.machine_st.reset();
let result = match stream_to_toplevel(stream, self) {
Ok(packet) => compile_term(self, packet),
Err(e) => EvalSession::from(e)
};
self.handle_eval_session(result, snapshot);
}
}
self.machine_st.p = CodePtr::Local(p);
}
fn handle_eval_session(&mut self, result: EvalSession, snapshot: MachineState) {
match result {
EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) =>
loop {
let bindings = {
let mut output = PrinterOutputter::new();
self.toplevel_heap_view(&heap_locs, output).result()
};
let attr_goals = self.attribute_goals(&heap_locs);
if !(self.machine_st.b > 0) {
if bindings.is_empty() {
if !attr_goals.is_empty() {
println!("{}.", attr_goals);
} else {
println!("true.");
}
self.machine_st.absorb_snapshot(snapshot);
return;
}
} else if bindings.is_empty() && attr_goals.is_empty() {
print!("true");
stdout().flush().unwrap();
}
let mut raw_stdout = stdout().into_raw_mode().unwrap();
if !attr_goals.is_empty() {
if bindings.is_empty() {
write!(raw_stdout, "{}", attr_goals).unwrap();
} else {
write!(raw_stdout, "{}, {}", bindings, attr_goals).unwrap();
}
} else if !bindings.is_empty() {
write!(raw_stdout, "{}", bindings).unwrap();
}
if self.machine_st.b > 0 {
raw_stdout.flush().unwrap();
let result = match next_keypress(raw_stdout) {
ContinueResult::ContinueQuery =>
self.continue_query(&alloc_locs, &mut heap_locs),
ContinueResult::Conclude => {
self.machine_st.absorb_snapshot(snapshot);
return;
}
};
let mut raw_stdout = stdout().into_raw_mode().unwrap();
match result {
EvalSession::QueryFailure => {
write!(raw_stdout, "false.\r\n").unwrap();
raw_stdout.flush().unwrap();
self.machine_st.absorb_snapshot(snapshot);
return;
},
EvalSession::Error(err) => {
self.machine_st.absorb_snapshot(snapshot);
self.throw_session_error(err, (clause_name!("repl"), 0));
return;
},
_ => {}
}
} else {
if bindings.is_empty() && attr_goals.is_empty() {
write!(raw_stdout, "true.\r\n").unwrap();
} else {
write!(raw_stdout, ".\r\n").unwrap();
}
break;
}
},
EvalSession::Error(err) => {
self.machine_st.absorb_snapshot(snapshot);
self.throw_session_error(err, (clause_name!("repl"), 0));
return;
},
EvalSession::QueryFailure =>
if self.machine_st.ball.stub.len() > 0 {
let ball = self.machine_st.ball.take();
self.machine_st.absorb_snapshot(snapshot);
self.machine_st.ball = ball;
let stub = self.machine_st.copy_and_align_ball();
self.machine_st.throw_exception(stub);
return;
} else {
println!("false.");
},
_ => {}
}
self.machine_st.absorb_snapshot(snapshot);
}
pub(super) pub(super)
fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict) fn run_query(&mut self, alloc_locs: &AllocVarDict, heap_locs: &mut HeapVarDict)
{ {
@@ -359,10 +560,13 @@ impl Machine {
self.machine_st.p = top_level_code_ptr!(cn, p); self.machine_st.p = top_level_code_ptr!(cn, p);
} }
self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo); self.machine_st.query_stepper(&mut self.indices, &mut self.policies, &mut self.code_repo,
&mut self.prolog_stream);
match self.machine_st.p { match self.machine_st.p {
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {}, CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => {},
CodePtr::REPL(code_ptr, p) =>
self.handle_toplevel_command(code_ptr, p),
CodePtr::DynamicTransaction(trans_type, p) => { CodePtr::DynamicTransaction(trans_type, p) => {
// self.code_repo.cached_query is about to be overwritten by the term expander, // self.code_repo.cached_query is about to be overwritten by the term expander,
// so hold onto it locally and restore it after the compiler has finished. // so hold onto it locally and restore it after the compiler has finished.
@@ -399,18 +603,19 @@ impl Machine {
self.machine_st.p = self.machine_st.or_stack[b].bp.clone(); self.machine_st.p = self.machine_st.or_stack[b].bp.clone();
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p { if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
return EvalSession::from(SessionError::QueryFailure); self.machine_st.fail = true;
return EvalSession::QueryFailure;
} }
self.run_query(alloc_l, heap_l); self.run_query(alloc_l, heap_l);
if self.machine_st.fail { if self.machine_st.fail {
self.fail() EvalSession::QueryFailure
} else { } else {
EvalSession::SubsequentQuerySuccess EvalSession::SubsequentQuerySuccess
} }
} else { } else {
EvalSession::from(SessionError::QueryFailure) EvalSession::QueryFailure
} }
} }
@@ -422,11 +627,6 @@ impl Machine {
for (var, addr) in sorted_vars { for (var, addr) in sorted_vars {
let addr = self.machine_st.store(self.machine_st.deref(addr.clone())); let addr = self.machine_st.store(self.machine_st.deref(addr.clone()));
// if addr.is_ref() {
// continue;
// }
output = self.machine_st.print_var_eq(var.clone(), addr, var_dir, output); output = self.machine_st.print_var_eq(var.clone(), addr, var_dir, output);
} }
@@ -450,22 +650,12 @@ impl Machine {
pub fn or_stack_is_empty(&self) -> bool { pub fn or_stack_is_empty(&self) -> bool {
self.machine_st.b == 0 self.machine_st.b == 0
} }
pub fn clear(&mut self) {
let mut machine = Machine::new();
mem::swap(self, &mut machine);
}
pub fn reset(&mut self) {
self.policies.cut_policy = Box::new(DefaultCutPolicy {});
self.machine_st.reset();
}
} }
impl MachineState { impl MachineState {
fn execute_instr(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies, fn execute_instr(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies,
code_repo: &CodeRepo) code_repo: &CodeRepo, prolog_stream: &mut PrologStream)
{ {
let instr = match code_repo.lookup_instr(self.last_call, &self.p) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) {
Some(instr) => instr, Some(instr) => instr,
@@ -481,7 +671,8 @@ impl MachineState {
self.execute_cut_instr(cut_instr, &mut policies.cut_policy), self.execute_cut_instr(cut_instr, &mut policies.cut_policy),
&Line::Control(ref control_instr) => &Line::Control(ref control_instr) =>
self.execute_ctrl_instr(indices, &mut policies.call_policy, self.execute_ctrl_instr(indices, &mut policies.call_policy,
&mut policies.cut_policy, control_instr), &mut policies.cut_policy, prolog_stream,
control_instr),
&Line::Fact(ref fact_instr) => { &Line::Fact(ref fact_instr) => {
self.execute_fact_instr(&fact_instr); self.execute_fact_instr(&fact_instr);
self.p += 1; self.p += 1;
@@ -516,10 +707,10 @@ impl MachineState {
} }
fn query_stepper(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies, fn query_stepper(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies,
code_repo: &mut CodeRepo) code_repo: &mut CodeRepo, prolog_stream: &mut PrologStream)
{ {
loop { loop {
self.execute_instr(indices, policies, code_repo); self.execute_instr(indices, policies, code_repo, prolog_stream);
if self.fail { if self.fail {
self.backtrack(); self.backtrack();
@@ -538,7 +729,7 @@ impl MachineState {
self.fail = true, self.fail = true,
CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) CodePtr::Local(LocalCodePtr::InSituDirEntry(p))
if p < code_repo.in_situ_code.len() => {}, if p < code_repo.in_situ_code.len() => {},
CodePtr::Local(_) => CodePtr::Local(_) | CodePtr::REPL(..) =>
break, break,
CodePtr::VerifyAttrInterrupt(p) => CodePtr::VerifyAttrInterrupt(p) =>
self.verify_attr_interrupt(p), self.verify_attr_interrupt(p),

View File

@@ -1,5 +1,6 @@
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use std::vec::Vec; use std::vec::Vec;
@@ -74,6 +75,11 @@ impl OrStack {
self.0.push(Frame::new(global_index, e, cp, attr_var_init_b, b, bp, tr, pstr_tr, h, b0, n)); self.0.push(Frame::new(global_index, e, cp, attr_var_init_b, b, bp, tr, pstr_tr, h, b0, n));
} }
#[inline]
pub(crate) fn take(&mut self) -> Self {
OrStack(mem::replace(&mut self.0, vec![]))
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.0.len() self.0.len()
} }

View File

@@ -11,11 +11,12 @@ 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 ref_thread_local::RefThreadLocal; use ref_thread_local::RefThreadLocal;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{stdout, Read, Write}; use std::io::{stdout, Write};
use std::iter::once; use std::iter::once;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
@@ -201,6 +202,17 @@ impl MachineState {
threshold + lh_offset + 2 threshold + lh_offset + 2
} }
fn repl_redirect(&mut self, repl_code_ptr: REPLCodePtr) -> CallResult {
let p = if self.last_call {
self.cp
} else {
self.p.local() + 1
};
self.p = CodePtr::REPL(repl_code_ptr, p);
return Ok(());
}
fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr) fn truncate_if_no_lifted_heap_diff<AddrConstr>(&mut self, addr_constr: AddrConstr)
where AddrConstr: Fn(usize) -> Addr where AddrConstr: Fn(usize) -> Addr
{ {
@@ -301,7 +313,8 @@ impl MachineState {
ct: &SystemClauseType, ct: &SystemClauseType,
indices: &mut IndexStore, indices: &mut IndexStore,
call_policy: &mut Box<CallPolicy>, call_policy: &mut Box<CallPolicy>,
cut_policy: &mut Box<CutPolicy>) cut_policy: &mut Box<CutPolicy>,
parsing_stream: &mut PrologStream)
-> CallResult -> CallResult
{ {
match ct { match ct {
@@ -542,16 +555,14 @@ impl MachineState {
}; };
}, },
&SystemClauseType::GetChar => { &SystemClauseType::GetChar => {
let c = std::io::stdin() readline::toggle_prompt(false);
.bytes()
.next()
.and_then(|result| result.ok());
let result = parsing_stream.next();
let a1 = self[temp_v!(1)].clone(); let a1 = self[temp_v!(1)].clone();
match c { match result {
Some(c) => self.unify(Addr::Con(Constant::Char(c as char)), a1), Some(Ok(b)) => self.unify(Addr::Con(Constant::Char(b as char)), a1),
None => { _ => {
let stub = MachineError::functor_stub(clause_name!("get_char"), 1); let stub = MachineError::functor_stub(clause_name!("get_char"), 1);
let err = MachineError::representation_error(RepFlag::Character); let err = MachineError::representation_error(RepFlag::Character);
let err = self.error_form(err, stub); let err = self.error_form(err, stub);
@@ -1228,6 +1239,8 @@ impl MachineState {
None => panic!("remove_inference_counter: requires \\ None => panic!("remove_inference_counter: requires \\
CWILCallPolicy.") CWILCallPolicy.")
}, },
&SystemClauseType::REPL(repl_code_ptr) =>
return self.repl_redirect(repl_code_ptr),
&SystemClauseType::ModuleRetractClause => { &SystemClauseType::ModuleRetractClause => {
let p = self.cp; let p = self.cp;
let trans_type = DynamicTransactionType::ModuleRetract; let trans_type = DynamicTransactionType::ModuleRetract;
@@ -1249,7 +1262,6 @@ impl MachineState {
}, },
&SystemClauseType::ReturnFromVerifyAttr => { &SystemClauseType::ReturnFromVerifyAttr => {
let e = self.e; let e = self.e;
let frame_len = self.and_stack[e].len(); let frame_len = self.and_stack[e].len();
for i in 1 .. frame_len - 1 { for i in 1 .. frame_len - 1 {
@@ -1264,7 +1276,7 @@ impl MachineState {
self.num_of_args = num_of_args; self.num_of_args = num_of_args;
} }
self.p = CodePtr::Local(self.and_stack[e].special_form_cp); self.p = CodePtr::Local(self.and_stack[e].interrupt_cp);
self.deallocate(); self.deallocate();
return Ok(()); return Ok(());
@@ -1334,7 +1346,8 @@ impl MachineState {
let h = self.heap.h; let h = self.heap.h;
if self.ball.stub.len() > 0 { if self.ball.stub.len() > 0 {
self.copy_and_align_ball_to_heap(0); let stub = self.copy_and_align_ball();
self.heap.append(stub);
} else { } else {
self.fail = true; self.fail = true;
return Ok(()); return Ok(());
@@ -1391,6 +1404,51 @@ impl MachineState {
&SystemClauseType::InstallNewBlock => { &SystemClauseType::InstallNewBlock => {
self.install_new_block(temp_v!(1)); self.install_new_block(temp_v!(1));
}, },
&SystemClauseType::ReadTerm => {
readline::toggle_prompt(true);
match self.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) {
Ok(term_write_result) => {
let a1 = self[temp_v!(1)].clone();
self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
if self.fail {
return Ok(());
}
let mut list_of_var_eqs = vec![];
for (var, binding) in term_write_result.var_dict {
let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
let var_atom = Constant::Atom(var_atom, None);
let h = self.heap.h;
let op_desc = Some(SharedOpDesc::new(700, XFX));
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), op_desc));
self.heap.push(HeapCellValue::Addr(Addr::Con(var_atom)));
self.heap.push(HeapCellValue::Addr(binding));
list_of_var_eqs.push(Addr::Str(h));
}
let a2 = self[temp_v!(2)].clone();
let list_offset = Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
self.unify(list_offset, a2);
},
Err(err) => {
// reset the input stream after an input failure.
*parsing_stream = readline::input_stream();
let h = self.heap.h;
let syntax_error = MachineError::syntax_error(h, err);
let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
return Err(self.error_form(syntax_error, stub));
}
}
},
&SystemClauseType::ResetBlock => { &SystemClauseType::ResetBlock => {
let addr = self.deref(self[temp_v!(1)].clone()); let addr = self.deref(self[temp_v!(1)].clone());
self.reset_block(addr); self.reset_block(addr);
@@ -1414,43 +1472,19 @@ impl MachineState {
&SystemClauseType::Succeed => {}, &SystemClauseType::Succeed => {},
&SystemClauseType::TermVariables => { &SystemClauseType::TermVariables => {
let a1 = self[temp_v!(1)].clone(); let a1 = self[temp_v!(1)].clone();
let mut vars = Vec::new();
{
let iter = self.acyclic_pre_order_iter(a1);
for item in iter {
match item {
HeapCellValue::Addr(Addr::AttrVar(h)) =>
vars.push(Ref::AttrVar(h)),
HeapCellValue::Addr(Addr::HeapCell(h)) =>
vars.push(Ref::HeapCell(h)),
HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
vars.push(Ref::StackCell(fr, sc)),
_ => {}
}
}
}
let mut h = self.heap.h;
let outcome = Addr::HeapCell(h);
let mut seen_vars = HashSet::new(); let mut seen_vars = HashSet::new();
for r in vars { for item in self.acyclic_pre_order_iter(a1) {
if seen_vars.contains(&r) { match item {
continue; HeapCellValue::Addr(addr) =>
if addr.is_ref() {
seen_vars.insert(addr);
},
_ => {}
} }
self.heap.push(HeapCellValue::Addr(Addr::Lis(h+1)));
self.heap.push(HeapCellValue::Addr(r.as_addr()));
h += 2;
seen_vars.insert(r);
} }
self.heap.push(HeapCellValue::Addr(Addr::Con(Constant::EmptyList))); let outcome = Addr::HeapCell(self.heap.to_list(seen_vars.into_iter()));
let a2 = self[temp_v!(2)].clone(); let a2 = self[temp_v!(2)].clone();
self.unify(a2, outcome); self.unify(a2, outcome);

View File

@@ -4,7 +4,6 @@ use prolog_parser::parser::*;
use prolog::machine::*; use prolog::machine::*;
use prolog::machine::machine_indices::HeapCellValue; use prolog::machine::machine_indices::HeapCellValue;
use prolog::num::*; use prolog::num::*;
use prolog::read::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
@@ -74,7 +73,7 @@ pub struct TermStream<'a, R: Read> {
pub(crate) indices: &'a mut IndexStore, pub(crate) indices: &'a mut IndexStore,
policies: &'a mut MachinePolicies, policies: &'a mut MachinePolicies,
pub(crate) code_repo: &'a mut CodeRepo, pub(crate) code_repo: &'a mut CodeRepo,
parser: Parser<R>, parser: Parser<'a, R>,
in_module: bool, in_module: bool,
pub(crate) flags: MachineFlags, pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize), term_expansion_lens: (usize, usize),
@@ -111,7 +110,7 @@ impl<'a, R: Read> Drop for TermStream<'a, R> {
} }
impl<'a, R: Read> TermStream<'a, R> { impl<'a, R: Read> TermStream<'a, R> {
pub fn new(src: R, atom_tbl: TabledData<Atom>, flags: MachineFlags, pub fn new(src: &'a mut ParsingStream<R>, atom_tbl: TabledData<Atom>, flags: MachineFlags,
indices: &'a mut IndexStore, policies: &'a mut MachinePolicies, indices: &'a mut IndexStore, policies: &'a mut MachinePolicies,
code_repo: &'a mut CodeRepo) code_repo: &'a mut CodeRepo)
-> Self -> Self
@@ -129,6 +128,11 @@ impl<'a, R: Read> TermStream<'a, R> {
} }
} }
#[inline]
pub fn add_to_top(&mut self, buf: &str) {
self.parser.add_to_top(buf);
}
#[inline] #[inline]
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) { pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
match hook { match hook {
@@ -185,14 +189,16 @@ impl<'a, R: Read> TermStream<'a, R> {
}, },
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
Ok(self.stack.push(term)), Ok(self.stack.push(term)),
_ => Err(ParserError::ExpectedTopLevelTerm) _ =>
Err(ParserError::ExpectedTopLevelTerm)
} }
} }
fn parse_expansion_output(&self, term_string: &str, op_dir: &OpDir) -> Result<Term, ParserError> fn parse_expansion_output(&self, term_string: &str, op_dir: &OpDir) -> Result<Term, ParserError>
{ {
let mut parser = Parser::new(term_string.trim().as_bytes(), self.parser.get_atom_tbl(), let mut stream = parsing_stream(term_string.trim().as_bytes());
self.flags); let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
parser.read_term(composite_op!(self.in_module, &self.indices.op_dir, op_dir)) parser.read_term(composite_op!(self.in_module, &self.indices.op_dir, op_dir))
} }
@@ -230,24 +236,23 @@ impl<'a, R: Read> TermStream<'a, R> {
match term { match term {
Term::Clause(cell, name, mut terms, arity) => { Term::Clause(cell, name, mut terms, arity) => {
let mut new_terms = { let mut new_terms = {
let old_terms = if name.as_str() == ":-" && terms.len() == 2 { let old_terms = match (name.as_str(), terms.len()) {
let comma_term = *terms.pop().unwrap(); (":-", 2) => {
unfold_by_str(comma_term, ",") let comma_term = *terms.pop().unwrap();
} else if name.as_str() == "?-" && terms.len() == 1 { unfold_by_str(comma_term, ",")
let comma_term = *terms.pop().unwrap(); },
unfold_by_str(comma_term, ",") ("?-", 1) =>
} else { unfold_by_str(*terms.pop().unwrap(), ","),
return Ok(Term::Clause(cell, name, terms, arity)); _ => return Ok(Term::Clause(cell, name, terms, arity))
}; };
self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))? self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))?
}; };
let initial_term = new_terms.pop().unwrap(); let initial_term = new_terms.pop().unwrap();
terms.push(Box::new(fold_by_str(new_terms.into_iter(), initial_term, terms.push(Box::new(fold_by_str(new_terms.into_iter(), initial_term,
clause_name!(",")))); clause_name!(","))));
Ok(Term::Clause(cell, name, terms, None)) Ok(Term::Clause(cell, name, terms, arity))
}, },
_ => _ =>
Ok(term) Ok(term)
@@ -302,6 +307,8 @@ impl MachineState {
// style variable names will be longer than the keys of the var_dict, and therefore // style variable names will be longer than the keys of the var_dict, and therefore
// not equal to any of them. // not equal to any of them.
printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26; printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26;
printer.drop_toplevel_spec();
printer.see_all_locs(); printer.see_all_locs();
let mut output = printer.print(addr); let mut output = printer.print(addr);
@@ -324,7 +331,7 @@ impl MachineState {
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)]; let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
code_repo.cached_query = code; code_repo.cached_query = code;
self.query_stepper(indices, policies, code_repo); self.query_stepper(indices, policies, code_repo, &mut readline::input_stream());
if self.fail { if self.fail {
self.reset(); self.reset();

View File

@@ -681,6 +681,18 @@ impl RelationWorker {
} }
} }
fn try_term_to_query(&mut self, indices: &mut CompositeIndices, terms: Vec<Box<Term>>, blocks_cuts: bool)
-> Result<TopLevel, ParserError>
{
match setup_declaration(terms.iter().cloned().collect()) {
Ok(Declaration::Op(..)) => {}, // this is now a predicate call in the query context.
Ok(decl) => return Ok(TopLevel::Declaration(decl)),
_ => {}
};
Ok(TopLevel::Query(self.setup_query(indices, terms, blocks_cuts)?))
}
fn try_term_to_tl(&mut self, indices: &mut CompositeIndices, term: Term, blocks_cuts: bool) fn try_term_to_tl(&mut self, indices: &mut CompositeIndices, term: Term, blocks_cuts: bool)
-> Result<TopLevel, ParserError> -> Result<TopLevel, ParserError>
{ {
@@ -692,13 +704,7 @@ impl RelationWorker {
Ok(TopLevel::Declaration(Declaration::Hook(hook, clause, queue))) Ok(TopLevel::Declaration(Declaration::Hook(hook, clause, queue)))
} else if name.as_str() == "?-" { } else if name.as_str() == "?-" {
match setup_declaration(terms.iter().cloned().collect()) { self.try_term_to_query(indices, terms, blocks_cuts)
Ok(Declaration::Op(..)) => {}, // this is now a predicate call in the query context.
Ok(decl) => return Ok(TopLevel::Declaration(decl)),
_ => {}
};
Ok(TopLevel::Query(self.setup_query(indices, terms, blocks_cuts)?))
} else if name.as_str() == ":-" && terms.len() == 2 { } else if name.as_str() == ":-" && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule(indices, terms, blocks_cuts, true)?)) Ok(TopLevel::Rule(self.setup_rule(indices, terms, blocks_cuts, true)?))
} else if name.as_str() == ":-" && terms.len() == 1 { } else if name.as_str() == ":-" && terms.len() == 1 {
@@ -770,21 +776,24 @@ fn term_to_toplevel<R>(term_stream: &mut TermStream<R>, code_dir: &mut CodeDir,
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)?;
Ok((tl, rel_worker)) Ok((tl, rel_worker))
} }
pub pub
fn string_to_toplevel<R: Read>(buffer: R, wam: &mut Machine) -> Result<TopLevelPacket, SessionError> fn stream_to_toplevel<R: Read>(mut buffer: ParsingStream<R>, wam: &mut Machine)
-> Result<TopLevelPacket, SessionError>
{ {
let mut term_stream = TermStream::new(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);
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)?;
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);
@@ -804,7 +813,8 @@ pub struct TopLevelBatchWorker<'a, R: Read> {
} }
impl<'a, R: Read> TopLevelBatchWorker<'a, R> { impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
pub fn new(inner: R, atom_tbl: TabledData<Atom>,
pub fn new(inner: &'a mut ParsingStream<R>, atom_tbl: TabledData<Atom>,
flags: MachineFlags, indices: &'a mut IndexStore, flags: MachineFlags, indices: &'a mut IndexStore,
policies: &'a mut MachinePolicies, code_repo: &'a mut CodeRepo) policies: &'a mut MachinePolicies, code_repo: &'a mut CodeRepo)
-> Self -> Self

View File

@@ -4,7 +4,6 @@ use prolog_parser::tabled_rc::TabledData;
use prolog::forms::*; use prolog::forms::*;
use prolog::iterators::*; use prolog::iterators::*;
use prolog::machine::machine_errors::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use prolog::machine::machine_state::MachineState; use prolog::machine::machine_state::MachineState;
@@ -24,16 +23,14 @@ impl<'a> TermRef<'a> {
} }
} }
pub enum Input { pub type PrologStream = ParsingStream<Box<Read>>;
Clear,
Batch,
TermString(String)
}
#[cfg(feature = "readline_rs_compat")] #[cfg(feature = "readline_rs_compat")]
pub mod readline pub mod readline
{ {
use prolog_parser::ast::*;
use readline_rs_compat::readline::*; use readline_rs_compat::readline::*;
use std::io::{Error, Read};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum LineMode { pub enum LineMode {
@@ -41,9 +38,74 @@ pub mod readline
Multi Multi
} }
pub struct ReadlineStream {
pending_input: String
}
impl ReadlineStream {
#[inline]
fn new(pending_input: String) -> Self {
ReadlineStream { pending_input }
}
fn call_readline(&mut self, prompt: &str, buf: &mut [u8]) -> std::io::Result<usize> {
match readline_rl(prompt) {
Some(text) => {
self.pending_input += &text;
Ok(self.write_to_buf(buf))
},
None => Err(Error::last_os_error())
}
}
fn split_pending(&mut self, buf: &mut [u8], split_idx: usize) -> usize {
let (outgoing, _) = self.pending_input.split_at(split_idx);
for (idx, b) in outgoing.bytes().enumerate() {
buf[idx] = b;
}
outgoing.len()
}
fn write_to_buf(&mut self, buf: &mut [u8]) -> usize {
let split_idx = std::cmp::min(self.pending_input.len(), buf.len());
let output_len = self.split_pending(buf, split_idx);
if split_idx < self.pending_input.len() {
self.pending_input = self.pending_input[split_idx ..].to_string();
} else {
self.pending_input.clear();
}
output_len
}
}
impl Read for ReadlineStream {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if self.pending_input.is_empty() {
let prompt = unsafe {
if PRINT_PROMPT { "?- " } else { "" }
};
self.call_readline(prompt, buf)
} else {
Ok(self.write_to_buf(buf))
}
}
}
static mut PRINT_PROMPT: bool = true;
static mut LINE_MODE: LineMode = LineMode::Single; static mut LINE_MODE: LineMode = LineMode::Single;
static mut END_OF_LINE: bool = false; static mut END_OF_LINE: bool = false;
pub fn toggle_prompt(on_or_off: bool) {
unsafe {
PRINT_PROMPT = on_or_off;
}
}
pub fn set_line_mode(mode: LineMode) { pub fn set_line_mode(mode: LineMode) {
unsafe { unsafe {
LINE_MODE = mode; LINE_MODE = mode;
@@ -52,13 +114,6 @@ pub mod readline
} }
} }
fn is_directive(buf: &str) -> bool {
match buf {
"?- [user]." | "?- [clear]." => true,
_ => false
}
}
unsafe extern "C" fn bind_end_chord(_: i32, _: i32) -> i32 { unsafe extern "C" fn bind_end_chord(_: i32, _: i32) -> i32 {
if let LineMode::Multi = LINE_MODE { if let LineMode::Multi = LINE_MODE {
rl_done = 1; rl_done = 1;
@@ -67,26 +122,9 @@ pub mod readline
0 0
} }
unsafe extern "C" fn bind_end_key(_: i32, _: i32) -> i32 {
insert_text_rl(".");
if let LineMode::Single = LINE_MODE {
END_OF_LINE = true;
}
0
}
unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 { unsafe extern "C" fn bind_cr(_: i32, _: i32) -> i32 {
if END_OF_LINE { if let LineMode::Single = LINE_MODE {
if let Some(buf) = rl_line_buffer_as_str() { insert_text_rl("\n");
if is_directive(buf) {
println!("");
rl_done = 1;
return 0;
}
}
println!(""); println!("");
rl_done = 1; rl_done = 1;
} else { } else {
@@ -103,24 +141,11 @@ pub mod readline
panic!("initialize_rl() failed with return code {}", rc); panic!("initialize_rl() failed with return code {}", rc);
} }
unsafe {
rl_startup_hook = insert_query_prompt;
}
bind_key_rl('.' as i32, bind_end_key);
bind_key_rl('\n' as i32, bind_cr); bind_key_rl('\n' as i32, bind_cr);
bind_key_rl('\r' as i32, bind_cr); bind_key_rl('\r' as i32, bind_cr);
bind_keyseq_rl("\\C-d", bind_end_chord); bind_keyseq_rl("\\C-d", bind_end_chord);
} }
unsafe extern "C" fn insert_query_prompt() -> i32 {
if let LineMode::Single = LINE_MODE {
insert_text_rl("?- ");
}
0
}
pub fn read_batch(prompt: &str) -> Result<Vec<u8>, ::SessionError> { pub fn read_batch(prompt: &str) -> Result<Vec<u8>, ::SessionError> {
match readline_rl(prompt) { match readline_rl(prompt) {
Some(input) => Ok(Vec::from(input.as_bytes())), Some(input) => Ok(Vec::from(input.as_bytes())),
@@ -128,18 +153,41 @@ pub mod readline
} }
} }
pub fn read_line(prompt: &str) -> Result<String, ::SessionError> { #[inline]
match readline_rl(prompt) { pub fn input_stream() -> ::PrologStream {
Some(input) => Ok(String::from(input)), let reader: Box<Read> = Box::new(ReadlineStream::new(String::from("")));
None => Err(::SessionError::UserPrompt) parsing_stream(reader)
}
} }
} }
#[cfg(not(feature = "readline_rs_compat"))] #[cfg(not(feature = "readline_rs_compat"))]
pub mod readline pub mod readline
{ {
use std::io::{BufRead, Read, stdin, stdout, Write}; use prolog_parser::ast::*;
use std::io::{BufReader, Read, Stdin, Write, stdin, stdout};
static mut PRINT_PROMPT: bool = false;
struct StdinWrapper {
buf: BufReader<Stdin>
}
fn print_prompt() {
unsafe {
if PRINT_PROMPT {
print!("?- ");
stdout().flush().unwrap();
PRINT_PROMPT = false;
}
}
}
impl Read for StdinWrapper {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
print_prompt();
self.buf.read(buf)
}
}
pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> { pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> {
let mut buf = vec![]; let mut buf = vec![];
@@ -153,54 +201,30 @@ pub mod readline
} }
} }
pub fn read_line(_: &str) -> Result<String, ::SessionError> { #[inline]
print!("?- "); pub fn input_stream() -> ::PrologStream {
stdout().flush().unwrap(); print_prompt();
let stdin = stdin(); let reader: Box<Read> = Box::new(StdinWrapper { buf: BufReader::new(stdin()) });
let stdin = stdin.lock(); parsing_stream(reader)
}
let mut buf = "?- ".to_string();
for line in stdin.lines() { pub fn toggle_prompt(on_or_off: bool) {
match line { unsafe {
Ok(line) => { PRINT_PROMPT = on_or_off;
buf += &line;
if line.trim().ends_with(".") {
break;
}
},
_ => return Err(::SessionError::UserPrompt)
}
} }
Ok(buf)
} }
} }
pub fn toplevel_read_line() -> Result<Input, SessionError>
{
let buffer = readline::read_line("")?;
Ok(match &*buffer.trim() {
"?- [clear]." => Input::Clear,
"?- [user]." => {
println!("(type Enter + Ctrl-D to terminate the stream when finished)");
Input::Batch
},
_ => Input::TermString(buffer)
})
}
impl MachineState { impl MachineState {
pub fn read<R: Read>(&mut self, inner: R, atom_tbl: TabledData<Atom>, op_dir: &OpDir) pub fn read(&mut self, inner: &mut PrologStream, atom_tbl: TabledData<Atom>, op_dir: &OpDir)
-> Result<usize, ParserError> -> Result<TermWriteResult, ParserError>
{ {
let mut parser = Parser::new(inner, atom_tbl, self.flags); let mut parser = Parser::new(inner, atom_tbl, self.flags);
let term = parser.read_term(composite_op!(op_dir))?; let term = parser.read_term(composite_op!(op_dir))?;
Ok(write_term_to_heap(&term, self).heap_loc) Ok(write_term_to_heap(&term, self))
} }
} }
@@ -220,12 +244,13 @@ fn modify_head_of_queue(machine_st: &mut MachineState, queue: &mut SubtermDeque,
} }
} }
pub(crate) struct TermWriteResult { pub struct TermWriteResult {
pub(crate) heap_loc: usize, pub(crate) heap_loc: usize,
pub(crate) var_dict: HeapVarDict, pub(crate) var_dict: HeapVarDict,
} }
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult pub(crate)
fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult
{ {
let heap_loc = machine_st.heap.h; let heap_loc = machine_st.heap.h;

19
src/prolog/toplevel.pl Normal file
View File

@@ -0,0 +1,19 @@
repl :-
catch(read_and_match, E, '$print_exception'(E)),
false. %% this is for GC, until we get actual GC.
repl :- repl.
read_and_match :-
read_term(Term, [variable_names(VarList)]),
'$instruction_match'(Term, VarList).
'$instruction_match'([user], []) :-
!, '$compile_batch'.
'$instruction_match'(Term, VarList) :-
'$submit_query_and_print_results'(Term, VarList),
!.
'$print_exception'(E) :-
write_term('error: exception thrown: ', [quoted(false)]),
writeq(E),
nl.

View File

@@ -1,22 +1,16 @@
use prolog::clause_types::*; use prolog::clause_types::*;
use prolog::forms::*; use prolog::forms::*;
use prolog::heap_print::*;
use prolog::instructions::*; use prolog::instructions::*;
use prolog::machine::*;
use prolog::machine::machine_errors::*; use prolog::machine::machine_errors::*;
use prolog::machine::machine_indices::*; use prolog::machine::machine_indices::*;
use termion::raw::{IntoRawMode, RawTerminal};
use termion::input::TermRead; use termion::input::TermRead;
use termion::event::Key; use termion::event::Key;
use termion::raw::{RawTerminal};
use std::io::{Write, stdin, stdout}; use std::io::{Write, stdin};
use std::fmt; use std::fmt;
fn error_string<StringT: AsRef<str>>(e: &StringT) -> String {
format!("error: exception thrown: {}", e.as_ref())
}
impl fmt::Display for LocalCodePtr { impl fmt::Display for LocalCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -34,6 +28,17 @@ impl fmt::Display for LocalCodePtr {
} }
} }
impl fmt::Display for REPLCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
REPLCodePtr::CompileBatch =>
write!(f, "REPLCodePtr::CompileBatch"),
REPLCodePtr::SubmitQueryAndPrintResults =>
write!(f, "REPLCodePtr::SubmitQueryAndPrintResults")
}
}
}
impl fmt::Display for IndexPtr { impl fmt::Display for IndexPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -262,10 +267,6 @@ impl fmt::Display for SessionError {
&SessionError::ModuleNotFound => write!(f, "module not found."), &SessionError::ModuleNotFound => write!(f, "module not found."),
&SessionError::ModuleDoesNotContainExport => &SessionError::ModuleDoesNotContainExport =>
write!(f, "module does not contain claimed export."), write!(f, "module does not contain claimed export."),
&SessionError::QueryFailure =>
write!(f, "false."),
&SessionError::QueryFailureWithException(ref e) =>
write!(f, "{}", error_string(e)),
&SessionError::OpIsInfixAndPostFix(_) => &SessionError::OpIsInfixAndPostFix(_) =>
write!(f, "cannot define an op to be both postfix and infix."), write!(f, "cannot define an op to be both postfix and infix."),
&SessionError::NamelessEntry => &SessionError::NamelessEntry =>
@@ -357,12 +358,13 @@ impl fmt::Display for Level {
} }
} }
enum ContinueResult { pub enum ContinueResult {
ContinueQuery, ContinueQuery,
Conclude Conclude
} }
fn next_step(mut stdout: RawTerminal<std::io::Stdout>) -> ContinueResult pub
fn next_keypress(mut stdout: RawTerminal<std::io::Stdout>) -> ContinueResult
{ {
let stdin = stdin(); let stdin = stdin();
@@ -382,81 +384,3 @@ fn next_step(mut stdout: RawTerminal<std::io::Stdout>) -> ContinueResult
ContinueResult::Conclude ContinueResult::Conclude
} }
pub fn print(wam: &mut Machine, result: EvalSession) {
match result {
EvalSession::InitialQuerySuccess(alloc_locs, mut heap_locs) =>
loop {
let bindings = {
let mut output = PrinterOutputter::new();
wam.toplevel_heap_view(&heap_locs, output).result()
};
let attr_goals = wam.attribute_goals(&heap_locs);
if wam.or_stack_is_empty() {
if bindings.is_empty() {
if !attr_goals.is_empty() {
println!("{}.", attr_goals);
} else {
println!("true.");
}
return;
}
} else if bindings.is_empty() && attr_goals.is_empty() {
print!("true");
stdout().flush().unwrap();
}
let mut raw_stdout = stdout().into_raw_mode().unwrap();
if !attr_goals.is_empty() {
if bindings.is_empty() {
write!(raw_stdout, "{}", attr_goals).unwrap();
} else {
write!(raw_stdout, "{}, {}", bindings, attr_goals).unwrap();
}
} else if !bindings.is_empty() {
write!(raw_stdout, "{}", bindings).unwrap();
}
if !wam.or_stack_is_empty() {
raw_stdout.flush().unwrap();
let result = match next_step(raw_stdout) {
ContinueResult::ContinueQuery =>
wam.continue_query(&alloc_locs, &mut heap_locs),
ContinueResult::Conclude =>
return
};
let mut raw_stdout = stdout().into_raw_mode().unwrap();
if let &EvalSession::Error(SessionError::QueryFailure) = &result
{
write!(raw_stdout, "false.\r\n").unwrap();
raw_stdout.flush().unwrap();
return;
}
if let &EvalSession::Error(SessionError::QueryFailureWithException(ref e)) = &result
{
write!(raw_stdout, "{}\r\n", error_string(e)).unwrap();
raw_stdout.flush().unwrap();
return;
}
} else {
if bindings.is_empty() && attr_goals.is_empty() {
write!(raw_stdout, "true.\r\n").unwrap();
} else {
write!(raw_stdout, ".\r\n").unwrap();
}
break;
}
},
EvalSession::Error(e) => println!("{}", e),
_ => {}
};
}

File diff suppressed because it is too large Load Diff