[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:
peter klausler 2018-08-17 09:50:32 -07:00
parent e798ab7d91
commit 856123351c
6 changed files with 175 additions and 154 deletions

View File

@ -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_

View File

@ -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>;

View File

@ -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)

View File

@ -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) { \

View File

@ -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_;

View File

@ -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();
}