adapt write_term family, add handling for EOF actions.

This commit is contained in:
Mark Thom
2020-05-04 21:17:06 -06:00
parent 0d7a9f32d6
commit dd247cd541
5 changed files with 169 additions and 97 deletions

View File

@@ -124,21 +124,14 @@ read_term_from_chars(Chars, Term) :-
write_term_to_chars(_, Options, _) :- write_term_to_chars(_, Options, _) :-
var(Options), instantiation_error(write_term_to_chars/3). var(Options), instantiation_error(write_term_to_chars/3).
write_term_to_chars(Term, Options, Chars) :- write_term_to_chars(Term, Options, Chars) :-
'$skip_max_list'(_, -1, Options, Options0), builtins:parse_write_options(Options,
( var(Options0) -> [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames],
instantiation_error(write_term_to_chars/3) write_term_to_chars/3),
; nonvar(Chars) -> ( nonvar(Chars) ->
throw(error(uninstantiation_error(Chars), write_term_to_chars/3)) throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
; Options0 == [] ->
true
; ;
type_error(list, Options, write_term_to_chars/3) true
), ),
builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
builtins:inst_member_or(Options, quoted(Quoted), quoted(false)),
builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])),
builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
term_variables(Term, Vars), term_variables(Term, Vars),
extend_var_list(Vars, VarNames, NewVarNames, numbervars), extend_var_list(Vars, VarNames, NewVarNames, numbervars),
'$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth, Chars). '$write_term_to_chars'(Chars, Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth).

View File

@@ -619,100 +619,109 @@ impl MachineState {
stream: Stream, stream: Stream,
indices: &mut IndexStore, indices: &mut IndexStore,
) -> CallResult { ) -> CallResult {
let mut orig_stream = stream.clone();
let mut stream = self.open_parsing_stream(stream, "read_term", 3)?; let mut stream = self.open_parsing_stream(stream, "read_term", 3)?;
match self.read( loop {
&mut stream, match self.read(
indices.atom_tbl.clone(), &mut stream,
&indices.op_dir, indices.atom_tbl.clone(),
) { &indices.op_dir,
Ok(term_write_result) => { ) {
let term = self[temp_v!(2)]; Ok(term_write_result) => {
self.unify(Addr::HeapCell(term_write_result.heap_loc), term); let term = self[temp_v!(2)];
self.unify(Addr::HeapCell(term_write_result.heap_loc), term);
if self.fail { if self.fail {
return Ok(()); return Ok(());
} }
let mut list_of_var_eqs = vec![]; let mut list_of_var_eqs = vec![];
for (var, binding) in term_write_result.var_dict.into_iter() { for (var, binding) in term_write_result.var_dict.into_iter() {
let var_atom = clause_name!(var.to_string(), indices.atom_tbl); let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
let h = self.heap.h(); let h = self.heap.h();
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec)); self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
self.heap.push(HeapCellValue::Atom(var_atom, None)); self.heap.push(HeapCellValue::Atom(var_atom, None));
self.heap.push(HeapCellValue::Addr(binding)); self.heap.push(HeapCellValue::Addr(binding));
list_of_var_eqs.push(Addr::Str(h)); list_of_var_eqs.push(Addr::Str(h));
} }
let mut var_set: IndexMap<Ref, bool> = IndexMap::new(); let mut var_set: IndexMap<Ref, bool> = IndexMap::new();
for addr in self.acyclic_pre_order_iter(term) { for addr in self.acyclic_pre_order_iter(term) {
if let Some(var) = addr.as_var() { if let Some(var) = addr.as_var() {
if !var_set.contains_key(&var) { if !var_set.contains_key(&var) {
var_set.insert(var, true); var_set.insert(var, true);
} else { } else {
var_set.insert(var, false); var_set.insert(var, false);
}
} }
} }
}
let mut var_list = vec![]; let mut var_list = vec![];
let mut singleton_var_list = vec![]; let mut singleton_var_list = vec![];
for addr in self.acyclic_pre_order_iter(term) { for addr in self.acyclic_pre_order_iter(term) {
if let Some(var) = addr.as_var() { if let Some(var) = addr.as_var() {
if var_set.get(&var) == Some(&true) { if var_set.get(&var) == Some(&true) {
singleton_var_list.push(var.as_addr()); singleton_var_list.push(var.as_addr());
}
var_list.push(var.as_addr());
} }
var_list.push(var.as_addr());
} }
let singleton_addr = self[temp_v!(3)];
let singletons_offset =
Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter()));
self.unify(singletons_offset, singleton_addr);
if self.fail {
return Ok(());
}
let vars_addr = self[temp_v!(4)];
let vars_offset =
Addr::HeapCell(self.heap.to_list(var_list.into_iter()));
self.unify(vars_offset, vars_addr);
if self.fail {
return Ok(());
}
let var_names_addr = self[temp_v!(5)];
let var_names_offset =
Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
return Ok(self.unify(var_names_offset, var_names_addr));
} }
Err(err) => {
if let ParserError::UnexpectedEOF = err {
self.eof_action(
self[temp_v!(2)],
&mut orig_stream,
clause_name!("read_term"),
3
)?;
let singleton_addr = self[temp_v!(3)]; if orig_stream.options.eof_action == EOFAction::Reset {
let singletons_offset = if self.fail == false {
Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter())); continue;
} else {
return Ok(());
}
}
}
self.unify(singletons_offset, singleton_addr);
if self.fail {
return Ok(()); return Ok(());
} }
let vars_addr = self[temp_v!(4)];
let vars_offset =
Addr::HeapCell(self.heap.to_list(var_list.into_iter()));
self.unify(vars_offset, vars_addr);
if self.fail {
return Ok(());
}
let var_names_addr = self[temp_v!(5)];
let var_names_offset =
Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
Ok(self.unify(var_names_offset, var_names_addr))
}
Err(err) => {
if let ParserError::UnexpectedEOF = err {
std::process::exit(0);
}
// reset the input stream after an input failure.
//*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);
Err(self.error_form(syntax_error, stub))
} }
} }
} }
@@ -809,9 +818,11 @@ impl MachineState {
var_names.insert(var, atom); var_names.insert(var, atom);
} }
_ => unreachable!(), _ => {
}
}, },
_ => unreachable!(), _ => {
}
} }
} }

