970 lines
25 KiB
Prolog
970 lines
25 KiB
Prolog
/* $Id$
|
|
|
|
Part of CHR (Constraint Handling Rules)
|
|
|
|
Author: Christian Holzbaur and Tom Schrijvers
|
|
E-mail: christian@ai.univie.ac.at
|
|
Tom.Schrijvers@cs.kuleuven.be
|
|
WWW: http://www.swi-prolog.org
|
|
Copyright (C): 2003-2004, K.U. Leuven
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
As a special exception, if you link this library with other files,
|
|
compiled with a Free Software compiler, to produce an executable, this
|
|
library does not by itself cause the resulting executable to be covered
|
|
by the GNU General Public License. This exception does not however
|
|
invalidate any other reasons why the executable file might be covered by
|
|
the GNU General Public License.
|
|
|
|
Distributed with SWI-Prolog under the above conditions with
|
|
permission from the authors.
|
|
*/
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%% _ _ _
|
|
%% ___| |__ _ __ _ __ _ _ _ __ | |_(_)_ __ ___ ___
|
|
%% / __| '_ \| '__| | '__| | | | '_ \| __| | '_ ` _ \ / _ \
|
|
%% | (__| | | | | | | | |_| | | | | |_| | | | | | | __/
|
|
%% \___|_| |_|_| |_| \__,_|_| |_|\__|_|_| |_| |_|\___|
|
|
%%
|
|
%% hProlog CHR runtime:
|
|
%%
|
|
%% * based on the SICStus CHR runtime by Christian Holzbaur
|
|
%%
|
|
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%% % Constraint Handling Rules version 2.2 %
|
|
%% % %
|
|
%% % (c) Copyright 1996-98 %
|
|
%% % LMU, Muenchen %
|
|
%% % %
|
|
%% % File: chr.pl %
|
|
%% % Author: Christian Holzbaur christian@ai.univie.ac.at %
|
|
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%%
|
|
%%
|
|
%% * modified by Tom Schrijvers, K.U.Leuven, Tom.Schrijvers@cs.kuleuven.be
|
|
%% - ported to hProlog
|
|
%% - modified for eager suspension removal
|
|
%%
|
|
%% * First working version: 6 June 2003
|
|
%%
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%% SWI-Prolog changes
|
|
%%
|
|
%% * Added initialization directives for saved-states
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
%% @addtogroup CHR_Rule_Types Rule Types
|
|
%% @ingroup CHR
|
|
%
|
|
% CHR controlling the compiler
|
|
%
|
|
:- module(chr_runtime,
|
|
[ 'chr sbag_del_element'/3,
|
|
'chr sbag_member'/2,
|
|
'chr merge_attributes'/3,
|
|
|
|
'chr run_suspensions'/1,
|
|
'chr run_suspensions_loop'/1,
|
|
|
|
'chr run_suspensions_d'/1,
|
|
'chr run_suspensions_loop_d'/1,
|
|
|
|
'chr insert_constraint_internal'/5,
|
|
'chr remove_constraint_internal'/2,
|
|
'chr allocate_constraint'/4,
|
|
'chr activate_constraint'/3,
|
|
|
|
'chr default_store'/1,
|
|
|
|
'chr via_1'/2,
|
|
'chr via_2'/3,
|
|
'chr via'/2,
|
|
'chr newvia_1'/2,
|
|
'chr newvia_2'/3,
|
|
'chr newvia'/2,
|
|
|
|
'chr lock'/1,
|
|
'chr unlock'/1,
|
|
'chr not_locked'/1,
|
|
'chr none_locked'/1,
|
|
|
|
'chr error_lock'/1,
|
|
'chr unerror_lock'/1,
|
|
'chr not_error_locked'/1,
|
|
'chr none_error_locked'/1,
|
|
|
|
'chr update_mutable'/2,
|
|
'chr get_mutable'/2,
|
|
'chr create_mutable'/2,
|
|
|
|
'chr novel_production'/2,
|
|
'chr extend_history'/2,
|
|
'chr empty_history'/1,
|
|
|
|
'chr gen_id'/1,
|
|
|
|
'chr debug_event'/1,
|
|
'chr debug command'/2, % Char, Command
|
|
|
|
'chr chr_indexed_variables'/2,
|
|
|
|
'chr all_suspensions'/3,
|
|
'chr new_merge_attributes'/3,
|
|
'chr normalize_attr'/2,
|
|
|
|
'chr select'/3,
|
|
|
|
chr_show_store/1, % +Module
|
|
find_chr_constraint/1,
|
|
|
|
chr_trace/0,
|
|
chr_notrace/0,
|
|
chr_leash/1
|
|
]).
|
|
|
|
%% SWI begin
|
|
:- set_prolog_flag(generate_debug_info, false).
|
|
%% SWI end
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
:- use_module(library(dialect/hprolog)).
|
|
:- include(chr_op).
|
|
|
|
%% SICStus begin
|
|
%% :- use_module(hpattvars).
|
|
%% :- use_module(b_globval).
|
|
%% SICStus end
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
% I N I T I A L I S A T I O N
|
|
|
|
%% SWI begin
|
|
:- dynamic user:exception/3.
|
|
:- multifile user:exception/3.
|
|
|
|
user:exception(undefined_global_variable, Name, retry) :-
|
|
chr_runtime_global_variable(Name),
|
|
chr_init.
|
|
|
|
chr_runtime_global_variable(chr_id).
|
|
chr_runtime_global_variable(chr_global).
|
|
chr_runtime_global_variable(chr_debug).
|
|
chr_runtime_global_variable(chr_debug_history).
|
|
|
|
chr_init :-
|
|
nb_setval(chr_id,0),
|
|
nb_setval(chr_global,_),
|
|
nb_setval(chr_debug,mutable(off)), % XXX
|
|
nb_setval(chr_debug_history,mutable([],0)). % XXX
|
|
%% SWI end
|
|
|
|
%% SICStus begin
|
|
%% chr_init :-
|
|
%% nb_setval(chr_id,0).
|
|
%% SICStus end
|
|
|
|
:- initialization chr_init.
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Contents of former chr_debug.pl
|
|
%
|
|
% chr_show_store(+Module)
|
|
%
|
|
% Prints all suspended constraints of module Mod to the standard
|
|
% output.
|
|
|
|
chr_show_store(Mod) :-
|
|
(
|
|
Mod:'$enumerate_constraints'(Constraint),
|
|
print(Constraint),nl, % allows use of portray to control printing
|
|
fail
|
|
;
|
|
true
|
|
).
|
|
|
|
find_chr_constraint(Constraint) :-
|
|
chr:'$chr_module'(Mod),
|
|
Mod:'$enumerate_constraints'(Constraint).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Inlining of some goals is good for performance
|
|
% That's the reason for the next section
|
|
% There must be correspondence with the predicates as implemented in chr_mutable.pl
|
|
% so that user:goal_expansion(G,G). also works (but do not add such a rule)
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
%% SWI begin
|
|
:- multifile user:goal_expansion/2.
|
|
:- dynamic user:goal_expansion/2.
|
|
|
|
user:goal_expansion('chr get_mutable'(Val,Var), Var=mutable(Val)).
|
|
user:goal_expansion('chr update_mutable'(Val,Var), setarg(1,Var,Val)).
|
|
user:goal_expansion('chr create_mutable'(Val,Var), Var=mutable(Val)).
|
|
user:goal_expansion('chr default_store'(X), nb_getval(chr_global,X)).
|
|
%% SWI end
|
|
|
|
% goal_expansion seems too different in SICStus 4 for me to cater for in a
|
|
% decent way at this moment - so I stick with the old way to do this
|
|
% so that it doesn't get lost, the code from Mats for SICStus 4 is included in comments
|
|
|
|
|
|
%% Mats begin
|
|
%% goal_expansion('chr get_mutable'(Val,Var), Lay, _M, get_mutable(Val,Var), Lay).
|
|
%% goal_expansion('chr update_mutable'(Val,Var), Lay, _M, update_mutable(Val,Var), Lay).
|
|
%% goal_expansion('chr create_mutable'(Val,Var), Lay, _M, create_mutable(Val,Var), Lay).
|
|
%% goal_expansion('chr default_store'(A), Lay, _M, global_term_ref_1(A), Lay).
|
|
%% Mats begin
|
|
|
|
|
|
%% SICStus begin
|
|
%% :- multifile user:goal_expansion/2.
|
|
%% :- dynamic user:goal_expansion/2.
|
|
%%
|
|
%% user:goal_expansion('chr get_mutable'(Val,Var), get_mutable(Val,Var)).
|
|
%% user:goal_expansion('chr update_mutable'(Val,Var), update_mutable(Val,Var)).
|
|
%% user:goal_expansion('chr create_mutable'(Val,Var), create_mutable(Val,Var)).
|
|
%% user:goal_expansion('chr default_store'(A), global_term_ref_1(A)).
|
|
%% SICStus end
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr run_suspensions'( Slots) :-
|
|
run_suspensions( Slots).
|
|
|
|
'chr run_suspensions_loop'([]).
|
|
'chr run_suspensions_loop'([L|Ls]) :-
|
|
run_suspensions(L),
|
|
'chr run_suspensions_loop'(Ls).
|
|
|
|
run_suspensions([]).
|
|
run_suspensions([S|Next] ) :-
|
|
arg( 2, S, Mref), % ARGXXX
|
|
'chr get_mutable'( Status, Mref),
|
|
( Status==active ->
|
|
'chr update_mutable'( triggered, Mref),
|
|
arg( 4, S, Gref), % ARGXXX
|
|
'chr get_mutable'( Gen, Gref),
|
|
Generation is Gen+1,
|
|
'chr update_mutable'( Generation, Gref),
|
|
arg( 3, S, Goal), % ARGXXX
|
|
call( Goal),
|
|
'chr get_mutable'( Post, Mref),
|
|
( Post==triggered ->
|
|
'chr update_mutable'( active, Mref) % catching constraints that did not do anything
|
|
;
|
|
true
|
|
)
|
|
;
|
|
true
|
|
),
|
|
run_suspensions( Next).
|
|
|
|
'chr run_suspensions_d'( Slots) :-
|
|
run_suspensions_d( Slots).
|
|
|
|
'chr run_suspensions_loop_d'([]).
|
|
'chr run_suspensions_loop_d'([L|Ls]) :-
|
|
run_suspensions_d(L),
|
|
'chr run_suspensions_loop_d'(Ls).
|
|
|
|
run_suspensions_d([]).
|
|
run_suspensions_d([S|Next] ) :-
|
|
arg( 2, S, Mref), % ARGXXX
|
|
'chr get_mutable'( Status, Mref),
|
|
( Status==active ->
|
|
'chr update_mutable'( triggered, Mref),
|
|
arg( 4, S, Gref), % ARGXXX
|
|
'chr get_mutable'( Gen, Gref),
|
|
Generation is Gen+1,
|
|
'chr update_mutable'( Generation, Gref),
|
|
arg( 3, S, Goal), % ARGXXX
|
|
(
|
|
'chr debug_event'(wake(S)),
|
|
call( Goal)
|
|
;
|
|
'chr debug_event'(fail(S)), !,
|
|
fail
|
|
),
|
|
(
|
|
'chr debug_event'(exit(S))
|
|
;
|
|
'chr debug_event'(redo(S)),
|
|
fail
|
|
),
|
|
'chr get_mutable'( Post, Mref),
|
|
( Post==triggered ->
|
|
'chr update_mutable'( active, Mref) % catching constraints that did not do anything
|
|
;
|
|
true
|
|
)
|
|
;
|
|
true
|
|
),
|
|
run_suspensions_d( Next).
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% L O C K I N G
|
|
%
|
|
% locking of variables in guards
|
|
|
|
%= IMPLEMENTATION 1: SILENT FAILURE ============================================
|
|
|
|
%- attribute handler -----------------------------------------------------------
|
|
% intercepts unification of locked variable unification
|
|
|
|
locked:attr_unify_hook(_,_) :- fail.
|
|
|
|
%- locking & unlocking ---------------------------------------------------------
|
|
'chr lock'(T) :-
|
|
( var(T)
|
|
-> put_attr(T, locked, x)
|
|
; term_variables(T,L),
|
|
lockv(L)
|
|
).
|
|
|
|
lockv([]).
|
|
lockv([T|R]) :- put_attr( T, locked, x), lockv(R).
|
|
|
|
'chr unlock'(T) :-
|
|
( var(T)
|
|
-> del_attr(T, locked)
|
|
; term_variables(T,L),
|
|
unlockv(L)
|
|
).
|
|
|
|
unlockv([]).
|
|
unlockv([T|R]) :- del_attr( T, locked), unlockv(R).
|
|
|
|
%- checking for locks ----------------------------------------------------------
|
|
|
|
'chr none_locked'( []).
|
|
'chr none_locked'( [V|Vs]) :-
|
|
( get_attr(V, locked, _) ->
|
|
fail
|
|
;
|
|
'chr none_locked'(Vs)
|
|
).
|
|
|
|
'chr not_locked'(V) :-
|
|
( var( V) ->
|
|
( get_attr( V, locked, _) ->
|
|
fail
|
|
;
|
|
true
|
|
)
|
|
;
|
|
true
|
|
).
|
|
|
|
%= IMPLEMENTATION 2: EXPLICT EXCEPTION =========================================
|
|
|
|
%- LOCK ERROR MESSAGE ----------------------------------------------------------
|
|
lock_error(Term) :-
|
|
throw(error(instantation_error(Term),context(_,'CHR Runtime Error: unification in guard not allowed!'))).
|
|
|
|
%- attribute handler -----------------------------------------------------------
|
|
% intercepts unification of locked variable unification
|
|
|
|
error_locked:attr_unify_hook(_,Term) :- lock_error(Term).
|
|
|
|
%- locking & unlocking ---------------------------------------------------------
|
|
'chr error_lock'(T) :-
|
|
( var(T)
|
|
-> put_attr(T, error_locked, x)
|
|
; term_variables(T,L),
|
|
error_lockv(L)
|
|
).
|
|
|
|
error_lockv([]).
|
|
error_lockv([T|R]) :- put_attr( T, error_locked, x), error_lockv(R).
|
|
|
|
'chr unerror_lock'(T) :-
|
|
( var(T)
|
|
-> del_attr(T, error_locked)
|
|
; term_variables(T,L),
|
|
unerror_lockv(L)
|
|
).
|
|
|
|
unerror_lockv([]).
|
|
unerror_lockv([T|R]) :- del_attr( T, error_locked), unerror_lockv(R).
|
|
|
|
%- checking for locks ----------------------------------------------------------
|
|
|
|
'chr none_error_locked'( []).
|
|
'chr none_error_locked'( [V|Vs]) :-
|
|
( get_attr(V, error_locked, _) ->
|
|
fail
|
|
;
|
|
'chr none_error_locked'(Vs)
|
|
).
|
|
|
|
'chr not_error_locked'(V) :-
|
|
( var( V) ->
|
|
( get_attr( V, error_locked, _) ->
|
|
fail
|
|
;
|
|
true
|
|
)
|
|
;
|
|
true
|
|
).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%
|
|
% Eager removal from all chains.
|
|
%
|
|
'chr remove_constraint_internal'( Susp, Agenda) :-
|
|
arg( 2, Susp, Mref), % ARGXXX
|
|
'chr get_mutable'( State, Mref),
|
|
'chr update_mutable'( removed, Mref), % mark in any case
|
|
( compound(State) -> % passive/1
|
|
Agenda = []
|
|
; State==removed ->
|
|
Agenda = []
|
|
%; State==triggered ->
|
|
% Agenda = []
|
|
;
|
|
Susp =.. [_,_,_,_,_,_,_|Args],
|
|
term_variables( Args, Vars),
|
|
'chr default_store'( Global),
|
|
Agenda = [Global|Vars]
|
|
).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr newvia_1'(X,V) :-
|
|
( var(X) ->
|
|
X = V
|
|
;
|
|
nonground(X,V)
|
|
).
|
|
|
|
'chr newvia_2'(X,Y,V) :-
|
|
( var(X) ->
|
|
X = V
|
|
; var(Y) ->
|
|
Y = V
|
|
; compound(X), nonground(X,V) ->
|
|
true
|
|
;
|
|
compound(Y), nonground(Y,V)
|
|
).
|
|
|
|
%
|
|
% The second arg is a witness.
|
|
% The formulation with term_variables/2 is
|
|
% cycle safe, but it finds a list of all vars.
|
|
% We need only one, and no list in particular.
|
|
%
|
|
'chr newvia'(L,V) :- nonground(L,V).
|
|
%~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
|
|
|
|
'chr via_1'(X,V) :-
|
|
( var(X) ->
|
|
X = V
|
|
; atomic(X) ->
|
|
'chr default_store'(V)
|
|
; nonground(X,V) ->
|
|
true
|
|
;
|
|
'chr default_store'(V)
|
|
).
|
|
|
|
'chr via_2'(X,Y,V) :-
|
|
( var(X) ->
|
|
X = V
|
|
; var(Y) ->
|
|
Y = V
|
|
; compound(X), nonground(X,V) ->
|
|
true
|
|
; compound(Y), nonground(Y,V) ->
|
|
true
|
|
;
|
|
'chr default_store'(V)
|
|
).
|
|
|
|
%
|
|
% The second arg is a witness.
|
|
% The formulation with term_variables/2 is
|
|
% cycle safe, but it finds a list of all vars.
|
|
% We need only one, and no list in particular.
|
|
%
|
|
'chr via'(L,V) :-
|
|
( nonground(L,V) ->
|
|
true
|
|
;
|
|
'chr default_store'(V)
|
|
).
|
|
|
|
nonground( Term, V) :-
|
|
term_variables( Term, Vs),
|
|
Vs = [V|_].
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr novel_production'( Self, Tuple) :-
|
|
arg( 5, Self, Ref), % ARGXXX
|
|
'chr get_mutable'( History, Ref),
|
|
( get_ds( Tuple, History, _) ->
|
|
fail
|
|
;
|
|
true
|
|
).
|
|
|
|
%
|
|
% Not folded with novel_production/2 because guard checking
|
|
% goes in between the two calls.
|
|
%
|
|
'chr extend_history'( Self, Tuple) :-
|
|
arg( 5, Self, Ref), % ARGXXX
|
|
'chr get_mutable'( History, Ref),
|
|
put_ds( Tuple, History, x, NewHistory),
|
|
'chr update_mutable'( NewHistory, Ref).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr allocate_constraint'( Closure, Self, F, Args) :-
|
|
Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
|
|
'chr create_mutable'(0, Gref),
|
|
'chr empty_history'(History),
|
|
'chr create_mutable'(History, Href),
|
|
'chr create_mutable'(passive(Args), Mref),
|
|
'chr gen_id'( Id).
|
|
|
|
%
|
|
% 'chr activate_constraint'( -, +, -).
|
|
%
|
|
% The transition gc->active should be rare
|
|
%
|
|
'chr activate_constraint'( Vars, Susp, Generation) :-
|
|
arg( 2, Susp, Mref), % ARGXXX
|
|
'chr get_mutable'( State, Mref),
|
|
'chr update_mutable'( active, Mref),
|
|
( nonvar(Generation) -> % aih
|
|
true
|
|
;
|
|
arg( 4, Susp, Gref), % ARGXXX
|
|
'chr get_mutable'( Gen, Gref),
|
|
Generation is Gen+1,
|
|
'chr update_mutable'( Generation, Gref)
|
|
),
|
|
( compound(State) -> % passive/1
|
|
term_variables( State, Vs),
|
|
'chr none_locked'( Vs),
|
|
Vars = [Global|Vs],
|
|
'chr default_store'(Global)
|
|
; State == removed -> % the price for eager removal ...
|
|
Susp =.. [_,_,_,_,_,_,_|Args],
|
|
term_variables( Args, Vs),
|
|
Vars = [Global|Vs],
|
|
'chr default_store'(Global)
|
|
;
|
|
Vars = []
|
|
).
|
|
|
|
'chr insert_constraint_internal'([Global|Vars], Self, Closure, F, Args) :-
|
|
'chr default_store'(Global),
|
|
term_variables(Args,Vars),
|
|
'chr none_locked'(Vars),
|
|
Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
|
|
'chr create_mutable'(active, Mref),
|
|
'chr create_mutable'(0, Gref),
|
|
'chr empty_history'(History),
|
|
'chr create_mutable'(History, Href),
|
|
'chr gen_id'(Id).
|
|
|
|
insert_constraint_internal([Global|Vars], Self, Term, Closure, F, Args) :-
|
|
'chr default_store'(Global),
|
|
term_variables( Term, Vars),
|
|
'chr none_locked'( Vars),
|
|
'chr empty_history'( History),
|
|
'chr create_mutable'( active, Mref),
|
|
'chr create_mutable'( 0, Gref),
|
|
'chr create_mutable'( History, Href),
|
|
'chr gen_id'( Id),
|
|
Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args]. % SUSPXXX
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr empty_history'( E) :- empty_ds( E).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr gen_id'( Id) :-
|
|
nb_getval(chr_id,Id),
|
|
NextId is Id + 1,
|
|
nb_setval(chr_id,NextId).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
%% SWI begin
|
|
'chr create_mutable'(V,mutable(V)).
|
|
'chr get_mutable'(V,mutable(V)).
|
|
'chr update_mutable'(V,M) :- setarg(1,M,V).
|
|
%% SWI end
|
|
|
|
%% SICStus begin
|
|
%% 'chr create_mutable'(Val, Mut) :- create_mutable(Val, Mut).
|
|
%% 'chr get_mutable'(Val, Mut) :- get_mutable(Val, Mut).
|
|
%% 'chr update_mutable'(Val, Mut) :- update_mutable(Val, Mut).
|
|
%% SICStus end
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
%% SWI begin
|
|
'chr default_store'(X) :- nb_getval(chr_global,X).
|
|
%% SWI end
|
|
|
|
%% SICStus begin
|
|
%% 'chr default_store'(A) :- global_term_ref_1(A).
|
|
%% SICStus end
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
'chr sbag_member'( Element, [Head|Tail]) :-
|
|
sbag_member( Element, Tail, Head).
|
|
|
|
% auxiliary to avoid choicepoint for last element
|
|
% does it really avoid the choicepoint? -jon
|
|
sbag_member( E, _, E).
|
|
sbag_member( E, [Head|Tail], _) :-
|
|
sbag_member( E, Tail, Head).
|
|
|
|
'chr sbag_del_element'( [], _, []).
|
|
'chr sbag_del_element'( [X|Xs], Elem, Set2) :-
|
|
( X==Elem ->
|
|
Set2 = Xs
|
|
;
|
|
Set2 = [X|Xss],
|
|
'chr sbag_del_element'( Xs, Elem, Xss)
|
|
).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
'chr merge_attributes'([],Ys,Ys).
|
|
'chr merge_attributes'([X | Xs],YL,R) :-
|
|
( YL = [Y | Ys] ->
|
|
arg(1,X,XId), % ARGXXX
|
|
arg(1,Y,YId), % ARGXXX
|
|
( XId < YId ->
|
|
R = [X | T],
|
|
'chr merge_attributes'(Xs,YL,T)
|
|
; XId > YId ->
|
|
R = [Y | T],
|
|
'chr merge_attributes'([X|Xs],Ys,T)
|
|
;
|
|
R = [X | T],
|
|
'chr merge_attributes'(Xs,Ys,T)
|
|
)
|
|
;
|
|
R = [X | Xs]
|
|
).
|
|
|
|
'chr new_merge_attributes'([],A2,A) :-
|
|
A = A2.
|
|
'chr new_merge_attributes'([E1|AT1],A2,A) :-
|
|
( A2 = [E2|AT2] ->
|
|
'chr new_merge_attributes'(E1,E2,AT1,AT2,A)
|
|
;
|
|
A = [E1|AT1]
|
|
).
|
|
|
|
'chr new_merge_attributes'(Pos1-L1,Pos2-L2,AT1,AT2,A) :-
|
|
( Pos1 < Pos2 ->
|
|
A = [Pos1-L1|AT],
|
|
'chr new_merge_attributes'(AT1,[Pos2-L2|AT2],AT)
|
|
; Pos1 > Pos2 ->
|
|
A = [Pos2-L2|AT],
|
|
'chr new_merge_attributes'([Pos1-L1|AT1],AT2,AT)
|
|
;
|
|
'chr merge_attributes'(L1,L2,L),
|
|
A = [Pos1-L|AT],
|
|
'chr new_merge_attributes'(AT1,AT2,AT)
|
|
).
|
|
|
|
'chr all_suspensions'([],_,_).
|
|
'chr all_suspensions'([Susps|SuspsList],Pos,Attr) :-
|
|
all_suspensions(Attr,Susps,SuspsList,Pos).
|
|
|
|
all_suspensions([],[],SuspsList,Pos) :-
|
|
all_suspensions([],[],SuspsList,Pos). % all empty lists
|
|
all_suspensions([APos-ASusps|RAttr],Susps,SuspsList,Pos) :-
|
|
NPos is Pos + 1,
|
|
( Pos == APos ->
|
|
Susps = ASusps,
|
|
'chr all_suspensions'(SuspsList,NPos,RAttr)
|
|
;
|
|
Susps = [],
|
|
'chr all_suspensions'(SuspsList,NPos,[APos-ASusps|RAttr])
|
|
).
|
|
|
|
'chr normalize_attr'([],[]).
|
|
'chr normalize_attr'([Pos-L|R],[Pos-NL|NR]) :-
|
|
sort(L,NL),
|
|
'chr normalize_attr'(R,NR).
|
|
|
|
'chr select'([E|T],F,R) :-
|
|
( E = F ->
|
|
R = T
|
|
;
|
|
R = [E|NR],
|
|
'chr select'(T,F,NR)
|
|
).
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
:- multifile
|
|
chr:debug_event/2, % +State, +Event
|
|
chr:debug_interact/3. % +Event, +Depth, -Command
|
|
|
|
'chr debug_event'(Event) :-
|
|
nb_getval(chr_debug,mutable(State)), % XXX
|
|
( State == off ->
|
|
true
|
|
; chr:debug_event(State, Event) ->
|
|
true
|
|
; debug_event(State,Event)
|
|
).
|
|
|
|
chr_trace :-
|
|
nb_setval(chr_debug,mutable(trace)).
|
|
chr_notrace :-
|
|
nb_setval(chr_debug,mutable(off)).
|
|
|
|
% chr_leash(+Spec)
|
|
%
|
|
% Define the set of ports at which we prompt for user interaction
|
|
|
|
chr_leash(Spec) :-
|
|
leashed_ports(Spec, Ports),
|
|
nb_setval(chr_leash,mutable(Ports)).
|
|
|
|
leashed_ports(none, []).
|
|
leashed_ports(off, []).
|
|
leashed_ports(all, [call, exit, redo, fail, wake, try, apply, insert, remove]).
|
|
leashed_ports(default, [call,exit,fail,wake,apply]).
|
|
leashed_ports(One, Ports) :-
|
|
atom(One), One \== [], !,
|
|
leashed_ports([One], Ports).
|
|
leashed_ports(Set, Ports) :-
|
|
sort(Set, Ports), % make unique
|
|
leashed_ports(all, All),
|
|
valid_ports(Ports, All).
|
|
|
|
valid_ports([], _).
|
|
valid_ports([H|T], Valid) :-
|
|
( memberchk(H, Valid)
|
|
-> true
|
|
; throw(error(domain_error(chr_port, H), _))
|
|
),
|
|
valid_ports(T, Valid).
|
|
|
|
user:exception(undefined_global_variable, Name, retry) :-
|
|
chr_runtime_debug_global_variable(Name),
|
|
chr_debug_init.
|
|
|
|
chr_runtime_debug_global_variable(chr_leash).
|
|
|
|
chr_debug_init :-
|
|
leashed_ports(default, Ports),
|
|
nb_setval(chr_leash, mutable(Ports)).
|
|
|
|
:- initialization chr_debug_init.
|
|
|
|
% debug_event(+State, +Event)
|
|
|
|
|
|
%debug_event(trace, Event) :-
|
|
% functor(Event, Name, Arity),
|
|
% writeln(Name/Arity), fail.
|
|
debug_event(trace,Event) :-
|
|
Event = call(_), !,
|
|
get_debug_history(History,Depth),
|
|
NDepth is Depth + 1,
|
|
chr_debug_interact(Event,NDepth),
|
|
set_debug_history([Event|History],NDepth).
|
|
debug_event(trace,Event) :-
|
|
Event = wake(_), !,
|
|
get_debug_history(History,Depth),
|
|
NDepth is Depth + 1,
|
|
chr_debug_interact(Event,NDepth),
|
|
set_debug_history([Event|History],NDepth).
|
|
debug_event(trace,Event) :-
|
|
Event = redo(_), !,
|
|
get_debug_history(_History, Depth),
|
|
chr_debug_interact(Event, Depth).
|
|
debug_event(trace,Event) :-
|
|
Event = exit(_),!,
|
|
get_debug_history([_|History],Depth),
|
|
chr_debug_interact(Event,Depth),
|
|
NDepth is Depth - 1,
|
|
set_debug_history(History,NDepth).
|
|
debug_event(trace,Event) :-
|
|
Event = fail(_),!,
|
|
get_debug_history(_,Depth),
|
|
chr_debug_interact(Event,Depth).
|
|
debug_event(trace, Event) :-
|
|
Event = remove(_), !,
|
|
get_debug_history(_,Depth),
|
|
chr_debug_interact(Event, Depth).
|
|
debug_event(trace, Event) :-
|
|
Event = insert(_), !,
|
|
get_debug_history(_,Depth),
|
|
chr_debug_interact(Event, Depth).
|
|
debug_event(trace, Event) :-
|
|
Event = try(_,_,_,_), !,
|
|
get_debug_history(_,Depth),
|
|
chr_debug_interact(Event, Depth).
|
|
debug_event(trace, Event) :-
|
|
Event = apply(_,_,_,_), !,
|
|
get_debug_history(_,Depth),
|
|
chr_debug_interact(Event,Depth).
|
|
|
|
debug_event(skip(_,_),Event) :-
|
|
Event = call(_), !,
|
|
get_debug_history(History,Depth),
|
|
NDepth is Depth + 1,
|
|
set_debug_history([Event|History],NDepth).
|
|
debug_event(skip(_,_),Event) :-
|
|
Event = wake(_), !,
|
|
get_debug_history(History,Depth),
|
|
NDepth is Depth + 1,
|
|
set_debug_history([Event|History],NDepth).
|
|
debug_event(skip(SkipSusp,SkipDepth),Event) :-
|
|
Event = exit(Susp),!,
|
|
get_debug_history([_|History],Depth),
|
|
( SkipDepth == Depth,
|
|
SkipSusp == Susp ->
|
|
set_chr_debug(trace),
|
|
chr_debug_interact(Event,Depth)
|
|
;
|
|
true
|
|
),
|
|
NDepth is Depth - 1,
|
|
set_debug_history(History,NDepth).
|
|
debug_event(skip(_,_),_) :- !,
|
|
true.
|
|
|
|
% chr_debug_interact(+Event, +Depth)
|
|
%
|
|
% Interact with the user on Event that took place at Depth. First
|
|
% calls chr:debug_interact(+Event, +Depth, -Command) hook. If this
|
|
% fails the event is printed and the system prompts for a command.
|
|
|
|
chr_debug_interact(Event, Depth) :-
|
|
chr:debug_interact(Event, Depth, Command), !,
|
|
handle_debug_command(Command,Event,Depth).
|
|
chr_debug_interact(Event, Depth) :-
|
|
print_event(Event, Depth),
|
|
( leashed(Event)
|
|
-> ask_continue(Command)
|
|
; Command = creep
|
|
),
|
|
handle_debug_command(Command,Event,Depth).
|
|
|
|
leashed(Event) :-
|
|
functor(Event, Port, _),
|
|
nb_getval(chr_leash, mutable(Ports)),
|
|
memberchk(Port, Ports).
|
|
|
|
ask_continue(Command) :-
|
|
print_message(trace, chr(prompt)),
|
|
get_single_char(CharCode),
|
|
( CharCode == -1
|
|
-> Char = end_of_file
|
|
; char_code(Char, CharCode)
|
|
),
|
|
( debug_command(Char, Command)
|
|
-> print_message(trace, chr(command(Command)))
|
|
; print_message(help, chr(invalid_command)),
|
|
ask_continue(Command)
|
|
).
|
|
|
|
|
|
'chr debug command'(Char, Command) :-
|
|
debug_command(Char, Command).
|
|
|
|
debug_command(c, creep).
|
|
debug_command(' ', creep).
|
|
debug_command('\r', creep).
|
|
debug_command(s, skip).
|
|
debug_command(g, ancestors).
|
|
debug_command(n, nodebug).
|
|
debug_command(a, abort).
|
|
debug_command(f, fail).
|
|
debug_command(b, break).
|
|
debug_command(?, help).
|
|
debug_command(h, help).
|
|
debug_command(end_of_file, exit).
|
|
|
|
|
|
handle_debug_command(creep,_,_) :- !.
|
|
handle_debug_command(skip, Event, Depth) :- !,
|
|
Event =.. [Type|Rest],
|
|
( Type \== call,
|
|
Type \== wake ->
|
|
handle_debug_command('c',Event,Depth)
|
|
;
|
|
Rest = [Susp],
|
|
set_chr_debug(skip(Susp,Depth))
|
|
).
|
|
|
|
handle_debug_command(ancestors,Event,Depth) :- !,
|
|
print_chr_debug_history,
|
|
chr_debug_interact(Event,Depth).
|
|
handle_debug_command(nodebug,_,_) :- !,
|
|
chr_notrace.
|
|
handle_debug_command(abort,_,_) :- !,
|
|
abort.
|
|
handle_debug_command(exit,_,_) :- !,
|
|
halt.
|
|
handle_debug_command(fail,_,_) :- !,
|
|
fail.
|
|
handle_debug_command(break,Event,Depth) :- !,
|
|
break,
|
|
chr_debug_interact(Event,Depth).
|
|
handle_debug_command(help,Event,Depth) :- !,
|
|
print_message(help, chr(debug_options)),
|
|
chr_debug_interact(Event,Depth).
|
|
handle_debug_command(Cmd, _, _) :-
|
|
throw(error(domain_error(chr_debug_command, Cmd), _)).
|
|
|
|
print_chr_debug_history :-
|
|
get_debug_history(History,Depth),
|
|
print_message(trace, chr(ancestors(History, Depth))).
|
|
|
|
print_event(Event, Depth) :-
|
|
print_message(trace, chr(event(Event, Depth))).
|
|
|
|
% {set,get}_debug_history(Ancestors, Depth)
|
|
%
|
|
% Set/get the list of ancestors and the depth of the current goal.
|
|
|
|
get_debug_history(History,Depth) :-
|
|
nb_getval(chr_debug_history,mutable(History,Depth)).
|
|
|
|
set_debug_history(History,Depth) :-
|
|
nb_getval(chr_debug_history,Mutable),
|
|
setarg(1,Mutable,History),
|
|
setarg(2,Mutable,Depth).
|
|
|
|
set_chr_debug(State) :-
|
|
nb_getval(chr_debug,Mutable),
|
|
setarg(1,Mutable,State).
|
|
|
|
'chr chr_indexed_variables'(Susp,Vars) :-
|
|
Susp =.. [_,_,_,_,_,_,_|Args],
|
|
term_variables(Args,Vars).
|