166 lines
5.0 KiB
C++
166 lines
5.0 KiB
C++
#include <anthem/Translation.h>
|
||
|
||
#include <fstream>
|
||
#include <iostream>
|
||
#include <sstream>
|
||
|
||
#include <clingo.hh>
|
||
|
||
#include <anthem/Completion.h>
|
||
#include <anthem/Context.h>
|
||
#include <anthem/IntegerVariableDetection.h>
|
||
#include <anthem/Simplification.h>
|
||
#include <anthem/StatementVisitor.h>
|
||
#include <anthem/output/AST.h>
|
||
|
||
namespace anthem
|
||
{
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Translation
|
||
//
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void translate(const std::vector<std::string> &fileNames, Context &context)
|
||
{
|
||
for (const auto &fileName : fileNames)
|
||
{
|
||
std::ifstream file(fileName, std::ios::in);
|
||
|
||
if (!file.is_open())
|
||
throw LogicException("could not read file “" + fileName + "”");
|
||
|
||
translate(fileName.c_str(), file, context);
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
void translate(const char *fileName, std::istream &stream, Context &context)
|
||
{
|
||
context.logger.log(output::Priority::Info) << "reading " << fileName;
|
||
|
||
auto fileContent = std::string(std::istreambuf_iterator<char>(stream), {});
|
||
|
||
std::vector<ast::ScopedFormula> scopedFormulas;
|
||
|
||
const auto translateStatement =
|
||
[&scopedFormulas, &context](const Clingo::AST::Statement &statement)
|
||
{
|
||
statement.data.accept(StatementVisitor(), statement, scopedFormulas, context);
|
||
};
|
||
|
||
const auto logger =
|
||
[&context](const Clingo::WarningCode, const char *text)
|
||
{
|
||
context.logger.log(output::Priority::Error) << text;
|
||
};
|
||
|
||
Clingo::parse_program(fileContent.c_str(), translateStatement, logger);
|
||
|
||
ast::PrintContext printContext(context);
|
||
|
||
if (!context.performCompletion)
|
||
{
|
||
// Simplify output if specified
|
||
if (context.performSimplification)
|
||
for (auto &scopedFormula : scopedFormulas)
|
||
simplify(scopedFormula.formula);
|
||
|
||
if (context.showStatementsUsed)
|
||
context.logger.log(output::Priority::Warning) << "#show statements are ignored because completion is not enabled";
|
||
|
||
if (context.externalStatementsUsed)
|
||
context.logger.log(output::Priority::Warning) << "#external statements are ignored because completion is not enabled";
|
||
|
||
for (const auto &scopedFormula : scopedFormulas)
|
||
{
|
||
ast::print(context.logger.outputStream(), scopedFormula.formula, printContext);
|
||
context.logger.outputStream() << std::endl;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// Perform completion
|
||
auto completedFormulas = complete(std::move(scopedFormulas), context);
|
||
|
||
for (const auto &predicateDeclaration : context.predicateDeclarations)
|
||
{
|
||
if (predicateDeclaration->isUsed)
|
||
continue;
|
||
|
||
// Check for #show statements with undeclared predicates
|
||
if (predicateDeclaration->visibility != ast::PredicateDeclaration::Visibility::Default)
|
||
context.logger.log(output::Priority::Warning)
|
||
<< "#show declaration of “"
|
||
<< predicateDeclaration->name
|
||
<< "/"
|
||
<< predicateDeclaration->arity()
|
||
<< "” does not match any declared predicate";
|
||
|
||
// Check for #external statements with undeclared predicates
|
||
if (predicateDeclaration->isExternal && !predicateDeclaration->isUsed)
|
||
context.logger.log(output::Priority::Warning)
|
||
<< "#external declaration of “"
|
||
<< predicateDeclaration->name
|
||
<< "/"
|
||
<< predicateDeclaration->arity()
|
||
<< "” does not match any declared predicate";
|
||
}
|
||
|
||
// Detect integer variables
|
||
if (context.performIntegerDetection)
|
||
detectIntegerVariables(completedFormulas);
|
||
|
||
// Simplify output if specified
|
||
if (context.performSimplification)
|
||
for (auto &completedFormula : completedFormulas)
|
||
simplify(completedFormula);
|
||
|
||
// TODO: remove variables that are not referenced after simplification
|
||
|
||
for (const auto &completedFormula : completedFormulas)
|
||
{
|
||
ast::print(context.logger.outputStream(), completedFormula, printContext);
|
||
context.logger.outputStream() << std::endl;
|
||
}
|
||
|
||
// Print specifiers for integer predicate parameters
|
||
for (auto &predicateDeclaration : context.predicateDeclarations)
|
||
{
|
||
// Check that the predicate is used and not declared #external
|
||
if (!predicateDeclaration->isUsed || predicateDeclaration->isExternal)
|
||
continue;
|
||
|
||
const auto isPredicateVisible =
|
||
(predicateDeclaration->visibility == ast::PredicateDeclaration::Visibility::Visible)
|
||
|| (predicateDeclaration->visibility == ast::PredicateDeclaration::Visibility::Default
|
||
&& context.defaultPredicateVisibility == ast::PredicateDeclaration::Visibility::Visible);
|
||
|
||
// If the predicate ought to be visible, don’t eliminate it
|
||
if (!isPredicateVisible)
|
||
continue;
|
||
|
||
for (size_t i = 0; i < predicateDeclaration->parameters.size(); i++)
|
||
{
|
||
auto ¶meter = predicateDeclaration->parameters[i];
|
||
|
||
if (parameter.domain != Domain::Integer)
|
||
continue;
|
||
|
||
context.logger.outputStream()
|
||
<< output::Keyword("int")
|
||
<< "(" << predicateDeclaration->name
|
||
<< "/" << output::Number(predicateDeclaration->arity())
|
||
<< "@" << output::Number(i + 1)
|
||
<< ")" << std::endl;
|
||
}
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
}
|