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.ATNConfig; 8 9 import antlr.v4.runtime.InterfaceRecognizer; 10 import antlr.v4.runtime.atn.ATNConfigObjectEqualityComparator; 11 import antlr.v4.runtime.atn.ATNState; 12 import antlr.v4.runtime.atn.PredictionContext; 13 import antlr.v4.runtime.atn.SemanticContext; 14 import antlr.v4.runtime.misc.MurmurHash; 15 import std.array; 16 import std.conv; 17 import std.stdio; 18 19 /** 20 * A tuple: (ATN state, predicted alt, syntactic, semantic context). 21 * The syntactic context is a graph-structured stack node whose 22 * path(s) to the root is the rule invocation(s) 23 * chain used to arrive at the state. The semantic context is 24 * the tree of semantic predicates encountered before reaching 25 * an ATN state. 26 */ 27 class ATNConfig 28 { 29 30 /** 31 * This field stores the bit mask for implementing the 32 * {@link #isPrecedenceFilterSuppressed} property as a bit within the 33 * existing {@link #reachesIntoOuterContext} field. 34 */ 35 public static immutable int SUPPRESS_PRECEDENCE_FILTER = 0x40000000; 36 37 /** 38 * The ATN state associated with this configuration. 39 */ 40 public ATNState state; 41 42 /** 43 * What alt (or lexer rule) is predicted by this configuration? 44 */ 45 public int alt; 46 47 /** 48 * The stack of invoking states leading to the rule/states associated 49 * with this config. We track only those contexts pushed during 50 * execution of the ATN simulator. 51 */ 52 public PredictionContext context; 53 54 /** 55 * We cannot execute predicates dependent upon local context unless 56 * we know for sure we are in the correct context. Because there is 57 * no way to do this efficiently, we simply cannot evaluate 58 * dependent predicates unless we are in the rule that initially 59 * invokes the ATN simulator. 60 * 61 * <p> 62 * closure() tracks the depth of how far we dip into the outer context: 63 * depth > 0. Note that it may not be totally accurate depth since I 64 * don't ever decrement. TODO: make it a boolean then</p> 65 * 66 * <p> 67 * For memory efficiency, the {@link #isPrecedenceFilterSuppressed} method 68 * is also backed by this field. Since the field is publicly accessible, the 69 * highest bit which would not cause the value to become negative is used to 70 * store this field. This choice minimizes the risk that code which only 71 * compares this value to 0 would be affected by the new purpose of the 72 * flag. It also ensures the performance of the existing {@link ATNConfig} 73 * constructors as well as certain operations like 74 * {@link ATNConfigSet#add(ATNConfig, DoubleKeyMap)} method are 75 * <em>completely</em> unaffected by the change.</p> 76 */ 77 public int reachesIntoOuterContext; 78 79 public SemanticContext semanticContext; 80 81 public size_t function(Object o) @trusted nothrow hashOfFp; 82 83 public bool function(Object a, Object b) opEqualsFp; 84 85 /** 86 * Duplication 87 */ 88 public this(ATNConfig old) 89 { 90 this.state = old.state; 91 this.alt = old.alt; 92 this.context = old.context; 93 this.semanticContext = old.semanticContext; 94 this.reachesIntoOuterContext = old.reachesIntoOuterContext; 95 this.hashOfFp = old.hashOfFp; 96 this.opEqualsFp = old.opEqualsFp; 97 } 98 99 public this(ATNState state, int alt, PredictionContext context) 100 { 101 if (!SemanticContext.NONE) { 102 auto sp = new SemanticContext; 103 SemanticContext.NONE = sp..new SemanticContext.Predicate; 104 } 105 this(state, alt, context, SemanticContext.NONE); 106 } 107 108 public this(ATNState state, int alt, PredictionContext context, const SemanticContext semanticContext) 109 { 110 this.state = state; 111 this.alt = alt; 112 this.context = context; 113 this.semanticContext = cast(SemanticContext)semanticContext; 114 this.hashOfFp = &ATNConfigObjectEqualityComparator.toHash; 115 this.opEqualsFp = &ATNConfigObjectEqualityComparator.opEquals; 116 } 117 118 public this(ATNConfig c, ATNState state) 119 { 120 //this.semanticContext = c.semanticContext; 121 this(c, state, c.context, c.semanticContext); 122 } 123 124 public this(ATNConfig c, ATNState state, SemanticContext semanticContext) 125 { 126 this(c, state, c.context, semanticContext); 127 } 128 129 public this(ATNConfig c, SemanticContext semanticContext) 130 { 131 this(c, c.state, c.context, semanticContext); 132 } 133 134 public this(ATNConfig c, ATNState state, PredictionContext context) 135 { 136 this(c, state, context, c.semanticContext); 137 } 138 139 public this(ATNConfig c, ATNState state, PredictionContext context, const SemanticContext semanticContext) 140 { 141 this.state = state; 142 this.alt = c.alt; 143 this.context = context; 144 this.semanticContext = cast(SemanticContext) semanticContext; 145 this.reachesIntoOuterContext = c.reachesIntoOuterContext; 146 this.hashOfFp = &ATNConfigObjectEqualityComparator.toHash; 147 this.opEqualsFp = &ATNConfigObjectEqualityComparator.opEquals; 148 } 149 150 /** 151 * This method gets the value of the {@link #reachesIntoOuterContext} field 152 * as it existed prior to the introduction of the 153 * {@link #isPrecedenceFilterSuppressed} method. 154 */ 155 public int getOuterContextDepth() 156 { 157 return reachesIntoOuterContext & ~SUPPRESS_PRECEDENCE_FILTER; 158 } 159 160 public bool isPrecedenceFilterSuppressed() 161 { 162 return (reachesIntoOuterContext & SUPPRESS_PRECEDENCE_FILTER) != 0; 163 } 164 165 public void setPrecedenceFilterSuppressed(bool value) 166 { 167 if (value) { 168 this.reachesIntoOuterContext |= 0x40000000; 169 } 170 else { 171 this.reachesIntoOuterContext &= ~SUPPRESS_PRECEDENCE_FILTER; 172 } 173 } 174 175 /** 176 * An ATN configuration is equal to another if both have 177 * the same state, they predict the same alternative, and 178 * syntactic/semantic contexts are the same. 179 * @uml 180 * @override 181 */ 182 public override bool opEquals(Object o) 183 { 184 if (!cast(ATNConfig)o) { 185 return false; 186 } 187 return this.opEquals(cast(ATNConfig)o); 188 } 189 190 public bool opEquals(ATNConfig other) 191 { 192 return opEqualsFp(this, other); 193 } 194 195 /** 196 * @uml 197 * @trusted 198 * @nothrow 199 * @override 200 */ 201 public override size_t toHash() @trusted nothrow 202 { 203 return hashOfFp(this); 204 } 205 206 /** 207 * @uml 208 * @override 209 */ 210 public override string toString() 211 { 212 return toString(null, true); 213 } 214 215 public string toString(InterfaceRecognizer recog, bool showAlt) 216 { 217 auto buf = appender!string; 218 // if ( state.ruleIndex>=0 ) { 219 // if ( recog!=null ) buf.append(recog.getRuleNames()[state.ruleIndex]+":"); 220 // else buf.append(state.ruleIndex+":"); 221 // } 222 buf.put('('); 223 buf.put(state.toString); 224 if ( showAlt ) { 225 buf.put(","); 226 buf.put(to!string(alt)); 227 } 228 if (context !is null) { 229 buf.put(",["); 230 buf.put(context.toString()); 231 buf.put("]"); 232 } 233 if (semanticContext && semanticContext != SemanticContext.NONE ) { 234 buf.put(","); 235 buf.put(semanticContext.toString); 236 } 237 if (getOuterContextDepth > 0) { 238 buf.put(",up="); 239 buf.put(to!string(getOuterContextDepth)); 240 } 241 buf.put(')'); 242 return buf.data; 243 } 244 245 }