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 */
28package org.antlr.analysis;
29
30import org.antlr.codegen.CodeGenerator;
31import org.antlr.grammar.v3.ANTLRParser;
32import org.antlr.tool.Grammar;
33import org.antlr.tool.GrammarAST;
34import org.stringtemplate.v4.ST;
35import org.stringtemplate.v4.STGroup;
36
37import 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 */
59public 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	 */
71	public abstract SemanticContext getGatedPredicateContext();
72
73	/** Generate an expression that will evaluate the semantic context,
74	 *  given a set of output templates.
75	 */
76	public abstract ST genExpr(CodeGenerator generator,
77										   STGroup templates,
78										   DFA dfa);
79
80	public abstract boolean hasUserSemanticPredicate(); // user-specified sempred {}? or {}?=>
81	public abstract boolean isSyntacticPredicate();
82
83	/** Notify the indicated grammar of any syn preds used within this context */
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
115		public Predicate(int constantValue) {
116			predicateAST = new GrammarAST();
117			this.constantValue=constantValue;
118		}
119
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
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		 */
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
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
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
212		public SemanticContext getGatedPredicateContext() {
213			if ( gated ) {
214				return this;
215			}
216			return null;
217		}
218
219		@Override
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
227		public boolean isSyntacticPredicate() {
228			return predicateAST !=null &&
229				( predicateAST.getType()==ANTLRParser.SYN_SEMPRED ||
230				  predicateAST.getType()==ANTLRParser.BACKTRACK_SEMPRED );
231		}
232
233		@Override
234		public void trackUseOfSyntacticPredicates(Grammar g) {
235			if ( synpred ) {
236				g.synPredNamesUsedInDFA.add(predicateAST.getText());
237			}
238		}
239
240		@Override
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 {
250		public TruePredicate() {
251			super(TRUE_PRED);
252		}
253
254		@Override
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
266		public boolean hasUserSemanticPredicate() {
267			return false; // not user specified.
268		}
269
270		@Override
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 {
277		public FalsePredicate() {
278			super(FALSE_PRED);
279		}
280
281		@Override
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
293		public boolean hasUserSemanticPredicate() {
294			return false; // not user specified.
295		}
296
297		@Override
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
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
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
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
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
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
371		public void trackUseOfSyntacticPredicates(Grammar g) {
372			for (SemanticContext semctx : operands) {
373				semctx.trackUseOfSyntacticPredicates(g);
374			}
375		}
376
377		@Override
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
412		public int hashCode(){
413			return hashcode;
414		}
415
416		@Override
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
432		public abstract String getOperandString();
433
434		public abstract SemanticContext combinePredicates(SemanticContext left, SemanticContext right);
435
436		public abstract int calculateHashCode();
437	}
438
439	public static class AND extends CommutativePredicate {
440		public AND(SemanticContext a, SemanticContext b) {
441			super(a,b);
442		}
443
444		public AND(HashSet<SemanticContext> contexts) {
445			super(contexts);
446		}
447
448		@Override
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
474		public String getOperandString() {
475			return "&&";
476		}
477
478		@Override
479		public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
480			return SemanticContext.and(left, right);
481		}
482
483		@Override
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 {
495		public OR(SemanticContext a, SemanticContext b) {
496			super(a,b);
497		}
498
499		public OR(HashSet<SemanticContext> contexts) {
500			super(contexts);
501		}
502
503		@Override
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
522		public String getOperandString() {
523			return "||";
524		}
525
526		@Override
527		public SemanticContext combinePredicates(SemanticContext left, SemanticContext right) {
528			return SemanticContext.or(left, right);
529		}
530
531		@Override
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;
544		public NOT(SemanticContext ctx) {
545			this.ctx = ctx;
546		}
547
548		@Override
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
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
574		public boolean hasUserSemanticPredicate() {
575			return ctx.hasUserSemanticPredicate();
576		}
577
578		@Override
579		public boolean isSyntacticPredicate() {
580			return ctx.isSyntacticPredicate();
581		}
582
583		@Override
584		public void trackUseOfSyntacticPredicates(Grammar g) {
585			ctx.trackUseOfSyntacticPredicates(g);
586		}
587
588		@Override
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
597		public int hashCode() {
598			return ~ctx.hashCode();
599		}
600
601		@Override
602		public String toString() {
603			return "!("+ctx+")";
604		}
605	}
606
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
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
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)
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)
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
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
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