#ifndef __ANTHEM__TERM_H #define __ANTHEM__TERM_H #include #include #include #include #include #include #include namespace anthem { //////////////////////////////////////////////////////////////////////////////////////////////////// // // Term // //////////////////////////////////////////////////////////////////////////////////////////////////// ast::BinaryOperation::Operator translate(Clingo::AST::BinaryOperator binaryOperator, const Clingo::AST::Term &term) { switch (binaryOperator) { case Clingo::AST::BinaryOperator::XOr: throw TranslationException(term.location, "binary operation “xor” currently unsupported"); case Clingo::AST::BinaryOperator::Or: throw TranslationException(term.location, "binary operation “or” currently unsupported"); case Clingo::AST::BinaryOperator::And: throw TranslationException(term.location, "binary operation “and” currently unsupported"); case Clingo::AST::BinaryOperator::Plus: return ast::BinaryOperation::Operator::Plus; case Clingo::AST::BinaryOperator::Minus: return ast::BinaryOperation::Operator::Minus; case Clingo::AST::BinaryOperator::Multiplication: return ast::BinaryOperation::Operator::Multiplication; case Clingo::AST::BinaryOperator::Division: return ast::BinaryOperation::Operator::Division; case Clingo::AST::BinaryOperator::Modulo: return ast::BinaryOperation::Operator::Modulo; case Clingo::AST::BinaryOperator::Power: return ast::BinaryOperation::Operator::Power; } throw TranslationException(term.location, "unknown binary operation"); } //////////////////////////////////////////////////////////////////////////////////////////////////// ast::Term translate(const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack); //////////////////////////////////////////////////////////////////////////////////////////////////// struct TermTranslateVisitor { std::optional visit(const Clingo::Symbol &symbol, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack) { switch (symbol.type()) { case Clingo::SymbolType::Number: return ast::Term::make(symbol.number()); case Clingo::SymbolType::Infimum: return ast::Term::make(ast::SpecialInteger::Type::Infimum); case Clingo::SymbolType::Supremum: return ast::Term::make(ast::SpecialInteger::Type::Supremum); case Clingo::SymbolType::String: return ast::Term::make(std::string(symbol.string())); case Clingo::SymbolType::Function: { auto function = ast::Term::make(symbol.name()); // TODO: remove workaround auto &functionRaw = function.get(); functionRaw.arguments.reserve(symbol.arguments().size()); for (const auto &argument : symbol.arguments()) { auto translatedArgument = visit(argument, term, ruleContext, variableStack); if (!translatedArgument) throw TranslationException(term.location, "could not translate argument"); functionRaw.arguments.emplace_back(std::move(translatedArgument.value())); } return std::move(function); } } return std::nullopt; } std::optional visit(const Clingo::AST::Variable &variable, const Clingo::AST::Term &, RuleContext &ruleContext, const ast::VariableStack &variableStack) { const auto matchingVariableDeclaration = variableStack.findUserVariableDeclaration(variable.name); const auto isAnonymousVariable = (strcmp(variable.name, "_") == 0); const auto isUndeclaredUserVariable = !matchingVariableDeclaration; const auto isUndeclared = isAnonymousVariable || isUndeclaredUserVariable; if (!isUndeclared) return ast::Term::make(*matchingVariableDeclaration); auto variableDeclaration = std::make_unique(ast::VariableDeclaration::Type::UserDefined, std::string(variable.name)); ruleContext.freeVariables.emplace_back(std::move(variableDeclaration)); return ast::Term::make(ruleContext.freeVariables.back().get()); } std::optional visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, RuleContext &, const ast::VariableStack &) { throw TranslationException(term.location, "“unary operation” terms currently unsupported"); return std::nullopt; } std::optional visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack) { const auto operator_ = translate(binaryOperation.binary_operator, term); auto left = translate(binaryOperation.left, ruleContext, variableStack); auto right = translate(binaryOperation.right, ruleContext, variableStack); return ast::Term::make(operator_, std::move(left), std::move(right)); } std::optional visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, RuleContext &ruleContext, const ast::VariableStack &variableStack) { auto left = translate(interval.left, ruleContext, variableStack); auto right = translate(interval.right, ruleContext, variableStack); return ast::Term::make(std::move(left), std::move(right)); } std::optional visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack) { if (function.external) throw TranslationException(term.location, "external functions currently unsupported"); std::vector arguments; arguments.reserve(function.arguments.size()); for (const auto &argument : function.arguments) arguments.emplace_back(translate(argument, ruleContext, variableStack)); return ast::Term::make(function.name, std::move(arguments)); } std::optional visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, RuleContext &, const ast::VariableStack &) { throw TranslationException(term.location, "“pool” terms currently unsupported"); return std::nullopt; } }; //////////////////////////////////////////////////////////////////////////////////////////////////// ast::Term translate(const Clingo::AST::Term &term, RuleContext &ruleContext, const ast::VariableStack &variableStack) { auto translatedTerm = term.data.accept(TermTranslateVisitor(), term, ruleContext, variableStack); if (!translatedTerm) throw TranslationException(term.location, "could not translate term"); return std::move(translatedTerm.value()); } //////////////////////////////////////////////////////////////////////////////////////////////////// } #endif