* Fix some Win32 compatibility issues
[chr.git] / chr_runtime.pl
blob78c5eba4c86e7d5bd08656108fc69080c77a8664
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_show_store/1, % +Module
117 find_chr_constraint/1,
119 chr_trace/0,
120 chr_notrace/0,
121 chr_leash/1
124 %% SWI begin
125 :- set_prolog_flag(generate_debug_info, false).
126 %% SWI end
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 :- use_module(hprolog).
131 :- include(chr_op).
133 %% SICStus begin
134 %% :- use_module(hpattvars).
135 %% :- use_module(b_globval).
136 %% SICStus end
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 % I N I T I A L I S A T I O N
143 %% SWI begin
144 :- dynamic user:exception/3.
145 :- multifile user:exception/3.
147 user:exception(undefined_global_variable, Name, retry) :-
148 chr_runtime_global_variable(Name),
149 chr_init.
151 chr_runtime_global_variable(chr_id).
152 chr_runtime_global_variable(chr_global).
153 chr_runtime_global_variable(chr_debug).
154 chr_runtime_global_variable(chr_debug_history).
156 chr_init :-
157 nb_setval(chr_id,0),
158 nb_setval(chr_global,_),
159 nb_setval(chr_debug,mutable(off)), % XXX
160 nb_setval(chr_debug_history,mutable([],0)). % XXX
161 %% SWI end
163 %% SICStus begin
164 %% chr_init :-
165 %% nb_setval(chr_id,0).
166 %% SICStus end
168 :- initialization chr_init.
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 % Contents of former chr_debug.pl
174 % chr_show_store(+Module)
176 % Prints all suspended constraints of module Mod to the standard
177 % output.
179 chr_show_store(Mod) :-
181 Mod:'$enumerate_constraints'(Constraint),
182 print(Constraint),nl, % allows use of portray to control printing
183 fail
185 true
188 find_chr_constraint(Constraint) :-
189 chr:'$chr_module'(Mod),
190 Mod:'$enumerate_constraints'(Constraint).
192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
193 % Inlining of some goals is good for performance
194 % That's the reason for the next section
195 % There must be correspondence with the predicates as implemented in chr_mutable.pl
196 % so that user:goal_expansion(G,G). also works (but do not add such a rule)
197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 %% SWI begin
200 :- multifile user:goal_expansion/2.
201 :- dynamic user:goal_expansion/2.
203 user:goal_expansion('chr get_mutable'(Val,Var), Var=mutable(Val)).
204 user:goal_expansion('chr update_mutable'(Val,Var), setarg(1,Var,Val)).
205 user:goal_expansion('chr create_mutable'(Val,Var), Var=mutable(Val)).
206 user:goal_expansion('chr default_store'(X), nb_getval(chr_global,X)).
207 %% SWI end
209 % goal_expansion seems too different in SICStus 4 for me to cater for in a
210 % decent way at this moment - so I stick with the old way to do this
211 % so that it doesn't get lost, the code from Mats for SICStus 4 is included in comments
214 %% Mats begin
215 %% goal_expansion('chr get_mutable'(Val,Var), Lay, _M, get_mutable(Val,Var), Lay).
216 %% goal_expansion('chr update_mutable'(Val,Var), Lay, _M, update_mutable(Val,Var), Lay).
217 %% goal_expansion('chr create_mutable'(Val,Var), Lay, _M, create_mutable(Val,Var), Lay).
218 %% goal_expansion('chr default_store'(A), Lay, _M, global_term_ref_1(A), Lay).
219 %% Mats begin
222 %% SICStus begin
223 %% :- multifile user:goal_expansion/2.
224 %% :- dynamic user:goal_expansion/2.
226 %% user:goal_expansion('chr get_mutable'(Val,Var), get_mutable(Val,Var)).
227 %% user:goal_expansion('chr update_mutable'(Val,Var), update_mutable(Val,Var)).
228 %% user:goal_expansion('chr create_mutable'(Val,Var), create_mutable(Val,Var)).
229 %% user:goal_expansion('chr default_store'(A), global_term_ref_1(A)).
230 %% SICStus end
233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 'chr run_suspensions'( Slots) :-
235 run_suspensions( Slots).
237 'chr run_suspensions_loop'([]).
238 'chr run_suspensions_loop'([L|Ls]) :-
239 run_suspensions(L),
240 'chr run_suspensions_loop'(Ls).
242 run_suspensions([]).
243 run_suspensions([S|Next] ) :-
244 arg( 2, S, Mref), % ARGXXX
245 'chr get_mutable'( Status, Mref),
246 ( Status==active ->
247 'chr update_mutable'( triggered, Mref),
248 arg( 4, S, Gref), % ARGXXX
249 'chr get_mutable'( Gen, Gref),
250 Generation is Gen+1,
251 'chr update_mutable'( Generation, Gref),
252 arg( 3, S, Goal), % ARGXXX
253 call( Goal),
254 'chr get_mutable'( Post, Mref),
255 ( Post==triggered ->
256 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
258 true
261 true
263 run_suspensions( Next).
265 'chr run_suspensions_d'( Slots) :-
266 run_suspensions_d( Slots).
268 'chr run_suspensions_loop_d'([]).
269 'chr run_suspensions_loop_d'([L|Ls]) :-
270 run_suspensions_d(L),
271 'chr run_suspensions_loop_d'(Ls).
273 run_suspensions_d([]).
274 run_suspensions_d([S|Next] ) :-
275 arg( 2, S, Mref), % ARGXXX
276 'chr get_mutable'( Status, Mref),
277 ( Status==active ->
278 'chr update_mutable'( triggered, Mref),
279 arg( 4, S, Gref), % ARGXXX
280 'chr get_mutable'( Gen, Gref),
281 Generation is Gen+1,
282 'chr update_mutable'( Generation, Gref),
283 arg( 3, S, Goal), % ARGXXX
285 'chr debug_event'(wake(S)),
286 call( Goal)
288 'chr debug_event'(fail(S)), !,
289 fail
292 'chr debug_event'(exit(S))
294 'chr debug_event'(redo(S)),
295 fail
297 'chr get_mutable'( Post, Mref),
298 ( Post==triggered ->
299 'chr update_mutable'( active, Mref) % catching constraints that did not do anything
301 true
304 true
306 run_suspensions_d( Next).
307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308 locked:attr_unify_hook(_,_) :- fail.
310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
311 'chr lock'(T) :-
312 ( var(T)
313 -> put_attr(T, locked, x)
314 ; term_variables(T,L),
315 lockv(L)
318 lockv([]).
319 lockv([T|R]) :- put_attr( T, locked, x), lockv(R).
321 'chr unlock'(T) :-
322 ( var(T)
323 -> del_attr(T, locked)
324 ; term_variables(T,L),
325 unlockv(L)
328 unlockv([]).
329 unlockv([T|R]) :- del_attr( T, locked), unlockv(R).
331 'chr none_locked'( []).
332 'chr none_locked'( [V|Vs]) :-
333 ( get_attr(V, locked, _) ->
334 fail
336 'chr none_locked'(Vs)
339 'chr not_locked'(V) :-
340 ( var( V) ->
341 ( get_attr( V, locked, _) ->
342 fail
344 true
347 true
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 % Eager removal from all chains.
354 'chr remove_constraint_internal'( Susp, Agenda) :-
355 arg( 2, Susp, Mref), % ARGXXX
356 'chr get_mutable'( State, Mref),
357 'chr update_mutable'( removed, Mref), % mark in any case
358 ( compound(State) -> % passive/1
359 Agenda = []
360 ; State==removed ->
361 Agenda = []
362 %; State==triggered ->
363 % Agenda = []
365 Susp =.. [_,_,_,_,_,_,_|Args],
366 term_variables( Args, Vars),
367 'chr default_store'( Global),
368 Agenda = [Global|Vars]
371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
372 'chr newvia_1'(X,V) :-
373 ( var(X) ->
374 X = V
376 nonground(X,V)
379 'chr newvia_2'(X,Y,V) :-
380 ( var(X) ->
381 X = V
382 ; var(Y) ->
383 Y = V
384 ; compound(X), nonground(X,V) ->
385 true
387 compound(Y), nonground(Y,V)
391 % The second arg is a witness.
392 % The formulation with term_variables/2 is
393 % cycle safe, but it finds a list of all vars.
394 % We need only one, and no list in particular.
396 'chr newvia'(L,V) :- nonground(L,V).
397 %~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
399 'chr via_1'(X,V) :-
400 ( var(X) ->
401 X = V
402 ; atomic(X) ->
403 'chr default_store'(V)
404 ; nonground(X,V) ->
405 true
407 'chr default_store'(V)
410 'chr via_2'(X,Y,V) :-
411 ( var(X) ->
412 X = V
413 ; var(Y) ->
414 Y = V
415 ; compound(X), nonground(X,V) ->
416 true
417 ; compound(Y), nonground(Y,V) ->
418 true
420 'chr default_store'(V)
424 % The second arg is a witness.
425 % The formulation with term_variables/2 is
426 % cycle safe, but it finds a list of all vars.
427 % We need only one, and no list in particular.
429 'chr via'(L,V) :-
430 ( nonground(L,V) ->
431 true
433 'chr default_store'(V)
436 nonground( Term, V) :-
437 term_variables( Term, Vs),
438 Vs = [V|_].
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 'chr novel_production'( Self, Tuple) :-
442 arg( 5, Self, Ref), % ARGXXX
443 'chr get_mutable'( History, Ref),
444 ( get_ds( Tuple, History, _) ->
445 fail
447 true
451 % Not folded with novel_production/2 because guard checking
452 % goes in between the two calls.
454 'chr extend_history'( Self, Tuple) :-
455 arg( 5, Self, Ref), % ARGXXX
456 'chr get_mutable'( History, Ref),
457 put_ds( Tuple, History, x, NewHistory),
458 'chr update_mutable'( NewHistory, Ref).
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461 constraint_generation( Susp, State, Generation) :-
462 arg( 2, Susp, Mref), % ARGXXX
463 'chr get_mutable'( State, Mref),
464 arg( 4, Susp, Gref), % ARGXXX
465 'chr get_mutable'( Generation, Gref). % not incremented meanwhile
467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
468 'chr allocate_constraint'( Closure, Self, F, Args) :-
469 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
470 'chr create_mutable'(0, Gref),
471 'chr empty_history'(History),
472 'chr create_mutable'(History, Href),
473 'chr create_mutable'(passive(Args), Mref),
474 'chr gen_id'( Id).
477 % 'chr activate_constraint'( -, +, -).
479 % The transition gc->active should be rare
481 'chr activate_constraint'( Vars, Susp, Generation) :-
482 arg( 2, Susp, Mref), % ARGXXX
483 'chr get_mutable'( State, Mref),
484 'chr update_mutable'( active, Mref),
485 ( nonvar(Generation) -> % aih
486 true
488 arg( 4, Susp, Gref), % ARGXXX
489 'chr get_mutable'( Gen, Gref),
490 Generation is Gen+1,
491 'chr update_mutable'( Generation, Gref)
493 ( compound(State) -> % passive/1
494 term_variables( State, Vs),
495 'chr none_locked'( Vs),
496 Vars = [Global|Vs],
497 'chr default_store'(Global)
498 ; State == removed -> % the price for eager removal ...
499 Susp =.. [_,_,_,_,_,_,_|Args],
500 term_variables( Args, Vs),
501 Vars = [Global|Vs],
502 'chr default_store'(Global)
504 Vars = []
507 'chr insert_constraint_internal'([Global|Vars], Self, Closure, F, Args) :-
508 'chr default_store'(Global),
509 term_variables(Args,Vars),
510 'chr none_locked'(Vars),
511 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], % SUSPXXX
512 'chr create_mutable'(active, Mref),
513 'chr create_mutable'(0, Gref),
514 'chr empty_history'(History),
515 'chr create_mutable'(History, Href),
516 'chr gen_id'(Id).
518 insert_constraint_internal([Global|Vars], Self, Term, Closure, F, Args) :-
519 'chr default_store'(Global),
520 term_variables( Term, Vars),
521 'chr none_locked'( Vars),
522 'chr empty_history'( History),
523 'chr create_mutable'( active, Mref),
524 'chr create_mutable'( 0, Gref),
525 'chr create_mutable'( History, Href),
526 'chr gen_id'( Id),
527 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args]. % SUSPXXX
529 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530 'chr empty_history'( E) :- empty_ds( E).
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 'chr gen_id'( Id) :-
534 nb_getval(chr_id,Id),
535 NextId is Id + 1,
536 nb_setval(chr_id,NextId).
538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540 %% SWI begin
541 'chr create_mutable'(V,mutable(V)).
542 'chr get_mutable'(V,mutable(V)).
543 'chr update_mutable'(V,M) :- setarg(1,M,V).
544 %% SWI end
546 %% SICStus begin
547 %% 'chr create_mutable'(Val, Mut) :- create_mutable(Val, Mut).
548 %% 'chr get_mutable'(Val, Mut) :- get_mutable(Val, Mut).
549 %% 'chr update_mutable'(Val, Mut) :- update_mutable(Val, Mut).
550 %% SICStus end
553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 %% SWI begin
555 'chr default_store'(X) :- nb_getval(chr_global,X).
556 %% SWI end
558 %% SICStus begin
559 %% 'chr default_store'(A) :- global_term_ref_1(A).
560 %% SICStus end
562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564 'chr sbag_member'( Element, [Head|Tail]) :-
565 sbag_member( Element, Tail, Head).
567 % auxiliary to avoid choicepoint for last element
568 % does it really avoid the choicepoint? -jon
569 sbag_member( E, _, E).
570 sbag_member( E, [Head|Tail], _) :-
571 sbag_member( E, Tail, Head).
573 'chr sbag_del_element'( [], _, []).
574 'chr sbag_del_element'( [X|Xs], Elem, Set2) :-
575 ( X==Elem ->
576 Set2 = Xs
578 Set2 = [X|Xss],
579 'chr sbag_del_element'( Xs, Elem, Xss)
582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
583 'chr merge_attributes'([],Ys,Ys).
584 'chr merge_attributes'([X | Xs],YL,R) :-
585 ( YL = [Y | Ys] ->
586 arg(1,X,XId), % ARGXXX
587 arg(1,Y,YId), % ARGXXX
588 ( XId < YId ->
589 R = [X | T],
590 'chr merge_attributes'(Xs,YL,T)
591 ; XId > YId ->
592 R = [Y | T],
593 'chr merge_attributes'([X|Xs],Ys,T)
595 R = [X | T],
596 'chr merge_attributes'(Xs,Ys,T)
599 R = [X | Xs]
602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
604 :- multifile
605 chr:debug_event/2, % +State, +Event
606 chr:debug_interact/3. % +Event, +Depth, -Command
608 'chr debug_event'(Event) :-
609 nb_getval(chr_debug,mutable(State)), % XXX
610 ( State == off ->
611 true
612 ; chr:debug_event(State, Event) ->
613 true
614 ; debug_event(State,Event)
617 chr_trace :-
618 nb_setval(chr_debug,mutable(trace)).
619 chr_notrace :-
620 nb_setval(chr_debug,mutable(off)).
622 % chr_leash(+Spec)
624 % Define the set of ports at which we prompt for user interaction
626 chr_leash(Spec) :-
627 leashed_ports(Spec, Ports),
628 nb_setval(chr_leash,mutable(Ports)).
630 leashed_ports(none, []).
631 leashed_ports(off, []).
632 leashed_ports(all, [call, exit, redo, fail, wake, try, apply, insert, remove]).
633 leashed_ports(default, [call,exit,fail,wake,apply]).
634 leashed_ports(One, Ports) :-
635 atom(One), One \== [], !,
636 leashed_ports([One], Ports).
637 leashed_ports(Set, Ports) :-
638 sort(Set, Ports), % make unique
639 leashed_ports(all, All),
640 valid_ports(Ports, All).
642 valid_ports([], _).
643 valid_ports([H|T], Valid) :-
644 ( memberchk(H, Valid)
645 -> true
646 ; throw(error(domain_error(chr_port, H), _))
648 valid_ports(T, Valid).
650 user:exception(undefined_global_variable, Name, retry) :-
651 chr_runtime_debug_global_variable(Name),
652 chr_debug_init.
654 chr_runtime_debug_global_variable(chr_leash).
656 chr_debug_init :-
657 leashed_ports(default, Ports),
658 nb_setval(chr_leash, mutable(Ports)).
660 :- initialization chr_debug_init.
662 % debug_event(+State, +Event)
665 %debug_event(trace, Event) :-
666 % functor(Event, Name, Arity),
667 % writeln(Name/Arity), fail.
668 debug_event(trace,Event) :-
669 Event = call(_), !,
670 get_debug_history(History,Depth),
671 NDepth is Depth + 1,
672 chr_debug_interact(Event,NDepth),
673 set_debug_history([Event|History],NDepth).
674 debug_event(trace,Event) :-
675 Event = wake(_), !,
676 get_debug_history(History,Depth),
677 NDepth is Depth + 1,
678 chr_debug_interact(Event,NDepth),
679 set_debug_history([Event|History],NDepth).
680 debug_event(trace,Event) :-
681 Event = redo(_), !,
682 get_debug_history(_History, Depth),
683 chr_debug_interact(Event, Depth).
684 debug_event(trace,Event) :-
685 Event = exit(_),!,
686 get_debug_history([_|History],Depth),
687 chr_debug_interact(Event,Depth),
688 NDepth is Depth - 1,
689 set_debug_history(History,NDepth).
690 debug_event(trace,Event) :-
691 Event = fail(_),!,
692 get_debug_history(_,Depth),
693 chr_debug_interact(Event,Depth).
694 debug_event(trace, Event) :-
695 Event = remove(_), !,
696 get_debug_history(_,Depth),
697 chr_debug_interact(Event, Depth).
698 debug_event(trace, Event) :-
699 Event = insert(_), !,
700 get_debug_history(_,Depth),
701 chr_debug_interact(Event, Depth).
702 debug_event(trace, Event) :-
703 Event = try(_,_,_,_), !,
704 get_debug_history(_,Depth),
705 chr_debug_interact(Event, Depth).
706 debug_event(trace, Event) :-
707 Event = apply(_,_,_,_), !,
708 get_debug_history(_,Depth),
709 chr_debug_interact(Event,Depth).
711 debug_event(skip(_,_),Event) :-
712 Event = call(_), !,
713 get_debug_history(History,Depth),
714 NDepth is Depth + 1,
715 set_debug_history([Event|History],NDepth).
716 debug_event(skip(_,_),Event) :-
717 Event = wake(_), !,
718 get_debug_history(History,Depth),
719 NDepth is Depth + 1,
720 set_debug_history([Event|History],NDepth).
721 debug_event(skip(SkipSusp,SkipDepth),Event) :-
722 Event = exit(Susp),!,
723 get_debug_history([_|History],Depth),
724 ( SkipDepth == Depth,
725 SkipSusp == Susp ->
726 set_chr_debug(trace),
727 chr_debug_interact(Event,Depth)
729 true
731 NDepth is Depth - 1,
732 set_debug_history(History,NDepth).
733 debug_event(skip(_,_),_) :- !,
734 true.
736 % chr_debug_interact(+Event, +Depth)
738 % Interact with the user on Event that took place at Depth. First
739 % calls chr:debug_interact(+Event, +Depth, -Command) hook. If this
740 % fails the event is printed and the system prompts for a command.
742 chr_debug_interact(Event, Depth) :-
743 chr:debug_interact(Event, Depth, Command), !,
744 handle_debug_command(Command,Event,Depth).
745 chr_debug_interact(Event, Depth) :-
746 print_event(Event, Depth),
747 ( leashed(Event)
748 -> ask_continue(Command)
749 ; Command = creep
751 handle_debug_command(Command,Event,Depth).
753 leashed(Event) :-
754 functor(Event, Port, _),
755 nb_getval(chr_leash, mutable(Ports)),
756 memberchk(Port, Ports).
758 ask_continue(Command) :-
759 print_message(debug, chr(prompt)),
760 get_single_char(CharCode),
761 ( CharCode == -1
762 -> Char = end_of_file
763 ; char_code(Char, CharCode)
765 ( debug_command(Char, Command)
766 -> print_message(debug, chr(command(Command)))
767 ; print_message(help, chr(invalid_command)),
768 ask_continue(Command)
772 'chr debug command'(Char, Command) :-
773 debug_command(Char, Command).
775 debug_command(c, creep).
776 debug_command(' ', creep).
777 debug_command('\r', creep).
778 debug_command(s, skip).
779 debug_command(g, ancestors).
780 debug_command(n, nodebug).
781 debug_command(a, abort).
782 debug_command(f, fail).
783 debug_command(b, break).
784 debug_command(?, help).
785 debug_command(h, help).
786 debug_command(end_of_file, exit).
789 handle_debug_command(creep,_,_) :- !.
790 handle_debug_command(skip, Event, Depth) :- !,
791 Event =.. [Type|Rest],
792 ( Type \== call,
793 Type \== wake ->
794 handle_debug_command('c',Event,Depth)
796 Rest = [Susp],
797 set_chr_debug(skip(Susp,Depth))
800 handle_debug_command(ancestors,Event,Depth) :- !,
801 print_chr_debug_history,
802 chr_debug_interact(Event,Depth).
803 handle_debug_command(nodebug,_,_) :- !,
804 chr_notrace.
805 handle_debug_command(abort,_,_) :- !,
806 abort.
807 handle_debug_command(exit,_,_) :- !,
808 halt.
809 handle_debug_command(fail,_,_) :- !,
810 fail.
811 handle_debug_command(break,Event,Depth) :- !,
812 break,
813 chr_debug_interact(Event,Depth).
814 handle_debug_command(help,Event,Depth) :- !,
815 print_message(help, chr(debug_options)),
816 chr_debug_interact(Event,Depth).
817 handle_debug_command(Cmd, _, _) :-
818 throw(error(domain_error(chr_debug_command, Cmd), _)).
820 print_chr_debug_history :-
821 get_debug_history(History,Depth),
822 print_message(debug, chr(ancestors(History, Depth))).
824 print_event(Event, Depth) :-
825 print_message(debug, chr(event(Event, Depth))).
827 % {set,get}_debug_history(Ancestors, Depth)
829 % Set/get the list of ancestors and the depth of the current goal.
831 get_debug_history(History,Depth) :-
832 nb_getval(chr_debug_history,mutable(History,Depth)).
834 set_debug_history(History,Depth) :-
835 nb_getval(chr_debug_history,Mutable),
836 setarg(1,Mutable,History),
837 setarg(2,Mutable,Depth).
839 set_chr_debug(State) :-
840 nb_getval(chr_debug,Mutable),
841 setarg(1,Mutable,State).
843 'chr chr_indexed_variables'(Susp,Vars) :-
844 Susp =.. [_,_,_,_,_,_,_|Args],
845 term_variables(Args,Vars).