/*************************************************************************
*									 *
*	 YAP Prolog 							 *
*									 *
*	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
*									 *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
*									 *
**************************************************************************
*									 *
* File:		modules.pl						 *
* Last rev:								 *
* mods:									 *
* comments:	module support						 *
*									 *
*************************************************************************/

% module handling

use_module(M) :-
	'$use_module'(M).

'$use_module'(V) :- var(V), !,
	'$do_error'(instantiation_error,use_module(V)).
'$use_module'([]) :- !.
'$use_module'([A|B]) :- !,
	'$use_module'(A),
	'$use_module'(B).
'$use_module'(M:F) :- atom(M), !,
        '$current_module'(M0),
        '$change_module'(M),
        '$use_module'(F),
        '$change_module'(M0).
'$use_module'(File) :- 
	'$find_in_path'(File,X,use_module(File)), !,
	(  recorded('$module','$module'(_,X,Publics),_) ->
		'$use_module'(File,Publics)
	;
		'$ensure_loaded'(File)
	).
'$use_module'(File) :-
	'$do_error'(permission_error(input,stream,File),use_module(File)).
	

use_module(File,I) :-
	'$use_module'(File, I).

'$use_module'(File,Imports) :- var(File), !,
	'$do_error'(instantiation_error,use_module(File,Imports)).
'$use_module'(File,Imports) :- var(Imports), !,
	'$do_error'(instantiation_error,use_module(File,Imports)).	
'$use_module'(M:F, Imports) :- atom(M), !,
        '$current_module'(M0),
        '$change_module'(M),
        '$use_module'(F, Imports),
        '$change_module'(M0).
'$use_module'(File,Imports) :-
	'$current_module'(M),
	'$find_in_path'(File,X,use_module(File,Imports)), !,
	'$open'(X,'$csult',Stream,0), !,
	( '$loaded'(Stream,M,TrueFileName) -> true
	     ;
	       % the following avoids import of all public predicates
	     '$consulting_file_name'(Stream,TrueFileName),
	     recorda('$importing','$importing'(TrueFileName),R),
	     '$reconsult'(File,M,Stream)
	 ),
	 '$close'(Stream),
	 ( var(R) -> true; erased(R) -> true; erase(R)),
	 ( recorded('$module','$module'(TrueFileName,Mod,Publics),_) ->
	     '$use_preds'(Imports,Publics,Mod,M)
	 ;

	  true
	 ).
'$use_module'(File,Imports) :-
	'$do_error'(permission_error(input,stream,File),use_module(File,Imports)).
	
use_module(Mod,F,I) :-
	'$use_module'(Mod,F,I).

'$use_module'(Module,V,Imports) :- var(V), !,
	'$use_module'(Module,Module,Imports).
'$use_module'(Module,M:File,Imports) :-
	atom(M), !,
        '$current_module'(M0),
        '$change_module'(M),
        '$use_module'(Module,File,Imports),
        '$change_module'(M0).
'$use_module'(Module,File,Imports) :-
	'$find_in_path'(File,X,use_module(Module,File,Imports)),
	'$open'(X,'$csult',Stream,0), !,
	'$current_module'(M),
	'$file_name'(Stream,FName),
	(
	  '$loaded'(Stream, M, TrueFileName)
	  ->
	  true
	;
	  '$consulting_file_name'(Stream,TrueFileName),
	  % the following avoids import of all public predicates
	  recorda('$importing','$importing'(TrueFileName),R),
	  '$reconsult'(File,M,Stream)
	  ),
	'$close'(Stream),
	( var(R) -> true; erased(R) -> true; erase(R)),
	(
	  recorded('$module','$module'(TrueFileName,Module,Publics),_)
	  ->
	  '$use_preds'(Imports,Publics,Module,M)
	  ;
	  true
	).
'$use_module'(Module,File,Imports) :-
	'$do_error'(permission_error(input,stream,File),use_module(Module,File,Imports)).
	
'$consulting_file_name'(Stream,F)  :-
	'$file_name'(Stream, F).


'$module'(_,N,P) :-
	'$module_dec'(N,P).

'$module'(O,N,P,Opts) :- !,
	'$module'(O,N,P),
	'$process_module_decls_options'(Opts,module(Opts,N,P)).

	
