add flush_output/{0,1}, past_end_of_stream

This commit is contained in:
Mark Thom
2020-05-05 14:10:49 -06:00
parent ab62603c5a
commit 53ae8b9bd1
8 changed files with 110 additions and 116 deletions

View File

@@ -181,6 +181,7 @@ pub enum SystemClauseType {
FetchGlobalVar, FetchGlobalVar,
FetchGlobalVarWithOffset, FetchGlobalVarWithOffset,
FileToChars, FileToChars,
FlushOutput,
GetChar, GetChar,
GetSingleChar, GetSingleChar,
ResetAttrVarState, ResetAttrVarState,
@@ -325,6 +326,7 @@ impl SystemClauseType {
clause_name!("$fetch_global_var_with_offset") clause_name!("$fetch_global_var_with_offset")
} }
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"), &SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetChar => clause_name!("$get_char"), &SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"), &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"), &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
@@ -468,6 +470,7 @@ impl SystemClauseType {
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
("$current_input", 1) => Some(SystemClauseType::CurrentInput), ("$current_input", 1) => Some(SystemClauseType::CurrentInput),
("$current_output", 1) => Some(SystemClauseType::CurrentOutput), ("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
("$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),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),

View File

@@ -48,13 +48,14 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
current_op/3, current_predicate/1, current_op/3, current_predicate/1,
current_prolog_flag/2, expand_goal/2, current_prolog_flag/2, expand_goal/2,
expand_term/2, fail/0, false/0, findall/3, expand_term/2, fail/0, false/0, findall/3,
findall/4, get_char/1, halt/0, max_arity/1, findall/4, flush_output/0, flush_output/1,
number_chars/2, number_codes/2, once/1, op/3, get_char/1, halt/0, max_arity/1, number_chars/2,
open/3, open/4, read_term/2, read_term/3, number_codes/2, once/1, op/3, open/3, open/4,
repeat/0, retract/1, set_prolog_flag/2, read_term/2, read_term/3, repeat/0, retract/1,
set_input/1, set_output/1, setof/3, sub_atom/5, set_prolog_flag/2, set_input/1, set_output/1,
subsumes_term/2, term_variables/2, throw/1, setof/3, sub_atom/5, subsumes_term/2,
true/0, unify_with_occurs_check/2, write/1, term_variables/2, throw/1, true/0,
unify_with_occurs_check/2, write/1,
write_canonical/1, write_term/2, write_term/3, write_canonical/1, write_term/2, write_term/3,
writeq/1]). writeq/1]).
@@ -1180,4 +1181,12 @@ close(Stream, CloseOptions) :-
'$close'(Stream, CloseOptions). '$close'(Stream, CloseOptions).
close(Stream) :- close(Stream) :-
close(Stream, []). '$close'(Stream, []).
flush_output(S) :-
'$flush_output'(S).
flush_output :-
current_output(S),
'$flush_output'(S).

View File

