]> Repositorios git - scryer-prolog.git/commitdiff
correct various bugs
authorMark Thom <[email protected]>
Mon, 29 Apr 2019 03:09:56 +0000 (21:09 -0600)
committerMark Thom <[email protected]>
Mon, 29 Apr 2019 03:09:56 +0000 (21:09 -0600)
Cargo.toml
src/prolog/lib/builtins.pl
src/prolog/machine/machine_errors.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/system_calls.rs

index 384e1f8f41f575c6f893de27a81d612cd9fa61c2..0bcfb2d68647a8148943175efe63fb2f1061f357 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.73"
+version = "0.8.74"
 authors = ["Mark Thom <[email protected]>"]
 repository = "https://github.com/mthom/scryer-prolog"
 description = "A modern Prolog implementation written mostly in Rust."
@@ -14,7 +14,7 @@ cfg-if = "0.1.7"
 downcast = "0.10.0"
 num = "0.2"
 ordered-float = "0.5.0"
-prolog_parser = "0.8.23"
+prolog_parser = "0.8.24"
 readline_rs_compat = { version = "0.1.9", optional = true }
 ref_thread_local = "0.0.0"
 
index 3a8d81e79eb3ce17790708451749f37d965e89e9..1c8ea40d5c34fb205f8750586f5cc8e2901eb02e 100644 (file)
@@ -733,27 +733,31 @@ atom_length(Atom, Length) :-
     ;  throw(error(type_error(atom, Atom), atom_length/2)) % 8.16.1.3 b)
     ).
 
-no_var_in_list([]).
-no_var_in_list([X|Xs]) :- var(X), !, '$fail'.
-no_var_in_list([_|Xs]) :- nonvar(Xs), no_var_in_list(Xs).
-
 atom_chars(Atom, List) :-
