read from streams.

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

View File

@@ -130,7 +130,7 @@ ref_thread_local! {
m.insert(("partial_string", 2), ClauseType::BuiltIn(BuiltInClauseType::PartialString));
m.insert(("read", 1), ClauseType::BuiltIn(BuiltInClauseType::Read));
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
m
};
}
@@ -177,7 +177,7 @@ pub enum SystemClauseType {
FetchGlobalVar,
GetChar,
TruncateIfNoLiftedHeapGrowthDiff,
TruncateIfNoLiftedHeapGrowth,
TruncateIfNoLiftedHeapGrowth,
GetAttributedVariableList,
GetAttrVarQueueDelimiter,
GetAttrVarQueueBeyond,
@@ -201,6 +201,8 @@ pub enum SystemClauseType {
ModuleRetractClause,
NoSuchPredicate,
OpDeclaration,
REPL(REPLCodePtr),
ReadTerm,
RedoAttrVarBindings,
RemoveCallPolicyCheck,
RemoveInferenceCounter,
@@ -236,7 +238,7 @@ impl SystemClauseType {
pub fn name(&self) -> ClauseName {
match self {
&SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
@@ -246,6 +248,9 @@ impl SystemClauseType {
&SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
&SystemClauseType::CharCode => clause_name!("char_code"),
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) =>
clause_name!("$submit_query_and_print_results"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -296,6 +301,7 @@ impl SystemClauseType {
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
@@ -326,6 +332,7 @@ impl SystemClauseType {
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$char_code", 2) => Some(SystemClauseType::CharCode),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
@@ -375,6 +382,7 @@ impl SystemClauseType {
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
@@ -385,6 +393,8 @@ impl SystemClauseType {
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
("$submit_query_and_print_results", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults)),
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
@@ -397,7 +407,7 @@ impl SystemClauseType {
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum BuiltInClauseType {
AcyclicTerm,
Arg,
Arg,
Compare,
CompareTerm(CompareTermQT),
CyclicTerm,

View File

@@ -398,6 +398,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
printer
}
pub fn drop_toplevel_spec(&mut self) {
self.toplevel_spec = None;
}
#[inline]
pub fn see_all_locs(&mut self) {
for key in self.heap_locs.keys().cloned() {
@@ -559,8 +563,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
fn check_for_seen(&mut self, iter: &mut HCPreOrderIterator) -> Option<HeapCellValue>
{
iter.stack().last().cloned().and_then(|addr| {
let addr = self.machine_st.store(self.machine_st.deref(addr));
let addr = self.machine_st.store(self.machine_st.deref(addr));
match self.heap_locs.get(&addr).cloned() {
Some(var) => if !self.printed_vars.contains(&addr) {
self.printed_vars.insert(addr);

View File

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

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@ impl CodeRepo {
term_dir: TermDir::new()
}
}
#[inline]
pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
self.term_dir.get(&key)
@@ -105,6 +105,8 @@ impl CodeRepo {
Some(RefOrOwned::Borrowed(&self.in_situ_code[p])),
&CodePtr::Local(LocalCodePtr::DirEntry(p)) =>
Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::REPL(..) =>
None,
&CodePtr::BuiltInClause(ref built_in, _) => {
let call_clause = call_clause!(ClauseType::BuiltIn(built_in.clone()),
built_in.arity(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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