387 lines
9.8 KiB
Prolog
387 lines
9.8 KiB
Prolog
/*************************************************************************
|
|
* *
|
|
* YAP Prolog *
|
|
* *
|
|
* Yap Prolog was developed at NCCUP - Universidade do Porto *
|
|
* *
|
|
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
|
|
* *
|
|
**************************************************************************
|
|
* *
|
|
* File: control.yap *
|
|
* Last rev: 20/08/09 *
|
|
* mods: *
|
|
* comments: control predicates available in yap *
|
|
* *
|
|
*************************************************************************/
|
|
|
|
once(G) :- '$execute'(G), !.
|
|
|
|
forall(Cond, Action) :- \+((Cond, \+(Action))).
|
|
|
|
ignore(Goal) :- (Goal->true;true).
|
|
|
|
if(X,Y,Z) :-
|
|
yap_hacks:env_choice_point(CP0),
|
|
(
|
|
CP is '$last_choice_pt',
|
|
'$call'(X,CP,if(X,Y,Z),M),
|
|
'$execute'(X),
|
|
'$clean_ifcp'(CP),
|
|
'$call'(Y,CP,if(X,Y,Z),M)
|
|
;
|
|
'$call'(Z,CP,if(X,Y,Z),M)
|
|
).
|
|
|
|
call(X,A) :- '$execute'(X,A).
|
|
|
|
call(X,A1,A2) :- '$execute'(X,A1,A2).
|
|
|
|
call(X,A1,A2,A3) :- '$execute'(X,A1,A2,A3).
|
|
|
|
call(X,A1,A2,A3,A4) :- '$execute'(X,A1,A2,A3,A4).
|
|
|
|
call(X,A1,A2,A3,A4,A5) :- '$execute'(X,A1,A2,A3,A4,A5).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6) :- '$execute'(X,A1,A2,A3,A4,A5,A6).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6,A7) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6,A7,A8) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A9).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10).
|
|
|
|
call(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11) :- '$execute'(X,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11).
|
|
|
|
call_cleanup(Goal, Cleanup) :-
|
|
setup_call_catcher_cleanup(true, Goal, _Catcher, Cleanup).
|
|
|
|
call_cleanup(Goal, Catcher, Cleanup) :-
|
|
setup_call_catcher_cleanup(true, Goal, Catcher, Cleanup).
|
|
|
|
setup_call_cleanup(Setup, Goal, Cleanup) :-
|
|
setup_call_catcher_cleanup(Setup, Goal, _Catcher, Cleanup).
|
|
|
|
setup_call_catcher_cleanup(Setup, Goal, Catcher, Cleanup) :-
|
|
yap_hacks:disable_interrupts,
|
|
'$check_goal_for_setup_call_cleanup'(Setup, setup_call_cleanup(Setup, Goal, Cleanup)),
|
|
catch('$do_setup'(Setup),Exception,'$handle_broken_setup'(Exception)),
|
|
'$check_goal_for_setup_call_cleanup'(Cleanup, setup_call_cleanup(Setup, Goal, Cleanup)),
|
|
'$safe_call_cleanup'(Goal,Cleanup,Catcher,Exception).
|
|
|
|
% make sure we don't lose interrupts if we get exceptions
|
|
% with setup.
|
|
'$handle_broken_setup'(Exception) :-
|
|
yap_hacks:enable_interrupts,
|
|
throw(Exception).
|
|
|
|
'$check_goal_for_setup_call_cleanup'(Goal, G) :-
|
|
strip_module(Goal, _, MG),
|
|
(
|
|
var(MG)
|
|
->
|
|
yap_hacks:enable_interrupts,
|
|
'$do_error'(instantiation_error,G)
|
|
;
|
|
true
|
|
).
|
|
|
|
% this is simple, do nothing
|
|
'$do_setup'(A:true) :- atom(A), !.
|
|
% this is tricky: please don't forget that interrupts are disabled at this point
|
|
% and that they will only be enabled after setting up Cleanup
|
|
'$do_setup'(Setup) :-
|
|
(
|
|
'$execute'(Setup),
|
|
% we don't need to care about enabling interrupts
|
|
!
|
|
;
|
|
% reenable interrupts if Setup failed
|
|
yap_hacks:enable_interrupts,
|
|
fail
|
|
).
|
|
|
|
|
|
'$cleanup_exception'(Exception, exception(Exception), Cleanup) :- !,
|
|
% whatever happens, let exception go through
|
|
catch('$clean_call'(_,Cleanup),_,true),
|
|
throw(Exception).
|
|
'$cleanup_exception'(Exception, _, _) :-
|
|
throw(Exception).
|
|
|
|
'$safe_call_cleanup'(Goal, Cleanup, Catcher, Exception) :-
|
|
'$current_choice_point'(MyCP1),
|
|
'$coroutining':freeze_goal(Catcher, '$clean_call'(Active, Cleanup)),
|
|
(
|
|
yap_hacks:trail_suspension_marker(Catcher),
|
|
yap_hacks:enable_interrupts,
|
|
'$current_choice_point'(CP0),
|
|
'$execute'(Goal),
|
|
'$stop_creeping',
|
|
'$current_choice_point'(CPF),
|
|
(
|
|
CP0 =:= CPF
|
|
->
|
|
Catcher = exit,
|
|
!
|
|
;
|
|
true
|
|
)
|
|
;
|
|
'$stop_creeping',
|
|
Catcher = fail,
|
|
fail
|
|
).
|
|
|
|
'$holds_true'.
|
|
|
|
% The first argument is used by JumpEnv to verify if a throw
|
|
% is going to be handled by the cleanup catcher. If it is so,
|
|
% clean_call will not be called from JumpToEnv.
|
|
'$clean_call'(_, Cleanup) :-
|
|
'$execute'(Cleanup), !.
|
|
'$clean_call'(_, _).
|
|
|
|
'$cc_check_throw' :-
|
|
'$nb_getval'('$catch', Ball, fail),
|
|
throw(Ball).
|
|
|
|
%%% The unknown predicate,
|
|
% informs about what the user wants to be done when
|
|
% there are no clauses for a certain predicate */
|
|
|
|
unknown(V0,V) :-
|
|
'$current_module'(M),
|
|
'$unknown'(V0,V,M).
|
|
|
|
% query mode
|
|
'$unknown'(V0,V,_) :- var(V), !,
|
|
'$ask_unknown_flag'(V),
|
|
V = V0.
|
|
% handle modules.
|
|
'$unknown'(V0,Mod:Handler,_) :-
|
|
'$unknown'(V0,Handler,Mod).
|
|
% check if we have one we like.
|
|
'$unknown'(_,New,Mod) :-
|
|
'$valid_unknown_handler'(New,Mod), fail.
|
|
% clean up previous unknown predicate handlers
|
|
'$unknown'(Old,New,Mod) :-
|
|
recorded('$unknown','$unknown'(_,MyOld),Ref), !,
|
|
erase(Ref),
|
|
'$cleanup_unknown_handler'(MyOld,Old),
|
|
'$new_unknown'(New, Mod).
|
|
% store the new one.
|
|
'$unknown'(fail,New,Mod) :-
|
|
'$new_unknown'(New, Mod).
|
|
|
|
'$valid_unknown_handler'(V,_) :-
|
|
var(V), !,
|
|
'$do_error'(instantiation_error,yap_flag(unknown,V)).
|
|
'$valid_unknown_handler'(fail,_) :- !.
|
|
'$valid_unknown_handler'(error,_) :- !.
|
|
'$valid_unknown_handler'(warning,_) :- !.
|
|
'$valid_unknown_handler'(S,M) :-
|
|
functor(S,_,1),
|
|
arg(1,S,A),
|
|
var(A),
|
|
\+ '$undefined'(S,M),
|
|
!.
|
|
'$valid_unknown_handler'(S,_) :-
|
|
'$do_error'(domain_error(flag_value,unknown+S),yap_flag(unknown,S)).
|
|
|
|
|
|
'$ask_unknown_flag'(Old) :-
|
|
recorded('$unknown','$unknown'(_,MyOld),_), !,
|
|
'$cleanup_unknown_handler'(MyOld,Old).
|
|
'$ask_unknown_flag'(fail).
|
|
|
|
'$cleanup_unknown_handler'('$unknown_error'(_),error) :- !.
|
|
'$cleanup_unknown_handler'('$unknown_warning'(_),warning) :- !.
|
|
'$cleanup_unknown_handler'(Handler, Handler).
|
|
|
|
'$new_unknown'(fail,_) :- !.
|
|
'$new_unknown'(error,_) :- !,
|
|
recorda('$unknown','$unknown'(P,'$unknown_error'(P)),_).
|
|
'$new_unknown'(warning,_) :- !,
|
|
recorda('$unknown','$unknown'(P,'$unknown_warning'(P)),_).
|
|
'$new_unknown'(X,M) :-
|
|
arg(1,X,A),
|
|
recorda('$unknown','$unknown'(A,M:X),_).
|
|
|
|
'$unknown_error'(Mod:Goal) :-
|
|
functor(Goal,Name,Arity),
|
|
'$program_continuation'(PMod,PName,PAr),
|
|
'$do_error'(existence_error(procedure,Name/Arity),context(Mod:Goal,PMod:PName/PAr)).
|
|
|
|
'$unknown_warning'(Mod:Goal) :-
|
|
functor(Goal,Name,Arity),
|
|
'$program_continuation'(PMod,PName,PAr),
|
|
print_message(error,error(existence_error(procedure,Name/Arity), context(Mod:Goal,PMod:PName/PAr))),
|
|
fail.
|
|
|
|
%%% Some "dirty" predicates
|
|
|
|
% Only efective if yap compiled with -DDEBUG
|
|
% this predicate shows the code produced by the compiler
|
|
'$show_code' :- '$debug'(0'f). %' just make emacs happy
|
|
|
|
grow_heap(X) :- '$grow_heap'(X).
|
|
grow_stack(X) :- '$grow_stack'(X).
|
|
|
|
%
|
|
% gc() expects to be called from "call". Make sure it has an
|
|
% environment to return to.
|
|
%
|
|
%garbage_collect :- save(dump), '$gc', save(dump2).
|
|
garbage_collect :-
|
|
'$gc'.
|
|
gc :-
|
|
yap_flag(gc,on).
|
|
nogc :-
|
|
yap_flag(gc,off).
|
|
|
|
garbage_collect_atoms :-
|
|
'$atom_gc'.
|
|
|
|
'$force_environment_for_gc'.
|
|
|
|
'$good_list_of_character_codes'(V) :- var(V), !.
|
|
'$good_list_of_character_codes'([]).
|
|
'$good_list_of_character_codes'([X|L]) :-
|
|
'$good_character_code'(X),
|
|
'$good_list_of_character_codes'(L).
|
|
|
|
'$good_character_code'(X) :- var(X), !.
|
|
'$good_character_code'(X) :- integer(X), X > -2, X < 256.
|
|
|
|
(initialization) :-
|
|
'$initialisation_goals'.
|
|
|
|
prolog_initialization(G) :- var(G), !,
|
|
'$do_error'(instantiation_error,initialization(G)).
|
|
prolog_initialization(T) :- callable(T), !,
|
|
'$assert_init'(T).
|
|
prolog_initialization(T) :-
|
|
'$do_error'(type_error(callable,T),initialization(T)).
|
|
|
|
'$assert_init'(T) :- recordz('$startup_goal',T,_), fail.
|
|
'$assert_init'(_).
|
|
|
|
version :- '$version'.
|
|
|
|
version(V) :- var(V), !,
|
|
'$do_error'(instantiation_error,version(V)).
|
|
version(T) :- atom(T), !, '$assert_version'(T).
|
|
version(T) :-
|
|
'$do_error'(type_error(atom,T),version(T)).
|
|
|
|
'$assert_version'(T) :- recordz('$version',T,_), fail.
|
|
'$assert_version'(_).
|
|
|
|
'$set_toplevel_hook'(_) :-
|
|
recorded('$toplevel_hooks',_,R),
|
|
erase(R),
|
|
fail.
|
|
'$set_toplevel_hook'(H) :-
|
|
recorda('$toplevel_hooks',H,_),
|
|
fail.
|
|
'$set_toplevel_hook'(_).
|
|
|
|
nb_getval(GlobalVariable, Val) :-
|
|
'$nb_getval'(GlobalVariable, Val, Error),
|
|
(var(Error)
|
|
->
|
|
true
|
|
;
|
|
'$getval_exception'(GlobalVariable, Val, nb_getval(GlobalVariable, Val)) ->
|
|
nb_getval(GlobalVariable, Val)
|
|
;
|
|
'$do_error'(existence_error(variable, GlobalVariable),nb_getval(GlobalVariable, Val))
|
|
).
|
|
|
|
|
|
b_getval(GlobalVariable, Val) :-
|
|
'$nb_getval'(GlobalVariable, Val, Error),
|
|
(var(Error)
|
|
->
|
|
true
|
|
;
|
|
'$getval_exception'(GlobalVariable, Val, b_getval(GlobalVariable, Val)) ->
|
|
true
|
|
;
|
|
'$do_error'(existence_error(variable, GlobalVariable),b_getval(GlobalVariable, Val))
|
|
).
|
|
|
|
|
|
/* This is the break predicate,
|
|
it saves the importante data about current streams and
|
|
debugger state */
|
|
|
|
break :-
|
|
'$init_debugger',
|
|
nb_getval('$system_mode',SystemMode),
|
|
nb_getval('$trace',Trace),
|
|
nb_setval('$trace',off),
|
|
nb_getval('$debug_jump',Jump),
|
|
nb_getval('$debug_run',Run),
|
|
'$debug_on'(Debug),
|
|
'$debug_on'(false),
|
|
nb_getval('$break',BL), NBL is BL+1,
|
|
nb_getval('$spy_gn',SPY_GN),
|
|
b_getval('$spy_glist',GList),
|
|
b_setval('$spy_glist',[]),
|
|
nb_setval('$break',NBL),
|
|
current_output(OutStream), current_input(InpStream),
|
|
format(user_error, '% Break (level ~w)~n', [NBL]),
|
|
'$do_live',
|
|
!,
|
|
set_value('$live','$true'),
|
|
b_setval('$spy_glist',GList),
|
|
nb_setval('$spy_gn',SPY_GN),
|
|
set_input(InpStream),
|
|
set_output(OutStream),
|
|
'$debug_on'(Debug),
|
|
nb_setval('$debug_jump',Jump),
|
|
nb_setval('$debug_run',Run),
|
|
nb_setval('$trace',Trace),
|
|
nb_setval('$break',BL),
|
|
nb_setval('$system_mode',SystemMode).
|
|
|
|
|
|
at_halt(G) :-
|
|
recorda('$halt', G, _),
|
|
fail.
|
|
at_halt(_).
|
|
|
|
halt :-
|
|
print_message(informational, halt),
|
|
fail.
|
|
halt :-
|
|
'$halt'(0).
|
|
|
|
halt(_) :-
|
|
recorded('$halt', G, _),
|
|
call(G),
|
|
fail.
|
|
halt(X) :-
|
|
'$sync_mmapped_arrays',
|
|
set_value('$live','$false'),
|
|
'$halt'(X).
|
|
|
|
prolog_current_frame(Env) :-
|
|
Env is '$env'.
|
|
|
|
'$run_atom_goal'(GA) :-
|
|
'$current_module'(Module),
|
|
atom_to_term(GA, G, _),
|
|
'$system_catch'('$query'(once(G), []),Module,Error,user:'$Error'(Error)).
|
|
|
|
'$add_dot_to_atom_goal'([],[0'.]) :- !. %'
|
|
'$add_dot_to_atom_goal'([0'.],[0'.]) :- !.
|
|
'$add_dot_to_atom_goal'([C|Gs0],[C|Gs]) :-
|
|
'$add_dot_to_atom_goal'(Gs0,Gs).
|
|
|
|
|