'$process_module_decls_options'(Var,Mod) :-
	var(Var), !,
	'$do_error'(instantiation_error,Mod).
'$process_module_decls_options'([],_) :- !.
'$process_module_decls_options'([H|L],M) :- !,
	'$process_module_decls_option'(H,M),
	'$process_module_decls_options'(L,M).
'$process_module_decls_options'(T,M) :-
	'$do_error'(type_error(list,T),M).

'$process_module_decls_option'(Var,M) :- 
	var(Var), 
	'$do_error'(instantiation_error,M).
'$process_module_decls_option'(At,_) :- 
	atom(At), !,
	'$use_module'(At).
'$process_module_decls_option'(library(L),_) :- !,
	'$use_module'(library(L)).
'$process_module_decls_option'(hidden(Bool),M) :- !,
	'$process_hidden_module'(Bool, M).
'$process_module_decls_option'(Opt,M) :- 
	'$do_error'(domain_error(module_decl_options,Opt),M).

'$process_hidden_module'(TNew,M) :-
        '$convert_true_off_mod3'(TNew, New, M),
	source_mode(Old, New),
	'$prepare_restore_hidden'(Old,New).

'$convert_true_off_mod3'(true, off, _).
'$convert_true_off_mod3'(false, on, _).
'$convert_true_off_mod3'(X, _, M) :-
	'$do_error'(domain_error(module_decl_options,hidden(X)),M).

'$prepare_restore_hidden'(Old,Old) :- !.
'$prepare_restore_hidden'(Old,New) :-
	recorda('$system_initialisation', source_mode(New,Old), _).

module(N) :-
	var(N), 
	'$do_error'(instantiation_error,module(N)).
module(N) :-
	atom(N), !,
	% set it as current module.
	'$current_module'(_,N).
module(N) :-
	'$do_error'(type_error(atom,N),module(N)).

'$module_dec'(N,P) :-
	'$current_module'(Old,N),
	get_value('$consulting_file',F),
	'$add_module_on_file'(N, F, P),
	( recorded('$importing','$importing'(F),_) ->
	         true
	;
	 	'$import'(P,N,Old)
	).

'$add_module_on_file'(Mod, F, Exports) :-
	recorded('$module','$module'(F0,Mod,_),R), !,
	'$add_preexisting_module_on_file'(F, F0, Mod, Exports, R).
'$add_module_on_file'(Mod, F, Exports) :-
	recorda('$module','$module'(F,Mod,Exports),_).

% redefining a previously-defined file, no problem.
'$add_preexisting_module_on_file'(F, F, Mod, Exports, R) :- !,
	erase(R),
	( recorded('$import','$import'(M,T,_,_),R), erase(R), fail; true),
	recorda('$module','$module'(F,Mod,Exports),_).
'$add_preexisting_module_on_file'(F,F0,Mod,Exports,R) :-
	repeat,
	format(user_error, "The module ~a is being redefined.~n    Old file:  ~a~n    New file:  ~a~nDo you really want to redefine it? (y or n)",[Mod,F0,F]),
	'$mod_scan'(C), !,
	( C is "y" ->
	    '$add_preexisting_module_on_file'(F, F, Mod, Exports, R)
	 ;
	    '$do_error'(permission_error(module,redefined,Mod),module(Mod,Exports))
	).

'$mod_scan'(C) :-
	get0(C),
	'$skipeol'(C),
	(C is "y" ; C is "n").

'$import'([],_,_) :- !.
'$import'([N/K|L],M,T) :-
	integer(K), atom(N), !,
	( '$check_import'(M,T,N,K) ->
	     ( T = user ->
	       ( recordzifnot('$import','$import'(M,user,N,K),_) -> true ; true)
             ;
	       ( recordaifnot('$import','$import'(M,T,N,K),_) -> true ; true )
             )
	 ;
	    true
	),
	'$import'(L,M,T).
'$import'([PS|L],M,T) :-
	'$do_error'(domain_error(predicate_spec,PS),import([PS|L])).

'$check_import'(M,T,N,K) :-
    recorded('$import','$import'(M1,T,N,K),R), M1 \= M, /* ZP */ !,
    format(user_error,"NAME CLASH: ~w was already imported to module ~w;~n",[M1:N/K,T]),
    format(user_error,"            Do you want to import it from ~w ? [y or n] ",M),
    repeat,
	get0(C), '$skipeol'(C),
	( C is "y" -> erase(R), !;
	  C is "n" -> !, fail;
	  write(user_error, ' Please answer with ''y'' or ''n'' '), fail
	).
