forked from OSchip/llvm-project
[flang] checkpoint
Original-commit: flang-compiler/f18@e874c926d0 Reviewed-on: https://github.com/flang-compiler/f18/pull/183 Tree-same-pre-rewrite: false
This commit is contained in:
parent
e798ab7d91
commit
856123351c
flang
|
@ -31,5 +31,7 @@ ENUM_CLASS(ImportKind, Default, Only, None, All)
|
|||
// The attribute on a type parameter can be KIND or LEN.
|
||||
ENUM_CLASS(TypeParamAttr, Kind, Len)
|
||||
|
||||
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
|
||||
|
||||
} // namespace Fortran::common
|
||||
#endif // FORTRAN_COMMON_FORTRAN_H_
|
||||
|
|
|
@ -116,14 +116,12 @@ using HostUnsignedInt =
|
|||
// - There is no default constructor (Class() {}), usually to prevent the
|
||||
// need for std::monostate as a default constituent in a std::variant<>.
|
||||
// - There are full copy and move semantics for construction and assignment.
|
||||
// - There's a Dump(std::ostream &) member function.
|
||||
#define CLASS_BOILERPLATE(t) \
|
||||
t() = delete; \
|
||||
t(const t &) = default; \
|
||||
t(t &&) = default; \
|
||||
t &operator=(const t &) = default; \
|
||||
t &operator=(t &&) = default; \
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
t &operator=(t &&) = default;
|
||||
|
||||
// Force availability of copy construction and assignment
|
||||
template<typename A> using CopyableIndirection = common::Indirection<A, true>;
|
||||
|
|
|
@ -27,16 +27,7 @@ using namespace Fortran::parser::literals;
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
template<typename D, typename R, typename... O>
|
||||
std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const {
|
||||
operand<0>().Dump(o << derived().prefix_);
|
||||
if constexpr (operands() > 1) {
|
||||
operand<1>().Dump(o << infix_);
|
||||
}
|
||||
return o << derived().suffix_;
|
||||
}
|
||||
|
||||
// TODO: dump Convert<Integer,x> as INT(x,KIND=), &c.
|
||||
// Folding
|
||||
|
||||
template<typename D, typename R, typename... O>
|
||||
auto Operation<D, R, O...>::Fold(FoldingContext &context)
|
||||
|
@ -134,9 +125,9 @@ auto Negate<A>::FoldScalar(FoldingContext &context, const Scalar<Operand> &c)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND, bool R>
|
||||
auto ComplexComponent<KIND, R>::FoldScalar(FoldingContext &context,
|
||||
const Scalar<Operand> &z) -> std::optional<Scalar<Result>> {
|
||||
template<int KIND>
|
||||
auto ComplexComponent<KIND>::FoldScalar(FoldingContext &context,
|
||||
const Scalar<Operand> &z) const -> std::optional<Scalar<Result>> {
|
||||
return {isRealPart ? z.REAL() : z.AIMAG()};
|
||||
}
|
||||
|
||||
|
@ -146,7 +137,39 @@ auto Not<KIND>::FoldScalar(FoldingContext &context, const Scalar<Operand> &x)
|
|||
return {Scalar<Result>{!x.IsTrue()}};
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
auto Add<A>::FoldScalar(FoldingContext &context, const Scalar<Operand> &x,
|
||||
const Scalar<Operand> &y) -> std::optional<Scalar<Result>> {
|
||||
if constexpr (Result::category == TypeCategory::Integer) {
|
||||
auto sum{x.AddSigned(y)};
|
||||
if (sum.overflow) {
|
||||
context.messages.Say("INTEGER addition overflowed"_en_US);
|
||||
} else {
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
} else {
|
||||
auto sum{x.Add(y, context.rounding)};
|
||||
RealFlagWarnings(context, sum.flags, "addition");
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Dumping
|
||||
|
||||
template<typename D, typename R, typename... O>
|
||||
std::ostream &Operation<D, R, O...>::Dump(std::ostream &o) const {
|
||||
operand<0>().Dump(o << derived().prefix());
|
||||
if constexpr (operands() > 1) {
|
||||
operand<1>().Dump(o << derived().infix());
|
||||
}
|
||||
return o << derived().suffix();
|
||||
}
|
||||
|
||||
template<typename A> std::string Comparison<A>::infix() const {
|
||||
return "."s + EnumToString(opr) + '.';
|
||||
}
|
||||
|
||||
template<typename... A>
|
||||
std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
|
||||
std::visit(common::visitors{[&](const BOZLiteralConstant &x) {
|
||||
|
@ -180,18 +203,18 @@ std::ostream &Binary<CRTP, RESULT, A, B>::Dump(
|
|||
template<int KIND>
|
||||
std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
|
||||
std::ostream &o) const {
|
||||
std::visit(
|
||||
common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); },
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Add &a) { a.Dump(o, "+"); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
[&](const Divide &d) { d.Dump(o, "/"); },
|
||||
[&](const Power &p) { p.Dump(o, "**"); },
|
||||
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
|
||||
[&](const auto &x) { x.Dump(o); }},
|
||||
std::visit(common::visitors{[&](const Scalar<Result> &n) {
|
||||
o << n.SignedDecimal() << '_' << KIND;
|
||||
},
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
[&](const Divide &d) { d.Dump(o, "/"); },
|
||||
[&](const Power &p) { p.Dump(o, "**"); },
|
||||
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
|
||||
[&](const auto &x) { x.Dump(o); }},
|
||||
u_);
|
||||
return o;
|
||||
}
|
||||
|
@ -205,20 +228,14 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
|
|||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Convert<Result, SomeInteger> &c) { c.Dump(o); },
|
||||
[&](const Convert<Result, SomeReal> &c) { c.Dump(o); },
|
||||
[&](const ComplexComponent<KIND, true> &z) { z.Dump(o); },
|
||||
[&](const ComplexComponent<KIND, false> &z) { z.Dump(o); },
|
||||
[&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Negate<Result> &n) { n.Dump(o); },
|
||||
[&](const Add &a) { a.Dump(o, "+"); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
[&](const Divide &d) { d.Dump(o, "/"); },
|
||||
[&](const Power &p) { p.Dump(o, "**"); },
|
||||
[&](const IntPower &p) { p.Dump(o, "**"); },
|
||||
[&](const Max &m) { m.Dump(o, ",", "MAX("); },
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); }},
|
||||
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
|
||||
[&](const auto &x) { x.Dump(o); }},
|
||||
u_);
|
||||
return o;
|
||||
}
|
||||
|
@ -231,7 +248,6 @@ std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump(
|
|||
},
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
[&](const Add &a) { a.Dump(o, "+"); },
|
||||
[&](const Subtract &s) { s.Dump(o, "-"); },
|
||||
[&](const Multiply &m) { m.Dump(o, "*"); },
|
||||
[&](const Divide &d) { d.Dump(o, "/"); },
|
||||
|
@ -247,7 +263,8 @@ template<int KIND>
|
|||
std::ostream &Expr<Type<TypeCategory::Character, KIND>>::Dump(
|
||||
std::ostream &o) const {
|
||||
std::visit(common::visitors{[&](const Scalar<Result> &s) {
|
||||
o << parser::QuoteCharacterLiteral(s);
|
||||
o << KIND << '_'
|
||||
<< parser::QuoteCharacterLiteral(s);
|
||||
},
|
||||
// [&](const Parentheses<Result> &p) { p.Dump(o); },
|
||||
[&](const Concat &concat) { concat.Dump(o, "//"); },
|
||||
|
@ -258,18 +275,12 @@ std::ostream &Expr<Type<TypeCategory::Character, KIND>>::Dump(
|
|||
return o;
|
||||
}
|
||||
|
||||
template<typename A> std::ostream &Comparison<A>::Dump(std::ostream &o) const {
|
||||
o << '(' << A::Dump() << "::";
|
||||
this->left().Dump(o);
|
||||
o << '.' << EnumToString(this->opr) << '.';
|
||||
return this->right().Dump(o) << ')';
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump(
|
||||
std::ostream &o) const {
|
||||
std::visit(common::visitors{[&](const Scalar<Result> &tf) {
|
||||
o << (tf.IsTrue() ? ".TRUE." : ".FALSE.");
|
||||
o << (tf.IsTrue() ? ".TRUE." : ".FALSE.") << '_'
|
||||
<< KIND;
|
||||
},
|
||||
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
|
||||
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
|
||||
|
@ -333,18 +344,6 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
auto sum{a.AddSigned(b)};
|
||||
if (sum.overflow) {
|
||||
context.messages.Say("integer addition overflowed"_en_US);
|
||||
return std::nullopt;
|
||||
}
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Integer, KIND>>::Subtract::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -450,15 +449,6 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
|
|||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
auto sum{a.Add(b, context.rounding)};
|
||||
RealFlagWarnings(context, sum.flags, "real addition");
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Real, KIND>>::Subtract::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
@ -555,15 +545,6 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
|
|||
u_);
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Complex, KIND>>::Add::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
-> std::optional<Scalar<Result>> {
|
||||
auto sum{a.Add(b, context.rounding)};
|
||||
RealFlagWarnings(context, sum.flags, "complex addition");
|
||||
return {std::move(sum.value)};
|
||||
}
|
||||
|
||||
template<int KIND>
|
||||
auto Expr<Type<TypeCategory::Complex, KIND>>::Subtract::FoldScalar(
|
||||
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "common.h"
|
||||
#include "type.h"
|
||||
#include "variable.h"
|
||||
#include "../lib/common/fortran.h"
|
||||
#include "../lib/common/idioms.h"
|
||||
#include "../lib/parser/char-block.h"
|
||||
#include "../lib/parser/message.h"
|
||||
|
@ -33,54 +34,51 @@
|
|||
|
||||
namespace Fortran::evaluate {
|
||||
|
||||
using common::RelationalOperator;
|
||||
|
||||
template<typename A> class Expr;
|
||||
|
||||
template<typename DERIVED, typename RESULT, typename... OPERAND>
|
||||
class Operation {
|
||||
private:
|
||||
using OperandTypes = std::tuple<OPERAND...>;
|
||||
|
||||
public:
|
||||
using Derived = DERIVED;
|
||||
using Result = RESULT;
|
||||
using OperandTypes = std::tuple<OPERAND...>;
|
||||
using OperandTuple = std::tuple<Expr<OPERAND>...>;
|
||||
template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
||||
using FoldableTrait = std::true_type;
|
||||
|
||||
static_assert(Result::kind > 0); // Operations have specific Result types
|
||||
|
||||
#if !__clang__
|
||||
CLASS_BOILERPLATE(Operation)
|
||||
#else // clang 6.0 erroneously deletes the "=default" copy constructor
|
||||
Operation() = delete;
|
||||
Operation(const Operation &that) : operand_{that.operand_} {}
|
||||
Operation(Operation &&) = default;
|
||||
Operation &operator=(const Operation &) = default;
|
||||
Operation &operator=(Operation &&) = default;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
#endif
|
||||
|
||||
Operation(Expr<OPERAND> &&... x) : operand_{std::move(x)...} {}
|
||||
Operation(const Expr<OPERAND> &... x) : operand_{x...} {}
|
||||
Operation(const Expr<OPERAND> &... x) : operand_{OperandTuple{x...}} {}
|
||||
Operation(Expr<OPERAND> &&... x)
|
||||
: operand_{OperandTuple{std::forward<Expr<OPERAND>>(x)...}} {}
|
||||
|
||||
DERIVED &derived() { return *static_cast<DERIVED *>(this); }
|
||||
const DERIVED &derived() const { return *static_cast<const DERIVED *>(this); }
|
||||
|
||||
static constexpr auto operands() { return sizeof...(OPERAND); }
|
||||
template<int J> Expr<Operand<J>> &operand() { return *std::get<J>(operand_); }
|
||||
static constexpr auto operands() { return std::tuple_size_v<OperandTypes>; }
|
||||
template<int J> Expr<Operand<J>> &operand() { return std::get<J>(*operand_); }
|
||||
template<int J> const Expr<Operand<J>> &operand() const {
|
||||
return *std::get<J>(operand_);
|
||||
return std::get<J>(*operand_);
|
||||
}
|
||||
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &); // TODO rank > 0
|
||||
|
||||
protected:
|
||||
// Overridable strings for Dump()
|
||||
static constexpr const char *prefix_{"("}, *infix_{""}, *suffix_{")"};
|
||||
// Overridable string functions for Dump()
|
||||
static const char *prefix() { return "("; }
|
||||
static const char *infix() { return ","; }
|
||||
static const char *suffix() { return ")"; }
|
||||
|
||||
private:
|
||||
std::tuple<CopyableIndirection<Expr<OPERAND>>...> operand_;
|
||||
CopyableIndirection<OperandTuple> operand_;
|
||||
};
|
||||
|
||||
// Unary operations
|
||||
|
||||
template<typename TO, typename FROM>
|
||||
struct Convert : public Operation<Convert<TO, FROM>, TO, FROM> {
|
||||
using Base = Operation<Convert<TO, FROM>, TO, FROM>;
|
||||
|
@ -110,24 +108,29 @@ template<typename A> struct Negate : public Operation<Negate<A>, A, A> {
|
|||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(-"};
|
||||
static const char *prefix() { return "(-"; }
|
||||
};
|
||||
|
||||
// TODO: re vs. im can be dynamic
|
||||
template<int KIND, bool realPart = true>
|
||||
template<int KIND>
|
||||
struct ComplexComponent
|
||||
: public Operation<ComplexComponent<KIND, realPart>,
|
||||
Type<TypeCategory::Real, KIND>, Type<TypeCategory::Complex, KIND>> {
|
||||
: public Operation<ComplexComponent<KIND>, Type<TypeCategory::Real, KIND>,
|
||||
Type<TypeCategory::Complex, KIND>> {
|
||||
using Base = Operation<ComplexComponent, Type<TypeCategory::Real, KIND>,
|
||||
Type<TypeCategory::Complex, KIND>>;
|
||||
static constexpr bool isRealPart{realPart};
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(("};
|
||||
static constexpr const char *suffix_{isRealPart ? ")%RE)" : ")%IM)"};
|
||||
CLASS_BOILERPLATE(ComplexComponent)
|
||||
ComplexComponent(bool isReal, const Expr<Operand> &x)
|
||||
: Base{x}, isRealPart{isReal} {}
|
||||
ComplexComponent(bool isReal, Expr<Operand> &&x)
|
||||
: Base{std::move(x)}, isRealPart{isReal} {}
|
||||
|
||||
std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &) const;
|
||||
static const char *prefix() { return "(("; }
|
||||
const char *suffix() const { return isRealPart ? "%RE)" : "%IM)"; }
|
||||
|
||||
bool isRealPart{true};
|
||||
};
|
||||
|
||||
template<int KIND>
|
||||
|
@ -140,7 +143,19 @@ struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>,
|
|||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &);
|
||||
static constexpr const char *prefix_{"(.NOT."};
|
||||
static const char *prefix() { return "(.NOT."; }
|
||||
};
|
||||
|
||||
// Binary operations
|
||||
|
||||
template<typename A> struct Add : public Operation<Add<A>, A, A, A> {
|
||||
using Base = Operation<Add, A, A, A>;
|
||||
using Base::Base;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
||||
static const char *infix() { return "+"; }
|
||||
};
|
||||
|
||||
template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A>
|
||||
|
@ -179,11 +194,6 @@ public:
|
|||
using FoldableTrait = std::true_type;
|
||||
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
|
||||
};
|
||||
struct Subtract : public Bin<Subtract> {
|
||||
using Bin<Subtract>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -247,14 +257,15 @@ public:
|
|||
// TODO: Also succeed when parenthesized constant
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
|
||||
private:
|
||||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>, Convert<Result, SomeInteger>,
|
||||
Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>, Add,
|
||||
Subtract, Multiply, Divide, Power, Max, Min>
|
||||
Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>,
|
||||
Add<Result>, Subtract, Multiply, Divide, Power, Max, Min>
|
||||
u_;
|
||||
};
|
||||
|
||||
|
@ -268,11 +279,6 @@ public:
|
|||
// Complex are done via decomposition to Real and reconstruction.
|
||||
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
|
||||
};
|
||||
struct Subtract : public Bin<Subtract> {
|
||||
using Bin<Subtract>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -337,6 +343,7 @@ public:
|
|||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
|
||||
|
@ -344,9 +351,8 @@ private:
|
|||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
|
||||
Convert<Result, SomeInteger>, Convert<Result, SomeReal>,
|
||||
ComplexComponent<KIND, true>, ComplexComponent<KIND, false>,
|
||||
Parentheses<Result>, Negate<Result>, Add, Subtract, Multiply, Divide,
|
||||
Power, IntPower, Max, Min>
|
||||
ComplexComponent<KIND>, Parentheses<Result>, Negate<Result>, Add<Result>,
|
||||
Subtract, Multiply, Divide, Power, IntPower, Max, Min>
|
||||
u_;
|
||||
};
|
||||
|
||||
|
@ -356,11 +362,6 @@ public:
|
|||
using FoldableTrait = std::true_type;
|
||||
|
||||
template<typename CRTP> using Bin = Binary<CRTP, Result>;
|
||||
struct Add : public Bin<Add> {
|
||||
using Bin<Add>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
|
||||
};
|
||||
struct Subtract : public Bin<Subtract> {
|
||||
using Bin<Subtract>::Bin;
|
||||
static std::optional<Scalar<Result>> FoldScalar(
|
||||
|
@ -405,13 +406,14 @@ public:
|
|||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
|
||||
private:
|
||||
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
|
||||
CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate<Result>,
|
||||
Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX>
|
||||
Add<Result>, Subtract, Multiply, Divide, Power, IntPower, CMPLX>
|
||||
u_;
|
||||
};
|
||||
|
||||
|
@ -464,6 +466,7 @@ public:
|
|||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
|
@ -479,21 +482,23 @@ private:
|
|||
// The Comparison class template is a helper for constructing logical
|
||||
// expressions with polymorphism over the cross product of the possible
|
||||
// categories and kinds of comparable operands.
|
||||
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
|
||||
|
||||
template<typename A>
|
||||
struct Comparison : public Binary<Comparison<A>, LogicalResult, A> {
|
||||
using Result = LogicalResult;
|
||||
using Operand = A;
|
||||
using Base = Binary<Comparison, Result, Operand>;
|
||||
struct Comparison : public Operation<Comparison<A>, LogicalResult, A, A> {
|
||||
using Base = Operation<Comparison, LogicalResult, A, A>;
|
||||
using typename Base::Result;
|
||||
using Operand = typename Base::template Operand<0>;
|
||||
CLASS_BOILERPLATE(Comparison)
|
||||
Comparison(
|
||||
RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b)
|
||||
: Base{a, b}, opr{r} {}
|
||||
Comparison(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b)
|
||||
: Base{std::move(a), std::move(b)}, opr{r} {}
|
||||
|
||||
std::optional<Scalar<Result>> FoldScalar(
|
||||
FoldingContext &c, const Scalar<Operand> &, const Scalar<Operand> &);
|
||||
std::string infix() const;
|
||||
|
||||
RelationalOperator opr;
|
||||
};
|
||||
|
||||
|
@ -506,6 +511,7 @@ template<TypeCategory CAT> struct CategoryComparison {
|
|||
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
|
||||
template<int KIND>
|
||||
CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
|
||||
|
@ -555,6 +561,7 @@ public:
|
|||
// TODO: parenthesized constants too
|
||||
return common::GetIf<Scalar<Result>>(u_);
|
||||
}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &c);
|
||||
int Rank() const { return 1; } // TODO
|
||||
|
||||
|
@ -581,6 +588,7 @@ public:
|
|||
template<int KIND> Expr(const KindExpr<KIND> &x) : u{x} {}
|
||||
template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {}
|
||||
std::optional<Scalar<Result>> ScalarValue() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &);
|
||||
int Rank() const;
|
||||
|
||||
|
@ -612,6 +620,7 @@ public:
|
|||
Expr(Expr<Type<CAT, KIND>> &&x) : u{Expr<SomeKind<CAT>>{std::move(x)}} {}
|
||||
|
||||
std::optional<Scalar<Result>> ScalarValue() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
std::optional<Scalar<Result>> Fold(FoldingContext &);
|
||||
int Rank() const;
|
||||
|
||||
|
@ -625,9 +634,7 @@ 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.
|
||||
// These definitions are created with temporary helper macros to reduce
|
||||
// C++ boilerplate. All combinations of lvalue and rvalue references are
|
||||
// allowed for operands.
|
||||
|
||||
template<TypeCategory C, int K>
|
||||
Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
|
||||
return {Negate<Type<C, K>>{x}};
|
||||
|
@ -638,7 +645,26 @@ Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
|
|||
[](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u);
|
||||
}
|
||||
|
||||
#define BINARY(FUNC, CONSTR) \
|
||||
#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)
|
||||
#undef BINARY
|
||||
|
||||
#define OLDBINARY(FUNC, CONSTR) \
|
||||
template<typename A> A FUNC(const A &x, const A &y) { \
|
||||
return {typename A::CONSTR{x, y}}; \
|
||||
} \
|
||||
|
@ -655,12 +681,11 @@ Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
|
|||
return {typename A::CONSTR{std::move(x), std::move(y)}}; \
|
||||
}
|
||||
|
||||
BINARY(operator+, Add)
|
||||
BINARY(operator-, Subtract)
|
||||
BINARY(operator*, Multiply)
|
||||
BINARY(operator/, Divide)
|
||||
BINARY(Power, Power)
|
||||
#undef BINARY
|
||||
OLDBINARY(operator-, Subtract)
|
||||
OLDBINARY(operator*, Multiply)
|
||||
OLDBINARY(operator/, Divide)
|
||||
OLDBINARY(Power, Power)
|
||||
#undef OLDBINARY
|
||||
|
||||
#define BINARY(FUNC, OP) \
|
||||
template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
DataRef &base() { return *base_; }
|
||||
const Symbol &symbol() const { return *symbol_; }
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
CopyableIndirection<DataRef> base_;
|
||||
|
@ -78,6 +79,7 @@ public:
|
|||
std::optional<Expr<SubscriptInteger>> lower() const;
|
||||
std::optional<Expr<SubscriptInteger>> upper() const;
|
||||
std::optional<Expr<SubscriptInteger>> stride() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::optional<IndirectSubscriptIntegerExpr> lower_, upper_, stride_;
|
||||
|
@ -93,6 +95,7 @@ public:
|
|||
: u_{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
|
||||
explicit Subscript(const Triplet &t) : u_{t} {}
|
||||
explicit Subscript(Triplet &&t) : u_{std::move(t)} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<IndirectSubscriptIntegerExpr, Triplet> u_;
|
||||
|
@ -111,6 +114,7 @@ public:
|
|||
ArrayRef(Component &&c, std::vector<Subscript> &&ss)
|
||||
: u_{std::move(c)}, subscript_(std::move(ss)) {}
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<const Symbol *, Component> u_;
|
||||
|
@ -133,6 +137,7 @@ public:
|
|||
CoarrayRef &setStat(Variable &&);
|
||||
CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false);
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::vector<const Symbol *> base_;
|
||||
|
@ -154,6 +159,7 @@ public:
|
|||
explicit DataRef(ArrayRef &&a) : u_{std::move(a)} {}
|
||||
explicit DataRef(CoarrayRef &&a) : u_{std::move(a)} {}
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u_;
|
||||
|
@ -176,6 +182,7 @@ public:
|
|||
Expr<SubscriptInteger> last() const;
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::optional<std::string> Fold(FoldingContext &);
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<DataRef, std::string> u_;
|
||||
|
@ -192,6 +199,7 @@ public:
|
|||
ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {}
|
||||
const DataRef &complex() const { return complex_; }
|
||||
Part part() const { return part_; }
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
DataRef complex_;
|
||||
|
@ -206,6 +214,7 @@ public:
|
|||
explicit Designator(DataRef &&d) : u_{std::move(d)} {}
|
||||
explicit Designator(Substring &&s) : u_{std::move(s)} {}
|
||||
explicit Designator(ComplexPart &&c) : u_{std::move(c)} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<DataRef, Substring, ComplexPart> u_;
|
||||
|
@ -219,6 +228,7 @@ public:
|
|||
explicit ProcedureDesignator(const Component &c) : u_{c} {}
|
||||
explicit ProcedureDesignator(Component &&c) : u_{std::move(c)} {}
|
||||
Expr<SubscriptInteger> LEN() const;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<IntrinsicProcedure, const Symbol *, Component> u_;
|
||||
|
@ -232,6 +242,7 @@ public:
|
|||
: proc_{std::move(p)}, argument_(std::move(a)) {}
|
||||
const ProcedureDesignator &proc() const { return proc_; }
|
||||
const std::vector<ArgumentType> &argument() const { return argument_; }
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
ProcedureDesignator proc_;
|
||||
|
@ -245,6 +256,7 @@ public:
|
|||
CLASS_BOILERPLATE(Variable)
|
||||
explicit Variable(Designator &&d) : u_{std::move(d)} {}
|
||||
explicit Variable(FunctionRef &&p) : u_{std::move(p)} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<Designator, FunctionRef> u_;
|
||||
|
@ -255,6 +267,7 @@ public:
|
|||
CLASS_BOILERPLATE(ActualFunctionArg)
|
||||
explicit ActualFunctionArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
|
||||
explicit ActualFunctionArg(Variable &&x) : u_{std::move(x)} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<CopyableIndirection<Expr<SomeType>>, Variable> u_;
|
||||
|
@ -264,6 +277,7 @@ struct Label { // TODO: this is a placeholder
|
|||
CLASS_BOILERPLATE(Label)
|
||||
explicit Label(int lab) : label{lab} {}
|
||||
int label;
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
};
|
||||
|
||||
class ActualSubroutineArg {
|
||||
|
@ -272,6 +286,7 @@ public:
|
|||
explicit ActualSubroutineArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
|
||||
explicit ActualSubroutineArg(Variable &&x) : u_{std::move(x)} {}
|
||||
explicit ActualSubroutineArg(const Label &l) : u_{&l} {}
|
||||
std::ostream &Dump(std::ostream &) const;
|
||||
|
||||
private:
|
||||
std::variant<CopyableIndirection<Expr<SomeType>>, Variable, const Label *> u_;
|
||||
|
|
|
@ -31,24 +31,24 @@ template<typename A> std::string Dump(const A &x) {
|
|||
int main() {
|
||||
using DefaultIntegerExpr = Expr<DefaultInteger>;
|
||||
TEST(DefaultIntegerExpr::Result::Dump() == "Integer(4)");
|
||||
MATCH("666", Dump(DefaultIntegerExpr{666}));
|
||||
MATCH("(-1)", Dump(-DefaultIntegerExpr{1}));
|
||||
MATCH("666_4", Dump(DefaultIntegerExpr{666}));
|
||||
MATCH("(-1_4)", Dump(-DefaultIntegerExpr{1}));
|
||||
auto ex1{
|
||||
DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}};
|
||||
MATCH("(2+(3*(-4)))", Dump(ex1));
|
||||
MATCH("(2_4+(3_4*(-4_4)))", Dump(ex1));
|
||||
Fortran::parser::CharBlock src;
|
||||
Fortran::parser::ContextualMessages messages{src, nullptr};
|
||||
FoldingContext context{messages};
|
||||
ex1.Fold(context);
|
||||
MATCH("-10", Dump(ex1));
|
||||
MATCH("(Integer(4)::6.LE.7)",
|
||||
MATCH("-10_4", Dump(ex1));
|
||||
MATCH("(6_4.LE.7_4)",
|
||||
Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
|
||||
DefaultIntegerExpr a{1};
|
||||
DefaultIntegerExpr b{2};
|
||||
MATCH("(1/2)", Dump(a / b));
|
||||
MATCH("1", Dump(a));
|
||||
MATCH("(1_4/2_4)", Dump(a / b));
|
||||
MATCH("1_4", Dump(a));
|
||||
a = b;
|
||||
MATCH("2", Dump(a));
|
||||
MATCH("2", Dump(b));
|
||||
MATCH("2_4", Dump(a));
|
||||
MATCH("2_4", Dump(b));
|
||||
return testing::Complete();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue