read from streams.
This commit is contained in:
@@ -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]
|
||||||
|
|||||||
49
src/main.rs
49
src/main.rs
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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)),
|
||||||
|
|||||||
@@ -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]))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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![]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
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::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),
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
1701
src/tests.rs
1701
src/tests.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user