]> Repositorios git - scryer-prolog.git/commitdiff
add number_chars/2
authorMark Thom <[email protected]>
Sun, 28 Apr 2019 20:36:38 +0000 (14:36 -0600)
committerMark Thom <[email protected]>
Sun, 28 Apr 2019 20:36:38 +0000 (14:36 -0600)
Cargo.toml
README.md
src/prolog/clause_types.rs
src/prolog/lib/builtins.pl
src/prolog/machine/machine_state.rs
src/prolog/machine/system_calls.rs

index 222973ab11e63dafa6a54a53d4515d6c9621a1d2..46257588ac3675b299959472beec3277062b8d32 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "scryer-prolog"
-version = "0.8.70"
+version = "0.8.71"
 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.22"
+prolog_parser = "0.8.23"
 readline_rs_compat = { version = "0.1.9", optional = true }
 ref_thread_local = "0.0.0"
 
index 14c835bc2c7b1a7710a96cd01140094cd5aaafb9..aa047a7688c47ced9763173eb27a964ee4d35dd4 100644 (file)
--- a/README.md
+++ b/README.md
@@ -206,6 +206,7 @@ The following predicates are built-in to Scryer.
 * `must_be/2`
 * `nl/0`
 * `nonvar/1`
+* `number_chars/2`
 * `numbervars/2`
 * `numlist/{2,3}`
 * `once/1`
index fc78dfd309152d51821714449cd5251b934e2781..63e46545bc8d40889816c06f633f3f3aa9ca41d6 100644 (file)
@@ -165,6 +165,7 @@ pub enum SystemClauseType {
     ModuleAssertDynamicPredicateToFront,
     ModuleAssertDynamicPredicateToBack,
     CharCode,
+    CharsToNumber,
     CheckCutPoint,
     CopyToLiftedHeap,
     DeleteAttribute,
@@ -200,6 +201,7 @@ pub enum SystemClauseType {
     ModuleOf,
     ModuleRetractClause,
     NoSuchPredicate,
+    NumberToChars,
     OpDeclaration,
     REPL(REPLCodePtr),
     ReadTerm,
@@ -246,7 +248,8 @@ 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::CharCode => clause_name!("$char_code"),
+            &SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
             &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
             &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
             &SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) =>
@@ -286,6 +289,7 @@ impl SystemClauseType {
             &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
             &SystemClauseType::ModuleOf => clause_name!("$module_of"),
             &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
+            &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
             &SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
             &SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
             &SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
@@ -331,6 +335,7 @@ impl SystemClauseType {
             ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
             ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
             ("$char_code", 2) => Some(SystemClauseType::CharCode),
+            ("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
             ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
             ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
             ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
@@ -366,6 +371,7 @@ impl SystemClauseType {
             ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
             ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
             ("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
+            ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
             ("$op", 3) => Some(SystemClauseType::OpDeclaration),
             ("$redo_attr_var_bindings", 0) => Some(SystemClauseType::RedoAttrVarBindings),
             ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
index 207b8e98b2501865a8aca2083102b89677d152f4..7a4a09f90b55d08b73c4a3cc383151bb32d4e2c3 100644 (file)
        atom_length/2, bagof/3, catch/3, char_code/2, clause/2,
        current_op/3, current_predicate/1, current_prolog_flag/2,
        expand_goal/2, expand_term/2, false/0, findall/3, findall/4,
-       get_char/1, halt/0, once/1, op/3, read_term/2, repeat/0,
-       retract/1, set_prolog_flag/2, setof/3, term_variables/2,
-       throw/1, true/0, write/1, write_canonical/1, write_term/2,
-       writeq/1]).
+       get_char/1, halt/0, number_chars/2, once/1, op/3, read_term/2,
+       repeat/0, retract/1, set_prolog_flag/2, setof/3,
+       term_variables/2, throw/1, true/0, write/1, write_canonical/1,
+       write_term/2, writeq/1]).
 
 % module resolution operator.
 :- op(600, xfy, :).
@@ -773,3 +773,45 @@ get_char(C) :-
     ;  atom_length(C, 1) -> '$get_char'(C)
     ;  throw(error(type_error(in_character, C), get_char/1))
     ).
+
+can_be_number(N, PI) :-
+    (  var(N) -> true
+    ;  must_be_number(N, PI)
+    ).
+
+must_be_number(N, _) :-
+    (  integer(N)
+    ;  float(N)
+    ),
+    !.
+must_be_number(N, PI) :-
+    (  nonvar(N) -> throw(error(type_error(number, N), PI))
+    ;  throw(error(instantiation_error, PI))
+    ).
+
+must_be_chars([], _).
+must_be_chars([C|Cs], PI) :-
+    (  nonvar(C) ->
+       (  atom_length(C, 1) ->
+         (  nonvar(Cs) -> must_be_chars(Cs, PI)
+         ;  false %% throw(error(type_error(list, Cs), PI))
+         )
+       ;  throw(error(type_error(character, C), PI))
+       )
+    ;  must_be_chars(Cs, PI)
+    ).
+
+number_chars(N, Chs) :-
+   (  ground(Chs)
+   -> can_be_number(N, number_chars/2),
+      can_be_list(Chs, number_chars/2),
+      '$chars_to_number'(Chs, Nx),
+      Nx = N
+   ;  must_be_number(N, number_chars/2),
+      (  var(Chs) -> true
+      ;  can_be_list(Chs, number_chars/2)
+      ,  must_be_chars(Chs, number_chars/2)
+      ),
+      '$number_to_chars'(N, Chsx),
+      Chsx = Chs
+    ).
index fd6b8c92f539c660eecacdf469a81d8cf2b09216..a870c21e7fd6196f51acdf9730b8a8214feaf1a5 100644 (file)
@@ -320,7 +320,8 @@ fn try_in_situ(machine_st: &mut MachineState, name: ClauseName, arity: usize,
     }
 }
 
