1 /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
2 * Use of this file is governed by the BSD 3-clause license that
3 * can be found in the LICENSE.txt file in the project root.
8 #include "Recognizer.h"
10 #include "atn/ATNState.h"
15 struct PredictionContextHasher;
16 struct PredictionContextComparer;
17 class PredictionContextMergeCache;
19 typedef std::unordered_set<Ref<PredictionContext>, PredictionContextHasher, PredictionContextComparer> PredictionContextCache;
21 class ANTLR4CPP_PUBLIC PredictionContext {
23 /// Represents $ in local context prediction, which means wildcard.
25 static const Ref<PredictionContext> EMPTY;
27 /// Represents $ in an array in full context mode, when $
28 /// doesn't mean wildcard: $ + x = [$,x]. Here,
29 /// $ = EMPTY_RETURN_STATE.
30 // ml: originally Integer.MAX_VALUE, which would be -1 for us, but this is already used in places where
31 // -1 is converted to unsigned, so we use a different value here. Any value does the job provided it doesn't
32 // conflict with real return states.
33 #if __cplusplus >= 201703L
34 static constexpr size_t EMPTY_RETURN_STATE = std::numeric_limits<size_t>::max() - 9;
37 EMPTY_RETURN_STATE = static_cast<size_t>(-10), // std::numeric_limits<size_t>::max() - 9; doesn't work in VS 2013
42 #if __cplusplus >= 201703L
43 static constexpr size_t INITIAL_HASH = 1;
51 static size_t globalNodeCount;
55 /// Stores the computed hash code of this <seealso cref="PredictionContext"/>. The hash
56 /// code is computed in parts to match the following reference algorithm.
59 /// private int referenceHashCode() {
60 /// int hash = <seealso cref="MurmurHash#initialize"/>(<seealso cref="#INITIAL_HASH"/>);
62 /// for (int i = 0; i < <seealso cref="#size()"/>; i++) {
63 /// hash = <seealso cref="MurmurHash#update"/>(hash, <seealso cref="#getParent"/>(i));
66 /// for (int i = 0; i < <seealso cref="#size()"/>; i++) {
67 /// hash = <seealso cref="MurmurHash#update"/>(hash, <seealso cref="#getReturnState"/>(i));
70 /// hash = <seealso cref="MurmurHash#finish"/>(hash, 2 * <seealso cref="#size()"/>);
75 const size_t cachedHashCode;
78 PredictionContext(size_t cachedHashCode);
82 /// Convert a RuleContext tree to a PredictionContext graph.
83 /// Return EMPTY if outerContext is empty.
84 static Ref<PredictionContext> fromRuleContext(const ATN &atn, RuleContext *outerContext);
86 virtual size_t size() const = 0;
87 virtual Ref<PredictionContext> getParent(size_t index) const = 0;
88 virtual size_t getReturnState(size_t index) const = 0;
90 virtual bool operator == (const PredictionContext &o) const = 0;
92 /// This means only the EMPTY (wildcard? not sure) context is in set.
93 virtual bool isEmpty() const;
94 virtual bool hasEmptyPath() const;
95 virtual size_t hashCode() const;
98 static size_t calculateEmptyHashCode();
99 static size_t calculateHashCode(Ref<PredictionContext> parent, size_t returnState);
100 static size_t calculateHashCode(const std::vector<Ref<PredictionContext>> &parents,
101 const std::vector<size_t> &returnStates);
105 static Ref<PredictionContext> merge(const Ref<PredictionContext> &a, const Ref<PredictionContext> &b,
106 bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
109 /// Merge two <seealso cref="SingletonPredictionContext"/> instances.
113 /// Stack tops equal, parents merge is same; return left graph.<br/>
114 /// <embed src="images/SingletonMerge_SameRootSamePar.svg" type="image/svg+xml"/>
118 /// Same stack top, parents differ; merge parents giving array node, then
119 /// remainders of those graphs. A new root node is created to point to the
120 /// merged parents.<br/>
121 /// <embed src="images/SingletonMerge_SameRootDiffPar.svg" type="image/svg+xml"/>
125 /// Different stack tops pointing to same parent. Make array node for the
126 /// root where both element in the root point to the same (original)
128 /// <embed src="images/SingletonMerge_DiffRootSamePar.svg" type="image/svg+xml"/>
132 /// Different stack tops pointing to different parents. Make array node for
133 /// the root where each element points to the corresponding original
135 /// <embed src="images/SingletonMerge_DiffRootDiffPar.svg" type="image/svg+xml"/>
137 /// <param name="a"> the first <seealso cref="SingletonPredictionContext"/> </param>
138 /// <param name="b"> the second <seealso cref="SingletonPredictionContext"/> </param>
139 /// <param name="rootIsWildcard"> {@code true} if this is a local-context merge,
140 /// otherwise false to indicate a full-context merge </param>
141 /// <param name="mergeCache"> </param>
142 static Ref<PredictionContext> mergeSingletons(const Ref<SingletonPredictionContext> &a,
143 const Ref<SingletonPredictionContext> &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
146 * Handle case where at least one of {@code a} or {@code b} is
147 * {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used
148 * to represent {@link #EMPTY}.
150 * <h2>Local-Context Merges</h2>
152 * <p>These local-context merge operations are used when {@code rootIsWildcard}
155 * <p>{@link #EMPTY} is superset of any graph; return {@link #EMPTY}.<br>
156 * <embed src="images/LocalMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
158 * <p>{@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is
159 * {@code #EMPTY}; return left graph.<br>
160 * <embed src="images/LocalMerge_EmptyParent.svg" type="image/svg+xml"/></p>
162 * <p>Special case of last merge if local context.<br>
163 * <embed src="images/LocalMerge_DiffRoots.svg" type="image/svg+xml"/></p>
165 * <h2>Full-Context Merges</h2>
167 * <p>These full-context merge operations are used when {@code rootIsWildcard}
170 * <p><embed src="images/FullMerge_EmptyRoots.svg" type="image/svg+xml"/></p>
172 * <p>Must keep all contexts; {@link #EMPTY} in array is a special value (and
174 * <embed src="images/FullMerge_EmptyRoot.svg" type="image/svg+xml"/></p>
176 * <p><embed src="images/FullMerge_SameRoot.svg" type="image/svg+xml"/></p>
178 * @param a the first {@link SingletonPredictionContext}
179 * @param b the second {@link SingletonPredictionContext}
180 * @param rootIsWildcard {@code true} if this is a local-context merge,
181 * otherwise false to indicate a full-context merge
183 static Ref<PredictionContext> mergeRoot(const Ref<SingletonPredictionContext> &a,
184 const Ref<SingletonPredictionContext> &b, bool rootIsWildcard);
187 * Merge two {@link ArrayPredictionContext} instances.
189 * <p>Different tops, different parents.<br>
190 * <embed src="images/ArrayMerge_DiffTopDiffPar.svg" type="image/svg+xml"/></p>
192 * <p>Shared top, same parents.<br>
193 * <embed src="images/ArrayMerge_ShareTopSamePar.svg" type="image/svg+xml"/></p>
195 * <p>Shared top, different parents.<br>
196 * <embed src="images/ArrayMerge_ShareTopDiffPar.svg" type="image/svg+xml"/></p>
198 * <p>Shared top, all shared parents.<br>
199 * <embed src="images/ArrayMerge_ShareTopSharePar.svg" type="image/svg+xml"/></p>
201 * <p>Equal tops, merge parents and reduce top to
202 * {@link SingletonPredictionContext}.<br>
203 * <embed src="images/ArrayMerge_EqualTop.svg" type="image/svg+xml"/></p>
205 static Ref<PredictionContext> mergeArrays(const Ref<ArrayPredictionContext> &a,
206 const Ref<ArrayPredictionContext> &b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache);
209 /// Make pass over all M parents; merge any equal() ones.
210 /// @returns true if the list has been changed (i.e. duplicates where found).
211 static bool combineCommonParents(std::vector<Ref<PredictionContext>> &parents);
214 static std::string toDOTString(const Ref<PredictionContext> &context);
216 static Ref<PredictionContext> getCachedContext(const Ref<PredictionContext> &context,
217 PredictionContextCache &contextCache,
218 std::map<Ref<PredictionContext>, Ref<PredictionContext>> &visited);
220 // ter's recursive version of Sam's getAllNodes()
221 static std::vector<Ref<PredictionContext>> getAllContextNodes(const Ref<PredictionContext> &context);
222 static void getAllContextNodes_(const Ref<PredictionContext> &context,
223 std::vector<Ref<PredictionContext>> &nodes, std::set<PredictionContext *> &visited);
225 virtual std::string toString() const;
226 virtual std::string toString(Recognizer *recog) const;
228 std::vector<std::string> toStrings(Recognizer *recognizer, int currentState);
229 std::vector<std::string> toStrings(Recognizer *recognizer, const Ref<PredictionContext> &stop, int currentState);
232 struct PredictionContextHasher {
233 size_t operator () (const Ref<PredictionContext> &k) const {
234 return k->hashCode();
238 struct PredictionContextComparer {
239 bool operator () (const Ref<PredictionContext> &lhs, const Ref<PredictionContext> &rhs) const
241 if (lhs == rhs) // Object identity.
243 return (lhs->hashCode() == rhs->hashCode()) && (*lhs == *rhs);
247 class PredictionContextMergeCache {
249 Ref<PredictionContext> put(Ref<PredictionContext> const& key1, Ref<PredictionContext> const& key2,
250 Ref<PredictionContext> const& value);
251 Ref<PredictionContext> get(Ref<PredictionContext> const& key1, Ref<PredictionContext> const& key2);
254 std::string toString() const;
255 size_t count() const;
258 std::unordered_map<Ref<PredictionContext>,
259 std::unordered_map<Ref<PredictionContext>, Ref<PredictionContext>, PredictionContextHasher, PredictionContextComparer>,
260 PredictionContextHasher, PredictionContextComparer> _data;
265 } // namespace antlr4