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