fix undefined procedures to allow hooks as before.
This commit is contained in:
parent
b108380cfc
commit
f6bcb22b7c
@ -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)
|
||||
|
14
C/modules.c
14
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
|
||||
|
@ -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));
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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).
|
||||
|
91
pl/boot.yap
91
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)
|
||||
).
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
@ -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.
|
||||
|
||||
|
@ -1093,7 +1093,6 @@ its parent goal.
|
||||
setup_call_catcher_cleanup(0,0,?,0),
|
||||
spy(:),
|
||||
stash_predicate(:),
|
||||
unknown(+,:),
|
||||
use_module(:),
|
||||
use_module(:,?),
|
||||
use_module(?,:,?),
|
||||
|
84
pl/preds.yap
84
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.
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
130
pl/undefined.yap
Normal file
130
pl/undefined.yap
Normal 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
|
||||
).
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
Reference in New Issue
Block a user