1 /* 2 * [The "BSD license"] 3 * Copyright (c) 2016 Terence Parr 4 * Copyright (c) 2016 Sam Harwell 5 * Copyright (c) 2017 Egbert Voigt 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 module antlr.v4.runtime.atn.SemanticContext; 33 34 import std.conv; 35 import antlr.v4.runtime.RuleContext; 36 import antlr.v4.runtime.InterfaceRecognizer; 37 import antlr.v4.runtime.atn.AND; 38 import antlr.v4.runtime.atn.OR; 39 import antlr.v4.runtime.misc.MurmurHash; 40 41 // Class SemanticContext 42 /** 43 * @uml 44 * A tree structure used to record the semantic context in which 45 * an ATN configuration is valid. It's either a single predicate, 46 * a conjunction {@code p1&&p2}, or a sum of products {@code p1||p2}. 47 * 48 * <p>I have scoped the {@link AND}, {@link OR}, and {@link Predicate} subclasses of 49 * {@link SemanticContext} within the scope of this outer class.</p> 50 */ 51 class SemanticContext 52 { 53 public bool eval(InterfaceRecognizer parser, RuleContext parserCallStack) 54 { 55 return true; 56 } 57 /** 58 * @uml 59 * The default {@link SemanticContext}, which is semantically equivalent to 60 * a predicate of the form {@code {true}?}. 61 */ 62 public static SemanticContext NONE; 63 64 /** 65 * @uml 66 * For context independent predicates, we evaluate them without a local 67 * context (i.e., null context). That way, we can evaluate them without 68 * having to create proper rule-specific context during prediction (as 69 * opposed to the parser, which creates them naturally). In a practical 70 * sense, this avoids a cast exception from RuleContext to myruleContext. 71 * 72 * <p>For context dependent predicates, we must pass in a local context so that 73 * references such as $arg evaluate properly as _localctx.arg. We only 74 * capture context dependent predicates in the context in which we begin 75 * prediction, so we passed in the outer context here in case of context 76 * dependent predicate evaluation.</p> 77 */ 78 //abstract public bool eval(InterfaceRecognizer parser, RuleContext parserCallStack); 79 80 /** 81 * @uml 82 * Evaluate the precedence predicates for the context and reduce the result. 83 * 84 * @param parser The parser instance. 85 * @param parserCallStack 86 * @return The simplified semantic context after precedence predicates are 87 * evaluated, which will be one of the following values. 88 * <ul> 89 * <li>{@link #NONE}: if the predicate simplifies to {@code true} after 90 * precedence predicates are evaluated.</li> 91 * <li>{@code null}: if the predicate simplifies to {@code false} after 92 * precedence predicates are evaluated.</li> 93 * <li>{@code this}: if the semantic context is not changed as a result of 94 * precedence predicate evaluation.</li> 95 * <li>A non-{@code null} {@link SemanticContext}: the new simplified 96 * semantic context after precedence predicates are evaluated.</li> 97 * </ul> 98 */ 99 public SemanticContext evalPrecedence(InterfaceRecognizer parser, RuleContext parserCallStack) 100 { 101 return this; 102 } 103 // Class Predicate 104 /** 105 * TODO add class description 106 */ 107 class Predicate : SemanticContext 108 { 109 /** 110 * The single instance of LexerMoreAction. 111 */ 112 private static __gshared Predicate instance_; 113 114 public int ruleIndex; 115 116 public int predIndex; 117 118 /** 119 * @uml 120 * e.g., $i ref in pred 121 */ 122 public bool isCtxDependent; 123 124 public this() 125 { 126 this.ruleIndex = -1; 127 this.predIndex = -1; 128 this.isCtxDependent = false; 129 } 130 131 public this(int ruleIndex, int predIndex, bool isCtxDependent) 132 { 133 this.ruleIndex = ruleIndex; 134 this.predIndex = predIndex; 135 this.isCtxDependent = isCtxDependent; 136 } 137 138 /** 139 * @uml 140 * @override 141 */ 142 public override bool eval(InterfaceRecognizer parser, RuleContext parserCallStack) 143 { 144 RuleContext localctx = isCtxDependent ? parserCallStack : null; 145 return parser.sempred(localctx, ruleIndex, predIndex); 146 } 147 148 /** 149 * @uml 150 * @override 151 * @safe 152 * @nothrow 153 */ 154 public override size_t toHash() @safe nothrow 155 { 156 size_t hashCode = MurmurHash.initialize(); 157 hashCode = MurmurHash.update(hashCode, ruleIndex); 158 hashCode = MurmurHash.update(hashCode, predIndex); 159 hashCode = MurmurHash.update(hashCode, isCtxDependent ? 1 : 0); 160 hashCode = MurmurHash.finish(hashCode, 3); 161 return hashCode; 162 } 163 164 /** 165 * @uml 166 * @override 167 */ 168 public override bool opEquals(Object obj) 169 { 170 if (typeid(typeof(obj)) != typeid(Predicate*)) return false; 171 if ( this is obj ) return true; 172 Predicate p = cast(Predicate)obj; 173 return this.ruleIndex == p.ruleIndex && 174 this.predIndex == p.predIndex && 175 this.isCtxDependent == p.isCtxDependent; 176 } 177 178 /** 179 * @uml 180 * @override 181 */ 182 public override string toString() 183 { 184 return "{" ~ to!string(ruleIndex) ~ ":" ~ to!string(predIndex) ~ "}?"; 185 } 186 187 // /** 188 // * Creates the single instance of Predicate. 189 // */ 190 // private shared static this() 191 // { 192 // instance_ = new Predicate; 193 // } 194 195 // /** 196 // * Returns: A single instance of LexerMoreAction. 197 // */ 198 // public static Predicate instance() 199 // { 200 // return instance_; 201 // } 202 203 } 204 // Class PrecedencePredicate 205 /** 206 * TODO add class description 207 */ 208 class PrecedencePredicate : SemanticContext 209 { 210 211 /** 212 * @uml 213 * @final 214 */ 215 public int precedence; 216 217 protected this() 218 { 219 this.precedence = 0; 220 } 221 222 public this(int precedence) 223 { 224 this.precedence = precedence; 225 } 226 227 /** 228 * @uml 229 * @override 230 */ 231 public override bool eval(InterfaceRecognizer parser, RuleContext parserCallStack) 232 { 233 return parser.precpred(parserCallStack, precedence); 234 } 235 236 /** 237 * @uml 238 * @override 239 */ 240 public override SemanticContext evalPrecedence(InterfaceRecognizer parser, RuleContext parserCallStack) 241 { 242 if (parser.precpred(parserCallStack, precedence)) { 243 if (!SemanticContext.NONE) 244 SemanticContext.NONE = new Predicate; 245 return SemanticContext.NONE; 246 } 247 else { 248 return null; 249 } 250 } 251 252 /** 253 * @uml 254 * @override 255 */ 256 public override int opCmp(Object o) 257 { 258 return precedence - (cast(PrecedencePredicate)o).precedence; 259 } 260 261 /** 262 * @uml 263 * @override 264 * @safe 265 * @nothrow 266 */ 267 public override size_t toHash() @safe nothrow 268 { 269 int hashCode = 1; 270 hashCode = 31 * hashCode + precedence; 271 return hashCode; 272 } 273 274 /** 275 * @uml 276 * @override 277 */ 278 public override bool opEquals(Object obj) 279 { 280 if (obj.classinfo != PrecedencePredicate.classinfo) { 281 return false; 282 } 283 284 if (this == obj) { 285 return true; 286 } 287 288 PrecedencePredicate other = cast(PrecedencePredicate)obj; 289 return this.precedence == other.precedence; 290 } 291 292 /** 293 * @uml 294 * @override 295 * precedence >= _precedenceStack.peek() 296 */ 297 public override string toString() 298 { 299 return "{" ~ to!string(precedence) ~ ">=prec}?"; 300 } 301 302 } 303 304 /** 305 * @uml 306 * @safe 307 * @nothrow 308 * @override 309 */ 310 public override size_t toHash() @safe nothrow 311 { 312 return 1; 313 } 314 315 public static SemanticContext and(SemanticContext a, SemanticContext b) 316 { 317 if (a is null || a == NONE ) return b; 318 if (b is null || b == NONE ) return a; 319 AND result = new AND(a, b); 320 if (result.opnds.length == 1) { 321 return result.opnds[0]; 322 } 323 return result; 324 } 325 326 public static SemanticContext or(SemanticContext a, SemanticContext b) 327 { 328 if (a is null ) return b; 329 if (b is null ) return a; 330 if (a == NONE || b == NONE ) return NONE; 331 OR result = new OR(a, b); 332 if (result.opnds.length == 1) { 333 return result.opnds[0]; 334 } 335 return result; 336 } 337 338 public PrecedencePredicate[] filterPrecedencePredicates(SemanticContext[] collection) 339 { 340 PrecedencePredicate[] result; 341 foreach (context; collection) { 342 if (context.classinfo == PrecedencePredicate.classinfo) { 343 result ~= cast(PrecedencePredicate)context; 344 } 345 } 346 return result; 347 } 348 349 }