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