'$check_import'(_,_,_,_).

% $use_preds(Imports,Publics,Mod,M)
'$use_preds'(M:L,Publics,Mod,_) :-
	'$use_preds'(L,Publics,Mod,M).
'$use_preds'([],_,_,_) :- !.
'$use_preds'([P|Ps],Publics,Mod,M) :- !,
	'$use_preds'(P,Publics,Mod,M),
	'$use_preds'(Ps,Publics,Mod,M).
'$use_preds'(N/K,Publics,M,Mod) :-
    (  '$member'(N/K,Publics) -> true ;
	print_message(warning,import(N/K,Mod,M,private))
    ),
    ( '$check_import'(M,Mod,N,K) -> 
	%	     format(user_error,'[ Importing ~w to ~w]~n',[M:N/K,Mod]),
        %            '$trace_module'(importing(M:N/K,Mod)),
	  (Mod = user ->
             ( recordzifnot('$import','$import'(M,user,N,K),_) -> true ; true )
	     ;
	     ( recordaifnot('$import','$import'(M,Mod,N,K),_) -> true ; true )
          )
	 ;
	   true
    ). 

% expand module names in a clause
'$module_expansion'(((Mod:H) :-B ),((Mod:H) :- B1),((Mod:H) :- BO),M) :- !,
	'$prepare_body_with_correct_modules'(B, M, B0),
	'$module_u_vars'(H,UVars,M),	 % collect head variables in
					 % expanded positions
	'$module_expansion'(B0,B1,BO,M,M,M,UVars). % expand body
'$module_expansion'((H:-B),(H:-B1),(H:-BO),M) :-
	'$module_u_vars'(H,UVars,M),	 % collect head variables in
					 % expanded positions
	'$module_expansion'(B,B1,BO,M,M,M,UVars). % expand body
%	$trace_module((H:-B),(H:-B1)).

% expand module names in a body
'$prepare_body_with_correct_modules'(V,M,call(M:V)) :- var(V), !.
'$prepare_body_with_correct_modules'((A,B),M,(A1,B1)) :- !,
	'$prepare_body_with_correct_modules'(A,M,A1),
	'$prepare_body_with_correct_modules'(B,M,B1).
'$prepare_body_with_correct_modules'((A;B),M,(A1;B1)) :- !,
	'$prepare_body_with_correct_modules'(A,M,A1),
	'$prepare_body_with_correct_modules'(B,M,B1).
'$prepare_body_with_correct_modules'((A->B),M,(A1->B1)) :- !,
	'$prepare_body_with_correct_modules'(A,M,A1),
	'$prepare_body_with_correct_modules'(B,M,B1).
'$prepare_body_with_correct_modules'(true,_,true) :- !.
'$prepare_body_with_correct_modules'(fail,_,fail) :- !.
'$prepare_body_with_correct_modules'(false,_,false) :- !.
'$prepare_body_with_correct_modules'(M:G,_,M:G) :- !.
'$prepare_body_with_correct_modules'(G,M,G) :-
	'$system_predicate'(G,M), !.
'$prepare_body_with_correct_modules'(G,M,M:G).


'$trace_module'(X) :-
	telling(F),
	tell('P0:debug'),
	write(X),nl,
	tell(F), fail.
'$trace_module'(_).

'$trace_module'(X,Y) :- X==Y, !.
'$trace_module'(X,Y) :-
	telling(F),
	tell('~/.dbg.modules'),
	write('***************'), nl,
	portray_clause(X),
	portray_clause(Y),
	tell(F),fail.
'$trace_module'(_,_).

	
% expand module names in a body
% args are:
%       goals to expand
%       code to pass to compiler
%       code to pass to listing
%       current module for looking up preds
%       current module for fixing up meta-call arguments
%       current module for predicate
%       head variables.
'$module_expansion'(V,call(MM:V),call(MM:V),_M,MM,_TM,_) :- var(V), !.
'$module_expansion'((A,B),(A1,B1),(AO,BO),M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars),
	'$module_expansion'(B,B1,BO,M,MM,TM,HVars).
