/* 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 "Recognizer.h"
#include "support/CPPUtils.h"
#include "atn/SemanticContextType.h"
namespace antlr4 {
namespace atn {
/// A tree structure used to record the semantic context in which
/// an ATN configuration is valid. It's either a single predicate,
/// a conjunction "p1 && p2", or a sum of products "p1||p2".
///
/// I have scoped the AND, OR, and Predicate subclasses of
/// SemanticContext within the scope of this outer class.
class ANTLR4CPP_PUBLIC SemanticContext : public std::enable_shared_from_this {
public:
virtual ~SemanticContext() = default;
SemanticContextType getContextType() const { return _contextType; }
///
/// For context independent predicates, we evaluate them without a local
/// context (i.e., null context). That way, we can evaluate them without
/// having to create proper rule-specific context during prediction (as
/// opposed to the parser, which creates them naturally). In a practical
/// sense, this avoids a cast exception from RuleContext to myruleContext.
///
/// For context dependent predicates, we must pass in a local context so that
/// references such as $arg evaluate properly as _localctx.arg. We only
/// capture context dependent predicates in the context in which we begin
/// prediction, so we passed in the outer context here in case of context
/// dependent predicate evaluation.
///
virtual bool eval(Recognizer *parser, RuleContext *parserCallStack) const = 0;
/**
* Evaluate the precedence predicates for the context and reduce the result.
*
* @param parser The parser instance.
* @param parserCallStack
* @return The simplified semantic context after precedence predicates are
* evaluated, which will be one of the following values.
*
* - {@link #NONE}: if the predicate simplifies to {@code true} after
* precedence predicates are evaluated.
* - {@code null}: if the predicate simplifies to {@code false} after
* precedence predicates are evaluated.
* - {@code this}: if the semantic context is not changed as a result of
* precedence predicate evaluation.
* - A non-{@code null} {@link SemanticContext}: the new simplified
* semantic context after precedence predicates are evaluated.
*
*/
virtual Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const;
virtual size_t hashCode() const = 0;
virtual bool equals(const SemanticContext &other) const = 0;
virtual std::string toString() const = 0;
static Ref And(Ref a, Ref b);
/// See also: ParserATNSimulator::getPredsForAmbigAlts.
static Ref Or(Ref a, Ref b);
class Empty;
class Predicate;
class PrecedencePredicate;
class Operator;
class AND;
class OR;
protected:
explicit SemanticContext(SemanticContextType contextType) : _contextType(contextType) {}
private:
const SemanticContextType _contextType;
};
inline bool operator==(const SemanticContext &lhs, const SemanticContext &rhs) {
return lhs.equals(rhs);
}
inline bool operator!=(const SemanticContext &lhs, const SemanticContext &rhs) {
return !operator==(lhs, rhs);
}
class ANTLR4CPP_PUBLIC SemanticContext::Empty : public SemanticContext{
public:
/**
* The default {@link SemanticContext}, which is semantically equivalent to
* a predicate of the form {@code {true}?}.
*/
static const Ref Instance;
};
class ANTLR4CPP_PUBLIC SemanticContext::Predicate final : public SemanticContext {
public:
static bool is(const SemanticContext &semanticContext) { return semanticContext.getContextType() == SemanticContextType::PREDICATE; }
static bool is(const SemanticContext *semanticContext) { return semanticContext != nullptr && is(*semanticContext); }
const size_t ruleIndex;
const size_t predIndex;
const bool isCtxDependent; // e.g., $i ref in pred
Predicate(size_t ruleIndex, size_t predIndex, bool isCtxDependent);
bool eval(Recognizer *parser, RuleContext *parserCallStack) const override;
size_t hashCode() const override;
bool equals(const SemanticContext &other) const override;
std::string toString() const override;
};
class ANTLR4CPP_PUBLIC SemanticContext::PrecedencePredicate final : public SemanticContext {
public:
static bool is(const SemanticContext &semanticContext) { return semanticContext.getContextType() == SemanticContextType::PRECEDENCE; }
static bool is(const SemanticContext *semanticContext) { return semanticContext != nullptr && is(*semanticContext); }
const int precedence;
explicit PrecedencePredicate(int precedence);
bool eval(Recognizer *parser, RuleContext *parserCallStack) const override;
Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override;
size_t hashCode() const override;
bool equals(const SemanticContext &other) const override;
std::string toString() const override;
};
/**
* This is the base class for semantic context "operators", which operate on
* a collection of semantic context "operands".
*
* @since 4.3
*/
class ANTLR4CPP_PUBLIC SemanticContext::Operator : public SemanticContext {
public:
static bool is(const SemanticContext &semanticContext) {
const auto contextType = semanticContext.getContextType();
return contextType == SemanticContextType::AND || contextType == SemanticContextType::OR;
}
static bool is(const SemanticContext *semanticContext) { return semanticContext != nullptr && is(*semanticContext); }
/**
* Gets the operands for the semantic context operator.
*
* @return a collection of {@link SemanticContext} operands for the
* operator.
*
* @since 4.3
*/
virtual const std::vector[>& getOperands() const = 0;
protected:
using SemanticContext::SemanticContext;
};
/**
* A semantic context which is true whenever none of the contained contexts
* is false.
*/
class ANTLR4CPP_PUBLIC SemanticContext::AND final : public SemanticContext::Operator {
public:
static bool is(const SemanticContext &semanticContext) { return semanticContext.getContextType() == SemanticContextType::AND; }
static bool is(const SemanticContext *semanticContext) { return semanticContext != nullptr && is(*semanticContext); }
AND(Ref a, Ref b) ;
const std::vector][>& getOperands() const override;
/**
* The evaluation of predicates by this context is short-circuiting, but
* unordered.]
*/
bool eval(Recognizer *parser, RuleContext *parserCallStack) const override;
Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override;
size_t hashCode() const override;
bool equals(const SemanticContext &other) const override;
std::string toString() const override;
private:
std::vector[> _opnds;
};
/**
* A semantic context which is true whenever at least one of the contained
* contexts is true.
*/
class ANTLR4CPP_PUBLIC SemanticContext::OR final : public SemanticContext::Operator {
public:
static bool is(const SemanticContext &semanticContext) { return semanticContext.getContextType() == SemanticContextType::OR; }
static bool is(const SemanticContext *semanticContext) { return semanticContext != nullptr && is(*semanticContext); }
OR(Ref a, Ref b);
const std::vector][>& getOperands() const override;
/**
* The evaluation of predicates by this context is short-circuiting, but
* unordered.
*/
bool eval(Recognizer *parser, RuleContext *parserCallStack) const override;
Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override;
size_t hashCode() const override;
bool equals(const SemanticContext &other) const override;
std::string toString() const override;
private:
std::vector][> _opnds;
};
} // namespace atn
} // namespace antlr4
namespace std {
template <>
struct hash<::antlr4::atn::SemanticContext> {
size_t operator()(const ::antlr4::atn::SemanticContext &semanticContext) const {
return semanticContext.hashCode();
}
};
} // namespace std
]