35
69
70:- module(chr_runtime,
71 [ 'chr sbag_del_element'/3,
72 'chr merge_attributes'/3,
73
74 'chr run_suspensions'/1,
75 'chr run_suspensions_loop'/1,
76
77 'chr run_suspensions_d'/1,
78 'chr run_suspensions_loop_d'/1,
79
80 'chr insert_constraint_internal'/5,
81 'chr remove_constraint_internal'/2,
82 'chr allocate_constraint'/4,
83 'chr activate_constraint'/3,
84
85 'chr default_store'/1,
86
87 'chr via_1'/2,
88 'chr via_2'/3,
89 'chr via'/2,
90 'chr newvia_1'/2,
91 'chr newvia_2'/3,
92 'chr newvia'/2,
93
94 'chr lock'/1,
95 'chr unlock'/1,
96 'chr not_locked'/1,
97 'chr none_locked'/1,
98
99 'chr error_lock'/1,
100 'chr unerror_lock'/1,
101 'chr not_error_locked'/1,
102 'chr none_error_locked'/1,
103
104 'chr update_mutable'/2,
105 'chr get_mutable'/2,
106 'chr create_mutable'/2,
107
108 'chr novel_production'/2,
109 'chr extend_history'/2,
110 'chr empty_history'/1,
111
112 'chr gen_id'/1,
113
114 'chr debugging'/0,
115 'chr debug_event'/1,
116 'chr debug command'/2, 117
118 'chr chr_indexed_variables'/2,
119
120 'chr all_suspensions'/3,
121 'chr new_merge_attributes'/3,
122 'chr normalize_attr'/2,
123
124 'chr select'/3,
125
126 'chr module'/1, 127
128 chr_show_store/1, 129 find_chr_constraint/1, 130 current_chr_constraint/1, 131
132 chr_trace/0,
133 chr_notrace/0,
134 chr_leash/1
135 ]).
138:- set_prolog_flag(generate_debug_info, false). 139:- use_module(library(modules), [current_temporary_module/1]).
142:- meta_predicate
143 current_chr_constraint(:). 144
146
147:- use_module(library(dialect/hprolog)). 148:- include(chr_op).
157
161:- dynamic user:exception/3. 162:- multifile user:exception/3. 163
164user:exception(undefined_global_variable, Name, retry) :-
165 chr_runtime_global_variable(Name),
166 chr_init.
167
168chr_runtime_global_variable(chr_id).
169chr_runtime_global_variable(chr_global).
170chr_runtime_global_variable(chr_debug).
171chr_runtime_global_variable(chr_debug_history).
172
173chr_init :-
174 nb_setval(chr_id,0),
175 nb_setval(chr_global,_),
176 nb_setval(chr_debug,mutable(off)), 177 nb_setval(chr_debug_history,mutable([],0)).
185:- initialization chr_init. 186
187
195
196chr_show_store(Mod) :-
197 (
198 Mod:'$enumerate_constraints'(Constraint),
199 print(Constraint),nl, 200 fail
201 ;
202 true
203 ).
212find_chr_constraint(Constraint) :-
213 'chr module'(Mod),
214 Mod:'$enumerate_constraints'(Constraint).
221current_chr_constraint(Mod:Constraint) :-
222 'chr module'(Mod),
223 Mod:'$enumerate_constraints'(Constraint).
231'chr module'(Module) :-
232 chr:'$chr_module'(Module).
233:- if(current_prolog_flag(dialect, swi)). 234'chr module'(Module) :-
235 current_temporary_module(Module),
236 current_predicate(Module:'$chr_initialization'/0),
237 \+ predicate_property(Module:'$chr_initialization', imported_from(_)).
238:- endif. 239
248:- multifile user:goal_expansion/2. 249:- dynamic user:goal_expansion/2. 250
251user:goal_expansion('chr get_mutable'(Val,Var), Var=mutable(Val)).
252user:goal_expansion('chr update_mutable'(Val,Var), setarg(1,Var,Val)).
253user:goal_expansion('chr create_mutable'(Val,Var), Var=mutable(Val)).
254user:goal_expansion('chr default_store'(X), nb_getval(chr_global,X)).
282'chr run_suspensions'( Slots) :-
283 run_suspensions( Slots).
284
285'chr run_suspensions_loop'([]).
286'chr run_suspensions_loop'([L|Ls]) :-
287 run_suspensions(L),
288 'chr run_suspensions_loop'(Ls).
289
290run_suspensions([]).
291run_suspensions([S|Next] ) :-
292 arg( 2, S, Mref), 293 'chr get_mutable'( Status, Mref),
294 ( Status==active ->
295 'chr update_mutable'( triggered, Mref),
296 arg( 4, S, Gref), 297 'chr get_mutable'( Gen, Gref),
298 Generation is Gen+1,
299 'chr update_mutable'( Generation, Gref),
300 arg( 3, S, Goal), 301 call( Goal),
302 'chr get_mutable'( Post, Mref),
303 ( Post==triggered ->
304 'chr update_mutable'( active, Mref) 305 ;
306 true
307 )
308 ;
309 true
310 ),
311 run_suspensions( Next).
312
313'chr run_suspensions_d'( Slots) :-
314 run_suspensions_d( Slots).
315
316'chr run_suspensions_loop_d'([]).
317'chr run_suspensions_loop_d'([L|Ls]) :-
318 run_suspensions_d(L),
319 'chr run_suspensions_loop_d'(Ls).
320
321run_suspensions_d([]).
322run_suspensions_d([S|Next] ) :-
323 arg( 2, S, Mref), 324 'chr get_mutable'( Status, Mref),
325 ( Status==active ->
326 'chr update_mutable'( triggered, Mref),
327 arg( 4, S, Gref), 328 'chr get_mutable'( Gen, Gref),
329 Generation is Gen+1,
330 'chr update_mutable'( Generation, Gref),
331 arg( 3, S, Goal), 332 (
333 'chr debug_event'(wake(S)),
334 call( Goal)
335 ;
336 'chr debug_event'(fail(S)), !,
337 fail
338 ),
339 (
340 'chr debug_event'(exit(S))
341 ;
342 'chr debug_event'(redo(S)),
343 fail
344 ),
345 'chr get_mutable'( Post, Mref),
346 ( Post==triggered ->
347 'chr update_mutable'( active, Mref) 348 ;
349 true
350 )
351 ;
352 true
353 ),
354 run_suspensions_d( Next).
359
361
364
365:- public locked:attr_unify_hook/2. 366locked:attr_unify_hook(_,_) :- fail.
367
369'chr lock'(T) :-
370 ( var(T)
371 -> put_attr(T, locked, x)
372 ; term_variables(T,L),
373 lockv(L)
374 ).
375
376lockv([]).
377lockv([T|R]) :- put_attr( T, locked, x), lockv(R).
378
379'chr unlock'(T) :-
380 ( var(T)
381 -> del_attr(T, locked)
382 ; term_variables(T,L),
383 unlockv(L)
384 ).
385
386unlockv([]).
387unlockv([T|R]) :- del_attr( T, locked), unlockv(R).
388
390
391'chr none_locked'( []).
392'chr none_locked'( [V|Vs]) :-
393 ( get_attr(V, locked, _) ->
394 fail
395 ;
396 'chr none_locked'(Vs)
397 ).
398
399'chr not_locked'(V) :-
400 ( var( V) ->
401 ( get_attr( V, locked, _) ->
402 fail
403 ;
404 true
405 )
406 ;
407 true
408 ).
409
411
413lock_error(Term) :-
414 throw(error(instantation_error(Term),context(_,'CHR Runtime Error: unification in guard not allowed!'))).
415
418
419error_locked:attr_unify_hook(_,Term) :- lock_error(Term).
420
422'chr error_lock'(T) :-
423 ( var(T)
424 -> put_attr(T, error_locked, x)
425 ; term_variables(T,L),
426 error_lockv(L)
427 ).
428
429error_lockv([]).
430error_lockv([T|R]) :- put_attr( T, error_locked, x), error_lockv(R).
431
432'chr unerror_lock'(T) :-
433 ( var(T)
434 -> del_attr(T, error_locked)
435 ; term_variables(T,L),
436 unerror_lockv(L)
437 ).
438
439unerror_lockv([]).
440unerror_lockv([T|R]) :- del_attr( T, error_locked), unerror_lockv(R).
441
443
444'chr none_error_locked'( []).
445'chr none_error_locked'( [V|Vs]) :-
446 ( get_attr(V, error_locked, _) ->
447 fail
448 ;
449 'chr none_error_locked'(Vs)
450 ).
451
452'chr not_error_locked'(V) :-
453 ( var( V) ->
454 ( get_attr( V, error_locked, _) ->
455 fail
456 ;
457 true
458 )
459 ;
460 true
461 ).
462
467'chr remove_constraint_internal'( Susp, Agenda) :-
468 arg( 2, Susp, Mref), 469 'chr get_mutable'( State, Mref),
470 'chr update_mutable'( removed, Mref), 471 ( compound(State) -> 472 Agenda = []
473 ; State==removed ->
474 Agenda = []
475 476 477 ;
478 Susp =.. [_,_,_,_,_,_,_|Args],
479 term_variables( Args, Vars),
480 'chr default_store'( Global),
481 Agenda = [Global|Vars]
482 ).
483
485'chr newvia_1'(X,V) :-
486 ( var(X) ->
487 X = V
488 ;
489 nonground(X,V)
490 ).
491
492'chr newvia_2'(X,Y,V) :-
493 ( var(X) ->
494 X = V
495 ; var(Y) ->
496 Y = V
497 ; compound(X), nonground(X,V) ->
498 true
499 ;
500 compound(Y), nonground(Y,V)
501 ).
502
509'chr newvia'(L,V) :- nonground(L,V).
511
512'chr via_1'(X,V) :-
513 ( var(X) ->
514 X = V
515 ; atomic(X) ->
516 'chr default_store'(V)
517 ; nonground(X,V) ->
518 true
519 ;
520 'chr default_store'(V)
521 ).
522
523'chr via_2'(X,Y,V) :-
524 ( var(X) ->
525 X = V
526 ; var(Y) ->
527 Y = V
528 ; compound(X), nonground(X,V) ->
529 true
530 ; compound(Y), nonground(Y,V) ->
531 true
532 ;
533 'chr default_store'(V)
534 ).
535
542'chr via'(L,V) :-
543 ( nonground(L,V) ->
544 true
545 ;
546 'chr default_store'(V)
547 ).
548
549:- if(\+current_predicate(nonground/2)). 550nonground( Term, V) :-
551 term_variables( Term, Vs),
552 Vs = [V|_].
553:- endif. 554
556'chr novel_production'( Self, Tuple) :-
557 arg( 5, Self, Ref), 558 'chr get_mutable'( History, Ref),
559 ( get_ds( Tuple, History, _) ->
560 fail
561 ;
562 true
563 ).
564
569'chr extend_history'( Self, Tuple) :-
570 arg( 5, Self, Ref), 571 'chr get_mutable'( History, Ref),
572 put_ds( Tuple, History, x, NewHistory),
573 'chr update_mutable'( NewHistory, Ref).
574
576'chr allocate_constraint'( Closure, Self, F, Args) :-
577 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], 578 'chr create_mutable'(0, Gref),
579 'chr empty_history'(History),
580 'chr create_mutable'(History, Href),
581 'chr create_mutable'(passive(Args), Mref),
582 'chr gen_id'( Id).
583
589'chr activate_constraint'( Vars, Susp, Generation) :-
590 arg( 2, Susp, Mref), 591 'chr get_mutable'( State, Mref),
592 'chr update_mutable'( active, Mref),
593 ( nonvar(Generation) -> 594 true
595 ;
596 arg( 4, Susp, Gref), 597 'chr get_mutable'( Gen, Gref),
598 Generation is Gen+1,
599 'chr update_mutable'( Generation, Gref)
600 ),
601 ( compound(State) -> 602 term_variables( State, Vs),
603 'chr none_locked'( Vs),
604 Vars = [Global|Vs],
605 'chr default_store'(Global)
606 ; State == removed -> 607 Susp =.. [_,_,_,_,_,_,_|Args],
608 term_variables( Args, Vs),
609 Vars = [Global|Vs],
610 'chr default_store'(Global)
611 ;
612 Vars = []
613 ).
614
615'chr insert_constraint_internal'([Global|Vars], Self, Closure, F, Args) :-
616 'chr default_store'(Global),
617 term_variables(Args,Vars),
618 'chr none_locked'(Vars),
619 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args], 620 'chr create_mutable'(active, Mref),
621 'chr create_mutable'(0, Gref),
622 'chr empty_history'(History),
623 'chr create_mutable'(History, Href),
624 'chr gen_id'(Id).
625
626insert_constraint_internal([Global|Vars], Self, Term, Closure, F, Args) :-
627 'chr default_store'(Global),
628 term_variables( Term, Vars),
629 'chr none_locked'( Vars),
630 'chr empty_history'( History),
631 'chr create_mutable'( active, Mref),
632 'chr create_mutable'( 0, Gref),
633 'chr create_mutable'( History, Href),
634 'chr gen_id'( Id),
635 Self =.. [suspension,Id,Mref,Closure,Gref,Href,F|Args]. 636
638'chr empty_history'( E) :- empty_ds( E).
639
641'chr gen_id'( Id) :-
642 nb_getval(chr_id,Id),
643 NextId is Id + 1,
644 nb_setval(chr_id,NextId).
645
649'chr create_mutable'(V,mutable(V)).
650'chr get_mutable'(V,mutable(V)).
651'chr update_mutable'(V,M) :- setarg(1,M,V).
663'chr default_store'(X) :- nb_getval(chr_global,X).
671
672'chr sbag_del_element'( [], _, []).
673'chr sbag_del_element'( [X|Xs], Elem, Set2) :-
674 ( X==Elem ->
675 Set2 = Xs
676 ;
677 Set2 = [X|Xss],
678 'chr sbag_del_element'( Xs, Elem, Xss)
679 ).
680
682'chr merge_attributes'([],Ys,Ys).
683'chr merge_attributes'([X | Xs],YL,R) :-
684 ( YL = [Y | Ys] ->
685 arg(1,X,XId), 686 arg(1,Y,YId), 687 ( XId < YId ->
688 R = [X | T],
689 'chr merge_attributes'(Xs,YL,T)
690 ; XId > YId ->
691 R = [Y | T],
692 'chr merge_attributes'([X|Xs],Ys,T)
693 ;
694 R = [X | T],
695 'chr merge_attributes'(Xs,Ys,T)
696 )
697 ;
698 R = [X | Xs]
699 ).
700
701'chr new_merge_attributes'([],A2,A) :-
702 A = A2.
703'chr new_merge_attributes'([E1|AT1],A2,A) :-
704 ( A2 = [E2|AT2] ->
705 'chr new_merge_attributes'(E1,E2,AT1,AT2,A)
706 ;
707 A = [E1|AT1]
708 ).
709
710'chr new_merge_attributes'(Pos1-L1,Pos2-L2,AT1,AT2,A) :-
711 ( Pos1 < Pos2 ->
712 A = [Pos1-L1|AT],
713 'chr new_merge_attributes'(AT1,[Pos2-L2|AT2],AT)
714 ; Pos1 > Pos2 ->
715 A = [Pos2-L2|AT],
716 'chr new_merge_attributes'([Pos1-L1|AT1],AT2,AT)
717 ;
718 'chr merge_attributes'(L1,L2,L),
719 A = [Pos1-L|AT],
720 'chr new_merge_attributes'(AT1,AT2,AT)
721 ).
722
723'chr all_suspensions'([],_,_).
724'chr all_suspensions'([Susps|SuspsList],Pos,Attr) :-
725 all_suspensions(Attr,Susps,SuspsList,Pos).
726
727all_suspensions([],[],SuspsList,Pos) :-
728 all_suspensions([],[],SuspsList,Pos). 729all_suspensions([APos-ASusps|RAttr],Susps,SuspsList,Pos) :-
730 NPos is Pos + 1,
731 ( Pos == APos ->
732 Susps = ASusps,
733 'chr all_suspensions'(SuspsList,NPos,RAttr)
734 ;
735 Susps = [],
736 'chr all_suspensions'(SuspsList,NPos,[APos-ASusps|RAttr])
737 ).
738
739'chr normalize_attr'([],[]).
740'chr normalize_attr'([Pos-L|R],[Pos-NL|NR]) :-
741 sort(L,NL),
742 'chr normalize_attr'(R,NR).
743
744'chr select'([E|T],F,R) :-
745 ( E = F ->
746 R = T
747 ;
748 R = [E|NR],
749 'chr select'(T,F,NR)
750 ).
751
753
754:- multifile
755 chr:debug_event/2, 756 chr:debug_interact/3. 757
758'chr debugging' :-
759 nb_getval(chr_debug,mutable(trace)).
760
761'chr debug_event'(Event) :-
762 ( nb_getval(chr_debug,mutable(State)),
763 State \== off
764 -> ( chr:debug_event(State, Event)
765 -> true
766 ; debug_event(State,Event)
767 )
768 ; true
769 ).
770
771chr_trace :-
772 nb_setval(chr_debug,mutable(trace)).
773chr_notrace :-
774 nb_setval(chr_debug,mutable(off)).
775
779
780chr_leash(Spec) :-
781 leashed_ports(Spec, Ports),
782 nb_setval(chr_leash,mutable(Ports)).
783
784leashed_ports(none, []).
785leashed_ports(off, []).
786leashed_ports(all, [call, exit, redo, fail, wake, try, apply, insert, remove]).
787leashed_ports(default, [call,exit,fail,wake,apply]).
788leashed_ports(One, Ports) :-
789 atom(One), One \== [], !,
790 leashed_ports([One], Ports).
791leashed_ports(Set, Ports) :-
792 sort(Set, Ports), 793 leashed_ports(all, All),
794 valid_ports(Ports, All).
795
796valid_ports([], _).
797valid_ports([H|T], Valid) :-
798 ( memberchk(H, Valid)
799 -> true
800 ; throw(error(domain_error(chr_port, H), _))
801 ),
802 valid_ports(T, Valid).
803
804user:exception(undefined_global_variable, Name, retry) :-
805 chr_runtime_debug_global_variable(Name),
806 chr_debug_init.
807
808chr_runtime_debug_global_variable(chr_leash).
809
810chr_debug_init :-
811 leashed_ports(default, Ports),
812 nb_setval(chr_leash, mutable(Ports)).
813
814:- initialization chr_debug_init. 815
817
818
822debug_event(trace,Event) :-
823 Event = call(_), !,
824 get_debug_history(History,Depth),
825 NDepth is Depth + 1,
826 chr_debug_interact(Event,NDepth),
827 set_debug_history([Event|History],NDepth).
828debug_event(trace,Event) :-
829 Event = wake(_), !,
830 get_debug_history(History,Depth),
831 NDepth is Depth + 1,
832 chr_debug_interact(Event,NDepth),
833 set_debug_history([Event|History],NDepth).
834debug_event(trace,Event) :-
835 Event = redo(_), !,
836 get_debug_history(_History, Depth),
837 chr_debug_interact(Event, Depth).
838debug_event(trace,Event) :-
839 Event = exit(_),!,
840 get_debug_history([_|History],Depth),
841 chr_debug_interact(Event,Depth),
842 NDepth is Depth - 1,
843 set_debug_history(History,NDepth).
844debug_event(trace,Event) :-
845 Event = fail(_),!,
846 get_debug_history(_,Depth),
847 chr_debug_interact(Event,Depth).
848debug_event(trace, Event) :-
849 Event = remove(_), !,
850 get_debug_history(_,Depth),
851 chr_debug_interact(Event, Depth).
852debug_event(trace, Event) :-
853 Event = insert(_), !,
854 get_debug_history(_,Depth),
855 chr_debug_interact(Event, Depth).
856debug_event(trace, Event) :-
857 Event = try(_,_,_,_), !,
858 get_debug_history(_,Depth),
859 chr_debug_interact(Event, Depth).
860debug_event(trace, Event) :-
861 Event = apply(_,_,_,_), !,
862 get_debug_history(_,Depth),
863 chr_debug_interact(Event,Depth).
864
865debug_event(skip(_,_),Event) :-
866 Event = call(_), !,
867 get_debug_history(History,Depth),
868 NDepth is Depth + 1,
869 set_debug_history([Event|History],NDepth).
870debug_event(skip(_,_),Event) :-
871 Event = wake(_), !,
872 get_debug_history(History,Depth),
873 NDepth is Depth + 1,
874 set_debug_history([Event|History],NDepth).
875debug_event(skip(SkipSusp,SkipDepth),Event) :-
876 Event = exit(Susp),!,
877 get_debug_history([_|History],Depth),
878 ( SkipDepth == Depth,
879 SkipSusp == Susp ->
880 set_chr_debug(trace),
881 chr_debug_interact(Event,Depth)
882 ;
883 true
884 ),
885 NDepth is Depth - 1,
886 set_debug_history(History,NDepth).
887debug_event(skip(_,_),_) :- !,
888 true.
889
895
896chr_debug_interact(Event, Depth) :-
897 chr:debug_interact(Event, Depth, Command), !,
898 handle_debug_command(Command,Event,Depth).
899chr_debug_interact(Event, Depth) :-
900 print_event(Event, Depth),
901 ( leashed(Event)
902 -> ask_continue(Command)
903 ; Command = creep
904 ),
905 handle_debug_command(Command,Event,Depth).
906
907leashed(Event) :-
908 functor(Event, Port, _),
909 nb_getval(chr_leash, mutable(Ports)),
910 memberchk(Port, Ports).
911
912:- multifile
913 chr:debug_ask_continue/1. 914
915ask_continue(Command) :-
916 chr:debug_ask_continue(Command), !.
917ask_continue(Command) :-
918 print_message(trace, chr(prompt)),
919 get_single_char(CharCode),
920 ( CharCode == -1
921 -> Char = end_of_file
922 ; char_code(Char, CharCode)
923 ),
924 ( debug_command(Char, Command)
925 -> print_message(trace, chr(command(Command)))
926 ; print_message(help, chr(invalid_command)),
927 ask_continue(Command)
928 ).
929
930
931'chr debug command'(Char, Command) :-
932 debug_command(Char, Command).
933
934debug_command(c, creep).
935debug_command(' ', creep).
936debug_command('\r', creep).
937debug_command(s, skip).
938debug_command(g, ancestors).
939debug_command(n, nodebug).
940debug_command(a, abort).
941debug_command(f, fail).
942debug_command(b, break).
943debug_command(?, help).
944debug_command(h, help).
945debug_command(end_of_file, exit).
946
947
948handle_debug_command(creep,_,_) :- !.
949handle_debug_command(skip, Event, Depth) :- !,
950 Event =.. [Type|Rest],
951 ( Type \== call,
952 Type \== wake ->
953 handle_debug_command(creep,Event,Depth)
954 ;
955 Rest = [Susp],
956 set_chr_debug(skip(Susp,Depth))
957 ).
958handle_debug_command(ancestors,Event,Depth) :- !,
959 print_chr_debug_history,
960 chr_debug_interact(Event,Depth).
961handle_debug_command(nodebug,_,_) :- !,
962 chr_notrace.
963handle_debug_command(abort,_,_) :- !,
964 abort.
965handle_debug_command(exit,_,_) :- !,
966 ( thread_self(main) 967 -> halt 968 ; permission_error(access, chr_debug, halt)
969 ).
970handle_debug_command(fail,_,_) :- !,
971 fail.
972handle_debug_command(break,Event,Depth) :- !,
973 break,
974 chr_debug_interact(Event,Depth).
975handle_debug_command(help,Event,Depth) :- !,
976 print_message(help, chr(debug_options)),
977 chr_debug_interact(Event,Depth).
978handle_debug_command(Cmd, _, _) :-
979 throw(error(domain_error(chr_debug_command, Cmd), _)).
980
981print_chr_debug_history :-
982 get_debug_history(History,Depth),
983 print_message(trace, chr(ancestors(History, Depth))).
984
985print_event(Event, Depth) :-
986 print_message(trace, chr(event(Event, Depth))).
987
991
992get_debug_history(History,Depth) :-
993 nb_getval(chr_debug_history,mutable(History,Depth)).
994
995set_debug_history(History,Depth) :-
996 nb_getval(chr_debug_history,Mutable),
997 setarg(1,Mutable,History),
998 setarg(2,Mutable,Depth).
999
1000set_chr_debug(State) :-
1001 nb_getval(chr_debug,Mutable),
1002 setarg(1,Mutable,State).
1003
1004'chr chr_indexed_variables'(Susp,Vars) :-
1005 Susp =.. [_,_,_,_,_,_,_|Args],
1006 term_variables(Args,Vars).
1007
1008
1009 1012:- multifile
1013 sandbox:safe_primitive/1. 1014
1015sandbox:safe_primitive(chr_runtime:handle_debug_command(_,_,_)).
1016sandbox:safe_primitive(chr_runtime:ask_continue(_))