[flang] Remove GenericExpr, move operator overloads to tools.h

Original-commit: flang-compiler/f18@23e7a6c27c
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-08-20 09:29:08 -07:00
parent c0d3a67fac
commit b114c58118
8 changed files with 100 additions and 120 deletions

View File

@ -15,6 +15,7 @@
#include "expression.h"
#include "common.h"
#include "int-power.h"
#include "tools.h"
#include "variable.h"
#include "../common/idioms.h"
#include "../parser/characters.h"

View File

@ -42,6 +42,8 @@ using common::RelationalOperator;
// wrap discriminated unions.
template<typename A> class Expr;
template<typename A> using ResultType = typename std::decay_t<A>::Result;
template<typename DERIVED, typename RESULT, typename... OPERAND>
class Operation {
public:
@ -597,92 +599,6 @@ public:
u;
};
using GenericExpr = Expr<SomeType>; // TODO: delete name?
template<typename A> using ResultType = typename std::decay_t<A>::Result;
// Convenience functions and operator overloadings for expression construction.
template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
return {Negate<Type<C, K>>{x}};
}
template<TypeCategory C>
Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
return std::visit(
[](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u);
}
#define BINARY(op, CONSTR) \
template<TypeCategory C, int K> \
Expr<Type<C, K>> operator op( \
const Expr<Type<C, K>> &x, const Expr<Type<C, K>> &y) { \
return {CONSTR<Type<C, K>>{x, y}}; \
} \
template<TypeCategory C> \
Expr<SomeKind<C>> operator op( \
const Expr<SomeKind<C>> &x, const Expr<SomeKind<C>> &y) { \
return std::visit( \
[](const auto &xk, const auto &yk) -> Expr<SomeKind<C>> { \
return {xk op yk}; \
}, \
x.u, y.u); \
}
BINARY(+, Add)
BINARY(-, Subtract)
BINARY(*, Multiply)
BINARY(/, Divide)
#undef BINARY
#if 0
#define OLDBINARY(FUNC, CONSTR) \
template<typename A> A FUNC(const A &x, const A &y) { \
return {CONSTR<typename A::Result>{x, y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(const A &x, A &&y) { \
return {CONSTR<typename A::Result>{A{x}, std::move(y)}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, const A &y) { \
return {CONSTR<typename A::Result>{std::move(x), A{y}}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, A &&y) { \
return {CONSTR<typename A::Result>{std::move(x), std::move(y)}}; \
}
#undef OLDBINARY
#endif
#define BINARY(FUNC, OP) \
template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
return {Relational<ResultType<A>>{OP, x, y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
const A &x, A &&y) { \
return {Relational<ResultType<A>>{OP, x, std::move(y)}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, const A &y) { \
return {Relational<ResultType<A>>{OP, std::move(x), y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, A &&y) { \
return {Relational<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
}
BINARY(operator<, RelationalOperator::LT)
BINARY(operator<=, RelationalOperator::LE)
BINARY(operator==, RelationalOperator::EQ)
BINARY(operator!=, RelationalOperator::NE)
BINARY(operator>=, RelationalOperator::GE)
BINARY(operator>, RelationalOperator::GT)
#undef BINARY
extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO others
extern template struct Relational<Type<TypeCategory::Integer, 1>>;
extern template struct Relational<Type<TypeCategory::Integer, 2>>;

View File

@ -20,20 +20,9 @@ using namespace Fortran::parser::literals;
namespace Fortran::evaluate {
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeInteger> &from) {
return std::visit(
[&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
}
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeReal> &from) {
return std::visit(
[&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
}
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) {
parser::ContextualMessages &messages, Expr<SomeType> &&x,
Expr<SomeType> &&y) {
return std::visit(
common::visitors{[&](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) {
// Can happen in a CMPLX() constructor. Per F'2018,
@ -43,11 +32,11 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
Expr<SomeReal>{Expr<DefaultReal>{std::move(iy)}})};
},
[&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) {
auto rx{ConvertToTypeOf(ry, std::move(ix))};
auto rx{ConvertToTypeAndKindOf(ry, std::move(ix))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) {
auto ry{ConvertToTypeOf(rx, std::move(iy))};
auto ry{ConvertToTypeAndKindOf(rx, std::move(iy))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) {
@ -63,8 +52,8 @@ std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
}
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
parser::ContextualMessages &messages, std::optional<GenericExpr> &&x,
std::optional<GenericExpr> &&y) {
parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&x,
std::optional<Expr<SomeType>> &&y) {
if (x.has_value() && y.has_value()) {
return ConvertRealOperands(messages, std::move(*x), std::move(*y));
}

View File

@ -23,18 +23,92 @@
namespace Fortran::evaluate {
// Convert the second argument to the same type and kind of the first.
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeInteger> &from);
Expr<SomeReal> ConvertToTypeOf(
const Expr<SomeReal> &to, const Expr<SomeReal> &from);
// Convenience functions and operator overloadings for expression construction.
template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
return {Negate<Type<C, K>>{std::move(x)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Add<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Subtract<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator*(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Multiply<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C, int K>
Expr<Type<C, K>> operator/(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
return {Divide<Type<C, K>>{std::move(x), std::move(y)}};
}
template<TypeCategory C> Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x) {
return std::visit(
[](auto &xk) { return Expr<SomeKind<C>>{-std::move(xk)}; }, x.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator+(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) + std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) - std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator*(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) * std::move(yk)};
},
x.u, y.u);
}
template<TypeCategory C>
Expr<SomeKind<C>> operator/(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
return std::visit(
[](auto &xk, auto &yk) {
return Expr<SomeKind<C>>{std::move(xk) / std::move(yk)};
},
x.u, y.u);
}
// Convert the second argument expression to an expression of the same type
// and kind as that of the first.
template<TypeCategory TC, typename F>
Expr<SomeKind<TC>> ConvertToTypeAndKindOf(
const Expr<SomeKind<TC>> &to, Expr<F> &&from) {
return std::visit(
[&](const auto &tk) -> Expr<SomeKind<TC>> {
using SpecificExpr = std::decay_t<decltype(tk)>;
return {SpecificExpr{std::move(from)}};
},
to.u);
}
// Ensure that both operands of an intrinsic REAL operation or CMPLX()
// are INTEGER or REAL, and convert them as necessary to the same REAL type.
using ConvertRealOperandsResult =
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>;
ConvertRealOperandsResult ConvertRealOperands(
parser::ContextualMessages &, GenericExpr &&, GenericExpr &&);
parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
template<TypeCategory CAT>
void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include "variable.h"
#include "tools.h"
#include "../common/idioms.h"
#include "../parser/char-block.h"
#include "../parser/characters.h"

View File

@ -25,7 +25,7 @@ namespace Fortran::semantics {
using common::TypeCategory;
using evaluate::Expr;
using evaluate::GenericExpr;
using evaluate::SomeType;
using evaluate::Type;
using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>;
@ -117,8 +117,8 @@ static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
}
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
std::function<GenericExpr(A &&)> f{
[](A &&y) { return GenericExpr{std::move(y)}; }};
std::function<Expr<SomeType>(A &&)> f{
[](A &&y) { return Expr<SomeType>{std::move(y)}; }};
return common::MapOptional(f, std::move(x));
}
@ -153,7 +153,7 @@ MaybeExpr AnalyzeHelper(
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
chExpr.Fold(ea.context());
return {GenericExpr{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
return {Expr<SomeType>{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
}
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
@ -269,7 +269,7 @@ static std::optional<Expr<evaluate::SomeReal>> AnalyzeLiteral(
AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
if (sign == parser::Sign::Negative) {
return {-*result};
return {-std::move(*result)};
}
}
return result;
@ -577,12 +577,12 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
MaybeExpr &&real, MaybeExpr &&imaginary) {
// TODO: pmk abstract further, this will be a common pattern
auto partial{[&](GenericExpr &&x, GenericExpr &&y) {
auto partial{[&](Expr<SomeType> &&x, Expr<SomeType> &&y) {
return evaluate::ConvertRealOperands(
context_.messages, std::move(x), std::move(y));
}};
using fType =
evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&);
evaluate::ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
std::function<fType> f{partial};
auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
if (auto joined{common::JoinOptionals(std::move(converted))}) {

View File

@ -23,7 +23,7 @@
namespace Fortran::semantics {
using MaybeExpr = std::optional<evaluate::GenericExpr>;
using MaybeExpr = std::optional<evaluate::Expr<evaluate::SomeType>>;
class ExpressionAnalyzer {
public:

View File

@ -13,6 +13,7 @@
// limitations under the License.
#include "../../lib/evaluate/expression.h"
#include "../../lib/evaluate/tools.h"
#include "testing.h"
#include "../../lib/parser/message.h"
#include <cstdio>
@ -41,11 +42,9 @@ int main() {
FoldingContext context{messages};
ex1.Fold(context);
MATCH("-10_4", Dump(ex1));
MATCH("(6_4.LE.7_4)",
Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
MATCH("(1_4/2_4)", Dump(DefaultIntegerExpr{1} / DefaultIntegerExpr{2}));
DefaultIntegerExpr a{1};
DefaultIntegerExpr b{2};
MATCH("(1_4/2_4)", Dump(a / b));
MATCH("1_4", Dump(a));
a = b;
MATCH("2_4", Dump(a));