View File

@@ -1,16 +1,16 @@
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::prolog::read::PrologStream;
use crate::prolog::read::readline::*; use crate::prolog::read::readline::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
use crate::prolog::read::PrologStream;
use std::cell::RefCell; use std::cell::RefCell;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use std::fs::File; use std::fs::File;
use std::io::{stdout, Cursor, ErrorKind, Read, Write}; use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::net::TcpStream; use std::net::TcpStream;
use std::rc::Rc; use std::rc::Rc;
@@ -148,6 +148,9 @@ pub struct Stream {
impl From<TcpStream> for Stream { impl From<TcpStream> for Stream {
fn from(tcp_stream: TcpStream) -> Self { fn from(tcp_stream: TcpStream) -> Self {
tcp_stream.set_read_timeout(None).unwrap();
tcp_stream.set_write_timeout(None).unwrap();
Stream { Stream {
options: StreamOptions::default(), options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new( stream_inst: WrappedStreamInstance::new(
@@ -322,9 +325,70 @@ impl Stream {
} }
} }
} }
// returns true on success.
#[inline]
fn reset(&mut self) -> bool {
match *self.stream_inst.0.borrow_mut() {
StreamInstance::Bytes(ref mut cursor) => {
cursor.set_position(0);
true
}
StreamInstance::InputFile(ref mut file) => {
file.seek(SeekFrom::Start(0)).unwrap();
true
}
StreamInstance::ReadlineStream(ref mut stream) => {
*stream = ReadlineStream::new(String::new());
true
}
_ => {
false
}
}
}
} }
impl MachineState { impl MachineState {
#[inline]
pub(crate)
fn eof_action(
&mut self,
result: Addr,
stream: &mut Stream,
caller: ClauseName,
arity: usize,
) -> CallResult {
match stream.options.eof_action {
EOFAction::Error => {
let stub = MachineError::functor_stub(caller, arity);
let stream = vec![
HeapCellValue::Stream(stream.clone())
];
let err = MachineError::permission_error(
self.heap.h(),
Permission::InputStream,
"past_end_of_stream",
stream,
);
Err(self.error_form(err, stub))
}
EOFAction::EOFCode => {
let end_of_stream = self.heap.to_unifiable(
HeapCellValue::Atom(clause_name!("end_of_stream"), None)
);
Ok(self.unify(result, end_of_stream))
}
EOFAction::Reset => {
Ok(self.fail = !stream.reset())
}
}
}
pub(crate) pub(crate)
fn to_stream_options( fn to_stream_options(
&self, &self,
@@ -426,14 +490,13 @@ impl MachineState {
} }
None => { None => {
let stub = MachineError::functor_stub(clause_name!(caller), arity); let stub = MachineError::functor_stub(clause_name!(caller), arity);
let h = self.heap.h();
let addr = self.heap.to_unifiable( let addr = self.heap.to_unifiable(
HeapCellValue::Atom(atom.clone(), spec.clone()) HeapCellValue::Atom(atom.clone(), spec.clone())
); );
return Err(self.error_form( return Err(self.error_form(
MachineError::existence_error(h + 1, ExistenceError::Stream(addr)), MachineError::existence_error(self.heap.h(), ExistenceError::Stream(addr)),
stub, stub,
)); ));
} }
@@ -474,9 +537,9 @@ impl MachineState {
stub_name: &'static str, stub_name: &'static str,
stub_arity: usize, stub_arity: usize,
) -> Result<PrologStream, MachineStub> { ) -> Result<PrologStream, MachineStub> {
match parsing_stream(stream) { match parsing_stream(stream.clone()) {
Ok(stream) => { Ok(parsing_stream) => {
Ok(stream) Ok(parsing_stream)
} }
Err(e) => { Err(e) => {
let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity);

View File

@@ -3949,7 +3949,7 @@ impl MachineState {
stream.flush().unwrap(); stream.flush().unwrap();
} }
&SystemClauseType::WriteTermToChars => { &SystemClauseType::WriteTermToChars => {
let addr = self[temp_v!(1)]; let addr = self[temp_v!(2)];
let printer = let printer =
match self.write_term(&indices.op_dir)? { match self.write_term(&indices.op_dir)? {
@@ -3965,7 +3965,7 @@ impl MachineState {
let result = printer.print(addr).result(); let result = printer.print(addr).result();
let chars = self.heap.put_complete_string(&result); let chars = self.heap.put_complete_string(&result);
let result_addr = self.store(self.deref(self[temp_v!(7)])); let result_addr = self.store(self.deref(self[temp_v!(1)]));
if let Some(var) = result_addr.as_var() { if let Some(var) = result_addr.as_var() {
self.bind(var, chars); self.bind(var, chars);

View File

@@ -42,6 +42,11 @@ pub mod readline {
} }
impl ReadlineStream { impl ReadlineStream {
pub fn new(pending_input: String) -> Self {
let rl = Editor::<()>::new();
ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
}
pub fn input_stream(pending_input: String) -> Stream { pub fn input_stream(pending_input: String) -> Stream {
let mut rl = Editor::<()>::new(); let mut rl = Editor::<()>::new();
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string())); rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));