@@ -1,6 +1,5 @@
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*; use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use std::mem; use std::mem;
use std::ops::IndexMut; use std::ops::IndexMut;
@@ -215,24 +214,6 @@ impl<T: CopierTarget> CopyTermState<T> {
} }
} }
fn copy_stream(&mut self, addr: usize) {
let threshold = self.target.threshold();
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Stream(threshold)),
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.target.push(HeapCellValue::Stream(Stream::null_stream()));
self.scan += 1;
}
fn copy_structure(&mut self, addr: usize) { fn copy_structure(&mut self, addr: usize) {
match self.target[addr].context_free_clone() { match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => { HeapCellValue::NamedStr(arity, name, fixity) => {
@@ -285,11 +266,12 @@ impl<T: CopierTarget> CopyTermState<T> {
*self.value_at_scan() = HeapCellValue::Addr(addr); *self.value_at_scan() = HeapCellValue::Addr(addr);
} }
} }
Addr::Lis(h) if h >= self.old_h => {
self.scan += 1;
}
Addr::Lis(h) => { Addr::Lis(h) => {
self.copy_list(h); if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
} }
addr @ Addr::AttrVar(_) | addr @ Addr::AttrVar(_) |
addr @ Addr::HeapCell(_) | addr @ Addr::HeapCell(_) |
@@ -303,7 +285,7 @@ impl<T: CopierTarget> CopyTermState<T> {
self.copy_partial_string(addr, n); self.copy_partial_string(addr, n);
} }
Addr::Stream(h) => { Addr::Stream(h) => {
self.copy_stream(h); *self.value_at_scan() = self.target[h].context_free_clone();
} }
_ => { _ => {
self.scan += 1; self.scan += 1;

View File

@@ -288,10 +288,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
HeapCellValue::Addr(addr) => { HeapCellValue::Addr(addr) => {
addr addr
} }
val @ HeapCellValue::Atom(..) val @ HeapCellValue::Atom(..) |
| val @ HeapCellValue::Integer(_) val @ HeapCellValue::Integer(_) |
| val @ HeapCellValue::DBRef(_) val @ HeapCellValue::DBRef(_) |
| val @ HeapCellValue::Rational(_) => { val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val)) Addr::Con(self.push(val))
} }
val @ HeapCellValue::NamedStr(..) => { val @ HeapCellValue::NamedStr(..) => {

View File

@@ -443,8 +443,8 @@ impl HeapCellValue {
&HeapCellValue::PartialString(ref pstr, has_tail) => { &HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail) HeapCellValue::PartialString(pstr.clone(), has_tail)
} }
&HeapCellValue::Stream(_) => { &HeapCellValue::Stream(ref stream) => {
HeapCellValue::Stream(Stream::null_stream()) HeapCellValue::Stream(stream.clone())
} }
&HeapCellValue::TcpListener(_) => { &HeapCellValue::TcpListener(_) => {
HeapCellValue::Atom(clause_name!("$socket_server"), None) HeapCellValue::Atom(clause_name!("$socket_server"), None)

View File

@@ -619,6 +619,32 @@ impl MachineState {
stream: Stream, stream: Stream,
indices: &mut IndexStore, indices: &mut IndexStore,
) -> CallResult { ) -> CallResult {
let opt_err =
if !stream.is_input_stream() {
Some("stream") // 8.14.2.3 g)
} else if stream.options.stream_type == StreamType::Binary {
Some("binary_stream") // 8.14.2.3 h)
} else {
None
};
if let Some(err_string) = opt_err {
let stub = MachineError::functor_stub(clause_name!("read_term"), 3);
let addr = vec![
HeapCellValue::Stream(stream)
];
let err = MachineError::permission_error(
self.heap.h(),
Permission::InputStream,
err_string,
addr,
);
return Err(self.error_form(err, stub));
}
let mut orig_stream = stream.clone(); 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)?;

View File

@@ -37,7 +37,6 @@ pub enum StreamInstance {
OutputFile(File), OutputFile(File),
Null, Null,
ReadlineStream(ReadlineStream), ReadlineStream(ReadlineStream),
// Stdin,
Stdout, Stdout,
TcpStream(TcpStream), TcpStream(TcpStream),
} }
@@ -154,6 +153,7 @@ impl Default for StreamOptions {
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub struct Stream { pub struct Stream {
past_end_of_stream: bool,
pub options: StreamOptions, pub options: StreamOptions,
stream_inst: WrappedStreamInstance, stream_inst: WrappedStreamInstance,
} }
@@ -172,45 +172,25 @@ impl From<TcpStream> for Stream {
tcp_stream.set_read_timeout(None).unwrap(); tcp_stream.set_read_timeout(None).unwrap();
tcp_stream.set_write_timeout(None).unwrap(); tcp_stream.set_write_timeout(None).unwrap();
Stream { Stream::from_inst(StreamInstance::TcpStream(tcp_stream))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::TcpStream(tcp_stream)
)
}
} }
} }
impl From<String> for Stream { impl From<String> for Stream {
fn from(string: String) -> Self { fn from(string: String) -> Self {
Stream { Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Bytes(Cursor::new(string.into_bytes()))
)
}
} }
} }
impl From<ReadlineStream> for Stream { impl From<ReadlineStream> for Stream {
fn from(rl_stream: ReadlineStream) -> Self { fn from(rl_stream: ReadlineStream) -> Self {
Stream { Stream::from_inst(StreamInstance::ReadlineStream(rl_stream))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::ReadlineStream(rl_stream)
),
}
} }
} }
impl From<&'static str> for Stream { impl From<&'static str> for Stream {
fn from(src: &'static str) -> Stream { fn from(src: &'static str) -> Stream {
Stream { Stream::from_inst(StreamInstance::DynReadSource(Box::new(src.as_bytes())))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::DynReadSource(Box::new(src.as_bytes()))
),
}
} }
} }
@@ -229,61 +209,31 @@ impl Stream {
ptr as *const u8 ptr as *const u8
} }
#[inline]
fn from_inst(stream_inst: StreamInstance) -> Self {
Stream {
past_end_of_stream: false,
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(stream_inst)
}
}
#[inline] #[inline]
pub(crate) pub(crate)
fn stdout() -> Self { fn stdout() -> Self {
Stream { Stream::from_inst(StreamInstance::Stdout)
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Stdout
),
}
} }
#[inline] #[inline]
pub(crate) pub(crate)
fn from_file_as_output(file: File) -> Self { fn from_file_as_output(file: File) -> Self {
Stream { Stream::from_inst(StreamInstance::OutputFile(file))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::OutputFile(file)
),
}
} }
#[inline] #[inline]
pub(crate) pub(crate)
fn from_file_as_input(file: File) -> Self { fn from_file_as_input(file: File) -> Self {
Stream { Stream::from_inst(StreamInstance::InputFile(file))
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::InputFile(file)
),
}
}
/*
#[inline]
pub(crate)
fn stdin() -> Self {
Stream {
options: StreamOptions::default(),
stream_inst: WrappedStreamInstance::new(
StreamInstance::Stdin
),
}
}
*/
#[inline]
pub(crate)
fn null_stream() -> Self {
Stream {
options: StreamOptions::default(), // TODO: null_options?
stream_inst: WrappedStreamInstance::new(
StreamInstance::Null
),
}
} }
#[inline] #[inline]
@@ -388,9 +338,10 @@ impl MachineState {
) -> CallResult { ) -> CallResult {
match stream.options.eof_action { match stream.options.eof_action {
EOFAction::Error => { EOFAction::Error => {
let stub = MachineError::functor_stub(caller, arity); stream.past_end_of_stream = true;
let stream = vec![ let stub = MachineError::functor_stub(caller, arity);
let payload = vec![
HeapCellValue::Stream(stream.clone()) HeapCellValue::Stream(stream.clone())
]; ];
@@ -398,7 +349,7 @@ impl MachineState {
self.heap.h(), self.heap.h(),
Permission::InputStream, Permission::InputStream,
"past_end_of_stream", "past_end_of_stream",
stream, payload,
); );
Err(self.error_form(err, stub)) Err(self.error_form(err, stub))
@@ -408,10 +359,12 @@ impl MachineState {
HeapCellValue::Atom(clause_name!("end_of_stream"), None) HeapCellValue::Atom(clause_name!("end_of_stream"), None)
); );
stream.past_end_of_stream = true;
Ok(self.unify(result, end_of_stream)) Ok(self.unify(result, end_of_stream))
} }
EOFAction::Reset => { EOFAction::Reset => {
Ok(self.fail = !stream.reset()) stream.past_end_of_stream = !stream.reset();
Ok(self.fail = stream.past_end_of_stream)
} }
} }
} }

