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 }