1 /*
2  * [The "BSD license"]
3  *  Copyright (c) 2012 Terence Parr
4  *  Copyright (c) 2012 Sam Harwell
5  *  Copyright (c) 2017 Egbert Voigt
6  *  All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions
10  *  are met:
11  *
12  *  1. Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *  2. Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  *  3. The name of the author may not be used to endorse or promote products
18  *     derived from this software without specific prior written permission.
19  *
20  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 module antlr.v4.runtime.atn.OR;
33 
34 import std.conv;
35 import std.algorithm.searching;
36 import std.algorithm.iteration;
37 import std.algorithm.comparison;
38 import antlr.v4.runtime.InterfaceRecognizer;
39 import antlr.v4.runtime.Token;
40 import antlr.v4.runtime.RuleContext;
41 import antlr.v4.runtime.atn.Operator;
42 import antlr.v4.runtime.atn.SemanticContext;
43 import antlr.v4.runtime.misc.MurmurHash;
44 
45 // Class OR
46 /**
47  * A semantic context which is true whenever at least one of the contained
48  * contexts is true.
49  */
50 class OR : Operator
51 {
52 
53     public SemanticContext[] opnds;
54 
55     public this(SemanticContext a, SemanticContext b)
56     {
57         SemanticContext[] operands;
58         if (a.classinfo == OR.classinfo) operands ~= (cast(OR)a).opnds;
59         else operands ~= a;
60         if (b.classinfo == OR.classinfo) operands ~= (cast(OR)b).opnds;
61         else operands ~= b;
62 
63         SemanticContext.PrecedencePredicate[] precedencePredicates = filterPrecedencePredicates(operands);
64         if (precedencePredicates.length) {
65             // interested in the transition with the highest precedence
66             SemanticContext.PrecedencePredicate reduced = maxElement(precedencePredicates);
67             operands ~= reduced;
68         }
69         this.opnds = operands;
70     }
71 
72     /**
73      * @uml
74      * @override
75      */
76     public override SemanticContext[] getOperands()
77     {
78         return opnds;
79     }
80 
81     /**
82      * @uml
83      * @override
84      */
85     public override bool opEquals(Object obj)
86     {
87         return this.opnds == (cast(OR)obj).opnds;
88     }
89 
90     /**
91      * @uml
92      * @override
93      * @trusted
94      */
95     public override size_t toHash() @trusted
96     {
97         return MurmurHash.hashCode(opnds, this.toHash);
98     }
99 
100     /**
101      * @uml
102      * @override
103      */
104     public override bool eval(InterfaceRecognizer parser, RuleContext parserCallStack)
105     {
106         foreach (SemanticContext opnd; opnds) {
107             if (opnd.eval(parser, parserCallStack))
108                 return true;
109         }
110         return false;
111     }
112 
113     /**
114      * @uml
115      * @override
116      */
117     public override SemanticContext evalPrecedence(InterfaceRecognizer parser, RuleContext parserCallStack)
118     {
119         bool differs = false;
120         SemanticContext[] operands;
121         foreach (SemanticContext context; opnds) {
122             SemanticContext evaluated = context.evalPrecedence(parser, parserCallStack);
123             differs |= (evaluated != context);
124             if (evaluated == NONE) {
125                 // The OR context is true if any element is true
126                 return NONE;
127             }
128             else if (evaluated !is null) {
129                 // Reduce the result by skipping false elements
130                 operands ~= evaluated;
131             }
132         }
133 
134         if (!differs) {
135             return this;
136         }
137 
138         if (operands.length == 0) {
139             // all elements were false, so the OR context is false
140             return null;
141         }
142 
143         SemanticContext result = operands[0];
144         for (int i = 1; i < operands.length; i++) {
145             result = SemanticContext.or(result, operands[i]);
146         }
147         return result;
148     }
149 
150     /**
151      * @uml
152      * @override
153      */
154     public override string toString()
155     {
156         return to!string(map!(n => n.toString)(opnds).joiner(" || "));
157     }
158 
159 }