/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. * Use of this file is governed by the BSD 3-clause license that * can be found in the LICENSE.txt file in the project root. */ #pragma once #include #include "Recognizer.h" #include "atn/ATN.h" #include "atn/ATNState.h" #include "atn/PredictionContextType.h" namespace antlr4 { class RuleContext; namespace atn { class ATN; class ArrayPredictionContext; class SingletonPredictionContext; class PredictionContextCache; class PredictionContextMergeCache; class ANTLR4CPP_PUBLIC PredictionContext { public: /// Represents $ in local context prediction, which means wildcard. /// *+x = *. static const Ref EMPTY; /// Represents $ in an array in full context mode, when $ /// doesn't mean wildcard: $ + x = [$,x]. Here, /// $ = EMPTY_RETURN_STATE. // ml: originally Integer.MAX_VALUE, which would be -1 for us, but this is already used in places where // -1 is converted to unsigned, so we use a different value here. Any value does the job provided it doesn't // conflict with real return states. static constexpr size_t EMPTY_RETURN_STATE = std::numeric_limits::max() - 9; // dispatch static Ref merge(Ref a, Ref b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); /// /// Merge two instances. /// ///

/// /// Stack tops equal, parents merge is same; return left graph.
/// /// ///

/// /// Same stack top, parents differ; merge parents giving array node, then /// remainders of those graphs. A new root node is created to point to the /// merged parents.
/// /// ///

/// /// Different stack tops pointing to same parent. Make array node for the /// root where both element in the root point to the same (original) /// parent.
/// /// ///

/// /// Different stack tops pointing to different parents. Make array node for /// the root where each element points to the corresponding original /// parent.
/// ///

/// the first /// the second /// {@code true} if this is a local-context merge, /// otherwise false to indicate a full-context merge /// static Ref mergeSingletons(Ref a, Ref b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); /** * Handle case where at least one of {@code a} or {@code b} is * {@link #EMPTY}. In the following diagrams, the symbol {@code $} is used * to represent {@link #EMPTY}. * *

Local-Context Merges

* *

These local-context merge operations are used when {@code rootIsWildcard} * is true.

* *

{@link #EMPTY} is superset of any graph; return {@link #EMPTY}.
*

* *

{@link #EMPTY} and anything is {@code #EMPTY}, so merged parent is * {@code #EMPTY}; return left graph.
*

* *

Special case of last merge if local context.
*

* *

Full-Context Merges

* *

These full-context merge operations are used when {@code rootIsWildcard} * is false.

* *

* *

Must keep all contexts; {@link #EMPTY} in array is a special value (and * null parent).
*

* *

* * @param a the first {@link SingletonPredictionContext} * @param b the second {@link SingletonPredictionContext} * @param rootIsWildcard {@code true} if this is a local-context merge, * otherwise false to indicate a full-context merge */ static Ref mergeRoot(Ref a, Ref b, bool rootIsWildcard); /** * Merge two {@link ArrayPredictionContext} instances. * *

Different tops, different parents.
*

* *

Shared top, same parents.
*

* *

Shared top, different parents.
*

* *

Shared top, all shared parents.
*

* *

Equal tops, merge parents and reduce top to * {@link SingletonPredictionContext}.
*

*/ static Ref mergeArrays(Ref a, Ref b, bool rootIsWildcard, PredictionContextMergeCache *mergeCache); static std::string toDOTString(const Ref &context); static Ref getCachedContext(const Ref &context, PredictionContextCache &contextCache); static std::vector> getAllContextNodes(const Ref &context); /// Convert a RuleContext tree to a PredictionContext graph. /// Return EMPTY if outerContext is empty. static Ref fromRuleContext(const ATN &atn, RuleContext *outerContext); PredictionContext(const PredictionContext&) = delete; virtual ~PredictionContext() = default; PredictionContext& operator=(const PredictionContext&) = delete; PredictionContext& operator=(PredictionContext&&) = delete; PredictionContextType getContextType() const { return _contextType; } virtual size_t size() const = 0; virtual const Ref& getParent(size_t index) const = 0; virtual size_t getReturnState(size_t index) const = 0; /// This means only the EMPTY (wildcard? not sure) context is in set. virtual bool isEmpty() const = 0; bool hasEmptyPath() const; size_t hashCode() const; virtual bool equals(const PredictionContext &other) const = 0; virtual std::string toString() const = 0; std::vector toStrings(Recognizer *recognizer, int currentState) const; std::vector toStrings(Recognizer *recognizer, const Ref &stop, int currentState) const; protected: explicit PredictionContext(PredictionContextType contextType); PredictionContext(PredictionContext&& other); virtual size_t hashCodeImpl() const = 0; size_t cachedHashCode() const { return _hashCode.load(std::memory_order_relaxed); } private: const PredictionContextType _contextType; mutable std::atomic _hashCode; }; inline bool operator==(const PredictionContext &lhs, const PredictionContext &rhs) { return lhs.equals(rhs); } inline bool operator!=(const PredictionContext &lhs, const PredictionContext &rhs) { return !operator==(lhs, rhs); } } // namespace atn } // namespace antlr4 namespace std { template <> struct hash<::antlr4::atn::PredictionContext> { size_t operator()(const ::antlr4::atn::PredictionContext &predictionContext) const { return predictionContext.hashCode(); } }; } // namespace std