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 &gt; 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 }