CHR performance improvements
[chr.git] / chr_runtime.pl
blob7765c920633fc8f8536d884d4d59063d85e34712
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 update_mutable'/2,
102 'chr get_mutable'/2,
103 'chr create_mutable'/2,
105 'chr novel_production'/2,
106 'chr extend_history'/2,
107 'chr empty_history'/1,
109 'chr gen_id'/1,
111 'chr debug_event'/1,
112 'chr debug command'/2, % Char, Command
114 'chr chr_indexed_variables'/2,
116 'chr all_suspensions'/3,
117 'chr new_merge_attributes'/3,
118 'chr normalize_attr'/2,
120 'chr select'/3,
122 chr_show_store/1, % +Module
123 find_chr_constraint/1,
125 chr_trace/0,
126 chr_notrace/0,
127 chr_leash/1
130 %% SWI begin
131 :- set_prolog_flag(generate_debug_info, false).
132 %% SWI end
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
136 :- use_module(hprolog).
137 :- include(chr_op).
139 %% SICStus begin
140 %% :- use_module(hpattvars).
141 %% :- use_module(b_globval).
142 %% SICStus end
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 % I N I T I A L I S A T I O N
149 %% SWI begin
150 :- dynamic user:exception/3.
151 :- multifile user:exception/3.
153 user:exception(undefined_global_variable, Name, retry) :-
154 chr_runtime_global_variable(Name),
155 chr_init.
157 chr_runtime_global_variable(chr_id).
158 chr_runtime_global_variable(chr_global).
159 chr_runtime_global_variable(chr_debug).
160 chr_runtime_global_variable(chr_debug_history).
162 chr_init :-
163 nb_setval(chr_id,0),
164 nb_setval(chr_global,_),
165 nb_setval(chr_debug,mutable(off)), % XXX
166 nb_setval(chr_debug_history,mutable([],0)). % XXX
167 %% SWI end
169 %% SICStus begin
170 %% chr_init :-
171 %% nb_setval(chr_id,0).
172 %% SICStus end
174 :- initialization chr_init.
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178 % Contents of former chr_debug.pl
180 % chr_show_store(+Module)
182 % Prints all suspended constraints of module Mod to the standard
183 % output.
185 chr_show_store(Mod) :-
187 Mod:'$enumerate_constraints'(Constraint),
188 print(Constraint),nl, % allows use of portray to control printing
189 fail
191 true
194 find_chr_constraint(Constraint) :-
195 chr:'$chr_module'(Mod),
196 Mod:'$enumerate_constraints'(Constraint).
198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 % Inlining of some goals is good for performance
200 % That's the reason for the next section
201 % There must be correspondence with the predicates as implemented in chr_mutable.pl
202 % so that user:goal_expansion(G,G). also works (but do not add such a rule)
203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205 %% SWI begin
206 :- multifile user:goal_expansion/2.
207 :- dynamic user:goal_expansion/2.
209 user:goal_expansion('chr get_mutable'(Val,Var), Var=mutable(Val)).
210 user:goal_expansion('chr update_mutable'(Val,Var), setarg(1,Var,Val)).
211 user:goal_expansion('chr create_mutable'(Val,Var), Var=mutable(Val)).
212 user:goal_expansion('chr default_store'(X), nb_getval(chr_global,X)).
213 %% SWI end
215 % goal_expansion seems too different in SICStus 4 for me to cater for in a
216 % decent way at this moment - so I stick with the old way to do this
217 % so that it doesn't get lost, the code from Mats for SICStus 4 is included in comments
220 %% Mats begin
221 %% goal_expansion('chr get_mutable'(Val,Var), Lay, _M, get_mutable(Val,Var), Lay).
222 %% goal_expansion('chr update_mutable'(Val,Var), Lay, _M, update_mutable(Val,Var), Lay).
223 %% goal_expansion('chr create_mutable'(Val,Var), Lay, _M, create_mutable(Val,Var), Lay).
224 %% goal_expansion('chr default_store'(A), Lay, _M, global_term_ref_1(A), Lay).
225 %% Mats begin
228 %% SICStus begin
229 %% :- multifile user:goal_expansion/2.
230 %% :- dynamic user:goal_expansion/2.
232 %% user:goal_expansion('chr get_mutable'(Val,Var), get_mutable(Val,Var)).
233 %% user:goal_expansion('chr update_mutable'(Val,Var), update_mutable(Val,Var)).
234 %% user:goal_expansion('chr create_mutable'(Val,Var), create_mutable(Val,Var)).
235 %% user:goal_expansion('chr default_store'(A), global_term_ref_1(A)).
236 %% SICStus end
239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 'chr run_suspensions'( Slots) :-
241 run_suspensions( Slots).
243 'chr run_suspensions_loop'([]).
244 'chr run_suspensions_loop'([L|Ls]) :-
245 run_suspensions(L),
246 'chr run_suspensions_loop'(Ls).
248 run_suspensions([]).
249 run_suspensions([S|Next] ) :-
250 arg( 2, S, Mref), % ARGXXX
251 'chr get_mutable'( Status, Mref),
252 ( Status==active ->
253 'chr update_mutable'( triggered, Mref),
254 arg( 4, S, Gref), % ARGXXX
255 'chr get_mutable'( Gen, Gref),
256 Generation is Gen+1,
257 'chr update_mutable'( Generation, Gref),
258 arg( 3, S, Goal), % ARGXXX
259 call( Goal),
260 'chr get_mutable'( Post, Mref),
261 ( Post==triggered ->
262 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
264 true
267 true
269 run_suspensions( Next).
271 'chr run_suspensions_d'( Slots) :-
272 run_suspensions_d( Slots).
274 'chr run_suspensions_loop_d'([]).
275 'chr run_suspensions_loop_d'([L|Ls]) :-
276 run_suspensions_d(L),
277 'chr run_suspensions_loop_d'(Ls).
279 run_suspensions_d([]).
280 run_suspensions_d([S|Next] ) :-
281 arg( 2, S, Mref), % ARGXXX
282 'chr get_mutable'( Status, Mref),
283 ( Status==active ->
284 'chr update_mutable'( triggered, Mref),
285 arg( 4, S, Gref), % ARGXXX
286 'chr get_mutable'( Gen, Gref),
287 Generation is Gen+1,
288 'chr update_mutable'( Generation, Gref),
289 arg( 3, S, Goal), % ARGXXX
291 'chr debug_event'(wake(S)),
292 call( Goal)
294 'chr debug_event'(fail(S)), !,
295 fail
298 'chr debug_event'(exit(S))
300 'chr debug_event'(redo(S)),
301 fail
303 'chr get_mutable'( Post, Mref),
304 ( Post==triggered ->
305 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
307 true
310 true
312 run_suspensions_d( Next).
313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314 locked:attr_unify_hook(_,_) :- fail.
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317 'chr lock'(T) :-
318 ( var(T)
319 -> put_attr(T, locked, x)
320 ; term_variables(T,L),
321 lockv(L)
324 lockv([]).
325 lockv([T|R]) :- put_attr( T, locked, x), lockv(R).
327 'chr unlock'(T) :-
328 ( var(T)
329 -> del_attr(T, locked)
330 ; term_variables(T,L),
331 unlockv(L)
334 unlockv([]).
335 unlockv([T|R]) :- del_attr( T, locked), unlockv(R).
337 'chr none_locked'( []).
338 'chr none_locked'( [V|Vs]) :-
339 ( get_attr(V, locked, _) ->
340 fail
342 'chr none_locked'(Vs)
345 'chr not_locked'(V) :-
346 ( var( V) ->
347 ( get_attr( V, locked, _) ->
348 fail
350 true
353 true
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 % Eager removal from all chains.
360 'chr remove_constraint_internal'( Susp, Agenda) :-
361 arg( 2, Susp, Mref), % ARGXXX
362 'chr get_mutable'( State, Mref),
363 'chr update_mutable'( removed, Mref), % mark in any case
364 ( compound(State) -> % passive/1
365 Agenda = []
366 ; State==removed ->
367 Agenda = []
368 %; State==triggered ->
369 % Agenda = []
371 Susp =.. [_,_,_,_,_,_,_|Args],
372 term_variables( Args, Vars),
373 'chr default_store'( Global),
374 Agenda = [Global|Vars]
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 'chr newvia_1'(X,V) :-
379 ( var(X) ->
380 X = V
382 nonground(X,V)
385 'chr newvia_2'(X,Y,V) :-
386 ( var(X) ->
387 X = V
388 ; var(Y) ->
389 Y = V
390 ; compound(X), nonground(X,V) ->
391 true
393 compound(Y), nonground(Y,V)
397 % The second arg is a witness.
398 % The formulation with term_variables/2 is
399 % cycle safe, but it finds a list of all vars.
400 % We need only one, and no list in particular.
402 'chr newvia'(L,V) :- nonground(L,V).
403 %~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
405 'chr via_1'(X,V) :-
406 ( var(X) ->
407 X = V
408 ; atomic(X) ->
409 'chr default_store'(V)
410 ; nonground(X,V) ->
411 true
413 'chr default_store'(V)
416 'chr via_2'(X,Y,V) :-
417 ( var(X) ->
418 X = V
419 ; var(Y) ->
420 Y = V
421 ; compound(X), nonground(X,V) ->
422 true
423 ; compound(Y), nonground(Y,V) ->
424 true
426 'chr default_store'(V)
430 % The second arg is a witness.
431 % The formulation with term_variables/2 is
432 % cycle safe, but it finds a list of all vars.
433 % We need only one, and no list in particular.
435 'chr via'(L,V) :-
436 ( nonground(L,V) ->
437 true
439 'chr default_store'(V)
442 nonground( Term, V) :-
443 term_variables( Term, Vs),
444 Vs = [V|_].
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447 'chr novel_production'( Self, Tuple) :-
448 arg( 5, Self, Ref), % ARGXXX
449 'chr get_mutable'( History, Ref),
450 ( get_ds( Tuple, History, _) ->
451 fail
453 true
457 % Not folded with novel_production/2 because guard checking
458 % goes in between the two calls.
460 'chr extend_history'( Self, Tuple) :-
461 arg( 5, Self, Ref), % ARGXXX
462 'chr get_mutable'( History, Ref),
463 put_ds( Tuple, History, x, NewHistory),
464 'chr update_mutable'( NewHistory, Ref).
466 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 constraint_generation( Susp, State, Generation) :-
468 arg( 2, Susp, Mref), % ARGXXX
469 'chr get_mutable'( State, Mref),
470 arg( 4, Susp, Gref), % ARGXXX
471 'chr get_mutable'( Generation, Gref). % not incremented meanwhile
473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474 'chr allocate_constraint'( Closure, Self, F, Args) :-
475 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
476 'chr create_mutable'(0, Gref),
477 'chr empty_history'(History),
478 'chr create_mutable'(History, Href),
479 'chr create_mutable'(passive(Args), Mref),
480 'chr gen_id'( Id).
483 % 'chr activate_constraint'( -, +, -).
485 % The transition gc->active should be rare
487 'chr activate_constraint'( Vars, Susp, Generation) :-
488 arg( 2, Susp, Mref), % ARGXXX
489 'chr get_mutable'( State, Mref),
490 'chr update_mutable'( active, Mref),
491 ( nonvar(Generation) -> % aih
492 true
494 arg( 4, Susp, Gref), % ARGXXX
495 'chr get_mutable'( Gen, Gref),
496 Generation is Gen+1,
497 'chr update_mutable'( Generation, Gref)
499 ( compound(State) -> % passive/1
500 term_variables( State, Vs),
501 'chr none_locked'( Vs),
502 Vars = [Global|Vs],
503 'chr default_store'(Global)
504 ; State == removed -> % the price for eager removal ...
505 Susp =.. [_,_,_,_,_,_,_|Args],
506 term_variables( Args, Vs),
507 Vars = [Global|Vs],
508 'chr default_store'(Global)
510 Vars = []
513 'chr insert_constraint_internal'([Global|Vars], Self, Closure, F, Args) :-
514 'chr default_store'(Global),
515 term_variables(Args,Vars),
516 'chr none_locked'(Vars),
517 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
518 'chr create_mutable'(active, Mref),
519 'chr create_mutable'(0, Gref),
520 'chr empty_history'(History),
521 'chr create_mutable'(History, Href),
522 'chr gen_id'(Id).
524 insert_constraint_internal([Global|Vars], Self, Term, Closure, F, Args) :-
525 'chr default_store'(Global),
526 term_variables( Term, Vars),
527 'chr none_locked'( Vars),
528 'chr empty_history'( History),
529 'chr create_mutable'( active, Mref),
530 'chr create_mutable'( 0, Gref),
531 'chr create_mutable'( History, Href),
532 'chr gen_id'( Id),
533 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args]. % SUSPXXX
535 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536 'chr empty_history'( E) :- empty_ds( E).
538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 'chr gen_id'( Id) :-
540 nb_getval(chr_id,Id),
541 NextId is Id + 1,
542 nb_setval(chr_id,NextId).
544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
546 %% SWI begin
547 'chr create_mutable'(V,mutable(V)).
548 'chr get_mutable'(V,mutable(V)).
549 'chr update_mutable'(V,M) :- setarg(1,M,V).
550 %% SWI end
552 %% SICStus begin
553 %% 'chr create_mutable'(Val, Mut) :- create_mutable(Val, Mut).
554 %% 'chr get_mutable'(Val, Mut) :- get_mutable(Val, Mut).
555 %% 'chr update_mutable'(Val, Mut) :- update_mutable(Val, Mut).
556 %% SICStus end
559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 %% SWI begin
561 'chr default_store'(X) :- nb_getval(chr_global,X).
562 %% SWI end
564 %% SICStus begin
565 %% 'chr default_store'(A) :- global_term_ref_1(A).
566 %% SICStus end
568 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
570 'chr sbag_member'( Element, [Head|Tail]) :-
571 sbag_member( Element, Tail, Head).
573 % auxiliary to avoid choicepoint for last element
574 % does it really avoid the choicepoint? -jon
575 sbag_member( E, _, E).
576 sbag_member( E, [Head|Tail], _) :-
577 sbag_member( E, Tail, Head).
579 'chr sbag_del_element'( [], _, []).
580 'chr sbag_del_element'( [X|Xs], Elem, Set2) :-
581 ( X==Elem ->
582 Set2 = Xs
584 Set2 = [X|Xss],
585 'chr sbag_del_element'( Xs, Elem, Xss)
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
589 'chr merge_attributes'([],Ys,Ys).
590 'chr merge_attributes'([X | Xs],YL,R) :-
591 ( YL = [Y | Ys] ->
592 arg(1,X,XId), % ARGXXX
593 arg(1,Y,YId), % ARGXXX
594 ( XId < YId ->
595 R = [X | T],
596 'chr merge_attributes'(Xs,YL,T)
597 ; XId > YId ->
598 R = [Y | T],
599 'chr merge_attributes'([X|Xs],Ys,T)
601 R = [X | T],
602 'chr merge_attributes'(Xs,Ys,T)
605 R = [X | Xs]
608 'chr new_merge_attributes'([],A2,A) :-
609 A = A2.
610 'chr new_merge_attributes'([E1|AT1],A2,A) :-
611 ( A2 = [E2|AT2] ->
612 'chr new_merge_attributes'(E1,E2,AT1,AT2,A)
614 A = [E1|AT1]
617 'chr new_merge_attributes'(Pos1-L1,Pos2-L2,AT1,AT2,A) :-
618 ( Pos1 < Pos2 ->
619 A = [Pos1-L1|AT],
620 'chr new_merge_attributes'(AT1,[Pos2-L2|AT2],AT)
621 ; Pos1 > Pos2 ->
622 A = [Pos2-L2|AT],
623 'chr new_merge_attributes'([Pos1-L1|AT1],AT2,AT)
625 'chr merge_attributes'(L1,L2,L),
626 A = [Pos1-L|AT],
627 'chr new_merge_attributes'(AT1,AT2,AT)
630 'chr all_suspensions'([],_,_).
631 'chr all_suspensions'([Susps|SuspsList],Pos,Attr) :-
632 all_suspensions(Attr,Susps,SuspsList,Pos).
634 all_suspensions([],[],SuspsList,Pos) :-
635 all_suspensions([],[],SuspsList,Pos). % all empty lists
636 all_suspensions([APos-ASusps|RAttr],Susps,SuspsList,Pos) :-
637 NPos is Pos + 1,
638 ( Pos == APos ->
639 Susps = ASusps,
640 'chr all_suspensions'(SuspsList,NPos,RAttr)
642 Susps = [],
643 'chr all_suspensions'(SuspsList,NPos,[APos-ASusps|RAttr])
646 'chr normalize_attr'([],[]).
647 'chr normalize_attr'([Pos-L|R],[Pos-NL|NR]) :-
648 sort(L,NL),
649 'chr normalize_attr'(R,NR).
651 'chr select'([E|T],F,R) :-
652 ( E = F ->
653 R = T
655 R = [E|NR],
656 'chr select'(T,F,NR)
659 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661 :- multifile
662 chr:debug_event/2, % +State, +Event
663 chr:debug_interact/3. % +Event, +Depth, -Command
665 'chr debug_event'(Event) :-
666 nb_getval(chr_debug,mutable(State)), % XXX
667 ( State == off ->
668 true
669 ; chr:debug_event(State, Event) ->
670 true
671 ; debug_event(State,Event)
674 chr_trace :-
675 nb_setval(chr_debug,mutable(trace)).
676 chr_notrace :-
677 nb_setval(chr_debug,mutable(off)).
679 % chr_leash(+Spec)
681 % Define the set of ports at which we prompt for user interaction
683 chr_leash(Spec) :-
684 leashed_ports(Spec, Ports),
685 nb_setval(chr_leash,mutable(Ports)).
687 leashed_ports(none, []).
688 leashed_ports(off, []).
689 leashed_ports(all, [call, exit, redo, fail, wake, try, apply, insert, remove]).
690 leashed_ports(default, [call,exit,fail,wake,apply]).
691 leashed_ports(One, Ports) :-
692 atom(One), One \== [], !,
693 leashed_ports([One], Ports).
694 leashed_ports(Set, Ports) :-
695 sort(Set, Ports), % make unique
696 leashed_ports(all, All),
697 valid_ports(Ports, All).
699 valid_ports([], _).
700 valid_ports([H|T], Valid) :-
701 ( memberchk(H, Valid)
702 -> true
703 ; throw(error(domain_error(chr_port, H), _))
705 valid_ports(T, Valid).
707 user:exception(undefined_global_variable, Name, retry) :-
708 chr_runtime_debug_global_variable(Name),
709 chr_debug_init.
711 chr_runtime_debug_global_variable(chr_leash).
713 chr_debug_init :-
714 leashed_ports(default, Ports),
715 nb_setval(chr_leash, mutable(Ports)).
717 :- initialization chr_debug_init.
719 % debug_event(+State, +Event)
722 %debug_event(trace, Event) :-
723 % functor(Event, Name, Arity),
724 % writeln(Name/Arity), fail.
725 debug_event(trace,Event) :-
726 Event = call(_), !,
727 get_debug_history(History,Depth),
728 NDepth is Depth + 1,
729 chr_debug_interact(Event,NDepth),
730 set_debug_history([Event|History],NDepth).
731 debug_event(trace,Event) :-
732 Event = wake(_), !,
733 get_debug_history(History,Depth),
734 NDepth is Depth + 1,
735 chr_debug_interact(Event,NDepth),
736 set_debug_history([Event|History],NDepth).
737 debug_event(trace,Event) :-
738 Event = redo(_), !,
739 get_debug_history(_History, Depth),
740 chr_debug_interact(Event, Depth).
741 debug_event(trace,Event) :-
742 Event = exit(_),!,
743 get_debug_history([_|History],Depth),
744 chr_debug_interact(Event,Depth),
745 NDepth is Depth - 1,
746 set_debug_history(History,NDepth).
747 debug_event(trace,Event) :-
748 Event = fail(_),!,
749 get_debug_history(_,Depth),
750 chr_debug_interact(Event,Depth).
751 debug_event(trace, Event) :-
752 Event = remove(_), !,
753 get_debug_history(_,Depth),
754 chr_debug_interact(Event, Depth).
755 debug_event(trace, Event) :-
756 Event = insert(_), !,
757 get_debug_history(_,Depth),
758 chr_debug_interact(Event, Depth).
759 debug_event(trace, Event) :-
760 Event = try(_,_,_,_), !,
761 get_debug_history(_,Depth),
762 chr_debug_interact(Event, Depth).
763 debug_event(trace, Event) :-
764 Event = apply(_,_,_,_), !,
765 get_debug_history(_,Depth),
766 chr_debug_interact(Event,Depth).
768 debug_event(skip(_,_),Event) :-
769 Event = call(_), !,
770 get_debug_history(History,Depth),
771 NDepth is Depth + 1,
772 set_debug_history([Event|History],NDepth).
773 debug_event(skip(_,_),Event) :-
774 Event = wake(_), !,
775 get_debug_history(History,Depth),
776 NDepth is Depth + 1,
777 set_debug_history([Event|History],NDepth).
778 debug_event(skip(SkipSusp,SkipDepth),Event) :-
779 Event = exit(Susp),!,
780 get_debug_history([_|History],Depth),
781 ( SkipDepth == Depth,
782 SkipSusp == Susp ->
783 set_chr_debug(trace),
784 chr_debug_interact(Event,Depth)
786 true
788 NDepth is Depth - 1,
789 set_debug_history(History,NDepth).
790 debug_event(skip(_,_),_) :- !,
791 true.
793 % chr_debug_interact(+Event, +Depth)
795 % Interact with the user on Event that took place at Depth. First
796 % calls chr:debug_interact(+Event, +Depth, -Command) hook. If this
797 % fails the event is printed and the system prompts for a command.
799 chr_debug_interact(Event, Depth) :-
800 chr:debug_interact(Event, Depth, Command), !,
801 handle_debug_command(Command,Event,Depth).
802 chr_debug_interact(Event, Depth) :-
803 print_event(Event, Depth),
804 ( leashed(Event)
805 -> ask_continue(Command)
806 ; Command = creep
808 handle_debug_command(Command,Event,Depth).
810 leashed(Event) :-
811 functor(Event, Port, _),
812 nb_getval(chr_leash, mutable(Ports)),
813 memberchk(Port, Ports).
815 ask_continue(Command) :-
816 print_message(debug, chr(prompt)),
817 get_single_char(CharCode),
818 ( CharCode == -1
819 -> Char = end_of_file
820 ; char_code(Char, CharCode)
822 ( debug_command(Char, Command)
823 -> print_message(debug, chr(command(Command)))
824 ; print_message(help, chr(invalid_command)),
825 ask_continue(Command)
829 'chr debug command'(Char, Command) :-
830 debug_command(Char, Command).
832 debug_command(c, creep).
833 debug_command(' ', creep).
834 debug_command('\r', creep).
835 debug_command(s, skip).
836 debug_command(g, ancestors).
837 debug_command(n, nodebug).
838 debug_command(a, abort).
839 debug_command(f, fail).
840 debug_command(b, break).
841 debug_command(?, help).
842 debug_command(h, help).
843 debug_command(end_of_file, exit).
846 handle_debug_command(creep,_,_) :- !.
847 handle_debug_command(skip, Event, Depth) :- !,
848 Event =.. [Type|Rest],
849 ( Type \== call,
850 Type \== wake ->
851 handle_debug_command('c',Event,Depth)
853 Rest = [Susp],
854 set_chr_debug(skip(Susp,Depth))
857 handle_debug_command(ancestors,Event,Depth) :- !,
858 print_chr_debug_history,
859 chr_debug_interact(Event,Depth).
860 handle_debug_command(nodebug,_,_) :- !,
861 chr_notrace.
862 handle_debug_command(abort,_,_) :- !,
863 abort.
864 handle_debug_command(exit,_,_) :- !,
865 halt.
866 handle_debug_command(fail,_,_) :- !,
867 fail.
868 handle_debug_command(break,Event,Depth) :- !,
869 break,
870 chr_debug_interact(Event,Depth).
871 handle_debug_command(help,Event,Depth) :- !,
872 print_message(help, chr(debug_options)),
873 chr_debug_interact(Event,Depth).
874 handle_debug_command(Cmd, _, _) :-
875 throw(error(domain_error(chr_debug_command, Cmd), _)).
877 print_chr_debug_history :-
878 get_debug_history(History,Depth),
879 print_message(debug, chr(ancestors(History, Depth))).
881 print_event(Event, Depth) :-
882 print_message(debug, chr(event(Event, Depth))).
884 % {set,get}_debug_history(Ancestors, Depth)
886 % Set/get the list of ancestors and the depth of the current goal.
888 get_debug_history(History,Depth) :-
889 nb_getval(chr_debug_history,mutable(History,Depth)).
891 set_debug_history(History,Depth) :-
892 nb_getval(chr_debug_history,Mutable),
893 setarg(1,Mutable,History),
894 setarg(2,Mutable,Depth).
896 set_chr_debug(State) :-
897 nb_getval(chr_debug,Mutable),
898 setarg(1,Mutable,State).
900 'chr chr_indexed_variables'(Susp,Vars) :-
901 Susp =.. [_,_,_,_,_,_,_|Args],
902 term_variables(Args,Vars).