cleanup on reading predicates, add get_char/{1,2}
This commit is contained in:
@@ -490,7 +490,7 @@ impl SystemClauseType {
|
|||||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||||
("$file_to_chars", 2) => Some(SystemClauseType::FileToChars),
|
("$file_to_chars", 2) => Some(SystemClauseType::FileToChars),
|
||||||
("$get_byte", 2) => Some(SystemClauseType::GetByte),
|
("$get_byte", 2) => Some(SystemClauseType::GetByte),
|
||||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
("$get_char", 2) => Some(SystemClauseType::GetChar),
|
||||||
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
|
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
|
||||||
("$points_to_cont_reset_marker", 1) => {
|
("$points_to_cont_reset_marker", 1) => {
|
||||||
Some(SystemClauseType::PointsToContinuationResetMarker)
|
Some(SystemClauseType::PointsToContinuationResetMarker)
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
current_prolog_flag/2, expand_goal/2,
|
current_prolog_flag/2, expand_goal/2,
|
||||||
expand_term/2, fail/0, false/0, findall/3,
|
expand_term/2, fail/0, false/0, findall/3,
|
||||||
findall/4, flush_output/0, flush_output/1,
|
findall/4, flush_output/0, flush_output/1,
|
||||||
get_byte/1, get_byte/2, get_char/1, halt/0,
|
get_byte/1, get_byte/2, get_char/1, get_char/2,
|
||||||
max_arity/1, number_chars/2, number_codes/2,
|
halt/0, max_arity/1, number_chars/2,
|
||||||
once/1, op/3, open/3, open/4, read_term/2,
|
number_codes/2, once/1, op/3, open/3, open/4,
|
||||||
read_term/3, repeat/0, retract/1,
|
read_term/2, read_term/3, repeat/0, retract/1,
|
||||||
set_prolog_flag/2, set_input/1, set_output/1,
|
set_prolog_flag/2, set_input/1, set_output/1,
|
||||||
setof/3, sub_atom/5, subsumes_term/2,
|
setof/3, sub_atom/5, subsumes_term/2,
|
||||||
term_variables/2, throw/1, true/0,
|
term_variables/2, throw/1, true/0,
|
||||||
@@ -1000,11 +1000,11 @@ char_code(Char, Code) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
get_char(C) :-
|
get_char(C) :-
|
||||||
( var(C) -> '$get_char'(C)
|
current_input(S),
|
||||||
; C == end_of_file -> '$get_char'(C)
|
'$get_char'(S, C).
|
||||||
; atom_length(C, 1) -> '$get_char'(C)
|
|
||||||
; throw(error(type_error(in_character, C), get_char/1))
|
get_char(S, C) :-
|
||||||
).
|
'$get_char'(S, C).
|
||||||
|
|
||||||
can_be_number(N, PI) :-
|
can_be_number(N, PI) :-
|
||||||
( var(N) -> true
|
( var(N) -> true
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ pub enum ValidType {
|
|||||||
Evaluable,
|
Evaluable,
|
||||||
Float,
|
Float,
|
||||||
InByte,
|
InByte,
|
||||||
// InCharacter,
|
InCharacter,
|
||||||
Integer,
|
Integer,
|
||||||
List,
|
List,
|
||||||
// Number,
|
// Number,
|
||||||
@@ -519,7 +519,7 @@ impl ValidType {
|
|||||||
ValidType::Evaluable => "evaluable",
|
ValidType::Evaluable => "evaluable",
|
||||||
ValidType::Float => "float",
|
ValidType::Float => "float",
|
||||||
ValidType::InByte => "in_byte",
|
ValidType::InByte => "in_byte",
|
||||||
// ValidType::InCharacter => "in_character",
|
ValidType::InCharacter => "in_character",
|
||||||
ValidType::Integer => "integer",
|
ValidType::Integer => "integer",
|
||||||
ValidType::List => "list",
|
ValidType::List => "list",
|
||||||
// ValidType::Number => "number",
|
// ValidType::Number => "number",
|
||||||
@@ -555,7 +555,7 @@ impl DomainErrorType {
|
|||||||
// from 7.12.2 f) of 13211-1:1995
|
// from 7.12.2 f) of 13211-1:1995
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum RepFlag {
|
pub enum RepFlag {
|
||||||
Character,
|
// Character,
|
||||||
CharacterCode,
|
CharacterCode,
|
||||||
// InCharacterCode,
|
// InCharacterCode,
|
||||||
MaxArity,
|
MaxArity,
|
||||||
@@ -566,7 +566,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",
|
||||||
|
|||||||
@@ -616,26 +616,23 @@ impl MachineState {
|
|||||||
pub(crate)
|
pub(crate)
|
||||||
fn read_term(
|
fn read_term(
|
||||||
&mut self,
|
&mut self,
|
||||||
stream: Stream,
|
mut stream: Stream,
|
||||||
indices: &mut IndexStore,
|
indices: &mut IndexStore,
|
||||||
) -> CallResult {
|
) -> CallResult {
|
||||||
let opt_err =
|
self.check_stream_properties(
|
||||||
if !stream.is_input_stream() {
|
&mut stream,
|
||||||
Some("stream") // 8.14.2.3 g)
|
StreamType::Text,
|
||||||
} else if stream.options.stream_type == StreamType::Binary {
|
Some(self[temp_v!(2)]),
|
||||||
Some("binary_stream") // 8.14.2.3 h)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(err_string) = opt_err {
|
|
||||||
return Err(self.stream_permission_error(
|
|
||||||
Permission::InputStream,
|
|
||||||
err_string,
|
|
||||||
stream,
|
|
||||||
clause_name!("read_term"),
|
clause_name!("read_term"),
|
||||||
3,
|
3,
|
||||||
));
|
)?;
|
||||||
|
|
||||||
|
if stream.past_end_of_stream {
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut orig_stream = stream.clone();
|
let mut orig_stream = stream.clone();
|
||||||
|
|||||||
@@ -21,6 +21,17 @@ pub enum StreamType {
|
|||||||
Text,
|
Text,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StreamType {
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
StreamType::Binary => "binary_stream",
|
||||||
|
StreamType::Text => "text_stream",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum EOFAction {
|
pub enum EOFAction {
|
||||||
EOFCode,
|
EOFCode,
|
||||||
@@ -615,6 +626,54 @@ impl MachineState {
|
|||||||
|
|
||||||
return self.error_form(err, stub);
|
return self.error_form(err, stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn check_stream_properties(
|
||||||
|
&mut self,
|
||||||
|
stream: &mut Stream,
|
||||||
|
expected_type: StreamType,
|
||||||
|
input: Option<Addr>,
|
||||||
|
caller: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> CallResult {
|
||||||
|
let opt_err =
|
||||||
|
if input.is_some() && !stream.is_input_stream() {
|
||||||
|
Some("stream") // 8.14.2.3 g)
|
||||||
|
} else if input.is_none() && stream.is_input_stream() {
|
||||||
|
Some("stream") // 8.14.2.3 g)
|
||||||
|
} else if stream.options.stream_type != expected_type {
|
||||||
|
Some(expected_type.as_str()) // 8.14.2.3 h)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let permission =
|
||||||
|
if input.is_some() { Permission::InputStream } else { Permission::OutputStream };
|
||||||
|
|
||||||
|
if let Some(err_string) = opt_err {
|
||||||
|
return Err(self.stream_permission_error(
|
||||||
|
permission,
|
||||||
|
err_string,
|
||||||
|
stream.clone(),
|
||||||
|
caller,
|
||||||
|
arity,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(input) = input {
|
||||||
|
if stream.past_end_of_stream {
|
||||||
|
self.eof_action(
|
||||||
|
input,
|
||||||
|
stream,
|
||||||
|
caller,
|
||||||
|
arity,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Read for Stream {
|
impl Read for Stream {
|
||||||
|
|||||||
@@ -1596,33 +1596,15 @@ impl MachineState {
|
|||||||
let mut stream =
|
let mut stream =
|
||||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
|
||||||
|
|
||||||
let opt_err =
|
self.check_stream_properties(
|
||||||
if !stream.is_input_stream() {
|
|
||||||
Some("stream") // 8.14.2.3 g)
|
|
||||||
} else if stream.options.stream_type == StreamType::Text {
|
|
||||||
Some("text_stream") // 8.14.2.3 h)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(err_string) = opt_err {
|
|
||||||
return Err(self.stream_permission_error(
|
|
||||||
Permission::InputStream,
|
|
||||||
err_string,
|
|
||||||
stream,
|
|
||||||
clause_name!("get_byte"),
|
|
||||||
2,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if stream.past_end_of_stream {
|
|
||||||
self.eof_action(
|
|
||||||
self[temp_v!(2)],
|
|
||||||
&mut stream,
|
&mut stream,
|
||||||
|
StreamType::Binary,
|
||||||
|
Some(self[temp_v!(2)]),
|
||||||
clause_name!("get_byte"),
|
clause_name!("get_byte"),
|
||||||
2,
|
2,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if stream.past_end_of_stream {
|
||||||
if EOFAction::Reset != stream.options.eof_action {
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
return return_from_clause!(self.last_call, self);
|
return return_from_clause!(self.last_call, self);
|
||||||
} else if self.fail {
|
} else if self.fail {
|
||||||
@@ -1691,33 +1673,105 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
&SystemClauseType::GetChar => {
|
&SystemClauseType::GetChar => {
|
||||||
let mut iter = self.open_parsing_stream(
|
let mut stream =
|
||||||
current_input_stream.clone(),
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_char", 2)?;
|
||||||
"get_char",
|
|
||||||
1,
|
self.check_stream_properties(
|
||||||
|
&mut stream,
|
||||||
|
StreamType::Text,
|
||||||
|
Some(self[temp_v!(2)]),
|
||||||
|
clause_name!("get_char"),
|
||||||
|
2,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
if stream.past_end_of_stream {
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut iter = self.open_parsing_stream(
|
||||||
|
stream.clone(),
|
||||||
|
"get_char",
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
loop {
|
||||||
let result = iter.next();
|
let result = iter.next();
|
||||||
let a1 = self[temp_v!(1)];
|
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Some(Ok(c)) => {
|
Some(Ok(c)) => {
|
||||||
self.unify(Addr::Char(c), a1);
|
match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
|
addr if addr.is_ref() => {
|
||||||
|
if let Some(var) = addr.as_var() {
|
||||||
|
self.bind(var, Addr::Char(c));
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
Some(Err(_)) => {
|
}
|
||||||
let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
clause_name!("end_of_file"),
|
match &self.heap[h] {
|
||||||
None,
|
HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
|
||||||
));
|
if let Some(d) = atom.as_str().chars().next() {
|
||||||
|
if c == d {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Char(d) => {
|
||||||
|
if c == d {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
culprit => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
|
||||||
|
let err = MachineError::type_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ValidType::InCharacter,
|
||||||
|
culprit,
|
||||||
|
);
|
||||||
|
|
||||||
self.unify(a1, end_of_file);
|
return Err(self.error_form(err, stub));
|
||||||
}
|
}
|
||||||
None => {
|
}
|
||||||
let stub = MachineError::functor_stub(clause_name!("get_char"), 1);
|
}
|
||||||
|
_ => {
|
||||||
|
self.eof_action(
|
||||||
|
self[temp_v!(2)],
|
||||||
|
&mut stream,
|
||||||
|
clause_name!("get_char"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}/*
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
|
||||||
let err = MachineError::representation_error(RepFlag::Character);
|
let err = MachineError::representation_error(RepFlag::Character);
|
||||||
let err = self.error_form(err, stub);
|
let err = self.error_form(err, stub);
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4035,6 +4089,14 @@ impl MachineState {
|
|||||||
3,
|
3,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
self.check_stream_properties(
|
||||||
|
&mut stream,
|
||||||
|
StreamType::Text,
|
||||||
|
None, // input
|
||||||
|
clause_name!("write_term"),
|
||||||
|
3,
|
||||||
|
)?;
|
||||||
|
|
||||||
let opt_err =
|
let opt_err =
|
||||||
if !stream.is_output_stream() {
|
if !stream.is_output_stream() {
|
||||||
Some("stream") // 8.14.2.3 g)
|
Some("stream") // 8.14.2.3 g)
|
||||||
|
|||||||
Reference in New Issue
Block a user