'$module_expansion'((A;B),(A1;B1),(AO;BO),M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars),
	'$module_expansion'(B,B1,BO,M,MM,TM,HVars).
'$module_expansion'((A|B),(A1|B1),(AO|BO),M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars),
	'$module_expansion'(B,B1,BO,M,MM,TM,HVars).
'$module_expansion'((A->B),(A1->B1),(AO->BO),M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars),
	'$module_expansion'(B,B1,BO,M,MM,TM,HVars).
'$module_expansion'(\+A,\+A1,\+AO,M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars).
'$module_expansion'(not(A),not(A1),not(AO),M,MM,TM,HVars) :- !,
	'$module_expansion'(A,A1,AO,M,MM,TM,HVars).
'$module_expansion'(true,true,true,_,_,_,_) :- !.
'$module_expansion'(fail,fail,fail,_,_,_,_) :- !.
'$module_expansion'(false,false,false,_,_,_,_) :- !.
% if I don't know what the module is, I cannot do anything to the goal,
% so I just put a call for later on.
'$module_expansion'(M:G,call(M:G),call(M:G),_,_,_,_) :- var(M), !.
'$module_expansion'(M:G,G1,GO,_,_,TM,HVars) :-
	'$module_expansion'(G,G1,GO,M,M,TM,HVars).
% if M1 is given explicitly process G within M1's context.
% '$module_expansion'(M:G,G1,GO,_Mod,_MM,TM,HVars) :- !,
% 	% is this imported from some other module M1?
% 	( '$imported_pred'(G, M, M1) ->
% 	    % continue recursively...
% 	    '$module_expansion'(G,G1,GO,M1,M,TM,HVars)
% 	;
% 	  (
% 	      '$meta_expansion'(M, M, G, NG, HVars)
% 	  ;
% 	      G = NG
% 	  ),
% 	  '$complete_goal_expansion'(NG, M, M, TM, G1, GO, HVars)
% 	).
%
% next, check if this is something imported.
%
'$module_expansion'(G, G1, GO, CurMod, MM, TM, HVars) :-
	% is this imported from some other module M1?
	( '$imported_pred'(G, CurMod, M1) ->
	    '$module_expansion'(G, G1, GO, M1, MM, TM, HVars)
	;
	( '$meta_expansion'(CurMod, MM, G, GI, HVars)
          ;
          GI = G
        ),
	'$complete_goal_expansion'(GI, CurMod, MM, TM, G1, GO, HVars)
	).


'$imported_pred'(G, ImportingMod, ExportingMod) :-
	'$undefined'(G, ImportingMod),
	functor(G,F,N),
	recorded('$import','$import'(ExportingMod,ImportingMod,F,N),_),
	ExportingMod \= ImportingMod.

% args are:
%       goal to expand
%       current module for looking up pred
%       current module from top-level clause
%       goal to pass to compiler
%       goal to pass to listing
%       head variables.
'$complete_goal_expansion'(G, M, CM, TM, G1, G2, HVars) :-
	'$pred_goal_expansion_on',
	user:goal_expansion(G,M,GI), !,
	'$module_expansion'(GI,G1,G2,M,CM,TM,HVars).
'$complete_goal_expansion'(G, M, CM, TM, G1, G2, HVars) :-
	'$system_predicate'(G,M), !,
	'$c_built_in'(G,M,Gi),
	(Gi \== G ->
	   '$module_expansion'(Gi,_,G2,M,CM,TM,HVars),
	    % make built-in processing transparent.
	    (TM = M -> G1 = G ; G1 = M:G)
	 ; TM = M ->
	    G2 = G, G1 = G
	;
	    G2 = M:G, G1 = M:G % atts:
	).
'$complete_goal_expansion'(G, Mod, _, Mod, G, G, _) :- !.
'$complete_goal_expansion'(G, GMod, _, _, GMod:G, GMod:G, _).

% meta_predicate declaration
% records $meta_predicate(SourceModule,Functor,Arity,Declaration)

% directive now meta_predicate Ps :- $meta_predicate(Ps).

:- dynamic_predicate('$meta_predicate'/4,logical).

:- multifile '$meta_predicate'/4.

'$meta_predicate'((P,Ps), M) :- !, 
	'$meta_predicate'(P, M),
	'$meta_predicate'(Ps, M).
'$meta_predicate'(M:D, _) :- !,
	'$meta_predicate'(D, M).
'$meta_predicate'(P, M1) :-
	'$install_meta_predicate'(P, M1).


'$install_meta_predicate'(P, M1) :-
	functor(P,F,N),
	( M1 = prolog -> M = _ ; M1 = M),
	( retractall('$meta_predicate'(F,M,N,_)), fail ; true),
	asserta(prolog:'$meta_predicate'(F,M,N,P)),
	'$flags'(P, M1, Fl, Fl),
	NFlags is Fl \/ 0x200000,
	'$flags'(P, M1, Fl, NFlags).

% return list of vars in expanded positions on the head of a clause.
%
% these variables should not be expanded by meta-calls in the body of the goal.
%
'$module_u_vars'(H,UVars,M) :-
	functor(H,F,N),
	'$meta_predicate'(F,M,N,D), !,
	'$module_u_vars'(N,D,H,UVars).
'$module_u_vars'(_,[],_).

'$module_u_vars'(0,_,_,[]) :- !.
'$module_u_vars'(I,D,H,[Y|L]) :-
	arg(I,D,X), ( X=':' ; integer(X)),
	arg(I,H,Y), var(Y), !,
	I1 is I-1,
	'$module_u_vars'(I1,D,H,L).
'$module_u_vars'(I,D,H,L) :-
	I1 is I-1,
	'$module_u_vars'(I1,D,H,L).

% expand arguments of a meta-predicate
% $meta_expansion(ModuleWhereDefined,CurrentModule,Goal,ExpandedGoal,MetaVariables)

'$meta_expansion'(Mod,MP,G,G1,HVars) :- 
	functor(G,F,N),
	'$meta_predicate'(F,Mod,N,D), !,
	functor(G1,F,N),
	'$meta_expansion_loop'(N,D,G,G1,HVars,MP).
%	format(user_error," gives ~w~n]",[G1]).

% expand argument
'$meta_expansion_loop'(0,_,_,_,_,_) :- !.
'$meta_expansion_loop'(I,D,G,G1,HVars,M) :- 
	arg(I,D,X), (X==':' ; integer(X)),
	arg(I,G,A), '$do_expand'(A,HVars), !,
	'$process_expanded_arg'(A, M, NA),
	arg(I,G1,NA),
	I1 is I-1,
	'$meta_expansion_loop'(I1,D,G,G1,HVars,M).
'$meta_expansion_loop'(I,D,G,G1,HVars,M) :- 
	arg(I,G,A),
	arg(I,G1,A),
	I1 is I-1,
	'$meta_expansion_loop'(I1,D,G,G1,HVars,M).

% check if an argument should be expanded
'$do_expand'(V,HVars) :- var(V), !, '$not_in_vars'(V,HVars).
'$do_expand'(_:_,_) :- !, fail.
'$do_expand'(_,_).

'$process_expanded_arg'(V, M, M:V) :- var(V), !.
'$process_expanded_arg'((V1,V2), M, (NV1,NV2)) :- !,
	'$process_expanded_arg'(V1, M, NV1),
	'$process_expanded_arg'(V2, M, NV2).
'$process_expanded_arg'((V1;V2), M, (NV1;NV2)) :- !,
	'$process_expanded_arg'(V1, M, NV1),
	'$process_expanded_arg'(V2, M, NV2).
'$process_expanded_arg'((V1|V2), M, (NV1|NV2)) :- !,
	'$process_expanded_arg'(V1, M, NV1),
	'$process_expanded_arg'(V2, M, NV2).
'$process_expanded_arg'((V1->V2), M, (NV1->NV2)) :- !,
	'$process_expanded_arg'(V1, M, NV1),
	'$process_expanded_arg'(V2, M, NV2).
'$process_expanded_arg'(\+V, M, \+NV) :- !,
	'$process_expanded_arg'(V, M, NV).
'$process_expanded_arg'(M:A, _, M:A) :- !.
%'$process_expanded_arg'(G, M, G) :-
%	'$system_predicate'(G,M), !.
'$process_expanded_arg'(A, M, M:A).
	
'$not_in_vars'(_,[]).
'$not_in_vars'(V,[X|L]) :- X\==V, '$not_in_vars'(V,L).

current_module(Mod) :-
	'$all_current_modules'(Mod).

