Implemented explicit syntax tree representation for first-order formulas.
This commit is contained in:
parent
7ff537a515
commit
9e6d135781
|
@ -22,10 +22,20 @@ struct BinaryOperation
|
||||||
{
|
{
|
||||||
enum class Operator
|
enum class Operator
|
||||||
{
|
{
|
||||||
Add,
|
Plus,
|
||||||
Subtract
|
Minus,
|
||||||
|
Multiplication,
|
||||||
|
Division,
|
||||||
|
Modulo
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BinaryOperation(Operator operator_, Term &&left, Term &&right)
|
||||||
|
: operator_{operator_},
|
||||||
|
left{std::move(left)},
|
||||||
|
right{std::move(right)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Operator operator_;
|
Operator operator_;
|
||||||
Term left;
|
Term left;
|
||||||
Term right;
|
Term right;
|
||||||
|
@ -35,53 +45,173 @@ struct BinaryOperation
|
||||||
|
|
||||||
struct Boolean
|
struct Boolean
|
||||||
{
|
{
|
||||||
|
Boolean(bool value)
|
||||||
|
: value{value}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool value = false;
|
bool value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Equals
|
struct Comparison
|
||||||
{
|
{
|
||||||
|
enum class Operator
|
||||||
|
{
|
||||||
|
GreaterThan,
|
||||||
|
LessThan,
|
||||||
|
LessEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
NotEqual,
|
||||||
|
Equal
|
||||||
|
};
|
||||||
|
|
||||||
|
Comparison(Operator operator_, Term &&left, Term &&right)
|
||||||
|
: operator_{operator_},
|
||||||
|
left{std::move(left)},
|
||||||
|
right{std::move(right)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Operator operator_;
|
||||||
Term left;
|
Term left;
|
||||||
Term right;
|
Term right;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct Constant
|
||||||
|
{
|
||||||
|
Constant(std::string &&name)
|
||||||
|
: name{std::move(name)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Function
|
struct Function
|
||||||
{
|
{
|
||||||
const char *name = nullptr;
|
Function(std::string &&name, std::vector<Term> &&arguments)
|
||||||
|
: name{std::move(name)},
|
||||||
|
arguments{std::move(arguments)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
std::vector<Term> arguments;
|
std::vector<Term> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct In
|
||||||
|
{
|
||||||
|
In(Term &&element, Term &&set)
|
||||||
|
: element{std::move(element)},
|
||||||
|
set{std::move(set)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Term element;
|
||||||
|
Term set;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Integer
|
struct Integer
|
||||||
{
|
{
|
||||||
|
Integer(int value)
|
||||||
|
: value{value}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct IntegerRange
|
struct Interval
|
||||||
{
|
{
|
||||||
Integer from;
|
Interval(Term &&from, Term &&to)
|
||||||
Integer to;
|
: from{std::move(from)},
|
||||||
|
to{std::move(to)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Term from;
|
||||||
|
Term to;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Predicate
|
struct Predicate
|
||||||
{
|
{
|
||||||
const char *name = nullptr;
|
Predicate(std::string &&name)
|
||||||
|
: name{std::move(name)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Predicate(std::string &&name, std::vector<Term> &&arguments)
|
||||||
|
: name{std::move(name)},
|
||||||
|
arguments{std::move(arguments)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
std::vector<Term> arguments;
|
std::vector<Term> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct SpecialInteger
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Infimum,
|
||||||
|
Supremum
|
||||||
|
};
|
||||||
|
|
||||||
|
SpecialInteger(Type type)
|
||||||
|
: type{type}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct String
|
||||||
|
{
|
||||||
|
String(std::string &&text)
|
||||||
|
: text{std::move(text)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Variable
|
struct Variable
|
||||||
{
|
{
|
||||||
const char *name = nullptr;
|
enum class Type
|
||||||
|
{
|
||||||
|
UserDefined,
|
||||||
|
Reserved
|
||||||
|
};
|
||||||
|
|
||||||
|
Variable(std::string &&name, Type type)
|
||||||
|
: name{std::move(name)},
|
||||||
|
type{type}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
Type type;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -90,6 +220,13 @@ struct Variable
|
||||||
|
|
||||||
struct And
|
struct And
|
||||||
{
|
{
|
||||||
|
And() = default;
|
||||||
|
|
||||||
|
And(std::vector<Formula> &&arguments)
|
||||||
|
: arguments{std::move(arguments)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Formula> arguments;
|
std::vector<Formula> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -97,6 +234,12 @@ struct And
|
||||||
|
|
||||||
struct Biconditional
|
struct Biconditional
|
||||||
{
|
{
|
||||||
|
Biconditional(Formula &&left, Formula &&right)
|
||||||
|
: left{std::move(left)},
|
||||||
|
right{std::move(right)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Formula left;
|
Formula left;
|
||||||
Formula right;
|
Formula right;
|
||||||
};
|
};
|
||||||
|
@ -105,22 +248,40 @@ struct Biconditional
|
||||||
|
|
||||||
struct Exists
|
struct Exists
|
||||||
{
|
{
|
||||||
|
Exists(std::vector<VariablePointer> &&variables, Formula &&argument)
|
||||||
|
: variables{std::move(variables)},
|
||||||
|
argument{std::move(argument)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<VariablePointer> variables;
|
std::vector<VariablePointer> variables;
|
||||||
Formula formula;
|
Formula argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct ForAll
|
struct ForAll
|
||||||
{
|
{
|
||||||
|
ForAll(std::vector<VariablePointer> &&variables, Formula &&argument)
|
||||||
|
: variables{std::move(variables)},
|
||||||
|
argument{std::move(argument)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<VariablePointer> variables;
|
std::vector<VariablePointer> variables;
|
||||||
Formula formula;
|
Formula argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct Implies
|
struct Implies
|
||||||
{
|
{
|
||||||
|
Implies(Formula &&antecedent, Formula &&consequent)
|
||||||
|
: antecedent{std::move(antecedent)},
|
||||||
|
consequent{std::move(consequent)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Formula antecedent;
|
Formula antecedent;
|
||||||
Formula consequent;
|
Formula consequent;
|
||||||
};
|
};
|
||||||
|
@ -129,6 +290,11 @@ struct Implies
|
||||||
|
|
||||||
struct Not
|
struct Not
|
||||||
{
|
{
|
||||||
|
Not(Formula &&argument)
|
||||||
|
: argument{std::move(argument)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Formula argument;
|
Formula argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,12 +302,261 @@ struct Not
|
||||||
|
|
||||||
struct Or
|
struct Or
|
||||||
{
|
{
|
||||||
|
Or() = default;
|
||||||
|
|
||||||
|
Or(std::vector<Formula> &&arguments)
|
||||||
|
: arguments{std::move(arguments)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<Formula> arguments;
|
std::vector<Formula> arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Deep Copying
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
BinaryOperation deepCopy(const BinaryOperation &other);
|
||||||
|
Boolean deepCopy(const Boolean &other);
|
||||||
|
Comparison deepCopy(const Comparison &other);
|
||||||
|
Constant deepCopy(const Constant &other);
|
||||||
|
Function deepCopy(const Function &other);
|
||||||
|
Integer deepCopy(const Integer &other);
|
||||||
|
Interval deepCopy(const Interval &other);
|
||||||
|
Predicate deepCopy(const Predicate &other);
|
||||||
|
SpecialInteger deepCopy(const SpecialInteger &other);
|
||||||
|
String deepCopy(const String &other);
|
||||||
|
Variable deepCopy(const Variable &other);
|
||||||
|
std::vector<VariablePointer> deepCopy(const std::vector<VariablePointer> &other);
|
||||||
|
And deepCopy(const And &other);
|
||||||
|
Biconditional deepCopy(const Biconditional &other);
|
||||||
|
Exists deepCopy(const Exists &other);
|
||||||
|
ForAll deepCopy(const ForAll &other);
|
||||||
|
Implies deepCopy(const Implies &other);
|
||||||
|
Not deepCopy(const Not &other);
|
||||||
|
Or deepCopy(const Or &other);
|
||||||
|
|
||||||
|
Formula deepCopy(const Formula &formula);
|
||||||
|
std::vector<Formula> deepCopy(const std::vector<Formula> &formulas);
|
||||||
|
Term deepCopy(const Term &term);
|
||||||
|
std::vector<Term> deepCopy(const std::vector<Term> &terms);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const auto deepCopyUniquePtr =
|
||||||
|
[](const auto &uniquePtr) -> typename std::decay<decltype(uniquePtr)>::type
|
||||||
|
{
|
||||||
|
using Type = typename std::decay<decltype(uniquePtr)>::type::element_type;
|
||||||
|
return std::make_unique<Type>(deepCopy(*uniquePtr));
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const auto deepCopyUniquePtrVector =
|
||||||
|
[](const auto &uniquePtrVector) -> typename std::decay<decltype(uniquePtrVector)>::type
|
||||||
|
{
|
||||||
|
using Type = typename std::decay<decltype(uniquePtrVector)>::type::value_type;
|
||||||
|
|
||||||
|
std::vector<Type> result;
|
||||||
|
result.reserve(uniquePtrVector.size());
|
||||||
|
|
||||||
|
for (const auto &uniquePtr : uniquePtrVector)
|
||||||
|
result.emplace_back(deepCopyUniquePtr(uniquePtr));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const auto deepCopyVariant =
|
||||||
|
[](const auto &variant) -> typename std::decay<decltype(variant)>::type
|
||||||
|
{
|
||||||
|
return variant.match([](const auto &x) -> typename std::decay<decltype(variant)>::type {return deepCopyUniquePtr(x);});
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const auto deepCopyVariantVector =
|
||||||
|
[](const auto &variantVector) -> typename std::decay<decltype(variantVector)>::type
|
||||||
|
{
|
||||||
|
using Type = typename std::decay<decltype(variantVector)>::type::value_type;
|
||||||
|
|
||||||
|
std::vector<Type> result;
|
||||||
|
result.reserve(variantVector.size());
|
||||||
|
|
||||||
|
for (const auto &variant : variantVector)
|
||||||
|
result.emplace_back(deepCopyVariant(variant));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
BinaryOperation deepCopy(const BinaryOperation &other)
|
||||||
|
{
|
||||||
|
return BinaryOperation(other.operator_, deepCopy(other.left), deepCopy(other.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Boolean deepCopy(const Boolean &other)
|
||||||
|
{
|
||||||
|
return Boolean(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Comparison deepCopy(const Comparison &other)
|
||||||
|
{
|
||||||
|
return Comparison(other.operator_, deepCopy(other.left), deepCopy(other.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Constant deepCopy(const Constant &other)
|
||||||
|
{
|
||||||
|
return Constant(std::string(other.name));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Function deepCopy(const Function &other)
|
||||||
|
{
|
||||||
|
return Function(std::string(other.name), deepCopy(other.arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Integer deepCopy(const Integer &other)
|
||||||
|
{
|
||||||
|
return Integer(other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Interval deepCopy(const Interval &other)
|
||||||
|
{
|
||||||
|
return Interval(deepCopy(other.from), deepCopy(other.to));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Predicate deepCopy(const Predicate &other)
|
||||||
|
{
|
||||||
|
return Predicate(std::string(other.name), deepCopy(other.arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SpecialInteger deepCopy(const SpecialInteger &other)
|
||||||
|
{
|
||||||
|
return SpecialInteger(other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
String deepCopy(const String &other)
|
||||||
|
{
|
||||||
|
return String(std::string(other.text));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Variable deepCopy(const Variable &other)
|
||||||
|
{
|
||||||
|
return Variable(std::string(other.name), other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::vector<VariablePointer> deepCopy(const std::vector<VariablePointer> &other)
|
||||||
|
{
|
||||||
|
return deepCopyUniquePtrVector(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
And deepCopy(const And &other)
|
||||||
|
{
|
||||||
|
return And(deepCopy(other.arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Biconditional deepCopy(const Biconditional &other)
|
||||||
|
{
|
||||||
|
return Biconditional(deepCopy(other.left), deepCopy(other.right));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Exists deepCopy(const Exists &other)
|
||||||
|
{
|
||||||
|
return Exists(deepCopy(other.variables), deepCopy(other.argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ForAll deepCopy(const ForAll &other)
|
||||||
|
{
|
||||||
|
return ForAll(deepCopy(other.variables), deepCopy(other.argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
In deepCopy(const In &other)
|
||||||
|
{
|
||||||
|
return In(deepCopy(other.element), deepCopy(other.set));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Implies deepCopy(const Implies &other)
|
||||||
|
{
|
||||||
|
return Implies(deepCopy(other.antecedent), deepCopy(other.consequent));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Not deepCopy(const Not &other)
|
||||||
|
{
|
||||||
|
return Not(deepCopy(other.argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Or deepCopy(const Or &other)
|
||||||
|
{
|
||||||
|
return Or(deepCopy(other.arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Formula deepCopy(const Formula &formula)
|
||||||
|
{
|
||||||
|
return deepCopyVariant(formula);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::vector<Formula> deepCopy(const std::vector<Formula> &formulas)
|
||||||
|
{
|
||||||
|
return deepCopyVariantVector(formulas);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Term deepCopy(const Term &term)
|
||||||
|
{
|
||||||
|
return deepCopyVariant(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
std::vector<Term> deepCopy(const std::vector<Term> &terms)
|
||||||
|
{
|
||||||
|
return deepCopyVariantVector(terms);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -24,60 +24,55 @@ struct And;
|
||||||
struct BinaryOperation;
|
struct BinaryOperation;
|
||||||
struct Biconditional;
|
struct Biconditional;
|
||||||
struct Boolean;
|
struct Boolean;
|
||||||
|
struct Comparison;
|
||||||
struct Constant;
|
struct Constant;
|
||||||
struct Equals;
|
|
||||||
struct Exists;
|
struct Exists;
|
||||||
struct ForAll;
|
struct ForAll;
|
||||||
struct Function;
|
struct Function;
|
||||||
struct Implies;
|
struct Implies;
|
||||||
|
struct In;
|
||||||
struct Integer;
|
struct Integer;
|
||||||
struct IntegerRange;
|
struct Interval;
|
||||||
struct Not;
|
struct Not;
|
||||||
struct Or;
|
struct Or;
|
||||||
struct Predicate;
|
struct Predicate;
|
||||||
|
struct SpecialInteger;
|
||||||
|
struct String;
|
||||||
struct Variable;
|
struct Variable;
|
||||||
|
|
||||||
using AndPointer = std::unique_ptr<And>;
|
using AndPointer = std::unique_ptr<And>;
|
||||||
using BinaryOperationPointer = std::unique_ptr<BinaryOperation>;
|
using BinaryOperationPointer = std::unique_ptr<BinaryOperation>;
|
||||||
using BiconditionalPointer = std::unique_ptr<Biconditional>;
|
using BiconditionalPointer = std::unique_ptr<Biconditional>;
|
||||||
using BooleanPointer = std::unique_ptr<Boolean>;
|
using BooleanPointer = std::unique_ptr<Boolean>;
|
||||||
|
using ComparisonPointer = std::unique_ptr<Comparison>;
|
||||||
using ConstantPointer = std::unique_ptr<Constant>;
|
using ConstantPointer = std::unique_ptr<Constant>;
|
||||||
using EqualsPointer = std::unique_ptr<Equals>;
|
|
||||||
using ExistsPointer = std::unique_ptr<Exists>;
|
using ExistsPointer = std::unique_ptr<Exists>;
|
||||||
using ForAllPointer = std::unique_ptr<ForAll>;
|
using ForAllPointer = std::unique_ptr<ForAll>;
|
||||||
using FunctionPointer = std::unique_ptr<Function>;
|
using FunctionPointer = std::unique_ptr<Function>;
|
||||||
using ImpliesPointer = std::unique_ptr<Implies>;
|
using ImpliesPointer = std::unique_ptr<Implies>;
|
||||||
|
using InPointer = std::unique_ptr<In>;
|
||||||
using IntegerPointer = std::unique_ptr<Integer>;
|
using IntegerPointer = std::unique_ptr<Integer>;
|
||||||
using IntegerRangePointer = std::unique_ptr<IntegerRange>;
|
using IntervalPointer = std::unique_ptr<Interval>;
|
||||||
using NotPointer = std::unique_ptr<Not>;
|
using NotPointer = std::unique_ptr<Not>;
|
||||||
using OrPointer = std::unique_ptr<Or>;
|
using OrPointer = std::unique_ptr<Or>;
|
||||||
using PredicatePointer = std::unique_ptr<Predicate>;
|
using PredicatePointer = std::unique_ptr<Predicate>;
|
||||||
|
using SpecialIntegerPointer = std::unique_ptr<SpecialInteger>;
|
||||||
|
using StringPointer = std::unique_ptr<String>;
|
||||||
using VariablePointer = std::unique_ptr<Variable>;
|
using VariablePointer = std::unique_ptr<Variable>;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Variants
|
// Variants
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
using TermT = mapbox::util::variant<
|
|
||||||
BinaryOperationPointer,
|
|
||||||
ConstantPointer,
|
|
||||||
IntegerPointer,
|
|
||||||
FunctionPointer,
|
|
||||||
VariablePointer>;
|
|
||||||
|
|
||||||
class Term : public TermT
|
|
||||||
{
|
|
||||||
using TermT::TermT;
|
|
||||||
};
|
|
||||||
|
|
||||||
using FormulaT = mapbox::util::variant<
|
using FormulaT = mapbox::util::variant<
|
||||||
AndPointer,
|
AndPointer,
|
||||||
BiconditionalPointer,
|
BiconditionalPointer,
|
||||||
BooleanPointer,
|
BooleanPointer,
|
||||||
EqualsPointer,
|
ComparisonPointer,
|
||||||
ExistsPointer,
|
ExistsPointer,
|
||||||
ForAllPointer,
|
ForAllPointer,
|
||||||
ImpliesPointer,
|
ImpliesPointer,
|
||||||
|
InPointer,
|
||||||
NotPointer,
|
NotPointer,
|
||||||
OrPointer,
|
OrPointer,
|
||||||
PredicatePointer>;
|
PredicatePointer>;
|
||||||
|
@ -87,7 +82,21 @@ class Formula : public FormulaT
|
||||||
using FormulaT::FormulaT;
|
using FormulaT::FormulaT;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Formulas = std::vector<Formula>;
|
using TermT = mapbox::util::variant<
|
||||||
|
BinaryOperationPointer,
|
||||||
|
BooleanPointer,
|
||||||
|
ConstantPointer,
|
||||||
|
FunctionPointer,
|
||||||
|
IntegerPointer,
|
||||||
|
IntervalPointer,
|
||||||
|
SpecialIntegerPointer,
|
||||||
|
StringPointer,
|
||||||
|
VariablePointer>;
|
||||||
|
|
||||||
|
class Term : public TermT
|
||||||
|
{
|
||||||
|
using TermT::TermT;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <anthem/Context.h>
|
#include <anthem/AST.h>
|
||||||
|
#include <anthem/Term.h>
|
||||||
#include <anthem/Utils.h>
|
#include <anthem/Utils.h>
|
||||||
#include <anthem/output/ClingoOutput.h>
|
|
||||||
#include <anthem/output/Formatting.h>
|
#include <anthem/output/Formatting.h>
|
||||||
|
|
||||||
namespace anthem
|
namespace anthem
|
||||||
|
@ -17,204 +17,199 @@ namespace anthem
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct TermPrintVisitor
|
ast::Comparison::Operator translate(Clingo::AST::ComparisonOperator comparisonOperator)
|
||||||
{
|
{
|
||||||
void visit(const Clingo::Symbol &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
switch (comparisonOperator)
|
||||||
|
{
|
||||||
|
case Clingo::AST::ComparisonOperator::GreaterThan:
|
||||||
|
return ast::Comparison::Operator::GreaterThan;
|
||||||
|
case Clingo::AST::ComparisonOperator::LessThan:
|
||||||
|
return ast::Comparison::Operator::LessThan;
|
||||||
|
case Clingo::AST::ComparisonOperator::LessEqual:
|
||||||
|
return ast::Comparison::Operator::LessEqual;
|
||||||
|
case Clingo::AST::ComparisonOperator::GreaterEqual:
|
||||||
|
return ast::Comparison::Operator::GreaterEqual;
|
||||||
|
case Clingo::AST::ComparisonOperator::NotEqual:
|
||||||
|
return ast::Comparison::Operator::NotEqual;
|
||||||
|
case Clingo::AST::ComparisonOperator::Equal:
|
||||||
|
return ast::Comparison::Operator::Equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast::Comparison::Operator::NotEqual;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ast::VariablePointer makeAuxiliaryBodyVariable(const int i)
|
||||||
|
{
|
||||||
|
auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(i);
|
||||||
|
|
||||||
|
return std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved);
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct BodyTermTranslateVisitor
|
||||||
|
{
|
||||||
|
std::experimental::optional<ast::Formula> visit(const Clingo::Symbol &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“symbol” terms currently unsupported in this context", context);
|
throwErrorAtLocation(term.location, "“symbol” terms currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Variable &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Variable &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“variable” terms currently unsupported in this context", context);
|
throwErrorAtLocation(term.location, "“variable” terms currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported in this context", context);
|
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported in this context", context);
|
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Interval &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Interval &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“interval” terms currently unsupported in this context", context);
|
throwErrorAtLocation(term.location, "“interval” terms currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check correctness
|
// TODO: refactor
|
||||||
void visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Literal &literal, const Clingo::AST::Term &, Context &context)
|
||||||
{
|
{
|
||||||
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
|
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
|
||||||
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
|
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
|
||||||
|
|
||||||
auto &outputStream = context.logger.outputStream();
|
|
||||||
|
|
||||||
if (function.arguments.empty())
|
if (function.arguments.empty())
|
||||||
|
return std::make_unique<ast::Predicate>(std::string(function.name));
|
||||||
|
|
||||||
|
std::vector<ast::VariablePointer> variables;
|
||||||
|
variables.reserve(function.arguments.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < function.arguments.size(); i++)
|
||||||
|
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i));
|
||||||
|
|
||||||
|
auto conjunction = std::make_unique<ast::And>();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < function.arguments.size(); i++)
|
||||||
{
|
{
|
||||||
outputStream << output::Function(function.name);
|
const auto &argument = function.arguments[i];
|
||||||
return;
|
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i), translate(argument, context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
outputStream << output::Keyword("exists") << " ";
|
auto predicate = std::make_unique<ast::Predicate>(std::string(function.name));
|
||||||
|
predicate->arguments.reserve(function.arguments.size());
|
||||||
|
|
||||||
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
for (size_t i = 0; i < function.arguments.size(); i++)
|
||||||
{
|
predicate->arguments.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + i));
|
||||||
if (i != function.arguments.cbegin())
|
|
||||||
outputStream << ", ";
|
|
||||||
|
|
||||||
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
|
if (literal.sign == Clingo::AST::Sign::None)
|
||||||
|
conjunction->arguments.emplace_back(std::move(predicate));
|
||||||
outputStream << output::Variable(variableName.c_str());
|
else
|
||||||
}
|
conjunction->arguments.emplace_back(std::make_unique<ast::Not>(std::move(predicate)));
|
||||||
|
|
||||||
outputStream << " (";
|
|
||||||
|
|
||||||
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
|
||||||
{
|
|
||||||
const auto &argument = *i;
|
|
||||||
|
|
||||||
if (i != function.arguments.cbegin())
|
|
||||||
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
|
|
||||||
|
|
||||||
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
|
|
||||||
|
|
||||||
outputStream
|
|
||||||
<< output::Variable(variableName.c_str())
|
|
||||||
<< " " << output::Keyword("in") << " "
|
|
||||||
<< argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStream
|
|
||||||
<< " " << Clingo::AST::BinaryOperator::And << " "
|
|
||||||
<< literal.sign
|
|
||||||
<< output::Function(function.name) << "(";
|
|
||||||
|
|
||||||
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
|
||||||
{
|
|
||||||
if (i != function.arguments.cbegin())
|
|
||||||
outputStream << ", ";
|
|
||||||
|
|
||||||
const auto variableName = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + i - function.arguments.cbegin());
|
|
||||||
|
|
||||||
outputStream << output::Variable(variableName.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
outputStream << "))";
|
|
||||||
|
|
||||||
context.auxiliaryBodyLiteralID += function.arguments.size();
|
context.auxiliaryBodyLiteralID += function.arguments.size();
|
||||||
|
|
||||||
|
return std::make_unique<ast::Exists>(std::move(variables), std::move(conjunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Pool &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Pool &, const Clingo::AST::Literal &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
|
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct LiteralPrintVisitor
|
struct BodyLiteralTranslateVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(literal.location, "“boolean” literals currently unsupported in this context", context);
|
throwErrorAtLocation(literal.location, "“boolean” literals currently unsupported in this context", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
term.data.accept(TermPrintVisitor(), literal, term, context);
|
return term.data.accept(BodyTermTranslateVisitor(), literal, term, context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
void visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Comparison &comparison, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
assert(literal.sign == Clingo::AST::Sign::None);
|
assert(literal.sign == Clingo::AST::Sign::None);
|
||||||
|
|
||||||
const char *operatorName = "";
|
const auto operator_ = translate(comparison.comparison);
|
||||||
|
|
||||||
switch (comparison.comparison)
|
std::vector<ast::VariablePointer> variables;
|
||||||
{
|
variables.reserve(2);
|
||||||
case Clingo::AST::ComparisonOperator::GreaterThan:
|
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID));
|
||||||
operatorName = ">";
|
variables.emplace_back(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1));
|
||||||
break;
|
|
||||||
case Clingo::AST::ComparisonOperator::LessThan:
|
|
||||||
operatorName = "<";
|
|
||||||
break;
|
|
||||||
case Clingo::AST::ComparisonOperator::LessEqual:
|
|
||||||
operatorName = "<=";
|
|
||||||
break;
|
|
||||||
case Clingo::AST::ComparisonOperator::GreaterEqual:
|
|
||||||
operatorName = ">=";
|
|
||||||
break;
|
|
||||||
case Clingo::AST::ComparisonOperator::NotEqual:
|
|
||||||
operatorName = "!=";
|
|
||||||
break;
|
|
||||||
case Clingo::AST::ComparisonOperator::Equal:
|
|
||||||
operatorName = "=";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto variableName1 = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID);
|
auto conjunction = std::make_unique<ast::And>();
|
||||||
const auto variableName2 = std::string(AuxiliaryBodyVariablePrefix) + std::to_string(context.auxiliaryBodyLiteralID + 1);
|
conjunction->arguments.reserve(3);
|
||||||
|
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID), translate(comparison.left, context)));
|
||||||
context.logger.outputStream()
|
conjunction->arguments.emplace_back(std::make_unique<ast::In>(makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1), translate(comparison.right, context)));
|
||||||
<< output::Keyword("exists") << " " << output::Variable(variableName1.c_str())
|
conjunction->arguments.emplace_back(std::make_unique<ast::Comparison>(operator_, makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID), makeAuxiliaryBodyVariable(context.auxiliaryBodyLiteralID + 1)));
|
||||||
<< ", " << output::Variable(variableName2.c_str())
|
|
||||||
<< " ("
|
|
||||||
<< output::Variable(variableName1.c_str())
|
|
||||||
<< " " << output::Keyword("in") << " " << comparison.left
|
|
||||||
<< " " << Clingo::AST::BinaryOperator::And << " "
|
|
||||||
<< output::Variable(variableName2.c_str())
|
|
||||||
<< " " << output::Keyword("in") << " " << comparison.right
|
|
||||||
<< " " << Clingo::AST::BinaryOperator::And << " "
|
|
||||||
<< output::Variable(variableName1.c_str())
|
|
||||||
<< " " << output::Operator(operatorName) << " "
|
|
||||||
<< output::Variable(variableName2.c_str())
|
|
||||||
<< ")";
|
|
||||||
|
|
||||||
context.auxiliaryBodyLiteralID += 2;
|
context.auxiliaryBodyLiteralID += 2;
|
||||||
|
|
||||||
|
return std::make_unique<ast::Exists>(std::move(variables), std::move(conjunction));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(literal.location, "CSP literals currently unsupported", context);
|
throwErrorAtLocation(literal.location, "CSP literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct BodyLiteralPrintVisitor
|
struct BodyBodyLiteralTranslateVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::BodyLiteral &, Context &context)
|
||||||
{
|
{
|
||||||
literal.data.accept(LiteralPrintVisitor(), literal, context);
|
return literal.data.accept(BodyLiteralTranslateVisitor(), literal, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::ConditionalLiteral &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ConditionalLiteral &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(bodyLiteral.location, "“conditional literal” body literals currently unsupported", context);
|
throwErrorAtLocation(bodyLiteral.location, "“conditional literal” body literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Aggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Aggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(bodyLiteral.location, "“aggregate” body literals currently unsupported", context);
|
throwErrorAtLocation(bodyLiteral.location, "“aggregate” body literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::BodyAggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BodyAggregate &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(bodyLiteral.location, "“body aggregate” body literals currently unsupported", context);
|
throwErrorAtLocation(bodyLiteral.location, "“body aggregate” body literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(bodyLiteral.location, "“theory atom” body literals currently unsupported", context);
|
throwErrorAtLocation(bodyLiteral.location, "“theory atom” body literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Disjoint &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Disjoint &, const Clingo::AST::BodyLiteral &bodyLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(bodyLiteral.location, "“disjoint” body literals currently unsupported", context);
|
throwErrorAtLocation(bodyLiteral.location, "“disjoint” body literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <anthem/AST.h>
|
||||||
#include <anthem/Utils.h>
|
#include <anthem/Utils.h>
|
||||||
#include <anthem/output/ClingoOutput.h>
|
|
||||||
#include <anthem/output/Formatting.h>
|
#include <anthem/output/Formatting.h>
|
||||||
|
|
||||||
namespace anthem
|
namespace anthem
|
||||||
|
@ -139,155 +139,179 @@ struct HeadLiteralCollectFunctionTermsVisitor
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct TermPrintSubstitutedVisitor
|
struct FunctionTermTranslateVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::Symbol &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::Symbol &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“symbol” terms not allowed, function expected", context);
|
throwErrorAtLocation(term.location, "“symbol” terms not allowed, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Variable &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Variable &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“variable” terms currently unsupported, function expected", context);
|
throwErrorAtLocation(term.location, "“variable” terms currently unsupported, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported, function expected", context);
|
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::BinaryOperation &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported, function expected", context);
|
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Interval &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Interval &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“interval” terms currently unsupported, function expected", context);
|
throwErrorAtLocation(term.location, "“interval” terms currently unsupported, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check correctness
|
// TODO: check correctness
|
||||||
void visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
if (function.external)
|
if (function.external)
|
||||||
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
|
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
|
||||||
|
|
||||||
auto &outputStream = context.logger.outputStream();
|
std::vector<ast::Term> arguments;
|
||||||
|
arguments.reserve(function.arguments.size());
|
||||||
outputStream << output::Function(function.name);
|
|
||||||
|
|
||||||
if (function.arguments.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
outputStream << "(";
|
|
||||||
|
|
||||||
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
||||||
{
|
{
|
||||||
if (i != function.arguments.cbegin())
|
|
||||||
outputStream << ", ";
|
|
||||||
|
|
||||||
const auto &argument = *i;
|
const auto &argument = *i;
|
||||||
|
|
||||||
const auto matchingTerm = std::find(context.headTerms.cbegin(), context.headTerms.cend(), &argument);
|
const auto matchingTerm = std::find(context.headTerms.cbegin(), context.headTerms.cend(), &argument);
|
||||||
|
|
||||||
assert(matchingTerm != context.headTerms.cend());
|
assert(matchingTerm != context.headTerms.cend());
|
||||||
|
|
||||||
const auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(matchingTerm - context.headTerms.cbegin() + 1);
|
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(matchingTerm - context.headTerms.cbegin() + 1);
|
||||||
|
arguments.emplace_back(std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved));
|
||||||
outputStream << output::Variable(variableName.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
outputStream << ")";
|
return std::make_unique<ast::Predicate>(function.name, std::move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(term.location, "“pool” terms currently unsupported, function expected", context);
|
throwErrorAtLocation(term.location, "“pool” terms currently unsupported, function expected", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct LiteralPrintSubstitutedVisitor
|
struct LiteralTranslateVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Boolean &boolean, const Clingo::AST::Literal &, Context &)
|
||||||
{
|
{
|
||||||
context.logger.outputStream() << boolean;
|
return std::make_unique<ast::Boolean>(boolean.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Term &term, const Clingo::AST::Literal &, Context &context)
|
||||||
{
|
{
|
||||||
term.data.accept(TermPrintSubstitutedVisitor(), term, context);
|
return term.data.accept(FunctionTermTranslateVisitor(), term, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Comparison &, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Comparison &, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
|
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::CSPLiteral &, const Clingo::AST::Literal &literal, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
|
throwErrorAtLocation(literal.location, "only disjunctions of literals allowed as head literals", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
struct HeadLiteralPrintSubstitutedVisitor
|
struct HeadLiteralTranslateToConsequentVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Literal &literal, const Clingo::AST::HeadLiteral &, Context &context)
|
||||||
{
|
{
|
||||||
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
|
if (literal.sign == Clingo::AST::Sign::DoubleNegation)
|
||||||
throwErrorAtLocation(literal.location, "double-negated literals currently unsupported", context);
|
throwErrorAtLocation(literal.location, "double-negated head literals currently unsupported", context);
|
||||||
|
|
||||||
context.logger.outputStream() << literal.sign;
|
auto translatedLiteral = literal.data.accept(LiteralTranslateVisitor(), literal, context);
|
||||||
|
|
||||||
literal.data.accept(LiteralPrintSubstitutedVisitor(), literal, context);
|
if (literal.sign == Clingo::AST::Sign::None)
|
||||||
|
return translatedLiteral;
|
||||||
|
|
||||||
|
if (!translatedLiteral)
|
||||||
|
return std::experimental::nullopt;
|
||||||
|
|
||||||
|
return std::make_unique<ast::Not>(std::move(translatedLiteral.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Disjunction &disjunction, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
||||||
{
|
{
|
||||||
for (auto i = disjunction.elements.cbegin(); i != disjunction.elements.cend(); i++)
|
std::vector<ast::Formula> arguments;
|
||||||
{
|
arguments.reserve(disjunction.elements.size());
|
||||||
const auto &conditionalLiteral = *i;
|
|
||||||
|
|
||||||
|
for (const auto &conditionalLiteral : disjunction.elements)
|
||||||
|
{
|
||||||
if (!conditionalLiteral.condition.empty())
|
if (!conditionalLiteral.condition.empty())
|
||||||
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
|
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
|
||||||
|
|
||||||
if (i != disjunction.elements.cbegin())
|
auto argument = visit(conditionalLiteral.literal, headLiteral, context);
|
||||||
context.logger.outputStream() << " " << Clingo::AST::BinaryOperator::Or << " ";
|
|
||||||
|
|
||||||
visit(conditionalLiteral.literal, headLiteral, context);
|
if (!argument)
|
||||||
|
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
|
||||||
|
|
||||||
|
arguments.emplace_back(std::move(argument.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return std::make_unique<ast::Or>(std::move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Aggregate &aggregate, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
||||||
{
|
{
|
||||||
if (aggregate.left_guard || aggregate.right_guard)
|
if (aggregate.left_guard || aggregate.right_guard)
|
||||||
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards not allowed", context);
|
throwErrorAtLocation(headLiteral.location, "aggregates with left or right guards not allowed", context);
|
||||||
|
|
||||||
for (auto i = aggregate.elements.cbegin(); i != aggregate.elements.cend(); i++)
|
const auto translateConditionalLiteral =
|
||||||
|
[&](const auto &conditionalLiteral)
|
||||||
|
{
|
||||||
|
if (!conditionalLiteral.condition.empty())
|
||||||
|
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
|
||||||
|
|
||||||
|
return this->visit(conditionalLiteral.literal, headLiteral, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (aggregate.elements.size() == 1)
|
||||||
|
return translateConditionalLiteral(aggregate.elements[0]);
|
||||||
|
|
||||||
|
std::vector<ast::Formula> arguments;
|
||||||
|
arguments.reserve(aggregate.elements.size());
|
||||||
|
|
||||||
|
for (const auto &conditionalLiteral : aggregate.elements)
|
||||||
{
|
{
|
||||||
const auto &conditionalLiteral = *i;
|
auto argument = translateConditionalLiteral(conditionalLiteral);
|
||||||
|
|
||||||
if (!conditionalLiteral.condition.empty())
|
if (!argument)
|
||||||
throwErrorAtLocation(headLiteral.location, "conditional head literals currently unsupported", context);
|
throwErrorAtLocation(headLiteral.location, "could not parse argument", context);
|
||||||
|
|
||||||
if (i != aggregate.elements.cbegin())
|
arguments.emplace_back(std::move(argument.value()));
|
||||||
context.logger.outputStream() << " " << Clingo::AST::BinaryOperator::Or << " ";
|
|
||||||
|
|
||||||
visit(conditionalLiteral.literal, headLiteral, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return std::make_unique<ast::Or>(std::move(arguments));
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::HeadAggregate &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::HeadAggregate &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(headLiteral.location, "“head aggregate” head literals currently unsupported", context);
|
throwErrorAtLocation(headLiteral.location, "“head aggregate” head literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryAtom &, const Clingo::AST::HeadLiteral &headLiteral, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(headLiteral.location, "“theory” head literals currently unsupported", context);
|
throwErrorAtLocation(headLiteral.location, "“theory” head literals currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#ifndef __ANTHEM__STATEMENT_VISITOR_H
|
#ifndef __ANTHEM__STATEMENT_VISITOR_H
|
||||||
#define __ANTHEM__STATEMENT_VISITOR_H
|
#define __ANTHEM__STATEMENT_VISITOR_H
|
||||||
|
|
||||||
|
#include <anthem/AST.h>
|
||||||
#include <anthem/Body.h>
|
#include <anthem/Body.h>
|
||||||
#include <anthem/Head.h>
|
#include <anthem/Head.h>
|
||||||
|
#include <anthem/Term.h>
|
||||||
#include <anthem/Utils.h>
|
#include <anthem/Utils.h>
|
||||||
#include <anthem/output/ClingoOutput.h>
|
|
||||||
|
|
||||||
namespace anthem
|
namespace anthem
|
||||||
{
|
{
|
||||||
|
@ -17,37 +18,46 @@ namespace anthem
|
||||||
|
|
||||||
struct StatementVisitor
|
struct StatementVisitor
|
||||||
{
|
{
|
||||||
void visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Program &program, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
// TODO: refactor
|
// TODO: refactor
|
||||||
context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str());
|
context.logger.log(output::Priority::Debug, (std::string("[program] ") + program.name).c_str());
|
||||||
|
|
||||||
if (!program.parameters.empty())
|
if (!program.parameters.empty())
|
||||||
throwErrorAtLocation(statement.location, "program parameters currently unsupported", context);
|
throwErrorAtLocation(statement.location, "program parameters currently unsupported", context);
|
||||||
|
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Rule &rule, const Clingo::AST::Statement &, Context &context)
|
||||||
{
|
{
|
||||||
context.reset();
|
context.reset();
|
||||||
|
|
||||||
auto &outputStream = context.logger.outputStream();
|
|
||||||
|
|
||||||
// Concatenate all head terms
|
// Concatenate all head terms
|
||||||
rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context);
|
rule.head.data.accept(HeadLiteralCollectFunctionTermsVisitor(), rule.head, context);
|
||||||
|
|
||||||
|
auto antecedent = std::make_unique<ast::And>();
|
||||||
|
|
||||||
|
// 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 std::experimental::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
// Print auxiliary variables replacing the head atom’s arguments
|
// Print auxiliary variables replacing the head atom’s arguments
|
||||||
for (auto i = context.headTerms.cbegin(); i != context.headTerms.cend(); i++)
|
for (auto i = context.headTerms.cbegin(); i != context.headTerms.cend(); i++)
|
||||||
{
|
{
|
||||||
const auto &headTerm = **i;
|
const auto &headTerm = **i;
|
||||||
|
|
||||||
if (i != context.headTerms.cbegin())
|
auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1);
|
||||||
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
|
auto element = std::make_unique<ast::Variable>(std::move(variableName), ast::Variable::Type::Reserved);
|
||||||
|
auto set = translate(headTerm, context);
|
||||||
|
auto in = std::make_unique<ast::In>(std::move(element), std::move(set));
|
||||||
|
|
||||||
const auto variableName = std::string(AuxiliaryHeadVariablePrefix) + std::to_string(i - context.headTerms.cbegin() + 1);
|
antecedent->arguments.emplace_back(std::move(in));
|
||||||
|
|
||||||
outputStream
|
|
||||||
<< output::Variable(variableName.c_str())
|
|
||||||
<< " " << output::Keyword("in") << " " << headTerm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print translated body literals
|
// Print translated body literals
|
||||||
|
@ -55,97 +65,94 @@ struct StatementVisitor
|
||||||
{
|
{
|
||||||
const auto &bodyLiteral = *i;
|
const auto &bodyLiteral = *i;
|
||||||
|
|
||||||
if (!context.headTerms.empty() || i != rule.body.cbegin())
|
|
||||||
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
|
|
||||||
|
|
||||||
if (bodyLiteral.sign != Clingo::AST::Sign::None)
|
if (bodyLiteral.sign != Clingo::AST::Sign::None)
|
||||||
throwErrorAtLocation(bodyLiteral.location, "only positive literals currently supported", context);
|
throwErrorAtLocation(bodyLiteral.location, "only positive literals currently supported", context);
|
||||||
|
|
||||||
bodyLiteral.data.accept(BodyLiteralPrintVisitor(), bodyLiteral, context);
|
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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle choice rules
|
// Handle choice rules
|
||||||
if (context.isChoiceRule)
|
if (context.isChoiceRule)
|
||||||
{
|
antecedent->arguments.emplace_back(ast::deepCopy(consequent.value()));
|
||||||
const bool isFirstOutput = rule.body.empty() && context.headTerms.empty();
|
|
||||||
|
|
||||||
if (!isFirstOutput)
|
// Use “true” as the consequent in case it is empty
|
||||||
outputStream << " " << Clingo::AST::BinaryOperator::And << " ";
|
if (antecedent->arguments.empty())
|
||||||
|
return std::make_unique<ast::Implies>(std::make_unique<ast::Boolean>(true), std::move(consequent.value()));
|
||||||
|
else if (antecedent->arguments.size() == 1)
|
||||||
|
return std::make_unique<ast::Implies>(std::move(antecedent->arguments[0]), std::move(consequent.value()));
|
||||||
|
|
||||||
if (context.numberOfHeadLiterals > 1 && !isFirstOutput)
|
return std::make_unique<ast::Implies>(std::move(antecedent), std::move(consequent.value()));
|
||||||
outputStream << "(";
|
|
||||||
|
|
||||||
rule.head.data.accept(HeadLiteralPrintSubstitutedVisitor(), rule.head, context);
|
|
||||||
|
|
||||||
if (context.numberOfHeadLiterals > 1 && !isFirstOutput)
|
|
||||||
outputStream << ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print “true” on the left side of the formula in case there is nothing else
|
|
||||||
if (rule.body.empty() && context.headTerms.empty() && !context.isChoiceRule)
|
|
||||||
outputStream << Clingo::AST::Boolean({true});
|
|
||||||
|
|
||||||
outputStream << " " << output::Operator("->") << " ";
|
|
||||||
|
|
||||||
// Print consequent of the implication
|
|
||||||
rule.head.data.accept(HeadLiteralPrintSubstitutedVisitor(), rule.head, context);
|
|
||||||
|
|
||||||
outputStream << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Definition &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Definition &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“definition” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“definition” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::ShowSignature &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ShowSignature &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“show signature” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“show signature” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“show term” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“show term” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Minimize &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Minimize &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“minimize” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“minimize” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Script &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Script &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“script” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“script” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::External &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::External &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“external” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“external” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Edge &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Edge &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“edge” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“edge” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::Heuristic &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::Heuristic &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“heuristic” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“heuristic” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::ProjectAtom &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ProjectAtom &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“project atom” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“project atom” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::ProjectSignature &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::ProjectSignature &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“project signature” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“project signature” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(const Clingo::AST::TheoryDefinition &, const Clingo::AST::Statement &statement, Context &context)
|
std::experimental::optional<ast::Formula> visit(const Clingo::AST::TheoryDefinition &, const Clingo::AST::Statement &statement, Context &context)
|
||||||
{
|
{
|
||||||
throwErrorAtLocation(statement.location, "“theory definition” statements currently unsupported", context);
|
throwErrorAtLocation(statement.location, "“theory definition” statements currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
#ifndef __ANTHEM__TERM_H
|
||||||
|
#define __ANTHEM__TERM_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <anthem/AST.h>
|
||||||
|
#include <anthem/Utils.h>
|
||||||
|
#include <anthem/output/Formatting.h>
|
||||||
|
|
||||||
|
namespace anthem
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Term
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ast::BinaryOperation::Operator translate(Clingo::AST::BinaryOperator binaryOperator, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
switch (binaryOperator)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
default:
|
||||||
|
throwErrorAtLocation(term.location, "“binary operation” terms currently unsupported", context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast::BinaryOperation::Operator::Plus;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ast::Term translate(const Clingo::AST::Term &term, Context &context);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct TermTranslateVisitor
|
||||||
|
{
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::Symbol &symbol, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
switch (symbol.type())
|
||||||
|
{
|
||||||
|
case Clingo::SymbolType::Number:
|
||||||
|
return std::make_unique<ast::Integer>(symbol.number());
|
||||||
|
case Clingo::SymbolType::Infimum:
|
||||||
|
return std::make_unique<ast::SpecialInteger>(ast::SpecialInteger::Type::Infimum);
|
||||||
|
case Clingo::SymbolType::Supremum:
|
||||||
|
return std::make_unique<ast::SpecialInteger>(ast::SpecialInteger::Type::Supremum);
|
||||||
|
case Clingo::SymbolType::String:
|
||||||
|
return std::make_unique<ast::String>(std::string(symbol.string()));
|
||||||
|
default:
|
||||||
|
throwErrorAtLocation(term.location, "only numeric “symbol” terms allowed", context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::experimental::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::Variable &variable, const Clingo::AST::Term &, Context &)
|
||||||
|
{
|
||||||
|
return std::make_unique<ast::Variable>(std::string(variable.name), ast::Variable::Type::UserDefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::UnaryOperation &, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
throwErrorAtLocation(term.location, "“unary operation” terms currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::BinaryOperation &binaryOperation, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
const auto operator_ = translate(binaryOperation.binary_operator, term, context);
|
||||||
|
auto left = translate(binaryOperation.left, context);
|
||||||
|
auto right = translate(binaryOperation.right, context);
|
||||||
|
|
||||||
|
return std::make_unique<ast::BinaryOperation>(operator_, std::move(left), std::move(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::Interval &interval, const Clingo::AST::Term &, Context &context)
|
||||||
|
{
|
||||||
|
auto left = translate(interval.left, context);
|
||||||
|
auto right = translate(interval.right, context);
|
||||||
|
|
||||||
|
return std::make_unique<ast::Interval>(std::move(left), std::move(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::Function &function, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
if (function.external)
|
||||||
|
throwErrorAtLocation(term.location, "external functions currently unsupported", context);
|
||||||
|
|
||||||
|
std::vector<ast::Term> arguments;
|
||||||
|
arguments.reserve(function.arguments.size());
|
||||||
|
|
||||||
|
for (const auto &argument : function.arguments)
|
||||||
|
arguments.emplace_back(translate(argument, context));
|
||||||
|
|
||||||
|
return std::make_unique<ast::Function>(function.name, std::move(arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::experimental::optional<ast::Term> visit(const Clingo::AST::Pool &, const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
throwErrorAtLocation(term.location, "“pool” terms currently unsupported", context);
|
||||||
|
return std::experimental::nullopt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
ast::Term translate(const Clingo::AST::Term &term, Context &context)
|
||||||
|
{
|
||||||
|
auto translatedTerm = term.data.accept(TermTranslateVisitor(), term, context);
|
||||||
|
|
||||||
|
if (!translatedTerm)
|
||||||
|
throwErrorAtLocation(term.location, "could not translate term", context);
|
||||||
|
|
||||||
|
return std::move(translatedTerm.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,345 @@
|
||||||
|
#ifndef __ANTHEM__OUTPUT__AST_H
|
||||||
|
#define __ANTHEM__OUTPUT__AST_H
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <anthem/AST.h>
|
||||||
|
#include <anthem/Utils.h>
|
||||||
|
#include <anthem/output/ColorStream.h>
|
||||||
|
#include <anthem/output/Formatting.h>
|
||||||
|
|
||||||
|
namespace anthem
|
||||||
|
{
|
||||||
|
namespace ast
|
||||||
|
{
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// AST
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Function &function);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const In &in);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Integer &integer);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Interval &interval);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Predicate &predicate);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const SpecialInteger &specialInteger);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const String &string);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Variable &variable);
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const And &and_);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Biconditional &biconditional);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Exists &exists);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const ForAll &forAll);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Implies &implies);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Not ¬_);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Or &or_);
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Formula &formula);
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Term &term);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Primitives
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, BinaryOperation::Operator operator_)
|
||||||
|
{
|
||||||
|
switch (operator_)
|
||||||
|
{
|
||||||
|
case BinaryOperation::Operator::Plus:
|
||||||
|
return (stream << output::Operator("+"));
|
||||||
|
case BinaryOperation::Operator::Minus:
|
||||||
|
return (stream << output::Operator("-"));
|
||||||
|
case BinaryOperation::Operator::Multiplication:
|
||||||
|
return (stream << output::Operator("*"));
|
||||||
|
case BinaryOperation::Operator::Division:
|
||||||
|
return (stream << output::Operator("/"));
|
||||||
|
case BinaryOperation::Operator::Modulo:
|
||||||
|
return (stream << output::Operator("%"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const BinaryOperation &binaryOperation)
|
||||||
|
{
|
||||||
|
return (stream << "(" << binaryOperation.left << " " << binaryOperation.operator_ << " " << binaryOperation.right << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Boolean &boolean)
|
||||||
|
{
|
||||||
|
if (boolean.value)
|
||||||
|
return (stream << output::Boolean("#true"));
|
||||||
|
|
||||||
|
return (stream << output::Boolean("#false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, Comparison::Operator operator_)
|
||||||
|
{
|
||||||
|
switch (operator_)
|
||||||
|
{
|
||||||
|
case Comparison::Operator::GreaterThan:
|
||||||
|
return (stream << output::Operator(">"));
|
||||||
|
case Comparison::Operator::LessThan:
|
||||||
|
return (stream << output::Operator("<"));
|
||||||
|
case Comparison::Operator::LessEqual:
|
||||||
|
return (stream << output::Operator("<="));
|
||||||
|
case Comparison::Operator::GreaterEqual:
|
||||||
|
return (stream << output::Operator(">="));
|
||||||
|
case Comparison::Operator::NotEqual:
|
||||||
|
return (stream << output::Operator("!="));
|
||||||
|
case Comparison::Operator::Equal:
|
||||||
|
return (stream << output::Operator("="));
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Comparison &comparison)
|
||||||
|
{
|
||||||
|
return (stream << comparison.left << " " << comparison.operator_ << " " << comparison.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Constant &constant)
|
||||||
|
{
|
||||||
|
return (stream << constant.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Function &function)
|
||||||
|
{
|
||||||
|
stream << function.name;
|
||||||
|
|
||||||
|
if (function.arguments.empty())
|
||||||
|
return stream;
|
||||||
|
|
||||||
|
stream << "(";
|
||||||
|
|
||||||
|
for (auto i = function.arguments.cbegin(); i != function.arguments.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != function.arguments.cbegin())
|
||||||
|
stream << ", ";
|
||||||
|
|
||||||
|
stream << (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (function.name.empty() && function.arguments.size() == 1)
|
||||||
|
stream << ",";
|
||||||
|
|
||||||
|
return (stream << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const In &in)
|
||||||
|
{
|
||||||
|
return (stream << in.element << " " << output::Keyword("in") << " " << in.set);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Integer &integer)
|
||||||
|
{
|
||||||
|
return (stream << output::Number<int>(integer.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Interval &interval)
|
||||||
|
{
|
||||||
|
return (stream << interval.from << ".." << interval.to);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Predicate &predicate)
|
||||||
|
{
|
||||||
|
stream << predicate.name;
|
||||||
|
|
||||||
|
if (predicate.arguments.empty())
|
||||||
|
return stream;
|
||||||
|
|
||||||
|
stream << "(";
|
||||||
|
|
||||||
|
for (auto i = predicate.arguments.cbegin(); i != predicate.arguments.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != predicate.arguments.cbegin())
|
||||||
|
stream << ", ";
|
||||||
|
|
||||||
|
stream << (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const SpecialInteger &specialInteger)
|
||||||
|
{
|
||||||
|
switch (specialInteger.type)
|
||||||
|
{
|
||||||
|
case SpecialInteger::Type::Infimum:
|
||||||
|
return (stream << output::Number<std::string>("#inf"));
|
||||||
|
case SpecialInteger::Type::Supremum:
|
||||||
|
return (stream << output::Number<std::string>("#sup"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const String &string)
|
||||||
|
{
|
||||||
|
return (stream << output::String(string.text.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Variable &variable)
|
||||||
|
{
|
||||||
|
assert(!variable.name.empty());
|
||||||
|
assert(variable.name[0] >= 65 && variable.name[0] <= 90);
|
||||||
|
|
||||||
|
if (variable.type == ast::Variable::Type::Reserved || !isReservedVariableName(variable.name.c_str()))
|
||||||
|
return (stream << output::Variable(variable.name.c_str()));
|
||||||
|
|
||||||
|
const auto variableName = std::string(UserVariablePrefix) + variable.name;
|
||||||
|
|
||||||
|
return (stream << output::Variable(variableName.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Expressions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const And &and_)
|
||||||
|
{
|
||||||
|
stream << "(";
|
||||||
|
|
||||||
|
for (auto i = and_.arguments.cbegin(); i != and_.arguments.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != and_.arguments.cbegin())
|
||||||
|
stream << " " << output::Keyword("and") << " ";
|
||||||
|
|
||||||
|
stream << (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Biconditional &biconditional)
|
||||||
|
{
|
||||||
|
return (stream << "(" << biconditional.left << " <-> " << biconditional.right << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Exists &exists)
|
||||||
|
{
|
||||||
|
stream << output::Keyword("exists") << " ";
|
||||||
|
|
||||||
|
for (auto i = exists.variables.cbegin(); i != exists.variables.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != exists.variables.cbegin())
|
||||||
|
stream << ", ";
|
||||||
|
|
||||||
|
stream << (**i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream << " " << exists.argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const ForAll &forAll)
|
||||||
|
{
|
||||||
|
stream << output::Keyword("forall") << " ";
|
||||||
|
|
||||||
|
for (auto i = forAll.variables.cbegin(); i != forAll.variables.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != forAll.variables.cbegin())
|
||||||
|
stream << ", ";
|
||||||
|
|
||||||
|
stream << (**i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream << " " << forAll.argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Implies &implies)
|
||||||
|
{
|
||||||
|
return (stream << "(" << implies.antecedent << " -> " << implies.consequent << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Not ¬_)
|
||||||
|
{
|
||||||
|
return (stream << output::Keyword("not ") << not_.argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Or &or_)
|
||||||
|
{
|
||||||
|
stream << "(";
|
||||||
|
|
||||||
|
for (auto i = or_.arguments.cbegin(); i != or_.arguments.cend(); i++)
|
||||||
|
{
|
||||||
|
if (i != or_.arguments.cbegin())
|
||||||
|
stream << " " << output::Keyword("or") << " ";
|
||||||
|
|
||||||
|
stream << (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stream << ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Variants
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Formula &formula)
|
||||||
|
{
|
||||||
|
formula.match([&](const auto &x){stream << *x;});
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
output::ColorStream &operator<<(output::ColorStream &stream, const Term &term)
|
||||||
|
{
|
||||||
|
term.match([&](const auto &x){stream << *x;});
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,36 +0,0 @@
|
||||||
#ifndef __ANTHEM__OUTPUT__CLINGO_OUTPUT_H
|
|
||||||
#define __ANTHEM__OUTPUT__CLINGO_OUTPUT_H
|
|
||||||
|
|
||||||
#include <clingo.hh>
|
|
||||||
|
|
||||||
#include <anthem/output/ColorStream.h>
|
|
||||||
|
|
||||||
namespace anthem
|
|
||||||
{
|
|
||||||
namespace output
|
|
||||||
{
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// ClingoOutput
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::Symbol &symbol);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Sign &sign);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Boolean &boolean);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Variable &variable);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperator &binaryOperator);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::UnaryOperation &unaryOperation);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperation &binaryOperation);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Interval &interval);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Function &function);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Pool &pool);
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Term &term);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -118,7 +118,7 @@ struct Keyword
|
||||||
inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword)
|
inline ColorStream &operator<<(ColorStream &stream, const Keyword &keyword)
|
||||||
{
|
{
|
||||||
return (stream
|
return (stream
|
||||||
<< Format({Color::Blue, FontWeight::Bold})
|
<< Format({Color::Blue, FontWeight::Normal})
|
||||||
<< keyword.name
|
<< keyword.name
|
||||||
<< ResetFormat());
|
<< ResetFormat());
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <anthem/Context.h>
|
#include <anthem/Context.h>
|
||||||
#include <anthem/StatementVisitor.h>
|
#include <anthem/StatementVisitor.h>
|
||||||
|
#include <anthem/output/AST.h>
|
||||||
|
|
||||||
namespace anthem
|
namespace anthem
|
||||||
{
|
{
|
||||||
|
@ -40,7 +41,12 @@ void translate(const char *fileName, std::istream &stream, Context &context)
|
||||||
const auto translateStatement =
|
const auto translateStatement =
|
||||||
[&context](const Clingo::AST::Statement &statement)
|
[&context](const Clingo::AST::Statement &statement)
|
||||||
{
|
{
|
||||||
statement.data.accept(StatementVisitor(), statement, context);
|
const auto formula = statement.data.accept(StatementVisitor(), statement, context);
|
||||||
|
|
||||||
|
if (!formula)
|
||||||
|
return;
|
||||||
|
|
||||||
|
context.logger.outputStream() << formula.value() << std::endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto logger =
|
const auto logger =
|
||||||
|
|
|
@ -1,257 +0,0 @@
|
||||||
#include <anthem/output/ClingoOutput.h>
|
|
||||||
|
|
||||||
#include <anthem/Utils.h>
|
|
||||||
#include <anthem/output/Formatting.h>
|
|
||||||
|
|
||||||
namespace anthem
|
|
||||||
{
|
|
||||||
namespace output
|
|
||||||
{
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// ClingoOutput
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
const auto printCollection = [](auto &stream, const auto &collection,
|
|
||||||
const auto &preToken, const auto &delimiter, const auto &postToken, bool printTokensIfEmpty)
|
|
||||||
{
|
|
||||||
if (collection.empty() && !printTokensIfEmpty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (collection.empty() && printTokensIfEmpty)
|
|
||||||
{
|
|
||||||
stream << preToken << postToken;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << preToken;
|
|
||||||
|
|
||||||
// TODO: use cbegin/cend (requires support by Clingo::SymbolSpan)
|
|
||||||
for (auto i = collection.begin(); i != collection.end(); i++)
|
|
||||||
{
|
|
||||||
if (i != collection.begin())
|
|
||||||
stream << delimiter;
|
|
||||||
|
|
||||||
stream << *i;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream << postToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::Symbol &symbol)
|
|
||||||
{
|
|
||||||
switch (symbol.type())
|
|
||||||
{
|
|
||||||
case Clingo::SymbolType::Infimum:
|
|
||||||
return (stream << Keyword("#inf"));
|
|
||||||
case Clingo::SymbolType::Supremum:
|
|
||||||
return (stream << Keyword("#sup"));
|
|
||||||
case Clingo::SymbolType::Number:
|
|
||||||
return (stream << Number<decltype(symbol.number())>(symbol.number()));
|
|
||||||
case Clingo::SymbolType::String:
|
|
||||||
return (stream << String(symbol.string()));
|
|
||||||
case Clingo::SymbolType::Function:
|
|
||||||
{
|
|
||||||
const auto isNegative = symbol.is_negative();
|
|
||||||
assert(isNegative != symbol.is_positive());
|
|
||||||
|
|
||||||
const auto isUnaryTuple = (symbol.name()[0] == '\0' && symbol.arguments().size() == 1);
|
|
||||||
const auto printIfEmpty = (symbol.name()[0] == '\0' || !symbol.arguments().empty());
|
|
||||||
|
|
||||||
if (isNegative)
|
|
||||||
stream << Operator("-");
|
|
||||||
|
|
||||||
stream << Function(symbol.name());
|
|
||||||
|
|
||||||
const auto postToken = (isUnaryTuple ? ",)" : ")");
|
|
||||||
|
|
||||||
printCollection(stream, symbol.arguments(), "(", ", ", postToken, printIfEmpty);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Sign &sign)
|
|
||||||
{
|
|
||||||
switch (sign)
|
|
||||||
{
|
|
||||||
case Clingo::AST::Sign::None:
|
|
||||||
return stream;
|
|
||||||
case Clingo::AST::Sign::Negation:
|
|
||||||
return (stream << Keyword("not") << " ");
|
|
||||||
case Clingo::AST::Sign::DoubleNegation:
|
|
||||||
return (stream << Keyword("not") << " " << Keyword("not") << " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Boolean &boolean)
|
|
||||||
{
|
|
||||||
if (boolean.value == true)
|
|
||||||
return (stream << Boolean("#true"));
|
|
||||||
|
|
||||||
return (stream << Boolean("#false"));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Variable &variable)
|
|
||||||
{
|
|
||||||
if (!isReservedVariableName(variable.name))
|
|
||||||
return (stream << Variable(variable.name));
|
|
||||||
|
|
||||||
const auto variableName = std::string(UserVariablePrefix) + variable.name;
|
|
||||||
|
|
||||||
return (stream << Variable(variableName.c_str()));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperator &binaryOperator)
|
|
||||||
{
|
|
||||||
switch (binaryOperator)
|
|
||||||
{
|
|
||||||
case Clingo::AST::BinaryOperator::XOr:
|
|
||||||
return (stream << Keyword("xor"));
|
|
||||||
case Clingo::AST::BinaryOperator::Or:
|
|
||||||
return (stream << Keyword("or"));
|
|
||||||
case Clingo::AST::BinaryOperator::And:
|
|
||||||
return (stream << Keyword("and"));
|
|
||||||
case Clingo::AST::BinaryOperator::Plus:
|
|
||||||
return (stream << Operator("+"));
|
|
||||||
case Clingo::AST::BinaryOperator::Minus:
|
|
||||||
return (stream << Operator("-"));
|
|
||||||
case Clingo::AST::BinaryOperator::Multiplication:
|
|
||||||
return (stream << Operator("*"));
|
|
||||||
case Clingo::AST::BinaryOperator::Division:
|
|
||||||
return (stream << Operator("/"));
|
|
||||||
case Clingo::AST::BinaryOperator::Modulo:
|
|
||||||
return (stream << Operator("\\"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::UnaryOperation &unaryOperation)
|
|
||||||
{
|
|
||||||
return (stream
|
|
||||||
<< Keyword(Clingo::AST::left_hand_side(unaryOperation.unary_operator))
|
|
||||||
<< unaryOperation.argument
|
|
||||||
<< Keyword(Clingo::AST::right_hand_side(unaryOperation.unary_operator)));
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::BinaryOperation &binaryOperation)
|
|
||||||
{
|
|
||||||
return (stream << "(" << binaryOperation.left
|
|
||||||
<< " " << binaryOperation.binary_operator
|
|
||||||
<< " " << binaryOperation.right << ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Interval &interval)
|
|
||||||
{
|
|
||||||
return (stream << "(" << interval.left << Operator("..") << interval.right << ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Function &function)
|
|
||||||
{
|
|
||||||
const auto isUnaryTuple = (function.name[0] == '\0' && function.arguments.size() == 1);
|
|
||||||
const auto printIfEmpty = (function.name[0] == '\0' || !function.arguments.empty());
|
|
||||||
|
|
||||||
if (function.external)
|
|
||||||
stream << Operator("@");
|
|
||||||
|
|
||||||
stream << output::Function(function.name);
|
|
||||||
|
|
||||||
const auto postToken = (isUnaryTuple ? ",)" : ")");
|
|
||||||
|
|
||||||
printCollection(stream, function.arguments, "(", ", ", postToken, printIfEmpty);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Pool &pool)
|
|
||||||
{
|
|
||||||
// Note: There is no representation for an empty pool
|
|
||||||
if (pool.arguments.empty())
|
|
||||||
return (stream << "(" << Number<int>(1) << "/" << Number<int>(0) << ")");
|
|
||||||
|
|
||||||
printCollection(stream, pool.arguments, "(", ";", ")", true);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
struct TermOutputVisitor
|
|
||||||
{
|
|
||||||
void visit(const Clingo::Symbol &symbol, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::Variable &variable, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << variable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::UnaryOperation &unaryOperation, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << unaryOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::BinaryOperation &binaryOperation, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << binaryOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::Interval &interval, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::Function &function, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << function;
|
|
||||||
}
|
|
||||||
|
|
||||||
void visit(const Clingo::AST::Pool &pool, ColorStream &stream)
|
|
||||||
{
|
|
||||||
stream << pool;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
ColorStream &operator<<(ColorStream &stream, const Clingo::AST::Term &term)
|
|
||||||
{
|
|
||||||
term.data.accept(TermOutputVisitor(), stream);
|
|
||||||
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(1..5).";
|
input << "p(1..5).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in (1..5) -> p(V1)\n");
|
REQUIRE(output.str() == "(V1 in 1..5 -> p(V1))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("simple example 2")
|
SECTION("simple example 2")
|
||||||
|
@ -29,7 +29,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(N) :- N = 1..5.";
|
input << "p(N) :- N = 1..5.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in N and exists X1, X2 (X1 in N and X2 in (1..5) and X1 = X2) -> p(V1)\n");
|
REQUIRE(output.str() == "((V1 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> p(V1))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("simple example 3")
|
SECTION("simple example 3")
|
||||||
|
@ -37,7 +37,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(N + 1) :- q(N).";
|
input << "p(N + 1) :- q(N).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in (N + 1) and exists X1 (X1 in N and q(X1)) -> p(V1)\n");
|
REQUIRE(output.str() == "((V1 in (N + 1) and exists X1 (X1 in N and q(X1))) -> p(V1))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("n-ary head")
|
SECTION("n-ary head")
|
||||||
|
@ -45,7 +45,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(N, 1, 2) :- N = 1..5.";
|
input << "p(N, 1, 2) :- N = 1..5.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in N and V2 in 1 and V3 in 2 and exists X1, X2 (X1 in N and X2 in (1..5) and X1 = X2) -> p(V1, V2, V3)\n");
|
REQUIRE(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> p(V1, V2, V3))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("disjunctive head")
|
SECTION("disjunctive head")
|
||||||
|
@ -54,7 +54,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "q(3, N); p(N, 1, 2) :- N = 1..5.";
|
input << "q(3, N); p(N, 1, 2) :- N = 1..5.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in (1..5) and X1 = X2) -> p(V1, V2, V3) or q(V4, V5)\n");
|
REQUIRE(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("disjunctive head (alternative syntax)")
|
SECTION("disjunctive head (alternative syntax)")
|
||||||
|
@ -63,7 +63,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "q(3, N), p(N, 1, 2) :- N = 1..5.";
|
input << "q(3, N), p(N, 1, 2) :- N = 1..5.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in (1..5) and X1 = X2) -> p(V1, V2, V3) or q(V4, V5)\n");
|
REQUIRE(output.str() == "((V1 in N and V2 in 1 and V3 in 2 and V4 in 3 and V5 in N and exists X1, X2 (X1 in N and X2 in 1..5 and X1 = X2)) -> (p(V1, V2, V3) or q(V4, V5)))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("escaping conflicting variable names")
|
SECTION("escaping conflicting variable names")
|
||||||
|
@ -71,7 +71,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X1, V1) :- q(X1), q(V1).";
|
input << "p(X1, V1) :- q(X1), q(V1).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in _X1 and V2 in _V1 and exists X1 (X1 in _X1 and q(X1)) and exists X2 (X2 in _V1 and q(X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in _X1 and V2 in _V1 and exists X1 (X1 in _X1 and q(X1)) and exists X2 (X2 in _V1 and q(X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("fact")
|
SECTION("fact")
|
||||||
|
@ -79,7 +79,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(42).";
|
input << "p(42).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in 42 -> p(V1)\n");
|
REQUIRE(output.str() == "(V1 in 42 -> p(V1))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("0-ary fact")
|
SECTION("0-ary fact")
|
||||||
|
@ -87,7 +87,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p.";
|
input << "p.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "#true -> p\n");
|
REQUIRE(output.str() == "(#true -> p)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("disjunctive fact (no arguments)")
|
SECTION("disjunctive fact (no arguments)")
|
||||||
|
@ -95,7 +95,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "q; p.";
|
input << "q; p.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "#true -> p or q\n");
|
REQUIRE(output.str() == "(#true -> (p or q))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("disjunctive fact (arguments)")
|
SECTION("disjunctive fact (arguments)")
|
||||||
|
@ -103,7 +103,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "q; p(42).";
|
input << "q; p(42).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in 42 -> p(V1) or q\n");
|
REQUIRE(output.str() == "(V1 in 42 -> (p(V1) or q))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("integrity constraint (no arguments)")
|
SECTION("integrity constraint (no arguments)")
|
||||||
|
@ -111,7 +111,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << ":- p, q.";
|
input << ":- p, q.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "p and q -> #false\n");
|
REQUIRE(output.str() == "((p and q) -> #false)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("contradiction")
|
SECTION("contradiction")
|
||||||
|
@ -119,7 +119,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << ":-.";
|
input << ":-.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "#true -> #false\n");
|
REQUIRE(output.str() == "(#true -> #false)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("integrity constraint (arguments)")
|
SECTION("integrity constraint (arguments)")
|
||||||
|
@ -127,7 +127,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << ":- p(42), q.";
|
input << ":- p(42), q.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "exists X1 (X1 in 42 and p(X1)) and q -> #false\n");
|
REQUIRE(output.str() == "((exists X1 (X1 in 42 and p(X1)) and q) -> #false)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("inf/sup")
|
SECTION("inf/sup")
|
||||||
|
@ -135,7 +135,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X, #inf) :- q(X, #sup).";
|
input << "p(X, #inf) :- q(X, #sup).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in #inf and exists X1, X2 (X1 in X and X2 in #sup and q(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in #inf and exists X1, X2 (X1 in X and X2 in #sup and q(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("strings")
|
SECTION("strings")
|
||||||
|
@ -143,7 +143,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X, \"foo\") :- q(X, \"bar\").";
|
input << "p(X, \"foo\") :- q(X, \"bar\").";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in \"foo\" and exists X1, X2 (X1 in X and X2 in \"bar\" and q(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in \"foo\" and exists X1, X2 (X1 in X and X2 in \"bar\" and q(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("tuples")
|
SECTION("tuples")
|
||||||
|
@ -151,7 +151,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X, (1, 2, 3)) :- q(X, (4, 5)).";
|
input << "p(X, (1, 2, 3)) :- q(X, (4, 5)).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in (1, 2, 3) and exists X1, X2 (X1 in X and X2 in (4, 5) and q(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in (1, 2, 3) and exists X1, X2 (X1 in X and X2 in (4, 5) and q(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("1-ary tuples")
|
SECTION("1-ary tuples")
|
||||||
|
@ -159,7 +159,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X, (1,)) :- q(X, (2,)).";
|
input << "p(X, (1,)) :- q(X, (2,)).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in (1,) and exists X1, X2 (X1 in X and X2 in (2,) and q(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in (1,) and exists X1, X2 (X1 in X and X2 in (2,) and q(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("intervals")
|
SECTION("intervals")
|
||||||
|
@ -167,7 +167,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(X, 1..10) :- q(X, 6..12).";
|
input << "p(X, 1..10) :- q(X, 6..12).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in (1..10) and exists X1, X2 (X1 in X and X2 in (6..12) and q(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in 1..10 and exists X1, X2 (X1 in X and X2 in 6..12 and q(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("comparisons")
|
SECTION("comparisons")
|
||||||
|
@ -175,7 +175,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(M, N, O, P) :- M < N, P != O.";
|
input << "p(M, N, O, P) :- M < N, P != O.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in M and V2 in N and V3 in O and V4 in P and exists X1, X2 (X1 in M and X2 in N and X1 < X2) and exists X3, X4 (X3 in P and X4 in O and X3 != X4) -> p(V1, V2, V3, V4)\n");
|
REQUIRE(output.str() == "((V1 in M and V2 in N and V3 in O and V4 in P and exists X1, X2 (X1 in M and X2 in N and X1 < X2) and exists X3, X4 (X3 in P and X4 in O and X3 != X4)) -> p(V1, V2, V3, V4))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("single negation")
|
SECTION("single negation")
|
||||||
|
@ -183,7 +183,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "not p(X, 1) :- not q(X, 2).";
|
input << "not p(X, 1) :- not q(X, 2).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) -> not p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2))) -> not p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("variable numbering")
|
SECTION("variable numbering")
|
||||||
|
@ -192,9 +192,9 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "f; q(A1, A2); p(A3, r(A4)); g(g(A5)) :- g(A3), f, q(A4, A1), p(A2, A5).";
|
input << "f; q(A1, A2); p(A3, r(A4)); g(g(A5)) :- g(A3), f, q(A4, A1), p(A2, A5).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in A1 and V2 in A2 and V3 in A3 and V4 in r(A4) and V5 in g(A5)"
|
REQUIRE(output.str() == "((V1 in A1 and V2 in A2 and V3 in A3 and V4 in r(A4) and V5 in g(A5)"
|
||||||
" and exists X1 (X1 in A3 and g(X1)) and f and exists X2, X3 (X2 in A4 and X3 in A1 and q(X2, X3)) and exists X4, X5 (X4 in A2 and X5 in A5 and p(X4, X5))"
|
" and exists X1 (X1 in A3 and g(X1)) and f and exists X2, X3 (X2 in A4 and X3 in A1 and q(X2, X3)) and exists X4, X5 (X4 in A2 and X5 in A5 and p(X4, X5)))"
|
||||||
" -> q(V1, V2) or p(V3, V4) or g(V5) or f\n");
|
" -> (q(V1, V2) or p(V3, V4) or g(V5) or f))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("nested functions")
|
SECTION("nested functions")
|
||||||
|
@ -202,7 +202,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "p(q(s(t(X1))), u(X2)) :- u(v(w(X2)), z(X1)).";
|
input << "p(q(s(t(X1))), u(X2)) :- u(v(w(X2)), z(X1)).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in q(s(t(_X1))) and V2 in u(_X2) and exists X1, X2 (X1 in v(w(_X2)) and X2 in z(_X1) and u(X1, X2)) -> p(V1, V2)\n");
|
REQUIRE(output.str() == "((V1 in q(s(t(_X1))) and V2 in u(_X2) and exists X1, X2 (X1 in v(w(_X2)) and X2 in z(_X1) and u(X1, X2))) -> p(V1, V2))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("choice rule (simple)")
|
SECTION("choice rule (simple)")
|
||||||
|
@ -210,7 +210,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "{p}.";
|
input << "{p}.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "p -> p\n");
|
REQUIRE(output.str() == "(p -> p)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("choice rule (two elements)")
|
SECTION("choice rule (two elements)")
|
||||||
|
@ -218,7 +218,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "{p; q}.";
|
input << "{p; q}.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "p or q -> p or q\n");
|
REQUIRE(output.str() == "((p or q) -> (p or q))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("choice rule (n-ary elements)")
|
SECTION("choice rule (n-ary elements)")
|
||||||
|
@ -226,7 +226,7 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "{p(1..3, N); q(2..4)}.";
|
input << "{p(1..3, N); q(2..4)}.";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in (1..3) and V2 in N and V3 in (2..4) and (p(V1, V2) or q(V3)) -> p(V1, V2) or q(V3)\n");
|
REQUIRE(output.str() == "((V1 in 1..3 and V2 in N and V3 in 2..4 and (p(V1, V2) or q(V3))) -> (p(V1, V2) or q(V3)))\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("choice rule with body")
|
SECTION("choice rule with body")
|
||||||
|
@ -234,6 +234,22 @@ TEST_CASE("[translation] Rules are translated correctly", "[translation]")
|
||||||
input << "{p(M, N); q(P)} :- s(M, N, P).";
|
input << "{p(M, N); q(P)} :- s(M, N, P).";
|
||||||
anthem::translate("input", input, context);
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
REQUIRE(output.str() == "V1 in M and V2 in N and V3 in P and exists X1, X2, X3 (X1 in M and X2 in N and X3 in P and s(X1, X2, X3)) and (p(V1, V2) or q(V3)) -> p(V1, V2) or q(V3)\n");
|
REQUIRE(output.str() == "((V1 in M and V2 in N and V3 in P and exists X1, X2, X3 (X1 in M and X2 in N and X3 in P and s(X1, X2, X3)) and (p(V1, V2) or q(V3))) -> (p(V1, V2) or q(V3)))\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("choice rule with negation")
|
||||||
|
{
|
||||||
|
input << "{not p(X, 1)} :- not q(X, 2).";
|
||||||
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
|
REQUIRE(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) and not p(V1, V2)) -> not p(V1, V2))\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("choice rule with negation (two elements)")
|
||||||
|
{
|
||||||
|
input << "{not p(X, 1); not s} :- not q(X, 2).";
|
||||||
|
anthem::translate("input", input, context);
|
||||||
|
|
||||||
|
REQUIRE(output.str() == "((V1 in X and V2 in 1 and exists X1, X2 (X1 in X and X2 in 2 and not q(X1, X2)) and (not p(V1, V2) or not s)) -> (not p(V1, V2) or not s))\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue