PopCount,
#[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
CpuNow,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$det_length_rundown")))]
+ DeterministicLengthRundown,
REPL(REPLCodePtr),
}
&Instruction::CallInstallNewBlock(_) |
&Instruction::CallMaybe(_) |
&Instruction::CallCpuNow(_) |
+ &Instruction::CallDeterministicLengthRundown(_) |
&Instruction::CallCurrentTime(_) |
&Instruction::CallQuotedToken(_) |
&Instruction::CallReadTermFromChars(_) |
&Instruction::ExecuteInstallNewBlock(_) |
&Instruction::ExecuteMaybe(_) |
&Instruction::ExecuteCpuNow(_) |
+ &Instruction::ExecuteDeterministicLengthRundown(_) |
&Instruction::ExecuteCurrentTime(_) |
&Instruction::ExecuteQuotedToken(_) |
&Instruction::ExecuteReadTermFromChars(_) |
:- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?).
+:- use_module(library(error)).
+
+:- meta_predicate(resource_error(+,:)).
+
+resource_error(Resource, Context) :-
+ throw(error(resource_error(Resource), Context)).
+
length(Xs0, N) :-
'$skip_max_list'(M, N, Xs0,Xs),
!,
( Xs == [] -> N = M
- ; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
+ ; nonvar(Xs) -> var(N), Xs = [_|_], resource_error(finite_memory,length/2)
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
- ; N == Xs -> throw(error(resource_error(finite_memory),length/2))
+ ; N == Xs -> failingvarskip(Xs), resource_error(finite_memory,length/2)
; length_addendum(Xs, N, M)
).
length(_, N) :-
length(_, N) :-
type_error(integer, N, length/2).
+length_rundown(Xs, 0) :- !, Xs = [].
+length_rundown(Vs, N) :-
+ \+ \+ '$project_atts':copy_term(Vs,Vs,[]), % unconstrained
+ !,
+ '$det_length_rundown'(Vs, N).
+length_rundown([_|Xs], N) :- % force unification
+ N1 is N-1,
+ length(Xs, N1). % maybe some new info on Xs
+
+failingvarskip(Xs) :-
+ \+ \+ '$project_atts':copy_term(Xs,Xs,[]), % unconstrained
+ !.
+failingvarskip([_|Xs0]) :- % force unification
+ '$skip_max_list'(_, _, Xs0,Xs),
+ ( nonvar(Xs) -> Xs = [_|_]
+ ; failingvarskip(Xs)
+ ).
+
length_addendum([], N, N).
length_addendum([_|Xs], N, M) :-
M1 is M + 1,
length_addendum(Xs, N, M1).
-length_rundown(Xs, 0) :- !, Xs = [].
-length_rundown([_|Xs], N) :-
- N1 is N-1,
- length_rundown(Xs, N1).
-
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
self.cpu_now();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
+ &Instruction::CallDeterministicLengthRundown(_) => {
+ try_or_throw!(self.machine_st, self.det_length_rundown());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeterministicLengthRundown(_) => {
+ try_or_throw!(self.machine_st, self.det_length_rundown());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
&Instruction::CallCurrentTime(_) => {
self.current_time();
step_or_fail!(self, self.machine_st.p += 1);
self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
}
+ #[inline(always)]
+ pub(crate) fn det_length_rundown(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("length"), 2);
+ let len = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+ let n = match Number::try_from(len) {
+ Ok(Number::Fixnum(n)) => n.get_num() as usize,
+ Ok(Number::Integer(n)) => match n.to_usize() {
+ Some(n) => n,
+ None => {
+ let err = self.machine_st.resource_error(len);
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
+ }
+ _ => {
+ unreachable!()
+ }
+ };
+
+ let h = self.machine_st.heap.len();
+
+ iter_to_heap_list(
+ &mut self.machine_st.heap,
+ (0 .. n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)),
+ );
+
+ let tail = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+ self.machine_st.bind(tail.as_var().unwrap(), heap_loc_as_cell!(h));
+
+ Ok(())
+ }
+
#[inline(always)]
pub(crate) fn current_time(&mut self) {
let timestamp = self.systemtime_to_timestamp(SystemTime::now());