-pub(super) fn try_char_list(addrs: Vec<Addr>) -> Result<String, MachineError>
+pub(super)
+fn try_char_list(addrs: Vec<Addr>) -> Result<String, MachineError>
 {        
     let mut chars = String::new();
 
index 508b946ee83812236757cbe8aadc7ced5e75e160..e463b81206b559dbc98871f631789ccf4bedb602 100644 (file)
@@ -1,5 +1,5 @@
 use prolog_parser::ast::*;
-use prolog_parser::parser::{get_desc, get_clause_spec};
+use prolog_parser::parser::*;
 use prolog_parser::tabled_rc::*;
 
 use prolog::clause_types::*;
@@ -12,6 +12,7 @@ use prolog::machine::machine_state::*;
 use prolog::machine::toplevel::{to_op_decl};
 use prolog::num::{FromPrimitive, ToPrimitive, Zero};
 use prolog::num::bigint::{BigInt};
+use prolog::ordered_float::OrderedFloat;
 use prolog::read::{PrologStream, readline};
 
 use ref_thread_local::RefThreadLocal;
@@ -35,7 +36,7 @@ impl BrentAlgState {
     }
 }
 
-impl MachineState {    
+impl MachineState {
     // a step in Brent's algorithm.
     fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
     {
@@ -329,7 +330,7 @@ impl MachineState {
                               indices: &mut IndexStore,
                               call_policy: &mut Box<CallPolicy>,
                               cut_policy:  &mut Box<CutPolicy>,
-                              parsing_stream: &mut PrologStream)
+                              current_input_stream: &mut PrologStream)
                               -> CallResult
     {
         match ct {
@@ -399,9 +400,9 @@ impl MachineState {
                                         let chars = clause_name!(string, indices.atom_tbl);
                                         self.unify(addr.clone(), Addr::Con(Constant::Atom(chars, None)));
                                     },
-                                    Err(err) => 
+                                    Err(err) =>
                                         return Err(self.error_form(err, stub))
-                                }                        
+                                }
                         }
                     },
                     _ => unreachable!()
@@ -481,6 +482,75 @@ impl MachineState {
 
                 self.unify(a2, Addr::Con(Constant::Number(len)));
             },
+            &SystemClauseType::CharsToNumber => {
+                let nx  = self[temp_v!(2)].clone();
+                let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
+
+                match self.try_from_list(temp_v!(1), stub.clone()) {
+                    Err(e) => return Err(e),
+                    Ok(addrs) =>
+                        match 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));
+                                let mut parser = Parser::new(&mut stream, indices.atom_tbl.clone(),
+                                                             self.machine_flags());
+
+                                match parser.read_term(composite_op!(&indices.op_dir)) {
+                                    Err(err) => {
+                                        let h = self.heap.h;
+                                        let err = MachineError::syntax_error(h, err);
+
+                                        return Err(self.error_form(err, stub));
+                                    },
+                                    Ok(Term::Constant(_, Constant::Number(n))) =>
+                                        self.unify(nx, Addr::Con(Constant::Number(n))),
+                                    Ok(Term::Constant(_, Constant::CharCode(c))) =>
+                                        self.unify(nx, Addr::Con(Constant::CharCode(c))),
+                                    _ => {
+                                        let err = ParserError::ParseBigInt;
+                                        
+                                        let h = self.heap.h;
+                                        let err = MachineError::syntax_error(h, err);
+
+                                        return Err(self.error_form(err, stub));
+                                    }
+                                }
+                            },
+                            Err(err) =>
+                                return Err(self.error_form(err, stub))
+                        }
+                }
+            },
+            &SystemClauseType::NumberToChars => {
+                let n = self[temp_v!(1)].clone();
+                let chs = self[temp_v!(2)].clone();
+
+                let string = match self.store(self.deref(n)) {
+                    Addr::Con(Constant::Number(Number::Float(OrderedFloat(n)))) =>
+                        format!("{0:<20?}", n),
+                    Addr::Con(Constant::Number(Number::Integer(n))) =>
+                        n.to_string(),
+                    _ => unreachable!()
+                };
+
+                let chars = string.trim().chars().map(|c| Addr::Con(Constant::Char(c)));
+                let char_list = Addr::HeapCell(self.heap.to_list(chars));
+
+                self.unify(char_list, chs);
+            },
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
                 let p = self.cp;
                 let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front);
@@ -555,7 +625,7 @@ impl MachineState {
                 };
             },
             &SystemClauseType::GetChar => {
-                let result = parsing_stream.next();
+                let result = current_input_stream.next();
                 let a1 = self[temp_v!(1)].clone();
 
                 match result {
@@ -1409,7 +1479,7 @@ impl MachineState {
                 self.install_new_block(temp_v!(1));
             },
             &SystemClauseType::ReadTerm => {
-                match self.read(parsing_stream, indices.atom_tbl.clone(), &indices.op_dir) {
+                match self.read(current_input_stream, indices.atom_tbl.clone(), &indices.op_dir) {
                     Ok(term_write_result) => {
                         let a1 = self[temp_v!(1)].clone();
                         self.unify(Addr::HeapCell(term_write_result.heap_loc), a1);
@@ -1441,7 +1511,7 @@ impl MachineState {
                     },
                     Err(err) => {
                         // reset the input stream after an input failure.
-                        *parsing_stream = readline::input_stream();
+                        *current_input_stream = readline::input_stream();
 
                         let h = self.heap.h;
                         let syntax_error = MachineError::syntax_error(h, err);