adapt write_term family, add handling for EOF actions.
This commit is contained in:
@@ -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).
|
||||||
|
|||||||
@@ -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!(),
|
_ => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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()));
|
||||||
|
|||||||
Reference in New Issue
Block a user