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