1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2010 Terence Parr 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 package org.antlr.analysis; 29 30 import org.antlr.codegen.CodeGenerator; 31 import org.antlr.grammar.v3.ANTLRParser; 32 import org.antlr.tool.Grammar; 33 import org.antlr.tool.GrammarAST; 34 import org.stringtemplate.v4.ST; 35 import org.stringtemplate.v4.STGroup; 36 37 import java.util.*; 38 39 /** A binary tree structure used to record the semantic context in which 40 * an NFA configuration is valid. It's either a single predicate or 41 * a tree representing an operation tree such as: p1&&p2 or p1||p2. 42 * 43 * For NFA o-p1->o-p2->o, create tree AND(p1,p2). 44 * For NFA (1)-p1->(2) 45 * | ^ 46 * | | 47 * (3)-p2---- 48 * we will have to combine p1 and p2 into DFA state as we will be 49 * adding NFA configurations for state 2 with two predicates p1,p2. 50 * So, set context for combined NFA config for state 2: OR(p1,p2). 51 * 52 * I have scoped the AND, NOT, OR, and Predicate subclasses of 53 * SemanticContext within the scope of this outer class. 54 * 55 * July 7, 2006: TJP altered OR to be set of operands. the Binary tree 56 * made it really hard to reduce complicated || sequences to their minimum. 57 * Got huge repeated || conditions. 58 */ 59 public abstract class SemanticContext { 60 /** Create a default value for the semantic context shared among all 61 * NFAConfigurations that do not have an actual semantic context. 62 * This prevents lots of if!=null type checks all over; it represents 63 * just an empty set of predicates. 64 */ 65 public static final SemanticContext EMPTY_SEMANTIC_CONTEXT = new Predicate(Predicate.INVALID_PRED_VALUE); 66 67 /** Given a semantic context expression tree, return a tree with all 68 * nongated predicates set to true and then reduced. So p&&(q||r) would 69 * return p&&r if q is nongated but p and r are gated. 70 */ getGatedPredicateContext()71 public abstract SemanticContext getGatedPredicateContext(); 72 73 /** Generate an expression that will evaluate the semantic context, 74 * given a set of output templates. 75 */ genExpr(CodeGenerator generator, STGroup templates, DFA dfa)76 public abstract ST genExpr(CodeGenerator generator, 77 STGroup templates, 78 DFA dfa); 79 hasUserSemanticPredicate()80 public abstract boolean hasUserSemanticPredicate(); // user-specified sempred {}? or {}?=> isSyntacticPredicate()81 public abstract boolean isSyntacticPredicate(); 82 83 /** Notify the indicated grammar of any syn preds used within this context */ trackUseOfSyntacticPredicates(Grammar g)84 public void trackUseOfSyntacticPredicates(Grammar g) { 85 } 86 87 public static class Predicate extends SemanticContext { 88 /** The AST node in tree created from the grammar holding the predicate */ 89 public GrammarAST predicateAST; 90 91 /** Is this a {...}?=> gating predicate or a normal disambiguating {..}? 92 * If any predicate in expression is gated, then expression is considered 93 * gated. 94 * 95 * The simple Predicate object's predicate AST's type is used to set 96 * gated to true if type==GATED_SEMPRED. 97 */ 98 protected boolean gated = false; 99 100 /** syntactic predicates are converted to semantic predicates 101 * but synpreds are generated slightly differently. 102 */ 103 protected boolean synpred = false; 104 105 public static final int INVALID_PRED_VALUE = -2; 106 public static final int FALSE_PRED = 0; 107 public static final int TRUE_PRED = ~0; 108 109 /** sometimes predicates are known to be true or false; we need 110 * a way to represent this without resorting to a target language 111 * value like true or TRUE. 112 */ 113 protected int constantValue = INVALID_PRED_VALUE; 114 Predicate(int constantValue)115 public Predicate(int constantValue) { 116 predicateAST = new GrammarAST(); 117 this.constantValue=constantValue; 118 } 119 Predicate(GrammarAST predicate)120 public Predicate(GrammarAST predicate) { 121 this.predicateAST = predicate; 122 this.gated = 123 predicate.getType()==ANTLRParser.GATED_SEMPRED || 124 predicate.getType()==ANTLRParser.SYN_SEMPRED ; 125 this.synpred = 126 predicate.getType()==ANTLRParser.SYN_SEMPRED || 127 predicate.getType()==ANTLRParser.BACKTRACK_SEMPRED; 128 } 129 Predicate(Predicate p)130 public Predicate(Predicate p) { 131 this.predicateAST = p.predicateAST; 132 this.gated = p.gated; 133 this.synpred = p.synpred; 134 this.constantValue = p.constantValue; 135 } 136 137 /** Two predicates are the same if they are literally the same 138 * text rather than same node in the grammar's AST. 139 * Or, if they have the same constant value, return equal. 140 * As of July 2006 I'm not sure these are needed. 141 */ equals(Object o)142 public boolean equals(Object o) { 143 if ( !(o instanceof Predicate) ) { 144 return false; 145 } 146 147 Predicate other = (Predicate)o; 148 if (this.constantValue != other.constantValue){ 149 return false; 150 } 151 152 if (this.constantValue != INVALID_PRED_VALUE){ 153 return true; 154 } 155 156 return predicateAST.getText().equals(other.predicateAST.getText()); 157 } 158 hashCode()159 public int hashCode() { 160 if (constantValue != INVALID_PRED_VALUE){ 161 return constantValue; 162 } 163 164 if ( predicateAST ==null ) { 165 return 0; 166 } 167 168 return predicateAST.getText().hashCode(); 169 } 170 genExpr(CodeGenerator generator, STGroup templates, DFA dfa)171 public ST genExpr(CodeGenerator generator, 172 STGroup templates, 173 DFA dfa) 174 { 175 ST eST = null; 176 if ( templates!=null ) { 177 if ( synpred ) { 178 eST = templates.getInstanceOf("evalSynPredicate"); 179 } 180 else { 181 eST = templates.getInstanceOf("evalPredicate"); 182 generator.grammar.decisionsWhoseDFAsUsesSemPreds.add(dfa); 183 } 184 String predEnclosingRuleName = predicateAST.enclosingRuleName; 185 /* 186 String decisionEnclosingRuleName = 187 dfa.getNFADecisionStartState().getEnclosingRule(); 188 // if these rulenames are diff, then pred was hoisted out of rule 189 // Currently I don't warn you about this as it could be annoying. 190 // I do the translation anyway. 191 */ 192 //eST.add("pred", this.toString()); 193 if ( generator!=null ) { 194 eST.add("pred", 195 generator.translateAction(predEnclosingRuleName,predicateAST)); 196 } 197 } 198 else { 199 eST = new ST("<pred>"); 200 eST.add("pred", this.toString()); 201 return eST; 202 } 203 if ( generator!=null ) { 204 String description = 205 generator.target.getTargetStringLiteralFromString(this.toString()); 206 eST.add("description", description); 207 } 208 return eST; 209 } 210 211 @Override getGatedPredicateContext()212 public SemanticContext getGatedPredicateContext() { 213 if ( gated ) { 214 return this; 215 } 216 return null; 217 } 218 219 @Override hasUserSemanticPredicate()220 public boolean hasUserSemanticPredicate() { // user-specified sempred 221 return predicateAST !=null && 222 ( predicateAST.getType()==ANTLRParser.GATED_SEMPRED || 223 predicateAST.getType()==ANTLRParser.SEMPRED ); 224 } 225 226 @Override isSyntacticPredicate()227 public boolean isSyntacticPredicate() { 228 return predicateAST !=null && 229 ( predicateAST.getType()==ANTLRParser.SYN_SEMPRED || 230 predicateAST.getType()==ANTLRParser.BACKTRACK_SEMPRED ); 231 } 232 233 @Override trackUseOfSyntacticPredicates(Grammar g)234 public void trackUseOfSyntacticPredicates(Grammar g) { 235 if ( synpred ) { 236 g.synPredNamesUsedInDFA.add(predicateAST.getText()); 237 } 238 } 239 240 @Override toString()241 public String toString() { 242 if ( predicateAST ==null ) { 243 return "<nopred>"; 244 } 245 return predicateAST.getText(); 246 } 247 } 248 249 public static class TruePredicate extends Predicate { TruePredicate()250 public TruePredicate() { 251 super(TRUE_PRED); 252 } 253 254 @Override genExpr(CodeGenerator generator, STGroup templates, DFA dfa)255 public ST genExpr(CodeGenerator generator, 256 STGroup templates, 257 DFA dfa) 258 { 259 if ( templates!=null ) { 260 return templates.getInstanceOf("true_value"); 261 } 262 return new ST("true"); 263 } 264 265 @Override hasUserSemanticPredicate()266 public boolean hasUserSemanticPredicate() { 267 return false; // not user specified. 268 } 269 270 @Override toString()271 public String toString() { 272 return "true"; // not used for code gen, just DOT and print outs 273 } 274 } 275 276 public static class FalsePredicate extends Predicate { FalsePredicate()277 public FalsePredicate() { 278 super(FALSE_PRED); 279 } 280 281 @Override genExpr(CodeGenerator generator, STGroup templates, DFA dfa)282 public ST genExpr(CodeGenerator generator, 283 STGroup templates, 284 DFA dfa) 285 { 286 if ( templates!=null ) { 287 return templates.getInstanceOf("false"); 288 } 289 return new ST("false"); 290 } 291 292 @Override hasUserSemanticPredicate()293 public boolean hasUserSemanticPredicate() { 294 return false; // not user specified. 295 } 296 297 @Override toString()298 public String toString() { 299 return "false"; // not used for code gen, just DOT and print outs 300 } 301 } 302 303 public static abstract class CommutativePredicate extends SemanticContext { 304 protected final Set<SemanticContext> operands = new HashSet<SemanticContext>(); 305 protected int hashcode; 306 CommutativePredicate(SemanticContext a, SemanticContext b)307 public CommutativePredicate(SemanticContext a, SemanticContext b) { 308 if (a.getClass() == this.getClass()){ 309 CommutativePredicate predicate = (CommutativePredicate)a; 310 operands.addAll(predicate.operands); 311 } else { 312 operands.add(a); 313 } 314 315 if (b.getClass() == this.getClass()){ 316 CommutativePredicate predicate = (CommutativePredicate)b; 317 operands.addAll(predicate.operands); 318 } else { 319 operands.add(b); 320 } 321 322 hashcode = calculateHashCode(); 323 } 324 CommutativePredicate(HashSet<SemanticContext> contexts)325 public CommutativePredicate(HashSet<SemanticContext> contexts){ 326 for (SemanticContext context : contexts){ 327 if (context.getClass() == this.getClass()){ 328 CommutativePredicate predicate = (CommutativePredicate)context; 329 operands.addAll(predicate.operands); 330 } else { 331 operands.add(context); 332 } 333 } 334 335 hashcode = calculateHashCode(); 336 } 337 338 @Override getGatedPredicateContext()339 public SemanticContext getGatedPredicateContext() { 340 SemanticContext result = null; 341 for (SemanticContext semctx : operands) { 342 SemanticContext gatedPred = semctx.getGatedPredicateContext(); 343 if ( gatedPred!=null ) { 344 result = combinePredicates(result, gatedPred); 345 } 346 } 347 return result; 348 } 349 350 @Override hasUserSemanticPredicate()351 public boolean hasUserSemanticPredicate() { 352 for (SemanticContext semctx : operands) { 353 if ( semctx.hasUserSemanticPredicate() ) { 354 return true; 355 } 356 } 357 return false; 358 } 359 360 @Override isSyntacticPredicate()361 public boolean isSyntacticPredicate() { 362 for (SemanticContext semctx : operands) { 363 if ( semctx.isSyntacticPredicate() ) { 364 return true; 365 } 366 } 367 return false; 368 } 369 370 @Override trackUseOfSyntacticPredicates(Grammar g)371 public void trackUseOfSyntacticPredicates(Grammar g) { 372 for (SemanticContext semctx : operands) { 373 semctx.trackUseOfSyntacticPredicates(g); 374 } 375 } 376 377 @Override equals(Object obj)378 public boolean equals(Object obj) { 379 if (this == obj) 380 return true; 381 382 if (obj.getClass() == this.getClass()) { 383 CommutativePredicate commutative = (CommutativePredicate)obj; 384 Set<SemanticContext> otherOperands = commutative.operands; 385 if (operands.size() != otherOperands.size()) 386 return false; 387 388 return operands.containsAll(otherOperands); 389 } 390 391 if (obj instanceof NOT) 392 { 393 NOT not = (NOT)obj; 394 if (not.ctx instanceof CommutativePredicate && not.ctx.getClass() != this.getClass()) { 395 Set<SemanticContext> otherOperands = ((CommutativePredicate)not.ctx).operands; 396 if (operands.size() != otherOperands.size()) 397 return false; 398 399 ArrayList<SemanticContext> temp = new ArrayList<SemanticContext>(operands.size()); 400 for (SemanticContext context : otherOperands) { 401 temp.add(not(context)); 402 } 403 404 return operands.containsAll(temp); 405 } 406 } 407 408 return false; 409 } 410 411 @Override hashCode()412 public int hashCode(){ 413 return hashcode; 414 } 415 416 @Override toString()417 public String toString() { 418 StringBuffer buf = new StringBuffer(); 419 buf.append("("); 420 int i = 0; 421 for (SemanticContext semctx : operands) { 422 if ( i>0 ) { 423 buf.append(getOperandString()); 424 } 425 buf.append(semctx.toString()); 426 i++; 427 } 428 buf.append(")"); 429 return buf.toString(); 430 } 431 getOperandString()432 public abstract String getOperandString(); 433 combinePredicates(SemanticContext left, SemanticContext right)434 public abstract SemanticContext combinePredicates(SemanticContext left, SemanticContext right); 435 calculateHashCode()436 public abstract int calculateHashCode(); 437 } 438 439 public static class AND extends CommutativePredicate { AND(SemanticContext a, SemanticContext b)440 public AND(SemanticContext a, SemanticContext b) { 441 super(a,b); 442 } 443 AND(HashSet<SemanticContext> contexts)444 public AND(HashSet<SemanticContext> contexts) { 445 super(contexts); 446 } 447 448 @Override genExpr(CodeGenerator generator, STGroup templates, DFA dfa)449 public ST genExpr(CodeGenerator generator, 450 STGroup templates, 451 DFA dfa) 452 { 453 ST result = null; 454 for (SemanticContext operand : operands) { 455 if (result == null) 456 result = operand.genExpr(generator, templates, dfa); 457 458 ST eST = null; 459 if ( templates!=null ) { 460 eST = templates.getInstanceOf("andPredicates"); 461 } 462 else { 463 eST = new ST("(<left>&&<right>)"); 464 } 465 eST.add("left", result); 466 eST.add("right", operand.genExpr(generator,templates,dfa)); 467 result = eST; 468 } 469 470 return result; 471 } 472 473 @Override getOperandString()474 public String getOperandString() { 475 return "&&"; 476 } 477 478 @Override combinePredicates(SemanticContext left, SemanticContext right)479 public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) { 480 return SemanticContext.and(left, right); 481 } 482 483 @Override calculateHashCode()484 public int calculateHashCode() { 485 int hashcode = 0; 486 for (SemanticContext context : operands) { 487 hashcode = hashcode ^ context.hashCode(); 488 } 489 490 return hashcode; 491 } 492 } 493 494 public static class OR extends CommutativePredicate { OR(SemanticContext a, SemanticContext b)495 public OR(SemanticContext a, SemanticContext b) { 496 super(a,b); 497 } 498 OR(HashSet<SemanticContext> contexts)499 public OR(HashSet<SemanticContext> contexts) { 500 super(contexts); 501 } 502 503 @Override genExpr(CodeGenerator generator, STGroup templates, DFA dfa)504 public ST genExpr(CodeGenerator generator, 505 STGroup templates, 506 DFA dfa) 507 { 508 ST eST = null; 509 if ( templates!=null ) { 510 eST = templates.getInstanceOf("orPredicates"); 511 } 512 else { 513 eST = new ST("(<first(operands)><rest(operands):{o | ||<o>}>)"); 514 } 515 for (SemanticContext semctx : operands) { 516 eST.add("operands", semctx.genExpr(generator,templates,dfa)); 517 } 518 return eST; 519 } 520 521 @Override getOperandString()522 public String getOperandString() { 523 return "||"; 524 } 525 526 @Override combinePredicates(SemanticContext left, SemanticContext right)527 public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) { 528 return SemanticContext.or(left, right); 529 } 530 531 @Override calculateHashCode()532 public int calculateHashCode() { 533 int hashcode = 0; 534 for (SemanticContext context : operands) { 535 hashcode = ~hashcode ^ context.hashCode(); 536 } 537 538 return hashcode; 539 } 540 } 541 542 public static class NOT extends SemanticContext { 543 protected SemanticContext ctx; NOT(SemanticContext ctx)544 public NOT(SemanticContext ctx) { 545 this.ctx = ctx; 546 } 547 548 @Override genExpr(CodeGenerator generator, STGroup templates, DFA dfa)549 public ST genExpr(CodeGenerator generator, 550 STGroup templates, 551 DFA dfa) 552 { 553 ST eST = null; 554 if ( templates!=null ) { 555 eST = templates.getInstanceOf("notPredicate"); 556 } 557 else { 558 eST = new ST("!(<pred>)"); 559 } 560 eST.add("pred", ctx.genExpr(generator,templates,dfa)); 561 return eST; 562 } 563 564 @Override getGatedPredicateContext()565 public SemanticContext getGatedPredicateContext() { 566 SemanticContext p = ctx.getGatedPredicateContext(); 567 if ( p==null ) { 568 return null; 569 } 570 return new NOT(p); 571 } 572 573 @Override hasUserSemanticPredicate()574 public boolean hasUserSemanticPredicate() { 575 return ctx.hasUserSemanticPredicate(); 576 } 577 578 @Override isSyntacticPredicate()579 public boolean isSyntacticPredicate() { 580 return ctx.isSyntacticPredicate(); 581 } 582 583 @Override trackUseOfSyntacticPredicates(Grammar g)584 public void trackUseOfSyntacticPredicates(Grammar g) { 585 ctx.trackUseOfSyntacticPredicates(g); 586 } 587 588 @Override equals(Object object)589 public boolean equals(Object object) { 590 if ( !(object instanceof NOT) ) { 591 return false; 592 } 593 return this.ctx.equals(((NOT)object).ctx); 594 } 595 596 @Override hashCode()597 public int hashCode() { 598 return ~ctx.hashCode(); 599 } 600 601 @Override toString()602 public String toString() { 603 return "!("+ctx+")"; 604 } 605 } 606 and(SemanticContext a, SemanticContext b)607 public static SemanticContext and(SemanticContext a, SemanticContext b) { 608 //System.out.println("AND: "+a+"&&"+b); 609 SemanticContext[] terms = factorOr(a, b); 610 SemanticContext commonTerms = terms[0]; 611 a = terms[1]; 612 b = terms[2]; 613 614 boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof TruePredicate); 615 if (factored) { 616 return or(commonTerms, and(a, b)); 617 } 618 619 //System.Console.Out.WriteLine( "AND: " + a + "&&" + b ); 620 if (a instanceof FalsePredicate || b instanceof FalsePredicate) 621 return new FalsePredicate(); 622 623 if ( a==EMPTY_SEMANTIC_CONTEXT || a==null ) { 624 return b; 625 } 626 if ( b==EMPTY_SEMANTIC_CONTEXT || b==null ) { 627 return a; 628 } 629 630 if (a instanceof TruePredicate) 631 return b; 632 633 if (b instanceof TruePredicate) 634 return a; 635 636 //// Factoring takes care of this case 637 //if (a.Equals(b)) 638 // return a; 639 640 //System.out.println("## have to AND"); 641 return new AND(a,b); 642 } 643 or(SemanticContext a, SemanticContext b)644 public static SemanticContext or(SemanticContext a, SemanticContext b) { 645 //System.out.println("OR: "+a+"||"+b); 646 SemanticContext[] terms = factorAnd(a, b); 647 SemanticContext commonTerms = terms[0]; 648 a = terms[1]; 649 b = terms[2]; 650 boolean factored = commonTerms != null && commonTerms != EMPTY_SEMANTIC_CONTEXT && !(commonTerms instanceof FalsePredicate); 651 if (factored) { 652 return and(commonTerms, or(a, b)); 653 } 654 655 if ( a==EMPTY_SEMANTIC_CONTEXT || a==null || a instanceof FalsePredicate ) { 656 return b; 657 } 658 659 if ( b==EMPTY_SEMANTIC_CONTEXT || b==null || b instanceof FalsePredicate ) { 660 return a; 661 } 662 663 if ( a instanceof TruePredicate || b instanceof TruePredicate || commonTerms instanceof TruePredicate ) { 664 return new TruePredicate(); 665 } 666 667 //// Factoring takes care of this case 668 //if (a.equals(b)) 669 // return a; 670 671 if ( a instanceof NOT ) { 672 NOT n = (NOT)a; 673 // check for !p||p 674 if ( n.ctx.equals(b) ) { 675 return new TruePredicate(); 676 } 677 } 678 else if ( b instanceof NOT ) { 679 NOT n = (NOT)b; 680 // check for p||!p 681 if ( n.ctx.equals(a) ) { 682 return new TruePredicate(); 683 } 684 } 685 686 //System.out.println("## have to OR"); 687 OR result = new OR(a,b); 688 if (result.operands.size() == 1) 689 return result.operands.iterator().next(); 690 691 return result; 692 } 693 not(SemanticContext a)694 public static SemanticContext not(SemanticContext a) { 695 if (a instanceof NOT) { 696 return ((NOT)a).ctx; 697 } 698 699 if (a instanceof TruePredicate) 700 return new FalsePredicate(); 701 else if (a instanceof FalsePredicate) 702 return new TruePredicate(); 703 704 return new NOT(a); 705 } 706 707 // Factor so (a && b) == (result && a && b) factorAnd(SemanticContext a, SemanticContext b)708 public static SemanticContext[] factorAnd(SemanticContext a, SemanticContext b) 709 { 710 if (a == EMPTY_SEMANTIC_CONTEXT || a == null || a instanceof FalsePredicate) 711 return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b }; 712 if (b == EMPTY_SEMANTIC_CONTEXT || b == null || b instanceof FalsePredicate) 713 return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b }; 714 715 if (a instanceof TruePredicate || b instanceof TruePredicate) 716 { 717 return new SemanticContext[] { new TruePredicate(), EMPTY_SEMANTIC_CONTEXT, EMPTY_SEMANTIC_CONTEXT }; 718 } 719 720 HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getAndOperands(a)); 721 HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getAndOperands(b)); 722 723 HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA); 724 result.retainAll(opsB); 725 if (result.size() == 0) 726 return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b }; 727 728 opsA.removeAll(result); 729 if (opsA.size() == 0) 730 a = new TruePredicate(); 731 else if (opsA.size() == 1) 732 a = opsA.iterator().next(); 733 else 734 a = new AND(opsA); 735 736 opsB.removeAll(result); 737 if (opsB.size() == 0) 738 b = new TruePredicate(); 739 else if (opsB.size() == 1) 740 b = opsB.iterator().next(); 741 else 742 b = new AND(opsB); 743 744 if (result.size() == 1) 745 return new SemanticContext[] { result.iterator().next(), a, b }; 746 747 return new SemanticContext[] { new AND(result), a, b }; 748 } 749 750 // Factor so (a || b) == (result || a || b) factorOr(SemanticContext a, SemanticContext b)751 public static SemanticContext[] factorOr(SemanticContext a, SemanticContext b) 752 { 753 HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getOrOperands(a)); 754 HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getOrOperands(b)); 755 756 HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA); 757 result.retainAll(opsB); 758 if (result.size() == 0) 759 return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b }; 760 761 opsA.removeAll(result); 762 if (opsA.size() == 0) 763 a = new FalsePredicate(); 764 else if (opsA.size() == 1) 765 a = opsA.iterator().next(); 766 else 767 a = new OR(opsA); 768 769 opsB.removeAll(result); 770 if (opsB.size() == 0) 771 b = new FalsePredicate(); 772 else if (opsB.size() == 1) 773 b = opsB.iterator().next(); 774 else 775 b = new OR(opsB); 776 777 if (result.size() == 1) 778 return new SemanticContext[] { result.iterator().next(), a, b }; 779 780 return new SemanticContext[] { new OR(result), a, b }; 781 } 782 getAndOperands(SemanticContext context)783 public static Collection<SemanticContext> getAndOperands(SemanticContext context) 784 { 785 if (context instanceof AND) 786 return ((AND)context).operands; 787 788 if (context instanceof NOT) { 789 Collection<SemanticContext> operands = getOrOperands(((NOT)context).ctx); 790 List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size()); 791 for (SemanticContext operand : operands) { 792 result.add(not(operand)); 793 } 794 return result; 795 } 796 797 ArrayList<SemanticContext> result = new ArrayList<SemanticContext>(); 798 result.add(context); 799 return result; 800 } 801 getOrOperands(SemanticContext context)802 public static Collection<SemanticContext> getOrOperands(SemanticContext context) 803 { 804 if (context instanceof OR) 805 return ((OR)context).operands; 806 807 if (context instanceof NOT) { 808 Collection<SemanticContext> operands = getAndOperands(((NOT)context).ctx); 809 List<SemanticContext> result = new ArrayList<SemanticContext>(operands.size()); 810 for (SemanticContext operand : operands) { 811 result.add(not(operand)); 812 } 813 return result; 814 } 815 816 ArrayList<SemanticContext> result = new ArrayList<SemanticContext>(); 817 result.add(context); 818 return result; 819 } 820 } 821