clean up stream error handling, add get_byte/{1,2}
This commit is contained in:
@@ -182,6 +182,7 @@ pub enum SystemClauseType {
|
|||||||
FetchGlobalVarWithOffset,
|
FetchGlobalVarWithOffset,
|
||||||
FileToChars,
|
FileToChars,
|
||||||
FlushOutput,
|
FlushOutput,
|
||||||
|
GetByte,
|
||||||
GetChar,
|
GetChar,
|
||||||
GetSingleChar,
|
GetSingleChar,
|
||||||
ResetAttrVarState,
|
ResetAttrVarState,
|
||||||
@@ -327,6 +328,7 @@ impl SystemClauseType {
|
|||||||
}
|
}
|
||||||
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
|
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
|
||||||
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
||||||
|
&SystemClauseType::GetByte => clause_name!("$get_byte"),
|
||||||
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
||||||
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
|
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
|
||||||
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
||||||
@@ -487,6 +489,7 @@ impl SystemClauseType {
|
|||||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||||
("$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_char", 1) => Some(SystemClauseType::GetChar),
|
("$get_char", 1) => 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) => {
|
||||||
|
|||||||
@@ -49,9 +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_char/1, halt/0, max_arity/1, number_chars/2,
|
get_byte/1, get_byte/2, get_char/1, halt/0,
|
||||||
number_codes/2, once/1, op/3, open/3, open/4,
|
max_arity/1, number_chars/2, number_codes/2,
|
||||||
read_term/2, read_term/3, repeat/0, retract/1,
|
once/1, op/3, open/3, open/4, 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,
|
||||||
@@ -1190,3 +1191,11 @@ flush_output(S) :-
|
|||||||
flush_output :-
|
flush_output :-
|
||||||
current_output(S),
|
current_output(S),
|
||||||
'$flush_output'(S).
|
'$flush_output'(S).
|
||||||
|
|
||||||
|
|
||||||
|
get_byte(S, B) :-
|
||||||
|
'$get_byte'(S, B).
|
||||||
|
|
||||||
|
get_byte(S) :-
|
||||||
|
current_input(S),
|
||||||
|
'$get_byte'(S, B).
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ pub enum ValidType {
|
|||||||
Compound,
|
Compound,
|
||||||
Evaluable,
|
Evaluable,
|
||||||
Float,
|
Float,
|
||||||
// InByte,
|
InByte,
|
||||||
// InCharacter,
|
// InCharacter,
|
||||||
Integer,
|
Integer,
|
||||||
List,
|
List,
|
||||||
@@ -518,7 +518,7 @@ impl ValidType {
|
|||||||
ValidType::Compound => "compound",
|
ValidType::Compound => "compound",
|
||||||
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",
|
||||||
|
|||||||
@@ -629,20 +629,13 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(err_string) = opt_err {
|
if let Some(err_string) = opt_err {
|
||||||
let stub = MachineError::functor_stub(clause_name!("read_term"), 3);
|
return Err(self.stream_permission_error(
|
||||||
|
|
||||||
let addr = vec![
|
|
||||||
HeapCellValue::Stream(stream)
|
|
||||||
];
|
|
||||||
|
|
||||||
let err = MachineError::permission_error(
|
|
||||||
self.heap.h(),
|
|
||||||
Permission::InputStream,
|
Permission::InputStream,
|
||||||
err_string,
|
err_string,
|
||||||
addr,
|
stream,
|
||||||
);
|
clause_name!("read_term"),
|
||||||
|
3,
|
||||||
return Err(self.error_form(err, stub));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut orig_stream = stream.clone();
|
let mut orig_stream = stream.clone();
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ impl Default for StreamOptions {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct Stream {
|
pub struct Stream {
|
||||||
past_end_of_stream: bool,
|
pub past_end_of_stream: bool,
|
||||||
pub options: StreamOptions,
|
pub options: StreamOptions,
|
||||||
stream_inst: WrappedStreamInstance,
|
stream_inst: WrappedStreamInstance,
|
||||||
}
|
}
|
||||||
@@ -339,20 +339,7 @@ impl MachineState {
|
|||||||
match stream.options.eof_action {
|
match stream.options.eof_action {
|
||||||
EOFAction::Error => {
|
EOFAction::Error => {
|
||||||
stream.past_end_of_stream = true;
|
stream.past_end_of_stream = true;
|
||||||
|
return Err(self.open_past_eos_error(stream.clone(), caller, arity));
|
||||||
let stub = MachineError::functor_stub(caller, arity);
|
|
||||||
let payload = vec![
|
|
||||||
HeapCellValue::Stream(stream.clone())
|
|
||||||
];
|
|
||||||
|
|
||||||
let err = MachineError::permission_error(
|
|
||||||
self.heap.h(),
|
|
||||||
Permission::InputStream,
|
|
||||||
"past_end_of_stream",
|
|
||||||
payload,
|
|
||||||
);
|
|
||||||
|
|
||||||
Err(self.error_form(err, stub))
|
|
||||||
}
|
}
|
||||||
EOFAction::EOFCode => {
|
EOFAction::EOFCode => {
|
||||||
let end_of_stream = self.heap.to_unifiable(
|
let end_of_stream = self.heap.to_unifiable(
|
||||||
@@ -533,6 +520,47 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate)
|
||||||
|
fn stream_permission_error(
|
||||||
|
&self,
|
||||||
|
perm: Permission,
|
||||||
|
err_string: &'static str,
|
||||||
|
stream: Stream,
|
||||||
|
caller: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> MachineStub {
|
||||||
|
let stub = MachineError::functor_stub(caller, arity);
|
||||||
|
let payload = vec![
|
||||||
|
HeapCellValue::Stream(stream)
|
||||||
|
];
|
||||||
|
|
||||||
|
let err = MachineError::permission_error(
|
||||||
|
self.heap.h(),
|
||||||
|
perm,
|
||||||
|
err_string,
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
|
||||||
|
return self.error_form(err, stub);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn open_past_eos_error(
|
||||||
|
&self,
|
||||||
|
stream: Stream,
|
||||||
|
caller: ClauseName,
|
||||||
|
arity: usize,
|
||||||
|
) -> MachineStub {
|
||||||
|
self.stream_permission_error(
|
||||||
|
Permission::InputStream,
|
||||||
|
"past_end_of_stream",
|
||||||
|
stream,
|
||||||
|
caller,
|
||||||
|
arity,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn open_permission_error<T: PermissionError>(
|
fn open_permission_error<T: PermissionError>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -1592,6 +1592,104 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(complete_string, a2);
|
self.unify(complete_string, a2);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::GetByte => {
|
||||||
|
let mut stream =
|
||||||
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
|
||||||
|
|
||||||
|
let opt_err =
|
||||||
|
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,
|
||||||
|
clause_name!("get_byte"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut b = [0u8; 1];
|
||||||
|
|
||||||
|
match stream.read(&mut b) {
|
||||||
|
Ok(1) => {
|
||||||
|
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::Usize(b[0] as usize));
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addr => {
|
||||||
|
match Number::try_from((addr, &self.heap)) {
|
||||||
|
Ok(Number::Integer(n)) => {
|
||||||
|
if let Some(nb) = n.to_u8() {
|
||||||
|
self.fail = b[0] != nb;
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Number::Fixnum(n)) => {
|
||||||
|
if let Ok(nb) = u8::try_from(n) {
|
||||||
|
self.fail = b[0] != nb;
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("get_byte"), 2);
|
||||||
|
let err = MachineError::type_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ValidType::InByte,
|
||||||
|
self[temp_v!(2)],
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.eof_action(
|
||||||
|
self[temp_v!(2)],
|
||||||
|
&mut stream,
|
||||||
|
clause_name!("get_byte"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&SystemClauseType::GetChar => {
|
&SystemClauseType::GetChar => {
|
||||||
let mut iter = self.open_parsing_stream(
|
let mut iter = self.open_parsing_stream(
|
||||||
current_input_stream.clone(),
|
current_input_stream.clone(),
|
||||||
@@ -3947,19 +4045,13 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(err_string) = opt_err {
|
if let Some(err_string) = opt_err {
|
||||||
let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
|
return Err(self.stream_permission_error(
|
||||||
let addr = vec![
|
|
||||||
HeapCellValue::Stream(stream)
|
|
||||||
];
|
|
||||||
|
|
||||||
let err = MachineError::permission_error(
|
|
||||||
self.heap.h(),
|
|
||||||
Permission::OutputStream,
|
Permission::OutputStream,
|
||||||
err_string,
|
err_string,
|
||||||
addr,
|
stream,
|
||||||
);
|
clause_name!("write_term"),
|
||||||
|
3,
|
||||||
return Err(self.error_form(err, stub));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let addr = self[temp_v!(2)];
|
let addr = self[temp_v!(2)];
|
||||||
|
|||||||
Reference in New Issue
Block a user