/* File:      flrundefined.P  -- Catcher of undefined predicates and methods
**
** Author(s): Chang Zhao
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 2002
** 
** FLORA-2 is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
** 
** FLORA-2 is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
** 
** You should have received a copy of the GNU Library General Public License
** along with FLORA-2; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: flrundefined.P,v 1.11 2003/06/18 07:01:35 kifer Exp $
**
*/


:- compiler_options([xpp_on]).

#include "flora_terms.flh"
#include "flora_exceptions.flh"
#include "flora_porting.flh"

#define MOST_GENERAL	most_general

/***********************************************************************
 * flora_debug_code(+CompileList)
 * Generate facts that will be loaded into fld storage
 * from facts and rule heads
 ***********************************************************************/
flora_debug_code(TermList, File) :-
	retractall(term_seen(_)),
	flora_build_debug_inter_codelist(TermList),
	telling(PreOut),
	tell(File),
	writeln('#include "flrheader.flh"'),
	nl,
	generate_patches,
	told,
	tell(PreOut).

/***********************************************************************
 * flora_build_debug_inter_codelist(+CompileList)
 * patch facts will be asserted into ter_seen(Term) to remove duplicates
 ***********************************************************************/
flora_build_debug_inter_codelist([]) :- !.

flora_build_debug_inter_codelist([T|L]) :-
	flora_build_debug_inter_code(T),
	flora_build_debug_inter_codelist(L).

flora_build_debug_inter_code(Term) :-
	( (is_prrule(Term,Head,_);is_prfact(Term,Head)) ->
	    ( flora_build_debug_skeleton(Head,Code,GFlag) ->
		( var(Code) ->
		    true
		;
		    ( GFlag==MOST_GENERAL ->
			(term_seen(OldTerm), subsumes(OldTerm,Code) ->
			    true
			;
			    retractall(term_seen(Code)),
			    assert(term_seen(Code))
			)
		    ;
	                ( term_seen(Code) ->
	                    true
	                ;
	                    assert(term_seen(Code))
			)
	            )
		)
            ;
	        true
	    )
	; true
	).

/***********************************************************
 * flora_build_debug_skeleton(+Term, -Code, -Flag)
 * builds the intermediate form of the skeletons of all facts
 * and rule heads and returns a flag showing whether the 
 * skeleton is of the most general form, eg. fd's whose second
 * parameter is a variable
 ***********************************************************/
flora_build_debug_skeleton(Term,Atom,_GFlag) :-
	is_pratom(Term,Atom,_Index),
	!.

flora_build_debug_skeleton(Term,_NewVar,MOST_GENERAL) :-
	is_prvariable(Term,_Name,_Index),
	!.

flora_build_debug_skeleton(Term,Sk,GFlag) :-
	is_prterm(Term,FObj,N,_ObjList),
	!,
	( is_pratom(FObj,FAtom,_Index), flora_prlgdef(FAtom,N) ->
	    fail
	;
	    flora_build_debug_skeleton(FObj,FCode,GFlag),
	    var_list(N,ObjListCode),
	    Sk =.. [WRAP_HILOG,FCode|ObjListCode]
	).

flora_build_debug_skeleton(Term,Sk,_GFlag) :-
        is_pratomlit(Term,A,_Index),
	!,
	( flora_prlgdef(A,0) ->
	    fail
        ;
		Sk=WRAP_HILOG(A)
        ).

flora_build_debug_skeleton(Term,Sk,GFlag) :-
	is_prtermlit(Term,FObj,N,_ObjList),
	!,
	( is_pratom(FObj,FAtom,_Index) ->
	    ( flora_prlgdef(FAtom, N) ->
	        fail
	    ;
		    var_list(N,ObjListCode),
		    Sk=..[WRAP_HILOG,FAtom|ObjListCode]
	    )
	;
	    var_list(N,ObjListCode),
	    flora_build_debug_skeleton(FObj,FCode,GFlag),
	    Sk=..[WRAP_HILOG,FCode|ObjListCode]
	).

