[package]
name = "scryer-prolog"
-version = "0.8.70"
+version = "0.8.71"
repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust."
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"
* `must_be/2`
* `nl/0`
* `nonvar/1`
+* `number_chars/2`
* `numbervars/2`
* `numlist/{2,3}`
* `once/1`
ModuleAssertDynamicPredicateToFront,
ModuleAssertDynamicPredicateToBack,
CharCode,
+ CharsToNumber,
CheckCutPoint,
CopyToLiftedHeap,
DeleteAttribute,
ModuleOf,
ModuleRetractClause,
NoSuchPredicate,
+ NumberToChars,
OpDeclaration,
REPL(REPLCodePtr),
ReadTerm,
&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) =>
&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"),
("$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),
("$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),
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, :).
; 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
+ ).
}
}
-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();
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::*;
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;
}
}
-impl MachineState {
+impl MachineState {
// a step in Brent's algorithm.
fn brents_alg_step(&self, brent_st: &mut BrentAlgState) -> Option<CycleSearchResult>
{
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 {
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!()
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);
};
},
&SystemClauseType::GetChar => {
- let result = parsing_stream.next();
+ let result = current_input_stream.next();
let a1 = self[temp_v!(1)].clone();
match result {
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);
},
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);