clean up stream error handling, add get_byte/{1,2}
This commit is contained in:
@@ -182,6 +182,7 @@ pub enum SystemClauseType {
|
||||
FetchGlobalVarWithOffset,
|
||||
FileToChars,
|
||||
FlushOutput,
|
||||
GetByte,
|
||||
GetChar,
|
||||
GetSingleChar,
|
||||
ResetAttrVarState,
|
||||
@@ -327,6 +328,7 @@ impl SystemClauseType {
|
||||
}
|
||||
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
|
||||
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
||||
&SystemClauseType::GetByte => clause_name!("$get_byte"),
|
||||
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
||||
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
|
||||
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
||||
@@ -487,6 +489,7 @@ impl SystemClauseType {
|
||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||
("$file_to_chars", 2) => Some(SystemClauseType::FileToChars),
|
||||
("$get_byte", 2) => Some(SystemClauseType::GetByte),
|
||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
||||
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
|
||||
("$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,
|
||||
expand_term/2, fail/0, false/0, findall/3,
|
||||
findall/4, flush_output/0, flush_output/1,
|
||||
get_char/1, halt/0, max_arity/1, number_chars/2,
|
||||
number_codes/2, once/1, op/3, open/3, open/4,
|
||||
read_term/2, read_term/3, repeat/0, retract/1,
|
||||
get_byte/1, get_byte/2, get_char/1, halt/0,
|
||||
max_arity/1, number_chars/2, number_codes/2,
|
||||
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,
|
||||
setof/3, sub_atom/5, subsumes_term/2,
|
||||
term_variables/2, throw/1, true/0,
|
||||
@@ -1190,3 +1191,11 @@ flush_output(S) :-
|
||||
flush_output :-
|
||||
current_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,
|
||||
Evaluable,
|
||||
Float,
|
||||
// InByte,
|
||||
InByte,
|
||||
// InCharacter,
|
||||
Integer,
|
||||
List,
|
||||
@@ -518,7 +518,7 @@ impl ValidType {
|
||||
ValidType::Compound => "compound",
|
||||
ValidType::Evaluable => "evaluable",
|
||||
ValidType::Float => "float",
|
||||
// ValidType::InByte => "in_byte",
|
||||
ValidType::InByte => "in_byte",
|
||||
// ValidType::InCharacter => "in_character",
|
||||
ValidType::Integer => "integer",
|
||||
ValidType::List => "list",
|
||||
|
||||
@@ -629,20 +629,13 @@ impl MachineState {
|
||||
};
|
||||
|
||||
if let Some(err_string) = opt_err {
|
||||
let stub = MachineError::functor_stub(clause_name!("read_term"), 3);
|
||||
|
||||
let addr = vec![
|
||||
HeapCellValue::Stream(stream)
|
||||
];
|
||||
|
||||
let err = MachineError::permission_error(
|
||||
self.heap.h(),
|
||||
return Err(self.stream_permission_error(
|
||||
Permission::InputStream,
|
||||
err_string,
|
||||
addr,
|
||||
);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
stream,
|
||||
clause_name!("read_term"),
|
||||
3,
|
||||
));
|
||||
}
|
||||
|
||||
let mut orig_stream = stream.clone();
|
||||
|
||||
@@ -153,7 +153,7 @@ impl Default for StreamOptions {
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct Stream {
|
||||
past_end_of_stream: bool,
|
||||
pub past_end_of_stream: bool,
|
||||
pub options: StreamOptions,
|
||||
stream_inst: WrappedStreamInstance,
|
||||
}
|
||||
@@ -339,20 +339,7 @@ impl MachineState {
|
||||
match stream.options.eof_action {
|
||||
EOFAction::Error => {
|
||||
stream.past_end_of_stream = true;
|
||||
|
||||
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))
|
||||
return Err(self.open_past_eos_error(stream.clone(), caller, arity));
|
||||
}
|
||||
EOFAction::EOFCode => {
|
||||
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)
|
||||
fn open_permission_error<T: PermissionError>(
|
||||
&self,
|
||||
|
||||
@@ -1592,6 +1592,104 @@ impl MachineState {
|
||||
|
||||
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 => {
|
||||
let mut iter = self.open_parsing_stream(
|
||||
current_input_stream.clone(),
|
||||
@@ -3947,19 +4045,13 @@ impl MachineState {
|
||||
};
|
||||
|
||||
if let Some(err_string) = opt_err {
|
||||
let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
|
||||
let addr = vec![
|
||||
HeapCellValue::Stream(stream)
|
||||
];
|
||||
|
||||
let err = MachineError::permission_error(
|
||||
self.heap.h(),
|
||||
return Err(self.stream_permission_error(
|
||||
Permission::OutputStream,
|
||||
err_string,
|
||||
addr,
|
||||
);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
stream,
|
||||
clause_name!("write_term"),
|
||||
3,
|
||||
));
|
||||
}
|
||||
|
||||
let addr = self[temp_v!(2)];
|
||||
|
||||
Reference in New Issue
Block a user