]> Repositorios git - scryer-prolog.git/commitdiff
add put_byte/{1,2}, put_char/{1,2}
authorMark Thom <[email protected]>
Tue, 5 May 2020 23:42:18 +0000 (17:42 -0600)
committerMark Thom <[email protected]>
Tue, 5 May 2020 23:42:18 +0000 (17:42 -0600)
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_errors.rs
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs

index 614df359682349fb40c5ac258d42b27bdaf38511..bf0d75a906b24bebce0c9f93fecb68d4d8dd7d36 100644 (file)
@@ -222,6 +222,8 @@ pub enum SystemClauseType {
     Open,
     PartialStringTail,
     PointsToContinuationResetMarker,
+    PutByte,
+    PutChar,
     REPL(REPLCodePtr),
     ReadQueryTerm,
     ReadTerm,
@@ -385,6 +387,12 @@ impl SystemClauseType {
             &SystemClauseType::PointsToContinuationResetMarker => {
                 clause_name!("$points_to_cont_reset_marker")
             }
+            &SystemClauseType::PutByte => {
+                clause_name!("$put_byte")
+            }
+            &SystemClauseType::PutChar => {
+                clause_name!("$put_char")
+            }
             &SystemClauseType::QuotedToken => {
                 clause_name!("$quoted_token")
             }
@@ -495,6 +503,12 @@ impl SystemClauseType {
             ("$points_to_cont_reset_marker", 1) => {
                 Some(SystemClauseType::PointsToContinuationResetMarker)
             }
+            ("$put_byte", 2) => {
+                Some(SystemClauseType::PutByte)
+            }
+            ("$put_char", 2) => {
+                Some(SystemClauseType::PutChar)
+            }
             ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
             ("$truncate_if_no_lh_growth", 1) => {
                 Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
index 22c7619fc0d3e2bc4d91a00f04ece94a2f5eda5a..9848b1e611af677e32eb8b999775baedf1364ef7 100644 (file)
@@ -52,6 +52,7 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
                      get_byte/1, get_byte/2, get_char/1, get_char/2,
                      halt/0, max_arity/1, number_chars/2,
                      number_codes/2, once/1, op/3, open/3, open/4,
+                     put_byte/1, put_byte/2, put_char/1, put_char/2,
                      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,
@@ -1199,3 +1200,19 @@ get_byte(S, B) :-
 get_byte(S) :-
     current_input(S),
     '$get_byte'(S, B).
+
+
+put_char(C) :-
+    current_output(S),
+    '$put_char'(S, C).
+
+put_char(S, C) :-
+    '$put_char'(S, C).
+
+
+put_byte(C) :-
+    current_output(S),
+    '$put_byte'(S, C).
+
+put_byte(S, C) :-
+    '$put_byte'(S, C).
index 5afae4438fd937bfb626c0849fe7c5283eadc255..cb44819953d3c2aacd9cfbec475ee5caf1434f4c 100644 (file)
@@ -489,7 +489,7 @@ pub enum ValidType {
     Atom,
     Atomic,
     //    Boolean,
-    //    Byte,
+    Byte,
     Callable,
     Character,
     Compound,
@@ -512,7 +512,7 @@ impl ValidType {
             ValidType::Atom => "atom",
             ValidType::Atomic => "atomic",
             //            ValidType::Boolean => "boolean",
-            //            ValidType::Byte => "byte",
+            ValidType::Byte => "byte",
             ValidType::Callable => "callable",
             ValidType::Character => "character",
             ValidType::Compound => "compound",
index 7e11c0dfe8c3f2fa6cddab05685687ec360b6443..2ac482e77bf91de8af59318a3d32e21ce57052a0 100644 (file)
@@ -278,6 +278,17 @@ impl Stream {
     pub(crate)
     fn close(&mut self) {
         *self.stream_inst.0.borrow_mut() = StreamInstance::Null;
+        self.past_end_of_stream = true;
+    }
+
+    #[inline]
+    pub(crate)
+    fn is_null_stream(&self) -> bool {
+        if let StreamInstance::Null = *self.stream_inst.0.borrow() {
+            true
+        } else {
+            false
+        }
     }
 
     #[inline]
@@ -485,7 +496,15 @@ impl MachineState {
             }
             Addr::Stream(h) => {
                 if let HeapCellValue::Stream(ref stream) = &self.heap[h] {
-                    stream.clone()
+                    if stream.is_null_stream() {
+                        return Err(self.open_permission_error(
+                            Addr::Stream(h),
+                            caller,
+                            arity,
+                        ));
+                    } else {
+                        stream.clone()
+                    }
                 } else {
                     unreachable!()
                 }
index 434922474afc398679e1ffd06083759a1bcb4b8d..7c6c6c885fc0cdf9da4223f33e299a8573a2416c 100644 (file)
@@ -1592,6 +1592,109 @@ impl MachineState {
 
                 self.unify(complete_string, a2);
             }
+            &SystemClauseType::PutChar => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "put_char", 2)?;
+
+                self.check_stream_properties(
+                    &mut stream,
+                    StreamType::Text,
+                    None,
+                    clause_name!("put_char"),
+                    2,
+                )?;
+
+                match self.store(self.deref(self[temp_v!(2)])) {
+                    addr if addr.is_ref() => {
+                        let stub = MachineError::functor_stub(clause_name!("put_char"), 2);
+                        let err = MachineError::instantiation_error();
+
+                        return Err(self.error_form(err, stub));
+                    }
+                    addr => {
+                        match self.store(self.deref(self[temp_v!(2)])) {
+                            Addr::Con(h) if self.heap.atom_at(h) => {
+                                match &self.heap[h] {
+                                    HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
+                                        if let Some(c) = atom.as_str().chars().next() {
+                                            write!(&mut stream, "{}", c).unwrap();
+                                            return return_from_clause!(self.last_call, self);
+                                        } else {
+                                            unreachable!()
+                                        }
+                                    }
+                                    _ => {
+                                        unreachable!()
+                                    }
+                                }
+                            }
+                            Addr::Char(c) => {
+                                write!(&mut stream, "{}", c).unwrap();
+                                return return_from_clause!(self.last_call, self);
+                            }
+                            _ => {
+                            }
+                        }
+
+                        let stub = MachineError::functor_stub(clause_name!("put_char"), 2);
+                        let err = MachineError::type_error(
+                            self.heap.h(),
+                            ValidType::Character,
+                            addr,
+                        );
+
+                        return Err(self.error_form(err, stub));
+                    }
+                }
+            }
+            &SystemClauseType::PutByte => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "put_byte", 2)?;
+
+                self.check_stream_properties(
+                    &mut stream,
+                    StreamType::Binary,
+                    None,
+                    clause_name!("put_byte"),
+                    2,
+                )?;
+
+                match self.store(self.deref(self[temp_v!(2)])) {
+                    addr if addr.is_ref() => {
+                        let stub = MachineError::functor_stub(clause_name!("put_byte"), 2);
+                        let err = MachineError::instantiation_error();
+
+                        return Err(self.error_form(err, stub));
+                    }
+                    addr => {
+                        match Number::try_from((addr, &self.heap)) {
+                            Ok(Number::Integer(n)) => {
+                                if let Some(nb) = n.to_u8() {
+                                    stream.write(&mut [nb]).unwrap();
+                                    return return_from_clause!(self.last_call, self);
+                                }
+                            }
+                            Ok(Number::Fixnum(n)) => {
+                                if let Ok(nb) = u8::try_from(n) {
+                                    stream.write(&mut [nb]).unwrap();
+                                    return return_from_clause!(self.last_call, self);
+                                }
+                            }
+                            _ => {
+                            }
+                        }
+
+                        let stub = MachineError::functor_stub(clause_name!("put_byte"), 2);
+                        let err = MachineError::type_error(
+                            self.heap.h(),
+                            ValidType::Byte,
+                            self[temp_v!(2)],
+                        );
+
+                        return Err(self.error_form(err, stub));
+                    }
+                }
+            }
             &SystemClauseType::GetByte => {
                 let mut stream =
                     self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
@@ -2436,7 +2539,7 @@ impl MachineState {
                             true
                         }
                         "write" => {
-                            open_options.read(false).write(true).create(true).append(false);
+                            open_options.read(false).write(true).truncate(true).create(true);
                             false
                         }
                         "append" => {