read from streams.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.51"
|
||||
version = "0.8.52"
|
||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||
repository = "https://github.com/mthom/scryer-prolog"
|
||||
description = "A modern Prolog implementation written mostly in Rust."
|
||||
@@ -14,8 +14,8 @@ cfg-if = "0.1.7"
|
||||
downcast = "0.10.0"
|
||||
num = "0.2"
|
||||
ordered-float = "0.5.0"
|
||||
prolog_parser = "0.8.18"
|
||||
readline_rs_compat = { version = "0.1.7", optional = true }
|
||||
prolog_parser = { version = "0.8.19", path = "../prolog_parser" }
|
||||
readline_rs_compat = { version = "0.1.8", path = "../readline.rs", optional = true }
|
||||
ref_thread_local = "0.0.0"
|
||||
|
||||
[dependencies.termion]
|
||||
|
||||
49
src/main.rs
49
src/main.rs
@@ -14,59 +14,16 @@ extern crate termion;
|
||||
mod prolog;
|
||||
|
||||
use prolog::machine::*;
|
||||
use prolog::machine::compile::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::toplevel::string_to_toplevel;
|
||||
use prolog::read::*;
|
||||
use prolog::write::*;
|
||||
|
||||
#[cfg(test)]
|
||||
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() {
|
||||
#[cfg(feature = "readline_rs_compat")]
|
||||
readline::readline_initialize();
|
||||
prolog_repl();
|
||||
|
||||
let mut wam = Machine::new(readline::input_stream());
|
||||
wam.run_toplevel();
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ ref_thread_local! {
|
||||
m.insert(("partial_string", 2), ClauseType::BuiltIn(BuiltInClauseType::PartialString));
|
||||
m.insert(("read", 1), ClauseType::BuiltIn(BuiltInClauseType::Read));
|
||||
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
|
||||
|
||||
|
||||
m
|
||||
};
|
||||
}
|
||||
@@ -177,7 +177,7 @@ pub enum SystemClauseType {
|
||||
FetchGlobalVar,
|
||||
GetChar,
|
||||
TruncateIfNoLiftedHeapGrowthDiff,
|
||||
TruncateIfNoLiftedHeapGrowth,
|
||||
TruncateIfNoLiftedHeapGrowth,
|
||||
GetAttributedVariableList,
|
||||
GetAttrVarQueueDelimiter,
|
||||
GetAttrVarQueueBeyond,
|
||||
@@ -201,6 +201,8 @@ pub enum SystemClauseType {
|
||||
ModuleRetractClause,
|
||||
NoSuchPredicate,
|
||||
OpDeclaration,
|
||||
REPL(REPLCodePtr),
|
||||
ReadTerm,
|
||||
RedoAttrVarBindings,
|
||||
RemoveCallPolicyCheck,
|
||||
RemoveInferenceCounter,
|
||||
@@ -236,7 +238,7 @@ impl SystemClauseType {
|
||||
pub fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
|
||||
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
|
||||
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
|
||||
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
|
||||
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
|
||||
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
||||
@@ -246,6 +248,9 @@ impl SystemClauseType {
|
||||
&SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
|
||||
&SystemClauseType::CharCode => clause_name!("char_code"),
|
||||
&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::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||
@@ -296,6 +301,7 @@ impl SystemClauseType {
|
||||
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
||||
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
||||
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
|
||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
|
||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||
@@ -326,6 +332,7 @@ impl SystemClauseType {
|
||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
|
||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
||||
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
||||
@@ -375,6 +382,7 @@ impl SystemClauseType {
|
||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
||||
@@ -385,6 +393,8 @@ impl SystemClauseType {
|
||||
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
|
||||
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
||||
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
||||
("$submit_query_and_print_results", 2) =>
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults)),
|
||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||
@@ -397,7 +407,7 @@ impl SystemClauseType {
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
pub enum BuiltInClauseType {
|
||||
AcyclicTerm,
|
||||
Arg,
|
||||
Arg,
|
||||
Compare,
|
||||
CompareTerm(CompareTermQT),
|
||||
CyclicTerm,
|
||||
|
||||
@@ -398,6 +398,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
|
||||
printer
|
||||
}
|
||||
|
||||
pub fn drop_toplevel_spec(&mut self) {
|
||||
self.toplevel_spec = None;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn see_all_locs(&mut self) {
|
||||
for key in self.heap_locs.keys().cloned() {
|
||||
@@ -559,8 +563,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
|
||||
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue>
|
||||
{
|
||||
iter.stack().last().cloned().and_then(|addr| {
|
||||
let addr = self.machine_st.store(self.machine_st.deref(addr));
|
||||
|
||||
let addr = self.machine_st.store(self.machine_st.deref(addr));
|
||||
|
||||
match self.heap_locs.get(&addr).cloned() {
|
||||
Some(var) => if !self.printed_vars.contains(&addr) {
|
||||
self.printed_vars.insert(addr);
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
char_code/2, clause/2, current_predicate/1, current_op/3,
|
||||
current_prolog_flag/2, expand_goal/2, expand_term/2,
|
||||
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,
|
||||
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)
|
||||
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) :-
|
||||
'$skip_max_list'(_, -1, Options, Options0),
|
||||
( Options0 == [] -> true
|
||||
; throw(error(type_error(list, Options), write_term/2)) ), % 8.14.2.3 c)
|
||||
( Options0 == [] -> true
|
||||
; 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, numbervars(NumberVars), numbervars(false)),
|
||||
inst_member_or(Options, quoted(Quoted), quoted(false)),
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
:- module(dif, [dif/2]).
|
||||
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(ordsets)).
|
||||
|
||||
:- attribute dif/1.
|
||||
|
||||
put_dif_att(Var, X, Y) :-
|
||||
( get_atts(Var, +dif(Z)) ->
|
||||
ord_add_element(Z, X \== Y, NewZ),
|
||||
( Z == NewZ -> true
|
||||
; put_atts(Var, +dif(NewZ))
|
||||
)
|
||||
sort([X \== Y | Z], NewZ),
|
||||
put_atts(Var, +dif(NewZ))
|
||||
; put_atts(Var, +dif([X \== Y]))
|
||||
).
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use prolog::machine::machine_indices::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::vec::Vec;
|
||||
|
||||
@@ -8,7 +9,7 @@ pub struct Frame {
|
||||
pub global_index: usize,
|
||||
pub e: usize,
|
||||
pub cp: LocalCodePtr,
|
||||
pub special_form_cp: LocalCodePtr,
|
||||
pub interrupt_cp: LocalCodePtr,
|
||||
perms: Vec<Addr>
|
||||
}
|
||||
|
||||
@@ -18,7 +19,7 @@ impl Frame {
|
||||
global_index,
|
||||
e: e,
|
||||
cp: cp,
|
||||
special_form_cp: LocalCodePtr::default(),
|
||||
interrupt_cp: LocalCodePtr::default(),
|
||||
perms: (1 .. n+1).map(|i| Addr::StackCell(fr, i)).collect()
|
||||
}
|
||||
}
|
||||
@@ -36,6 +37,11 @@ impl AndStack {
|
||||
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) {
|
||||
let len = self.0.len();
|
||||
self.0.push(Frame::new(global_index, len, e, cp, n));
|
||||
|
||||
@@ -57,14 +57,6 @@ impl MachineState {
|
||||
(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)
|
||||
{
|
||||
for (h, _) in &self.attr_var_init.bindings {
|
||||
@@ -122,17 +114,17 @@ impl MachineState {
|
||||
|
||||
pub(super)
|
||||
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
|
||||
// self.b0 and self.num_of_args. why self.bo? if we return to a
|
||||
// NeckCut after finishing the interrupt, it won't
|
||||
// work correctly if self.b == self.b0. we must
|
||||
// change it back when we return, as if nothing happened.
|
||||
// store temp vars in perm vars slots along with self.b0 and
|
||||
// self.num_of_args. why self.b0? if we return to a NeckCut
|
||||
// after finishing the interrupt, it won't work correctly if
|
||||
// self.b == self.b0. we must change it back when we return,
|
||||
// as if nothing happened.
|
||||
self.allocate(rs + 2);
|
||||
|
||||
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 {
|
||||
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.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)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ impl CodeRepo {
|
||||
term_dir: TermDir::new()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
|
||||
self.term_dir.get(&key)
|
||||
@@ -105,6 +105,8 @@ impl CodeRepo {
|
||||
Some(RefOrOwned::Borrowed(&self.in_situ_code[p])),
|
||||
&CodePtr::Local(LocalCodePtr::DirEntry(p)) =>
|
||||
Some(RefOrOwned::Borrowed(&self.code[p])),
|
||||
&CodePtr::REPL(..) =>
|
||||
None,
|
||||
&CodePtr::BuiltInClause(ref built_in, _) => {
|
||||
let call_clause = call_clause!(ClauseType::BuiltIn(built_in.clone()),
|
||||
built_in.arity(),
|
||||
|
||||
@@ -123,6 +123,7 @@ fn compile_query(terms: Vec<QueryTerm>, queue: VecDeque<TopLevel>, flags: Machin
|
||||
let mut code = try!(cg.compile_query(&terms));
|
||||
|
||||
compile_appendix(&mut code, &queue, false, flags)?;
|
||||
|
||||
Ok((code, cg.take_vars()))
|
||||
}
|
||||
|
||||
@@ -214,7 +215,8 @@ fn setup_module_expansions(wam: &mut Machine, module_name: ClauseName)
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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,
|
||||
module_name: ClauseName, src: R, mut indices: IndexStore)
|
||||
module_name: ClauseName, src: ParsingStream<R>,
|
||||
mut indices: IndexStore)
|
||||
-> Result<(), SessionError>
|
||||
{
|
||||
setup_module_expansions(wam, module_name.clone());
|
||||
@@ -556,7 +559,7 @@ impl ListingCompiler {
|
||||
let spec = get_desc(op_decl.name(), composite_op!(self.module.is_some(),
|
||||
&wam_indices.op_dir,
|
||||
&mut indices.op_dir));
|
||||
|
||||
|
||||
op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir)
|
||||
},
|
||||
Declaration::UseModule(name) =>
|
||||
@@ -597,12 +600,13 @@ impl ListingCompiler {
|
||||
}
|
||||
|
||||
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>
|
||||
{
|
||||
let flags = wam.machine_flags();
|
||||
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.code_repo);
|
||||
|
||||
@@ -649,8 +653,8 @@ impl ListingCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine, src: R,
|
||||
mut indices: IndexStore)
|
||||
fn compile_work<R: Read>(compiler: &mut ListingCompiler, wam: &mut Machine,
|
||||
src: ParsingStream<R>, mut indices: IndexStore)
|
||||
-> EvalSession
|
||||
{
|
||||
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
|
||||
compiling code composing special forms, ie. the code that calls
|
||||
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());
|
||||
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]
|
||||
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);
|
||||
|
||||
@@ -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());
|
||||
try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices));
|
||||
compile_listing(wam, src, indices)
|
||||
|
||||
@@ -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() {
|
||||
"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 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;
|
||||
|
||||
if let EvalSession::Error(err) = result {
|
||||
|
||||
@@ -2,6 +2,7 @@ use prolog_parser::ast::*;
|
||||
|
||||
use prolog::machine::machine_indices::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
pub struct Heap {
|
||||
@@ -21,6 +22,17 @@ impl Heap {
|
||||
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]
|
||||
pub fn truncate(&mut self, h: usize) {
|
||||
self.h = h;
|
||||
|
||||
@@ -385,8 +385,6 @@ pub enum SessionError {
|
||||
NamelessEntry,
|
||||
OpIsInfixAndPostFix(ClauseName),
|
||||
ParserError(ParserError),
|
||||
QueryFailure,
|
||||
QueryFailureWithException(ClauseName),
|
||||
UserPrompt
|
||||
}
|
||||
|
||||
@@ -394,6 +392,7 @@ pub enum EvalSession {
|
||||
EntrySuccess,
|
||||
Error(SessionError),
|
||||
InitialQuerySuccess(AllocVarDict, HeapVarDict),
|
||||
QueryFailure,
|
||||
SubsequentQuerySuccess,
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
type Output = Addr;
|
||||
|
||||
@@ -260,13 +278,20 @@ pub enum DynamicTransactionType {
|
||||
Retract // dynamic index of the clause to remove.
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum REPLCodePtr {
|
||||
CompileBatch,
|
||||
SubmitQueryAndPrintResults
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum CodePtr {
|
||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||
CallN(usize, LocalCodePtr), // arity, local.
|
||||
Local(LocalCodePtr),
|
||||
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
|
||||
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
|
||||
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
|
||||
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
|
||||
}
|
||||
|
||||
impl CodePtr {
|
||||
@@ -276,7 +301,8 @@ impl CodePtr {
|
||||
| &CodePtr::CallN(_, ref local)
|
||||
| &CodePtr::Local(ref local) => local.clone(),
|
||||
&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 {
|
||||
match self {
|
||||
p @ CodePtr::VerifyAttrInterrupt(_)
|
||||
p @ CodePtr::REPL(..)
|
||||
| p @ CodePtr::VerifyAttrInterrupt(_)
|
||||
| p @ CodePtr::DynamicTransaction(..) => p,
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::CallN(_, local) | CodePtr::BuiltInClause(_, local) => CodePtr::Local(local + rhs)
|
||||
@@ -412,7 +439,7 @@ pub struct IndexStore {
|
||||
pub(super) global_variables: GlobalVarDir,
|
||||
pub(super) in_situ_code_dir: InSituCodeDir,
|
||||
pub(super) modules: ModuleDir,
|
||||
pub(super) op_dir: OpDir,
|
||||
pub(super) op_dir: OpDir,
|
||||
}
|
||||
|
||||
impl IndexStore {
|
||||
@@ -475,6 +502,7 @@ impl IndexStore {
|
||||
in_situ_code_dir: InSituCodeDir::new(),
|
||||
op_dir: default_op_dir(),
|
||||
modules: ModuleDir::new(),
|
||||
// parsing_stream: readline::parsing_stream(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,13 @@ use prolog::machine::machine_indices::*;
|
||||
use prolog::machine::modules::*;
|
||||
use prolog::machine::or_stack::*;
|
||||
use prolog::num::{BigInt, BigUint, Zero, One};
|
||||
use prolog::read::{PrologStream, readline};
|
||||
|
||||
use downcast::Any;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::io::{Write, stdin, stdout};
|
||||
use std::mem::swap;
|
||||
use std::io::{Write, stdout};
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -35,6 +36,16 @@ impl Ball {
|
||||
self.boundary = 0;
|
||||
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> {
|
||||
@@ -88,7 +99,7 @@ pub(super) struct CopyBallTerm<'a> {
|
||||
and_stack: &'a mut AndStack,
|
||||
heap: &'a mut Heap,
|
||||
heap_boundary: usize,
|
||||
stub: &'a mut MachineStub,
|
||||
stub: &'a mut MachineStub,
|
||||
}
|
||||
|
||||
impl<'a> CopyBallTerm<'a> {
|
||||
@@ -227,7 +238,7 @@ pub struct MachineState {
|
||||
pub(crate) flags: MachineFlags
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
impl MachineState {
|
||||
fn call_at_index(&mut self, arity: usize, p: usize)
|
||||
{
|
||||
self.cp.assign_if_local(self.p.clone() + 1);
|
||||
@@ -518,7 +529,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
|
||||
fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
|
||||
indices: &mut IndexStore)
|
||||
indices: &mut IndexStore, parsing_stream: &mut PrologStream)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
@@ -572,10 +583,12 @@ pub(crate) trait CallPolicy: Any {
|
||||
return_from_clause!(machine_st.last_call, machine_st)
|
||||
},
|
||||
&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) => {
|
||||
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) => {
|
||||
let h = machine_st.heap.h;
|
||||
@@ -695,7 +708,8 @@ pub(crate) trait CallPolicy: Any {
|
||||
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
|
||||
{
|
||||
if let Some((name, arity)) = machine_st.setup_call_n(arity) {
|
||||
@@ -711,7 +725,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
},
|
||||
ClauseType::BuiltIn(built_in) => {
|
||||
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) => {
|
||||
machine_st.execute_inlined(&inlined);
|
||||
@@ -781,17 +795,18 @@ impl CallPolicy for CWILCallPolicy {
|
||||
}
|
||||
|
||||
fn call_builtin(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType,
|
||||
indices: &mut IndexStore)
|
||||
indices: &mut IndexStore, parsing_stream: &mut PrologStream)
|
||||
-> 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)
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
self.prev_policy.call_n(machine_st, arity, indices)?;
|
||||
self.prev_policy.call_n(machine_st, arity, indices, parsing_stream)?;
|
||||
self.increment(machine_st)
|
||||
}
|
||||
}
|
||||
@@ -813,7 +828,7 @@ impl CWILCallPolicy {
|
||||
pub(crate) fn new_in_place(policy: &mut Box<CallPolicy>)
|
||||
{
|
||||
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,
|
||||
count: BigUint::zero(),
|
||||
@@ -870,7 +885,7 @@ impl CWILCallPolicy {
|
||||
|
||||
pub(crate) fn into_inner(&mut self) -> Box<CallPolicy> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ use prolog::machine::machine_state::*;
|
||||
use prolog::num::{Integer, Signed, ToPrimitive, One, Zero};
|
||||
use prolog::num::bigint::{BigInt, BigUint};
|
||||
use prolog::num::rational::Ratio;
|
||||
use prolog::read::PrologStream;
|
||||
|
||||
use std::cmp::{max, Ordering};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
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)]
|
||||
pub fn print_heap(&self) {
|
||||
for h in 0 .. self.heap.h {
|
||||
@@ -182,19 +214,6 @@ impl MachineState {
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
fn heap_ball_boundary_diff(&self) -> usize {
|
||||
if self.ball.boundary > self.heap.h {
|
||||
self.ball.boundary - self.heap.h
|
||||
} else {
|
||||
self.heap.h - self.ball.boundary
|
||||
}
|
||||
fn heap_ball_boundary_diff(&self) -> i64 {
|
||||
self.ball.boundary as i64 - self.heap.h as i64
|
||||
}
|
||||
|
||||
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 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();
|
||||
|
||||
self.heap.push(match heap_value {
|
||||
stub.push(match heap_value {
|
||||
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr - diff),
|
||||
_ => heap_value
|
||||
});
|
||||
}
|
||||
|
||||
diff
|
||||
stub
|
||||
}
|
||||
|
||||
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,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
parsing_stream: &mut PrologStream,
|
||||
ct: &ClauseType,
|
||||
arity: usize,
|
||||
lco: bool,
|
||||
@@ -2379,9 +2396,9 @@ impl MachineState {
|
||||
|
||||
match 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 =>
|
||||
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) =>
|
||||
try_or_fail!(self, call_policy.compile_hook(self, hook)),
|
||||
&ClauseType::Inlined(ref ct) => {
|
||||
@@ -2395,13 +2412,15 @@ impl MachineState {
|
||||
try_or_fail!(self, call_policy.context_call(self, name.clone(), arity, idx.clone(),
|
||||
indices)),
|
||||
&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,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
parsing_stream: &mut PrologStream,
|
||||
instr: &ControlInstruction)
|
||||
{
|
||||
match instr {
|
||||
@@ -2409,7 +2428,8 @@ impl MachineState {
|
||||
self.allocate(num_cells),
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) =>
|
||||
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::JmpBy(arity, offset, _, lco) => {
|
||||
if !lco {
|
||||
@@ -2569,4 +2589,58 @@ impl MachineState {
|
||||
self.ball.reset();
|
||||
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![]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use prolog::fixtures::*;
|
||||
use prolog::forms::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::instructions::*;
|
||||
use prolog::read::*;
|
||||
use prolog::write::{ContinueResult, next_keypress};
|
||||
|
||||
pub mod machine_indices;
|
||||
pub mod heap;
|
||||
@@ -32,12 +34,17 @@ use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_indices::*;
|
||||
use prolog::machine::machine_state::*;
|
||||
use prolog::machine::modules::*;
|
||||
use prolog::machine::toplevel::stream_to_toplevel;
|
||||
use prolog::read::PrologStream;
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::io::{Read, Write, stdout};
|
||||
use std::mem;
|
||||
use std::ops::Index;
|
||||
use std::rc::Rc;
|
||||
|
||||
use termion::raw::{IntoRawMode};
|
||||
|
||||
pub struct MachinePolicies {
|
||||
call_policy: Box<CallPolicy>,
|
||||
cut_policy: Box<CutPolicy>,
|
||||
@@ -57,7 +64,9 @@ pub struct Machine {
|
||||
pub(super) machine_st: MachineState,
|
||||
pub(super) policies: MachinePolicies,
|
||||
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 {
|
||||
@@ -157,9 +166,11 @@ static REIF: &str = include_str!("../lib/reif.pl");
|
||||
static ASSOC: &str = include_str!("../lib/assoc.pl");
|
||||
static ORDSETS: &str = include_str!("../lib/ordsets.pl");
|
||||
|
||||
static TOPLEVEL: &str = include_str!("../toplevel.pl");
|
||||
|
||||
impl Machine {
|
||||
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) => {
|
||||
self.machine_st.attr_var_init.verify_attrs_loc = self.code_repo.code.len();
|
||||
self.code_repo.code.extend(code.into_iter());
|
||||
@@ -167,7 +178,7 @@ impl Machine {
|
||||
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) => {
|
||||
self.machine_st.attr_var_init.project_attrs_loc = self.code_repo.code.len();
|
||||
self.code_repo.code.extend(code.into_iter());
|
||||
@@ -176,37 +187,57 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_libraries(&mut self) {
|
||||
compile_user_module(self, NON_ISO.as_bytes());
|
||||
compile_user_module(self, LISTS.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());
|
||||
fn compile_top_level(&mut self) {
|
||||
self.toplevel_idx = self.code_repo.code.len();
|
||||
compile_user_module(self, parsing_stream(TOPLEVEL.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 {
|
||||
machine_st: MachineState::new(),
|
||||
policies: MachinePolicies::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();
|
||||
|
||||
compile_listing(&mut wam, BUILTINS.as_bytes(),
|
||||
compile_listing(&mut wam, parsing_stream(BUILTINS.as_bytes()),
|
||||
default_index_store!(atom_tbl.clone()));
|
||||
|
||||
wam.compile_libraries();
|
||||
wam.compile_special_forms();
|
||||
wam.compile_top_level();
|
||||
|
||||
wam
|
||||
}
|
||||
@@ -251,7 +282,7 @@ impl Machine {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir)
|
||||
{
|
||||
// error detection has finished, so update the master index of keys.
|
||||
@@ -283,33 +314,15 @@ impl Machine {
|
||||
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
|
||||
{
|
||||
let mut heap_locs = HashMap::new();
|
||||
let mut heap_locs = HeapVarDict::new();
|
||||
|
||||
self.code_repo.cached_query = code;
|
||||
self.run_query(&alloc_locs, &mut heap_locs);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail()
|
||||
EvalSession::QueryFailure
|
||||
} else {
|
||||
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)
|
||||
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.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 {
|
||||
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) => {
|
||||
// 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.
|
||||
@@ -399,21 +603,22 @@ impl Machine {
|
||||
self.machine_st.p = self.machine_st.or_stack[b].bp.clone();
|
||||
|
||||
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);
|
||||
|
||||
if self.machine_st.fail {
|
||||
self.fail()
|
||||
EvalSession::QueryFailure
|
||||
} else {
|
||||
EvalSession::SubsequentQuerySuccess
|
||||
}
|
||||
} else {
|
||||
EvalSession::from(SessionError::QueryFailure)
|
||||
EvalSession::QueryFailure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn toplevel_heap_view<Outputter>(&self, var_dir: &HeapVarDict, mut output: Outputter) -> Outputter
|
||||
where Outputter: HCValueOutputter
|
||||
{
|
||||
@@ -422,11 +627,6 @@ impl Machine {
|
||||
|
||||
for (var, addr) in sorted_vars {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -450,22 +650,12 @@ impl Machine {
|
||||
pub fn or_stack_is_empty(&self) -> bool {
|
||||
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 {
|
||||
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) {
|
||||
Some(instr) => instr,
|
||||
@@ -481,7 +671,8 @@ impl MachineState {
|
||||
self.execute_cut_instr(cut_instr, &mut policies.cut_policy),
|
||||
&Line::Control(ref control_instr) =>
|
||||
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) => {
|
||||
self.execute_fact_instr(&fact_instr);
|
||||
self.p += 1;
|
||||
@@ -516,10 +707,10 @@ impl MachineState {
|
||||
}
|
||||
|
||||
fn query_stepper(&mut self, indices: &mut IndexStore, policies: &mut MachinePolicies,
|
||||
code_repo: &mut CodeRepo)
|
||||
code_repo: &mut CodeRepo, prolog_stream: &mut PrologStream)
|
||||
{
|
||||
loop {
|
||||
self.execute_instr(indices, policies, code_repo);
|
||||
self.execute_instr(indices, policies, code_repo, prolog_stream);
|
||||
|
||||
if self.fail {
|
||||
self.backtrack();
|
||||
@@ -538,7 +729,7 @@ impl MachineState {
|
||||
self.fail = true,
|
||||
CodePtr::Local(LocalCodePtr::InSituDirEntry(p))
|
||||
if p < code_repo.in_situ_code.len() => {},
|
||||
CodePtr::Local(_) =>
|
||||
CodePtr::Local(_) | CodePtr::REPL(..) =>
|
||||
break,
|
||||
CodePtr::VerifyAttrInterrupt(p) =>
|
||||
self.verify_attr_interrupt(p),
|
||||
@@ -546,7 +737,7 @@ impl MachineState {
|
||||
// prevent use of dynamic transactions from
|
||||
// succeeding in expansions. this will be toggled
|
||||
// back to true later.
|
||||
self.fail = true;
|
||||
self.fail = true;
|
||||
break;
|
||||
},
|
||||
_ => {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use prolog::machine::machine_indices::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
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));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn take(&mut self) -> Self {
|
||||
OrStack(mem::replace(&mut self.0, vec![]))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@ use prolog::machine::machine_state::*;
|
||||
use prolog::machine::toplevel::to_op_decl;
|
||||
use prolog::num::{FromPrimitive, ToPrimitive, Zero};
|
||||
use prolog::num::bigint::{BigInt};
|
||||
use prolog::read::{PrologStream, readline};
|
||||
|
||||
use ref_thread_local::RefThreadLocal;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::io::{stdout, Read, Write};
|
||||
use std::io::{stdout, Write};
|
||||
use std::iter::once;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
@@ -201,6 +202,17 @@ impl MachineState {
|
||||
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)
|
||||
where AddrConstr: Fn(usize) -> Addr
|
||||
{
|
||||
@@ -301,7 +313,8 @@ impl MachineState {
|
||||
ct: &SystemClauseType,
|
||||
indices: &mut IndexStore,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>)
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
parsing_stream: &mut PrologStream)
|
||||
-> CallResult
|
||||
{
|
||||
match ct {
|
||||
@@ -498,7 +511,7 @@ impl MachineState {
|
||||
},
|
||||
ref addr if addr.is_ref() => {
|
||||
let a2 = self[temp_v!(2)].clone();
|
||||
|
||||
|
||||
match self.store(self.deref(a2)) {
|
||||
Addr::Con(Constant::CharCode(code)) =>
|
||||
self.unify(Addr::Con(Constant::Char(code as char)), addr.clone()),
|
||||
@@ -542,23 +555,21 @@ impl MachineState {
|
||||
};
|
||||
},
|
||||
&SystemClauseType::GetChar => {
|
||||
let c = std::io::stdin()
|
||||
.bytes()
|
||||
.next()
|
||||
.and_then(|result| result.ok());
|
||||
readline::toggle_prompt(false);
|
||||
|
||||
let result = parsing_stream.next();
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
|
||||
match c {
|
||||
Some(c) => self.unify(Addr::Con(Constant::Char(c as char)), a1),
|
||||
None => {
|
||||
|
||||
match result {
|
||||
Some(Ok(b)) => self.unify(Addr::Con(Constant::Char(b as char)), a1),
|
||||
_ => {
|
||||
let stub = MachineError::functor_stub(clause_name!("get_char"), 1);
|
||||
let err = MachineError::representation_error(RepFlag::Character);
|
||||
let err = self.error_form(err, stub);
|
||||
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
&SystemClauseType::GetModuleClause => {
|
||||
let module = self[temp_v!(3)].clone();
|
||||
@@ -1228,6 +1239,8 @@ impl MachineState {
|
||||
None => panic!("remove_inference_counter: requires \\
|
||||
CWILCallPolicy.")
|
||||
},
|
||||
&SystemClauseType::REPL(repl_code_ptr) =>
|
||||
return self.repl_redirect(repl_code_ptr),
|
||||
&SystemClauseType::ModuleRetractClause => {
|
||||
let p = self.cp;
|
||||
let trans_type = DynamicTransactionType::ModuleRetract;
|
||||
@@ -1249,7 +1262,6 @@ impl MachineState {
|
||||
},
|
||||
&SystemClauseType::ReturnFromVerifyAttr => {
|
||||
let e = self.e;
|
||||
|
||||
let frame_len = self.and_stack[e].len();
|
||||
|
||||
for i in 1 .. frame_len - 1 {
|
||||
@@ -1264,7 +1276,7 @@ impl MachineState {
|
||||
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();
|
||||
|
||||
return Ok(());
|
||||
@@ -1334,7 +1346,8 @@ impl MachineState {
|
||||
let h = self.heap.h;
|
||||
|
||||
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 {
|
||||
self.fail = true;
|
||||
return Ok(());
|
||||
@@ -1391,6 +1404,51 @@ impl MachineState {
|
||||
&SystemClauseType::InstallNewBlock => {
|
||||
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 => {
|
||||
let addr = self.deref(self[temp_v!(1)].clone());
|
||||
self.reset_block(addr);
|
||||
@@ -1414,43 +1472,19 @@ impl MachineState {
|
||||
&SystemClauseType::Succeed => {},
|
||||
&SystemClauseType::TermVariables => {
|
||||
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();
|
||||
|
||||
for r in vars {
|
||||
if seen_vars.contains(&r) {
|
||||
continue;
|
||||
for item in self.acyclic_pre_order_iter(a1) {
|
||||
match item {
|
||||
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();
|
||||
self.unify(a2, outcome);
|
||||
|
||||
@@ -4,7 +4,6 @@ use prolog_parser::parser::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::machine::machine_indices::HeapCellValue;
|
||||
use prolog::num::*;
|
||||
use prolog::read::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
@@ -74,7 +73,7 @@ pub struct TermStream<'a, R: Read> {
|
||||
pub(crate) indices: &'a mut IndexStore,
|
||||
policies: &'a mut MachinePolicies,
|
||||
pub(crate) code_repo: &'a mut CodeRepo,
|
||||
parser: Parser<R>,
|
||||
parser: Parser<'a, R>,
|
||||
in_module: bool,
|
||||
pub(crate) flags: MachineFlags,
|
||||
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> {
|
||||
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,
|
||||
code_repo: &'a mut CodeRepo)
|
||||
-> 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]
|
||||
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
|
||||
match hook {
|
||||
@@ -185,14 +189,16 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
},
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
|
||||
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>
|
||||
{
|
||||
let mut parser = Parser::new(term_string.trim().as_bytes(), self.parser.get_atom_tbl(),
|
||||
self.flags);
|
||||
let mut stream = parsing_stream(term_string.trim().as_bytes());
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -230,24 +236,23 @@ impl<'a, R: Read> TermStream<'a, R> {
|
||||
match term {
|
||||
Term::Clause(cell, name, mut terms, arity) => {
|
||||
let mut new_terms = {
|
||||
let old_terms = if name.as_str() == ":-" && terms.len() == 2 {
|
||||
let comma_term = *terms.pop().unwrap();
|
||||
unfold_by_str(comma_term, ",")
|
||||
} else if name.as_str() == "?-" && terms.len() == 1 {
|
||||
let comma_term = *terms.pop().unwrap();
|
||||
unfold_by_str(comma_term, ",")
|
||||
} else {
|
||||
return Ok(Term::Clause(cell, name, terms, arity));
|
||||
let old_terms = match (name.as_str(), terms.len()) {
|
||||
(":-", 2) => {
|
||||
let comma_term = *terms.pop().unwrap();
|
||||
unfold_by_str(comma_term, ",")
|
||||
},
|
||||
("?-", 1) =>
|
||||
unfold_by_str(*terms.pop().unwrap(), ","),
|
||||
_ => return Ok(Term::Clause(cell, name, terms, arity))
|
||||
};
|
||||
|
||||
self.expand_goals(machine_st, op_dir, VecDeque::from(old_terms))?
|
||||
};
|
||||
|
||||
let initial_term = new_terms.pop().unwrap();
|
||||
|
||||
terms.push(Box::new(fold_by_str(new_terms.into_iter(), initial_term,
|
||||
clause_name!(","))));
|
||||
Ok(Term::Clause(cell, name, terms, None))
|
||||
Ok(Term::Clause(cell, name, terms, arity))
|
||||
},
|
||||
_ =>
|
||||
Ok(term)
|
||||
@@ -302,6 +307,8 @@ impl MachineState {
|
||||
// style variable names will be longer than the keys of the var_dict, and therefore
|
||||
// not equal to any of them.
|
||||
printer.numbervars_offset = pow(BigInt::from(10), max_var_length) * 26;
|
||||
printer.drop_toplevel_spec();
|
||||
|
||||
printer.see_all_locs();
|
||||
|
||||
let mut output = printer.print(addr);
|
||||
@@ -324,7 +331,7 @@ impl MachineState {
|
||||
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
||||
|
||||
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 {
|
||||
self.reset();
|
||||
|
||||
@@ -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)
|
||||
-> Result<TopLevel, ParserError>
|
||||
{
|
||||
@@ -692,13 +704,7 @@ impl RelationWorker {
|
||||
|
||||
Ok(TopLevel::Declaration(Declaration::Hook(hook, clause, queue)))
|
||||
} else if name.as_str() == "?-" {
|
||||
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)?))
|
||||
self.try_term_to_query(indices, terms, blocks_cuts)
|
||||
} else if name.as_str() == ":-" && terms.len() == 2 {
|
||||
Ok(TopLevel::Rule(self.setup_rule(indices, terms, blocks_cuts, true)?))
|
||||
} 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 tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
|
||||
|
||||
Ok((tl, rel_worker))
|
||||
}
|
||||
|
||||
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,
|
||||
&mut wam.policies, &mut wam.code_repo);
|
||||
|
||||
term_stream.add_to_top("?- ");
|
||||
|
||||
let term = term_stream.read_term(&OpDir::new())?;
|
||||
let mut code_dir = CodeDir::new();
|
||||
|
||||
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())?;
|
||||
|
||||
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> {
|
||||
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,
|
||||
policies: &'a mut MachinePolicies, code_repo: &'a mut CodeRepo)
|
||||
-> Self
|
||||
|
||||
@@ -4,7 +4,6 @@ use prolog_parser::tabled_rc::TabledData;
|
||||
|
||||
use prolog::forms::*;
|
||||
use prolog::iterators::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_indices::*;
|
||||
use prolog::machine::machine_state::MachineState;
|
||||
|
||||
@@ -24,16 +23,14 @@ impl<'a> TermRef<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Input {
|
||||
Clear,
|
||||
Batch,
|
||||
TermString(String)
|
||||
}
|
||||
pub type PrologStream = ParsingStream<Box<Read>>;
|
||||
|
||||
#[cfg(feature = "readline_rs_compat")]
|
||||
pub mod readline
|
||||
{
|
||||
use prolog_parser::ast::*;
|
||||
use readline_rs_compat::readline::*;
|
||||
use std::io::{Error, Read};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum LineMode {
|
||||
@@ -41,9 +38,74 @@ pub mod readline
|
||||
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 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) {
|
||||
unsafe {
|
||||
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 {
|
||||
if let LineMode::Multi = LINE_MODE {
|
||||
rl_done = 1;
|
||||
@@ -67,26 +122,9 @@ pub mod readline
|
||||
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 {
|
||||
if END_OF_LINE {
|
||||
if let Some(buf) = rl_line_buffer_as_str() {
|
||||
if is_directive(buf) {
|
||||
println!("");
|
||||
rl_done = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if let LineMode::Single = LINE_MODE {
|
||||
insert_text_rl("\n");
|
||||
println!("");
|
||||
rl_done = 1;
|
||||
} else {
|
||||
@@ -103,24 +141,11 @@ pub mod readline
|
||||
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('\r' as i32, bind_cr);
|
||||
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> {
|
||||
match readline_rl(prompt) {
|
||||
Some(input) => Ok(Vec::from(input.as_bytes())),
|
||||
@@ -128,18 +153,41 @@ pub mod readline
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_line(prompt: &str) -> Result<String, ::SessionError> {
|
||||
match readline_rl(prompt) {
|
||||
Some(input) => Ok(String::from(input)),
|
||||
None => Err(::SessionError::UserPrompt)
|
||||
}
|
||||
#[inline]
|
||||
pub fn input_stream() -> ::PrologStream {
|
||||
let reader: Box<Read> = Box::new(ReadlineStream::new(String::from("")));
|
||||
parsing_stream(reader)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "readline_rs_compat"))]
|
||||
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> {
|
||||
let mut buf = vec![];
|
||||
@@ -153,54 +201,30 @@ pub mod readline
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_line(_: &str) -> Result<String, ::SessionError> {
|
||||
print!("?- ");
|
||||
stdout().flush().unwrap();
|
||||
#[inline]
|
||||
pub fn input_stream() -> ::PrologStream {
|
||||
print_prompt();
|
||||
|
||||
let stdin = stdin();
|
||||
let stdin = stdin.lock();
|
||||
let reader: Box<Read> = Box::new(StdinWrapper { buf: BufReader::new(stdin()) });
|
||||
parsing_stream(reader)
|
||||
}
|
||||
|
||||
let mut buf = "?- ".to_string();
|
||||
|
||||
for line in stdin.lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
buf += &line;
|
||||
|
||||
if line.trim().ends_with(".") {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => return Err(::SessionError::UserPrompt)
|
||||
}
|
||||
pub fn toggle_prompt(on_or_off: bool) {
|
||||
unsafe {
|
||||
PRINT_PROMPT = on_or_off;
|
||||
}
|
||||
|
||||
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 {
|
||||
pub fn read<R: Read>(&mut self, inner: R, atom_tbl: TabledData<Atom>, op_dir: &OpDir)
|
||||
-> Result<usize, ParserError>
|
||||
pub fn read(&mut self, inner: &mut PrologStream, atom_tbl: TabledData<Atom>, op_dir: &OpDir)
|
||||
-> Result<TermWriteResult, ParserError>
|
||||
{
|
||||
let mut parser = Parser::new(inner, atom_tbl, self.flags);
|
||||
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) 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;
|
||||
|
||||
|
||||
19
src/prolog/toplevel.pl
Normal file
19
src/prolog/toplevel.pl
Normal 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.
|
||||
@@ -1,22 +1,16 @@
|
||||
use prolog::clause_types::*;
|
||||
use prolog::forms::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::instructions::*;
|
||||
use prolog::machine::*;
|
||||
use prolog::machine::machine_errors::*;
|
||||
use prolog::machine::machine_indices::*;
|
||||
|
||||
use termion::raw::{IntoRawMode, RawTerminal};
|
||||
use termion::input::TermRead;
|
||||
use termion::event::Key;
|
||||
use termion::raw::{RawTerminal};
|
||||
|
||||
use std::io::{Write, stdin, stdout};
|
||||
use std::io::{Write, stdin};
|
||||
use std::fmt;
|
||||
|
||||
fn error_string<StringT: AsRef<str>>(e: &StringT) -> String {
|
||||
format!("error: exception thrown: {}", e.as_ref())
|
||||
}
|
||||
|
||||
impl fmt::Display for LocalCodePtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
@@ -262,10 +267,6 @@ impl fmt::Display for SessionError {
|
||||
&SessionError::ModuleNotFound => write!(f, "module not found."),
|
||||
&SessionError::ModuleDoesNotContainExport =>
|
||||
write!(f, "module does not contain claimed export."),
|
||||
&SessionError::QueryFailure =>
|
||||
write!(f, "false."),
|
||||
&SessionError::QueryFailureWithException(ref e) =>
|
||||
write!(f, "{}", error_string(e)),
|
||||
&SessionError::OpIsInfixAndPostFix(_) =>
|
||||
write!(f, "cannot define an op to be both postfix and infix."),
|
||||
&SessionError::NamelessEntry =>
|
||||
@@ -302,7 +303,7 @@ impl fmt::Display for ArithmeticInstruction {
|
||||
&ArithmeticInstruction::Pow(ref a1, ref a2, ref t) =>
|
||||
write!(f, "** {}, {}, @{}", a1, a2, t),
|
||||
&ArithmeticInstruction::IntPow(ref a1, ref a2, ref t) =>
|
||||
write!(f, "^ {}, {}, @{}", a1, a2, t),
|
||||
write!(f, "^ {}, {}, @{}", a1, a2, t),
|
||||
&ArithmeticInstruction::Div(ref a1, ref a2, ref t) =>
|
||||
write!(f, "div {}, {}, @{}", a1, a2, t),
|
||||
&ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) =>
|
||||
@@ -357,12 +358,13 @@ impl fmt::Display for Level {
|
||||
}
|
||||
}
|
||||
|
||||
enum ContinueResult {
|
||||
pub enum ContinueResult {
|
||||
ContinueQuery,
|
||||
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();
|
||||
|
||||
@@ -382,81 +384,3 @@ fn next_step(mut stdout: RawTerminal<std::io::Stdout>) -> ContinueResult
|
||||
|
||||
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),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
1709
src/tests.rs
1709
src/tests.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user