1 /*
2  * Copyright (c) 2012-2018 The ANTLR Project. All rights reserved.
3  * Use of this file is governed by the BSD 3-clause license that
4  * can be found in the LICENSE.txt file in the project root.
5  */
6 
7 module antlr.v4.runtime.atn.OR;
8 
9 import antlr.v4.runtime.InterfaceRecognizer;
10 import antlr.v4.runtime.RuleContext;
11 import antlr.v4.runtime.Token;
12 import antlr.v4.runtime.atn.Operator;
13 import antlr.v4.runtime.atn.SemanticContext;
14 import antlr.v4.runtime.misc.MurmurHash;
15 import std.algorithm.comparison;
16 import std.algorithm.iteration;
17 import std.algorithm.searching;
18 import std.conv;
19 
20 /**
21  * A semantic context which is true whenever at least one of the contained
22  * contexts is true.
23  */
24 class OR : Operator
25 {
26 
27     public SemanticContext[] opnds;
28 
29     public this(SemanticContext a, SemanticContext b)
30     {
31         SemanticContext[] operands;
32         if (cast(OR)a) operands ~= (cast(OR)a).opnds;
33         else operands ~= a;
34         if (cast(OR)b) operands ~= (cast(OR)b).opnds;
35         else operands ~= b;
36 
37         SemanticContext.PrecedencePredicate[] precedencePredicates =
38             filterPrecedencePredicates(operands);
39         if (precedencePredicates.length) {
40             // interested in the transition with the highest precedence
41             SemanticContext.PrecedencePredicate reduced = maxElement(precedencePredicates);
42             operands ~= reduced;
43         }
44         this.opnds = operands;
45     }
46 
47     /**
48      * @uml
49      * @override
50      */
51     public override SemanticContext[] getOperands()
52     {
53         return opnds;
54     }
55 
56     /**
57      * @uml
58      * @override
59      */
60     public override bool opEquals(Object obj)
61     {
62         if (this is obj)
63             return true;
64         if (!cast(OR)obj)
65             return false;
66         return this.opnds == (cast(OR)obj).opnds;
67     }
68 
69     /**
70      * @uml
71      * @override
72      * @trusted
73      */
74     public override size_t toHash() @trusted
75     {
76         return MurmurHash.hashCode(opnds, this.toHash);
77     }
78 
79     /**
80      * @uml
81      * @override
82      */
83     public override bool eval(InterfaceRecognizer parser, RuleContext parserCallStack)
84     {
85         foreach (SemanticContext opnd; opnds) {
86             if (opnd.eval(parser, parserCallStack))
87                 return true;
88         }
89         return false;
90     }
91 
92     /**
93      * @uml
94      * @override
95      */
96     public override SemanticContext evalPrecedence(InterfaceRecognizer parser, RuleContext parserCallStack)
97     {
98         bool differs = false;
99         SemanticContext[] operands;
100         foreach (SemanticContext context; opnds) {
101             SemanticContext evaluated = context.evalPrecedence(parser, parserCallStack);
102             differs |= (evaluated != context);
103             if (evaluated == NONE) {
104                 // The OR context is true if any element is true
105                 return NONE;
106             }
107             else if (evaluated !is null) {
108                 // Reduce the result by skipping false elements
109                 operands ~= evaluated;
110             }
111         }
112 
113         if (!differs) {
114             return this;
115         }
116 
117         if (operands.length == 0) {
118             // all elements were false, so the OR context is false
119             return null;
120         }
121 
122         SemanticContext result = operands[0];
123         for (int i = 1; i < operands.length; i++) {
124             result = SemanticContext.or(result, operands[i]);
125         }
126         return result;
127     }
128 
129     /**
130      * @uml
131      * @override
132      */
133     public override string toString()
134     {
135         return to!string(map!(n => n.toString)(opnds).joiner(" || "));
136     }
137 
138 }