]> Repositorios git - scryer-prolog.git/commitdiff
add close/{1,2}, better EOF action handling in read_term
authorMark Thom <[email protected]>
Tue, 5 May 2020 06:38:21 +0000 (00:38 -0600)
committerMark Thom <[email protected]>
Tue, 5 May 2020 06:38:21 +0000 (00:38 -0600)
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index ce5d9e68f6037324675293a2a6fe304dad11eb38..e6f577e74e7bdf1d4691418e1997f1961a7fe996 100644 (file)
@@ -165,6 +165,7 @@ pub enum SystemClauseType {
     CodesToNumber,
     CopyTermWithoutAttrVars,
     CheckCutPoint,
+    Close,
     CopyToLiftedHeap,
     CreatePartialString,
     CurrentHostname,
@@ -310,6 +311,7 @@ impl SystemClauseType {
             &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
                     clause_name!("$use_qualified_module_from_file")
             }
+            &SystemClauseType::Close => clause_name!("$close"),
             &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
             &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
             &SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -462,6 +464,7 @@ impl SystemClauseType {
             ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
             ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
             ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
+            ("$close", 2) => Some(SystemClauseType::Close),
             ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
             ("$current_input", 1) => Some(SystemClauseType::CurrentInput),
             ("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
index 2ec5680e1b00b46cc0cd26dc17d3778af6a5fd29..f1f20f8ca2d5125ba5016469bf4472b69b1263b3 100644 (file)
@@ -43,18 +43,18 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
                      (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
                      abolish/1, asserta/1, assertz/1, atom_chars/2,
                      atom_codes/2, atom_concat/3, atom_length/2,
-                     bagof/3, catch/3, char_code/2, clause/2,
-                     current_input/1, current_output/1, 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,
+                     bagof/3, catch/3, char_code/2, clause/2, close/1,
+                     close/2, current_input/1, current_output/1,
+                     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,
                      write_canonical/1, write_term/2, write_term/3,
                      writeq/1]).
 
@@ -1161,3 +1161,23 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
        '$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
     ).
 
+
+parse_close_options(Options, OptionValues, Stub) :-
+    DefaultOptions = [force-false],
+    parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub).
+
+parse_close_options_(force(Force), force-Force) :-
+    (  nonvar(Force), lists:member(Force, [true, false]), !
+    ;
+       throw(error(domain_error(close_option, force(Force)), _))
+    ).
+parse_close_options_(E, _) :-
+    throw(error(domain_error(close_option, E), _)).
+
+
+close(Stream, CloseOptions) :-
+    parse_close_options(CloseOptions, [Force], close/2),
+    '$close'(Stream, CloseOptions).
+
+close(Stream) :-
+    close(Stream, []).
index 1dbb753263957c03e4d32a31fbe1b1a8bc716e5e..e4df47346d322cb1e60d09c97686bd8d9e390ccc 100644 (file)
@@ -12,7 +12,7 @@ use std::fmt;
 use std::fs::File;
 use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
 use std::hash::{Hash, Hasher};
-use std::net::TcpStream;
+use std::net::{Shutdown, TcpStream};
 use std::rc::Rc;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -42,6 +42,18 @@ pub enum StreamInstance {
     TcpStream(TcpStream),
 }
 
+impl Drop for StreamInstance {
+    fn drop(&mut self) {
+        match self {
+            StreamInstance::TcpStream(ref mut tcp_stream) => {
+                tcp_stream.shutdown(Shutdown::Both).unwrap();
+            }
+            _ => {
+            }
+        }
+    }
+}
+
 impl fmt::Debug for StreamInstance {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -140,12 +152,21 @@ impl Default for StreamOptions {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone, Hash)]
 pub struct Stream {
     pub options: StreamOptions,
     stream_inst: WrappedStreamInstance,
 }
 
+impl PartialEq for Stream {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.stream_inst == other.stream_inst
+    }
+}
+
+impl Eq for Stream {}
+
 impl From<TcpStream> for Stream {
     fn from(tcp_stream: TcpStream) -> Self {
         tcp_stream.set_read_timeout(None).unwrap();
@@ -292,6 +313,12 @@ impl Stream {
         }
     }
 
+    #[inline]
+    pub(crate)
+    fn close(&mut self) {
+        *self.stream_inst.0.borrow_mut() = StreamInstance::Null;
+    }
+
     #[inline]
     pub(crate)
     fn is_input_stream(&self) -> bool {
index 83d4eb48c44b4366529f392919e6539eeab2f470..7a73a1550faf6fb99a87494c229d48f3f2718b68 100644 (file)
@@ -1743,6 +1743,26 @@ impl MachineState {
                     }
                 };
             }
+            &SystemClauseType::Close => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?;
+
+                if stream.is_output_stream() {
+                    stream.flush().unwrap(); // 8.11.6.1b)
+                }
+
+                if stream == *current_input_stream {
+                    *current_input_stream = readline::input_stream();
+                } else if stream == *current_output_stream {
+                    *current_output_stream = Stream::stdout();
+                }
+
+                stream.close();
+
+                if let Some(alias) = stream.options.alias {
+                    indices.stream_aliases.remove(&alias);
+                }
+            }
             &SystemClauseType::CopyToLiftedHeap => {
                 match self.store(self.deref(self[temp_v!(1)])) {
                     Addr::Usize(lh_offset) => {
@@ -2298,6 +2318,10 @@ impl MachineState {
 
                 stream.options = options;
 
+                if let Some(ref alias) = &stream.options.alias {
+                    indices.stream_aliases.insert(alias.clone(), stream.clone());
+                }
+
                 let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
                 let stream_var = self.store(self.deref(self[temp_v!(3)]));
 
@@ -3464,12 +3488,12 @@ impl MachineState {
                     match TcpStream::connect(socket_addr).map_err(|e| e.kind()) {
                         Ok(tcp_stream) => {
                             let mut stream = Stream::from(tcp_stream);
+                            stream.options = options;
 
-                            if let Some(ref alias) = &options.alias {
+                            if let Some(ref alias) = &stream.options.alias {
                                 indices.stream_aliases.insert(alias.clone(), stream.clone());
                             }
 
-                            stream.options = options;
                             self.heap.to_unifiable(HeapCellValue::Stream(stream))
                         }
                         Err(ErrorKind::PermissionDenied) => {