Merge branch 'master' into library-use-case
This commit is contained in:
@@ -29,7 +29,7 @@ pub(crate) trait Allocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
@@ -42,7 +42,7 @@ pub(crate) trait Allocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
context: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
);
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::parser::ast::*;
|
||||
use crate::targets::*;
|
||||
use crate::temp_v;
|
||||
use crate::types::*;
|
||||
use crate::variable_records::*;
|
||||
|
||||
use crate::instr;
|
||||
use crate::machine::disjuncts::*;
|
||||
@@ -60,6 +61,7 @@ impl BranchCodeStack {
|
||||
marker: &mut DebrayAllocator,
|
||||
) -> SubsumedBranchHits {
|
||||
let mut subsumed_hits = SubsumedBranchHits::with_hasher(FxBuildHasher::default());
|
||||
let mut propagated_var_nums = IndexSet::with_hasher(FxBuildHasher::default());
|
||||
|
||||
for idx in (self.stack.len() - depth..self.stack.len()).rev() {
|
||||
let branch = &mut marker.branch_stack[idx];
|
||||
@@ -85,9 +87,17 @@ impl BranchCodeStack {
|
||||
}
|
||||
}
|
||||
|
||||
if idx > self.stack.len() - depth {
|
||||
propagated_var_nums.insert(var_num);
|
||||
}
|
||||
|
||||
subsumed_hits.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
for var_num in propagated_var_nums.drain(..) {
|
||||
marker.branch_stack[idx - 1].add_branch_occurrence(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
subsumed_hits
|
||||
@@ -277,7 +287,6 @@ impl DebrayAllocator {
|
||||
code: &mut CodeDeque,
|
||||
) -> RegType {
|
||||
self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
|
||||
|
||||
vr.get().norm()
|
||||
}
|
||||
|
||||
@@ -296,7 +305,14 @@ impl DebrayAllocator {
|
||||
self.mark_var_in_non_callable(var_num, term_loc, vr, code);
|
||||
temp_v!(arg)
|
||||
} else {
|
||||
self.increment_running_count(var_num);
|
||||
if let VarAlloc::Perm(_, PermVarAllocation::Pending) =
|
||||
&self.var_data.records[var_num].allocation
|
||||
{
|
||||
self.mark_var_in_non_callable(var_num, term_loc, vr, code);
|
||||
} else {
|
||||
self.increment_running_count(var_num);
|
||||
}
|
||||
|
||||
RegType::Perm(p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,19 @@ impl BranchOccurrences {
|
||||
subsumed_hits: SubsumedBranchHits::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||
debug_assert!(self.current_branch < self.num_branches);
|
||||
let num_branches = self.num_branches;
|
||||
|
||||
let entry = self
|
||||
.hits
|
||||
.entry(var_num)
|
||||
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||
|
||||
entry.set(self.current_branch, true);
|
||||
self.subsumed_hits.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -92,17 +105,7 @@ impl BranchStack {
|
||||
|
||||
pub(crate) fn add_branch_occurrence(&mut self, var_num: usize) {
|
||||
if let Some(occurrences) = self.last_mut() {
|
||||
debug_assert!(occurrences.current_branch < occurrences.num_branches);
|
||||
|
||||
let num_branches = occurrences.num_branches;
|
||||
|
||||
let entry = occurrences
|
||||
.hits
|
||||
.entry(var_num)
|
||||
.or_insert_with(|| BitVec::repeat(false, num_branches));
|
||||
|
||||
entry.set(occurrences.current_branch, true);
|
||||
occurrences.subsumed_hits.insert(var_num);
|
||||
occurrences.add_branch_occurrence(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,30 +169,26 @@ impl DebrayAllocator {
|
||||
for var_num in subsumed_hits {
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Perm(_, ref mut allocation) => {
|
||||
match allocation {
|
||||
PermVarAllocation::Done {
|
||||
shallow_safety,
|
||||
deep_safety,
|
||||
..
|
||||
} => {
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.shallow_safety.insert(var_num);
|
||||
}
|
||||
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.deep_safety.insert(var_num);
|
||||
}
|
||||
if let PermVarAllocation::Done {
|
||||
shallow_safety,
|
||||
deep_safety,
|
||||
..
|
||||
} = allocation
|
||||
{
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(shallow_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.shallow_safety.insert(var_num);
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
|
||||
if !self
|
||||
.branch_stack
|
||||
.safety_unneeded_in_branch(deep_safety, &branch_designator)
|
||||
{
|
||||
let branch_occurrences = self.branch_stack.last_mut().unwrap();
|
||||
branch_occurrences.deep_safety.insert(var_num);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,7 +739,7 @@ impl Allocator for DebrayAllocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
) {
|
||||
@@ -748,11 +747,11 @@ impl Allocator for DebrayAllocator {
|
||||
RegType::Temp(0) => {
|
||||
let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
|
||||
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||
|
||||
(RegType::Temp(o), true)
|
||||
}
|
||||
RegType::Perm(0) => {
|
||||
let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
|
||||
cell.set(VarReg::Norm(RegType::Perm(p)));
|
||||
(RegType::Perm(p), true)
|
||||
}
|
||||
r @ RegType::Perm(_) => {
|
||||
@@ -780,7 +779,7 @@ impl Allocator for DebrayAllocator {
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
cell: &Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut CodeDeque,
|
||||
r: RegType,
|
||||
@@ -846,8 +845,21 @@ impl Allocator for DebrayAllocator {
|
||||
|
||||
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
|
||||
match self.get_binding(var_num) {
|
||||
RegType::Perm(0) | RegType::Temp(0) => {
|
||||
RegType::Perm(self.alloc_perm_var(var_num, chunk_num))
|
||||
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
|
||||
RegType::Temp(0) => {
|
||||
let t = self.alloc_reg_to_non_var();
|
||||
|
||||
match &mut self.var_data.records[var_num].allocation {
|
||||
VarAlloc::Temp {
|
||||
temp_reg, safety, ..
|
||||
} => {
|
||||
*temp_reg = t;
|
||||
*safety = VarSafetyStatus::GloballyUnneeded;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
RegType::Temp(t)
|
||||
}
|
||||
r => r,
|
||||
}
|
||||
|
||||
21
src/forms.rs
21
src/forms.rs
@@ -744,7 +744,11 @@ impl Number {
|
||||
Number::Float(f) => Number::Float(OrderedFloat(f.signum())),
|
||||
_ => {
|
||||
if self.is_positive() {
|
||||
Number::Fixnum(Fixnum::build_with(1))
|
||||
if self.is_zero() {
|
||||
Number::Fixnum(Fixnum::build_with(0))
|
||||
} else {
|
||||
Number::Fixnum(Fixnum::build_with(1))
|
||||
}
|
||||
} else if self.is_negative() {
|
||||
Number::Fixnum(Fixnum::build_with(-1))
|
||||
} else {
|
||||
@@ -876,7 +880,7 @@ impl ClauseIndexInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub(crate) struct PredicateInfo {
|
||||
pub(crate) is_extensible: bool,
|
||||
pub(crate) is_discontiguous: bool,
|
||||
@@ -885,19 +889,6 @@ pub(crate) struct PredicateInfo {
|
||||
pub(crate) has_clauses: bool,
|
||||
}
|
||||
|
||||
impl Default for PredicateInfo {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
PredicateInfo {
|
||||
is_extensible: false,
|
||||
is_discontiguous: false,
|
||||
is_dynamic: false,
|
||||
is_multifile: false,
|
||||
has_clauses: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PredicateInfo {
|
||||
#[inline]
|
||||
pub(crate) fn compile_incrementally(&self) -> bool {
|
||||
|
||||
@@ -1762,7 +1762,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
while let Some(loc_data) = self.state_stack.pop() {
|
||||
match loc_data {
|
||||
TokenOrRedirect::Atom(atom) => self.print_impromptu_atom(atom),
|
||||
TokenOrRedirect::BarAsOp => append_str!(self, " | "),
|
||||
TokenOrRedirect::BarAsOp => append_str!(self, "|"),
|
||||
TokenOrRedirect::Char(c) => print_char!(self, self.quoted, c),
|
||||
TokenOrRedirect::Op(atom, op) => {
|
||||
self.print_op(&atom.as_str());
|
||||
|
||||
@@ -51,7 +51,8 @@ use wasm_bindgen::prelude::*;
|
||||
#[wasm_bindgen]
|
||||
pub fn eval_code(s: &str) -> String {
|
||||
use machine::mock_wam::*;
|
||||
use web_sys::console;
|
||||
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
let mut wam = Machine::with_test_streams();
|
||||
let bytes = wam.test_load_string(s);
|
||||
|
||||
@@ -1173,8 +1173,13 @@ clause(H, B) :-
|
||||
% The clause will be inserted at the beginning of the module.
|
||||
asserta(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
iso_ext:asserta(Module, Clause).
|
||||
asserta_(Module, Clause).
|
||||
|
||||
asserta_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$asserta'(Module, Head, Body).
|
||||
asserta_(Module, Fact) :-
|
||||
'$asserta'(Module, Fact, true).
|
||||
|
||||
:- meta_predicate assertz(:).
|
||||
|
||||
@@ -1184,7 +1189,13 @@ asserta(Clause0) :-
|
||||
% The clase will be inserted at the end of the module.
|
||||
assertz(Clause0) :-
|
||||
loader:strip_subst_module(Clause0, user, Module, Clause),
|
||||
iso_ext:assertz(Module, Clause).
|
||||
assertz_(Module, Clause).
|
||||
|
||||
assertz_(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$assertz'(Module, Head, Body).
|
||||
assertz_(Module, Fact) :-
|
||||
'$assertz'(Module, Fact, true).
|
||||
|
||||
|
||||
:- meta_predicate retract(:).
|
||||
@@ -1203,6 +1214,9 @@ retract(Clause0) :-
|
||||
Body = true,
|
||||
retract_module_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
( var(Module) -> Module = user
|
||||
; true
|
||||
),
|
||||
retract_module_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
@@ -7968,11 +7968,11 @@ coeff_var_term(C-V, T) :- ( C =:= 1 -> T = #V ; T = C * #V ).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#=(X, Y, T) :-
|
||||
X #= Y #<==> B,
|
||||
X #= Y #<==> #B,
|
||||
zo_t(B, T).
|
||||
|
||||
#<(X, Y, T) :-
|
||||
X #< Y #<==> B,
|
||||
X #< Y #<==> #B,
|
||||
zo_t(B, T).
|
||||
|
||||
zo_t(0, false).
|
||||
|
||||
@@ -33,11 +33,13 @@ remove_goal([G0|G0s], Goal0, Goals) :-
|
||||
|
||||
vars_remove_goal([], _).
|
||||
vars_remove_goal([Var|Vars], Goal0) :-
|
||||
get_atts(Var, +dif(Goals0)),
|
||||
remove_goal(Goals0, Goal0, Goals),
|
||||
( Goals = [] ->
|
||||
put_atts(Var, -dif(_))
|
||||
; put_atts(Var, +dif(Goals))
|
||||
( get_atts(Var, +dif(Goals0)) ->
|
||||
remove_goal(Goals0, Goal0, Goals),
|
||||
( Goals = [] ->
|
||||
put_atts(Var, -dif(_))
|
||||
; put_atts(Var, +dif(Goals))
|
||||
)
|
||||
; true
|
||||
),
|
||||
vars_remove_goal(Vars, Goal0).
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@ but they're not part of the ISO Prolog standard at the moment.
|
||||
succ/2,
|
||||
call_nth/2,
|
||||
countall/2,
|
||||
copy_term_nat/2,
|
||||
asserta/2,
|
||||
assertz/2]).
|
||||
copy_term_nat/2]).
|
||||
|
||||
:- use_module(library(error), [can_be/2,
|
||||
domain_error/3,
|
||||
@@ -384,21 +382,3 @@ countall(Goal, N) :-
|
||||
copy_term_nat(Source, Dest) :-
|
||||
'$copy_term_without_attr_vars'(Source, Dest).
|
||||
|
||||
%% asserta(Module, Rule_Fact).
|
||||
%
|
||||
% Similar to `asserta/1` but allows specifying a Module
|
||||
asserta(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$asserta'(Module, Head, Body).
|
||||
asserta(Module, Fact) :-
|
||||
'$asserta'(Module, Fact, true).
|
||||
|
||||
%% assertz(Module, Rule_Fact).
|
||||
%
|
||||
% Similar to `assertz/1` but allows specifying a Module
|
||||
assertz(Module, (Head :- Body)) :-
|
||||
!,
|
||||
'$assertz'(Module, Head, Body).
|
||||
assertz(Module, Fact) :-
|
||||
'$assertz'(Module, Fact, true).
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
atomic_si/1,
|
||||
list_si/1,
|
||||
character_si/1,
|
||||
term_si/1,
|
||||
chars_si/1,
|
||||
dif_si/2]).
|
||||
|
||||
@@ -68,6 +69,11 @@ character_si(Ch) :-
|
||||
atom(Ch),
|
||||
atom_length(Ch,1).
|
||||
|
||||
term_si(Term) :-
|
||||
( ground(Term) -> acyclic_term(Term)
|
||||
; throw(error(instantiation_error, term_si/1))
|
||||
).
|
||||
|
||||
chars_si(Chs0) :-
|
||||
'$skip_max_list'(_,_, Chs0,Chs),
|
||||
( nonvar(Chs) -> Chs == [] ; true ), % fails for infinite lists too
|
||||
|
||||
@@ -96,7 +96,7 @@ sleep(T) :-
|
||||
:- meta_predicate time(0).
|
||||
|
||||
:- dynamic(time_id/1).
|
||||
:- dynamic(time_state/2).
|
||||
:- dynamic(time_state/3).
|
||||
|
||||
time_next_id(N) :-
|
||||
( retract(time_id(N0)) ->
|
||||
@@ -111,9 +111,9 @@ time_next_id(N) :-
|
||||
% Reports the execution time of Goal.
|
||||
|
||||
time(Goal) :-
|
||||
'$cpu_now'(T0),
|
||||
cputime_inferences(T0, I0),
|
||||
time_next_id(ID),
|
||||
setup_call_cleanup(asserta(time_state(ID, T0)),
|
||||
setup_call_cleanup(asserta(time_state(ID, T0, I0)),
|
||||
( call_cleanup(catch(Goal, E, (report_time(ID),throw(E))),
|
||||
Det = true),
|
||||
time_true(ID),
|
||||
@@ -123,49 +123,72 @@ time(Goal) :-
|
||||
; report_time(ID),
|
||||
false
|
||||
),
|
||||
retract(time_state(ID, _))).
|
||||
retract(time_state(ID, _, _))).
|
||||
|
||||
cputime_inferences(T, I) :-
|
||||
'$cpu_now'(T),
|
||||
'$inference_count'(I).
|
||||
|
||||
time_true(ID) :-
|
||||
report_time(ID).
|
||||
time_true(ID) :-
|
||||
% on backtracking, update the stored CPU time for this ID
|
||||
retract(time_state(ID, _)),
|
||||
'$cpu_now'(T0),
|
||||
asserta(time_state(ID, T0)),
|
||||
retract(time_state(ID, _, _)),
|
||||
cputime_inferences(T0, I0),
|
||||
asserta(time_state(ID, T0, I0)),
|
||||
false.
|
||||
|
||||
report_time(ID) :-
|
||||
time_state(ID, T0),
|
||||
'$cpu_now'(T),
|
||||
time_state(ID, T0, I0),
|
||||
cputime_inferences(T, I),
|
||||
Time is T - T0,
|
||||
Inferences0 is I - I0,
|
||||
% we must subtract the number of inferences that time/1 itself takes;
|
||||
% this may have to be adapted if the implementation changes,
|
||||
% so that (for example) true/1 takes exactly 1 inference.
|
||||
( bb_get('$answer_count', 0) ->
|
||||
Inferences is Inferences0 - 60,
|
||||
Pre = " ", Post = ""
|
||||
; Pre = "", Post = " "
|
||||
; Inferences is Inferences0 - 9,
|
||||
Pre = "", Post = " "
|
||||
),
|
||||
format("~s% CPU time: ~3fs~n~s", [Pre,Time,Post]).
|
||||
phrase((Pre,"% CPU time: ", format_("~3f", [Time]), "s, ",
|
||||
format_("~U", [Inferences])," inference",s_if_necessary(Inferences),"\n",
|
||||
Post), Cs),
|
||||
format("~s", [Cs]).
|
||||
|
||||
s_if_necessary(Inferences) -->
|
||||
{ compare(C, 1, Inferences) },
|
||||
s_(C).
|
||||
|
||||
s_(=) --> "".
|
||||
s_(<) --> "s".
|
||||
s_(>) --> " (exception?)".
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- time((true;false)).
|
||||
%@ % CPU time: 0.006s
|
||||
%@ true
|
||||
%@ ; % CPU time: 0.001s
|
||||
%@ false.
|
||||
% CPU time: 0.000s, 1 inference
|
||||
true
|
||||
; % CPU time: 0.000s, 0 inference (exception?)
|
||||
false.
|
||||
|
||||
:- time(use_module(library(clpz))).
|
||||
%@ % CPU time: 3.711s
|
||||
%@ true.
|
||||
% CPU time: 0.343s, 409_874 inferences
|
||||
true.
|
||||
|
||||
:- time(use_module(library(lists))).
|
||||
%@ % CPU time: 0.006s
|
||||
%@ true.
|
||||
% CPU time: 0.000s, 19 inferences
|
||||
true.
|
||||
|
||||
?- time(member(X, "abc")).
|
||||
%@ % CPU time: 0.005s
|
||||
%@ X = a
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ X = b
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ X = c
|
||||
%@ ; % CPU time: 0.000s
|
||||
%@ false.
|
||||
% CPU time: 0.000s, 1 inference
|
||||
X = a
|
||||
; % CPU time: 0.000s, 3 inferences
|
||||
X = b
|
||||
; % CPU time: 0.000s, 3 inferences
|
||||
X = c.
|
||||
|
||||
?- time((repeat,false)).
|
||||
% CPU time: 2.726s, 53_330_502 inferences
|
||||
error('$interrupt_thrown',repl/0).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
29
src/lib/wasm.pl
Normal file
29
src/lib/wasm.pl
Normal file
@@ -0,0 +1,29 @@
|
||||
/** Predicates for the WebAssembly platform
|
||||
|
||||
This module contains predicates that are only available in
|
||||
the WASM (WebAssembly) version of Scryer Prolog.
|
||||
*/
|
||||
|
||||
:- module(wasm, [js_eval/2]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
|
||||
%% js_eval(+JsCode, -Result).
|
||||
%
|
||||
% Executes a JavaScript snippet `JsCode` using the platform
|
||||
% `eval` function. `Result` takes the return value of that code.
|
||||
% Strings, booleans, numbers, null and undefined are directly mapped to Prolog.
|
||||
% Arrays, objects, bigints, symbols and functions are not mapped.
|
||||
% Instead, a `js_{type}` atom will be returned.
|
||||
%
|
||||
% Example (on a browser):
|
||||
%
|
||||
% ```
|
||||
% ?- js_eval("prompt('What is your name?')", Name).
|
||||
% % A prompt is showed, with a textbox.
|
||||
% Name = "Whatever was written on the textbox".
|
||||
% ```
|
||||
js_eval(JsCode, Result) :-
|
||||
must_be(chars, JsCode),
|
||||
can_be(chars, Result),
|
||||
'$js_eval'(JsCode, Result).
|
||||
@@ -348,7 +348,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
let n1_i = n1.get_num();
|
||||
|
||||
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2.is_zero() {
|
||||
if !(n1_i == 1 || n1_i == 0 || n1_i == -1) && n2.is_negative() {
|
||||
let n = Number::Fixnum(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -359,7 +359,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
(Number::Integer(n1), Number::Fixnum(n2)) => {
|
||||
let n2_i = n2.get_num();
|
||||
|
||||
if !(*n1 == Integer::from(1) || n1.is_zero() || *n1 == Integer::from(-1)) && n2_i < 0 {
|
||||
if !(n1.is_one() || n1.is_zero() || n1.num_eq(&-1)) && n2_i < 0 {
|
||||
let n = Number::Integer(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -368,9 +368,7 @@ pub(crate) fn int_pow(n1: Number, n2: Number, arena: &mut Arena) -> Result<Numbe
|
||||
}
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
if !(*n1 == Integer::from(1) || n1.is_zero() || *n1 == Integer::from(-1))
|
||||
&& n2.is_zero()
|
||||
{
|
||||
if !(n1.is_one() || n1.is_zero() || n1.num_eq(&-1)) && n2.is_negative() {
|
||||
let n = Number::Integer(n1);
|
||||
Err(numerical_type_error(ValidType::Float, n, stub_gen))
|
||||
} else {
|
||||
@@ -711,11 +709,8 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
let n1 = Integer::from(n1.get_num());
|
||||
|
||||
match (&*n2).try_into() as Result<u32, _> {
|
||||
Ok(n2) => {
|
||||
let n1: u64 = n1.try_into().unwrap();
|
||||
Ok(Number::arena_from(n1 << n2, arena))
|
||||
}
|
||||
match (&*n2).try_into() as Result<usize, _> {
|
||||
Ok(n2) => Ok(Number::arena_from(n1 << n2, arena)),
|
||||
_ => Ok(Number::arena_from(n1 << usize::max_value(), arena)),
|
||||
}
|
||||
}
|
||||
@@ -726,11 +721,8 @@ pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, M
|
||||
arena,
|
||||
)),
|
||||
},
|
||||
(Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<u32, _> {
|
||||
Ok(n2) => {
|
||||
let n1: u64 = (&*n1).try_into().unwrap();
|
||||
Ok(Number::arena_from(Integer::from(n1 << n2), arena))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => match (&*n2).try_into() as Result<usize, _> {
|
||||
Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
|
||||
_ => Ok(Number::arena_from(
|
||||
Integer::from(&*n1 << usize::max_value()),
|
||||
arena,
|
||||
|
||||
@@ -18,6 +18,7 @@ pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn push(&mut self, value: HeapCellValue);
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize);
|
||||
fn stack(&mut self) -> &mut Stack;
|
||||
fn threshold(&self) -> usize;
|
||||
}
|
||||
@@ -73,7 +74,6 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = list_loc_as_cell!(h);
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -96,14 +96,19 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
||||
|
||||
if !cdr.is_var() {
|
||||
// mark addr + 1 as a list back edge in the cdr of the list
|
||||
self.trail_list_cell(addr + 1, threshold);
|
||||
self.target[addr + 1].set_mark_bit(true);
|
||||
self.target[addr + 1].set_forwarding_bit(true);
|
||||
} else {
|
||||
let car = self
|
||||
.target
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr)));
|
||||
|
||||
if !car.is_var() {
|
||||
// mark addr as a list back edge in the car of the list
|
||||
self.trail_list_cell(addr, threshold);
|
||||
self.target[addr].set_mark_bit(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,6 +183,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
for (threshold, list_loc) in iter {
|
||||
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
|
||||
self.target.push_attr_var_queue(threshold - 1);
|
||||
self.copy_attr_var_list(list_loc);
|
||||
}
|
||||
}
|
||||
@@ -263,6 +269,7 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
}
|
||||
|
||||
fn copy_var(&mut self, addr: HeapCellValue) {
|
||||
let index = addr.get_value() as usize;
|
||||
let rd = self.target.deref(addr);
|
||||
let ra = self.target.store(rd);
|
||||
|
||||
@@ -271,7 +278,20 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = ra;
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h && self.target[index].get_mark_bit() {
|
||||
*self.value_at_scan() = heap_loc_as_cell!(
|
||||
if ra.get_forwarding_bit() {
|
||||
h + 1
|
||||
} else {
|
||||
h
|
||||
}
|
||||
);
|
||||
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -356,12 +376,16 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn unwind_trail(&mut self) {
|
||||
for (r, value) in self.trail.drain(0..) {
|
||||
fn unwind_trail(mut self) {
|
||||
for (r, value) in self.trail {
|
||||
let index = r.get_value() as usize;
|
||||
|
||||
match r.get_tag() {
|
||||
RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
|
||||
RefTag::AttrVar | RefTag::HeapCell => {
|
||||
self.target[index] = value;
|
||||
self.target[index].set_mark_bit(false);
|
||||
self.target[index].set_forwarding_bit(false);
|
||||
}
|
||||
RefTag::StackCell => self.target.stack()[index] = value,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,12 +663,16 @@ impl VariableClassifier {
|
||||
state_stack.last(),
|
||||
Some(TraversalState::RemoveBranchNum)
|
||||
) {
|
||||
// check if the second-to-last element is a regular BuildDisjunct, as we don't
|
||||
// want to add GetPrevLevel in case of a TrustMe.
|
||||
matches!(
|
||||
state_stack.iter().rev().nth(1),
|
||||
Some(TraversalState::BuildDisjunct(..))
|
||||
)
|
||||
// check if the second-to-last element
|
||||
// is a regular BuildDisjunct, as we
|
||||
// don't want to add GetPrevLevel in
|
||||
// case of a TrustMe.
|
||||
match state_stack.iter().rev().nth(1) {
|
||||
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
|
||||
preceding_len + 1 == build_stack.len()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ macro_rules! try_or_throw {
|
||||
|
||||
macro_rules! increment_call_count {
|
||||
($s:expr) => {{
|
||||
if !($s.increment_call_count_fn)(&mut $s) {
|
||||
if !$s.increment_call_count() {
|
||||
$s.backtrack();
|
||||
continue;
|
||||
}
|
||||
@@ -208,6 +208,7 @@ impl MachineState {
|
||||
l
|
||||
}
|
||||
(HeapCellValueTag::Fixnum |
|
||||
HeapCellValueTag::CutPoint |
|
||||
HeapCellValueTag::Char |
|
||||
HeapCellValueTag::F64) => {
|
||||
c
|
||||
@@ -3675,6 +3676,16 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.install_inference_counter());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallInferenceCount => {
|
||||
let global_count = self.machine_st.cwil.global_count.clone();
|
||||
self.inference_count(self.machine_st.registers[1], global_count);
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteInferenceCount => {
|
||||
let global_count = self.machine_st.cwil.global_count.clone();
|
||||
self.inference_count(self.machine_st.registers[1], global_count);
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallLiftedHeapLength => {
|
||||
self.lifted_heap_length();
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
@@ -4128,6 +4139,14 @@ impl Machine {
|
||||
try_or_throw!(self.machine_st, self.define_foreign_struct());
|
||||
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
|
||||
}
|
||||
&Instruction::CallJsEval => {
|
||||
try_or_throw!(self.machine_st, self.js_eval());
|
||||
step_or_fail!(self, self.machine_st.p += 1);
|
||||
}
|
||||
&Instruction::ExecuteJsEval => {
|
||||
try_or_throw!(self.machine_st, self.js_eval());
|
||||
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);
|
||||
|
||||
@@ -57,10 +57,11 @@ impl Machine {
|
||||
or_frame.prelude.attr_var_queue_len = 0;
|
||||
|
||||
self.machine_st.b = stub_b;
|
||||
self.machine_st.hb = self.machine_st.heap.len();
|
||||
}
|
||||
|
||||
pub fn run_query(&mut self, query: String) -> QueryResult {
|
||||
println!("Query: {}", query);
|
||||
// println!("Query: {}", query);
|
||||
// Parse the query so we can analyze and then call the term
|
||||
let mut parser = Parser::new(
|
||||
Stream::from_owned_string(query, &mut self.machine_st.arena),
|
||||
@@ -87,6 +88,7 @@ impl Machine {
|
||||
.expect("couldn't get code index")
|
||||
.local()
|
||||
.unwrap();
|
||||
self.machine_st.b0 = self.machine_st.b;
|
||||
|
||||
let var_names: IndexMap<_, _> = term_write_result
|
||||
.var_dict
|
||||
@@ -192,7 +194,7 @@ impl Machine {
|
||||
let outputter = printer.print();
|
||||
|
||||
let output: String = outputter.result();
|
||||
println!("Result: {} = {}", var_key.to_string(), output);
|
||||
// println!("Result: {} = {}", var_key.to_string(), output);
|
||||
|
||||
bindings.insert(var_key.to_string(), Value::try_from(output).expect("asdfs"));
|
||||
}
|
||||
@@ -444,10 +446,7 @@ mod tests {
|
||||
}
|
||||
|
||||
// Check if the block is a query
|
||||
if block.starts_with("query") {
|
||||
// Extract the query from the block
|
||||
let query = &block[5..];
|
||||
|
||||
if let Some(query) = block.strip_prefix("query") {
|
||||
i += 1;
|
||||
println!("query #{}: {}", i, query);
|
||||
// Parse and execute the query
|
||||
@@ -457,10 +456,7 @@ mod tests {
|
||||
|
||||
// Print the result
|
||||
println!("{:?}", result);
|
||||
} else if block.starts_with("consult") {
|
||||
// Extract the code from the block
|
||||
let code = &block[7..];
|
||||
|
||||
} else if let Some(code) = block.strip_prefix("consult") {
|
||||
println!("load code: {}", code);
|
||||
|
||||
// Load the code into the machine
|
||||
|
||||
@@ -148,9 +148,10 @@ impl<'a, LS: LoadState<'a>> Drop for Loader<'a, LS> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Default)]
|
||||
pub enum CompilationTarget {
|
||||
Module(Atom),
|
||||
#[default]
|
||||
User,
|
||||
}
|
||||
|
||||
@@ -163,13 +164,6 @@ impl fmt::Display for CompilationTarget {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CompilationTarget {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
CompilationTarget::User
|
||||
}
|
||||
}
|
||||
|
||||
impl CompilationTarget {
|
||||
#[inline]
|
||||
pub(crate) fn module_name(&self) -> Atom {
|
||||
|
||||
@@ -492,13 +492,22 @@ impl MachineState {
|
||||
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
||||
}
|
||||
SessionError::ExistenceError(err) => self.existence_error(err),
|
||||
SessionError::ModuleDoesNotContainExport(..) => {
|
||||
let error_atom = atom!("module_does_not_contain_claimed_export");
|
||||
SessionError::ModuleDoesNotContainExport(module_name, key) => {
|
||||
let functor_stub = functor_stub(key.0, key.1);
|
||||
|
||||
let stub = functor!(
|
||||
atom!("module_does_not_contain_claimed_export"),
|
||||
[
|
||||
atom(module_name),
|
||||
str(self.heap.len() + 4, 0)
|
||||
],
|
||||
[functor_stub]
|
||||
);
|
||||
|
||||
self.permission_error(
|
||||
Permission::Access,
|
||||
atom!("private_procedure"),
|
||||
functor!(error_atom),
|
||||
stub,
|
||||
)
|
||||
}
|
||||
SessionError::ModuleCannotImportSelf(module_name) => {
|
||||
|
||||
@@ -96,7 +96,6 @@ pub struct MachineState {
|
||||
pub(crate) unify_fn: fn(&mut MachineState),
|
||||
pub(crate) bind_fn: fn(&mut MachineState, Ref, HeapCellValue),
|
||||
pub(crate) run_cleaners_fn: fn(&mut Machine) -> bool,
|
||||
pub(crate) increment_call_count_fn: fn(&mut MachineState) -> bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for MachineState {
|
||||
@@ -290,6 +289,11 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
||||
self.state.heap.push(hcv);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||
self.state.store(value)
|
||||
@@ -308,6 +312,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct CopyBallTerm<'a> {
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
heap_boundary: usize,
|
||||
@@ -315,10 +320,16 @@ pub(super) struct CopyBallTerm<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CopyBallTerm<'a> {
|
||||
pub(super) fn new(stack: &'a mut Stack, heap: &'a mut Heap, stub: &'a mut Heap) -> Self {
|
||||
pub(super) fn new(
|
||||
attr_var_queue: &'a mut Vec<usize>,
|
||||
stack: &'a mut Stack,
|
||||
heap: &'a mut Heap,
|
||||
stub: &'a mut Heap,
|
||||
) -> Self {
|
||||
let hb = heap.len();
|
||||
|
||||
CopyBallTerm {
|
||||
attr_var_queue,
|
||||
stack,
|
||||
heap,
|
||||
heap_boundary: hb,
|
||||
@@ -360,6 +371,11 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
|
||||
self.stub.push(value);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.attr_var_queue.push(attr_var_loc);
|
||||
}
|
||||
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||
@@ -417,15 +433,17 @@ impl MachineState {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.cwil.global_count += 1;
|
||||
|
||||
if let Some(&(ref limit, block)) = self.cwil.limits.last() {
|
||||
if self.cwil.count == *limit {
|
||||
if self.cwil.local_count == *limit {
|
||||
self.cwil.inference_limit_exceeded = true;
|
||||
self.block = block;
|
||||
self.unwind_stack();
|
||||
|
||||
return false;
|
||||
} else {
|
||||
self.cwil.count += 1;
|
||||
self.cwil.local_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -967,7 +985,8 @@ impl MachineState {
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CWIL {
|
||||
count: Integer,
|
||||
local_count: Integer,
|
||||
pub(crate) global_count: Integer,
|
||||
limits: Vec<(Integer, usize)>,
|
||||
pub(crate) inference_limit_exceeded: bool,
|
||||
}
|
||||
@@ -975,22 +994,22 @@ pub(crate) struct CWIL {
|
||||
impl CWIL {
|
||||
pub(crate) fn new() -> Self {
|
||||
CWIL {
|
||||
count: Integer::from(0),
|
||||
local_count: Integer::from(0),
|
||||
global_count: Integer::from(0),
|
||||
limits: vec![],
|
||||
inference_limit_exceeded: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_limit(&mut self, limit: usize, block: usize) -> &Integer {
|
||||
let mut limit = Integer::from(limit);
|
||||
limit += &self.count;
|
||||
pub(crate) fn add_limit(&mut self, mut limit: Integer, block: usize) -> &Integer {
|
||||
limit += &self.local_count;
|
||||
|
||||
match self.limits.last() {
|
||||
Some((ref inner_limit, _)) if *inner_limit <= limit => {}
|
||||
_ => self.limits.push((limit, block)),
|
||||
};
|
||||
}
|
||||
|
||||
&self.count
|
||||
&self.local_count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -1001,12 +1020,12 @@ impl CWIL {
|
||||
}
|
||||
}
|
||||
|
||||
&self.count
|
||||
&self.local_count
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.count = Integer::from(0);
|
||||
self.local_count = Integer::from(0);
|
||||
self.limits.clear();
|
||||
self.inference_limit_exceeded = false;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,6 @@ impl MachineState {
|
||||
unify_fn: MachineState::unify,
|
||||
bind_fn: MachineState::bind,
|
||||
run_cleaners_fn: |_| false,
|
||||
increment_call_count_fn: |_| true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +334,12 @@ impl MachineState {
|
||||
self.ball.boundary = self.heap.len();
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.ball.stub),
|
||||
CopyBallTerm::new(
|
||||
&mut self.attr_var_init.attr_var_queue,
|
||||
&mut self.stack,
|
||||
&mut self.heap,
|
||||
&mut self.ball.stub,
|
||||
),
|
||||
addr,
|
||||
AttrVarPolicy::DeepCopy,
|
||||
);
|
||||
|
||||
@@ -159,6 +159,14 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
|
||||
self.wam.machine_st.heap.push(val);
|
||||
}
|
||||
|
||||
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
|
||||
self.wam
|
||||
.machine_st
|
||||
.attr_var_init
|
||||
.attr_var_queue
|
||||
.push(attr_var_loc);
|
||||
}
|
||||
|
||||
fn stack(&mut self) -> &mut Stack {
|
||||
&mut self.wam.machine_st.stack
|
||||
}
|
||||
|
||||
@@ -211,6 +211,15 @@ impl Machine {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_inference_count(&mut self) -> u64 {
|
||||
self.machine_st
|
||||
.cwil
|
||||
.global_count
|
||||
.clone()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||
let err = self.machine_st.session_error(err);
|
||||
let stub = functor_stub(key.0, key.1);
|
||||
|
||||
@@ -27,6 +27,7 @@ use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||
use std::mem;
|
||||
use std::net::{Shutdown, TcpStream};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
@@ -1837,42 +1838,55 @@ impl MachineState {
|
||||
}
|
||||
};
|
||||
|
||||
let file = match open_options.open(&*file_spec.as_str()) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
// 8.11.5.3j)
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let mut path = PathBuf::from(&*file_spec.as_str());
|
||||
|
||||
let err =
|
||||
self.existence_error(ExistenceError::SourceSink(self[temp_v!(1)]));
|
||||
loop {
|
||||
let file = match open_options.open(&path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
match err.kind() {
|
||||
ErrorKind::NotFound => {
|
||||
// 8.11.5.3j)
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
let err =
|
||||
self.existence_error(ExistenceError::SourceSink(self[temp_v!(1)]));
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
ErrorKind::PermissionDenied => {
|
||||
// 8.11.5.3k)
|
||||
return Err(self.open_permission_error(
|
||||
self.registers[1],
|
||||
atom!("open"),
|
||||
4,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// assume the OS is out of file descriptors.
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let err = self.resource_error(ResourceError::OutOfFiles);
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
}
|
||||
}
|
||||
ErrorKind::PermissionDenied => {
|
||||
// 8.11.5.3k)
|
||||
return Err(self.open_permission_error(
|
||||
self.registers[1],
|
||||
atom!("open"),
|
||||
4,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// assume the OS is out of file descriptors.
|
||||
let stub = functor_stub(atom!("open"), 4);
|
||||
let err = self.resource_error(ResourceError::OutOfFiles);
|
||||
}
|
||||
};
|
||||
|
||||
return Err(self.error_form(err, stub));
|
||||
if path.extension().is_none() {
|
||||
if let Some(metadata) = file.metadata().ok() {
|
||||
if metadata.is_dir() {
|
||||
path.set_extension("pl");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(if is_input_file {
|
||||
Stream::from_file_as_input(file_spec, file, &mut self.arena)
|
||||
} else {
|
||||
Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena)
|
||||
})
|
||||
return Ok(if is_input_file {
|
||||
Stream::from_file_as_input(file_spec, file, &mut self.arena)
|
||||
} else {
|
||||
Stream::from_file_as_output(file_spec, file, in_append_mode, &mut self.arena)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::*;
|
||||
|
||||
use dashu::integer::Sign;
|
||||
use dashu::integer::UBig;
|
||||
use dashu::integer::{Sign, UBig};
|
||||
use lazy_static::lazy_static;
|
||||
use num_order::NumOrd;
|
||||
|
||||
@@ -828,8 +827,12 @@ impl MachineState {
|
||||
) -> usize {
|
||||
let threshold = self.lifted_heap.len() - lh_offset;
|
||||
|
||||
let mut copy_ball_term =
|
||||
CopyBallTerm::new(&mut self.stack, &mut self.heap, &mut self.lifted_heap);
|
||||
let mut copy_ball_term = CopyBallTerm::new(
|
||||
&mut self.attr_var_init.attr_var_queue,
|
||||
&mut self.stack,
|
||||
&mut self.heap,
|
||||
&mut self.lifted_heap,
|
||||
);
|
||||
|
||||
copy_ball_term.push(list_loc_as_cell!(threshold + 1));
|
||||
copy_ball_term.push(heap_loc_as_cell!(threshold + 3));
|
||||
@@ -4188,7 +4191,14 @@ impl Machine {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn cpu_now(&mut self) {
|
||||
// TODO
|
||||
let millisecs = web_sys::window()
|
||||
.expect("window global object should be available")
|
||||
.performance()
|
||||
.expect("performance property in window should be available")
|
||||
.now();
|
||||
let secs = float_alloc!(millisecs / 1000.0, self.machine_st.arena);
|
||||
|
||||
self.machine_st.unify_f64(secs, self.deref_register(1));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -4879,6 +4889,70 @@ impl Machine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[inline(always)]
|
||||
pub(crate) fn js_eval(&mut self) -> CallResult {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[inline(always)]
|
||||
pub(crate) fn js_eval(&mut self) -> CallResult {
|
||||
let code = self.deref_register(1);
|
||||
let result_reg = self.deref_register(2);
|
||||
if let Some(code) = self.machine_st.value_to_str_like(code) {
|
||||
match js_sys::eval(&code.as_str()) {
|
||||
Ok(result) => self.unify_js_value(result, result_reg),
|
||||
Err(result) => self.unify_js_value(result, result_reg),
|
||||
};
|
||||
return Ok(());
|
||||
}
|
||||
self.machine_st.fail = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn unify_js_value(&mut self, result: wasm_bindgen::JsValue, result_reg: HeapCellValue) {
|
||||
match result.as_bool() {
|
||||
Some(result) => match result {
|
||||
true => self.machine_st.unify_atom(atom!("true"), result_reg),
|
||||
false => self.machine_st.unify_atom(atom!("false"), result_reg),
|
||||
},
|
||||
None => match result.as_f64() {
|
||||
Some(result) => {
|
||||
let n = float_alloc!(result, self.machine_st.arena);
|
||||
self.machine_st.unify_f64(n, result_reg);
|
||||
}
|
||||
None => match result.as_string() {
|
||||
Some(result) => {
|
||||
let result = AtomTable::build_with(&self.machine_st.atom_tbl, &result);
|
||||
self.machine_st.unify_complete_string(result, result_reg);
|
||||
}
|
||||
None => {
|
||||
if result.is_null() {
|
||||
self.machine_st.unify_atom(atom!("null"), result_reg);
|
||||
} else if result.is_undefined() {
|
||||
self.machine_st.unify_atom(atom!("undefined"), result_reg);
|
||||
} else if result.is_symbol() {
|
||||
self.machine_st.unify_atom(atom!("js_symbol"), result_reg);
|
||||
} else if result.is_object() {
|
||||
self.machine_st.unify_atom(atom!("js_object"), result_reg);
|
||||
} else if result.is_array() {
|
||||
self.machine_st.unify_atom(atom!("js_array"), result_reg);
|
||||
} else if result.is_function() {
|
||||
self.machine_st.unify_atom(atom!("js_function"), result_reg);
|
||||
} else if result.is_bigint() {
|
||||
self.machine_st.unify_atom(atom!("js_bigint"), result_reg);
|
||||
} else {
|
||||
self.machine_st
|
||||
.unify_atom(atom!("js_unknown_type"), result_reg);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn current_time(&mut self) {
|
||||
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
|
||||
@@ -5516,11 +5590,8 @@ impl Machine {
|
||||
let a2 = self.deref_register(2);
|
||||
|
||||
let n = match Number::try_from(a2) {
|
||||
Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
|
||||
Ok(Number::Integer(n)) => {
|
||||
let value: usize = (&*n).try_into().unwrap();
|
||||
value
|
||||
}
|
||||
Ok(Number::Fixnum(bp)) => Integer::from(bp.get_num() as usize),
|
||||
Ok(Number::Integer(n)) => (*n).clone(),
|
||||
_ => {
|
||||
let stub = functor_stub(atom!("call_with_inference_limit"), 3);
|
||||
|
||||
@@ -5531,21 +5602,24 @@ impl Machine {
|
||||
|
||||
let bp = cell_as_fixnum!(a1).get_num() as usize;
|
||||
let a3 = self.deref_register(3);
|
||||
let count = self.machine_st.cwil.add_limit(n, bp);
|
||||
|
||||
let result = count.try_into();
|
||||
if let Ok(value) = result {
|
||||
self.machine_st.unify_fixnum(Fixnum::build_with(value), a3);
|
||||
} else {
|
||||
let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
|
||||
self.machine_st.unify_big_int(count, a3);
|
||||
}
|
||||
|
||||
self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
|
||||
let count = self.machine_st.cwil.add_limit(n, bp).clone();
|
||||
self.inference_count(a3, count);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn inference_count(&mut self, count_var: HeapCellValue, count: Integer) {
|
||||
if let Some(value) = <&Integer as TryInto<i64>>::try_into(&count).ok() {
|
||||
self.machine_st
|
||||
.unify_fixnum(Fixnum::build_with(value), count_var);
|
||||
} else {
|
||||
let count = arena_alloc!(count, &mut self.machine_st.arena);
|
||||
self.machine_st.unify_big_int(count, count_var);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn module_exists(&mut self) {
|
||||
let module = self.deref_register(1);
|
||||
@@ -5671,7 +5745,6 @@ impl Machine {
|
||||
|
||||
if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
|
||||
self.machine_st.cwil.reset();
|
||||
self.machine_st.increment_call_count_fn = |_| true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6791,6 +6864,7 @@ impl Machine {
|
||||
|
||||
copy_term(
|
||||
CopyBallTerm::new(
|
||||
&mut self.machine_st.attr_var_init.attr_var_queue,
|
||||
&mut self.machine_st.stack,
|
||||
&mut self.machine_st.heap,
|
||||
&mut ball.stub,
|
||||
|
||||
@@ -327,8 +327,9 @@ impl DoubleQuotes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub enum Unknown {
|
||||
#[default]
|
||||
Error,
|
||||
Fail,
|
||||
Warn,
|
||||
@@ -348,13 +349,6 @@ impl Unknown {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Unknown {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Unknown::Error
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_op_dir() -> OpDir {
|
||||
let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
|
||||
|
||||
|
||||
@@ -207,6 +207,13 @@ test("scryer-prolog#2056",(
|
||||
\+ E=[]
|
||||
)).
|
||||
|
||||
% https://github.com/mthom/scryer-prolog/issues/2175
|
||||
test("scryer-prolog#2175",(
|
||||
dif(A,B),
|
||||
A=_C*[],
|
||||
A=[]*D*B,D=[]
|
||||
)).
|
||||
|
||||
main :-
|
||||
findall(test(Name, Goal), test(Name, Goal), Tests),
|
||||
run_tests(Tests, Failed),
|
||||
|
||||
@@ -452,4 +452,4 @@ print_exception_with_check(E) :-
|
||||
% is expected to be printed instead.
|
||||
; print_exception(E)
|
||||
).
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user