("$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_char", 2) => Some(SystemClauseType::GetChar),
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
("$points_to_cont_reset_marker", 1) => {
Some(SystemClauseType::PointsToContinuationResetMarker)
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_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,
+ get_byte/1, get_byte/2, get_char/1, get_char/2,
+ 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,
).
get_char(C) :-
- ( var(C) -> '$get_char'(C)
- ; C == end_of_file -> '$get_char'(C)
- ; atom_length(C, 1) -> '$get_char'(C)
- ; throw(error(type_error(in_character, C), get_char/1))
- ).
+ current_input(S),
+ '$get_char'(S, C).
+
+get_char(S, C) :-
+ '$get_char'(S, C).
can_be_number(N, PI) :-
( var(N) -> true
Evaluable,
Float,
InByte,
- // InCharacter,
+ InCharacter,
Integer,
List,
// Number,
ValidType::Evaluable => "evaluable",
ValidType::Float => "float",
ValidType::InByte => "in_byte",
- // ValidType::InCharacter => "in_character",
+ ValidType::InCharacter => "in_character",
ValidType::Integer => "integer",
ValidType::List => "list",
// ValidType::Number => "number",
// from 7.12.2 f) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum RepFlag {
- Character,
+ // Character,
CharacterCode,
// InCharacterCode,
MaxArity,
impl RepFlag {
pub fn as_str(self) -> &'static str {
match self {
- RepFlag::Character => "character",
+ // RepFlag::Character => "character",
RepFlag::CharacterCode => "character_code",
// RepFlag::InCharacterCode => "in_character_code",
RepFlag::MaxArity => "max_arity",
pub(crate)
fn read_term(
&mut self,
- stream: Stream,
+ mut stream: Stream,
indices: &mut IndexStore,
) -> CallResult {
- let opt_err =
- if !stream.is_input_stream() {
- Some("stream") // 8.14.2.3 g)
- } else if stream.options.stream_type == StreamType::Binary {
- Some("binary_stream") // 8.14.2.3 h)
- } else {
- None
- };
+ self.check_stream_properties(
+ &mut stream,
+ StreamType::Text,
+ Some(self[temp_v!(2)]),
+ clause_name!("read_term"),
+ 3,
+ )?;
- if let Some(err_string) = opt_err {
- return Err(self.stream_permission_error(
- Permission::InputStream,
- err_string,
- stream,
- clause_name!("read_term"),
- 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();
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)]
pub enum EOFAction {
EOFCode,
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 {
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,
- ));
- }
+ self.check_stream_properties(
+ &mut stream,
+ StreamType::Binary,
+ Some(self[temp_v!(2)]),
+ 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 {
}
}
&SystemClauseType::GetChar => {
+ let mut stream =
+ self.get_stream_or_alias(self[temp_v!(1)], indices, "get_char", 2)?;
+
+ 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(
- current_input_stream.clone(),
+ stream.clone(),
"get_char",
- 1,
+ 2,
)?;
- let result = iter.next();
- let a1 = self[temp_v!(1)];
+ loop {
+ let result = iter.next();
- match result {
- Some(Ok(c)) => {
- self.unify(Addr::Char(c), a1);
- }
- Some(Err(_)) => {
- let end_of_file = self.heap.to_unifiable(HeapCellValue::Atom(
- clause_name!("end_of_file"),
- None,
- ));
+ match result {
+ Some(Ok(c)) => {
+ 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!()
+ }
+ }
+ Addr::Con(h) if self.heap.atom_at(h) => {
+ match &self.heap[h] {
+ 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,
+ );
+
+ return Err(self.error_form(err, stub));
+ }
+ }
+ }
+ _ => {
+ self.eof_action(
+ self[temp_v!(2)],
+ &mut stream,
+ clause_name!("get_char"),
+ 2,
+ )?;
- self.unify(a1, end_of_file);
- }
- None => {
- let stub = MachineError::functor_stub(clause_name!("get_char"), 1);
- let err = MachineError::representation_error(RepFlag::Character);
- let err = self.error_form(err, stub);
+ 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 = self.error_form(err, stub);
- return Err(err);
+ return Err(err);
+ }*/
}
}
}
3,
)?;
+ self.check_stream_properties(
+ &mut stream,
+ StreamType::Text,
+ None, // input
+ clause_name!("write_term"),
+ 3,
+ )?;
+
let opt_err =
if !stream.is_output_stream() {
Some("stream") // 8.14.2.3 g)