11package liquidjava .rj_language .opt ;
22
33import static liquidjava .rj_language .opt .VCSimplificationUtils .copyWithRefinement ;
4+ import static liquidjava .rj_language .opt .VCSimplificationUtils .containsExpression ;
45
6+ import java .util .ArrayList ;
7+ import java .util .List ;
58import java .util .Optional ;
69
710import liquidjava .processor .VCImplication ;
1619public class VCFunctionSubstitution implements VCSimplificationPass {
1720
1821 /**
19- * A substitution discovered from a function invocation equality
22+ * A substitution discovered from a function invocation equality. At {@code sourceNode}, remove
23+ * {@code sourceEquality} and in the following nodes replace {@code invocation} with {@code replacement}
2024 */
21- private record Substitution (VCImplication node , FunctionInvocation invocation , Expression replacement ) {
25+ private record Substitution (VCImplication sourceNode , FunctionInvocation invocation , Expression replacement ,
26+ Expression sourceEquality ) {
2227 }
2328
2429 /**
2530 * Applies one function invocation substitution in a VC chain
2631 */
2732 @ Override
2833 public VCImplication apply (VCImplication implication ) {
29- VCImplication result = implication .clone ();
30- Optional <Substitution > substitutionOpt = findSubstitution (result );
34+ Optional <Substitution > substitutionOpt = findSubstitution (implication );
3135
3236 if (substitutionOpt .isPresent ()) {
3337 Substitution substitution = substitutionOpt .get ();
34- result = substitute (result , substitution .node (), substitution .invocation (), substitution .replacement ());
38+ return substitute (implication , substitution .sourceNode (), substitution .invocation (),
39+ substitution .replacement (), substitution .sourceEquality ());
3540 }
36- return result ;
41+ return implication ;
3742 }
3843
3944 /**
40- * Preserves nodes before the source equality and starts rewriting at the source suffix
45+ * Rewrites one VC chain with a single substitution and removes its source equality
4146 */
4247 private VCImplication substitute (VCImplication implication , VCImplication node , FunctionInvocation invocation ,
43- Expression replacement ) {
48+ Expression replacement , Expression sourceEquality ) {
4449 if (implication == null )
4550 return null ;
4651
47- // skip the source node to remove it from the chain and start substitution from the next node
52+ // consume the source equality and start substitution from the next node
4853 if (implication == node ) {
49- VCImplication result = copyWithRefinement (implication , implication .getRefinement ().clone ());
50- result .setNext (substituteSuffix (implication .getNext (), invocation , replacement ));
51- return result ;
54+ VCImplication suffix = substituteSuffix (implication .getNext (), invocation , replacement );
55+ VCImplication source = removeSourceEquality (implication , sourceEquality );
56+ if (source == null )
57+ return suffix ;
58+ source .setNext (suffix );
59+ return source ;
5260 }
5361
5462 // preserve the current node and continue rewriting the suffix
55- VCImplication result = copyWithRefinement (implication , implication .getRefinement (). clone () );
56- result .setNext (substitute (implication .getNext (), node , invocation , replacement ));
63+ VCImplication result = copyWithRefinement (implication , implication .getRefinement ());
64+ result .setNext (substitute (implication .getNext (), node , invocation , replacement , sourceEquality ));
5765 return result ;
5866 }
5967
68+ /**
69+ * Removes the equality conjunct that supplied the substitution, preserving any sibling conjuncts
70+ */
71+ private VCImplication removeSourceEquality (VCImplication implication , Expression sourceEquality ) {
72+ List <Expression > remaining = new ArrayList <>(implication .getRefinement ().getExpression ().getConjuncts ());
73+ remaining .remove (sourceEquality );
74+ if (remaining .isEmpty ())
75+ return null ;
76+
77+ Predicate refinement = new Predicate ();
78+ for (Expression conjunct : remaining )
79+ refinement = Predicate .createConjunction (refinement , new Predicate (conjunct ));
80+ return copyWithRefinement (implication , refinement );
81+ }
82+
6083 /**
6184 * Rewrites every node after the source equality with one function substitution
6285 */
@@ -75,11 +98,11 @@ private VCImplication substituteSuffix(VCImplication implication, FunctionInvoca
7598 */
7699 private VCImplication substituteNode (VCImplication implication , FunctionInvocation invocation ,
77100 Expression replacement ) {
78- Expression expression = implication .getRefinement ().getExpression (). clone () ;
101+ Expression expression = implication .getRefinement ().getExpression ();
79102 if (!containsExpression (expression , invocation ))
80- return copyWithRefinement (implication , new Predicate ( expression ));
103+ return copyWithRefinement (implication , implication . getRefinement ( ));
81104
82- Expression substituted = expression .substitute (invocation , replacement . clone () );
105+ Expression substituted = expression .substitute (invocation , replacement );
83106 return copyWithRefinement (implication , new Predicate (substituted ));
84107 }
85108
@@ -101,7 +124,7 @@ private Optional<Substitution> findSubstitution(VCImplication implication) {
101124 * Extracts a substitution from one VC node refinement
102125 */
103126 private Optional <Substitution > getSubstitution (VCImplication implication ) {
104- return getSubstitution (implication , implication .getRefinement ().getExpression (). clone () );
127+ return getSubstitution (implication , implication .getRefinement ().getExpression ());
105128 }
106129
107130 /**
@@ -121,33 +144,11 @@ private Optional<Substitution> getSubstitution(VCImplication implication, Expres
121144 Expression left = binary .getFirstOperand ();
122145 Expression right = binary .getSecondOperand ();
123146 if (left instanceof FunctionInvocation invocation && !containsExpression (right , left ))
124- return Optional .of (new Substitution (implication , ( FunctionInvocation ) invocation . clone () , right . clone () ));
147+ return Optional .of (new Substitution (implication , invocation , right , binary ));
125148 if (right instanceof FunctionInvocation invocation && !containsExpression (left , right ))
126- return Optional .of (new Substitution (implication , ( FunctionInvocation ) invocation . clone () , left . clone () ));
149+ return Optional .of (new Substitution (implication , invocation , left , binary ));
127150
128151 return Optional .empty ();
129152 }
130153
131- /**
132- * Checks whether an expression contains another expression
133- */
134- private boolean containsExpression (Expression expression , Expression target ) {
135- if (expression .equals (target ))
136- return true ;
137-
138- for (Expression child : expression .getChildren ())
139- if (containsExpression (child , target ))
140- return true ;
141- return false ;
142- }
143-
144- /**
145- * Checks whether a VC suffix contains an expression
146- */
147- private boolean containsExpression (VCImplication implication , Expression target ) {
148- for (VCImplication current = implication ; current != null ; current = current .getNext ())
149- if (containsExpression (current .getRefinement ().getExpression (), target ))
150- return true ;
151- return false ;
152- }
153154}
0 commit comments