+    '$skip_max_list'(_, -1, List, Tail),
+    (  ( Tail == [] ; var(Tail) ) -> true
+    ;  throw(error(type_error(list, List), atom_chars/2))
+    ),
     (  var(Atom) ->
-       (  var(List) -> throw(error(instantiation_error, atom_chars/2))
-       ;  can_be_list(List, atom_chars/3), no_var_in_list(List) -> '$atom_chars'(Atom, List)
+       (  var(Tail) -> throw(error(instantiation_error, atom_chars/2))
+       ;  ground(List), Tail == [] -> '$atom_chars'(Atom, List)
        ;  throw(error(instantiation_error, atom_chars/2))
        )
-    ;  atom(Atom) -> '$atom_chars'(Atom, List)
+    ;  atom(Atom) -> can_be_chars_or_vars(List, atom_chars/2), '$atom_chars'(Atom, List)
     ;  throw(error(type_error(atom, Atom), atom_chars/2))
     ).
 
 atom_codes(Atom, List) :-
+    '$skip_max_list'(_, -1, List, Tail),
+    (  ( Tail == [] ; var(Tail) ) -> true
+    ;  throw(error(type_error(list, List), atom_codes/2))
+    ),
     (  var(Atom) ->
-       (  var(List) -> throw(error(instantiation_error, atom_codes/2))
-       ;  can_be_list(List, atom_codes/3), no_var_in_list(List) -> '$atom_codes'(Atom, List)
+       (  var(Tail) -> throw(error(instantiation_error, atom_codes/2))
+       ;  ground(List), Tail == [] -> '$atom_codes'(Atom, List)
        ;  throw(error(instantiation_error, atom_codes/2))
        )
-    ;  atom(Atom) -> '$atom_codes'(Atom, List)
+    ;  atom(Atom) -> can_be_codes_or_vars(List, atom_codes/2), '$atom_codes'(Atom, List)
     ;  throw(error(type_error(atom, Atom), atom_codes/2))
     ).
 
@@ -789,16 +793,35 @@ must_be_number(N, PI) :-
     ;  throw(error(instantiation_error, PI))
     ).
 
-must_be_chars([], _).
-must_be_chars([C|Cs], PI) :-
+can_be_chars_or_vars(Cs, _) :- var(Cs), !.
+can_be_chars_or_vars(Cs, PI) :- chars_or_vars(Cs, PI).
+
+chars_or_vars([], _).
+chars_or_vars([C|Cs], PI) :-
     (  nonvar(C) ->
-       (  atom_length(C, 1) ->
-         (  nonvar(Cs) -> must_be_chars(Cs, PI)
-         ;  false %% throw(error(type_error(list, Cs), PI))
+       (  catch(atom_length(C, 1), _, false) ->
+         (  nonvar(Cs) -> chars_or_vars(Cs, PI)
+         ;  false
          )
        ;  throw(error(type_error(character, C), PI))
        )
-    ;  must_be_chars(Cs, PI)
+    ;  chars_or_vars(Cs, PI)
+    ).
+
+can_be_codes_or_vars(Cs, _) :- var(Cs), !.
+can_be_codes_or_vars(Cs, PI) :- codes_or_vars(Cs, PI).
+
+codes_or_vars([], _).
+codes_or_vars([C|Cs], PI) :-
+    (  nonvar(C) ->
+       (  catch(char_code(_, C), _, false) ->
+         (  nonvar(Cs) -> codes_or_vars(Cs, PI)
+         ;  false
+         )
+       ;  integer(C) -> throw(error(representation_error(character_code), PI))
+       ;  throw(error(type_error(integer, C), PI))
+       )
+    ;  codes_or_vars(Cs, PI)
     ).
 
 number_chars(N, Chs) :-
@@ -810,7 +833,7 @@ number_chars(N, Chs) :-
    ;  must_be_number(N, number_chars/2),
       (  var(Chs) -> true
       ;  can_be_list(Chs, number_chars/2)
-      ,  must_be_chars(Chs, number_chars/2)
+      ,  chars_or_vars(Chs, number_chars/2)
       ),
       '$number_to_chars'(N, Chsx),
       Chsx = Chs
index bdfdd343a857b7aabb8d15cc1aa341592ae7e62b..e9eb56f3e59994c4aca9d98f841fbb10235e69d1 100644 (file)
@@ -1,4 +1,5 @@
 use prolog_parser::ast::*;
+use prolog_parser::string_list::*;
 
 use prolog::machine::machine_indices::*;
 use prolog::machine::machine_state::*;
@@ -273,6 +274,7 @@ pub(super) enum CycleSearchResult {
     NotList,
     PartialList(usize, usize), // the list length (up to max), and an offset into the heap.
     ProperList(usize), // the list length.
+    String(usize, StringList), // the number of elements iterated, the string tail.
     UntouchedList(usize) // the address of an uniterated Addr::Lis(address).
 }
 
index a870c21e7fd6196f51acdf9730b8a8214feaf1a5..3994787c90b565716cfa1f0025d15a4dc187dc75 100644 (file)
@@ -239,6 +239,36 @@ pub struct MachineState {
 }
 
 impl MachineState {
+    pub(super)
+    fn try_char_list(&self, addrs: Vec<Addr>) -> Result<String, MachineError>
+    {
+        let mut chars = String::new();
+        let mut iter = addrs.iter();
+        
+        while let Some(addr) = iter.next() {
+            match addr {
+                &Addr::Con(Constant::String(ref s))
+                    if self.flags.double_quotes.is_chars() => {
+                        chars += s.borrow().as_str();
+
+                        if iter.next().is_some() {
+                            return Err(MachineError::type_error(ValidType::Character, addr.clone()));
+                        }
+                    },
+                &Addr::Con(Constant::Char(c)) =>
+                    chars.push(c),
+                &Addr::Con(Constant::Atom(ref name, _))
+                    if name.as_str().len() == 1 => {
+                        chars += name.as_str();
+                    },
+                _ =>
+                    return Err(MachineError::type_error(ValidType::Character, addr.clone()))
+            }
+        }
+
+        Ok(chars)
+    }
+
     fn call_at_index(&mut self, arity: usize, p: usize)
     {
         self.cp.assign_if_local(self.p.clone() + 1);
@@ -320,27 +350,6 @@ fn try_in_situ(machine_st: &mut MachineState, name: ClauseName, arity: usize,
     }
 }
 
-pub(super)
-fn try_char_list(addrs: Vec<Addr>) -> Result<String, MachineError>
-{        
-    let mut chars = String::new();
-
-    for addr in addrs.iter() {
-        match addr {
-            &Addr::Con(Constant::Char(c)) =>
-                chars.push(c),
-            &Addr::Con(Constant::Atom(ref name, _))
-                if name.as_str().len() == 1 => {
-                    chars += name.as_str();
-                },
-            _ =>
-                return Err(MachineError::type_error(ValidType::Character, addr.clone()))
-        }
-    }
-
-    Ok(chars)        
-}
-
 pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
 
 pub(crate) trait CallPolicy: Any {
index f022f0d932e388bcb2bf1e462fc5b0c91d66e3ce..a5d11bb860d761cfc722d3922de1a7802c08abd0 100644 (file)
@@ -1691,6 +1691,21 @@ impl MachineState {
                         } else {
                             self.fail = true;
                         },
+                    Addr::Con(Constant::String(ref s))
+                        if self.flags.double_quotes.is_chars() && !s.is_empty() => {
+                            if n == 1 || n == 2 {
+                                let a3  = self[temp_v!(3)].clone();
+                                let h_a = if n == 1 {
+                                    Addr::Con(Constant::Char(s.head().unwrap()))
+                                } else {
+                                    Addr::Con(Constant::String(s.tail()))
+                                };
+                                
+                                self.unify(a3, h_a);
+                            } else {
+                                self.fail = true;
+                            }
+                        },
                     _ => // 8.5.2.3 d)
                         return Err(self.error_form(MachineError::type_error(ValidType::Compound, term),
                                                    stub))
@@ -2089,6 +2104,11 @@ impl MachineState {
         match a1.clone() {
             Addr::DBRef(_) =>
                 self.fail = true,
+            Addr::Con(Constant::String(ref s))
+                if self.flags.double_quotes.is_chars() && !s.is_empty() => {
+                    let shared_op_desc = fetch_op_spec(clause_name!("."), 2, None, &indices.op_dir);
+                    self.try_functor_compound_case(clause_name!("."), 2, shared_op_desc)
+                },
             Addr::Con(_) =>
                 self.try_functor_unify_components(a1, Addr::Con(integer!(0))),
             Addr::Str(o) =>
@@ -2187,7 +2207,7 @@ impl MachineState {
             
             match self.try_from_list(r, stub.clone()) {
                 Ok(addrs) =>
-                    Ok(StringList::new(match try_char_list(addrs) {
+                    Ok(StringList::new(match self.try_char_list(addrs) {
                         Ok(string) => string,
                         Err(err) => {                            
                             return Err(self.error_form(err, stub));
@@ -2218,6 +2238,11 @@ impl MachineState {
                                     result.push(self.heap[hcp].as_addr(hcp));
                                     l = hcp + 1;
                                 },
+                                Addr::Con(Constant::String(ref s))
+                                    if self.flags.double_quotes.is_chars() => {
+                                        result.push(Addr::Con(Constant::String(s.clone())));
+                                        break;
+                                    },
                                 Addr::Con(Constant::EmptyList) =>
                                     break,
                                 Addr::HeapCell(_) | Addr::StackCell(..) =>
@@ -2229,11 +2254,13 @@ impl MachineState {
                         _ =>
                             return Err(self.error_form(MachineError::type_error(ValidType::List, a1),
                                                        caller))
-                    };
+                    }
                 }
 
                 Ok(result)
             },
+            Addr::Con(Constant::String(ref s)) if self.flags.double_quotes.is_chars() =>
+                Ok(vec![Addr::Con(Constant::String(s.clone()))]),
             Addr::HeapCell(_) | Addr::StackCell(..) =>
                 Err(self.error_form(MachineError::instantiation_error(), caller)),
             Addr::Con(Constant::EmptyList) =>
index e463b81206b559dbc98871f631789ccf4bedb602..bf0735fc4b9409dc6fc15aca321ca736b7d4fe9d 100644 (file)
@@ -1,5 +1,6 @@
 use prolog_parser::ast::*;
 use prolog_parser::parser::*;
+use prolog_parser::string_list::*;
 use prolog_parser::tabled_rc::*;
 
 use prolog::clause_types::*;
@@ -49,6 +50,9 @@ impl MachineState {
                         Some(CycleSearchResult::ProperList(brent_st.steps)),
                     Addr::HeapCell(_) | Addr::StackCell(..) =>
                         Some(CycleSearchResult::PartialList(brent_st.steps, brent_st.hare)),
+                    Addr::Con(Constant::String(ref s))
+                        if self.flags.double_quotes.is_chars() =>
+                          Some(CycleSearchResult::String(brent_st.steps, s.clone())),
                     Addr::Lis(l) => {
                         brent_st.hare = l + 1;
                         brent_st.steps += 1;
@@ -75,6 +79,9 @@ impl MachineState {
             Addr::Lis(offset) if max_steps > 0 => offset + 1,
             Addr::Lis(offset) => return CycleSearchResult::UntouchedList(offset),
             Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
+            Addr::Con(Constant::String(ref s))
+                if self.flags.double_quotes.is_chars() =>
+                   return CycleSearchResult::String(0, s.clone()),
             _ => return CycleSearchResult::NotList
         };
 
@@ -97,6 +104,9 @@ impl MachineState {
         let hare = match addr {
             Addr::Lis(offset) => offset + 1,
             Addr::Con(Constant::EmptyList) => return CycleSearchResult::EmptyList,
+            Addr::Con(Constant::String(ref s))
+                if self.flags.double_quotes.is_chars() =>
+                   return CycleSearchResult::String(0, s.clone()),
             _ => return CycleSearchResult::NotList
         };
 
@@ -135,18 +145,35 @@ impl MachineState {
                             self.unify(xs0, xs);
                         },
                         _ => {
-                            let search_result = if let Some(max_steps) = max_steps.to_isize() {
-                                if max_steps == -1 {
-                                    self.detect_cycles(self[temp_v!(3)].clone())
+                            let (max_steps, search_result) =
+                                if let Some(max_steps) = max_steps.to_isize() {
+                                    (max_steps, if max_steps == -1 {
+                                        self.detect_cycles(self[temp_v!(3)].clone())
+                                    } else {
+                                        self.detect_cycles_with_max(max_steps as usize,
+                                                                    self[temp_v!(3)].clone())
+                                    })
                                 } else {
-                                    self.detect_cycles_with_max(max_steps as usize,
-                                                                self[temp_v!(3)].clone())
-                                }
-                            } else {
-                                self.detect_cycles(self[temp_v!(3)].clone())
-                            };
+                                    (-1, self.detect_cycles(self[temp_v!(3)].clone()))
+                                };
 
                             match search_result {
+                                CycleSearchResult::String(n, s) =>                                    
+                                    if max_steps == -1 {
+                                        self.finalize_skip_max_list(n + s.len(),
+                                                                    Addr::Con(Constant::EmptyList))
+                                    } else {
+                                        let i = max_steps.to_usize().unwrap() - n;
+
+                                        if s.len() < i {
+                                            self.finalize_skip_max_list(n + s.len(),
+                                                                        Addr::Con(Constant::EmptyList))
+                                        } else {
+                                            let s = StringList::new(s.char_span(i), s.is_expandable());
+                                            self.finalize_skip_max_list(i + n,
+                                                                        Addr::Con(Constant::String(s)))
+                                        }
+                                    },
                                 CycleSearchResult::UntouchedList(l) =>
                                     self.finalize_skip_max_list(0, Addr::Lis(l)),
                                 CycleSearchResult::EmptyList =>
@@ -395,7 +422,7 @@ impl MachineState {
                         match self.try_from_list(temp_v!(2), stub.clone()) {
                             Err(e) => return Err(e),
                             Ok(addrs) =>
-                                match try_char_list(addrs) {
+                                match self.try_char_list(addrs) {
                                     Ok(string) => {
                                         let chars = clause_name!(string, indices.atom_tbl);
                                         self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None)));
@@ -453,7 +480,7 @@ impl MachineState {
                                         &Addr::Con(Constant::CharCode(c)) =>
                                             chars.push(c as char),
                                         _ => {
-                                            let err = MachineError::representation_error(RepFlag::CharacterCode);
+                                            let err = MachineError::type_error(ValidType::Integer, addr.clone());
                                             return Err(self.error_form(err, stub));
                                         }
                                     }
@@ -489,19 +516,19 @@ impl MachineState {
                 match self.try_from_list(temp_v!(1), stub.clone()) {
                     Err(e) => return Err(e),
                     Ok(addrs) =>
-                        match try_char_list(addrs) {
+                        match self.try_char_list(addrs) {
                             Ok(mut string) => {
                                 if let Some(c) = string.chars().last() {
                                     if layout_char!(c) {
                                         let err = ParserError::UnexpectedChar(c);
-                                        
+
                                         let h = self.heap.h;
                                         let err = MachineError::syntax_error(h, err);
 
                                         return Err(self.error_form(err, stub));
                                     }
                                 }
-                                
+
                                 string.push('.');
 
                                 let mut stream = parsing_stream(std::io::Cursor::new(string));
@@ -521,7 +548,7 @@ impl MachineState {
                                         self.unify(nx, Addr::Con(Constant::CharCode(c))),
                                     _ => {
                                         let err = ParserError::ParseBigInt;
-                                        
+
                                         let h = self.heap.h;
                                         let err = MachineError::syntax_error(h, err);