From 47e3a5e75a7eda482fc0c68dad4c739620bbd751 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Tue, 5 May 2020 17:42:18 -0600 Subject: [PATCH] add put_byte/{1,2}, put_char/{1,2} --- src/prolog/clause_types.rs | 14 ++++ src/prolog/lib/builtins.pl | 17 +++++ src/prolog/machine/machine_errors.rs | 4 +- src/prolog/machine/streams.rs | 21 +++++- src/prolog/machine/system_calls.rs | 105 ++++++++++++++++++++++++++- 5 files changed, 157 insertions(+), 4 deletions(-) diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index 614df359..bf0d75a9 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -222,6 +222,8 @@ pub enum SystemClauseType { Open, PartialStringTail, PointsToContinuationResetMarker, + PutByte, + PutChar, REPL(REPLCodePtr), ReadQueryTerm, ReadTerm, @@ -385,6 +387,12 @@ impl SystemClauseType { &SystemClauseType::PointsToContinuationResetMarker => { clause_name!("$points_to_cont_reset_marker") } + &SystemClauseType::PutByte => { + clause_name!("$put_byte") + } + &SystemClauseType::PutChar => { + clause_name!("$put_char") + } &SystemClauseType::QuotedToken => { clause_name!("$quoted_token") } @@ -495,6 +503,12 @@ impl SystemClauseType { ("$points_to_cont_reset_marker", 1) => { Some(SystemClauseType::PointsToContinuationResetMarker) } + ("$put_byte", 2) => { + Some(SystemClauseType::PutByte) + } + ("$put_char", 2) => { + Some(SystemClauseType::PutChar) + } ("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState), ("$truncate_if_no_lh_growth", 1) => { Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth) diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 22c7619f..9848b1e6 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -52,6 +52,7 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- 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, + put_byte/1, put_byte/2, put_char/1, put_char/2, 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, @@ -1199,3 +1200,19 @@ get_byte(S, B) :- get_byte(S) :- current_input(S), '$get_byte'(S, B). + + +put_char(C) :- + current_output(S), + '$put_char'(S, C). + +put_char(S, C) :- + '$put_char'(S, C). + + +put_byte(C) :- + current_output(S), + '$put_byte'(S, C). + +put_byte(S, C) :- + '$put_byte'(S, C). diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index 5afae443..cb448199 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -489,7 +489,7 @@ pub enum ValidType { Atom, Atomic, // Boolean, - // Byte, + Byte, Callable, Character, Compound, @@ -512,7 +512,7 @@ impl ValidType { ValidType::Atom => "atom", ValidType::Atomic => "atomic", // ValidType::Boolean => "boolean", - // ValidType::Byte => "byte", + ValidType::Byte => "byte", ValidType::Callable => "callable", ValidType::Character => "character", ValidType::Compound => "compound", diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index 7e11c0df..2ac482e7 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -278,6 +278,17 @@ impl Stream { pub(crate) fn close(&mut self) { *self.stream_inst.0.borrow_mut() = StreamInstance::Null; + self.past_end_of_stream = true; + } + + #[inline] + pub(crate) + fn is_null_stream(&self) -> bool { + if let StreamInstance::Null = *self.stream_inst.0.borrow() { + true + } else { + false + } } #[inline] @@ -485,7 +496,15 @@ impl MachineState { } Addr::Stream(h) => { if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - stream.clone() + if stream.is_null_stream() { + return Err(self.open_permission_error( + Addr::Stream(h), + caller, + arity, + )); + } else { + stream.clone() + } } else { unreachable!() } diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 43492247..7c6c6c88 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -1592,6 +1592,109 @@ impl MachineState { self.unify(complete_string, a2); } + &SystemClauseType::PutChar => { + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "put_char", 2)?; + + self.check_stream_properties( + &mut stream, + StreamType::Text, + None, + clause_name!("put_char"), + 2, + )?; + + match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => { + let stub = MachineError::functor_stub(clause_name!("put_char"), 2); + let err = MachineError::instantiation_error(); + + return Err(self.error_form(err, stub)); + } + addr => { + match self.store(self.deref(self[temp_v!(2)])) { + Addr::Con(h) if self.heap.atom_at(h) => { + match &self.heap[h] { + HeapCellValue::Atom(ref atom, _) if atom.is_char() => { + if let Some(c) = atom.as_str().chars().next() { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + } + } + Addr::Char(c) => { + write!(&mut stream, "{}", c).unwrap(); + return return_from_clause!(self.last_call, self); + } + _ => { + } + } + + let stub = MachineError::functor_stub(clause_name!("put_char"), 2); + let err = MachineError::type_error( + self.heap.h(), + ValidType::Character, + addr, + ); + + return Err(self.error_form(err, stub)); + } + } + } + &SystemClauseType::PutByte => { + let mut stream = + self.get_stream_or_alias(self[temp_v!(1)], indices, "put_byte", 2)?; + + self.check_stream_properties( + &mut stream, + StreamType::Binary, + None, + clause_name!("put_byte"), + 2, + )?; + + match self.store(self.deref(self[temp_v!(2)])) { + addr if addr.is_ref() => { + let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); + let err = MachineError::instantiation_error(); + + return Err(self.error_form(err, stub)); + } + addr => { + match Number::try_from((addr, &self.heap)) { + Ok(Number::Integer(n)) => { + if let Some(nb) = n.to_u8() { + stream.write(&mut [nb]).unwrap(); + return return_from_clause!(self.last_call, self); + } + } + Ok(Number::Fixnum(n)) => { + if let Ok(nb) = u8::try_from(n) { + stream.write(&mut [nb]).unwrap(); + return return_from_clause!(self.last_call, self); + } + } + _ => { + } + } + + let stub = MachineError::functor_stub(clause_name!("put_byte"), 2); + let err = MachineError::type_error( + self.heap.h(), + ValidType::Byte, + self[temp_v!(2)], + ); + + return Err(self.error_form(err, stub)); + } + } + } &SystemClauseType::GetByte => { let mut stream = self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?; @@ -2436,7 +2539,7 @@ impl MachineState { true } "write" => { - open_options.read(false).write(true).create(true).append(false); + open_options.read(false).write(true).truncate(true).create(true); false } "append" => { -- 2.54.0