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 }