current_module(Mod,TFN) :-
	'$all_current_modules'(Mod),
	( recorded('$module','$module'(TFN,Mod,_Publics),_) -> true ; TFN = user ).

source_module(Mod) :-
	'$current_module'(Mod).

'$member'(X,[X|_]) :- !.
'$member'(X,[_|L]) :- '$member'(X,L).

% comma has its own problems.
:- '$install_meta_predicate'((:,:), prolog).

:- meta_predicate
	abolish(:),
	abolish(:,+),
	all(?,:,?),
	assert(:),
	assert(:,+),
	assert_static(:),
	asserta(:),
	asserta(:,+),
	asserta_static(:),
	assertz(:),
	assertz(:,+),
	assertz_static(:),
	bagof(?,:,?),
	bb_get(:,-),
	bb_put(:,+),
	bb_delete(:,?),
	bb_update(:,?,?),
	call(:),
	call_with_args(:),
	call_with_args(:,?),
	call_with_args(:,?,?),
	call_with_args(:,?,?,?),
	call_with_args(:,?,?,?,?),
	call_with_args(:,?,?,?,?,?),
	call_with_args(:,?,?,?,?,?,?),
	call_with_args(:,?,?,?,?,?,?,?),
	call_with_args(:,?,?,?,?,?,?,?,?),
	call_with_args(:,?,?,?,?,?,?,?,?,?),
	call_residue(:,?),
	catch(:,+,:),
	clause(:,?),
	clause(:,?,?),
	compile(:),
	consult(:),
	current_predicate(:),
	current_predicate(?,:),
	depth_bound_call(:,+),
	ensure_loaded(:),
	findall(?,:,?),
	findall(?,:,?,?),
	freeze(?,:),
	hide_predicate(:),
	if(:,:,:),
	incore(:),
	listing(:),
	nospy(:),
        not(:),
        once(:),
        phrase(:,?),
        phrase(:,?,+),
	predicate_property(:,?),
	predicate_statistics(:,-,-,-),
	on_exception(+,:,:),
	reconsult(:),
	retract(:),
	retract(:,?),
	retractall(:),
	reconsult(:),
	setof(?,:,?),
	spy(:),
	unknown(+,:),
	use_module(:),
	use_module(:,?),
	use_module(?,:,?),
	when(?,:),
	^(+,:),
	\+ : .

%
% if we are asserting something in somewhere else's module,
% we need this little bird.
%
% assert((a:g :- b)) then SICStus compiles this into the original module.
% YAP is not 100% compatible, as it will transform this into:
%    a:assert(g :- user:b))
%
'$preprocess_clause_before_mod_change'((H:-B),M,M1,(H:-B1)) :-
	'$module_u_vars'(H,UVars,M1),
	'$preprocess_body_before_mod_change'(B,M,UVars,B1).

'$preprocess_body_before_mod_change'(V,M,_,call(M:V)) :- var(V), !.
'$preprocess_body_before_mod_change'((G1,G2),M,UVars,(NG1,NG2)) :- !,
	'$preprocess_body_before_mod_change'(G1,M,UVars,NG1),
	'$preprocess_body_before_mod_change'(G2,M,UVars,NG2).
'$preprocess_body_before_mod_change'((G1;G2),M,UVars,(NG1;NG2)) :- !,
	'$preprocess_body_before_mod_change'(G1,M,UVars,NG1),
	'$preprocess_body_before_mod_change'(G2,M,UVars,NG2).
'$preprocess_body_before_mod_change'((G1->G2),M,UVars,(NG1->NG2)) :- !,
	'$preprocess_body_before_mod_change'(G1,M,UVars,NG1),
	'$preprocess_body_before_mod_change'(G2,M,UVars,NG2).
'$preprocess_body_before_mod_change'(M:G,_,_,M:G) :- !.
'$preprocess_body_before_mod_change'(true,_,_,true) :- !.
'$preprocess_body_before_mod_change'(fail,_,_,fail) :- !.
'$preprocess_body_before_mod_change'(false,_,_,false) :- !.
'$preprocess_body_before_mod_change'(G,M,UVars,M:NG) :-
	'$meta_expansion'(M, M, G, NG, UVars), !.
'$preprocess_body_before_mod_change'(G,M,_,G) :-
	'$system_predicate'(G,M), !.
'$preprocess_body_before_mod_change'(G,M,_,M:G).


