Remove redundant alias resolution in at_end_of_stream/1, add corresponding tests for null streams

Also fixed at_end_of_stream/0 leaving a choicepoint.
This commit is contained in:
Emilie Burgun
2025-02-07 14:59:32 +01:00
parent 8966e175f1
commit f45b0bcfe8
3 changed files with 78 additions and 12 deletions

View File

@@ -2188,12 +2188,10 @@ stream_property(S, P) :-
%% at_end_of_stream(+Stream).
%
% True iff the stream Stream has ended
at_end_of_stream(S_or_a) :-
( var(S_or_a) ->
at_end_of_stream(S) :-
( var(S) ->
throw(error(instantiation_error, at_end_of_stream/1))
; atom(S_or_a) ->
stream_property(S, alias(S_or_a))
; S = S_or_a
; true
),
stream_property(S, end_of_stream(E)),
( E = at -> true ; E = past ).
@@ -2205,7 +2203,7 @@ at_end_of_stream :-
current_input(S),
stream_property(S, end_of_stream(E)),
!,
( E = at ; E = past ).
( E = at -> true ; E = past ).
%% set_stream_position(+Stream, +Position).
%

View File

@@ -510,9 +510,12 @@ impl Machine {
self.indices.streams.insert(self.user_error);
let mut null_options = StreamOptions::default();
null_options.set_alias_to_atom_opt(Some(atom!("null_stream")));
self.indices
.stream_aliases
.insert(atom!("null_stream"), Stream::Null(StreamOptions::default()));
.insert(atom!("null_stream"), Stream::Null(null_options));
}
#[inline(always)]

View File

@@ -1908,6 +1908,14 @@ impl MachineState {
mod test {
use super::*;
use crate::machine::config::*;
use crate::LeafAnswer;
fn is_successful<T>(answer: &Result<LeafAnswer, T>) -> bool {
matches!(
answer,
Ok(LeafAnswer::True) | Ok(LeafAnswer::LeafAnswer { .. })
)
}
#[test]
#[cfg_attr(miri, ignore)]
@@ -1919,7 +1927,7 @@ mod test {
let results = machine.run_query("current_input(S).").collect::<Vec<_>>();
assert_eq!(results.len(), 1);
assert!(results[0].is_ok());
assert!(is_successful(&results[0]));
}
#[test]
@@ -1933,7 +1941,7 @@ mod test {
assert_eq!(results.len(), 1);
assert!(
results[0].is_ok(),
is_successful(&results[0]),
"Expected read to succeed, got {:?}",
results[0]
);
@@ -1951,7 +1959,7 @@ mod test {
let results = machine.run_query("current_output(S).").collect::<Vec<_>>();
assert_eq!(results.len(), 1);
assert!(results[0].is_ok());
assert!(is_successful(&results[0]));
}
#[test]
@@ -1967,7 +1975,28 @@ mod test {
assert_eq!(results.len(), 1);
assert!(
results[0].is_ok(),
is_successful(&results[0]),
"Expected write to succeed, got {:?}",
results[0]
);
}
#[test]
#[cfg_attr(miri, ignore)]
fn put_code_null_stream() {
// TODO: switch to a proper solution for configuring the machine with null streams
// once `StreamConfig` supports it.
let mut machine = MachineBuilder::new().build();
machine.user_output = Stream::Null(StreamOptions::default());
machine.configure_streams();
let results = machine
.run_query("put_code(user_output, 65).")
.collect::<Vec<_>>();
assert_eq!(results.len(), 1);
assert!(
is_successful(&results[0]),
"Expected write to succeed, got {:?}",
results[0]
);
@@ -1987,9 +2016,45 @@ mod test {
assert_eq!(results.len(), 1);
assert!(
results[0].is_ok(),
is_successful(&results[0]),
"Expected write to succeed, got {:?}",
results[0]
);
}
#[test]
#[cfg_attr(miri, ignore)]
fn at_end_of_stream_0_null_stream() {
let mut machine = MachineBuilder::new()
.with_streams(StreamConfig::in_memory())
.build();
let results = machine.run_query("at_end_of_stream.").collect::<Vec<_>>();
assert_eq!(results.len(), 1);
assert!(
is_successful(&results[0]),
"Expected at_end_of_stream to succeed, got {:?}",
results[0]
);
}
#[test]
#[cfg_attr(miri, ignore)]
fn at_end_of_stream_1_null_stream() {
let mut machine = MachineBuilder::new()
.with_streams(StreamConfig::in_memory())
.build();
let results = machine
.run_query("current_input(Stream), at_end_of_stream(Stream).")
.collect::<Vec<_>>();
assert_eq!(results.len(), 1);
assert!(
is_successful(&results[0]),
"Expected at_end_of_stream to succeed, got {:?}",
results[0]
);
}
}