]> Repositorios git - scryer-prolog.git/commitdiff
fix more conformity errors
authorMark Thom <[email protected]>
Sat, 6 Apr 2019 23:44:04 +0000 (17:44 -0600)
committerMark Thom <[email protected]>
Sat, 6 Apr 2019 23:44:04 +0000 (17:44 -0600)
Cargo.toml
src/prolog/clause_types.rs
src/prolog/heap_print.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_errors.rs
src/prolog/machine/system_calls.rs
src/prolog/read.rs

index 352b8bbbe0ab7d402d4c916a713cfa1b0eccbc4f..dcc362f21d3e4fc3c32839a763c6129012ecefe2 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.45"
+version = "0.8.46"
 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.16"
+prolog_parser = "0.8.17"
 readline_rs_compat = { version = "0.1.7", optional = true }
 ref_thread_local = "0.0.0"
 
index 520d2ecb6375a7cb82cc3047040a0dd51c306cb4..7eb0a03c15b6ff8b3f46ae37270cc6b5ee56fadd 100644 (file)
@@ -164,6 +164,7 @@ pub enum SystemClauseType {
     AtomLength,
     ModuleAssertDynamicPredicateToFront,
     ModuleAssertDynamicPredicateToBack,
+    CharCode,
     CheckCutPoint,
     CopyToLiftedHeap,
     DeleteAttribute,
@@ -174,6 +175,7 @@ pub enum SystemClauseType {
     ExpandGoal,
     ExpandTerm,
     FetchGlobalVar,
+    GetChar,
     TruncateIfNoLiftedHeapGrowthDiff,
     TruncateIfNoLiftedHeapGrowth,    
     GetAttributedVariableList,
@@ -242,6 +244,7 @@ impl SystemClauseType {
             &SystemClauseType::AtomLength => clause_name!("$atom_length"),
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => clause_name!("$module_asserta"),
             &SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
+            &SystemClauseType::CharCode => clause_name!("char_code"),
             &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
             &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
             &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
@@ -252,6 +255,7 @@ impl SystemClauseType {
             &SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
             &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
             &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
+            &SystemClauseType::GetChar => clause_name!("$get_char"),
             &SystemClauseType::TruncateIfNoLiftedHeapGrowth => clause_name!("$truncate_if_no_lh_growth"),
             &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => clause_name!("$truncate_if_no_lh_growth_diff"),
             &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
@@ -320,6 +324,7 @@ impl SystemClauseType {
             ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
             ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
             ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
+            ("$char_code", 2) => Some(SystemClauseType::CharCode),
             ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
             ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
             ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
@@ -334,6 +339,7 @@ impl SystemClauseType {
             ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
             ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
             ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
+            ("$get_char", 1) => Some(SystemClauseType::GetChar),
             ("$truncate_if_no_lh_growth", 1) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth),
             ("$truncate_if_no_lh_growth_diff", 2) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff),
             ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
index 50eafeaa463e38531f42d6fd6e71eab0803b5d6b..632a8fdb6432e78a397b564646c4e0c4fbeac03b 100644 (file)
@@ -42,7 +42,7 @@ impl DirectedOp {
 fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool
 {
     match op {
-        &DirectedOp::Left(ref name, ref cell) => {            
+        &DirectedOp::Left(ref name, ref cell) => {
             let (priority, spec) = cell.get();
 
             if name.as_str() == "-" {
@@ -51,15 +51,21 @@ fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool
                     return true;
                 }
             }
-            
+
             let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec);
             child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right)
         },
         &DirectedOp::Right(_, ref cell) => {
-            let (priority, spec) = cell.get();            
+            let (priority, spec) = cell.get();
             let is_strict_left = is_xfx!(spec) || is_xfy!(spec) || is_xf!(spec);
-            
-            child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_left)
+
+            if child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_left) {
+                true
+            } else if (is_postfix!(spec) || is_infix!(spec)) && !is_postfix!(child_spec.assoc()) {
+                child_spec.prec() == priority
+            } else {
+                false
+            }
         }
     }
 }
@@ -103,6 +109,20 @@ impl<'a> HCPreOrderIterator<'a> {
     }
 }
 
