| /* 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 "misc/MurmurHash.h" |
| #include "support/CPPUtils.h" |
| #include "support/Arrays.h" |
| |
| #include "SemanticContext.h" |
| |
| using namespace antlr4; |
| using namespace antlr4::atn; |
| using namespace antlrcpp; |
| |
| //------------------ Predicate ----------------------------------------------------------------------------------------- |
| |
| SemanticContext::Predicate::Predicate() : Predicate(INVALID_INDEX, INVALID_INDEX, false) { |
| } |
| |
| SemanticContext::Predicate::Predicate(size_t ruleIndex, size_t predIndex, bool isCtxDependent) |
| : ruleIndex(ruleIndex), predIndex(predIndex), isCtxDependent(isCtxDependent) { |
| } |
| |
| |
| bool SemanticContext::Predicate::eval(Recognizer *parser, RuleContext *parserCallStack) { |
| RuleContext *localctx = nullptr; |
| 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, ruleIndex); |
| hashCode = misc::MurmurHash::update(hashCode, predIndex); |
| hashCode = misc::MurmurHash::update(hashCode, isCtxDependent ? 1 : 0); |
| hashCode = misc::MurmurHash::finish(hashCode, 3); |
| return hashCode; |
| } |
| |
| bool SemanticContext::Predicate::operator == (const SemanticContext &other) const { |
| if (this == &other) |
| return true; |
| |
| const Predicate *p = dynamic_cast<const Predicate*>(&other); |
| if (p == nullptr) |
| return false; |
| |
| return ruleIndex == p->ruleIndex && predIndex == p->predIndex && isCtxDependent == p->isCtxDependent; |
| } |
| |
| std::string SemanticContext::Predicate::toString() const { |
| return std::string("{") + std::to_string(ruleIndex) + std::string(":") + std::to_string(predIndex) + std::string("}?"); |
| } |
| |
| //------------------ PrecedencePredicate ------------------------------------------------------------------------------- |
| |
| SemanticContext::PrecedencePredicate::PrecedencePredicate() : precedence(0) { |
| } |
| |
| SemanticContext::PrecedencePredicate::PrecedencePredicate(int precedence) : precedence(precedence) { |
| } |
| |
| bool SemanticContext::PrecedencePredicate::eval(Recognizer *parser, RuleContext *parserCallStack) { |
| return parser->precpred(parserCallStack, precedence); |
| } |
| |
| Ref<SemanticContext> SemanticContext::PrecedencePredicate::evalPrecedence(Recognizer *parser, |
| RuleContext *parserCallStack) { |
| if (parser->precpred(parserCallStack, precedence)) { |
| return SemanticContext::NONE; |
| } |
| else { |
| return nullptr; |
| } |
| } |
| |
| int SemanticContext::PrecedencePredicate::compareTo(PrecedencePredicate *o) { |
| return precedence - o->precedence; |
| } |
| |
| size_t SemanticContext::PrecedencePredicate::hashCode() const { |
| size_t hashCode = 1; |
| hashCode = 31 * hashCode + static_cast<size_t>(precedence); |
| return hashCode; |
| } |
| |
| bool SemanticContext::PrecedencePredicate::operator == (const SemanticContext &other) const { |
| if (this == &other) |
| return true; |
| |
| const PrecedencePredicate *predicate = dynamic_cast<const PrecedencePredicate *>(&other); |
| if (predicate == nullptr) |
| return false; |
| |
| return precedence == predicate->precedence; |
| } |
| |
| std::string SemanticContext::PrecedencePredicate::toString() const { |
| return "{" + std::to_string(precedence) + ">=prec}?"; |
| } |
| |
| //------------------ AND ----------------------------------------------------------------------------------------------- |
| |
| SemanticContext::AND::AND(Ref<SemanticContext> const& a, Ref<SemanticContext> const& b) { |
| Set operands; |
| |
| if (is<AND>(a)) { |
| for (auto operand : std::dynamic_pointer_cast<AND>(a)->opnds) { |
| operands.insert(operand); |
| } |
| } else { |
| operands.insert(a); |
| } |
| |
| if (is<AND>(b)) { |
| for (auto operand : std::dynamic_pointer_cast<AND>(b)->opnds) { |
| operands.insert(operand); |
| } |
| } else { |
| operands.insert(b); |
| } |
| |
| std::vector<Ref<PrecedencePredicate>> precedencePredicates = filterPrecedencePredicates(operands); |
| |
| if (!precedencePredicates.empty()) { |
| // interested in the transition with the lowest precedence |
| auto predicate = [](Ref<PrecedencePredicate> const& a, Ref<PrecedencePredicate> const& b) { |
| return a->precedence < b->precedence; |
| }; |
| |
| auto reduced = std::min_element(precedencePredicates.begin(), precedencePredicates.end(), predicate); |
| operands.insert(*reduced); |
| } |
| |
| std::copy(operands.begin(), operands.end(), std::back_inserter(opnds)); |
| } |
| |
| std::vector<Ref<SemanticContext>> SemanticContext::AND::getOperands() const { |
| return opnds; |
| } |
| |
| bool SemanticContext::AND::operator == (const SemanticContext &other) const { |
| if (this == &other) |
| return true; |
| |
| const AND *context = dynamic_cast<const AND *>(&other); |
| if (context == nullptr) |
| return false; |
| |
| return Arrays::equals(opnds, context->opnds); |
| } |
| |
| size_t SemanticContext::AND::hashCode() const { |
| return misc::MurmurHash::hashCode(opnds, typeid(AND).hash_code()); |
| } |
| |
| bool SemanticContext::AND::eval(Recognizer *parser, RuleContext *parserCallStack) { |
| for (auto opnd : opnds) { |
| if (!opnd->eval(parser, parserCallStack)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| Ref<SemanticContext> SemanticContext::AND::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) { |
| bool differs = false; |
| std::vector<Ref<SemanticContext>> operands; |
| for (auto context : opnds) { |
| Ref<SemanticContext> 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) { |
| // Reduce the result by skipping true elements. |
| operands.push_back(evaluated); |
| } |
| } |
| |
| if (!differs) { |
| return shared_from_this(); |
| } |
| |
| if (operands.empty()) { |
| // All elements were true, so the AND context is true. |
| return NONE; |
| } |
| |
| Ref<SemanticContext> result = operands[0]; |
| for (size_t i = 1; i < operands.size(); ++i) { |
| result = SemanticContext::And(result, operands[i]); |
| } |
| |
| return result; |
| } |
| |
| std::string SemanticContext::AND::toString() const { |
| std::string tmp; |
| for (auto var : opnds) { |
| tmp += var->toString() + " && "; |
| } |
| return tmp; |
| } |
| |
| //------------------ OR ------------------------------------------------------------------------------------------------ |
| |
| SemanticContext::OR::OR(Ref<SemanticContext> const& a, Ref<SemanticContext> const& b) { |
| Set operands; |
| |
| if (is<OR>(a)) { |
| for (auto operand : std::dynamic_pointer_cast<OR>(a)->opnds) { |
| operands.insert(operand); |
| } |
| } else { |
| operands.insert(a); |
| } |
| |
| if (is<OR>(b)) { |
| for (auto operand : std::dynamic_pointer_cast<OR>(b)->opnds) { |
| operands.insert(operand); |
| } |
| } else { |
| operands.insert(b); |
| } |
| |
| std::vector<Ref<PrecedencePredicate>> precedencePredicates = filterPrecedencePredicates(operands); |
| if (!precedencePredicates.empty()) { |
| // interested in the transition with the highest precedence |
| auto predicate = [](Ref<PrecedencePredicate> const& a, Ref<PrecedencePredicate> const& b) { |
| return a->precedence < b->precedence; |
| }; |
| auto reduced = std::max_element(precedencePredicates.begin(), precedencePredicates.end(), predicate); |
| operands.insert(*reduced); |
| } |
| |
| std::copy(operands.begin(), operands.end(), std::back_inserter(opnds)); |
| } |
| |
| std::vector<Ref<SemanticContext>> SemanticContext::OR::getOperands() const { |
| return opnds; |
| } |
| |
| bool SemanticContext::OR::operator == (const SemanticContext &other) const { |
| if (this == &other) |
| return true; |
| |
| const OR *context = dynamic_cast<const OR *>(&other); |
| if (context == nullptr) |
| return false; |
| |
| return Arrays::equals(opnds, context->opnds); |
| } |
| |
| size_t SemanticContext::OR::hashCode() const { |
| return misc::MurmurHash::hashCode(opnds, typeid(OR).hash_code()); |
| } |
| |
| bool SemanticContext::OR::eval(Recognizer *parser, RuleContext *parserCallStack) { |
| for (auto opnd : opnds) { |
| if (opnd->eval(parser, parserCallStack)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| Ref<SemanticContext> SemanticContext::OR::evalPrecedence(Recognizer *parser, RuleContext *parserCallStack) { |
| bool differs = false; |
| std::vector<Ref<SemanticContext>> operands; |
| for (auto context : opnds) { |
| Ref<SemanticContext> 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) { |
| // Reduce the result by skipping false elements. |
| operands.push_back(evaluated); |
| } |
| } |
| |
| if (!differs) { |
| return shared_from_this(); |
| } |
| |
| if (operands.empty()) { |
| // All elements were false, so the OR context is false. |
| return nullptr; |
| } |
| |
| Ref<SemanticContext> result = operands[0]; |
| for (size_t i = 1; i < operands.size(); ++i) { |
| result = SemanticContext::Or(result, operands[i]); |
| } |
| |
| return result; |
| } |
| |
| std::string SemanticContext::OR::toString() const { |
| std::string tmp; |
| for(auto var : opnds) { |
| tmp += var->toString() + " || "; |
| } |
| return tmp; |
| } |
| |
| //------------------ SemanticContext ----------------------------------------------------------------------------------- |
| |
| const Ref<SemanticContext> SemanticContext::NONE = std::make_shared<Predicate>(INVALID_INDEX, INVALID_INDEX, false); |
| |
| SemanticContext::~SemanticContext() { |
| } |
| |
| bool SemanticContext::operator != (const SemanticContext &other) const { |
| return !(*this == other); |
| } |
| |
| Ref<SemanticContext> SemanticContext::evalPrecedence(Recognizer * /*parser*/, RuleContext * /*parserCallStack*/) { |
| return shared_from_this(); |
| } |
| |
| Ref<SemanticContext> SemanticContext::And(Ref<SemanticContext> const& a, Ref<SemanticContext> const& b) { |
| if (!a || a == NONE) { |
| return b; |
| } |
| |
| if (!b || b == NONE) { |
| return a; |
| } |
| |
| Ref<AND> result = std::make_shared<AND>(a, b); |
| if (result->opnds.size() == 1) { |
| return result->opnds[0]; |
| } |
| |
| return result; |
| } |
| |
| Ref<SemanticContext> SemanticContext::Or(Ref<SemanticContext> const& a, Ref<SemanticContext> const& b) { |
| if (!a) { |
| return b; |
| } |
| if (!b) { |
| return a; |
| } |
| |
| if (a == NONE || b == NONE) { |
| return NONE; |
| } |
| |
| Ref<OR> result = std::make_shared<OR>(a, b); |
| if (result->opnds.size() == 1) { |
| return result->opnds[0]; |
| } |
| |
| return result; |
| } |
| |
| std::vector<Ref<SemanticContext::PrecedencePredicate>> SemanticContext::filterPrecedencePredicates(const Set &collection) { |
| std::vector<Ref<SemanticContext::PrecedencePredicate>> result; |
| for (auto context : collection) { |
| if (antlrcpp::is<PrecedencePredicate>(context)) { |
| result.push_back(std::dynamic_pointer_cast<PrecedencePredicate>(context)); |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| //------------------ Operator ----------------------------------------------------------------------------------------- |
| |
| SemanticContext::Operator::~Operator() { |
| } |