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