fix undefined procedures to allow hooks as before.

This commit is contained in:
Vitor Santos Costa 2014-10-10 10:00:27 +01:00
parent b108380cfc
commit f6bcb22b7c
12 changed files with 156 additions and 189 deletions

View File

@ -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)

View File

@ -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

View File

@ -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));

View File

@ -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 \

View File

@ -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

View File

@ -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");

View File

@ -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).

View File

@ -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)
).
/**
@}
*/

View File

@ -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.

View File

@ -1093,7 +1093,6 @@ its parent goal.
setup_call_catcher_cleanup(0,0,?,0),
spy(:),
stash_predicate(:),
unknown(+,:),
use_module(:),
use_module(:,?),
use_module(?,:,?),

View File

@ -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.
/**
@}
*/

130
pl/undefined.yap Normal file
View File

@ -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
).
/**
@}
*/