From f6bcb22b7c656998940838c2845635381d2fa59b Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Fri, 10 Oct 2014 10:00:27 +0100 Subject: [PATCH] fix undefined procedures to allow hooks as before. --- C/absmi.c | 2 + C/modules.c | 14 +++-- H/ihstruct.h | 2 +- Makefile.in | 1 + misc/HEAPFIELDS | 2 +- os/pl-prologflag.c | 10 ++-- pl/attributes.yap | 4 +- pl/boot.yap | 91 ------------------------------- pl/init.yap | 4 +- pl/modules.yap | 1 - pl/preds.yap | 84 ++--------------------------- pl/undefined.yap | 130 +++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 156 insertions(+), 189 deletions(-) create mode 100644 pl/undefined.yap diff --git a/C/absmi.c b/C/absmi.c index 2504800f6..81d2a3e52 100755 --- a/C/absmi.c +++ b/C/absmi.c @@ -8159,6 +8159,7 @@ Yap_absmi(int inp) PELOCK(19,pe); #endif if ((pe->PredFlags & (DynamicPredFlag|LogUpdatePredFlag|MultiFileFlag)) || + CurrentModule == PROLOG_MODULE || (UndefCode->OpcodeOfPred == UNDEF_OPCODE)) { #if defined(YAPOR) || defined(THREADS) PP = NULL; @@ -8207,6 +8208,7 @@ Yap_absmi(int inp) ENDD(d0); HR[0] = Yap_Module_Name(pe); ARG1 = (Term) AbsPair(HR); + ARG2 = MkIntTerm(getUnknownModule(Yap_GetModuleEntry(HR[0]))); HR += 2; #ifdef LOW_LEVEL_TRACER if (Yap_do_low_level_trace) diff --git a/C/modules.c b/C/modules.c index 44726da61..0e693db1c 100644 --- a/C/modules.c +++ b/C/modules.c @@ -27,11 +27,6 @@ static Int p_current_module( USES_REGS1 ); static Int p_current_module1( USES_REGS1 ); static ModEntry *LookupModule(Term a); - unsigned int -getUnknownModule(ModEntry * m) { - return m->flags & UNKNOWN_MASK; -} - inline static ModEntry * FetchModuleEntry(Atom at) /* get predicate entry for ap/arity; create it if neccessary. */ @@ -90,6 +85,15 @@ GetModuleEntry(Atom at) return new; } + unsigned int + getUnknownModule(ModEntry * m) { + if (m && m->flags & UNKNOWN_MASK) + return m->flags & UNKNOWN_MASK; + else { + return GetModuleEntry(AtomUser)->flags & UNKNOWN_MASK; + } + +} #define ByteAdr(X) ((char *) &(X)) Term diff --git a/H/ihstruct.h b/H/ihstruct.h index 974f76525..96b1cb637 100644 --- a/H/ihstruct.h +++ b/H/ihstruct.h @@ -121,7 +121,7 @@ CreepCode = RepPredProp(PredPropByFunc(Yap_MkFunctor(AtomCreep,1),PROLOG_MODULE)); - UndefCode = RepPredProp(PredPropByFunc(Yap_MkFunctor(AtomUndefp,1),PROLOG_MODULE)); + UndefCode = RepPredProp(PredPropByFunc(Yap_MkFunctor(AtomUndefp,2),PROLOG_MODULE)); SpyCode = RepPredProp(PredPropByFunc(Yap_MkFunctor(AtomSpy,1),PROLOG_MODULE)); PredFail = RepPredProp(PredPropByAtom(AtomFail,PROLOG_MODULE)); PredTrue = RepPredProp(PredPropByAtom(AtomTrue,PROLOG_MODULE)); diff --git a/Makefile.in b/Makefile.in index 3c6500ccd..cd4ab8f49 100755 --- a/Makefile.in +++ b/Makefile.in @@ -356,6 +356,7 @@ PL_SOURCES= \ pl/strict_iso.yap \ pl/tabling.yap pl/threads.yap \ pl/udi.yap \ + pl/undefined.yap \ pl/utils.yap \ pl/history.pl \ pl/swi.yap \ diff --git a/misc/HEAPFIELDS b/misc/HEAPFIELDS index 81ea68302..2d2867726 100644 --- a/misc/HEAPFIELDS +++ b/misc/HEAPFIELDS @@ -129,7 +129,7 @@ UInt pred_hash_table_size PredHashTableSize void /* Well-Known Predicates */ struct pred_entry *creep_code CreepCode MkPred AtomCreep 1 PROLOG_MODULE -struct pred_entry *undef_code UndefCode MkPred AtomUndefp 1 PROLOG_MODULE +struct pred_entry *undef_code UndefCode MkPred AtomUndefp 2 PROLOG_MODULE struct pred_entry *spy_code SpyCode MkPred AtomSpy 1 PROLOG_MODULE struct pred_entry *pred_fail PredFail MkPred AtomFail 0 PROLOG_MODULE struct pred_entry *pred_true PredTrue MkPred AtomTrue 0 PROLOG_MODULE diff --git a/os/pl-prologflag.c b/os/pl-prologflag.c index 25145dd7d..e1df6ae80 100755 --- a/os/pl-prologflag.c +++ b/os/pl-prologflag.c @@ -287,6 +287,7 @@ setUnknown(term_t value, atom_t a, Module m) else return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_unknown, value); +#ifndef __YAP_PROLOG__ if ( !(flags&UNKNOWN_ERROR) && (m == MODULE_user || m == MODULE_system) ) { GET_LD @@ -297,12 +298,11 @@ setUnknown(term_t value, atom_t a, Module m) return PL_error(NULL, 0, NULL, ERR_PERMISSION, ATOM_modify, ATOM_flag, key); } - -#ifndef __YAP_PROLOG__ + if ( !SYSTEM_MODE ) printMessage(ATOM_warning, PL_CHARS, "unknown_in_module_user"); -#endif } +#endif m->flags = flags; @@ -1203,11 +1203,7 @@ initPrologFlags(void) setPrologFlag("occurs_check", FT_ATOM, "false"); setPrologFlag("access_level", FT_ATOM, "user"); setPrologFlag("double_quotes", FT_ATOM, "codes"); -#ifdef __YAP_PROLOG__ - setPrologFlag("unknown", FT_ATOM, "fail"); -#else setPrologFlag("unknown", FT_ATOM, "error"); -#endif setPrologFlag("debug", FT_BOOL, FALSE, 0); setPrologFlag("verbose", FT_ATOM|FF_KEEP, GD->options.silent ? "silent" : "normal"); setPrologFlag("verbose_load", FT_ATOM, "normal"); diff --git a/pl/attributes.yap b/pl/attributes.yap index 85f9081db..8353e2b39 100644 --- a/pl/attributes.yap +++ b/pl/attributes.yap @@ -310,7 +310,9 @@ do_continuation(Continuation, Module1) :- execute_continuation(Continuation, Module1) :- '$undefined'(Continuation, Module1), !, - '$undefp'([Module1|Continuation]). + '$current_module'( M ), + '$swi_current_prolog_flag'( M:unknown, Default ), + '$undefp'([Module1|Continuation] , Default ). execute_continuation(Continuation, Mod) :- % do not do meta-expansion nor any fancy stuff. '$execute0'(Continuation, Mod). diff --git a/pl/boot.yap b/pl/boot.yap index 9640693f3..e5c43d958 100644 --- a/pl/boot.yap +++ b/pl/boot.yap @@ -1572,98 +1572,7 @@ log_event( String, Args ) :- format( atom( M ), String, Args), log_event( M ). - /** @} */ -/** @defgroup Undefined_Procedures Handling Undefined Procedures -@ingroup YAPControl -@{ - -A predicate in a module is said to be undefined if there are no clauses -defining the predicate, and if the predicate has not been declared to be -dynamic. What YAP does when trying to execute undefined predicates can -be specified in three different ways: - - -+ By setting an YAP flag, through the yap_flag/2 or -set_prolog_flag/2 built-ins. This solution generalizes the -ISO standard. -+ By using the unknown/2 built-in (this solution is -compatible with previous releases of YAP). -+ By defining clauses for the hook predicate -`user:unknown_predicate_handler/3`. This solution is compatible -with SICStus Prolog. - - -*/ - -% Called by the abstract machine, if no clauses exist for a predicate -'$undefp'([M|G]) :- - '$find_goal_definition'(M, G, NM, NG), - '$execute0'(NG, NM). - -'$find_goal_definition'(M, G, NM, NG) :- - % make sure we do not loop on undefined predicates - % for undefined_predicates. - '$enter_undefp', - ( - '$get_undefined_pred'(G, M, Goal, NM) - -> - '$exit_undefp', - Goal \= fail, - '$complete_goal'(M, Goal, NM, G, NG) - ; - '$find_undefp_handler'(G, M), - NG = G, NM = M - ). - -'$complete_goal'(M, G, CurMod, G0, NG) :- - ( - '$is_metapredicate'(G,CurMod) - -> - '$meta_expansion'(G, M, CurMod, M, NG,[]) - ; - NG = G - ). - -'$find_undefp_handler'(G,M,NG,user) :- - functor(G, Na, Ar), - user:exception(undefined_predicate,M:Na/Ar,Action), !, - '$exit_undefp', - ( - Action == fail - -> - NG = fail - ; - Action == retry - -> - NG = G - ; - Action == error - -> - '$unknown_error'(M:G) - ; - '$do_error'(type_error(atom, Action),M:G) - ). - -'$find_undefp_handler'(G,M) :- - '$exit_undefp', - '$swi_current_prolog_flag'(M:unknown, Action), - ( - Action == fail - -> - fail - ; - Action == warning - -> - '$unknown_warning'(M:G), - fail - ; - '$unknown_error'(M:G) - ). - -/** -@} -*/ diff --git a/pl/init.yap b/pl/init.yap index ab7cec3b5..a7d93bc7b 100644 --- a/pl/init.yap +++ b/pl/init.yap @@ -182,6 +182,8 @@ version(yap,[6,3]). :- ['arrays.yap']. +:- ['undefined.yap']. + :- use_module('messages.yap'). :- use_module('hacks.yap'). :- use_module('attributes.yap'). @@ -334,7 +336,7 @@ If this hook predicate succeeds it must instantiate the _Action_ argument to th :- dynamic user:exception/3. -:- yap_flag(user:unknown,error). +:- yap_flag(unknown,error). :- stream_property(user_input, tty(true)) -> set_prolog_flag(readline, true) ; true. diff --git a/pl/modules.yap b/pl/modules.yap index c26bdd1c4..4af76d0b0 100644 --- a/pl/modules.yap +++ b/pl/modules.yap @@ -1093,7 +1093,6 @@ its parent goal. setup_call_catcher_cleanup(0,0,?,0), spy(:), stash_predicate(:), - unknown(+,:), use_module(:), use_module(:,?), use_module(?,:,?), diff --git a/pl/preds.yap b/pl/preds.yap index f498e1cfe..58036a241 100644 --- a/pl/preds.yap +++ b/pl/preds.yap @@ -892,11 +892,11 @@ abolish(X) :- functor(G,Name,Arity), print_message(warning,no_match(abolish(Module:Name/Arity))). '$abolishs'(G, M) :- - '$is_multifile'(G,M), !, + '$is_multifile'(G,M), functor(G,Name,Arity), - recorded('$mf','$mf_clause'(_,Name,Arity,M,Ref),R), + recorded('$mf','$mf_clause'(_,Name,Arity,M,_Ref),R), erase(R), - erase(Ref), +% no need erase(Ref), fail. '$abolishs'(T, M) :- recorded('$import','$import'(_,M,_,_,T,_,_),R), @@ -1369,81 +1369,3 @@ clause_property(ClauseRef, predicate(PredicateIndicator)) :- @} */ -/** - -@addtogroup Undefined_Procedures -@{ - -*/ - - -/** @pred unknown(- _O_,+ _N_) - - -Specifies an handler to be called is a program tries to call an -undefined static procedure _P_. - -The arity of _N_ may be zero or one. If the arity is `0`, the -new action must be one of `fail`, `warning`, or -`error`. If the arity is `1`, _P_ is an user-defined -handler and at run-time, the argument to the handler _P_ will be -unified with the undefined goal. Note that _N_ must be defined prior -to calling unknown/2, and that the single argument to _N_ must -be unbound. - -In YAP, the default action is to `fail` (note that in the ISO -Prolog standard the default action is `error`). - -After defining `undefined/1` by: - -~~~~~{.prolog} -undefined(A) :- format('Undefined predicate: ~w~n',[A]), fail. -~~~~~ -and executing the goal: - -~~~~~{.prolog} -unknown(U,undefined(X)). -~~~~~ -a call to a predicate for which no clauses were defined will result in -the output of a message of the form: - -~~~~~{.prolog} -Undefined predicate: user:xyz(A1,A2) -~~~~~ -followed by the failure of that call. - - -*/ -unknown(V0, V) :- - strip_module(V, M, G), - recorded('$unknown_handle', M0:G0, R), !, - recordz('$unknown_handle', M:G, _), - erase( R ), - strip_module(V0, M0, G0). -unknown(V0, V) :- - strip_module(V, M, G), - recordz('$unknown_handle', M:G, _), - V0 = fail. - -%%% The unknown predicate, -% informs about what the user wants to be done when -% there are no clauses for a certain predicate */ - -'$unknown_error'(Call) :- - recorded( '$unknown_handle', M:Goal, _), - arg(1, Goal, Call), !, - once(M:Goal). -'$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. - -/** -@} -*/ diff --git a/pl/undefined.yap b/pl/undefined.yap new file mode 100644 index 000000000..0f714e1f2 --- /dev/null +++ b/pl/undefined.yap @@ -0,0 +1,130 @@ +/************************************************************************* +* * +* YAP Prolog * +* * +* Yap Prolog was developed at NCCUP - Universidade do Porto * +* * +* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * +* * +************************************************************************** +* * +* File: undefined.yap * +* Last rev: 8/2/88 * +* mods: * +* comments: Predicate Undefined for YAP * +* * +*************************************************************************/ + +/** @defgroup Undefined_Procedures Handling Undefined Procedures +@ingroup YAPControl +@{ + +A predicate in a module is said to be undefined if there are no clauses +defining the predicate, and if the predicate has not been declared to be +dynamic. What YAP does when trying to execute undefined predicates can +be specified in three different ways: + + ++ By setting an YAP flag, through the yap_flag/2 or +set_prolog_flag/2 built-ins. This solution generalizes the +ISO standard by allowing module-specific behavior. ++ By using the unknown/2 built-in (this deprecated solution is +compatible with previous releases of YAP). ++ By defining clauses for the hook predicate +`user:unknown_predicate_handler/3`. This solution is compatible +with SICStus Prolog. + + +*/ + +'$undefp'([M0|G0], Default) :- + % make sure we do not loop on undefined predicates + % for undefined_predicates. + '$enter_undefp', + ( + '$get_undefined_pred'(G0, M0, Goal, NM) + -> + '$exit_undefp', + Goal \= fail, + '$complete_goal'(M0, G0, Goal, NM, NG), + '$execute0'(NG, NM) + ; + user:unknown_predicate_handler(G0,M0,NG) + -> + call(M:NG) + ; + '$exit_undefp', + '$handle_error'(Default,G0,M0) + ). + + + +/** @pred unknown(- _O_,+ _N_) + +The unknown predicate, informs about what the user wants to be done + when there are no clauses for a certain predicate. + +This predicate is strongly deprecated. Use prolog_flag for generic +behaviour, and user:unknown_predicate_handler/3 for flexible behaviour +on undefined goals. + +*/ + +unknown(P, NP) :- + prolog_flag( unknown, P, NP ). + +/** @pred user:unknown_predicate_handler(+ _Call_, + _M_, - _N_) + +In YAP, the default action on undefined predicates is to output an +`error` message. Alternatives are to silently `fail`, or to print a +`warning` message and then fail. This follows the ISO Prolog standard +where the default action is `error`. + +The user:unknown_predicate_handler/3 hook was originally include in +SICStus Prolog. It allows redefining the answer for specifici +calls. As an example. after defining `undefined/1` by: + +~~~~~{.prolog} +undefined(A) :- format('Undefined predicate: ~w~n',[A]), fail. +~~~~~ +and executing the goal: + +~~~~~{.prolog} +:- assert(user:unknown_predicate_handler(U,M,undefined(M:U)) ) +~~~~~ +a call to a predicate for which no clauses were defined will result in +the output of a message of the form: + +~~~~~{.prolog} +Undefined predicate: user:xyz(A1,A2) +~~~~~ +followed by the failure of that call. + + +*/ +:- multifile user:unknown_predicate_handler/3. + +'$handle_error'(0x0080,Goal,Mod) :- + functor(Goal,Name,Arity), + '$program_continuation'(PMod,PName,PAr), + '$do_error'(existence_error(procedure,Name/Arity),context(Mod:Goal,PMod:PName/PAr)). +'$handle_error'(0x0040,Goal,Mod) :- + functor(Goal,Name,Arity), + '$program_continuation'(PMod,PName,PAr), + print_message(warning,error(existence_error(procedure,Name/Arity), context(Mod:Goal,PMod:PName/PAr))), + fail. +'$handle_error'(0x0020,_Goal,_Mod) :- + fail. + +'$complete_goal'(M, G, CurMod, CurG, NG) :- + ( + '$is_metapredicate'(CurG,CurMod) + -> + '$meta_expansion'(G, M, CurMod, M, NG, []) + ; + NG = G + ). + +/** +@} +*/