1 /*
2  * Copyright (c) 2012-2020 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)
33             operands ~= (cast(OR)a).opnds;
34         else
35             operands ~= a;
36         if (cast(OR)b)
37             operands ~= (cast(OR)b).opnds;
38         else
39         {
40             auto foundEl = false;
41             foreach (el; operands)
42             {
43                 auto bHash = b.toHash;
44                 if (el.toHash == bHash)
45                 {
46                     foundEl = true;
47                     break;
48                 }
49             }
50             if (!foundEl)
51                 operands ~= b;
52         }
53 
54         SemanticContext.PrecedencePredicate[] precedencePredicates =
55             filterPrecedencePredicates(operands);
56         if (precedencePredicates.length) {
57             // interested in the transition with the highest precedence
58             SemanticContext.PrecedencePredicate reduced = maxElement(precedencePredicates);
59             operands ~= reduced;
60         }
61         this.opnds = operands;
62     }
63 
64     /**
65      * @uml
66      * @override
67      */
68     public override SemanticContext[] getOperands()
69     {
70         return opnds;
71     }
72 
73     /**
74      * @uml
75      * @override
76      */
77     public override bool opEquals(Object obj)
78     {
79         if (this is obj)
80             return true;
81         if (!cast(OR)obj)
82             return false;
83         return this.opnds == (cast(OR)obj).opnds;
84     }
85 
86     /**
87      * @uml
88      * @override
89      * @trusted
90      */
91     public override size_t toHash() @trusted
92     {
93         size_t classId = 0;
94         foreach(el; OR.classinfo.name)
95         {
96                 classId += cast(size_t)el;
97         }
98         return MurmurHash.hashCode(opnds, classId);
99     }
100 
101     /**
102      * @uml
103      * @override
104      */
105     public override bool eval(InterfaceRecognizer parser, RuleContext parserCallStack)
106     {
107         foreach (SemanticContext opnd; opnds) {
108             if (opnd.eval(parser, parserCallStack))
109                 return true;
110         }
111         return false;
112     }
113 
114     /**
115      * @uml
116      * @override
117      */
118     public override SemanticContext evalPrecedence(InterfaceRecognizer parser, RuleContext parserCallStack)
119     {
120         bool differs = false;
121         SemanticContext[] operands;
122         foreach (SemanticContext context; opnds) {
123             SemanticContext evaluated = context.evalPrecedence(parser, parserCallStack);
124             differs |= (evaluated != context);
125             if (evaluated == NONE) {
126                 // The OR context is true if any element is true
127                 return NONE;
128             }
129             else if (evaluated !is null) {
130                 // Reduce the result by skipping false elements
131                 operands ~= evaluated;
132             }
133         }
134 
135         if (!differs) {
136             return this;
137         }
138 
139         if (operands.length == 0) {
140             // all elements were false, so the OR context is false
141             return null;
142         }
143 
144         SemanticContext result = operands[0];
145         for (int i = 1; i < operands.length; i++) {
146             result = SemanticContext.or(result, operands[i]);
147         }
148         return result;
149     }
150 
151     /**
152      * @uml
153      * @override
154      */
155     public override string toString()
156     {
157         return to!string(map!(n => n.toString)(opnds).joiner("||"));
158     }
159 
160 }