fix more conformity errors

This commit is contained in:
Mark Thom
2019-04-06 17:44:04 -06:00
parent 16eadc7412
commit fb0b7085b4
7 changed files with 182 additions and 81 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.45" version = "0.8.46"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
repository = "https://github.com/mthom/scryer-prolog" repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
@@ -14,7 +14,7 @@ cfg-if = "0.1.7"
downcast = "0.10.0" downcast = "0.10.0"
num = "0.2" num = "0.2"
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = "0.8.16" prolog_parser = "0.8.17"
readline_rs_compat = { version = "0.1.7", optional = true } readline_rs_compat = { version = "0.1.7", optional = true }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"

View File

@@ -164,6 +164,7 @@ pub enum SystemClauseType {
AtomLength, AtomLength,
ModuleAssertDynamicPredicateToFront, ModuleAssertDynamicPredicateToFront,
ModuleAssertDynamicPredicateToBack, ModuleAssertDynamicPredicateToBack,
CharCode,
CheckCutPoint, CheckCutPoint,
CopyToLiftedHeap, CopyToLiftedHeap,
DeleteAttribute, DeleteAttribute,
@@ -174,6 +175,7 @@ pub enum SystemClauseType {
ExpandGoal, ExpandGoal,
ExpandTerm, ExpandTerm,
FetchGlobalVar, FetchGlobalVar,
GetChar,
TruncateIfNoLiftedHeapGrowthDiff, TruncateIfNoLiftedHeapGrowthDiff,
TruncateIfNoLiftedHeapGrowth, TruncateIfNoLiftedHeapGrowth,
GetAttributedVariableList, GetAttributedVariableList,
@@ -242,6 +244,7 @@ impl SystemClauseType {
&SystemClauseType::AtomLength => clause_name!("$atom_length"), &SystemClauseType::AtomLength => clause_name!("$atom_length"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => clause_name!("$module_asserta"), &SystemClauseType::ModuleAssertDynamicPredicateToFront => clause_name!("$module_asserta"),
&SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"), &SystemClauseType::ModuleAssertDynamicPredicateToBack => clause_name!("$module_assertz"),
&SystemClauseType::CharCode => clause_name!("char_code"),
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"), &SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
@@ -252,6 +255,7 @@ impl SystemClauseType {
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"), &SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"), &SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => clause_name!("$truncate_if_no_lh_growth"), &SystemClauseType::TruncateIfNoLiftedHeapGrowth => clause_name!("$truncate_if_no_lh_growth"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => clause_name!("$truncate_if_no_lh_growth_diff"), &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => clause_name!("$truncate_if_no_lh_growth_diff"),
&SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"), &SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
@@ -320,6 +324,7 @@ impl SystemClauseType {
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$char_code", 2) => Some(SystemClauseType::CharCode),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
@@ -334,6 +339,7 @@ impl SystemClauseType {
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$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", 1) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth),
("$truncate_if_no_lh_growth_diff", 2) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff), ("$truncate_if_no_lh_growth_diff", 2) => Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff),
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),

View File

@@ -42,7 +42,7 @@ impl DirectedOp {
fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool
{ {
match op { match op {
&DirectedOp::Left(ref name, ref cell) => { &DirectedOp::Left(ref name, ref cell) => {
let (priority, spec) = cell.get(); let (priority, spec) = cell.get();
if name.as_str() == "-" { if name.as_str() == "-" {
@@ -51,15 +51,21 @@ fn needs_bracketing(child_spec: &SharedOpDesc, op: &DirectedOp) -> bool
return true; return true;
} }
} }
let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec); let is_strict_right = is_yfx!(spec) || is_xfx!(spec) || is_fx!(spec);
child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right) child_spec.prec() > priority || (child_spec.prec() == priority && is_strict_right)
}, },
&DirectedOp::Right(_, ref cell) => { &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); 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)] #[derive(Clone)]
pub enum TokenOrRedirect { pub enum TokenOrRedirect {
Atom(ClauseName), Atom(ClauseName),
@@ -250,12 +270,6 @@ pub struct HCPrinter<'a, Outputter> {
macro_rules! push_space_if_amb { macro_rules! push_space_if_amb {
($self:expr, $atom:expr, $action:block) => ( ($self:expr, $atom:expr, $action:block) => (
if $self.ambiguity_check($atom) { 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(' '); $self.outputter.push_char(' ');
$action; $action;
} else { } else {
@@ -277,8 +291,10 @@ fn requires_space(atom: &str, op: &str) -> bool {
alpha_numeric_char!(oc) alpha_numeric_char!(oc)
} else if sign_char!(ac) { } else if sign_char!(ac) {
sign_char!(oc) || decimal_digit_char!(oc) sign_char!(oc) || decimal_digit_char!(oc)
} else if single_quote_char!(ac) {
single_quote_char!(oc)
} else if ac == '0' { } else if ac == '0' {
!non_quoted_token(op.chars()) oc == 'b' || oc == 'x' || oc == 'o' || !non_quoted_token(op.chars())
} else { } else {
false false
} }
@@ -432,7 +448,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
fn format_negated_operand(&mut self, spec: SharedOpDesc) fn format_negated_operand(&mut self, spec: SharedOpDesc)
{ {
let op = DirectedOp::Left(clause_name!("-"), spec); let op = DirectedOp::Left(clause_name!("-"), spec);
self.state_stack.push(TokenOrRedirect::CompositeRedirect(op)); self.state_stack.push(TokenOrRedirect::CompositeRedirect(op));
self.state_stack.push(TokenOrRedirect::Space); self.state_stack.push(TokenOrRedirect::Space);
self.state_stack.push(TokenOrRedirect::Atom(clause_name!("-"))); 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) { if self.format_numbered_vars(iter) {
return; return;
} }
} }
if let Some(spec) = ct.spec() { if let Some(spec) = ct.spec() {
if "." == ct.name().as_str() && is_infix!(spec.assoc()) { if "." == ct.name().as_str() && is_infix!(spec.assoc()) {
if !self.ignore_ops { if !self.ignore_ops {
@@ -474,7 +490,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter>
return; return;
} }
} }
if !self.ignore_ops && spec.prec() > 0 { if !self.ignore_ops && spec.prec() > 0 {
return self.enqueue_op(ct, spec); 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) { if let Some(offset_str) = self.offset_as_string(addr) {
push_space_if_amb!(self, &offset_str, { 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) { fn print_atom(&mut self, atom: &ClauseName) {
push_space_if_amb!(self, atom.as_str(), { let result = self.print_op_addendum(atom.as_str());
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()) { if !self.quoted || non_quoted_token(atom.chars()) {
self.append_str(atom); atom.to_string()
} else if atom == "''" { } else if atom == "''" {
self.append_str("''"); "''".to_string()
} else { } else {
let mut result = String::new();
if self.quoted { if self.quoted {
self.push_char('\''); result.push('\'');
} }
for c in atom.chars() { for c in atom.chars() {
self.print_char(c); result += &char_to_string(c);
} }
if self.quoted { if self.quoted {
self.push_char('\''); result.push('\'');
} }
result
} }
} }
fn print_op(&mut self, atom: &str) { fn print_op(&mut self, atom: &str) {
push_space_if_amb!(self, atom, { let result = if atom == "," {
if atom == "," { ",".to_string()
self.push_char(','); } else {
} else { self.print_op_addendum(atom)
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))
}; };
push_space_if_amb!(self, &result, {
self.append_str(&result);
});
} }
fn print_number(&mut self, n: Number, op: &Option<DirectedOp>) { 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>) { fn print_constant(&mut self, c: Constant, op: &Option<DirectedOp>) {
match c { 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 let Some(ref op) = op {
if self.outputter.ends_with(&format!(" {}", op.as_str())) { if self.outputter.ends_with(&format!(" {}", op.as_str())) {
self.push_char(' '); self.push_char(' ');
} }
self.push_char('('); self.push_char('(');
} }
self.print_atom(atom); self.print_atom(atom);
if op.is_some() { if op.is_some() {
self.push_char(')'); self.push_char(')');
} }
}, },
Constant::Atom(ref atom, None) => Constant::Atom(ref atom, _) =>
push_space_if_amb!(self, atom.as_str(), { push_space_if_amb!(self, atom.as_str(), {
self.print_atom(atom); self.print_atom(atom);
}), }),
Constant::Char(c) if non_quoted_token(once(c)) => Constant::Char(c) if non_quoted_token(once(c)) => {
self.print_char(c), let c = char_to_string(c);
Constant::Char(c) =>
push_space_if_amb!(self, &c, {
self.append_str(c.as_str());
});
},
Constant::Char(c) => {
let mut result = String::new();
if self.quoted { if self.quoted {
self.push_char('\''); result.push('\'');
self.print_char(c); result += &char_to_string(c);
self.push_char('\''); result.push('\'');
} else { } 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) => Constant::CharCode(c) =>
self.append_str(&format!("{}", c)), self.append_str(&format!("{}", c)),
Constant::EmptyList => Constant::EmptyList =>
self.append_str("[]"), self.append_str("[]"),
Constant::Number(n) => Constant::Number(n) =>

View File

@@ -9,12 +9,12 @@
abolish/1, asserta/1, assertz/1, atom_chars/2, atom_codes/2, 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, 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, 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, current_prolog_flag/2, expand_goal/2, expand_term/2,
findall/3, findall/4, halt/0, once/1, op/3, repeat/0, findall/3, findall/4, get_char/1, halt/0, once/1, op/3,
retract/1, set_prolog_flag/2, setof/3, setup_call_cleanup/3, repeat/0, retract/1, set_prolog_flag/2, setof/3,
term_variables/2, throw/1, true/0, false/0, write/1, setup_call_cleanup/3, term_variables/2, throw/1, true/0,
write_canonical/1, writeq/1, write_term/2]). 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 /* 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 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([X|Xs]) :- var(X), !, '$fail'.
no_var_in_list([_|Xs]) :- no_var_in_list(Xs). no_var_in_list([_|Xs]) :- no_var_in_list(Xs).
atom_chars(Atom, List) :- atom_chars(Atom, List) :-
( var(Atom) -> ( var(Atom) ->
( var(List) -> throw(error(instantiation_error, atom_chars/2)) ( 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) ; 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)) ; throw(error(type_error(atom, Atom), atom_chars/2))
). ).
atom_codes(Atom, List) :- atom_codes(Atom, List) :-
( var(Atom) -> ( var(Atom) ->
( var(List) -> throw(error(instantiation_error, atom_codes/2)) ( 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) ; 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) ; atom(Atom) -> '$atom_codes'(Atom, List)
; throw(error(type_error(atom, Atom), atom_codes/2)) ; 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))
).

View File

@@ -224,7 +224,7 @@ impl DomainError {
// from 7.12.2 f) of 13211-1:1995 // from 7.12.2 f) of 13211-1:1995
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum RepFlag { pub enum RepFlag {
// Character, Character,
CharacterCode, CharacterCode,
// InCharacterCode, // InCharacterCode,
MaxArity, MaxArity,
@@ -235,7 +235,7 @@ pub enum RepFlag {
impl RepFlag { impl RepFlag {
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
// RepFlag::Character => "character", RepFlag::Character => "character",
RepFlag::CharacterCode => "character_code", RepFlag::CharacterCode => "character_code",
// RepFlag::InCharacterCode => "in_character_code", // RepFlag::InCharacterCode => "in_character_code",
RepFlag::MaxArity => "max_arity", RepFlag::MaxArity => "max_arity",

View File

@@ -15,7 +15,7 @@ use prolog::num::bigint::{BigInt};
use ref_thread_local::RefThreadLocal; use ref_thread_local::RefThreadLocal;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::{stdout, Write}; use std::io::{stdout, Read, Write};
use std::iter::once; use std::iter::once;
use std::mem; use std::mem;
use std::rc::Rc; use std::rc::Rc;
@@ -355,14 +355,14 @@ impl MachineState {
let a2 = self[temp_v!(2)].clone(); let a2 = self[temp_v!(2)].clone();
let chars = vec![Addr::Con(Constant::Char('[')), let chars = vec![Addr::Con(Constant::Char('[')),
Addr::Con(Constant::Char(']'))]; Addr::Con(Constant::Char(']'))];
let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter())); let list_of_chars = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
self.unify(a2, list_of_chars); self.unify(a2, list_of_chars);
}, },
ref addr if addr.is_ref() => { ref addr if addr.is_ref() => {
let stub = MachineError::functor_stub(clause_name!("atom_chars"), 2); let stub = MachineError::functor_stub(clause_name!("atom_chars"), 2);
match self.try_from_list(temp_v!(2), stub.clone()) { match self.try_from_list(temp_v!(2), stub.clone()) {
Err(e) => return Err(e), Err(e) => return Err(e),
Ok(addrs) => { Ok(addrs) => {
@@ -402,7 +402,7 @@ impl MachineState {
let a2 = self[temp_v!(2)].clone(); let a2 = self[temp_v!(2)].clone();
self.unify(a2, list_of_codes); self.unify(a2, list_of_codes);
}, },
Addr::Con(Constant::Atom(name, _)) => { Addr::Con(Constant::Atom(name, _)) => {
let iter = name.as_str().chars().map(|c| Addr::Con(Constant::CharCode(c as u8))); 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)); 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 a2 = self[temp_v!(2)].clone();
let chars = vec![Addr::Con(Constant::CharCode('[' as u8)), let chars = vec![Addr::Con(Constant::CharCode('[' as u8)),
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())); let list_of_codes = Addr::HeapCell(self.heap.to_list(chars.into_iter()));
self.unify(a2, list_of_codes); self.unify(a2, list_of_codes);
@@ -452,12 +452,14 @@ impl MachineState {
let atom = match self.store(self.deref(a1)) { let atom = match self.store(self.deref(a1)) {
Addr::Con(Constant::Atom(name, _)) => name, 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!() _ => unreachable!()
}; };
let len = Number::Integer(Rc::new(BigInt::from_usize(atom.as_str().len()).unwrap())); let len = Number::Integer(Rc::new(BigInt::from_usize(atom.as_str().len()).unwrap()));
let a2 = self[temp_v!(2)].clone(); let a2 = self[temp_v!(2)].clone();
self.unify(a2, Addr::Con(Constant::Number(len))); self.unify(a2, Addr::Con(Constant::Number(len)));
}, },
&SystemClauseType::ModuleAssertDynamicPredicateToFront => { &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
@@ -480,6 +482,42 @@ impl MachineState {
self.unify(a1, lh_len); 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 => { &SystemClauseType::CheckCutPoint => {
let addr = self.store(self.deref(self[temp_v!(1)].clone())); let addr = self.store(self.deref(self[temp_v!(1)].clone()));
@@ -503,6 +541,25 @@ impl MachineState {
None => self.fail = true 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 => { &SystemClauseType::GetModuleClause => {
let module = self[temp_v!(3)].clone(); let module = self[temp_v!(3)].clone();
let head = self[temp_v!(1)].clone(); let head = self[temp_v!(1)].clone();

View File

@@ -40,7 +40,7 @@ pub mod readline
Single, Single,
Multi Multi
} }
static mut LINE_MODE: LineMode = LineMode::Single; static mut LINE_MODE: LineMode = LineMode::Single;
static mut END_OF_LINE: bool = false; static mut END_OF_LINE: bool = false;
@@ -117,7 +117,7 @@ pub mod readline
if let LineMode::Single = LINE_MODE { if let LineMode::Single = LINE_MODE {
insert_text_rl("?- "); insert_text_rl("?- ");
} }
0 0
} }
@@ -140,7 +140,7 @@ pub mod readline
pub mod readline pub mod readline
{ {
use std::io::{BufRead, Read, stdin, stdout, Write}; use std::io::{BufRead, Read, stdin, stdout, Write};
pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> { pub fn read_batch(_: &str) -> Result<Vec<u8>, ::SessionError> {
let mut buf = vec![]; let mut buf = vec![];
@@ -159,14 +159,14 @@ pub mod readline
let stdin = stdin(); let stdin = stdin();
let stdin = stdin.lock(); let stdin = stdin.lock();
let mut buf = "?- ".to_string(); let mut buf = "?- ".to_string();
for line in stdin.lines() { for line in stdin.lines() {
match line { match line {
Ok(line) => { Ok(line) => {
buf += &line; buf += &line;
if line.trim().ends_with(".") { if line.trim().ends_with(".") {
break; break;
} }