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