diff --git a/boost_tests/PushNegationTests.cpp b/boost_tests/PushNegationTests.cpp index e88d274b7..127e23aa2 100644 --- a/boost_tests/PushNegationTests.cpp +++ b/boost_tests/PushNegationTests.cpp @@ -4,6 +4,8 @@ #include #include "PetriEngine/PQL/Expressions.h" #include "PetriEngine/PQL/PushNegation.h" +#include "PetriEngine/PQL/QueryPrinter.h" +#include using namespace PetriEngine::PQL; @@ -90,3 +92,20 @@ BOOST_AUTO_TEST_CASE(equal_zero_with_plus_is_rewritten_to_leq) { BOOST_REQUIRE_MESSAGE(std::dynamic_pointer_cast(res) != nullptr, "Equality with non-negative expression should be rewritten to LessThanOrEqual"); } + +BOOST_AUTO_TEST_CASE(print_negated_trace_scoped_fireability) { + std::vector constraints(2); + constraints[0]._name = std::make_shared("N__idle"); + constraints[1]._name = std::make_shared("N__low_ready"); + for (auto& constraint : constraints) constraint._lower = 1; + auto bounds = std::make_shared(std::move(constraints), false); + auto condition = std::make_shared( + std::make_shared("T1", bounds)); + auto stats = negstat_t(); + auto simplified = pushNegation(condition, stats, EvaluationContext(), false, false, false); + + std::ostringstream os; + QueryPrinter printer(os); + Visitor::visit(printer, simplified); + BOOST_CHECK_EQUAL(os.str(), "(not ((1 <= T1.N__idle) and (1 <= T1.N__low_ready)))"); +} diff --git a/include/PetriEngine/PQL/QueryPrinter.h b/include/PetriEngine/PQL/QueryPrinter.h index 51903b4ae..944015788 100644 --- a/include/PetriEngine/PQL/QueryPrinter.h +++ b/include/PetriEngine/PQL/QueryPrinter.h @@ -122,6 +122,9 @@ namespace PetriEngine { protected: std::ostream &os; + std::string _path; + + void print_name(const std::string& name); void _accept(const LogicalCondition *element, const std::string &op); diff --git a/src/PetriEngine/PQL/QueryPrinter.cpp b/src/PetriEngine/PQL/QueryPrinter.cpp index cf86e4729..1ad7f4e00 100644 --- a/src/PetriEngine/PQL/QueryPrinter.cpp +++ b/src/PetriEngine/PQL/QueryPrinter.cpp @@ -19,6 +19,11 @@ namespace PetriEngine { namespace PQL { + void QueryPrinter::print_name(const std::string& name) { + if (!_path.empty()) os << _path << "."; + os << name; + } + void QueryPrinter::_accept(const NotCondition *element) { os << "(not "; Visitor::visit(this, (*element)[0]); @@ -69,23 +74,30 @@ namespace PetriEngine { } void QueryPrinter::_accept(const DeadlockCondition *element) { - os << "deadlock"; + print_name("deadlock"); } void QueryPrinter::_accept(const CompareConjunction *element) { os << "("; - if (element->isNegated()) os << "not"; + if (element->isNegated()) os << "not ("; bool first = true; for (const auto &cons : *element) { if (!first) os << " and "; - if (cons._lower != 0) - os << "(" << cons._lower << " <= " << *cons._name << ")"; + if (cons._lower != 0) { + os << "(" << cons._lower << " <= "; + print_name(*cons._name); + os << ")"; + } if (cons._lower != 0 && cons._upper != std::numeric_limits::max()) os << " and "; - if (cons._upper != std::numeric_limits::max()) - os << "(" << cons._upper << " >= " << *cons._name << ")"; + if (cons._upper != std::numeric_limits::max()) { + os << "(" << cons._upper << " >= "; + print_name(*cons._name); + os << ")"; + } first = false; } + if (element->isNegated()) os << ")"; os << ")"; } @@ -94,7 +106,7 @@ namespace PetriEngine { auto places = element->places(); for (size_t i = 0; i < places.size(); ++i) { if (i != 0) os << ", "; - os << *places[i]._name; + print_name(*places[i]._name); } os << ")"; } @@ -138,8 +150,10 @@ namespace PetriEngine { void QueryPrinter::_accept(const PathSelectCondition* condition) { - os << condition->name() << "."; + auto old = _path; + _path = condition->name(); Visitor::visit(this, condition->child()); + _path = old; } void QueryPrinter::_accept(const EXCondition *condition) { @@ -196,23 +210,28 @@ namespace PetriEngine { } void QueryPrinter::_accept(const UnfoldedFireableCondition *element) { - os << "is-fireable(" << *element->getName() << ")"; + os << "is-fireable("; + print_name(*element->getName()); + os << ")"; } void QueryPrinter::_accept(const FireableCondition *element) { - if(element->getCompiled()) + if (element->getCompiled()) { Visitor::visit(this, element->getCompiled()); - else - os << "is-fireable(" << *element->getName() << ")"; + return; + } + + os << "is-fireable("; + print_name(*element->getName()); + os << ")"; } void QueryPrinter::_accept(const UpperBoundsCondition *element) { os << "bounds ("; auto places = element->getPlaces(); - for(size_t i = 0; i < places.size(); ++i) - { + for(size_t i = 0; i < places.size(); ++i) { if(i != 0) os << ", "; - os << *places[i]; + print_name(*places[i]); } os << ")"; } @@ -263,7 +282,7 @@ namespace PetriEngine { } void QueryPrinter::_accept(const UnfoldedIdentifierExpr *element) { - os << *element->name(); + print_name(*element->name()); } void QueryPrinter::_accept(const LiteralExpr *element) { @@ -273,8 +292,10 @@ namespace PetriEngine { void QueryPrinter::_accept(const CommutativeExpr *element, const std::string &op) { os << "(" << element->constant(); for (const auto &id: element->places()) { - os << " " << op << " " << *id.second; + os << " " << op << " "; + print_name(*id.second); } + for (const auto &expr : element->expressions()) { os << " " << op << " "; Visitor::visit(this, expr); @@ -311,15 +332,19 @@ namespace PetriEngine { } void QueryPrinter::_accept(const IdentifierExpr *element) { - if(element->compiled()) + if (element->compiled()) { Visitor::visit(this, element->compiled()); - else - os << *element->name(); + return; + } + + print_name(*element->name()); } void QueryPrinter::_accept(const PathSelectExpr *element) { - os << element->name() << "."; + auto old = _path; + _path = element->name(); Visitor::visit(this, element->child()); + _path = old; } } }