From fb7b12ebc4b73ac846dc9923956262e8997d22d4 Mon Sep 17 00:00:00 2001 From: Justin King Date: Tue, 22 Mar 2022 12:15:54 -0700 Subject: [PATCH] [C++] Refactor and optimize SemanticContext --- .../runtime/src/FailedPredicateException.cpp | 7 +- runtime/Cpp/runtime/src/ParserInterpreter.cpp | 6 +- runtime/Cpp/runtime/src/antlr4-runtime.h | 1 - .../src/atn/AbstractPredicateTransition.cpp | 11 - .../src/atn/AbstractPredicateTransition.h | 21 -- runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp | 1 - .../Cpp/runtime/src/atn/LexerATNSimulator.cpp | 4 +- .../runtime/src/atn/ParserATNSimulator.cpp | 18 +- .../src/atn/PrecedencePredicateTransition.cpp | 9 +- .../src/atn/PrecedencePredicateTransition.h | 21 +- .../runtime/src/atn/PredicateTransition.cpp | 14 +- .../Cpp/runtime/src/atn/PredicateTransition.h | 32 ++- .../Cpp/runtime/src/atn/SemanticContext.cpp | 247 +++++++++++------- runtime/Cpp/runtime/src/atn/SemanticContext.h | 118 +++++---- .../Cpp/runtime/src/atn/SemanticContextType.h | 23 ++ .../Cpp/runtime/src/support/Declarations.h | 1 - 16 files changed, 288 insertions(+), 246 deletions(-) delete mode 100755 runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.cpp delete mode 100755 runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.h create mode 100644 runtime/Cpp/runtime/src/atn/SemanticContextType.h diff --git a/runtime/Cpp/runtime/src/FailedPredicateException.cpp b/runtime/Cpp/runtime/src/FailedPredicateException.cpp index 459f449e0d..b44725cce8 100755 --- a/runtime/Cpp/runtime/src/FailedPredicateException.cpp +++ b/runtime/Cpp/runtime/src/FailedPredicateException.cpp @@ -8,6 +8,7 @@ #include "atn/PredicateTransition.h" #include "atn/ATN.h" #include "atn/ATNState.h" +#include "support/Casts.h" #include "support/CPPUtils.h" #include "FailedPredicateException.h" @@ -27,9 +28,9 @@ FailedPredicateException::FailedPredicateException(Parser *recognizer, const std atn::ATNState *s = recognizer->getInterpreter()->atn.states[recognizer->getState()]; const atn::Transition *transition = s->transitions[0].get(); - if (is(transition)) { - _ruleIndex = static_cast(transition)->ruleIndex; - _predicateIndex = static_cast(transition)->predIndex; + if (transition->getTransitionType() == atn::TransitionType::PREDICATE) { + _ruleIndex = downCast(*transition).getRuleIndex(); + _predicateIndex = downCast(*transition).getPredIndex(); } else { _ruleIndex = 0; _predicateIndex = 0; diff --git a/runtime/Cpp/runtime/src/ParserInterpreter.cpp b/runtime/Cpp/runtime/src/ParserInterpreter.cpp index 38195fab76..8b7c805445 100755 --- a/runtime/Cpp/runtime/src/ParserInterpreter.cpp +++ b/runtime/Cpp/runtime/src/ParserInterpreter.cpp @@ -199,7 +199,7 @@ void ParserInterpreter::visitState(atn::ATNState *p) { case atn::TransitionType::PREDICATE: { const atn::PredicateTransition *predicateTransition = static_cast(transition); - if (!sempred(_ctx, predicateTransition->ruleIndex, predicateTransition->predIndex)) { + if (!sempred(_ctx, predicateTransition->getRuleIndex(), predicateTransition->getPredIndex())) { throw FailedPredicateException(this); } } @@ -214,8 +214,8 @@ void ParserInterpreter::visitState(atn::ATNState *p) { case atn::TransitionType::PRECEDENCE: { - if (!precpred(_ctx, static_cast(transition)->precedence)) { - throw FailedPredicateException(this, "precpred(_ctx, " + std::to_string(static_cast(transition)->precedence) + ")"); + if (!precpred(_ctx, static_cast(transition)->getPrecedence())) { + throw FailedPredicateException(this, "precpred(_ctx, " + std::to_string(static_cast(transition)->getPrecedence()) + ")"); } } break; diff --git a/runtime/Cpp/runtime/src/antlr4-runtime.h b/runtime/Cpp/runtime/src/antlr4-runtime.h index 193ea68964..722df6d075 100644 --- a/runtime/Cpp/runtime/src/antlr4-runtime.h +++ b/runtime/Cpp/runtime/src/antlr4-runtime.h @@ -60,7 +60,6 @@ #include "atn/ATNSimulator.h" #include "atn/ATNState.h" #include "atn/ATNType.h" -#include "atn/AbstractPredicateTransition.h" #include "atn/ActionTransition.h" #include "atn/AmbiguityInfo.h" #include "atn/ArrayPredictionContext.h" diff --git a/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.cpp b/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.cpp deleted file mode 100755 index d5c131d76a..0000000000 --- a/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.cpp +++ /dev/null @@ -1,11 +0,0 @@ -/* 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. - */ - -#include "atn/AbstractPredicateTransition.h" - -using namespace antlr4::atn; - -AbstractPredicateTransition::AbstractPredicateTransition(ATNState *target) : Transition(target) { -} diff --git a/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.h b/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.h deleted file mode 100755 index ee05b587f3..0000000000 --- a/runtime/Cpp/runtime/src/atn/AbstractPredicateTransition.h +++ /dev/null @@ -1,21 +0,0 @@ -/* 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 "atn/Transition.h" - -namespace antlr4 { -namespace atn { - - class ANTState; - - class ANTLR4CPP_PUBLIC AbstractPredicateTransition : public Transition { - public: - explicit AbstractPredicateTransition(ATNState *target); - }; - -} // namespace atn -} // namespace antlr4 diff --git a/runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp b/runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp index 4f28d8d5cd..1e6da892e0 100755 --- a/runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp +++ b/runtime/Cpp/runtime/src/atn/LL1Analyzer.cpp @@ -7,7 +7,6 @@ #include "atn/Transition.h" #include "atn/RuleTransition.h" #include "atn/SingletonPredictionContext.h" -#include "atn/AbstractPredicateTransition.h" #include "atn/WildcardTransition.h" #include "atn/NotSetTransition.h" #include "misc/IntervalSet.h" diff --git a/runtime/Cpp/runtime/src/atn/LexerATNSimulator.cpp b/runtime/Cpp/runtime/src/atn/LexerATNSimulator.cpp index b6eaff5265..ab7ba7a938 100755 --- a/runtime/Cpp/runtime/src/atn/LexerATNSimulator.cpp +++ b/runtime/Cpp/runtime/src/atn/LexerATNSimulator.cpp @@ -392,11 +392,11 @@ Ref LexerATNSimulator::getEpsilonTarget(CharStream *input, const const PredicateTransition *pt = static_cast(t); #if DEBUG_ATN == 1 - std::cout << "EVAL rule " << pt->ruleIndex << ":" << pt->predIndex << std::endl; + std::cout << "EVAL rule " << pt->getRuleIndex() << ":" << pt->getPredIndex() << std::endl; #endif configs->hasSemanticContext = true; - if (evaluatePredicate(input, pt->ruleIndex, pt->predIndex, speculative)) { + if (evaluatePredicate(input, pt->getRuleIndex(), pt->getPredIndex(), speculative)) { c = std::make_shared(*config, t->target); } break; diff --git a/runtime/Cpp/runtime/src/atn/ParserATNSimulator.cpp b/runtime/Cpp/runtime/src/atn/ParserATNSimulator.cpp index 77102d1800..534d11078c 100755 --- a/runtime/Cpp/runtime/src/atn/ParserATNSimulator.cpp +++ b/runtime/Cpp/runtime/src/atn/ParserATNSimulator.cpp @@ -1088,7 +1088,7 @@ Ref ParserATNSimulator::actionTransition(Ref const& config Ref ParserATNSimulator::precedenceTransition(Ref const& config, const PrecedencePredicateTransition *pt, bool collectPredicates, bool inContext, bool fullCtx) { #if DEBUG_DFA == 1 - std::cout << "PRED (collectPredicates=" << collectPredicates << ") " << pt->precedence << ">=_p" << ", ctx dependent=true" << std::endl; + std::cout << "PRED (collectPredicates=" << collectPredicates << ") " << pt->getPrecedence() << ">=_p" << ", ctx dependent=true" << std::endl; if (parser != nullptr) { std::cout << "context surrounding pred is " << Arrays::listToString(parser->getRuleInvocationStack(), ", ") << std::endl; } @@ -1096,7 +1096,7 @@ Ref ParserATNSimulator::precedenceTransition(Ref const& co Ref c; if (collectPredicates && inContext) { - Ref predicate = pt->getPredicate(); + const auto &predicate = pt->getPredicate(); if (fullCtx) { // In full context mode, we can evaluate predicates on-the-fly @@ -1105,14 +1105,14 @@ Ref ParserATNSimulator::precedenceTransition(Ref const& co // later during conflict resolution. size_t currentPosition = _input->index(); _input->seek(_startIndex); - bool predSucceeds = evalSemanticContext(pt->getPredicate(), _outerContext, config->alt, fullCtx); + bool predSucceeds = evalSemanticContext(predicate, _outerContext, config->alt, fullCtx); _input->seek(currentPosition); if (predSucceeds) { c = std::make_shared(*config, pt->target); // no pred context } } else { Ref newSemCtx = SemanticContext::And(config->semanticContext, predicate); - c = std::make_shared(*config, pt->target, newSemCtx); + c = std::make_shared(*config, pt->target, std::move(newSemCtx)); } } else { c = std::make_shared(*config, pt->target); @@ -1128,15 +1128,15 @@ Ref ParserATNSimulator::precedenceTransition(Ref const& co Ref ParserATNSimulator::predTransition(Ref const& config, const PredicateTransition *pt, bool collectPredicates, bool inContext, bool fullCtx) { #if DEBUG_DFA == 1 - std::cout << "PRED (collectPredicates=" << collectPredicates << ") " << pt->ruleIndex << ":" << pt->predIndex << ", ctx dependent=" << pt->isCtxDependent << std::endl; + std::cout << "PRED (collectPredicates=" << collectPredicates << ") " << pt->getRuleIndex() << ":" << pt->getPredIndex() << ", ctx dependent=" << pt->isCtxDependent() << std::endl; if (parser != nullptr) { std::cout << "context surrounding pred is " << Arrays::listToString(parser->getRuleInvocationStack(), ", ") << std::endl; } #endif Ref c = nullptr; - if (collectPredicates && (!pt->isCtxDependent || (pt->isCtxDependent && inContext))) { - Ref predicate = pt->getPredicate(); + if (collectPredicates && (!pt->isCtxDependent() || (pt->isCtxDependent() && inContext))) { + const auto &predicate = pt->getPredicate(); if (fullCtx) { // In full context mode, we can evaluate predicates on-the-fly // during closure, which dramatically reduces the size of @@ -1144,14 +1144,14 @@ Ref ParserATNSimulator::predTransition(Ref const& config, // later during conflict resolution. size_t currentPosition = _input->index(); _input->seek(_startIndex); - bool predSucceeds = evalSemanticContext(pt->getPredicate(), _outerContext, config->alt, fullCtx); + bool predSucceeds = evalSemanticContext(predicate, _outerContext, config->alt, fullCtx); _input->seek(currentPosition); if (predSucceeds) { c = std::make_shared(*config, pt->target); // no pred context } } else { Ref newSemCtx = SemanticContext::And(config->semanticContext, predicate); - c = std::make_shared(*config, pt->target, newSemCtx); + c = std::make_shared(*config, pt->target, std::move(newSemCtx)); } } else { c = std::make_shared(*config, pt->target); diff --git a/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.cpp b/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.cpp index 36f7bfa566..4e981a2a9c 100755 --- a/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.cpp +++ b/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.cpp @@ -8,8 +8,7 @@ using namespace antlr4::atn; PrecedencePredicateTransition::PrecedencePredicateTransition(ATNState *target, int precedence) - : AbstractPredicateTransition(target), precedence(precedence) { -} + : Transition(target), _predicate(std::make_shared(precedence)) {} TransitionType PrecedencePredicateTransition::getTransitionType() const { return TransitionType::PRECEDENCE; @@ -23,10 +22,6 @@ bool PrecedencePredicateTransition::matches(size_t /*symbol*/, size_t /*minVocab return false; } -Ref PrecedencePredicateTransition::getPredicate() const { - return std::make_shared(precedence); -} - std::string PrecedencePredicateTransition::toString() const { - return "PRECEDENCE " + Transition::toString() + " { precedence: " + std::to_string(precedence) + " }"; + return "PRECEDENCE " + Transition::toString() + " { precedence: " + std::to_string(getPrecedence()) + " }"; } diff --git a/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.h b/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.h index 886b7a28f7..52d95914d7 100755 --- a/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.h +++ b/runtime/Cpp/runtime/src/atn/PrecedencePredicateTransition.h @@ -5,24 +5,27 @@ #pragma once -#include "atn/AbstractPredicateTransition.h" -#include "SemanticContext.h" +#include "atn/Transition.h" +#include "atn/SemanticContext.h" namespace antlr4 { namespace atn { - class ANTLR4CPP_PUBLIC PrecedencePredicateTransition final : public AbstractPredicateTransition { + class ANTLR4CPP_PUBLIC PrecedencePredicateTransition final : public Transition { public: - const int precedence; - PrecedencePredicateTransition(ATNState *target, int precedence); + int getPrecedence() const { return _predicate->precedence; } + TransitionType getTransitionType() const override; - virtual bool isEpsilon() const override; - virtual bool matches(size_t symbol, size_t minVocabSymbol, size_t maxVocabSymbol) const override; - Ref getPredicate() const; - virtual std::string toString() const override; + bool isEpsilon() const override; + bool matches(size_t symbol, size_t minVocabSymbol, size_t maxVocabSymbol) const override; + std::string toString() const override; + + const Ref& getPredicate() const { return _predicate; } + private: + const std::shared_ptr _predicate; }; } // namespace atn diff --git a/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp b/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp index 2de6148aa9..394eaf691b 100755 --- a/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp +++ b/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp @@ -7,8 +7,8 @@ using namespace antlr4::atn; -PredicateTransition::PredicateTransition(ATNState *target, size_t ruleIndex, size_t predIndex, bool isCtxDependent) : AbstractPredicateTransition(target), ruleIndex(ruleIndex), predIndex(predIndex), isCtxDependent(isCtxDependent) { -} +PredicateTransition::PredicateTransition(ATNState *target, size_t ruleIndex, size_t predIndex, bool isCtxDependent) + : Transition(target), _predicate(std::make_shared(ruleIndex, predIndex, isCtxDependent)) {} TransitionType PredicateTransition::getTransitionType() const { return TransitionType::PREDICATE; @@ -22,13 +22,7 @@ bool PredicateTransition::matches(size_t /*symbol*/, size_t /*minVocabSymbol*/, return false; } -Ref PredicateTransition::getPredicate() const { - return std::make_shared(ruleIndex, predIndex, isCtxDependent); -} - std::string PredicateTransition::toString() const { - return "PREDICATE " + Transition::toString() + " { ruleIndex: " + std::to_string(ruleIndex) + - ", predIndex: " + std::to_string(predIndex) + ", isCtxDependent: " + std::to_string(isCtxDependent) + " }"; - - // Generate and add a predicate context here? + return "PREDICATE " + Transition::toString() + " { ruleIndex: " + std::to_string(getRuleIndex()) + + ", predIndex: " + std::to_string(getPredIndex()) + ", isCtxDependent: " + std::to_string(isCtxDependent()) + " }"; } diff --git a/runtime/Cpp/runtime/src/atn/PredicateTransition.h b/runtime/Cpp/runtime/src/atn/PredicateTransition.h index c9711baead..e41c0ad3e0 100755 --- a/runtime/Cpp/runtime/src/atn/PredicateTransition.h +++ b/runtime/Cpp/runtime/src/atn/PredicateTransition.h @@ -5,8 +5,8 @@ #pragma once -#include "atn/AbstractPredicateTransition.h" -#include "SemanticContext.h" +#include "atn/Transition.h" +#include "atn/SemanticContext.h" namespace antlr4 { namespace atn { @@ -16,23 +16,31 @@ namespace atn { /// In the ATN, labels will always be exactly one predicate, but the DFA /// may have to combine a bunch of them as it collects predicates from /// multiple ATN configurations into a single DFA state. - class ANTLR4CPP_PUBLIC PredicateTransition final : public AbstractPredicateTransition { + class ANTLR4CPP_PUBLIC PredicateTransition final : public Transition { public: - const size_t ruleIndex; - const size_t predIndex; - const bool isCtxDependent; // e.g., $i ref in pred - PredicateTransition(ATNState *target, size_t ruleIndex, size_t predIndex, bool isCtxDependent); - TransitionType getTransitionType() const override; + size_t getRuleIndex() const { + return _predicate->ruleIndex; + } - virtual bool isEpsilon() const override; - virtual bool matches(size_t symbol, size_t minVocabSymbol, size_t maxVocabSymbol) const override; + size_t getPredIndex() const { + return _predicate->predIndex; + } - Ref getPredicate() const; + bool isCtxDependent() const { + return _predicate->isCtxDependent; + } + + TransitionType getTransitionType() const override; + bool isEpsilon() const override; + bool matches(size_t symbol, size_t minVocabSymbol, size_t maxVocabSymbol) const override; + std::string toString() const override; - virtual std::string toString() const override; + const Ref& getPredicate() const { return _predicate; } + private: + const std::shared_ptr _predicate; }; } // namespace atn diff --git a/runtime/Cpp/runtime/src/atn/SemanticContext.cpp b/runtime/Cpp/runtime/src/atn/SemanticContext.cpp index 48aa410f11..f79210ed3c 100755 --- a/runtime/Cpp/runtime/src/atn/SemanticContext.cpp +++ b/runtime/Cpp/runtime/src/atn/SemanticContext.cpp @@ -38,7 +38,7 @@ namespace { Ref &precedencePredicate, Comparer comparer) { if (semanticContext != nullptr) { - if (is(semanticContext)) { + if (semanticContext->getContextType() == SemanticContextType::PRECEDENCE) { if (precedencePredicate == nullptr || comparer(downCast(semanticContext.get())->precedence, precedencePredicate->precedence)) { precedencePredicate = std::static_pointer_cast(semanticContext); } @@ -51,43 +51,79 @@ namespace { } } -} + template + void insertSemanticContext(Ref &&semanticContext, + std::unordered_set &operandSet, + std::vector> &operandList, + Ref &precedencePredicate, + Comparer comparer) { + if (semanticContext != nullptr) { + if (semanticContext->getContextType() == SemanticContextType::PRECEDENCE) { + if (precedencePredicate == nullptr || comparer(downCast(semanticContext.get())->precedence, precedencePredicate->precedence)) { + precedencePredicate = std::static_pointer_cast(std::move(semanticContext)); + } + } else { + auto [existing, inserted] = operandSet.insert(semanticContext.get()); + if (inserted) { + operandList.push_back(std::move(semanticContext)); + } + } + } + } -//------------------ Predicate ----------------------------------------------------------------------------------------- + size_t predictOperandCapacity(const Ref &x) { + switch (x->getContextType()) { + case SemanticContextType::AND: + return downCast(*x).getOperands().size(); + case SemanticContextType::OR: + return downCast(*x).getOperands().size(); + default: + return 1; + } + } + + size_t predictOperandCapacity(const Ref &a, const Ref &b) { + return predictOperandCapacity(a) + predictOperandCapacity(b); + } -SemanticContext::Predicate::Predicate() : Predicate(INVALID_INDEX, INVALID_INDEX, false) { } +//------------------ Predicate ----------------------------------------------------------------------------------------- + SemanticContext::Predicate::Predicate(size_t ruleIndex, size_t predIndex, bool isCtxDependent) -: ruleIndex(ruleIndex), predIndex(predIndex), isCtxDependent(isCtxDependent) { -} + : ruleIndex(ruleIndex), predIndex(predIndex), isCtxDependent(isCtxDependent) {} +SemanticContextType SemanticContext::Predicate::getContextType() const { + return SemanticContextType::PREDICATE; +} bool SemanticContext::Predicate::eval(Recognizer *parser, RuleContext *parserCallStack) const { RuleContext *localctx = nullptr; - if (isCtxDependent) + if (isCtxDependent) { localctx = parserCallStack; + } return parser->sempred(localctx, ruleIndex, predIndex); } size_t SemanticContext::Predicate::hashCode() const { size_t hashCode = misc::MurmurHash::initialize(); + hashCode = misc::MurmurHash::update(hashCode, static_cast(getContextType())); hashCode = misc::MurmurHash::update(hashCode, ruleIndex); hashCode = misc::MurmurHash::update(hashCode, predIndex); hashCode = misc::MurmurHash::update(hashCode, isCtxDependent ? 1 : 0); - hashCode = misc::MurmurHash::finish(hashCode, 3); + hashCode = misc::MurmurHash::finish(hashCode, 4); return hashCode; } -bool SemanticContext::Predicate::operator == (const SemanticContext &other) const { - if (this == &other) +bool SemanticContext::Predicate::equals(const SemanticContext &other) const { + if (this == &other) { return true; - - const Predicate *p = dynamic_cast(&other); - if (p == nullptr) + } + if (getContextType() != other.getContextType()) { return false; - - return ruleIndex == p->ruleIndex && predIndex == p->predIndex && isCtxDependent == p->isCtxDependent; + } + const Predicate &p = downCast(other); + return ruleIndex == p.ruleIndex && predIndex == p.predIndex && isCtxDependent == p.isCtxDependent; } std::string SemanticContext::Predicate::toString() const { @@ -96,10 +132,10 @@ std::string SemanticContext::Predicate::toString() const { //------------------ PrecedencePredicate ------------------------------------------------------------------------------- -SemanticContext::PrecedencePredicate::PrecedencePredicate() : precedence(0) { -} +SemanticContext::PrecedencePredicate::PrecedencePredicate(int precedence) : precedence(precedence) {} -SemanticContext::PrecedencePredicate::PrecedencePredicate(int precedence) : precedence(precedence) { +SemanticContextType SemanticContext::PrecedencePredicate::getContextType() const { + return SemanticContextType::PRECEDENCE; } bool SemanticContext::PrecedencePredicate::eval(Recognizer *parser, RuleContext *parserCallStack) const { @@ -111,30 +147,25 @@ Ref SemanticContext::PrecedencePredicate::evalPrecedence( if (parser->precpred(parserCallStack, precedence)) { return SemanticContext::NONE; } - else { - return nullptr; - } -} - -int SemanticContext::PrecedencePredicate::compareTo(PrecedencePredicate *o) { - return precedence - o->precedence; + return nullptr; } size_t SemanticContext::PrecedencePredicate::hashCode() const { - size_t hashCode = 1; - hashCode = 31 * hashCode + static_cast(precedence); - return hashCode; + size_t hashCode = misc::MurmurHash::initialize(); + hashCode = misc::MurmurHash::update(hashCode, static_cast(getContextType())); + hashCode = misc::MurmurHash::update(hashCode, static_cast(precedence)); + return misc::MurmurHash::finish(hashCode, 2); } -bool SemanticContext::PrecedencePredicate::operator == (const SemanticContext &other) const { - if (this == &other) +bool SemanticContext::PrecedencePredicate::equals(const SemanticContext &other) const { + if (this == &other) { return true; - - const PrecedencePredicate *predicate = dynamic_cast(&other); - if (predicate == nullptr) + } + if (getContextType() != other.getContextType()) { return false; - - return precedence == predicate->precedence; + } + const PrecedencePredicate &predicate = downCast(other); + return precedence == predicate.precedence; } std::string SemanticContext::PrecedencePredicate::toString() const { @@ -143,56 +174,64 @@ std::string SemanticContext::PrecedencePredicate::toString() const { //------------------ AND ----------------------------------------------------------------------------------------------- -SemanticContext::AND::AND(Ref const& a, Ref const& b) { +SemanticContext::AND::AND(Ref a, Ref b) { std::unordered_set operands; Ref precedencePredicate; - if (is(a)) { - for (const auto &operand : std::dynamic_pointer_cast(a)->opnds) { - insertSemanticContext(operand, operands, opnds, precedencePredicate, std::less{}); + _opnds.reserve(predictOperandCapacity(a, b) + 1); + + if (a->getContextType() == SemanticContextType::AND) { + for (const auto &operand : downCast(a.get())->getOperands()) { + insertSemanticContext(operand, operands, _opnds, precedencePredicate, std::less{}); } } else { - insertSemanticContext(a, operands, opnds, precedencePredicate, std::less{}); + insertSemanticContext(std::move(a), operands, _opnds, precedencePredicate, std::less{}); } - if (is(b)) { - for (const auto &operand : std::dynamic_pointer_cast(b)->opnds) { - insertSemanticContext(operand, operands, opnds, precedencePredicate, std::less{}); + if (b->getContextType() == SemanticContextType::AND) { + for (const auto &operand : downCast(b.get())->getOperands()) { + insertSemanticContext(operand, operands, _opnds, precedencePredicate, std::less{}); } } else { - insertSemanticContext(b, operands, opnds, precedencePredicate, std::less{}); + insertSemanticContext(std::move(b), operands, _opnds, precedencePredicate, std::less{}); } if (precedencePredicate != nullptr) { // interested in the transition with the lowest precedence auto [existing, inserted] = operands.insert(precedencePredicate.get()); if (inserted) { - opnds.push_back(std::move(precedencePredicate)); + _opnds.push_back(std::move(precedencePredicate)); } } } const std::vector>& SemanticContext::AND::getOperands() const { - return opnds; + return _opnds; } -bool SemanticContext::AND::operator==(const SemanticContext &other) const { - if (this == &other) - return true; +SemanticContextType SemanticContext::AND::getContextType() const { + return SemanticContextType::AND; +} - const AND *context = dynamic_cast(&other); - if (context == nullptr) +bool SemanticContext::AND::equals(const SemanticContext &other) const { + if (this == &other) { + return true; + } + if (getContextType() != other.getContextType()) { return false; - - return Arrays::equals(opnds, context->opnds); + } + const AND &context = downCast(other); + return Arrays::equals(getOperands(), context.getOperands()); } size_t SemanticContext::AND::hashCode() const { - return misc::MurmurHash::hashCode(opnds, typeid(AND).hash_code()); + size_t hash = misc::MurmurHash::initialize(); + hash = misc::MurmurHash::update(hash, static_cast(getContextType())); + return misc::MurmurHash::hashCode(getOperands(), hash); } bool SemanticContext::AND::eval(Recognizer *parser, RuleContext *parserCallStack) const { - for (const auto &opnd : opnds) { + for (const auto &opnd : getOperands()) { if (!opnd->eval(parser, parserCallStack)) { return false; } @@ -203,15 +242,16 @@ bool SemanticContext::AND::eval(Recognizer *parser, RuleContext *parserCallStack Ref SemanticContext::AND::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const { bool differs = false; std::vector> operands; - for (const auto &context : opnds) { - Ref evaluated = context->evalPrecedence(parser, parserCallStack); + for (const auto &context : getOperands()) { + auto evaluated = context->evalPrecedence(parser, parserCallStack); differs |= (evaluated != context); if (evaluated == nullptr) { // The AND context is false if any element is false. return nullptr; - } else if (evaluated != NONE) { + } + if (evaluated != NONE) { // Reduce the result by skipping true elements. - operands.push_back(evaluated); + operands.push_back(std::move(evaluated)); } } @@ -224,9 +264,9 @@ Ref SemanticContext::AND::evalPrecedence(Recognizer *pars return NONE; } - Ref result = operands[0]; + Ref result = std::move(operands[0]); for (size_t i = 1; i < operands.size(); ++i) { - result = SemanticContext::And(result, operands[i]); + result = SemanticContext::And(std::move(result), std::move(operands[i])); } return result; @@ -234,7 +274,7 @@ Ref SemanticContext::AND::evalPrecedence(Recognizer *pars std::string SemanticContext::AND::toString() const { std::string tmp; - for (const auto &var : opnds) { + for (const auto &var : getOperands()) { tmp += var->toString() + " && "; } return tmp; @@ -242,56 +282,64 @@ std::string SemanticContext::AND::toString() const { //------------------ OR ------------------------------------------------------------------------------------------------ -SemanticContext::OR::OR(Ref const& a, Ref const& b) { +SemanticContext::OR::OR(Ref a, Ref b) { std::unordered_set operands; Ref precedencePredicate; - if (is(a)) { - for (const auto &operand : std::dynamic_pointer_cast(a)->opnds) { - insertSemanticContext(operand, operands, opnds, precedencePredicate, std::greater{}); + _opnds.reserve(predictOperandCapacity(a, b) + 1); + + if (a->getContextType() == SemanticContextType::OR) { + for (const auto &operand : downCast(a.get())->getOperands()) { + insertSemanticContext(operand, operands, _opnds, precedencePredicate, std::greater{}); } } else { - insertSemanticContext(a, operands, opnds, precedencePredicate, std::greater{}); + insertSemanticContext(std::move(a), operands, _opnds, precedencePredicate, std::greater{}); } - if (is(b)) { - for (const auto &operand : std::dynamic_pointer_cast(b)->opnds) { - insertSemanticContext(operand, operands, opnds, precedencePredicate, std::greater{}); + if (b->getContextType() == SemanticContextType::OR) { + for (const auto &operand : downCast(b.get())->getOperands()) { + insertSemanticContext(operand, operands, _opnds, precedencePredicate, std::greater{}); } } else { - insertSemanticContext(b, operands, opnds, precedencePredicate, std::greater{}); + insertSemanticContext(std::move(b), operands, _opnds, precedencePredicate, std::greater{}); } if (precedencePredicate != nullptr) { // interested in the transition with the highest precedence auto [existing, inserted] = operands.insert(precedencePredicate.get()); if (inserted) { - opnds.push_back(std::move(precedencePredicate)); + _opnds.push_back(std::move(precedencePredicate)); } } } const std::vector>& SemanticContext::OR::getOperands() const { - return opnds; + return _opnds; } -bool SemanticContext::OR::operator==(const SemanticContext &other) const { - if (this == &other) - return true; +SemanticContextType SemanticContext::OR::getContextType() const { + return SemanticContextType::OR; +} - const OR *context = dynamic_cast(&other); - if (context == nullptr) +bool SemanticContext::OR::equals(const SemanticContext &other) const { + if (this == &other) { + return true; + } + if (getContextType() != other.getContextType()) { return false; - - return Arrays::equals(opnds, context->opnds); + } + const OR &context = downCast(other); + return Arrays::equals(getOperands(), context.getOperands()); } size_t SemanticContext::OR::hashCode() const { - return misc::MurmurHash::hashCode(opnds, typeid(OR).hash_code()); + size_t hash = misc::MurmurHash::initialize(); + hash = misc::MurmurHash::update(hash, static_cast(getContextType())); + return misc::MurmurHash::hashCode(getOperands(), hash); } bool SemanticContext::OR::eval(Recognizer *parser, RuleContext *parserCallStack) const { - for (const auto &opnd : opnds) { + for (const auto &opnd : getOperands()) { if (opnd->eval(parser, parserCallStack)) { return true; } @@ -302,15 +350,16 @@ bool SemanticContext::OR::eval(Recognizer *parser, RuleContext *parserCallStack) Ref SemanticContext::OR::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const { bool differs = false; std::vector> operands; - for (const auto &context : opnds) { - Ref evaluated = context->evalPrecedence(parser, parserCallStack); + for (const auto &context : getOperands()) { + auto evaluated = context->evalPrecedence(parser, parserCallStack); differs |= (evaluated != context); if (evaluated == NONE) { // The OR context is true if any element is true. return NONE; - } else if (evaluated != nullptr) { + } + if (evaluated != nullptr) { // Reduce the result by skipping false elements. - operands.push_back(evaluated); + operands.push_back(std::move(evaluated)); } } @@ -323,9 +372,9 @@ Ref SemanticContext::OR::evalPrecedence(Recognizer *parse return nullptr; } - Ref result = operands[0]; + Ref result = std::move(operands[0]); for (size_t i = 1; i < operands.size(); ++i) { - result = SemanticContext::Or(result, operands[i]); + result = SemanticContext::Or(std::move(result), std::move(operands[i])); } return result; @@ -333,7 +382,7 @@ Ref SemanticContext::OR::evalPrecedence(Recognizer *parse std::string SemanticContext::OR::toString() const { std::string tmp; - for(const auto &var : opnds) { + for(const auto &var : getOperands()) { tmp += var->toString() + " || "; } return tmp; @@ -343,15 +392,11 @@ std::string SemanticContext::OR::toString() const { const Ref SemanticContext::NONE = std::make_shared(INVALID_INDEX, INVALID_INDEX, false); -bool SemanticContext::operator!=(const SemanticContext &other) const { - return !(*this == other); -} - Ref SemanticContext::evalPrecedence(Recognizer * /*parser*/, RuleContext * /*parserCallStack*/) const { return shared_from_this(); } -Ref SemanticContext::And(Ref const& a, Ref const& b) { +Ref SemanticContext::And(Ref a, Ref b) { if (!a || a == NONE) { return b; } @@ -360,15 +405,15 @@ Ref SemanticContext::And(Ref const return a; } - Ref result = std::make_shared(a, b); - if (result->opnds.size() == 1) { - return result->opnds[0]; + Ref result = std::make_shared(std::move(a), std::move(b)); + if (result->getOperands().size() == 1) { + return result->getOperands()[0]; } return result; } -Ref SemanticContext::Or(Ref const& a, Ref const& b) { +Ref SemanticContext::Or(Ref a, Ref b) { if (!a) { return b; } @@ -380,9 +425,9 @@ Ref SemanticContext::Or(Ref const& return NONE; } - Ref result = std::make_shared(a, b); - if (result->opnds.size() == 1) { - return result->opnds[0]; + Ref result = std::make_shared(std::move(a), std::move(b)); + if (result->getOperands().size() == 1) { + return result->getOperands()[0]; } return result; diff --git a/runtime/Cpp/runtime/src/atn/SemanticContext.h b/runtime/Cpp/runtime/src/atn/SemanticContext.h index cf39c6c9a6..b7193332f7 100755 --- a/runtime/Cpp/runtime/src/atn/SemanticContext.h +++ b/runtime/Cpp/runtime/src/atn/SemanticContext.h @@ -7,6 +7,7 @@ #include "Recognizer.h" #include "support/CPPUtils.h" +#include "atn/SemanticContextType.h" namespace antlr4 { namespace atn { @@ -27,10 +28,7 @@ namespace atn { virtual ~SemanticContext() = default; - virtual size_t hashCode() const = 0; - virtual std::string toString() const = 0; - virtual bool operator==(const SemanticContext &other) const = 0; - virtual bool operator!=(const SemanticContext &other) const; + virtual SemanticContextType getContextType() const = 0; /// /// For context independent predicates, we evaluate them without a local @@ -67,10 +65,16 @@ namespace atn { */ virtual Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const; - static Ref And(Ref const& a, Ref const& b); + 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 const& a, Ref const& b); + static Ref Or(Ref a, Ref b); class Predicate; class PrecedencePredicate; @@ -79,40 +83,41 @@ namespace atn { class OR; }; - class ANTLR4CPP_PUBLIC SemanticContext::Predicate : public SemanticContext { + 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::Predicate final : public SemanticContext { public: const size_t ruleIndex; const size_t predIndex; const bool isCtxDependent; // e.g., $i ref in pred - protected: - Predicate(); - - public: Predicate(size_t ruleIndex, size_t predIndex, bool isCtxDependent); - virtual bool eval(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual size_t hashCode() const override; - virtual bool operator == (const SemanticContext &other) const override; - virtual std::string toString() const override; + SemanticContextType getContextType() const override; + 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 : public SemanticContext { + class ANTLR4CPP_PUBLIC SemanticContext::PrecedencePredicate final : public SemanticContext { public: const int precedence; - protected: - PrecedencePredicate(); - - public: explicit PrecedencePredicate(int precedence); - virtual bool eval(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual int compareTo(PrecedencePredicate *o); - virtual size_t hashCode() const override; - virtual bool operator == (const SemanticContext &other) const override; - virtual std::string toString() const override; + SemanticContextType getContextType() const override; + 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; }; /** @@ -139,61 +144,64 @@ namespace atn { * A semantic context which is true whenever none of the contained contexts * is false. */ - class ANTLR4CPP_PUBLIC SemanticContext::AND : public SemanticContext::Operator { + class ANTLR4CPP_PUBLIC SemanticContext::AND final : public SemanticContext::Operator { public: - std::vector> opnds; - - AND(Ref const& a, Ref const& b) ; + AND(Ref a, Ref b) ; - virtual const std::vector>& getOperands() const override; - virtual bool operator==(const SemanticContext &other) const override; - virtual size_t hashCode() const override; + const std::vector>& getOperands() const override; + SemanticContextType getContextType() const override; /** * The evaluation of predicates by this context is short-circuiting, but * unordered.

