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