From: Mark Thom Date: Sat, 9 May 2020 20:20:32 +0000 (-0600) Subject: add set_stream_position/2 X-Git-Tag: v0.8.123~57^2~1 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=6f927b99411c629947a0066781d96492ff35abd3;p=scryer-prolog.git add set_stream_position/2 --- diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index b4f1ee85..36f278df 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -248,6 +248,7 @@ pub enum SystemClauseType { StoreGlobalVar, StoreGlobalVarWithOffset, StreamProperty, + SetStreamPosition, InferenceLevel, CleanUpBlock, EraseBall, @@ -422,6 +423,7 @@ impl SystemClauseType { &SystemClauseType::SetOutput => clause_name!("$set_output"), &SystemClauseType::SetSeed => clause_name!("$set_seed"), &SystemClauseType::StreamProperty => clause_name!("$stream_property"), + &SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"), &SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"), &SystemClauseType::StoreGlobalVarWithOffset => { clause_name!("$store_global_var_with_offset") @@ -575,6 +577,7 @@ impl SystemClauseType { ("$set_input", 1) => Some(SystemClauseType::SetInput), ("$set_output", 1) => Some(SystemClauseType::SetOutput), ("$stream_property", 3) => Some(SystemClauseType::StreamProperty), + ("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition), ("$inference_level", 2) => Some(SystemClauseType::InferenceLevel), ("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock), ("$erase_ball", 0) => Some(SystemClauseType::EraseBall), diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index ba1f41fb..798e201a 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -59,10 +59,10 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- put_byte/1, put_byte/2, put_code/1, put_code/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, - stream_property/2, sub_atom/5, subsumes_term/2, - term_variables/2, throw/1, true/0, - unify_with_occurs_check/2, write/1, + set_input/1, set_stream_position/2, set_output/1, + setof/3, stream_property/2, sub_atom/5, + subsumes_term/2, term_variables/2, throw/1, + true/0, unify_with_occurs_check/2, write/1, write_canonical/1, write_term/2, write_term/3, writeq/1]). @@ -1320,3 +1320,12 @@ at_end_of_stream :- !, ( E = at ; E = past ). + +set_stream_position(S_or_a, Position) :- + ( var(Position) -> + throw(error(instantiation_error, set_stream_position/2)) + ; integer(Position), Position >= 0 -> + true + ; throw(error(domain_error(stream_position, Position))) + ), + '$set_stream_position'(S_or_a, Position). diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index d384185b..93c36a73 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -468,9 +468,11 @@ pub enum Permission { Modify, Open, OutputStream, + Reposition, } impl Permission { + #[inline] pub fn as_str(self) -> &'static str { match self { Permission::Access => "access", @@ -479,6 +481,7 @@ impl Permission { Permission::Modify => "modify", Permission::Open => "open", Permission::OutputStream => "output", + Permission::Reposition => "reposition", } } } diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index 66ad2b32..68b2ec3b 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -27,6 +27,15 @@ impl StreamType { #[inline] pub(crate) fn as_str(&self) -> &'static str { + match self { + StreamType::Binary => "binary_stream", + StreamType::Text => "text_stream", + } + } + + #[inline] + pub(crate) + fn as_property_str(&self) -> &'static str { match self { StreamType::Binary => "binary", StreamType::Text => "text", @@ -296,6 +305,22 @@ impl Stream { } } + #[inline] + pub(crate) + fn set_position(&mut self, position: u64) { + match self.stream_inst.0.borrow_mut().deref_mut() { + (past_end_of_stream, StreamInstance::InputFile(_, ref mut file)) => { + file.seek(SeekFrom::Start(position)).unwrap(); + + if let Ok(metadata) = file.metadata() { + *past_end_of_stream = position > metadata.len(); + } + } + _ => { + } + } + } + #[inline] pub(crate) fn past_end_of_stream(&self) -> bool { diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 43bfba86..e01008e0 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -4556,6 +4556,49 @@ impl MachineState { } } } + &SystemClauseType::SetStreamPosition => { + let mut stream = self.get_stream_or_alias( + self[temp_v!(1)], + indices, + "set_stream_position", + 2, + )?; + + if !stream.options.reposition { + let stub = MachineError::functor_stub(clause_name!("set_stream_position"), 2); + + let err = MachineError::permission_error( + self.heap.h(), + Permission::Reposition, + "stream", + vec![HeapCellValue::Stream(stream)], + ); + + return Err(self.error_form(err, stub)); + } + + let position = self.store(self.deref(self[temp_v!(2)])); + + let position = + match Number::try_from((position, &self.heap)) { + Ok(Number::Fixnum(n)) => { + n as u64 + } + Ok(Number::Integer(n)) => { + if let Some(n) = n.to_u64() { + n + } else { + self.fail = true; + return Ok(()); + } + } + _ => { + unreachable!() + } + }; + + stream.set_position(position); + } &SystemClauseType::StreamProperty => { let mut stream = self.get_stream_or_alias( self[temp_v!(1)], @@ -4648,7 +4691,7 @@ impl MachineState { } "type" => { HeapCellValue::Atom( - clause_name!(stream.options.stream_type.as_str()), + clause_name!(stream.options.stream_type.as_property_str()), None, ) }