FetchGlobalVar,
FetchGlobalVarWithOffset,
FileToChars,
+ FlushOutput,
GetChar,
GetSingleChar,
ResetAttrVarState,
clause_name!("$fetch_global_var_with_offset")
}
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
+ &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
+ ("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
current_op/3, current_predicate/1,
current_prolog_flag/2, expand_goal/2,
expand_term/2, fail/0, false/0, findall/3,
- findall/4, get_char/1, halt/0, max_arity/1,
- number_chars/2, number_codes/2, once/1, op/3,
- open/3, open/4, read_term/2, read_term/3,
- repeat/0, retract/1, set_prolog_flag/2,
- set_input/1, set_output/1, setof/3, sub_atom/5,
- subsumes_term/2, term_variables/2, throw/1,
- true/0, unify_with_occurs_check/2, write/1,
+ findall/4, flush_output/0, flush_output/1,
+ get_char/1, halt/0, max_arity/1, number_chars/2,
+ number_codes/2, once/1, op/3, open/3, open/4,
+ read_term/2, read_term/3, repeat/0, retract/1,
+ set_prolog_flag/2, set_input/1, set_output/1,
+ setof/3, sub_atom/5, subsumes_term/2,
+ term_variables/2, throw/1, true/0,
+ unify_with_occurs_check/2, write/1,
write_canonical/1, write_term/2, write_term/3,
writeq/1]).
'$close'(Stream, CloseOptions).
close(Stream) :-
- close(Stream, []).
+ '$close'(Stream, []).
+
+
+flush_output(S) :-
+ '$flush_output'(S).
+
+flush_output :-
+ current_output(S),
+ '$flush_output'(S).
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*;
-use crate::prolog::machine::streams::*;
use std::mem;
use std::ops::IndexMut;
}
}
- 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) {
match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
- Addr::Lis(h) if h >= self.old_h => {
- self.scan += 1;
- }
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::HeapCell(_) |
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
- self.copy_stream(h);
+ *self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
self.scan += 1;
HeapCellValue::Addr(addr) => {
addr
}
- val @ HeapCellValue::Atom(..)
- | val @ HeapCellValue::Integer(_)
- | val @ HeapCellValue::DBRef(_)
- | val @ HeapCellValue::Rational(_) => {
+ val @ HeapCellValue::Atom(..) |
+ val @ HeapCellValue::Integer(_) |
+ val @ HeapCellValue::DBRef(_) |
+ val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val))
}
val @ HeapCellValue::NamedStr(..) => {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail)
}
- &HeapCellValue::Stream(_) => {
- HeapCellValue::Stream(Stream::null_stream())
+ &HeapCellValue::Stream(ref stream) => {
+ HeapCellValue::Stream(stream.clone())
}
&HeapCellValue::TcpListener(_) => {
HeapCellValue::Atom(clause_name!("$socket_server"), None)
stream: Stream,
indices: &mut IndexStore,
) -> 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 stream = self.open_parsing_stream(stream, "read_term", 3)?;
OutputFile(File),
Null,
ReadlineStream(ReadlineStream),
- // Stdin,
Stdout,
TcpStream(TcpStream),
}
#[derive(Debug, Clone, Hash)]
pub struct Stream {
+ past_end_of_stream: bool,
pub options: StreamOptions,
stream_inst: WrappedStreamInstance,
}
tcp_stream.set_read_timeout(None).unwrap();
tcp_stream.set_write_timeout(None).unwrap();
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::TcpStream(tcp_stream)
- )
- }
+ Stream::from_inst(StreamInstance::TcpStream(tcp_stream))
}
}
impl From<String> for Stream {
fn from(string: String) -> Self {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::Bytes(Cursor::new(string.into_bytes()))
- )
- }
+ Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
}
}
impl From<ReadlineStream> for Stream {
fn from(rl_stream: ReadlineStream) -> Self {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::ReadlineStream(rl_stream)
- ),
- }
+ Stream::from_inst(StreamInstance::ReadlineStream(rl_stream))
}
}
impl From<&'static str> for Stream {
fn from(src: &'static str) -> Stream {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::DynReadSource(Box::new(src.as_bytes()))
- ),
- }
+ Stream::from_inst(StreamInstance::DynReadSource(Box::new(src.as_bytes())))
}
}
}
#[inline]
- pub(crate)
- fn stdout() -> Self {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::Stdout
- ),
- }
- }
-
- #[inline]
- pub(crate)
- fn from_file_as_output(file: File) -> Self {
+ fn from_inst(stream_inst: StreamInstance) -> Self {
Stream {
+ past_end_of_stream: false,
options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::OutputFile(file)
- ),
+ stream_inst: WrappedStreamInstance::new(stream_inst)
}
}
#[inline]
pub(crate)
- fn from_file_as_input(file: File) -> Self {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::InputFile(file)
- ),
- }
+ fn stdout() -> Self {
+ Stream::from_inst(StreamInstance::Stdout)
}
-/*
#[inline]
pub(crate)
- fn stdin() -> Self {
- Stream {
- options: StreamOptions::default(),
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::Stdin
- ),
- }
+ fn from_file_as_output(file: File) -> Self {
+ Stream::from_inst(StreamInstance::OutputFile(file))
}
-*/
#[inline]
pub(crate)
- fn null_stream() -> Self {
- Stream {
- options: StreamOptions::default(), // TODO: null_options?
- stream_inst: WrappedStreamInstance::new(
- StreamInstance::Null
- ),
- }
+ fn from_file_as_input(file: File) -> Self {
+ Stream::from_inst(StreamInstance::InputFile(file))
}
#[inline]
) -> CallResult {
match stream.options.eof_action {
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())
];
self.heap.h(),
Permission::InputStream,
"past_end_of_stream",
- stream,
+ payload,
);
Err(self.error_form(err, stub))
HeapCellValue::Atom(clause_name!("end_of_stream"), None)
);
+ stream.past_end_of_stream = true;
Ok(self.unify(result, end_of_stream))
}
EOFAction::Reset => {
- Ok(self.fail = !stream.reset())
+ stream.past_end_of_stream = !stream.reset();
+ Ok(self.fail = stream.past_end_of_stream)
}
}
}
let a1 = self[temp_v!(1)];
match result {
- Some(Ok(b)) => {
- self.unify(Addr::Char(b as char), a1);
+ Some(Ok(c)) => {
+ self.unify(Addr::Char(c), a1);
}
Some(Err(_)) => {
let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
}
}
}
+ &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 => {
let c = get_single_char();
if let Some(err_string) = opt_err {
let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
- let h = self.heap.h();
-
- let addr = self.heap.to_unifiable(
+ let addr = vec![
HeapCellValue::Stream(stream)
- );
+ ];
let err = MachineError::permission_error(
- h + 1,
+ self.heap.h(),
Permission::OutputStream,
err_string,
addr,