]> Repositorios git - scryer-prolog.git/commitdiff
clean up stream error handling, add get_byte/{1,2}
authorMark Thom <[email protected]>
Tue, 5 May 2020 22:09:17 +0000 (16:09 -0600)
committerMark Thom <[email protected]>
Tue, 5 May 2020 22:09:17 +0000 (16:09 -0600)
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_errors.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index bb39a35ea8118381af806fcdd7e90049662a2b95..992820137e7e7e3b4ab9d77084898f09991136e6 100644 (file)
@@ -182,6 +182,7 @@ pub enum SystemClauseType {
     FetchGlobalVarWithOffset,
     FileToChars,
     FlushOutput,
+    GetByte,
     GetChar,
     GetSingleChar,
     ResetAttrVarState,
@@ -327,6 +328,7 @@ impl SystemClauseType {
             }
             &SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
             &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
+            &SystemClauseType::GetByte => clause_name!("$get_byte"),
             &SystemClauseType::GetChar => clause_name!("$get_char"),
             &SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
             &SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
@@ -487,6 +489,7 @@ impl SystemClauseType {
             ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
             ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
             ("$file_to_chars", 2) => Some(SystemClauseType::FileToChars),
+            ("$get_byte", 2) => Some(SystemClauseType::GetByte),
             ("$get_char", 1) => Some(SystemClauseType::GetChar),
             ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
             ("$points_to_cont_reset_marker", 1) => {
index 31cfa75d7ec8ea37dce839f76d820b2824b9ffbf..ca6d738e8a7b42bba6be108921eb449f226e1e99 100644 (file)
@@ -49,9 +49,10 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
                      current_prolog_flag/2, expand_goal/2,
                      expand_term/2, fail/0, false/0, findall/3,
                      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,
+                     get_byte/1, get_byte/2, 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,
@@ -1190,3 +1191,11 @@ flush_output(S) :-
 flush_output :-
     current_output(S),
     '$flush_output'(S).
+
+
+get_byte(S, B) :-
+    '$get_byte'(S, B).
+
+get_byte(S) :-
+    current_input(S),
+    '$get_byte'(S, B).
index 4a022316b7dbbec9adba76989d9ccf0e8fcce19d..fdbd1d85a8c3026c2b852bcd89d5f39b699ca06a 100644 (file)
@@ -495,7 +495,7 @@ pub enum ValidType {
     Compound,
     Evaluable,
     Float,
-    //    InByte,
+    InByte,
     //    InCharacter,
     Integer,
     List,
@@ -518,7 +518,7 @@ impl ValidType {
             ValidType::Compound => "compound",
             ValidType::Evaluable => "evaluable",
             ValidType::Float => "float",
-            //            ValidType::InByte => "in_byte",
+            ValidType::InByte => "in_byte",
             //            ValidType::InCharacter => "in_character",
             ValidType::Integer => "integer",
             ValidType::List => "list",
index e58a04ece6dc747ef7aa9e24843e2b9e3418f708..9a7a1aa0a6404450c8d93e34f4b269c80546ae59 100644 (file)
@@ -629,20 +629,13 @@ impl MachineState {
             };
 
         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(),
+            return Err(self.stream_permission_error(
                 Permission::InputStream,
                 err_string,
-                addr,
-            );
-
-            return Err(self.error_form(err, stub));
+                stream,
+                clause_name!("read_term"),
+                3,
+            ));
         }
 
         let mut orig_stream = stream.clone();
index 0c2d9aac7f8d53b1acc4757053135d4485c26c88..5be540cbddc6c952801a0676ac211daf7ad74588 100644 (file)
@@ -153,7 +153,7 @@ impl Default for StreamOptions {
 
 #[derive(Debug, Clone, Hash)]
 pub struct Stream {
-    past_end_of_stream: bool,
+    pub past_end_of_stream: bool,
     pub options: StreamOptions,
     stream_inst: WrappedStreamInstance,
 }
@@ -339,20 +339,7 @@ impl MachineState {
         match stream.options.eof_action {
             EOFAction::Error => {
                 stream.past_end_of_stream = true;
-
-                let stub = MachineError::functor_stub(caller, arity);
-                let payload = vec![
-                    HeapCellValue::Stream(stream.clone())
-                ];
-
-                let err = MachineError::permission_error(
-                    self.heap.h(),
-                    Permission::InputStream,
-                    "past_end_of_stream",
-                    payload,
-                );
-
-                Err(self.error_form(err, stub))
+                return Err(self.open_past_eos_error(stream.clone(), caller, arity));
             }
             EOFAction::EOFCode => {
                 let end_of_stream = self.heap.to_unifiable(
@@ -533,6 +520,47 @@ impl MachineState {
         }
     }
 
+    pub(crate)
+    fn stream_permission_error(
+        &self,
+        perm: Permission,
+        err_string: &'static str,
+        stream: Stream,
+        caller: ClauseName,
+        arity: usize,
+    ) -> MachineStub {
+        let stub = MachineError::functor_stub(caller, arity);
+        let payload = vec![
+            HeapCellValue::Stream(stream)
+        ];
+
+        let err = MachineError::permission_error(
+            self.heap.h(),
+            perm,
+            err_string,
+            payload,
+        );
+
+        return self.error_form(err, stub);
+    }
+
+    #[inline]
+    pub(crate)
+    fn open_past_eos_error(
+        &self,
+        stream: Stream,
+        caller: ClauseName,
+        arity: usize,
+    ) -> MachineStub {
+        self.stream_permission_error(
+            Permission::InputStream,
+            "past_end_of_stream",
+            stream,
+            caller,
+            arity,
+        )
+    }
+
     pub(crate)
     fn open_permission_error<T: PermissionError>(
         &self,
index 14df438c103e9caf9e1131228e86b86837deca54..0837a0ad4e2709ed6aa12a490dc557b19dc28394 100644 (file)
@@ -1592,6 +1592,104 @@ impl MachineState {
 
                 self.unify(complete_string, a2);
             }
+            &SystemClauseType::GetByte => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
+
+                let opt_err =
+                    if !stream.is_input_stream() {
+                        Some("stream") // 8.14.2.3 g)
+                    } else if stream.options.stream_type == StreamType::Text {
+                        Some("text_stream") // 8.14.2.3 h)
+                    } else {
+                        None
+                    };
+
+                if let Some(err_string) = opt_err {
+                    return Err(self.stream_permission_error(
+                        Permission::InputStream,
+                        err_string,
+                        stream,
+                        clause_name!("get_byte"),
+                        2,
+                    ));
+                }
+
+                if stream.past_end_of_stream {
+                    self.eof_action(
+                        self[temp_v!(2)],
+                        &mut stream,
+                        clause_name!("get_byte"),
+                        2,
+                    )?;
+
+                    if EOFAction::Reset != stream.options.eof_action {
+                        return return_from_clause!(self.last_call, self);
+                    } else if self.fail {
+                        return Ok(());
+                    }
+                }
+
+                loop {
+                    let mut b = [0u8; 1];
+
+                    match stream.read(&mut b) {
+                        Ok(1) => {
+                            match self.store(self.deref(self[temp_v!(2)])) {
+                                addr if addr.is_ref() => {
+                                    if let Some(var) = addr.as_var() {
+                                        self.bind(var, Addr::Usize(b[0] as usize));
+                                        return return_from_clause!(self.last_call, self);
+                                    } else {
+                                        unreachable!()
+                                    }
+                                }
+                                addr => {
+                                    match Number::try_from((addr, &self.heap)) {
+                                        Ok(Number::Integer(n)) => {
+                                            if let Some(nb) = n.to_u8() {
+                                                self.fail = b[0] != nb;
+                                                return return_from_clause!(self.last_call, self);
+                                            }
+                                        }
+                                        Ok(Number::Fixnum(n)) => {
+                                            if let Ok(nb) = u8::try_from(n) {
+                                                self.fail = b[0] != nb;
+                                                return return_from_clause!(self.last_call, self);
+                                            }
+                                        }
+                                        _ => {
+                                        }
+                                    }
+                                }
+                            }
+
+                            let stub = MachineError::functor_stub(clause_name!("get_byte"), 2);
+                            let err = MachineError::type_error(
+                                self.heap.h(),
+                                ValidType::InByte,
+                                self[temp_v!(2)],
+                            );
+
+                            return Err(self.error_form(err, stub));
+                        }
+                        _ => {
+                            self.eof_action(
+                                self[temp_v!(2)],
+                                &mut stream,
+                                clause_name!("get_byte"),
+                                2,
+                            )?;
+
+                            if EOFAction::Reset != stream.options.eof_action {
+                                return return_from_clause!(self.last_call, self);
+                            } else if self.fail {
+                                return Ok(());
+                            }
+                        }
+                    }
+                }
+            }
             &SystemClauseType::GetChar => {
                 let mut iter = self.open_parsing_stream(
                     current_input_stream.clone(),
@@ -3947,19 +4045,13 @@ impl MachineState {
                     };
 
                 if let Some(err_string) = opt_err {
-                    let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
-                    let addr = vec![
-                        HeapCellValue::Stream(stream)
-                    ];
-
-                    let err = MachineError::permission_error(
-                        self.heap.h(),
+                    return Err(self.stream_permission_error(
                         Permission::OutputStream,
                         err_string,
-                        addr,
-                    );
-
-                    return Err(self.error_form(err, stub));
+                        stream,
+                        clause_name!("write_term"),
+                        3,
+                    ));
                 }
 
                 let addr = self[temp_v!(2)];