250 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
			
		
		
	
	
			250 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
/*  $Id$
 | 
						|
 | 
						|
    Part of CHR (Constraint Handling Rules)
 | 
						|
 | 
						|
    Author:        Tom Schrijvers
 | 
						|
    E-mail:        Tom.Schrijvers@cs.kuleuven.be
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 2003-2004, K.U. Leuven
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU General Public License
 | 
						|
    as published by the Free Software Foundation; either version 2
 | 
						|
    of the License, or (at your option) any later version.
 | 
						|
 | 
						|
    This program 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 General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 | 
						|
 | 
						|
    As a special exception, if you link this library with other files,
 | 
						|
    compiled with a Free Software compiler, to produce an executable, this
 | 
						|
    library does not by itself cause the resulting executable to be covered
 | 
						|
    by the GNU General Public License. This exception does not however
 | 
						|
    invalidate any other reasons why the executable file might be covered by
 | 
						|
    the GNU General Public License.
 | 
						|
*/
 | 
						|
 | 
						|
%   ____          _         ____ _                  _
 | 
						|
%  / ___|___   __| | ___   / ___| | ___  __ _ _ __ (_)_ __   __ _
 | 
						|
% | |   / _ \ / _` |/ _ \ | |   | |/ _ \/ _` | '_ \| | '_ \ / _` |
 | 
						|
% | |__| (_) | (_| |  __/ | |___| |  __/ (_| | | | | | | | | (_| |
 | 
						|
%  \____\___/ \__,_|\___|  \____|_|\___|\__,_|_| |_|_|_| |_|\__, |
 | 
						|
%                                                           |___/
 | 
						|
%
 | 
						|
% To be done:
 | 
						|
%	inline clauses
 | 
						|
 | 
						|
:- module(clean_code,
 | 
						|
	[
 | 
						|
		clean_clauses/2
 | 
						|
	]).
 | 
						|
 | 
						|
:- use_module(library(dialect/hprolog)).
 | 
						|
 | 
						|
clean_clauses(Clauses,NClauses) :-
 | 
						|
	clean_clauses1(Clauses,Clauses1),
 | 
						|
	merge_clauses(Clauses1,NClauses).
 | 
						|
 | 
						|
 | 
						|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
						|
% CLEAN CLAUSES
 | 
						|
%
 | 
						|
%	- move neck unification into the head of the clause
 | 
						|
%	- drop true body
 | 
						|
%	- specialize control flow goal wrt true and fail
 | 
						|
%
 | 
						|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
						|
 | 
						|
clean_clauses1([],[]).
 | 
						|
clean_clauses1([C|Cs],[NC|NCs]) :-
 | 
						|
	clean_clause(C,NC),
 | 
						|
	clean_clauses1(Cs,NCs).
 | 
						|
 | 
						|
clean_clause(Clause,NClause) :-
 | 
						|
	( Clause = (Head :- Body) ->
 | 
						|
		clean_goal(Body,Body1),
 | 
						|
		move_unification_into_head(Head,Body1,NHead,NBody),
 | 
						|
		( NBody == true ->
 | 
						|
			NClause = NHead
 | 
						|
		;
 | 
						|
			NClause = (NHead :- NBody)
 | 
						|
		)
 | 
						|
	; Clause = '$source_location'(File,Line) : ActualClause ->
 | 
						|
		NClause = '$source_location'(File,Line) :  NActualClause,
 | 
						|
		clean_clause(ActualClause,NActualClause)
 | 
						|
	;
 | 
						|
		NClause = Clause
 | 
						|
	).
 | 
						|
 | 
						|
clean_goal(Goal,NGoal) :-
 | 
						|
	var(Goal), !,
 | 
						|
	NGoal = Goal.
 | 
						|
clean_goal((G1,G2),NGoal) :-
 | 
						|
	!,
 | 
						|
	clean_goal(G1,NG1),
 | 
						|
	clean_goal(G2,NG2),
 | 
						|
	( NG1 == true ->
 | 
						|
		NGoal = NG2
 | 
						|
	; NG2 == true ->
 | 
						|
		NGoal = NG1
 | 
						|
	;
 | 
						|
		NGoal = (NG1,NG2)
 | 
						|
	).
 | 
						|
clean_goal((If -> Then ; Else),NGoal) :-
 | 
						|
	!,
 | 
						|
	clean_goal(If,NIf),
 | 
						|
	( NIf == true ->
 | 
						|
		clean_goal(Then,NThen),
 | 
						|
		NGoal = NThen
 | 
						|
	; NIf == fail ->
 | 
						|
		clean_goal(Else,NElse),
 | 
						|
		NGoal = NElse
 | 
						|
	;
 | 
						|
		clean_goal(Then,NThen),
 | 
						|
		clean_goal(Else,NElse),
 | 
						|
		NGoal = (NIf -> NThen; NElse)
 | 
						|
	).
 | 
						|
clean_goal((G1 ; G2),NGoal) :-
 | 
						|
	!,
 | 
						|
	clean_goal(G1,NG1),
 | 
						|
	clean_goal(G2,NG2),
 | 
						|
	( NG1 == fail ->
 | 
						|
		NGoal = NG2
 | 
						|
	; NG2 == fail ->
 | 
						|
		NGoal = NG1
 | 
						|
	;
 | 
						|
		NGoal = (NG1 ; NG2)
 | 
						|
	).
 | 
						|
clean_goal(once(G),NGoal) :-
 | 
						|
	!,
 | 
						|
	clean_goal(G,NG),
 | 
						|
	( NG == true ->
 | 
						|
		NGoal = true
 | 
						|
	; NG == fail ->
 | 
						|
		NGoal = fail
 | 
						|
	;
 | 
						|
		NGoal = once(NG)
 | 
						|
	).
 | 
						|
clean_goal((G1 -> G2),NGoal) :-
 | 
						|
	!,
 | 
						|
	clean_goal(G1,NG1),
 | 
						|
	( NG1 == true ->
 | 
						|
		clean_goal(G2,NGoal)
 | 
						|
	; NG1 == fail ->
 | 
						|
		NGoal = fail
 | 
						|
	;
 | 
						|
		clean_goal(G2,NG2),
 | 
						|
		NGoal = (NG1 -> NG2)
 | 
						|
	).
 | 
						|
clean_goal(Goal,Goal).
 | 
						|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
						|
move_unification_into_head(Head,Body,NHead,NBody) :-
 | 
						|
	conj2list(Body,BodyList),
 | 
						|
	move_unification_into_head_(BodyList,Head,NHead,NBody).
 | 
						|
 | 
						|
move_unification_into_head_([],Head,Head,true).
 | 
						|
move_unification_into_head_([G|Gs],Head,NHead,NBody) :-
 | 
						|
	( nonvar(G), G = (X = Y) ->
 | 
						|
		term_variables(Gs,GsVars),
 | 
						|
		( var(X), ( \+ memberchk_eq(X,GsVars) ; atomic(Y)) ->
 | 
						|
			X = Y,
 | 
						|
			move_unification_into_head_(Gs,Head,NHead,NBody)
 | 
						|
		; var(Y), (\+ memberchk_eq(Y,GsVars) ; atomic(X)) ->
 | 
						|
			X = Y,
 | 
						|
			move_unification_into_head_(Gs,Head,NHead,NBody)
 | 
						|
		;
 | 
						|
			Head = NHead,
 | 
						|
			list2conj([G|Gs],NBody)
 | 
						|
		)
 | 
						|
	;
 | 
						|
		Head = NHead,
 | 
						|
		list2conj([G|Gs],NBody)
 | 
						|
	).
 | 
						|
 | 
						|
 | 
						|
conj2list(Conj,L) :-				%% transform conjunctions to list
 | 
						|
  conj2list(Conj,L,[]).
 | 
						|
 | 
						|
conj2list(G,L,T) :-
 | 
						|
	var(G), !,
 | 
						|
	L = [G|T].
 | 
						|
conj2list(true,L,L) :- !.
 | 
						|
conj2list(Conj,L,T) :-
 | 
						|
  Conj = (G1,G2), !,
 | 
						|
  conj2list(G1,L,T1),
 | 
						|
  conj2list(G2,T1,T).
 | 
						|
conj2list(G,[G | T],T).
 | 
						|
 | 
						|
list2conj([],true).
 | 
						|
list2conj([G],X) :- !, X = G.
 | 
						|
list2conj([G|Gs],C) :-
 | 
						|
	( G == true ->				%% remove some redundant trues
 | 
						|
		list2conj(Gs,C)
 | 
						|
	;
 | 
						|
		C = (G,R),
 | 
						|
		list2conj(Gs,R)
 | 
						|
	).
 | 
						|
 | 
						|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
						|
% MERGE CLAUSES
 | 
						|
%
 | 
						|
%	Find common prefixes of successive clauses and share them.
 | 
						|
%
 | 
						|
%	Note: we assume that the prefix does not generate a side effect.
 | 
						|
%
 | 
						|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 | 
						|
 | 
						|
merge_clauses([],[]).
 | 
						|
merge_clauses([C],[C]).
 | 
						|
merge_clauses([X,Y|Clauses],NClauses) :-
 | 
						|
	( merge_two_clauses(X,Y,Clause) ->
 | 
						|
		merge_clauses([Clause|Clauses],NClauses)
 | 
						|
	;
 | 
						|
		NClauses = [X|RClauses],
 | 
						|
		merge_clauses([Y|Clauses],RClauses)
 | 
						|
	).
 | 
						|
 | 
						|
merge_two_clauses('$source_location'(F1,L1) : C1,
 | 
						|
		  '$source_location'(_F2,_L2) : C2,
 | 
						|
		  Result) :- !,
 | 
						|
	merge_two_clauses(C1,C2,C),
 | 
						|
	Result = '$source_location'(F1,L1) : C.
 | 
						|
merge_two_clauses((H1 :- B1), (H2 :- B2), (H :- B)) :-
 | 
						|
	H1 =@= H2,
 | 
						|
	H1 = H,
 | 
						|
	conj2list(B1,List1),
 | 
						|
	conj2list(B2,List2),
 | 
						|
	merge_lists(List1,List2,H1,H2,Unifier,List,NList1,NList2),
 | 
						|
	List \= [],
 | 
						|
	H1 = H2,
 | 
						|
	call(Unifier),
 | 
						|
	list2conj(List,Prefix),
 | 
						|
	list2conj(NList1,NB1),
 | 
						|
	( NList2 == (!) ->
 | 
						|
		B = Prefix
 | 
						|
	;
 | 
						|
		list2conj(NList2,NB2),
 | 
						|
		B = (Prefix,(NB1 ; NB2))
 | 
						|
	).
 | 
						|
 | 
						|
merge_lists([],[],_,_,true,[],[],[]).
 | 
						|
merge_lists([],L2,_,_,true,[],[],L2).
 | 
						|
merge_lists([!|Xs],_,_,_,true,[!|Xs],[],!) :- !.
 | 
						|
merge_lists([X|Xs],[],_,_,true,[],[X|Xs],[]).
 | 
						|
merge_lists([X|Xs],[Y|Ys],H1,H2,Unifier,Common,N1,N2) :-
 | 
						|
	( H1-X =@= H2-Y ->
 | 
						|
		Unifier = (X = Y, RUnifier),
 | 
						|
		Common = [X|NCommon],
 | 
						|
		merge_lists(Xs,Ys,H1/X,H2/Y,RUnifier,NCommon,N1,N2)
 | 
						|
	;
 | 
						|
		Unifier = true,
 | 
						|
		Common = [],
 | 
						|
		N1 = [X|Xs],
 | 
						|
		N2 = [Y|Ys]
 | 
						|
	).
 |