cleanup on reading predicates, add get_char/{1,2}

This commit is contained in:
Mark Thom
2020-05-05 16:54:40 -06:00
parent bfced59949
commit 573df892bc
6 changed files with 196 additions and 78 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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",

View File

@@ -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();

View File

@@ -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 {

View File

@@ -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)