+fn char_to_string(c: char) -> String {
+    match c {
+        '\n' => "\\n".to_string(),
+        '\r' => "\\r".to_string(),
+        '\t' => "\\t".to_string(),
+        '\u{0b}' => "\\v".to_string(), // UTF-8 vertical tab
+        '\u{0c}' => "\\f".to_string(), // UTF-8 form feed
+        '\u{08}' => "\\b".to_string(), // UTF-8 backspace
+        '\u{07}' => "\\a".to_string(), // UTF-8 alert
+        '\x20' ... '\x7e' => c.to_string(),
+        _ => format!("\\x{:x}\\", c as u32)
+    }
+}
+
 #[derive(Clone)]
 pub enum TokenOrRedirect {
     Atom(ClauseName),
@@ -250,12 +270,6 @@ pub struct HCPrinter<'a, Outputter> {
 macro_rules! push_space_if_amb {
     ($self:expr, $atom:expr, $action:block) => (
         if $self.ambiguity_check($atom) {
-            if $self.last_item_idx > 1 {
-                if !$self.outputter.range(0 .. $self.last_item_idx).ends_with(" ") {
-                    $self.outputter.insert($self.last_item_idx, ' ');
-                }
-            }
-
             $self.outputter.push_char(' ');
             $action;
         } else {
@@ -277,8 +291,10 @@ fn requires_space(atom: &str, op: &str) -> bool {
                 alpha_numeric_char!(oc)
             } else if sign_char!(ac) {
                 sign_char!(oc) || decimal_digit_char!(oc)
+            } else if single_quote_char!(ac) {
+                single_quote_char!(oc)
             } else if ac == '0' {
-                !non_quoted_token(op.chars())
+                oc == 'b' || oc == 'x' || oc == 'o' || !non_quoted_token(op.chars())
             } else {
                 false
             }
@@ -432,7 +448,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
     fn format_negated_operand(&mut self, spec: SharedOpDesc)
     {
         let op = DirectedOp::Left(clause_name!("-"), spec);
-            
+
         self.state_stack.push(TokenOrRedirect::CompositeRedirect(op));
         self.state_stack.push(TokenOrRedirect::Space);
         self.state_stack.push(TokenOrRedirect::Atom(clause_name!("-")));
@@ -465,8 +481,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
             if self.format_numbered_vars(iter) {
                 return;
             }
-        }        
-        
+        }
+
         if let Some(spec) = ct.spec() {
             if "." == ct.name().as_str() && is_infix!(spec.assoc()) {
                 if !self.ignore_ops {
@@ -474,7 +490,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
                     return;
                 }
             }
-            
+
             if !self.ignore_ops && spec.prec() > 0 {
                 return self.enqueue_op(ct, spec);
             }
@@ -533,7 +549,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
 
                         if let Some(offset_str) = self.offset_as_string(addr) {
                             push_space_if_amb!(self, &offset_str, {
-                                self.append_str(offset_str.as_str());
+                                self.append_str(&offset_str);
                             });
                         }
 
@@ -555,53 +571,47 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
     }
 
     fn print_atom(&mut self, atom: &ClauseName) {
-        push_space_if_amb!(self, atom.as_str(), {
-            self.print_op_addendum(atom.as_str());
+        let result = self.print_op_addendum(atom.as_str());
+
+        push_space_if_amb!(self, result.as_str(), {
+            self.append_str(&result);
         });
     }
 
-    fn print_op_addendum(&mut self, atom: &str) {
+    fn print_op_addendum(&mut self, atom: &str) -> String {
         if !self.quoted || non_quoted_token(atom.chars()) {
-            self.append_str(atom);
+            atom.to_string()
         } else if atom == "''" {
-            self.append_str("''");
+            "''".to_string()
         } else {
+            let mut result = String::new();
+
             if self.quoted {
-                self.push_char('\'');
+                result.push('\'');
             }
 
             for c in atom.chars() {
-                self.print_char(c);
+                result += &char_to_string(c);
             }
 
             if self.quoted {
-                self.push_char('\'');
+                result.push('\'');
             }
+
+            result
         }
     }
 
     fn print_op(&mut self, atom: &str) {
-        push_space_if_amb!(self, atom, {
-            if atom == "," {
-                self.push_char(',');
-            } else {
-                self.print_op_addendum(atom);
-            }
-        });
-    }
-
-    fn print_char(&mut self, c: char) {
-        match c {
-            '\n' => self.append_str("\\n"),
-            '\r' => self.append_str("\\r"),
-            '\t' => self.append_str("\\t"),
-            '\u{0b}' => self.append_str("\\v"), // UTF-8 vertical tab
-            '\u{0c}' => self.append_str("\\f"), // UTF-8 form feed
-            '\u{08}' => self.append_str("\\b"), // UTF-8 backspace
-            '\u{07}' => self.append_str("\\a"), // UTF-8 alert
-            '\x20' ... '\x7e' => self.push_char(c),
-            _ => self.append_str(&format!("\\x{:x}\\", c as u32))
+        let result = if atom == "," {
+            ",".to_string()
+        } else {
+            self.print_op_addendum(atom)
         };
+
+        push_space_if_amb!(self, &result, {
+            self.append_str(&result);
+        });
     }
 
     fn print_number(&mut self, n: Number, op: &Option<DirectedOp>) {
@@ -645,37 +655,49 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
 
     fn print_constant(&mut self, c: Constant, op: &Option<DirectedOp>) {
         match c {
-            Constant::Atom(ref atom, Some(_)) => {
+            Constant::Atom(ref atom, Some(ref spec)) if spec.prec() > 0 => {
                 if let Some(ref op) = op {
                     if self.outputter.ends_with(&format!(" {}", op.as_str())) {
                         self.push_char(' ');
                     }
-                    
+
                     self.push_char('(');
                 }
-                
+
                 self.print_atom(atom);
 
                 if op.is_some() {
                     self.push_char(')');
                 }
             },
-            Constant::Atom(ref atom, None) =>
+            Constant::Atom(ref atom, _) =>
                 push_space_if_amb!(self, atom.as_str(), {
                     self.print_atom(atom);
                 }),
-            Constant::Char(c) if non_quoted_token(once(c)) =>
-                self.print_char(c),
-            Constant::Char(c) =>
+            Constant::Char(c) if non_quoted_token(once(c)) => {
+                let c = char_to_string(c);
+
+                push_space_if_amb!(self, &c, {
+                    self.append_str(c.as_str());
+                });
+            },
+            Constant::Char(c) => {
+                let mut result = String::new();
+
                 if self.quoted {
-                    self.push_char('\'');
-                    self.print_char(c);
-                    self.push_char('\'');
+                    result.push('\'');
+                    result += &char_to_string(c);
+                    result.push('\'');
                 } else {
-                    self.print_char(c);
-                },
+                    result += &char_to_string(c);
+                }
+
+                push_space_if_amb!(self, &result, {
+                    self.append_str(result.as_str());
+                });
+            },
             Constant::CharCode(c) =>
-                self.append_str(&format!("{}", c)),            
+                self.append_str(&format!("{}", c)),
             Constant::EmptyList =>
                 self.append_str("[]"),
             Constant::Number(n) =>
index e86e305d461b34303a3f161275ec2b72108d3e9b..6e87ff6671c435029373c84474c1e6768a470370 100644 (file)
@@ -9,12 +9,12 @@
        abolish/1, asserta/1, assertz/1, atom_chars/2, atom_codes/2,
        atom_length/2, bagof/3, bb_b_put/2, bb_get/2, bb_put/2,
        call_cleanup/2, call_with_inference_limit/3, catch/3,
-       clause/2, current_predicate/1, current_op/3,
+       char_code/2, clause/2, current_predicate/1, current_op/3,
        current_prolog_flag/2, expand_goal/2, expand_term/2,
-       findall/3, findall/4, halt/0, once/1, op/3, repeat/0,
-       retract/1, set_prolog_flag/2, setof/3, setup_call_cleanup/3,
-       term_variables/2, throw/1, true/0, false/0, write/1,
-       write_canonical/1, writeq/1, write_term/2]).
+       findall/3, findall/4, get_char/1, halt/0, once/1, op/3,
+       repeat/0, retract/1, set_prolog_flag/2, setof/3,
+       setup_call_cleanup/3, term_variables/2, throw/1, true/0,
+       false/0, write/1, write_canonical/1, writeq/1, write_term/2]).
 
 /* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
    and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
@@ -816,7 +816,7 @@ no_var_in_list([]).
 no_var_in_list([X|Xs]) :- var(X), !, '$fail'.
 no_var_in_list([_|Xs]) :- no_var_in_list(Xs).
 
-atom_chars(Atom, List) :-    
+atom_chars(Atom, List) :-
     (  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)
@@ -825,7 +825,7 @@ atom_chars(Atom, List) :-
     ;  throw(error(type_error(atom, Atom), atom_chars/2))
     ).
 
-atom_codes(Atom, List) :-    
+atom_codes(Atom, List) :-
     (  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)
@@ -833,3 +833,19 @@ atom_codes(Atom, List) :-
     ;  atom(Atom) -> '$atom_codes'(Atom, List)
     ;  throw(error(type_error(atom, Atom), atom_codes/2))
     ).
+
+char_code(Char, Code) :-
+    (  var(Char) ->
+       (  var(Code) -> throw(error(instantiation_error, char_code/2))
+       ;  integer(Code) -> '$char_code'(Char, Code)
+       ;  throw(error(type_error(integer, Code), char_code/2))
+       )
+    ;  atom_length(Char, 1) -> '$char_code'(Char, Code)
+    ;  throw(error(type_error(character, Char), char_code/2))
+    ).
+
+get_char(C) :-
+    (  var(C) -> '$get_char'(C)
+    ;  atom_length(C, 1) -> '$get_char'(C)
+    ;  throw(error(type_error(in_character, C), get_char/1))
+    ).
index 59d670861865f0205d255f46b194498f620affd2..d69bfef60a67cef2f6edf038d4d32d81670fceb2 100644 (file)
@@ -224,7 +224,7 @@ impl DomainError {
 // from 7.12.2 f) of 13211-1:1995
 #[derive(Clone, Copy)]
 pub enum RepFlag {
-//    Character,
+    Character,
     CharacterCode,
 //    InCharacterCode,
     MaxArity,
@@ -235,7 +235,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 f8bbde797953ec0871333946644ca00716f3ee14..ebf42e07d9a7a92bf6c8b75fa77cdc8356cce188 100644 (file)
@@ -15,7 +15,7 @@ use prolog::num::bigint::{BigInt};
 use ref_thread_local::RefThreadLocal;
 
 use std::collections::HashSet;
-use std::io::{stdout, Write};
+use std::io::{stdout, Read, Write};
 use std::iter::once;
 use std::mem;
 use std::rc::Rc;
@@ -355,14 +355,14 @@ impl MachineState {
                         let a2 = self[temp_v!(2)].clone();
                         let chars = vec![Addr::Con(Constant::Char('[')),
                                          Addr::Con(Constant::Char(']'))];
-                        
+
                         let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
 
                         self.unify(a2, list_of_chars);
                     },
                     ref addr if addr.is_ref() => {
                         let stub = MachineError::functor_stub(clause_name!("atom_chars"), 2);
-                        
+
                         match self.try_from_list(temp_v!(2), stub.clone()) {
                             Err(e) => return Err(e),
                             Ok(addrs) => {
@@ -402,7 +402,7 @@ impl MachineState {
 
                         let a2 = self[temp_v!(2)].clone();
                         self.unify(a2, list_of_codes);
-                    },                    
+                    },
                     Addr::Con(Constant::Atom(name, _)) => {
                         let iter = name.as_str().chars().map(|c| Addr::Con(Constant::CharCode(c as u8)));
                         let list_of_codes = Addr::HeapCell(self.heap.to_list(iter));
@@ -415,7 +415,7 @@ impl MachineState {
                         let a2 = self[temp_v!(2)].clone();
                         let chars = vec![Addr::Con(Constant::CharCode('[' as u8)),
                                          Addr::Con(Constant::CharCode(']' as u8))];
-                        
+
                         let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
 
                         self.unify(a2, list_of_codes);
@@ -452,12 +452,14 @@ impl MachineState {
 
                 let atom = match self.store(self.deref(a1)) {
                     Addr::Con(Constant::Atom(name, _)) => name,
+                    Addr::Con(Constant::EmptyList) => clause_name!("[]"),
+                    Addr::Con(Constant::Char(c)) => clause_name!(c.to_string(), indices.atom_tbl),
                     _ => unreachable!()
                 };
 
                 let len = Number::Integer(Rc::new(BigInt::from_usize(atom.as_str().len()).unwrap()));
                 let a2  = self[temp_v!(2)].clone();
-                
+
                 self.unify(a2, Addr::Con(Constant::Number(len)));
             },
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
@@ -480,6 +482,42 @@ impl MachineState {
 
                 self.unify(a1, lh_len);
             },
+            &SystemClauseType::CharCode => {
+                let a1 = self[temp_v!(1)].clone();
+
+                match self.store(self.deref(a1)) {
+                    Addr::Con(Constant::Atom(name, _)) => {
+                        let c = name.as_str().chars().next().unwrap();
+                        let a2 = self[temp_v!(2)].clone();
+
+                        self.unify(Addr::Con(Constant::CharCode(c as u8)), a2);
+                    },
+                    Addr::Con(Constant::Char(c)) => {
+                        let a2 = self[temp_v!(2)].clone();
+                        self.unify(Addr::Con(Constant::CharCode(c as u8)), a2);
+                    },
+                    ref addr if addr.is_ref() => {
+                        let a2 = self[temp_v!(2)].clone();
+                        
+                        match self.store(self.deref(a2)) {
+                            Addr::Con(Constant::CharCode(code)) =>
+                                self.unify(Addr::Con(Constant::Char(code as char)), addr.clone()),
+                            Addr::Con(Constant::Number(Number::Integer(n))) =>
+                                if let Some(c) = n.to_u8() {
+                                    self.unify(Addr::Con(Constant::Char(c as char)), addr.clone());
+                                } else {
+                                    let stub = MachineError::functor_stub(clause_name!("char_code"), 2);
+                                    let err = MachineError::representation_error(RepFlag::CharacterCode);
+                                    let err = self.error_form(err, stub);
+
+                                    return Err(err);
+                                },
+                            _ => self.fail = true
+                        };
+                    },
+                    _ => unreachable!()
+                };
+            },
             &SystemClauseType::CheckCutPoint => {
                 let addr = self.store(self.deref(self[temp_v!(1)].clone()));
 
@@ -503,6 +541,25 @@ impl MachineState {
                     None => self.fail = true
                 };
             },
+            &SystemClauseType::GetChar => {
+                let c = std::io::stdin()
+                    .bytes() 
+                    .next()
+                    .and_then(|result| result.ok());
+
+                let a1 = self[temp_v!(1)].clone();
+                
+                match c {
+                    Some(c) => self.unify(Addr::Con(Constant::Char(c as char)), a1),
+                    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);
+
+                        return Err(err);
+                    }
+                }                
+            },
             &SystemClauseType::GetModuleClause => {
                 let module = self[temp_v!(3)].clone();
                 let head = self[temp_v!(1)].clone();
index 17d030e0dffbe6139a4b231712c2244b4e821ebe..1506486851bdb4219b57943bd2b0d14063f1a1ff 100644 (file)
@@ -40,7 +40,7 @@ pub mod readline
         Single,
         Multi
     }
-    
+
     static mut LINE_MODE: LineMode = LineMode::Single;
     static mut END_OF_LINE: bool = false;
 
@@ -117,7 +117,7 @@ pub mod readline
         if let LineMode::Single = LINE_MODE {
             insert_text_rl("?- ");
         }
-        
+
         0
     }
 
@@ -140,7 +140,7 @@ pub mod readline
 pub mod readline
 {
     use std::io::{BufRead, Read, stdin, stdout, Write};
-    
+
     pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> {
         let mut buf = vec![];
 
@@ -159,14 +159,14 @@ pub mod readline
 
         let stdin = stdin();
         let stdin = stdin.lock();
-        
+
         let mut buf = "?- ".to_string();
-        
+
         for line in stdin.lines() {
             match line {
                 Ok(line) => {
                     buf += &line;
-                    
+
                     if line.trim().ends_with(".") {
                         break;
                     }