From 811523e580cf867f38b832f2da7977b61c598616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20L=C3=BChne?= Date: Sun, 29 Apr 2018 20:37:40 +0200 Subject: [PATCH] Provide term type deduction function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements a function for retrieving the return type of terms, that is, both the domain to which the expression evaluates to as well as whether it’s an empty, unit, or general set with multiple values. --- include/anthem/Type.h | 166 +++++++++++++++++++++++++++++++++++++++++ include/anthem/Utils.h | 18 +++++ 2 files changed, 184 insertions(+) create mode 100644 include/anthem/Type.h diff --git a/include/anthem/Type.h b/include/anthem/Type.h new file mode 100644 index 0000000..61442ea --- /dev/null +++ b/include/anthem/Type.h @@ -0,0 +1,166 @@ +#ifndef __ANTHEM__TYPE_H +#define __ANTHEM__TYPE_H + +#include +#include + +namespace anthem +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Type +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct DefaultVariableDomainAccessor +{ + Domain operator()(const ast::Variable &variable) + { + return variable.declaration->domain; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Type type(const ast::Term &term, Arguments &&... arguments); + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +struct TermTypeVisitor +{ + template + static Type visit(const ast::BinaryOperation &binaryOperation, Arguments &&... arguments) + { + const auto leftType = type(binaryOperation.left, std::forward(arguments)...); + const auto rightType = type(binaryOperation.right, std::forward(arguments)...); + + // Binary operations on empty sets return an empty set (also with division) + if (leftType.setSize == SetSize::Empty || rightType.setSize == SetSize::Empty) + return {Domain::Unknown, SetSize::Empty}; + + // Binary operations on nonintegers return an empty set (also with division) + if (leftType.domain == Domain::Noninteger || rightType.domain == Domain::Noninteger) + return {Domain::Unknown, SetSize::Empty}; + + // Binary operations on unknown types return an unknown set + if (leftType.domain == Domain::Unknown || rightType.domain == Domain::Unknown) + return {Domain::Unknown, SetSize::Unknown}; + + // Divisions return an unknown set + if (binaryOperation.operator_ == ast::BinaryOperation::Operator::Division) + return {Domain::Integer, SetSize::Unknown}; + + // Binary operations on integer sets of unknown size return an integer set of unknown size + if (leftType.setSize == SetSize::Unknown || rightType.setSize == SetSize::Unknown) + return {Domain::Integer, SetSize::Unknown}; + + // Binary operations on integer sets with multiple elements return an integer set with multiple elements + if (leftType.setSize == SetSize::Multi || rightType.setSize == SetSize::Multi) + return {Domain::Integer, SetSize::Multi}; + + // Binary operations on plain integers return a plain integer + return {Domain::Integer, SetSize::Unit}; + } + + template + static Type visit(const ast::Boolean &, Arguments &&...) + { + return {Domain::Noninteger, SetSize::Unit}; + } + + template + static Type visit(const ast::Function &function, Arguments &&...) + { + // TODO: check that functions cannot return sets + + return {function.declaration->domain, SetSize::Unit}; + } + + template + static Type visit(const ast::Integer &, Arguments &&...) + { + return {Domain::Integer, SetSize::Unit}; + } + + template + static Type visit(const ast::Interval &interval, Arguments &&... arguments) + { + const auto fromType = type(interval.from, std::forward(arguments)...); + const auto toType = type(interval.to, std::forward(arguments)...); + + // Intervals with empty sets return an empty set + if (fromType.setSize == SetSize::Empty || toType.setSize == SetSize::Empty) + return {Domain::Unknown, SetSize::Empty}; + + // Intervals with nonintegers return an empty set + if (fromType.domain == Domain::Noninteger || toType.domain == Domain::Noninteger) + return {Domain::Unknown, SetSize::Empty}; + + // Intervals with unknown types return an unknown set + if (fromType.domain == Domain::Unknown || toType.domain == Domain::Unknown) + return {Domain::Unknown, SetSize::Unknown}; + + // Intervals with integers generally return integer sets + // TODO: handle 1-element intervals such as 1..1 and empty intervals such as 2..1 + return {Domain::Integer, SetSize::Unknown}; + } + + template + static Type visit(const ast::SpecialInteger &, Arguments &&...) + { + return {Domain::Noninteger, SetSize::Unit}; + } + + template + static Type visit(const ast::String &, Arguments &&...) + { + return {Domain::Noninteger, SetSize::Unit}; + } + + template + static Type visit(const ast::UnaryOperation &unaryOperation, Arguments &&... arguments) + { + assert(unaryOperation.operator_ == ast::UnaryOperation::Operator::Absolute); + + const auto argumentType = type(unaryOperation.argument, std::forward(arguments)...); + + // Absolute value of an empty set returns an empty set + if (argumentType.setSize == SetSize::Empty) + return {Domain::Unknown, SetSize::Empty}; + + // Absolute value of nonintegers returns an empty set + if (argumentType.domain == Domain::Noninteger) + return {Domain::Unknown, SetSize::Empty}; + + // Absolute value of integers returns the same type + if (argumentType.domain == Domain::Integer) + return argumentType; + + return {Domain::Unknown, SetSize::Unknown}; + } + + template + static Type visit(const ast::Variable &variable, Arguments &&... arguments) + { + const auto domain = VariableDomainAccessor()(variable, std::forward(arguments)...); + + return {domain, SetSize::Unit}; + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +template +Type type(const ast::Term &term, Arguments &&... arguments) +{ + return term.accept(TermTypeVisitor(), std::forward(arguments)...); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} + +#endif diff --git a/include/anthem/Utils.h b/include/anthem/Utils.h index 58c9dcf..bad2c1a 100644 --- a/include/anthem/Utils.h +++ b/include/anthem/Utils.h @@ -42,6 +42,24 @@ enum class Domain //////////////////////////////////////////////////////////////////////////////////////////////////// +enum class SetSize +{ + Empty, + Unit, + Multi, + Unknown, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct Type +{ + Domain domain{Domain::Unknown}; + SetSize setSize{SetSize::Unknown}; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + } #endif