]> Repositorios git - scryer-prolog.git/commitdiff
cleanup on reading predicates, add get_char/{1,2}
authorMark Thom <[email protected]>
Tue, 5 May 2020 22:54:40 +0000 (16:54 -0600)
committerMark Thom <[email protected]>
Tue, 5 May 2020 22:54:40 +0000 (16:54 -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 992820137e7e7e3b4ab9d77084898f09991136e6..614df359682349fb40c5ac258d42b27bdaf38511 100644 (file)
@@ -490,7 +490,7 @@ impl SystemClauseType {
             ("$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_char", 2) => Some(SystemClauseType::GetChar),
             ("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
             ("$points_to_cont_reset_marker", 1) => {
                 Some(SystemClauseType::PointsToContinuationResetMarker)
index ca6d738e8a7b42bba6be108921eb449f226e1e99..22c7619fc0d3e2bc4d91a00f04ece94a2f5eda5a 100644 (file)
@@ -49,10 +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_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,
+                     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,
+                     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,
@@ -1000,11 +1000,11 @@ char_code(Char, Code) :-
     ).
 
 get_char(C) :-
-    (  var(C) -> '$get_char'(C)
-    ;  C == end_of_file  -> '$get_char'(C)
-    ;  atom_length(C, 1) -> '$get_char'(C)
-    ;  throw(error(type_error(in_character, C), get_char/1))
-    ).
+    current_input(S),
+    '$get_char'(S, C).
+
+get_char(S, C) :-
+    '$get_char'(S, C).
 
 can_be_number(N, PI) :-
     (  var(N) -> true
index fdbd1d85a8c3026c2b852bcd89d5f39b699ca06a..5afae4438fd937bfb626c0849fe7c5283eadc255 100644 (file)
@@ -496,7 +496,7 @@ pub enum ValidType {
     Evaluable,
     Float,
     InByte,
-    //    InCharacter,
+    InCharacter,
     Integer,
     List,
     //    Number,
@@ -519,7 +519,7 @@ impl ValidType {
             ValidType::Evaluable => "evaluable",
             ValidType::Float => "float",
             ValidType::InByte => "in_byte",
-            //            ValidType::InCharacter => "in_character",
+            ValidType::InCharacter => "in_character",
             ValidType::Integer => "integer",
             ValidType::List => "list",
             //            ValidType::Number => "number",
@@ -555,7 +555,7 @@ impl DomainErrorType {
 // from 7.12.2 f) of 13211-1:1995
 #[derive(Debug, Clone, Copy)]
 pub enum RepFlag {
-    Character,
+    //    Character,
     CharacterCode,
     //    InCharacterCode,
     MaxArity,
@@ -566,7 +566,7 @@ pub enum RepFlag {
 impl RepFlag {
     pub fn as_str(self) -> &'static str {
         match self {
-            RepFlag::Character => "character",
+            //            RepFlag::Character => "character",
             RepFlag::CharacterCode => "character_code",
             //            RepFlag::InCharacterCode => "in_character_code",
             RepFlag::MaxArity => "max_arity",
index 9a7a1aa0a6404450c8d93e34f4b269c80546ae59..b16389d1905b1e6d975f26fbb6cc9a442871faf2 100644 (file)
@@ -616,26 +616,23 @@ impl MachineState {
     pub(crate)
     fn read_term(
         &mut self,
-        stream: Stream,
+        mut 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
-            };
+        self.check_stream_properties(
+            &mut stream,
+            StreamType::Text,
+            Some(self[temp_v!(2)]),
+            clause_name!("read_term"),
+            3,
+        )?;
 
-        if let Some(err_string) = opt_err {
-            return Err(self.stream_permission_error(
-                Permission::InputStream,
-                err_string,
-                stream,
-                clause_name!("read_term"),
-                3,
-            ));
+        if stream.past_end_of_stream {
+            if EOFAction::Reset != stream.options.eof_action {
+                return return_from_clause!(self.last_call, self);
+            } else if self.fail {
+                return Ok(());
+            }
         }
 
         let mut orig_stream = stream.clone();
index 5be540cbddc6c952801a0676ac211daf7ad74588..7e11c0dfe8c3f2fa6cddab05685687ec360b6443 100644 (file)
@@ -21,6 +21,17 @@ pub enum StreamType {
     Text,
 }
 
+impl StreamType {
+    #[inline]
+    pub(crate)
+    fn as_str(&self) -> &'static str {
+        match self {
+            StreamType::Binary => "binary_stream",
+            StreamType::Text => "text_stream",
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum EOFAction {
     EOFCode,
@@ -615,6 +626,54 @@ impl MachineState {
 
         return self.error_form(err, stub);
     }
+
+
+    pub(crate)
+    fn check_stream_properties(
+        &mut self,
+        stream: &mut Stream,
+        expected_type: StreamType,
+        input: Option<Addr>,
+        caller: ClauseName,
+        arity: usize,
+    ) -> CallResult {
+        let opt_err =
+            if input.is_some() && !stream.is_input_stream() {
+                Some("stream") // 8.14.2.3 g)
+            } else if input.is_none() && stream.is_input_stream() {
+                Some("stream") // 8.14.2.3 g)
+            } else if stream.options.stream_type != expected_type {
+                Some(expected_type.as_str()) // 8.14.2.3 h)
+            } else {
+                None
+            };
+
+        let permission =
+            if input.is_some() { Permission::InputStream } else { Permission::OutputStream };
+
+        if let Some(err_string) = opt_err {
+            return Err(self.stream_permission_error(
+                permission,
+                err_string,
+                stream.clone(),
+                caller,
+                arity,
+            ));
+        }
+
+        if let Some(input) = input {
+            if stream.past_end_of_stream {
+                self.eof_action(
+                    input,
+                    stream,
+                    caller,
+                    arity,
+                )?;
+            }
+        }
+
+        Ok(())
+    }
 }
 
 impl Read for Stream {
index 0837a0ad4e2709ed6aa12a490dc557b19dc28394..434922474afc398679e1ffd06083759a1bcb4b8d 100644 (file)
@@ -1596,33 +1596,15 @@ impl MachineState {
                 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,
-                    ));
-                }
+                self.check_stream_properties(
+                    &mut stream,
+                    StreamType::Binary,
+                    Some(self[temp_v!(2)]),
+                    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 {
@@ -1691,33 +1673,105 @@ impl MachineState {
                 }
             }
             &SystemClauseType::GetChar => {
+                let mut stream =
+                    self.get_stream_or_alias(self[temp_v!(1)], indices, "get_char", 2)?;
+
+                self.check_stream_properties(
+                    &mut stream,
+                    StreamType::Text,
+                    Some(self[temp_v!(2)]),
+                    clause_name!("get_char"),
+                    2,
+                )?;
+
+                if stream.past_end_of_stream {
+                    if EOFAction::Reset != stream.options.eof_action {
+                        return return_from_clause!(self.last_call, self);
+                    } else if self.fail {
+                        return Ok(());
+                    }
+                }
+
                 let mut iter = self.open_parsing_stream(
-                    current_input_stream.clone(),
+                    stream.clone(),
                     "get_char",
-                    1,
+                    2,
                 )?;
 
-                let result = iter.next();
-                let a1 = self[temp_v!(1)];
+                loop {
+                    let result = iter.next();
 
-                match result {
-                    Some(Ok(c)) => {
-                        self.unify(Addr::Char(c), a1);
-                    }
-                    Some(Err(_)) => {
-                        let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
-                            clause_name!("end_of_file"),
-                            None,
-                        ));
+                    match result {
+                        Some(Ok(c)) => {
+                            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::Char(c));
+                                        return return_from_clause!(self.last_call, self);
+                                    } else {
+                                        unreachable!()
+                                    }
+                                }
+                                Addr::Con(h) if self.heap.atom_at(h) => {
+                                    match &self.heap[h] {
+                                        HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
+                                            if let Some(d) = atom.as_str().chars().next() {
+                                                if c == d {
+                                                    return return_from_clause!(self.last_call, self);
+                                                } else {
+                                                    self.fail = true;
+                                                    return Ok(());
+                                                }
+                                            } else {
+                                                unreachable!()
+                                            }
+                                        }
+                                        _ => {
+                                            unreachable!()
+                                        }
+                                    }
+                                }
+                                Addr::Char(d) => {
+                                    if c == d {
+                                        return return_from_clause!(self.last_call, self);
+                                    } else {
+                                        self.fail = true;
+                                        return Ok(());
+                                    }
+                                }
+                                culprit => {
+                                    let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
+                                    let err = MachineError::type_error(
+                                        self.heap.h(),
+                                        ValidType::InCharacter,
+                                        culprit,
+                                    );
+
+                                    return Err(self.error_form(err, stub));
+                                }
+                            }
+                        }
+                        _ => {
+                            self.eof_action(
+                                self[temp_v!(2)],
+                                &mut stream,
+                                clause_name!("get_char"),
+                                2,
+                            )?;
 
-                        self.unify(a1, end_of_file);
-                    }
-                    None => {
-                        let stub = MachineError::functor_stub(clause_name!("get_char"), 1);
-                        let err = MachineError::representation_error(RepFlag::Character);
-                        let err = self.error_form(err, stub);
+                            if EOFAction::Reset != stream.options.eof_action {
+                                return return_from_clause!(self.last_call, self);
+                            } else if self.fail {
+                                return Ok(());
+                            }
+                        }/*
+                        _ => {
+                            let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
+                            let err = MachineError::representation_error(RepFlag::Character);
+                            let err = self.error_form(err, stub);
 
-                        return Err(err);
+                            return Err(err);
+                        }*/
                     }
                 }
             }
@@ -4035,6 +4089,14 @@ impl MachineState {
                     3,
                 )?;
 
+                self.check_stream_properties(
+                    &mut stream,
+                    StreamType::Text,
+                    None, // input
+                    clause_name!("write_term"),
+                    3,
+                )?;
+
                 let opt_err =
                     if !stream.is_output_stream() {
                         Some("stream") // 8.14.2.3 g)