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