250 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			250 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| 
								 | 
							
								/*  $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]
							 | 
						||
| 
								 | 
							
									).
							 |