*/ - virtual bool eval(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual std::string toString() const override; + 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 : public SemanticContext::Operator { + class ANTLR4CPP_PUBLIC SemanticContext::OR final : public SemanticContext::Operator { public: - std::vector> opnds; + OR(Ref a, Ref b); - OR(Ref const& a, Ref const& b); - - virtual const std::vector>& getOperands() const override; - virtual bool operator==(const SemanticContext &other) const override; - virtual size_t hashCode() const override; + const std::vector>& getOperands() const override; + SemanticContextType getContextType() const override; /** * The evaluation of predicates by this context is short-circuiting, but * unordered. */ - virtual bool eval(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual Ref evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) const override; - virtual std::string toString() const override; + 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 atn +} // namespace antlr4 // Hash function for SemanticContext, used in the MurmurHash::update function namespace std { - using antlr4::atn::SemanticContext; - template <> struct hash - { - size_t operator () (const SemanticContext &x) const - { - return x.hashCode(); + template <> + struct hash<::antlr4::atn::SemanticContext> { + size_t operator()(const ::antlr4::atn::SemanticContext &semanticContext) const { + return semanticContext.hashCode(); } }; -} + +} // namespace std diff --git a/runtime/Cpp/runtime/src/atn/SemanticContextType.h b/runtime/Cpp/runtime/src/atn/SemanticContextType.h new file mode 100644 index 0000000000..bca6e421d2 --- /dev/null +++ b/runtime/Cpp/runtime/src/atn/SemanticContextType.h @@ -0,0 +1,23 @@ +/* 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 "antlr4-common.h" + +namespace antlr4 { +namespace atn { + + enum class SemanticContextType : size_t { + PREDICATE = 1, + PRECEDENCE = 2, + AND = 3, + OR = 4, + }; + +} // namespace atn +} // namespace antlr4 diff --git a/runtime/Cpp/runtime/src/support/Declarations.h b/runtime/Cpp/runtime/src/support/Declarations.h index 519dbbaa5e..8e960676cf 100644 --- a/runtime/Cpp/runtime/src/support/Declarations.h +++ b/runtime/Cpp/runtime/src/support/Declarations.h @@ -69,7 +69,6 @@ namespace antlr4 { class ATNSimulator; class ATNState; enum class ATNType; - class AbstractPredicateTransition; class ActionTransition; class ArrayPredictionContext; class AtomTransition;