View File

@@ -1603,8 +1603,8 @@ impl MachineState {
let a1 = self[temp_v!(1)]; let a1 = self[temp_v!(1)];
match result { match result {
Some(Ok(b)) => { Some(Ok(c)) => {
self.unify(Addr::Char(b as char), a1); self.unify(Addr::Char(c), a1);
} }
Some(Err(_)) => { Some(Err(_)) => {
let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom( let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
@@ -1623,6 +1623,29 @@ impl MachineState {
} }
} }
} }
&SystemClauseType::FlushOutput => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "flush_output", 1)?;
if stream.is_input_stream() {
let stub = MachineError::functor_stub(clause_name!("flush_output"), 1);
let addr = vec![
HeapCellValue::Stream(stream)
];
let err = MachineError::permission_error(
self.heap.h(),
Permission::OutputStream,
"stream",
addr,
);
return Err(self.error_form(err, stub));
}
stream.flush().unwrap();
}
&SystemClauseType::GetSingleChar => { &SystemClauseType::GetSingleChar => {
let c = get_single_char(); let c = get_single_char();
@@ -3925,14 +3948,12 @@ impl MachineState {
if let Some(err_string) = opt_err { if let Some(err_string) = opt_err {
let stub = MachineError::functor_stub(clause_name!("write_term"), 3); let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
let h = self.heap.h(); let addr = vec![
let addr = self.heap.to_unifiable(
HeapCellValue::Stream(stream) HeapCellValue::Stream(stream)
); ];
let err = MachineError::permission_error( let err = MachineError::permission_error(
h + 1, self.heap.h(),
Permission::OutputStream, Permission::OutputStream,
err_string, err_string,
addr, addr,