clean up stream error handling, add get_byte/{1,2}

This commit is contained in:
Mark Thom
2020-05-05 16:09:17 -06:00
parent 9a63b1751b
commit bfced59949
6 changed files with 168 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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