FIX chr_identifier related bugs and performance issues
[chr.git] / chr_runtime.pl
blob9688449c32f96b1d9d00af5f92668272d232620e
1 /* $Id$
3 Part of CHR (Constraint Handling Rules)
5 Author: Christian Holzbaur and Tom Schrijvers
6 E-mail: christian@ai.univie.ac.at
7 Tom.Schrijvers@cs.kuleuven.be
8 WWW: http://www.swi-prolog.org
9 Copyright (C): 2003-2004, K.U. Leuven
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 As a special exception, if you link this library with other files,
26 compiled with a Free Software compiler, to produce an executable, this
27 library does not by itself cause the resulting executable to be covered
28 by the GNU General Public License. This exception does not however
29 invalidate any other reasons why the executable file might be covered by
30 the GNU General Public License.
32 Distributed with SWI-Prolog under the above conditions with
33 permission from the authors.
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 %% _ _ _
39 %% ___| |__ _ __ _ __ _ _ _ __ | |_(_)_ __ ___ ___
40 %% / __| '_ \| '__| | '__| | | | '_ \| __| | '_ ` _ \ / _ \
41 %% | (__| | | | | | | | |_| | | | | |_| | | | | | | __/
42 %% \___|_| |_|_| |_| \__,_|_| |_|\__|_|_| |_| |_|\___|
44 %% hProlog CHR runtime:
46 %% * based on the SICStus CHR runtime by Christian Holzbaur
47 %%
48 %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 %% % Constraint Handling Rules version 2.2 %
50 %% % %
51 %% % (c) Copyright 1996-98 %
52 %% % LMU, Muenchen %
53 %% % %
54 %% % File: chr.pl %
55 %% % Author: Christian Holzbaur christian@ai.univie.ac.at %
56 %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 %%
58 %%
59 %% * modified by Tom Schrijvers, K.U.Leuven, Tom.Schrijvers@cs.kuleuven.be
60 %% - ported to hProlog
61 %% - modified for eager suspension removal
63 %% * First working version: 6 June 2003
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 %% SWI-Prolog changes
67 %%
68 %% * Added initialization directives for saved-states
69 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 :- module(chr_runtime,
72 [ 'chr sbag_del_element'/3,
73 'chr sbag_member'/2,
74 'chr merge_attributes'/3,
76 'chr run_suspensions'/1,
77 'chr run_suspensions_loop'/1,
79 'chr run_suspensions_d'/1,
80 'chr run_suspensions_loop_d'/1,
82 'chr insert_constraint_internal'/5,
83 'chr remove_constraint_internal'/2,
84 'chr allocate_constraint'/4,
85 'chr activate_constraint'/3,
87 'chr default_store'/1,
89 'chr via_1'/2,
90 'chr via_2'/3,
91 'chr via'/2,
92 'chr newvia_1'/2,
93 'chr newvia_2'/3,
94 'chr newvia'/2,
96 'chr lock'/1,
97 'chr unlock'/1,
98 'chr not_locked'/1,
99 'chr none_locked'/1,
101 'chr error_lock'/1,
102 'chr unerror_lock'/1,
103 'chr not_error_locked'/1,
104 'chr none_error_locked'/1,
106 'chr update_mutable'/2,
107 'chr get_mutable'/2,
108 'chr create_mutable'/2,
110 'chr novel_production'/2,
111 'chr extend_history'/2,
112 'chr empty_history'/1,
114 'chr gen_id'/1,
116 'chr debug_event'/1,
117 'chr debug command'/2, % Char, Command
119 'chr chr_indexed_variables'/2,
121 'chr all_suspensions'/3,
122 'chr new_merge_attributes'/3,
123 'chr normalize_attr'/2,
125 'chr select'/3,
127 chr_show_store/1, % +Module
128 find_chr_constraint/1,
130 chr_trace/0,
131 chr_notrace/0,
132 chr_leash/1
135 %% SWI begin
136 :- set_prolog_flag(generate_debug_info, false).
137 %% SWI end
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 :- use_module(hprolog).
142 :- include(chr_op).
144 %% SICStus begin
145 %% :- use_module(hpattvars).
146 %% :- use_module(b_globval).
147 %% SICStus end
150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
152 % I N I T I A L I S A T I O N
154 %% SWI begin
155 :- dynamic user:exception/3.
156 :- multifile user:exception/3.
158 user:exception(undefined_global_variable, Name, retry) :-
159 chr_runtime_global_variable(Name),
160 chr_init.
162 chr_runtime_global_variable(chr_id).
163 chr_runtime_global_variable(chr_global).
164 chr_runtime_global_variable(chr_debug).
165 chr_runtime_global_variable(chr_debug_history).
167 chr_init :-
168 nb_setval(chr_id,0),
169 nb_setval(chr_global,_),
170 nb_setval(chr_debug,mutable(off)), % XXX
171 nb_setval(chr_debug_history,mutable([],0)). % XXX
172 %% SWI end
174 %% SICStus begin
175 %% chr_init :-
176 %% nb_setval(chr_id,0).
177 %% SICStus end
179 :- initialization chr_init.
182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 % Contents of former chr_debug.pl
185 % chr_show_store(+Module)
187 % Prints all suspended constraints of module Mod to the standard
188 % output.
190 chr_show_store(Mod) :-
192 Mod:'$enumerate_constraints'(Constraint),
193 print(Constraint),nl, % allows use of portray to control printing
194 fail
196 true
199 find_chr_constraint(Constraint) :-
200 chr:'$chr_module'(Mod),
201 Mod:'$enumerate_constraints'(Constraint).
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204 % Inlining of some goals is good for performance
205 % That's the reason for the next section
206 % There must be correspondence with the predicates as implemented in chr_mutable.pl
207 % so that user:goal_expansion(G,G). also works (but do not add such a rule)
208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 %% SWI begin
211 :- multifile user:goal_expansion/2.
212 :- dynamic user:goal_expansion/2.
214 user:goal_expansion('chr get_mutable'(Val,Var), Var=mutable(Val)).
215 user:goal_expansion('chr update_mutable'(Val,Var), setarg(1,Var,Val)).
216 user:goal_expansion('chr create_mutable'(Val,Var), Var=mutable(Val)).
217 user:goal_expansion('chr default_store'(X), nb_getval(chr_global,X)).
218 %% SWI end
220 % goal_expansion seems too different in SICStus 4 for me to cater for in a
221 % decent way at this moment - so I stick with the old way to do this
222 % so that it doesn't get lost, the code from Mats for SICStus 4 is included in comments
225 %% Mats begin
226 %% goal_expansion('chr get_mutable'(Val,Var), Lay, _M, get_mutable(Val,Var), Lay).
227 %% goal_expansion('chr update_mutable'(Val,Var), Lay, _M, update_mutable(Val,Var), Lay).
228 %% goal_expansion('chr create_mutable'(Val,Var), Lay, _M, create_mutable(Val,Var), Lay).
229 %% goal_expansion('chr default_store'(A), Lay, _M, global_term_ref_1(A), Lay).
230 %% Mats begin
233 %% SICStus begin
234 %% :- multifile user:goal_expansion/2.
235 %% :- dynamic user:goal_expansion/2.
237 %% user:goal_expansion('chr get_mutable'(Val,Var), get_mutable(Val,Var)).
238 %% user:goal_expansion('chr update_mutable'(Val,Var), update_mutable(Val,Var)).
239 %% user:goal_expansion('chr create_mutable'(Val,Var), create_mutable(Val,Var)).
240 %% user:goal_expansion('chr default_store'(A), global_term_ref_1(A)).
241 %% SICStus end
244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 'chr run_suspensions'( Slots) :-
246 run_suspensions( Slots).
248 'chr run_suspensions_loop'([]).
249 'chr run_suspensions_loop'([L|Ls]) :-
250 run_suspensions(L),
251 'chr run_suspensions_loop'(Ls).
253 run_suspensions([]).
254 run_suspensions([S|Next] ) :-
255 arg( 2, S, Mref), % ARGXXX
256 'chr get_mutable'( Status, Mref),
257 ( Status==active ->
258 'chr update_mutable'( triggered, Mref),
259 arg( 4, S, Gref), % ARGXXX
260 'chr get_mutable'( Gen, Gref),
261 Generation is Gen+1,
262 'chr update_mutable'( Generation, Gref),
263 arg( 3, S, Goal), % ARGXXX
264 call( Goal),
265 'chr get_mutable'( Post, Mref),
266 ( Post==triggered ->
267 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
269 true
272 true
274 run_suspensions( Next).
276 'chr run_suspensions_d'( Slots) :-
277 run_suspensions_d( Slots).
279 'chr run_suspensions_loop_d'([]).
280 'chr run_suspensions_loop_d'([L|Ls]) :-
281 run_suspensions_d(L),
282 'chr run_suspensions_loop_d'(Ls).
284 run_suspensions_d([]).
285 run_suspensions_d([S|Next] ) :-
286 arg( 2, S, Mref), % ARGXXX
287 'chr get_mutable'( Status, Mref),
288 ( Status==active ->
289 'chr update_mutable'( triggered, Mref),
290 arg( 4, S, Gref), % ARGXXX
291 'chr get_mutable'( Gen, Gref),
292 Generation is Gen+1,
293 'chr update_mutable'( Generation, Gref),
294 arg( 3, S, Goal), % ARGXXX
296 'chr debug_event'(wake(S)),
297 call( Goal)
299 'chr debug_event'(fail(S)), !,
300 fail
303 'chr debug_event'(exit(S))
305 'chr debug_event'(redo(S)),
306 fail
308 'chr get_mutable'( Post, Mref),
309 ( Post==triggered ->
310 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
312 true
315 true
317 run_suspensions_d( Next).
318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
319 % L O C K I N G
321 % locking of variables in guards
323 %= IMPLEMENTATION 1: SILENT FAILURE ============================================
325 %- attribute handler -----------------------------------------------------------
326 % intercepts unification of locked variable unification
328 locked:attr_unify_hook(_,_) :- fail.
330 %- locking & unlocking ---------------------------------------------------------
331 'chr lock'(T) :-
332 ( var(T)
333 -> put_attr(T, locked, x)
334 ; term_variables(T,L),
335 lockv(L)
338 lockv([]).
339 lockv([T|R]) :- put_attr( T, locked, x), lockv(R).
341 'chr unlock'(T) :-
342 ( var(T)
343 -> del_attr(T, locked)
344 ; term_variables(T,L),
345 unlockv(L)
348 unlockv([]).
349 unlockv([T|R]) :- del_attr( T, locked), unlockv(R).
351 %- checking for locks ----------------------------------------------------------
353 'chr none_locked'( []).
354 'chr none_locked'( [V|Vs]) :-
355 ( get_attr(V, locked, _) ->
356 fail
358 'chr none_locked'(Vs)
361 'chr not_locked'(V) :-
362 ( var( V) ->
363 ( get_attr( V, locked, _) ->
364 fail
366 true
369 true
372 %= IMPLEMENTATION 2: EXPLICT EXCEPTION =========================================
374 %- LOCK ERROR MESSAGE ----------------------------------------------------------
375 lock_error(Term) :-
376 throw(error(instantation_error(Term),context(_,'CHR Runtime Error: unification in guard not allowed!'))).
378 %- attribute handler -----------------------------------------------------------
379 % intercepts unification of locked variable unification
381 error_locked:attr_unify_hook(_,Term) :- lock_error(Term).
383 %- locking & unlocking ---------------------------------------------------------
384 'chr error_lock'(T) :-
385 ( var(T)
386 -> put_attr(T, error_locked, x)
387 ; term_variables(T,L),
388 error_lockv(L)
391 error_lockv([]).
392 error_lockv([T|R]) :- put_attr( T, error_locked, x), error_lockv(R).
394 'chr unerror_lock'(T) :-
395 ( var(T)
396 -> del_attr(T, error_locked)
397 ; term_variables(T,L),
398 unerror_lockv(L)
401 unerror_lockv([]).
402 unerror_lockv([T|R]) :- del_attr( T, error_locked), unerror_lockv(R).
404 %- checking for locks ----------------------------------------------------------
406 'chr none_error_locked'( []).
407 'chr none_error_locked'( [V|Vs]) :-
408 ( get_attr(V, error_locked, _) ->
409 fail
411 'chr none_error_locked'(Vs)
414 'chr not_error_locked'(V) :-
415 ( var( V) ->
416 ( get_attr( V, error_locked, _) ->
417 fail
419 true
422 true
425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 % Eager removal from all chains.
429 'chr remove_constraint_internal'( Susp, Agenda) :-
430 arg( 2, Susp, Mref), % ARGXXX
431 'chr get_mutable'( State, Mref),
432 'chr update_mutable'( removed, Mref), % mark in any case
433 ( compound(State) -> % passive/1
434 Agenda = []
435 ; State==removed ->
436 Agenda = []
437 %; State==triggered ->
438 % Agenda = []
440 Susp =.. [_,_,_,_,_,_,_|Args],
441 term_variables( Args, Vars),
442 'chr default_store'( Global),
443 Agenda = [Global|Vars]
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447 'chr newvia_1'(X,V) :-
448 ( var(X) ->
449 X = V
451 nonground(X,V)
454 'chr newvia_2'(X,Y,V) :-
455 ( var(X) ->
456 X = V
457 ; var(Y) ->
458 Y = V
459 ; compound(X), nonground(X,V) ->
460 true
462 compound(Y), nonground(Y,V)
466 % The second arg is a witness.
467 % The formulation with term_variables/2 is
468 % cycle safe, but it finds a list of all vars.
469 % We need only one, and no list in particular.
471 'chr newvia'(L,V) :- nonground(L,V).
472 %~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
474 'chr via_1'(X,V) :-
475 ( var(X) ->
476 X = V
477 ; atomic(X) ->
478 'chr default_store'(V)
479 ; nonground(X,V) ->
480 true
482 'chr default_store'(V)
485 'chr via_2'(X,Y,V) :-
486 ( var(X) ->
487 X = V
488 ; var(Y) ->
489 Y = V
490 ; compound(X), nonground(X,V) ->
491 true
492 ; compound(Y), nonground(Y,V) ->
493 true
495 'chr default_store'(V)
499 % The second arg is a witness.
500 % The formulation with term_variables/2 is
501 % cycle safe, but it finds a list of all vars.
502 % We need only one, and no list in particular.
504 'chr via'(L,V) :-
505 ( nonground(L,V) ->
506 true
508 'chr default_store'(V)
511 nonground( Term, V) :-
512 term_variables( Term, Vs),
513 Vs = [V|_].
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
516 'chr novel_production'( Self, Tuple) :-
517 arg( 5, Self, Ref), % ARGXXX
518 'chr get_mutable'( History, Ref),
519 ( get_ds( Tuple, History, _) ->
520 fail
522 true
526 % Not folded with novel_production/2 because guard checking
527 % goes in between the two calls.
529 'chr extend_history'( Self, Tuple) :-
530 arg( 5, Self, Ref), % ARGXXX
531 'chr get_mutable'( History, Ref),
532 put_ds( Tuple, History, x, NewHistory),
533 'chr update_mutable'( NewHistory, Ref).
535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536 constraint_generation( Susp, State, Generation) :-
537 arg( 2, Susp, Mref), % ARGXXX
538 'chr get_mutable'( State, Mref),
539 arg( 4, Susp, Gref), % ARGXXX
540 'chr get_mutable'( Generation, Gref). % not incremented meanwhile
542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
543 'chr allocate_constraint'( Closure, Self, F, Args) :-
544 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
545 'chr create_mutable'(0, Gref),
546 'chr empty_history'(History),
547 'chr create_mutable'(History, Href),
548 'chr create_mutable'(passive(Args), Mref),
549 'chr gen_id'( Id).
552 % 'chr activate_constraint'( -, +, -).
554 % The transition gc->active should be rare
556 'chr activate_constraint'( Vars, Susp, Generation) :-
557 arg( 2, Susp, Mref), % ARGXXX
558 'chr get_mutable'( State, Mref),
559 'chr update_mutable'( active, Mref),
560 ( nonvar(Generation) -> % aih
561 true
563 arg( 4, Susp, Gref), % ARGXXX
564 'chr get_mutable'( Gen, Gref),
565 Generation is Gen+1,
566 'chr update_mutable'( Generation, Gref)
568 ( compound(State) -> % passive/1
569 term_variables( State, Vs),
570 'chr none_locked'( Vs),
571 Vars = [Global|Vs],
572 'chr default_store'(Global)
573 ; State == removed -> % the price for eager removal ...
574 Susp =.. [_,_,_,_,_,_,_|Args],
575 term_variables( Args, Vs),
576 Vars = [Global|Vs],
577 'chr default_store'(Global)
579 Vars = []
582 'chr insert_constraint_internal'([Global|Vars], Self, Closure, F, Args) :-
583 'chr default_store'(Global),
584 term_variables(Args,Vars),
585 'chr none_locked'(Vars),
586 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
587 'chr create_mutable'(active, Mref),
588 'chr create_mutable'(0, Gref),
589 'chr empty_history'(History),
590 'chr create_mutable'(History, Href),
591 'chr gen_id'(Id).
593 insert_constraint_internal([Global|Vars], Self, Term, Closure, F, Args) :-
594 'chr default_store'(Global),
595 term_variables( Term, Vars),
596 'chr none_locked'( Vars),
597 'chr empty_history'( History),
598 'chr create_mutable'( active, Mref),
599 'chr create_mutable'( 0, Gref),
600 'chr create_mutable'( History, Href),
601 'chr gen_id'( Id),
602 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args]. % SUSPXXX
604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 'chr empty_history'( E) :- empty_ds( E).
607 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 'chr gen_id'( Id) :-
609 nb_getval(chr_id,Id),
610 NextId is Id + 1,
611 nb_setval(chr_id,NextId).
613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615 %% SWI begin
616 'chr create_mutable'(V,mutable(V)).
617 'chr get_mutable'(V,mutable(V)).
618 'chr update_mutable'(V,M) :- setarg(1,M,V).
619 %% SWI end
621 %% SICStus begin
622 %% 'chr create_mutable'(Val, Mut) :- create_mutable(Val, Mut).
623 %% 'chr get_mutable'(Val, Mut) :- get_mutable(Val, Mut).
624 %% 'chr update_mutable'(Val, Mut) :- update_mutable(Val, Mut).
625 %% SICStus end
628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 %% SWI begin
630 'chr default_store'(X) :- nb_getval(chr_global,X).
631 %% SWI end
633 %% SICStus begin
634 %% 'chr default_store'(A) :- global_term_ref_1(A).
635 %% SICStus end
637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 'chr sbag_member'( Element, [Head|Tail]) :-
640 sbag_member( Element, Tail, Head).
642 % auxiliary to avoid choicepoint for last element
643 % does it really avoid the choicepoint? -jon
644 sbag_member( E, _, E).
645 sbag_member( E, [Head|Tail], _) :-
646 sbag_member( E, Tail, Head).
648 'chr sbag_del_element'( [], _, []).
649 'chr sbag_del_element'( [X|Xs], Elem, Set2) :-
650 ( X==Elem ->
651 Set2 = Xs
653 Set2 = [X|Xss],
654 'chr sbag_del_element'( Xs, Elem, Xss)
657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
658 'chr merge_attributes'([],Ys,Ys).
659 'chr merge_attributes'([X | Xs],YL,R) :-
660 ( YL = [Y | Ys] ->
661 arg(1,X,XId), % ARGXXX
662 arg(1,Y,YId), % ARGXXX
663 ( XId < YId ->
664 R = [X | T],
665 'chr merge_attributes'(Xs,YL,T)
666 ; XId > YId ->
667 R = [Y | T],
668 'chr merge_attributes'([X|Xs],Ys,T)
670 R = [X | T],
671 'chr merge_attributes'(Xs,Ys,T)
674 R = [X | Xs]
677 'chr new_merge_attributes'([],A2,A) :-
678 A = A2.
679 'chr new_merge_attributes'([E1|AT1],A2,A) :-
680 ( A2 = [E2|AT2] ->
681 'chr new_merge_attributes'(E1,E2,AT1,AT2,A)
683 A = [E1|AT1]
686 'chr new_merge_attributes'(Pos1-L1,Pos2-L2,AT1,AT2,A) :-
687 ( Pos1 < Pos2 ->
688 A = [Pos1-L1|AT],
689 'chr new_merge_attributes'(AT1,[Pos2-L2|AT2],AT)
690 ; Pos1 > Pos2 ->
691 A = [Pos2-L2|AT],
692 'chr new_merge_attributes'([Pos1-L1|AT1],AT2,AT)
694 'chr merge_attributes'(L1,L2,L),
695 A = [Pos1-L|AT],
696 'chr new_merge_attributes'(AT1,AT2,AT)
699 'chr all_suspensions'([],_,_).
700 'chr all_suspensions'([Susps|SuspsList],Pos,Attr) :-
701 all_suspensions(Attr,Susps,SuspsList,Pos).
703 all_suspensions([],[],SuspsList,Pos) :-
704 all_suspensions([],[],SuspsList,Pos). % all empty lists
705 all_suspensions([APos-ASusps|RAttr],Susps,SuspsList,Pos) :-
706 NPos is Pos + 1,
707 ( Pos == APos ->
708 Susps = ASusps,
709 'chr all_suspensions'(SuspsList,NPos,RAttr)
711 Susps = [],
712 'chr all_suspensions'(SuspsList,NPos,[APos-ASusps|RAttr])
715 'chr normalize_attr'([],[]).
716 'chr normalize_attr'([Pos-L|R],[Pos-NL|NR]) :-
717 sort(L,NL),
718 'chr normalize_attr'(R,NR).
720 'chr select'([E|T],F,R) :-
721 ( E = F ->
722 R = T
724 R = [E|NR],
725 'chr select'(T,F,NR)
728 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730 :- multifile
731 chr:debug_event/2, % +State, +Event
732 chr:debug_interact/3. % +Event, +Depth, -Command
734 'chr debug_event'(Event) :-
735 nb_getval(chr_debug,mutable(State)), % XXX
736 ( State == off ->
737 true
738 ; chr:debug_event(State, Event) ->
739 true
740 ; debug_event(State,Event)
743 chr_trace :-
744 nb_setval(chr_debug,mutable(trace)).
745 chr_notrace :-
746 nb_setval(chr_debug,mutable(off)).
748 % chr_leash(+Spec)
750 % Define the set of ports at which we prompt for user interaction
752 chr_leash(Spec) :-
753 leashed_ports(Spec, Ports),
754 nb_setval(chr_leash,mutable(Ports)).
756 leashed_ports(none, []).
757 leashed_ports(off, []).
758 leashed_ports(all, [call, exit, redo, fail, wake, try, apply, insert, remove]).
759 leashed_ports(default, [call,exit,fail,wake,apply]).
760 leashed_ports(One, Ports) :-
761 atom(One), One \== [], !,
762 leashed_ports([One], Ports).
763 leashed_ports(Set, Ports) :-
764 sort(Set, Ports), % make unique
765 leashed_ports(all, All),
766 valid_ports(Ports, All).
768 valid_ports([], _).
769 valid_ports([H|T], Valid) :-
770 ( memberchk(H, Valid)
771 -> true
772 ; throw(error(domain_error(chr_port, H), _))
774 valid_ports(T, Valid).
776 user:exception(undefined_global_variable, Name, retry) :-
777 chr_runtime_debug_global_variable(Name),
778 chr_debug_init.
780 chr_runtime_debug_global_variable(chr_leash).
782 chr_debug_init :-
783 leashed_ports(default, Ports),
784 nb_setval(chr_leash, mutable(Ports)).
786 :- initialization chr_debug_init.
788 % debug_event(+State, +Event)
791 %debug_event(trace, Event) :-
792 % functor(Event, Name, Arity),
793 % writeln(Name/Arity), fail.
794 debug_event(trace,Event) :-
795 Event = call(_), !,
796 get_debug_history(History,Depth),
797 NDepth is Depth + 1,
798 chr_debug_interact(Event,NDepth),
799 set_debug_history([Event|History],NDepth).
800 debug_event(trace,Event) :-
801 Event = wake(_), !,
802 get_debug_history(History,Depth),
803 NDepth is Depth + 1,
804 chr_debug_interact(Event,NDepth),
805 set_debug_history([Event|History],NDepth).
806 debug_event(trace,Event) :-
807 Event = redo(_), !,
808 get_debug_history(_History, Depth),
809 chr_debug_interact(Event, Depth).
810 debug_event(trace,Event) :-
811 Event = exit(_),!,
812 get_debug_history([_|History],Depth),
813 chr_debug_interact(Event,Depth),
814 NDepth is Depth - 1,
815 set_debug_history(History,NDepth).
816 debug_event(trace,Event) :-
817 Event = fail(_),!,
818 get_debug_history(_,Depth),
819 chr_debug_interact(Event,Depth).
820 debug_event(trace, Event) :-
821 Event = remove(_), !,
822 get_debug_history(_,Depth),
823 chr_debug_interact(Event, Depth).
824 debug_event(trace, Event) :-
825 Event = insert(_), !,
826 get_debug_history(_,Depth),
827 chr_debug_interact(Event, Depth).
828 debug_event(trace, Event) :-
829 Event = try(_,_,_,_), !,
830 get_debug_history(_,Depth),
831 chr_debug_interact(Event, Depth).
832 debug_event(trace, Event) :-
833 Event = apply(_,_,_,_), !,
834 get_debug_history(_,Depth),
835 chr_debug_interact(Event,Depth).
837 debug_event(skip(_,_),Event) :-
838 Event = call(_), !,
839 get_debug_history(History,Depth),
840 NDepth is Depth + 1,
841 set_debug_history([Event|History],NDepth).
842 debug_event(skip(_,_),Event) :-
843 Event = wake(_), !,
844 get_debug_history(History,Depth),
845 NDepth is Depth + 1,
846 set_debug_history([Event|History],NDepth).
847 debug_event(skip(SkipSusp,SkipDepth),Event) :-
848 Event = exit(Susp),!,
849 get_debug_history([_|History],Depth),
850 ( SkipDepth == Depth,
851 SkipSusp == Susp ->
852 set_chr_debug(trace),
853 chr_debug_interact(Event,Depth)
855 true
857 NDepth is Depth - 1,
858 set_debug_history(History,NDepth).
859 debug_event(skip(_,_),_) :- !,
860 true.
862 % chr_debug_interact(+Event, +Depth)
864 % Interact with the user on Event that took place at Depth. First
865 % calls chr:debug_interact(+Event, +Depth, -Command) hook. If this
866 % fails the event is printed and the system prompts for a command.
868 chr_debug_interact(Event, Depth) :-
869 chr:debug_interact(Event, Depth, Command), !,
870 handle_debug_command(Command,Event,Depth).
871 chr_debug_interact(Event, Depth) :-
872 print_event(Event, Depth),
873 ( leashed(Event)
874 -> ask_continue(Command)
875 ; Command = creep
877 handle_debug_command(Command,Event,Depth).
879 leashed(Event) :-
880 functor(Event, Port, _),
881 nb_getval(chr_leash, mutable(Ports)),
882 memberchk(Port, Ports).
884 ask_continue(Command) :-
885 print_message(debug, chr(prompt)),
886 get_single_char(CharCode),
887 ( CharCode == -1
888 -> Char = end_of_file
889 ; char_code(Char, CharCode)
891 ( debug_command(Char, Command)
892 -> print_message(debug, chr(command(Command)))
893 ; print_message(help, chr(invalid_command)),
894 ask_continue(Command)
898 'chr debug command'(Char, Command) :-
899 debug_command(Char, Command).
901 debug_command(c, creep).
902 debug_command(' ', creep).
903 debug_command('\r', creep).
904 debug_command(s, skip).
905 debug_command(g, ancestors).
906 debug_command(n, nodebug).
907 debug_command(a, abort).
908 debug_command(f, fail).
909 debug_command(b, break).
910 debug_command(?, help).
911 debug_command(h, help).
912 debug_command(end_of_file, exit).
915 handle_debug_command(creep,_,_) :- !.
916 handle_debug_command(skip, Event, Depth) :- !,
917 Event =.. [Type|Rest],
918 ( Type \== call,
919 Type \== wake ->
920 handle_debug_command('c',Event,Depth)
922 Rest = [Susp],
923 set_chr_debug(skip(Susp,Depth))
926 handle_debug_command(ancestors,Event,Depth) :- !,
927 print_chr_debug_history,
928 chr_debug_interact(Event,Depth).
929 handle_debug_command(nodebug,_,_) :- !,
930 chr_notrace.
931 handle_debug_command(abort,_,_) :- !,
932 abort.
933 handle_debug_command(exit,_,_) :- !,
934 halt.
935 handle_debug_command(fail,_,_) :- !,
936 fail.
937 handle_debug_command(break,Event,Depth) :- !,
938 break,
939 chr_debug_interact(Event,Depth).
940 handle_debug_command(help,Event,Depth) :- !,
941 print_message(help, chr(debug_options)),
942 chr_debug_interact(Event,Depth).
943 handle_debug_command(Cmd, _, _) :-
944 throw(error(domain_error(chr_debug_command, Cmd), _)).
946 print_chr_debug_history :-
947 get_debug_history(History,Depth),
948 print_message(debug, chr(ancestors(History, Depth))).
950 print_event(Event, Depth) :-
951 print_message(debug, chr(event(Event, Depth))).
953 % {set,get}_debug_history(Ancestors, Depth)
955 % Set/get the list of ancestors and the depth of the current goal.
957 get_debug_history(History,Depth) :-
958 nb_getval(chr_debug_history,mutable(History,Depth)).
960 set_debug_history(History,Depth) :-
961 nb_getval(chr_debug_history,Mutable),
962 setarg(1,Mutable,History),
963 setarg(2,Mutable,Depth).
965 set_chr_debug(State) :-
966 nb_getval(chr_debug,Mutable),
967 setarg(1,Mutable,State).
969 'chr chr_indexed_variables'(Susp,Vars) :-
970 Susp =.. [_,_,_,_,_,_,_|Args],
971 term_variables(Args,Vars).