add flush_output/{0,1}, past_end_of_stream
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(..) => {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)?;
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user