#ifndef __ANTHEM__STATEMENT_VISITOR_H #define __ANTHEM__STATEMENT_VISITOR_H #include #include #include #include #include namespace anthem { //////////////////////////////////////////////////////////////////////////////////////////////////// // // StatementVisitor // //////////////////////////////////////////////////////////////////////////////////////////////////// struct StatementVisitor { std::vector visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, Context &context) { // TODO: refactor context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str()); if (!program.parameters.empty()) throwErrorAtLocation(statement.location, "program parameters currently unsupported", context); return {}; } std::vector visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, Context &context) { context.reset(); // Concatenate all head terms rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context); ast::And antecedent; // Compute consequent auto consequent = rule.head.data.accept(HeadLiteralTranslateToConsequentVisitor(), rule.head, context); if (!consequent) { context.logger.log(output::Priority::Error, "could not translate formula consequent"); return {}; } // Generate auxiliary variables replacing the head atom’s arguments for (auto i = context.headTerms.cbegin(); i != context.headTerms.cend(); i++) { const auto &headTerm = **i; auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1); auto element = ast::Variable(std::move(variableName), ast::Variable::Type::Reserved); auto set = translate(headTerm, context); auto in = ast::In(std::move(element), std::move(set)); antecedent.arguments.emplace_back(std::move(in)); } // Translate body literals for (auto i = rule.body.cbegin(); i != rule.body.cend(); i++) { const auto &bodyLiteral = *i; auto argument = bodyLiteral.data.accept(BodyBodyLiteralTranslateVisitor(), bodyLiteral, context); if (!argument) throwErrorAtLocation(bodyLiteral.location, "could not translate body literal", context); antecedent.arguments.emplace_back(std::move(argument.value())); } std::vector formulas; if (!context.isChoiceRule) formulas.emplace_back(ast::Formula::make(std::move(antecedent), std::move(consequent.value()))); else { const auto createFormula = [&](ast::Formula &argument, bool isLastOne) { auto consequent = std::move(argument); if (!isLastOne) formulas.emplace_back(ast::Formula::make(ast::deepCopy(antecedent), std::move(consequent))); else formulas.emplace_back(ast::Formula::make(std::move(antecedent), std::move(consequent))); auto &implies = formulas.back().get(); auto &antecedent = implies.antecedent.get(); antecedent.arguments.emplace_back(ast::deepCopy(implies.consequent)); }; if (consequent.value().is()) { auto &disjunction = consequent.value().get(); for (auto &argument : disjunction.arguments) createFormula(argument, &argument == &disjunction.arguments.back()); } // TODO: check whether this is really correct for all possible consequent types else createFormula(consequent.value(), true); } for (auto &formula : formulas) { auto &implies = formula.get(); auto &antecedent = implies.antecedent.get(); // Use “true” as the consequent in case it is empty if (antecedent.arguments.empty()) implies.antecedent = ast::Formula::make(true); else if (antecedent.arguments.size() == 1) { // TODO: remove workaround auto tmp = std::move(antecedent.arguments[0]); implies.antecedent = std::move(tmp); } } return formulas; } template std::vector visit(const T &, const Clingo::AST::Statement &statement, Context &context) { throwErrorAtLocation(statement.location, "statement currently unsupported, expected rule", context); return {}; } }; //////////////////////////////////////////////////////////////////////////////////////////////////// } #endif