[flang] cleanup
Original-commit: flang-compiler/f18@99c4bcb60c Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
3c850d05ca
commit
70febd9285
|
@ -104,7 +104,7 @@ template<typename... LAMBDAS> visitors(LAMBDAS... x)->visitors<LAMBDAS...>;
|
|||
return false; \
|
||||
} \
|
||||
} \
|
||||
template<typename A> constexpr bool T { class_trait_ns_##T::trait_value<A>() };
|
||||
template<typename A> constexpr bool T{class_trait_ns_##T::trait_value<A>()};
|
||||
|
||||
// Define enum class NAME with the given enumerators, a static
|
||||
// function EnumToString() that maps enumerators to std::string,
|
||||
|
@ -129,56 +129,5 @@ template<typename A> struct ListItemCount {
|
|||
static_cast<int>(e), #__VA_ARGS__); \
|
||||
}
|
||||
|
||||
template<typename A> std::optional<A> GetIfNonNull(const A *p) {
|
||||
if (p) {
|
||||
return {*p};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// If a variant holds a value of a particular type, return a copy in a
|
||||
// std::optional<>.
|
||||
template<typename A, typename VARIANT>
|
||||
std::optional<A> GetIf(const VARIANT &u) {
|
||||
return GetIfNonNull(std::get_if<A>(&u));
|
||||
}
|
||||
|
||||
// Collapses a nested std::optional<std::optional<A>> to std::optional<A>
|
||||
template<typename A>
|
||||
std::optional<A> JoinOptionals(std::optional<std::optional<A>> &&x) {
|
||||
if (x.has_value()) {
|
||||
return std::move(*x);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Apply a function to optional argument(s), if are all present.
|
||||
// N.B. This function uses a "functor" in the C++ sense -- a type with
|
||||
// a member function operator() -- to implement a "functor" in the category
|
||||
// theoretical sense.
|
||||
template<typename A, typename B>
|
||||
std::optional<A> MapOptional(std::function<A(B &&)> &f, std::optional<B> &&x) {
|
||||
if (x.has_value()) {
|
||||
return {f(std::move(*x))};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<typename A, typename B, typename C>
|
||||
std::optional<A> MapOptional(std::function<A(B &&, C &&)> &f,
|
||||
std::optional<B> &&x, std::optional<C> &&y) {
|
||||
if (x.has_value() && y.has_value()) {
|
||||
return {f(std::move(*x), std::move(*y))};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Move a value from one variant type to another. The types allowed in the
|
||||
// source variant must all be allowed in the destination variant type.
|
||||
template<typename TOV, typename FROMV> TOV MoveVariant(FROMV &&u) {
|
||||
return std::visit(
|
||||
[](auto &&x) -> TOV { return {std::move(x)}; }, std::move(u));
|
||||
}
|
||||
|
||||
} // namespace Fortran::common
|
||||
#endif // FORTRAN_COMMON_IDIOMS_H_
|
||||
|
|
|
@ -16,14 +16,48 @@
|
|||
#define FORTRAN_COMMON_TEMPLATE_H_
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
// Template metaprogramming utilities
|
||||
// Utility templates for metaprogramming and for composing the
|
||||
// std::optional<>, std::tuple<>, and std::variant<> containers.
|
||||
|
||||
namespace Fortran::common {
|
||||
|
||||
// const A * -> std::optional<A>
|
||||
template<typename A> std::optional<A> GetIfNonNull(const A *p) {
|
||||
if (p) {
|
||||
return {*p};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// const std::variant<..., A, ...> -> std::optional<A>
|
||||
// i.e., when a variant holds a value of a particular type, return a copy
|
||||
// of that value in a std::optional<>.
|
||||
template<typename A, typename VARIANT>
|
||||
std::optional<A> GetIf(const VARIANT &u) {
|
||||
return GetIfNonNull(std::get_if<A>(&u));
|
||||
}
|
||||
|
||||
// std::optional<std::optional<A>> -> std::optional<A>
|
||||
template<typename A>
|
||||
std::optional<A> JoinOptional(std::optional<std::optional<A>> &&x) {
|
||||
if (x.has_value()) {
|
||||
return std::move(*x);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Move a value from one variant type to another. The types allowed in the
|
||||
// source variant must all be allowed in the destination variant type.
|
||||
template<typename TOV, typename FROMV> TOV MoveVariant(FROMV &&u) {
|
||||
return std::visit(
|
||||
[](auto &&x) -> TOV { return {std::move(x)}; }, std::move(u));
|
||||
}
|
||||
|
||||
// SearchTypeList<PREDICATE, TYPES...> scans a list of types. The zero-based
|
||||
// index of the first type T in the list for which PREDICATE<T>::value() is
|
||||
// true is returned, or -1 if the predicate is false for every type in the list.
|
||||
|
@ -57,16 +91,9 @@ template<typename A> struct MatchType {
|
|||
template<typename A, typename... TYPES>
|
||||
constexpr int TypeIndex{SearchTypeList<MatchType<A>::template Match, TYPES...>};
|
||||
|
||||
// SearchVariantType<PREDICATE> scans the types that constitute the alternatives
|
||||
// of a std::variant instantiation. The zero-based index of the first type T
|
||||
// among the alternatives for which PREDICATE<T>::value() is true is returned,
|
||||
// or -1 if the predicate is false for every alternative of the union.
|
||||
|
||||
// N.B. It *is* possible to extract the types of the alternatives of a
|
||||
// std::variant discriminated union instantiation and reuse them as a
|
||||
// template parameter pack in another template instantiation. The trick is
|
||||
// to match the std::variant type with a partial specialization. And it
|
||||
// works with tuples, too, of course.
|
||||
// OverMembers extracts the list of types that constitute the alternatives
|
||||
// of a std::variant or elements of a std::tuple and passes that list as
|
||||
// parameter types to a given variadic template.
|
||||
template<template<typename...> class, typename> struct OverMembersHelper;
|
||||
template<template<typename...> class T, typename... Ts>
|
||||
struct OverMembersHelper<T, std::variant<Ts...>> {
|
||||
|
@ -80,12 +107,16 @@ struct OverMembersHelper<T, std::tuple<Ts...>> {
|
|||
template<template<typename...> class T, typename TorV>
|
||||
using OverMembers = typename OverMembersHelper<T, TorV>::type;
|
||||
|
||||
// SearchMembers<PREDICATE> scans the types that constitute the alternatives
|
||||
// of a std::variant instantiation or elements of a std::tuple.
|
||||
// The zero-based index of the first type T among the alternatives for which
|
||||
// PREDICATE<T>::value() is true is returned, or -1 when the predicate is false
|
||||
// for every type in the set.
|
||||
template<template<typename> class PREDICATE> struct SearchMembersHelper {
|
||||
template<typename... Ts> struct Scanner {
|
||||
static constexpr int value() { return SearchTypeList<PREDICATE, Ts...>; }
|
||||
};
|
||||
};
|
||||
|
||||
template<template<typename> class PREDICATE, typename TorV>
|
||||
constexpr int SearchMembers{
|
||||
OverMembers<SearchMembersHelper<PREDICATE>::template Scanner,
|
||||
|
@ -115,22 +146,26 @@ template<typename... Ts> struct VariantToTupleHelper<std::variant<Ts...>> {
|
|||
template<typename VARIANT>
|
||||
using VariantToTuple = typename VariantToTupleHelper<VARIANT>::type;
|
||||
|
||||
template<typename A, typename B, typename... REST> struct AreTypesDistinctHelper {
|
||||
template<typename A, typename B, typename... REST>
|
||||
struct AreTypesDistinctHelper {
|
||||
static constexpr bool value() {
|
||||
if constexpr (std::is_same_v<A, B>) {
|
||||
return false;
|
||||
}
|
||||
if constexpr (sizeof...(REST) > 0) {
|
||||
return AreTypesDistinctHelper<A, REST...>::value() && AreTypesDistinctHelper<B, REST...>::value();
|
||||
return AreTypesDistinctHelper<A, REST...>::value() &&
|
||||
AreTypesDistinctHelper<B, REST...>::value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
template<typename... Ts> constexpr bool AreTypesDistinct{AreTypesDistinctHelper<Ts...>::value()};
|
||||
template<typename... Ts>
|
||||
constexpr bool AreTypesDistinct{AreTypesDistinctHelper<Ts...>::value()};
|
||||
|
||||
template<typename> struct TupleToVariantHelper;
|
||||
template<typename... Ts> struct TupleToVariantHelper<std::tuple<Ts...>> {
|
||||
static_assert(AreTypesDistinct<Ts...> || !"TupleToVariant: types are not pairwise distinct");
|
||||
static_assert(AreTypesDistinct<Ts...> ||
|
||||
!"TupleToVariant: types are not pairwise distinct");
|
||||
using type = std::variant<Ts...>;
|
||||
};
|
||||
template<typename TUPLE>
|
||||
|
@ -142,26 +177,72 @@ template<typename... VARIANTS> struct CombineVariantsHelper {
|
|||
template<typename... VARIANTS>
|
||||
using CombineVariants = typename CombineVariantsHelper<VARIANTS...>::type;
|
||||
|
||||
// SquashVariantOfVariants: given a std::variant whose alternatives are
|
||||
// all std::variant instantiations, form a new union over their alternatives.
|
||||
template<typename VARIANT>
|
||||
using SquashVariantOfVariants = OverMembers<CombineVariants, VARIANT>;
|
||||
|
||||
// Given a type function, apply it to each of the types in a tuple or variant,
|
||||
// and collect the results in another tuple or variant.
|
||||
// Given a type function, MapTemplate applies it to each of the types
|
||||
// in a tuple or variant, and collect the results in a given variadic
|
||||
// template (typically a std::variant).
|
||||
template<template<typename> class, template<typename...> class, typename...>
|
||||
struct MapTemplateHelper;
|
||||
template<template<typename> class F, template<typename...> class TorV,
|
||||
template<template<typename> class F, template<typename...> class PACKAGE,
|
||||
typename... Ts>
|
||||
struct MapTemplateHelper<F, TorV, std::tuple<Ts...>> {
|
||||
using type = TorV<F<Ts>...>;
|
||||
struct MapTemplateHelper<F, PACKAGE, std::tuple<Ts...>> {
|
||||
using type = PACKAGE<F<Ts>...>;
|
||||
};
|
||||
template<template<typename> class F, template<typename...> class TorV,
|
||||
template<template<typename> class F, template<typename...> class PACKAGE,
|
||||
typename... Ts>
|
||||
struct MapTemplateHelper<F, TorV, std::variant<Ts...>> {
|
||||
using type = TorV<F<Ts>...>;
|
||||
struct MapTemplateHelper<F, PACKAGE, std::variant<Ts...>> {
|
||||
using type = PACKAGE<F<Ts>...>;
|
||||
};
|
||||
template<template<typename> class F, template<typename...> class TorV,
|
||||
typename TV>
|
||||
using MapTemplate = typename MapTemplateHelper<F, TorV, TV>::type;
|
||||
template<template<typename> class F, typename TorV,
|
||||
template<typename...> class PACKAGE = std::variant>
|
||||
using MapTemplate = typename MapTemplateHelper<F, PACKAGE, TorV>::type;
|
||||
|
||||
// std::tuple<std::optional<>...> -> std::optional<std::tuple<...>>
|
||||
// i.e., inverts a tuple of optional values into an optional tuple that has
|
||||
// a value only if all of the original elements were present.
|
||||
template<typename... A, std::size_t... J>
|
||||
std::optional<std::tuple<A...>> AllElementsPresentHelper(
|
||||
std::tuple<std::optional<A>...> &&t, std::index_sequence<J...>) {
|
||||
bool present[]{std::get<J>(t).has_value()...};
|
||||
for (std::size_t j{0}; j < sizeof...(J); ++j) {
|
||||
if (!present[j]) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return {std::make_tuple(*std::get<J>(t)...)};
|
||||
}
|
||||
|
||||
template<typename... A>
|
||||
std::optional<std::tuple<A...>> AllElementsPresent(
|
||||
std::tuple<std::optional<A>...> &&t) {
|
||||
return AllElementsPresentHelper(
|
||||
std::move(t), std::index_sequence_for<A...>{});
|
||||
}
|
||||
|
||||
// (std::optional<>...) -> std::optional<std::tuple<...>>
|
||||
// i.e., given some number of optional values, return a optional tuple of
|
||||
// those values that is present only of all of the values were so.
|
||||
template<typename... A>
|
||||
std::optional<std::tuple<A...>> AllPresent(std::optional<A> &&... x) {
|
||||
return AllElementsPresent(std::make_tuple(std::move(x)...));
|
||||
}
|
||||
|
||||
// (f(A...) -> R) -> std::optional<A>... -> std::optional<R>
|
||||
// Apply a function to optional arguments if all are present.
|
||||
// If the function returns std::optional, you will probably want to
|
||||
// pass it through JoinOptional to "squash" it.
|
||||
template<typename R, typename... A>
|
||||
std::optional<R> MapOptional(
|
||||
std::function<R(A &&...)> &&f, std::optional<A> &&... x) {
|
||||
if (auto args{AllPresent(std::move(x)...)}) {
|
||||
return std::make_optional(std::apply(std::move(f), std::move(*args)));
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace Fortran::common
|
||||
#endif // FORTRAN_COMMON_TEMPLATE_H_
|
||||
|
|
|
@ -539,7 +539,7 @@ template<> struct Relational<SomeType> {
|
|||
Relational(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
||||
: u{std::move(x)} {}
|
||||
std::ostream &Dump(std::ostream &o) const;
|
||||
common::MapTemplate<Relational, std::variant, RelationalTypes> u;
|
||||
common::MapTemplate<Relational, RelationalTypes> u;
|
||||
};
|
||||
|
||||
extern template struct Relational<Type<TypeCategory::Integer, 1>>;
|
||||
|
@ -605,7 +605,7 @@ public:
|
|||
template<typename A>
|
||||
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
||||
|
||||
common::MapTemplate<Expr, std::variant, CategoryTypes<CAT>> u;
|
||||
common::MapTemplate<Expr, CategoryTypes<CAT>> u;
|
||||
};
|
||||
|
||||
// BOZ literal constants need to be wide enough to hold an integer or real
|
||||
|
@ -645,7 +645,7 @@ public:
|
|||
}
|
||||
|
||||
using Others = std::variant<BOZLiteralConstant>;
|
||||
using Categories = common::MapTemplate<Expr, std::variant, SomeCategory>;
|
||||
using Categories = common::MapTemplate<Expr, SomeCategory>;
|
||||
common::CombineVariants<Others, Categories> u;
|
||||
};
|
||||
|
||||
|
|
|
@ -22,6 +22,25 @@ using namespace Fortran::parser::literals;
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
using SameRealExprPair = SameKindExprs<TypeCategory::Real>;
|
||||
|
||||
static SameRealExprPair ConversionHelper(
|
||||
Expr<SomeReal> &&x, Expr<SomeReal> &&y) {
|
||||
return std::visit(
|
||||
[&](auto &&rx, auto &&ry) -> SameRealExprPair {
|
||||
using XTy = ResultType<decltype(rx)>;
|
||||
using YTy = ResultType<decltype(ry)>;
|
||||
if constexpr (std::is_same_v<XTy, YTy>) {
|
||||
return {SameExprs<XTy>{std::move(rx), std::move(ry)}};
|
||||
} else if constexpr (XTy::kind < YTy::kind) {
|
||||
return {SameExprs<YTy>{ConvertTo(ry, std::move(rx)), std::move(ry)}};
|
||||
} else {
|
||||
return {SameExprs<XTy>{std::move(rx), ConvertTo(rx, std::move(ry))}};
|
||||
}
|
||||
},
|
||||
std::move(x.u), std::move(y.u));
|
||||
}
|
||||
|
||||
ConvertRealOperandsResult ConvertRealOperands(
|
||||
parser::ContextualMessages &messages, Expr<SomeType> &&x,
|
||||
Expr<SomeType> &&y) {
|
||||
|
@ -31,24 +50,22 @@ ConvertRealOperandsResult ConvertRealOperands(
|
|||
Expr<SomeInteger> &&iy) -> ConvertRealOperandsResult {
|
||||
// Can happen in a CMPLX() constructor. Per F'2018,
|
||||
// both integer operands are converted to default REAL.
|
||||
return std::optional{std::make_pair(
|
||||
ToCategoryExpr(ConvertToType<DefaultReal>(std::move(ix))),
|
||||
ToCategoryExpr(ConvertToType<DefaultReal>(std::move(iy))))};
|
||||
return {ConversionHelper(ConvertToType<DefaultReal>(std::move(ix)),
|
||||
ConvertToType<DefaultReal>(std::move(iy)))};
|
||||
},
|
||||
[&](Expr<SomeInteger> &&ix,
|
||||
Expr<SomeReal> &&ry) -> ConvertRealOperandsResult {
|
||||
auto rx{ConvertTo(ry, std::move(ix))};
|
||||
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||
return {
|
||||
ConversionHelper(ConvertTo(ry, std::move(ix)), std::move(ry))};
|
||||
},
|
||||
[&](Expr<SomeReal> &&rx,
|
||||
Expr<SomeInteger> &&iy) -> ConvertRealOperandsResult {
|
||||
auto ry{ConvertTo(rx, std::move(iy))};
|
||||
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||
return {
|
||||
ConversionHelper(std::move(rx), ConvertTo(rx, std::move(iy)))};
|
||||
},
|
||||
[&](Expr<SomeReal> &&rx,
|
||||
Expr<SomeReal> &&ry) -> ConvertRealOperandsResult {
|
||||
ConvertToSameKind(rx, ry);
|
||||
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
|
||||
return {ConversionHelper(std::move(rx), std::move(ry))};
|
||||
},
|
||||
[&](auto &&, auto &&) -> ConvertRealOperandsResult {
|
||||
// TODO: allow BOZ here?
|
||||
|
@ -66,8 +83,8 @@ ConvertRealOperandsResult ConvertRealOperands(
|
|||
}};
|
||||
using fType = ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
|
||||
std::function<fType> f{partial};
|
||||
return common::JoinOptionals(
|
||||
common::MapOptional(f, std::move(x), std::move(y)));
|
||||
return common::JoinOptional(
|
||||
common::MapOptional(std::move(f), std::move(x), std::move(y)));
|
||||
}
|
||||
|
||||
template<template<typename> class OPR, TypeCategory CAT>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "expression.h"
|
||||
#include "../common/idioms.h"
|
||||
#include "../parser/message.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
|
@ -93,18 +94,22 @@ Expr<SomeKind<C>> operator/(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
|
|||
// Generalizers: these take expressions of more specific types and wrap
|
||||
// them in more abstract containers.
|
||||
|
||||
template<TypeCategory CAT, int KIND>
|
||||
Expr<SomeKind<CAT>> ToCategoryExpr(Expr<Type<CAT, KIND>> &&x) {
|
||||
return {std::move(x)};
|
||||
}
|
||||
|
||||
template<typename A> Expr<SomeType> ToGenericExpr(A &&x) {
|
||||
template<typename A> Expr<ResultType<A>> AsExpr(A &&x) {
|
||||
return {std::move(x)};
|
||||
}
|
||||
|
||||
template<TypeCategory CAT, int KIND>
|
||||
Expr<SomeType> ToGenericExpr(Expr<Type<CAT, KIND>> &&x) {
|
||||
return {ToCategoryExpr(std::move(x))};
|
||||
Expr<SomeKind<CAT>> AsCategoryExpr(Expr<Type<CAT, KIND>> &&x) {
|
||||
return {std::move(x)};
|
||||
}
|
||||
|
||||
template<typename A> Expr<SomeType> AsGenericExpr(A &&x) {
|
||||
return {std::move(x)};
|
||||
}
|
||||
|
||||
template<TypeCategory CAT, int KIND>
|
||||
Expr<SomeType> AsGenericExpr(Expr<Type<CAT, KIND>> &&x) {
|
||||
return {AsCategoryExpr(std::move(x))};
|
||||
}
|
||||
|
||||
// Creation of conversion expressions can be done to either a known
|
||||
|
@ -125,7 +130,7 @@ Expr<Type<TC, TK>> ConvertTo(
|
|||
template<TypeCategory TC, int TK, TypeCategory FC, int FK>
|
||||
Expr<Type<TC, TK>> ConvertTo(
|
||||
const Expr<Type<TC, TK>> &, Expr<Type<FC, FK>> &&x) {
|
||||
return ConvertToType<Type<TC, TK>>(ToCategoryExpr(std::move(x)));
|
||||
return ConvertToType<Type<TC, TK>>(AsCategoryExpr(std::move(x)));
|
||||
}
|
||||
|
||||
template<TypeCategory TC, TypeCategory FC>
|
||||
|
@ -134,7 +139,7 @@ Expr<SomeKind<TC>> ConvertTo(
|
|||
return std::visit(
|
||||
[&](const auto &toKindExpr) {
|
||||
using KindExpr = std::decay_t<decltype(toKindExpr)>;
|
||||
return ToCategoryExpr(
|
||||
return AsCategoryExpr(
|
||||
ConvertToType<ResultType<KindExpr>>(std::move(from)));
|
||||
},
|
||||
to.u);
|
||||
|
@ -143,14 +148,14 @@ Expr<SomeKind<TC>> ConvertTo(
|
|||
template<TypeCategory TC, TypeCategory FC, int FK>
|
||||
Expr<SomeKind<TC>> ConvertTo(
|
||||
const Expr<SomeKind<TC>> &to, Expr<Type<FC, FK>> &&from) {
|
||||
return ConvertTo(to, ToCategoryExpr(std::move(from)));
|
||||
return ConvertTo(to, AsCategoryExpr(std::move(from)));
|
||||
}
|
||||
|
||||
template<typename FT>
|
||||
Expr<SomeType> ConvertTo(const Expr<SomeType> &to, Expr<FT> &&from) {
|
||||
return std::visit(
|
||||
[&](const auto &toCatExpr) {
|
||||
return ToGenericExpr(ConvertTo(toCatExpr, std::move(from)));
|
||||
return AsGenericExpr(ConvertTo(toCatExpr, std::move(from)));
|
||||
},
|
||||
to.u);
|
||||
}
|
||||
|
@ -175,9 +180,16 @@ void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {
|
|||
// Ensure that both operands of an intrinsic REAL operation (or CMPLX()
|
||||
// constructor) are INTEGER or REAL, then convert them as necessary to the
|
||||
// same kind of REAL.
|
||||
// TODO pmk: need a better type that guarantees that both have same kind
|
||||
template<int N = 2> struct SameExprsHelper {
|
||||
template<typename A> using SameExprs = std::array<Expr<A>, N>;
|
||||
};
|
||||
template<typename A, int N = 2> using SameExprs = std::array<Expr<A>, N>;
|
||||
template<TypeCategory CAT, int N = 2>
|
||||
using SameKindExprs =
|
||||
common::MapTemplate<SameExprsHelper<N>::template SameExprs,
|
||||
CategoryTypes<CAT>>;
|
||||
using ConvertRealOperandsResult =
|
||||
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>;
|
||||
std::optional<SameKindExprs<TypeCategory::Real, 2>>;
|
||||
ConvertRealOperandsResult ConvertRealOperands(
|
||||
parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
|
||||
ConvertRealOperandsResult ConvertRealOperands(parser::ContextualMessages &,
|
||||
|
|
|
@ -230,7 +230,7 @@ template<typename TYPES> struct SomeScalar {
|
|||
return common::GetIf<Scalar<T>>(u);
|
||||
}
|
||||
|
||||
common::MapTemplate<Scalar, std::variant, Types> u;
|
||||
common::MapTemplate<Scalar, Types> u;
|
||||
};
|
||||
|
||||
template<TypeCategory CATEGORY>
|
||||
|
|
|
@ -107,7 +107,7 @@ template<TypeCategory CAT, typename VALUE> struct ConstantHelper {
|
|||
if (kind == Ty::kind) {
|
||||
result = Expr<Ty>{evaluate::Constant<Ty>{std::move(value)}};
|
||||
} else {
|
||||
SetKindTraverser<J+1>(kind);
|
||||
SetKindTraverser<J + 1>(kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,10 +130,9 @@ static std::optional<Expr<evaluate::SomeCharacter>> AnalyzeLiteral(
|
|||
return std::move(helper.result);
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
MaybeExpr PackageGeneric(std::optional<A> &&x) {
|
||||
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
|
||||
if (x.has_value()) {
|
||||
return {evaluate::ToGenericExpr(std::move(*x))};
|
||||
return {evaluate::AsGenericExpr(std::move(*x))};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -154,12 +153,14 @@ MaybeExpr AnalyzeHelper(
|
|||
std::optional<Expr<evaluate::SubscriptInteger>> lb, ub;
|
||||
if (lbTree.has_value()) {
|
||||
if (MaybeIntExpr lbExpr{AnalyzeHelper(ea, *lbTree)}) {
|
||||
lb = evaluate::ConvertToType<evaluate::SubscriptInteger>(std::move(*lbExpr));
|
||||
lb = evaluate::ConvertToType<evaluate::SubscriptInteger>(
|
||||
std::move(*lbExpr));
|
||||
}
|
||||
}
|
||||
if (ubTree.has_value()) {
|
||||
if (MaybeIntExpr ubExpr{AnalyzeHelper(ea, *ubTree)}) {
|
||||
ub = evaluate::ConvertToType<evaluate::SubscriptInteger>(std::move(*ubExpr));
|
||||
ub = evaluate::ConvertToType<evaluate::SubscriptInteger>(
|
||||
std::move(*ubExpr));
|
||||
}
|
||||
}
|
||||
if (!lb.has_value() || !ub.has_value()) {
|
||||
|
@ -169,7 +170,7 @@ MaybeExpr AnalyzeHelper(
|
|||
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
|
||||
Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
|
||||
chExpr.Fold(ea.context());
|
||||
return {evaluate::ToGenericExpr(chExpr)};
|
||||
return {evaluate::AsGenericExpr(chExpr)};
|
||||
}
|
||||
|
||||
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
|
||||
|
@ -179,7 +180,8 @@ std::optional<Expr<evaluate::SomeInteger>> IntLiteralConstant(
|
|||
auto kind{ea.Analyze(std::get<std::optional<parser::KindParam>>(x.t),
|
||||
ea.defaultIntegerKind())};
|
||||
auto value{std::get<0>(x.t)}; // std::(u)int64_t
|
||||
ConstantHelper<TypeCategory::Integer, decltype(value)> helper{std::move(value)};
|
||||
ConstantHelper<TypeCategory::Integer, decltype(value)> helper{
|
||||
std::move(value)};
|
||||
helper.SetKind(kind);
|
||||
if (!helper.result.has_value()) {
|
||||
ea.context().messages.Say("unsupported INTEGER(KIND=%ju)"_err_en_US,
|
||||
|
@ -236,7 +238,8 @@ std::optional<Expr<evaluate::SomeReal>> ReadRealLiteral(
|
|||
if (context.flushDenormalsToZero) {
|
||||
value = value.FlushDenormalToZero();
|
||||
}
|
||||
return {evaluate::ToCategoryExpr(Expr<RealType>{evaluate::Constant<RealType>{value}})};
|
||||
return {evaluate::AsCategoryExpr(
|
||||
Expr<RealType>{evaluate::Constant<RealType>{value}})};
|
||||
}
|
||||
|
||||
struct RealHelper {
|
||||
|
@ -250,7 +253,7 @@ struct RealHelper {
|
|||
if (kind == Ty::kind) {
|
||||
result = ReadRealLiteral<Ty::kind>(literal, context);
|
||||
} else {
|
||||
SetKindTraverser<J+1>(kind);
|
||||
SetKindTraverser<J + 1>(kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -597,22 +600,19 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
|
|||
kindParam->u);
|
||||
}
|
||||
|
||||
// TODO pmk: need a way to represent a tuple of same-typed expressions, avoid CHECK here
|
||||
std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
|
||||
MaybeExpr &&real, MaybeExpr &&imaginary) {
|
||||
if (auto converted{evaluate::ConvertRealOperands(
|
||||
context_.messages, std::move(real), std::move(imaginary))}) {
|
||||
return {std::visit(
|
||||
[&](auto &&re) -> Expr<evaluate::SomeComplex> {
|
||||
using realType = evaluate::ResultType<decltype(re)>;
|
||||
auto *im{std::get_if<Expr<realType>>(&converted->second.u)};
|
||||
CHECK(im != nullptr);
|
||||
constexpr int kind{realType::kind};
|
||||
using zType = evaluate::Type<TypeCategory::Complex, kind>;
|
||||
return {Expr<evaluate::SomeComplex>{Expr<zType>{evaluate::ComplexConstructor<kind>{
|
||||
std::move(re), std::move(*im)}}}};
|
||||
[](auto &&pair) -> std::optional<Expr<evaluate::SomeComplex>> {
|
||||
using realType = evaluate::ResultType<decltype(pair[0])>;
|
||||
using zType = evaluate::SameKind<TypeCategory::Complex, realType>;
|
||||
auto cmplx{evaluate::ComplexConstructor<zType::kind>{
|
||||
std::move(pair[0]), std::move(pair[1])}};
|
||||
return {evaluate::AsCategoryExpr(evaluate::AsExpr(std::move(cmplx)))};
|
||||
},
|
||||
std::move(converted->first.u))};
|
||||
*converted)};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue