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 }