flora_build_debug_skeleton(PRISA(_Obj1,Obj2),WRAP_ISA(_NewVar,CCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Obj2,CCode,GFlag).

flora_build_debug_skeleton(PRSUB(_Obj1,Obj2),WRAP_SUB(_NewVar,CCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Obj2,CCode,GFlag).

flora_build_debug_skeleton(PRMETH(_Obj1,Meth),WRAP_METH(_NewVar,MCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Meth,MCode,GFlag).

flora_build_debug_skeleton(PRIMETH(_Obj1,IMeth),WRAP_IMETH(_NewVar,MCode),GFlag) :-
	!,
	flora_build_debug_skeleton(IMeth,MCode,GFlag).

flora_build_debug_skeleton(PRFDDEF(_Obj,Attr),WRAP_FDDEF(_NewVar,ACode),GFlag) :-
	!,
	flora_build_debug_skeleton(Attr,ACode,GFlag).

flora_build_debug_skeleton(PRMVDDEF(_Obj,Attr),WRAP_MVDDEF(_NewVar,ACode),GFlag) :-
	!,
	flora_build_debug_skeleton(Attr,ACode,GFlag).

flora_build_debug_skeleton(PRIFDDEF(_Obj,Attr),WRAP_IFDDEF(_NewVar,ACode),GFlag) :-
	!,
	flora_build_debug_skeleton(Attr,ACode,GFlag).

flora_build_debug_skeleton(PRIMVDDEF(_Obj,Attr),WRAP_IMVDDEF(_NewVar,ACode),GFlag) :-
	!,
	flora_build_debug_skeleton(Attr,ACode,GFlag).

flora_build_debug_skeleton(PRTRAN(_Obj,Tran),WRAP_TRAN(_NewVar,TCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Tran,TCode,GFlag).

flora_build_debug_skeleton(PRFD(_Obj,Att,_Val),WRAP_FD(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIFD(_Obj,Att,_Val),WRAP_IFD(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRFDSIG(_Obj,Att,_Val),WRAP_FDSIG(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRMVDSIG(_Obj,Att,_Val),WRAP_MVDSIG(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIFDSIG(_Obj,Att,_Val),WRAP_IFDSIG(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIMVDSIG(_Obj,Att,_Val),WRAP_IMVDSIG(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRMVD(_Obj,Att,_Val),WRAP_MVD(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIMVD(_Obj,Att,_Val),WRAP_IMVD(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRMVDINC(_Obj,Att,_Val),WRAP_MVDINC(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIMVDINC(_Obj,Att,_Val),WRAP_IMVDINC(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRMVDTOLIST(_Obj,Att,_Val),WRAP_MVDTOLIST(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(PRIMVDTOLIST(_Obj,Att,_Val),WRAP_IMVDTOLIST(_OCode,ACode,_VCode),GFlag) :-
	!,
	flora_build_debug_skeleton(Att,ACode,GFlag).

flora_build_debug_skeleton(_, _, _) :-
	!.

/*********************************************
 * generate_patches
 * generate a fact in intermediate form 
 * for each Term asserted in term_seen(Term)
 *********************************************/
generate_patches :-
 	term_seen(Term),
	Term =.. [F|Args],
	flora_write_atom('FLORA_THIS_WORKSPACE('),
	flora_write_quoted_atom(F),
	put(0')),
	put(0'(),
	write_args(Args),
	put(0')),
	put(0'.),
	nl,
	fail.

generate_patches :- !.

write_args([]) :- !.
write_args([A]) :-
	!,
	write_canonical(A).
write_args([H|L]) :-
	write_canonical(H),
	put(0',),
	write_args(L).
 
/***********************************************************
 * utilities for flora_build_skeleton
 ***********************************************************/
is_flogic_2params(WRAP_ISA) :- !.
is_flogic_2params(WRAP_SUB) :- !.
is_flogic_2params(WRAP_METH) :- !.
is_flogic_2params(WRAP_IMETH) :- !.
is_flogic_2params(WRAP_FDDEF) :- !.
is_flogic_2params(WRAP_MVDDEF) :- !.
is_flogic_2params(WRAP_IFDDEF) :- !.
is_flogic_2params(WRAP_IMVDDEF) :- !.
is_flogic_2params(WRAP_TRAN) :- !.

is_flogic_3params(WRAP_FD) :- !.
is_flogic_3params(WRAP_IFD) :- !.
is_flogic_3params(WRAP_FDSIG) :- !.
is_flogic_3params(WRAP_MVDSIG) :- !.
is_flogic_3params(WRAP_IFDSIG) :- !.
is_flogic_3params(WRAP_IMVDSIG) :- !.
is_flogic_3params(WRAP_MVD) :- !.
is_flogic_3params(WRAP_IMVD) :- !.
is_flogic_3params(WRAP_MVDINC) :- !.
is_flogic_3params(WRAP_IMVDINC) :- !.
is_flogic_3params(WRAP_MVDTOLIST) :- !.
is_flogic_3params(WRAP_IMVDTOLIST) :- !.

/***********************************************************
 * flora_build_skeleton(+Term, -Code)
 * builds the skeleton of Term
 * this is similar to flora_build_debug_skeleton, but the 
 * term is not in intermediate form.
 * This predicate is called at run time
 ***********************************************************/
flora_build_skeleton(Term,Term) :-
	atom(Term),
	!.

flora_build_skeleton(Term,Term) :-
	var(Term),
	!.

flora_build_skeleton([Wrap,_Obj1,Obj2],[Wrap,_,CCode]) :-
	is_flogic_2params(Wrap),
	!,
	flora_build_skeleton(Obj2,CCode).

flora_build_skeleton([Wrap,_Obj,Att,_Val],[Wrap,_,ACode,_]) :-
	is_flogic_3params(Wrap),
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton([WRAP_HILOG,F|Arg],[WRAP_HILOG,FSkeleton|VList]) :-
	!,
	length(Arg,N),
	var_list(N, VList),
	flora_build_skeleton(F,FSkeleton).

flora_build_skeleton([F|Arg],[FSkeleton,VList]) :-
	length(Arg,N),
	var_list(N,VList),
	flora_build_skeleton(F,FSkeleton).

flora_build_skeleton(WRAP_ISA(_Obj1,Obj2),WRAP_ISA(_,CCode)) :-
	!,
	flora_build_skeleton(Obj2,CCode).

flora_build_skeleton(WRAP_SUB(_Obj1,Obj2),WRAP_SUB(_,CCode)) :-
	!,
	flora_build_skeleton(Obj2,CCode).

flora_build_skeleton(WRAP_METH(_Obj1,Meth),WRAP_METH(_,MCode)) :-
	!,
	flora_build_skeleton(Meth,MCode).

flora_build_skeleton(WRAP_IMETH(_Obj1,IMeth),WRAP_IMETH(_,MCode)) :-
	!,
	flora_build_skeleton(IMeth,MCode).

flora_build_skeleton(WRAP_FDDEF(_Obj,Attr),WRAP_FDDEF(_,ACode)) :-
	!,
	flora_build_skeleton(Attr,ACode).

flora_build_skeleton(WRAP_MVDDEF(_Obj,Attr),WRAP_MVDDEF(_,ACode)) :-
	!,
	flora_build_skeleton(Attr,ACode).

flora_build_skeleton(WRAP_IFDDEF(_Obj,Attr),WRAP_IFDDEF(_,ACode)) :-
	!,
	flora_build_skeleton(Attr,ACode).

flora_build_skeleton(WRAP_IMVDDEF(_Obj,Attr),WRAP_IMVDDEF(_,ACode)) :-
	!,
	flora_build_skeleton(Attr,ACode).

flora_build_skeleton(WRAP_TRAN(_Obj,Tran),WRAP_TRAN(_,TCode)) :-
	!,
	flora_build_skeleton(Tran,TCode).

flora_build_skeleton(WRAP_FD(_Obj,Att,_Val),WRAP_FD(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IFD(_Obj,Att,_Val),WRAP_IFD(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_FDSIG(_Obj,Att,_Val),WRAP_FDSIG(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_MVDSIG(_Obj,Att,_Val),WRAP_MVDSIG(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IFDSIG(_Obj,Att,_Val),WRAP_IFDSIG(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IMVDSIG(_Obj,Att,_Val),WRAP_IMVDSIG(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_MVD(_Obj,Att,_Val),WRAP_MVD(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IMVD(_Obj,Att,_Val),WRAP_IMVD(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_MVDINC(_Obj,Att,_Val),WRAP_MVDINC(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IMVDINC(_Obj,Att,_Val),WRAP_IMVDINC(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_MVDTOLIST(_Obj,Att,_Val),WRAP_MVDTOLIST(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(WRAP_IMVDTOLIST(_Obj,Att,_Val),WRAP_IMVDTOLIST(_,ACode,_)) :-
	!,
	flora_build_skeleton(Att,ACode).

flora_build_skeleton(Term,Skeleton) :-
	functor(Term, WRAP_HILOG, N),
	!,
	Term =.. [WRAP_HILOG, MainFunct|_Args],
	M is N-1,
	var_list(M, VarList),
	flora_build_skeleton(MainFunct, MainFunctSkeleton),
	Skeleton =.. [WRAP_HILOG, MainFunctSkeleton|VarList].

flora_build_skeleton(Term, Skeleton) :-
	functor(Term, MainFunct, N),
	functor(Skeleton, MainFunct, N).

var_list(0, []) :- !.
var_list(N, [_|Rest]) :-
	M is N-1,
	var_list(M, Rest).

/*****************************************
* flora_define_predicate(+Predicate)
* compute the skeleton of Predcate and insert it to the corresponding trie
* (for the heads of dynamically inserted rules)
*****************************************/
flora_define_predicate(Predicate) :-
        flora_decode_predicate(Predicate,PType,MName,_WPrefix,PSymbol,AList),
        flora_module_type_and_name(MName,ModuleType,ModuleName),
	( (PType==hilog) ->
	    QCode = [WRAP_HILOG,PSymbol|AList]
	;
	    QCode = [PSymbol|AList]
	),
        candidate_list([QCode],ModuleType,ModuleName,[Skeleton]),
        flora_module_storage(ModuleType,ModuleName,fld,FldStorage),
	flora_db_insert_base(FldStorage,Skeleton).

/************************************************************
 * flora_module_type_and_name(+MName,-ModuleType,-ModuleName)
 ************************************************************/
flora_module_type_and_name(MName,ModuleType,ModuleName) :-
	( (MName = flora(ModuleName)) ->
	    ModuleType=system
	;
	    ModuleName=MName,
	    ModuleType=user
	).

/*********************************************************************
 * flora_module_storage(+ModuleType,+ModuleName,+StorageType,-Storage)
 *********************************************************************/
 :- table flora_module_storage/4.
flora_module_storage(ModuleType,ModuleName,StorageType,Storage) :-
	( ModuleType==user ->
            (StorageType==fdb ->
	        flora_concat_atoms([FLORA_USER_FDB_TRIE_PREFIX, ''''], S)
            ;
	        flora_concat_atoms([FLORA_USER_FLD_TRIE_PREFIX, ''''], S)
            )
	;
            (StorageType==fdb ->
	        flora_concat_atoms([FLORA_SYSTEM_FDB_TRIE_PREFIX, ''''], S)
            ;
	        flora_concat_atoms([FLORA_SYSTEM_FLD_TRIE_PREFIX, ''''], S)
            )
	),
	flora_concat_atoms([S, ModuleName],Storage).

/*****************************************************************************
*    flora_temp_protect_call(+Predicate,+Id)
*    flora_temp_unprotect_call(+Id) :-
* +Predicate is the call to be recorded as temporarily protected
*            from the undefinedness check.
* +Id is a unique Id that is used to delete the call from the registry.
*
* This is similar to flora_define_predicate/1 above.
*
* Compute the skeleton of Predcate and insert it to a temporary storage
* to prevent signalling undefinedness errrors. This is used for calls
* like Call@Var in flrdynmod.P, because when Var is a variable then
* undefinedness check for Call doesn't make sense.
*****************************************************************************/
flora_temp_protect_call(Predicate,Id) :-
        flora_decode_predicate(Predicate,PType,MName,_WPrefix,PSymbol,AList),
        flora_module_type_and_name(MName,ModuleType,ModuleName),
	( (PType==hilog) ->
	    QCode = [WRAP_HILOG,PSymbol|AList]
	;
	    QCode = [PSymbol|AList]
	),
        candidate_list([QCode],ModuleType,ModuleName,[Skeleton]),
	assert(flora_disabled_undefinedness_check_registry(MName,Id,Skeleton)).

flora_temp_unprotect_call(Id) :-
	retractall(flora_disabled_undefinedness_check_registry(_,Id,_)).

%% Tell if call is protected
temporarily_protected_call(PredicateSkel) :-
	flora_disabled_undefinedness_check_registry(_Mod,_Id,PredicateSkel).


/****************************************************************************
**  defined_by(+What,-ByWhat)
**  +What is a list that represents a query.
**  -ByWhat is a representation of a rule head that might define the call.
****************************************************************************/
defined_by([WRAP_ISA,X,Y],[WRAP_ISA,X,Y]).
defined_by([WRAP_ISA,X,Y],[WRAP_SUB,X,Y]).
defined_by([WRAP_SUB,X,Y],[WRAP_SUB,X,Y]).
defined_by([WRAP_METH,X,Y],[WRAP_METH,X,Y]).
defined_by([WRAP_METH,X,Y],[WRAP_IMETH,X,Y]).
defined_by([WRAP_IMETH,X,Y],[WRAP_IMETH,X,Y]).
defined_by([WRAP_FD,X,Y,Z],[WRAP_FD,X,Y,Z]).
defined_by([WRAP_FD,X,Y,Z],[WRAP_IFD,X,Y,Z]).
defined_by([WRAP_IFD,X,Y,Z],[WRAP_IFD,X,Y,Z]).
defined_by([WRAP_FDDEF,X,Y],[WRAP_FD,X,Y,_Z]).
defined_by([WRAP_FDDEF,X,Y],[WRAP_IFD,X,Y,_Z]).
defined_by([WRAP_IFDDEF,X,Y],[WRAP_IFD,X,Y,_Z]).
defined_by([WRAP_FDSIG,X,Y,Z],[WRAP_FDSIG,X,Y,Z]).
defined_by([WRAP_FDSIG,X,Y,Z],[WRAP_IFDSIG,X,Y,Z]).
defined_by([WRAP_FDSIGDEF,X,Y],[WRAP_FDSIGDEF,X,Y]).
defined_by([WRAP_FDSIGDEF,X,Y],[WRAP_IFDSIGDEF,X,Y]).
defined_by([WRAP_IFDSIG,X,Y,Z],[WRAP_IFDSIG,X,Y,Z]).
defined_by([WRAP_IFDSIGDEF,X,Y],[WRAP_IFDSIGDEF,X,Y]).
defined_by([WRAP_MVD,X,Y,Z],[WRAP_MVD,X,Y,Z]).
defined_by([WRAP_MVD,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_MVD,X,Y,_Z],[WRAP_MVDDEF,X,Y]).
defined_by([WRAP_MVD,X,Y,_Z],[WRAP_IMVDDEF,X,Y]).
defined_by([WRAP_IMVD,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_IMVD,X,Y,_Z],[WRAP_IMVDDEF,X,Y]).
defined_by([WRAP_MVDDEF,X,Y],[WRAP_MVD,X,Y,_Z]).
defined_by([WRAP_MVDDEF,X,Y],[WRAP_IMVD,X,Y,_Z]).
defined_by([WRAP_MVDDEF,X,Y],[WRAP_MVDDEF,X,Y]).
defined_by([WRAP_MVDDEF,X,Y],[WRAP_IMVDDEF,X,Y]).
defined_by([WRAP_IMVDDEF,X,Y],[WRAP_IMVD,X,Y,_Z]).
defined_by([WRAP_IMVDDEF,X,Y],[WRAP_IMVDDEF,X,Y]).
defined_by([WRAP_MVDSIG,X,Y,Z],[WRAP_MVDSIG,X,Y,Z]).
defined_by([WRAP_MVDSIG,X,Y,Z],[WRAP_IMVDSIG,X,Y,Z]).
defined_by([WRAP_IMVDSIG,X,Y,Z],[WRAP_IMVDSIG,X,Y,Z]).
defined_by([WRAP_MVDSIGDEF,X,Y],[WRAP_MVDSIGDEF,X,Y]).
defined_by([WRAP_MVDSIGDEF,X,Y],[WRAP_IMVDSIGDEF,X,Y]).
defined_by([WRAP_IMVDSIGDEF,X,Y],[WRAP_IMVDSIGDEF,X,Y]).
defined_by([WRAP_MVDINC,X,Y,Z],[WRAP_MVD,X,Y,Z]).
defined_by([WRAP_MVDINC,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_IMVDINC,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_MVDTOLIST,X,Y,Z],[WRAP_MVD,X,Y,Z]).
defined_by([WRAP_MVDTOLIST,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_IMVDTOLIST,X,Y,Z],[WRAP_IMVD,X,Y,Z]).
defined_by([WRAP_TRAN,X,Y],[WRAP_TRAN,X,Y]).

candidate_list([],_ModuleType,_ModuleName,[]) :- !.
candidate_list([QCode|Rest],ModuleType,ModuleName,[QSk|CanRest]) :-
   	flora_build_skeleton(QCode,QSkeleton),
	QSkeleton = [QFunct|QArgs],
	( ModuleType==user ->
	    flora_concat_atoms([FLORA_USER_MODULE_PREFIX, ''''], F)
	;
	    flora_concat_atoms([FLORA_SYSTEM_MODULE_PREFIX, ''''], F)
	),
	flora_concat_atoms([F,ModuleName,'''',QFunct],QNewFunct),
	QSk =.. [QNewFunct|QArgs],
        candidate_list(Rest,ModuleType,ModuleName,CanRest).

check_candidate_list([QSk|L],FdbStorage,Q) :-
	flora_db_find_base(FdbStorage,QSk),!,Q=QSk;
        check_candidate_list(L,FdbStorage,Q).

%% Check skeletons in the candidate list against temporarily protected calls
%% Succeeds, if matches
check_temporarily_protected_calls([QSk|L]) :-
	temporarily_protected_call(QSk), !;
	check_temporarily_protected_calls(L).

/*****************************************
* flora_error_undefined(+Predicate)
* if a fact with the same skeleton as
* Predicate, then it is not really
* undefined(fact is inserted at run time)
* else print 'undefined predicate message
*****************************************/
flora_error_undefined(Predicate) :-
	flora_decode_predicate(Predicate, PType, MName,
			       _WPrefix, PSymbol, AList),
        flora_module_type_and_name(MName,ModuleType,ModuleName),
        flora_module_storage(ModuleType,ModuleName,fld,FldStorage),
        flora_module_storage(ModuleType,ModuleName,fdb,FdbStorage),
	( (PType==hilog) ->
	    QCode = [WRAP_HILOG,PSymbol|AList],
            candidate_list([QCode],ModuleType,ModuleName,CanList)
	;
            findall(QCode,defined_by([PSymbol|AList],QCode),QCodeList),
            candidate_list(QCodeList,ModuleType,ModuleName,CanList)
	),

	(check_candidate_list(CanList,FdbStorage,QSk) ->
	    flora_decode_predicate(QSk, _PT, _MN, _WPrefix, _PS, FAList),
	    ( (PType==hilog) ->
	        FCode = [WRAP_HILOG,PSymbol|FAList]
	    ;
	        FCode = [PSymbol|FAList]
	    ),
   	    flora_build_skeleton(FCode,FSkeleton),
	    FSkeleton = [_FFunct|FArgs],
	    QSk =.. [QNewFunct|_QArgs],
	    FSk =.. [QNewFunct|FArgs],
	    flora_db_insert_base(FldStorage,FSk),
	    !,
	    fail
	; check_temporarily_protected_calls(CanList) -> fail
	;
	    predicate_msg(PSymbol, AList, PMsg),
	    ( PType==flogic, (PSymbol==WRAP_ISA ; PSymbol==WRAP_SUB) ->
		TypeMsg = 'Undefined class'
	    ; PType==flogic ->
	 	TypeMsg = 'Undefined method'
	    ;
		TypeMsg = 'Undefined predicate'
	    ),
	    ( MName=flora(Name) ->
		flora_concat_items([TypeMsg,' ',PMsg,' in system module ',Name],
				   ErrorMsg)
	    ;
		flora_concat_items([TypeMsg,' ',PMsg,' in user module ',MName],
				   ErrorMsg)
	    )
	),
	close_open_tables,
	throw(FLORA_UNDEFINED_EXCEPTION(Predicate,ErrorMsg)).

/**************************************************
 * predicate_msg(+PredicateSymbol, +ArgList, -PMsg)
 * generate a string from the predicate which is
 * more readable to the user
 **************************************************/
predicate_msg(Term,Term) :-
	atom(Term),
	!.

predicate_msg(Term,'_') :-
	var(Term),
	!.

predicate_msg(Term,PMsg) :-
	Term =.. [WRAP_HILOG,MainFunct|ArgList],
	!,
	predicate_msg(MainFunct, FMsg),
	( ArgList = [] ->
	    PMsg = FMsg
	;
	    varlist_to_str(ArgList, VMsg),
	    flora_concat_atoms([FMsg,'(',VMsg,')'],PMsg)
	).

predicate_msg(WRAP_ISA,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_:', O2Msg],PMsg).

predicate_msg(WRAP_SUB,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_::', O2Msg],PMsg).

predicate_msg(WRAP_METH,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_[',O2Msg,']'],PMsg).

predicate_msg(WRAP_IMETH,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_[*',O2Msg,']'],PMsg).

predicate_msg(WRAP_FDDEF,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_.',O2Msg,'[]'],PMsg).

predicate_msg(WRAP_MVDDEF,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_..',O2Msg,'[]'],PMsg).

predicate_msg(WRAP_IFDDEF,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_!',O2Msg,'[]'],PMsg).

predicate_msg(WRAP_IMVDDEF,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_!!',O2Msg,'[]'],PMsg).

predicate_msg(WRAP_TRAN,[_O1, O2], PMsg) :-
	!,
	predicate_msg(O2, O2Msg),
	flora_concat_atoms(['_[#',O2Msg,']'],PMsg).

predicate_msg(WRAP_FD, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'->_]'],PMsg).

predicate_msg(WRAP_IFD, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'*->_]'],PMsg).

predicate_msg(WRAP_FDSIG, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'=>_]'],PMsg).

predicate_msg(WRAP_MVDSIG, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'=>>_]'],PMsg).

predicate_msg(WRAP_IFDSIG, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'*=>_]'],PMsg).

predicate_msg(WRAP_IMVDSIG, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'*=>>_]'],PMsg).

predicate_msg(WRAP_MVD, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'->>_]'],PMsg).

predicate_msg(WRAP_IMVD, [_Obj, Att, _Val], PMsg) :- 
	!,
	predicate_msg(Att,AMsg),
	flora_concat_atoms(['_[',AMsg,'*->>_]'],PMsg).

predicate_msg(PredicateSymbol, ArgList, PMsg) :-
	predicate_msg(PredicateSymbol, PredMsg),
	varlist_count(ArgList, N),
	flora_concat_items([PredMsg,'/',N],PMsg).

/*****************************************************
 * varlist_to_str(+List, -String)
 * produce a string of underscores seperated by comma
 * the number of underscores is the same as the number
 * of elements in the input list
 *****************************************************/
varlist_to_str([_], '_') :- !.
varlist_to_str([_H|T], Str) :-
	varlist_to_str(T, RestStr),
	flora_concat_atoms(['_,',RestStr],Str).

/*****************************************************
 * varlist_count(+List, -Number)
 * count the number of elements in a list
 *****************************************************/
varlist_count([], 0) :- !.
varlist_count([_H|T], M) :-
	varlist_count(T, N),
	M is N+1.



syntax highlighted by Code2HTML, v. 0.9.1