[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. // The attribute on a type parameter can be KIND or LEN.
ENUM_CLASS(TypeParamAttr, Kind, Len) ENUM_CLASS(TypeParamAttr, Kind, Len)
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
} // namespace Fortran::common } // namespace Fortran::common
#endif // FORTRAN_COMMON_FORTRAN_H_ #endif // FORTRAN_COMMON_FORTRAN_H_

View File

@ -116,14 +116,12 @@ using HostUnsignedInt =
// - There is no default constructor (Class() {}), usually to prevent the // - There is no default constructor (Class() {}), usually to prevent the
// need for std::monostate as a default constituent in a std::variant<>. // need for std::monostate as a default constituent in a std::variant<>.
// - There are full copy and move semantics for construction and assignment. // - There are full copy and move semantics for construction and assignment.
// - There's a Dump(std::ostream &) member function.
#define CLASS_BOILERPLATE(t) \ #define CLASS_BOILERPLATE(t) \
t() = delete; \ t() = delete; \
t(const t &) = default; \ t(const t &) = default; \
t(t &&) = default; \ t(t &&) = default; \
t &operator=(const t &) = default; \ t &operator=(const t &) = default; \
t &operator=(t &&) = default; \ t &operator=(t &&) = default;
std::ostream &Dump(std::ostream &) const;
// Force availability of copy construction and assignment // Force availability of copy construction and assignment
template<typename A> using CopyableIndirection = common::Indirection<A, true>; template<typename A> using CopyableIndirection = common::Indirection<A, true>;

View File

@ -27,16 +27,7 @@ using namespace Fortran::parser::literals;
namespace Fortran::evaluate { namespace Fortran::evaluate {
template<typename D, typename R, typename... O> // Folding
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.
template<typename D, typename R, typename... O> template<typename D, typename R, typename... O>
auto Operation<D, R, O...>::Fold(FoldingContext &context) 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; return std::nullopt;
} }
template<int KIND, bool R> template<int KIND>
auto ComplexComponent<KIND, R>::FoldScalar(FoldingContext &context, auto ComplexComponent<KIND>::FoldScalar(FoldingContext &context,
const Scalar<Operand> &z) -> std::optional<Scalar<Result>> { const Scalar<Operand> &z) const -> std::optional<Scalar<Result>> {
return {isRealPart ? z.REAL() : z.AIMAG()}; 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()}}; 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 // 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> template<typename... A>
std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) { std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
std::visit(common::visitors{[&](const BOZLiteralConstant &x) { std::visit(common::visitors{[&](const BOZLiteralConstant &x) {
@ -180,18 +203,18 @@ std::ostream &Binary<CRTP, RESULT, A, B>::Dump(
template<int KIND> template<int KIND>
std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump( std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
std::ostream &o) const { std::ostream &o) const {
std::visit( std::visit(common::visitors{[&](const Scalar<Result> &n) {
common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); }, o << n.SignedDecimal() << '_' << KIND;
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const Add &a) { a.Dump(o, "+"); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Subtract &s) { s.Dump(o, "-"); }, [&](const Subtract &s) { s.Dump(o, "-"); },
[&](const Multiply &m) { m.Dump(o, "*"); }, [&](const Multiply &m) { m.Dump(o, "*"); },
[&](const Divide &d) { d.Dump(o, "/"); }, [&](const Divide &d) { d.Dump(o, "/"); },
[&](const Power &p) { p.Dump(o, "**"); }, [&](const Power &p) { p.Dump(o, "**"); },
[&](const Max &m) { m.Dump(o, ",", "MAX("); }, [&](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); }}, [&](const auto &x) { x.Dump(o); }},
u_); u_);
return o; return o;
} }
@ -205,20 +228,14 @@ std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); }, [&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &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 Subtract &s) { s.Dump(o, "-"); },
[&](const Multiply &m) { m.Dump(o, "*"); }, [&](const Multiply &m) { m.Dump(o, "*"); },
[&](const Divide &d) { d.Dump(o, "/"); }, [&](const Divide &d) { d.Dump(o, "/"); },
[&](const Power &p) { p.Dump(o, "**"); }, [&](const Power &p) { p.Dump(o, "**"); },
[&](const IntPower &p) { p.Dump(o, "**"); }, [&](const IntPower &p) { p.Dump(o, "**"); },
[&](const Max &m) { m.Dump(o, ",", "MAX("); }, [&](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_); u_);
return o; return o;
} }
@ -231,7 +248,6 @@ std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump(
}, },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); }, [&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Add &a) { a.Dump(o, "+"); },
[&](const Subtract &s) { s.Dump(o, "-"); }, [&](const Subtract &s) { s.Dump(o, "-"); },
[&](const Multiply &m) { m.Dump(o, "*"); }, [&](const Multiply &m) { m.Dump(o, "*"); },
[&](const Divide &d) { d.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 &Expr<Type<TypeCategory::Character, KIND>>::Dump(
std::ostream &o) const { std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &s) { 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 Parentheses<Result> &p) { p.Dump(o); },
[&](const Concat &concat) { concat.Dump(o, "//"); }, [&](const Concat &concat) { concat.Dump(o, "//"); },
@ -258,18 +275,12 @@ std::ostream &Expr<Type<TypeCategory::Character, KIND>>::Dump(
return o; 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> template<int KIND>
std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump( std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump(
std::ostream &o) const { std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &tf) { 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<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &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; 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> template<int KIND>
auto Expr<Type<TypeCategory::Integer, KIND>>::Subtract::FoldScalar( auto Expr<Type<TypeCategory::Integer, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
@ -450,15 +449,6 @@ auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
u_); 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> template<int KIND>
auto Expr<Type<TypeCategory::Real, KIND>>::Subtract::FoldScalar( auto Expr<Type<TypeCategory::Real, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
@ -555,15 +545,6 @@ auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
u_); 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> template<int KIND>
auto Expr<Type<TypeCategory::Complex, KIND>>::Subtract::FoldScalar( auto Expr<Type<TypeCategory::Complex, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b) FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)

View File

@ -24,6 +24,7 @@
#include "common.h" #include "common.h"
#include "type.h" #include "type.h"
#include "variable.h" #include "variable.h"
#include "../lib/common/fortran.h"
#include "../lib/common/idioms.h" #include "../lib/common/idioms.h"
#include "../lib/parser/char-block.h" #include "../lib/parser/char-block.h"
#include "../lib/parser/message.h" #include "../lib/parser/message.h"
@ -33,54 +34,51 @@
namespace Fortran::evaluate { namespace Fortran::evaluate {
using common::RelationalOperator;
template<typename A> class Expr; template<typename A> class Expr;
template<typename DERIVED, typename RESULT, typename... OPERAND> template<typename DERIVED, typename RESULT, typename... OPERAND>
class Operation { class Operation {
private:
using OperandTypes = std::tuple<OPERAND...>;
public: public:
using Derived = DERIVED; using Derived = DERIVED;
using Result = RESULT; 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>; template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
using FoldableTrait = std::true_type; using FoldableTrait = std::true_type;
static_assert(Result::kind > 0); // Operations have specific Result types static_assert(Result::kind > 0); // Operations have specific Result types
#if !__clang__
CLASS_BOILERPLATE(Operation) CLASS_BOILERPLATE(Operation)
#else // clang 6.0 erroneously deletes the "=default" copy constructor Operation(const Expr<OPERAND> &... x) : operand_{OperandTuple{x...}} {}
Operation() = delete; Operation(Expr<OPERAND> &&... x)
Operation(const Operation &that) : operand_{that.operand_} {} : operand_{OperandTuple{std::forward<Expr<OPERAND>>(x)...}} {}
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...} {}
DERIVED &derived() { return *static_cast<DERIVED *>(this); } DERIVED &derived() { return *static_cast<DERIVED *>(this); }
const DERIVED &derived() const { return *static_cast<const DERIVED *>(this); } const DERIVED &derived() const { return *static_cast<const DERIVED *>(this); }
static constexpr auto operands() { return sizeof...(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> Expr<Operand<J>> &operand() { return std::get<J>(*operand_); }
template<int J> const Expr<Operand<J>> &operand() const { 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 std::optional<Scalar<Result>> Fold(FoldingContext &); // TODO rank > 0
protected: protected:
// Overridable strings for Dump() // Overridable string functions for Dump()
static constexpr const char *prefix_{"("}, *infix_{""}, *suffix_{")"}; static const char *prefix() { return "("; }
static const char *infix() { return ","; }
static const char *suffix() { return ")"; }
private: private:
std::tuple<CopyableIndirection<Expr<OPERAND>>...> operand_; CopyableIndirection<OperandTuple> operand_;
}; };
// Unary operations
template<typename TO, typename FROM> template<typename TO, typename FROM>
struct Convert : public Operation<Convert<TO, FROM>, TO, FROM> { struct Convert : public Operation<Convert<TO, FROM>, TO, FROM> {
using Base = 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>; using Operand = typename Base::template Operand<0>;
static std::optional<Scalar<Result>> FoldScalar( static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Operand> &); FoldingContext &, const Scalar<Operand> &);
static constexpr const char *prefix_{"(-"}; static const char *prefix() { return "(-"; }
}; };
// TODO: re vs. im can be dynamic template<int KIND>
template<int KIND, bool realPart = true>
struct ComplexComponent struct ComplexComponent
: public Operation<ComplexComponent<KIND, realPart>, : public Operation<ComplexComponent<KIND>, Type<TypeCategory::Real, KIND>,
Type<TypeCategory::Real, KIND>, Type<TypeCategory::Complex, KIND>> { Type<TypeCategory::Complex, KIND>> {
using Base = Operation<ComplexComponent, Type<TypeCategory::Real, KIND>, using Base = Operation<ComplexComponent, Type<TypeCategory::Real, KIND>,
Type<TypeCategory::Complex, KIND>>; Type<TypeCategory::Complex, KIND>>;
static constexpr bool isRealPart{realPart};
using Base::Base;
using typename Base::Result; using typename Base::Result;
using Operand = typename Base::template Operand<0>; using Operand = typename Base::template Operand<0>;
static std::optional<Scalar<Result>> FoldScalar( CLASS_BOILERPLATE(ComplexComponent)
FoldingContext &, const Scalar<Operand> &); ComplexComponent(bool isReal, const Expr<Operand> &x)
static constexpr const char *prefix_{"(("}; : Base{x}, isRealPart{isReal} {}
static constexpr const char *suffix_{isRealPart ? ")%RE)" : ")%IM)"}; 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> template<int KIND>
@ -140,7 +143,19 @@ struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>,
using Operand = typename Base::template Operand<0>; using Operand = typename Base::template Operand<0>;
static std::optional<Scalar<Result>> FoldScalar( static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Operand> &); 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> template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A>
@ -179,11 +194,6 @@ public:
using FoldableTrait = std::true_type; using FoldableTrait = std::true_type;
template<typename CRTP> using Bin = Binary<CRTP, Result>; 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> { struct Subtract : public Bin<Subtract> {
using Bin<Subtract>::Bin; using Bin<Subtract>::Bin;
static std::optional<Scalar<Result>> FoldScalar( static std::optional<Scalar<Result>> FoldScalar(
@ -247,14 +257,15 @@ public:
// TODO: Also succeed when parenthesized constant // TODO: Also succeed when parenthesized constant
return common::GetIf<Scalar<Result>>(u_); return common::GetIf<Scalar<Result>>(u_);
} }
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO int Rank() const { return 1; } // TODO
private: private:
std::variant<Scalar<Result>, CopyableIndirection<DataRef>, std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Convert<Result, SomeInteger>, CopyableIndirection<FunctionRef>, Convert<Result, SomeInteger>,
Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>, Add, Convert<Result, SomeReal>, Parentheses<Result>, Negate<Result>,
Subtract, Multiply, Divide, Power, Max, Min> Add<Result>, Subtract, Multiply, Divide, Power, Max, Min>
u_; u_;
}; };
@ -268,11 +279,6 @@ public:
// Complex are done via decomposition to Real and reconstruction. // Complex are done via decomposition to Real and reconstruction.
template<typename CRTP> using Bin = Binary<CRTP, Result>; 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> { struct Subtract : public Bin<Subtract> {
using Bin<Subtract>::Bin; using Bin<Subtract>::Bin;
static std::optional<Scalar<Result>> FoldScalar( static std::optional<Scalar<Result>> FoldScalar(
@ -337,6 +343,7 @@ public:
// TODO: parenthesized constants too // TODO: parenthesized constants too
return common::GetIf<Scalar<Result>>(u_); return common::GetIf<Scalar<Result>>(u_);
} }
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO int Rank() const { return 1; } // TODO
@ -344,9 +351,8 @@ private:
std::variant<Scalar<Result>, CopyableIndirection<DataRef>, std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>, CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
Convert<Result, SomeInteger>, Convert<Result, SomeReal>, Convert<Result, SomeInteger>, Convert<Result, SomeReal>,
ComplexComponent<KIND, true>, ComplexComponent<KIND, false>, ComplexComponent<KIND>, Parentheses<Result>, Negate<Result>, Add<Result>,
Parentheses<Result>, Negate<Result>, Add, Subtract, Multiply, Divide, Subtract, Multiply, Divide, Power, IntPower, Max, Min>
Power, IntPower, Max, Min>
u_; u_;
}; };
@ -356,11 +362,6 @@ public:
using FoldableTrait = std::true_type; using FoldableTrait = std::true_type;
template<typename CRTP> using Bin = Binary<CRTP, Result>; 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> { struct Subtract : public Bin<Subtract> {
using Bin<Subtract>::Bin; using Bin<Subtract>::Bin;
static std::optional<Scalar<Result>> FoldScalar( static std::optional<Scalar<Result>> FoldScalar(
@ -405,13 +406,14 @@ public:
// TODO: parenthesized constants too // TODO: parenthesized constants too
return common::GetIf<Scalar<Result>>(u_); return common::GetIf<Scalar<Result>>(u_);
} }
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO int Rank() const { return 1; } // TODO
private: private:
std::variant<Scalar<Result>, CopyableIndirection<DataRef>, std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate<Result>, CopyableIndirection<FunctionRef>, Parentheses<Result>, Negate<Result>,
Add, Subtract, Multiply, Divide, Power, IntPower, CMPLX> Add<Result>, Subtract, Multiply, Divide, Power, IntPower, CMPLX>
u_; u_;
}; };
@ -464,6 +466,7 @@ public:
// TODO: parenthesized constants too // TODO: parenthesized constants too
return common::GetIf<Scalar<Result>>(u_); return common::GetIf<Scalar<Result>>(u_);
} }
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO int Rank() const { return 1; } // TODO
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
@ -479,21 +482,23 @@ private:
// The Comparison class template is a helper for constructing logical // The Comparison class template is a helper for constructing logical
// expressions with polymorphism over the cross product of the possible // expressions with polymorphism over the cross product of the possible
// categories and kinds of comparable operands. // categories and kinds of comparable operands.
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
template<typename A> template<typename A>
struct Comparison : public Binary<Comparison<A>, LogicalResult, A> { struct Comparison : public Operation<Comparison<A>, LogicalResult, A, A> {
using Result = LogicalResult; using Base = Operation<Comparison, LogicalResult, A, A>;
using Operand = A; using typename Base::Result;
using Base = Binary<Comparison, Result, Operand>; using Operand = typename Base::template Operand<0>;
CLASS_BOILERPLATE(Comparison) CLASS_BOILERPLATE(Comparison)
Comparison( Comparison(
RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b) RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b)
: Base{a, b}, opr{r} {} : Base{a, b}, opr{r} {}
Comparison(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b) Comparison(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b)
: Base{std::move(a), std::move(b)}, opr{r} {} : Base{std::move(a), std::move(b)}, opr{r} {}
std::optional<Scalar<Result>> FoldScalar( std::optional<Scalar<Result>> FoldScalar(
FoldingContext &c, const Scalar<Operand> &, const Scalar<Operand> &); FoldingContext &c, const Scalar<Operand> &, const Scalar<Operand> &);
std::string infix() const;
RelationalOperator opr; 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(const KindComparison<KIND> &x) : u{x} {}
template<int KIND> template<int KIND>
CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {} CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {}
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO int Rank() const { return 1; } // TODO
@ -555,6 +561,7 @@ public:
// TODO: parenthesized constants too // TODO: parenthesized constants too
return common::GetIf<Scalar<Result>>(u_); return common::GetIf<Scalar<Result>>(u_);
} }
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &c); std::optional<Scalar<Result>> Fold(FoldingContext &c);
int Rank() const { return 1; } // TODO 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(const KindExpr<KIND> &x) : u{x} {}
template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {} template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {}
std::optional<Scalar<Result>> ScalarValue() const; std::optional<Scalar<Result>> ScalarValue() const;
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &); std::optional<Scalar<Result>> Fold(FoldingContext &);
int Rank() const; int Rank() const;
@ -612,6 +620,7 @@ public:
Expr(Expr<Type<CAT, KIND>> &&x) : u{Expr<SomeKind<CAT>>{std::move(x)}} {} Expr(Expr<Type<CAT, KIND>> &&x) : u{Expr<SomeKind<CAT>>{std::move(x)}} {}
std::optional<Scalar<Result>> ScalarValue() const; std::optional<Scalar<Result>> ScalarValue() const;
std::ostream &Dump(std::ostream &) const;
std::optional<Scalar<Result>> Fold(FoldingContext &); std::optional<Scalar<Result>> Fold(FoldingContext &);
int Rank() const; 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; template<typename A> using ResultType = typename std::decay_t<A>::Result;
// Convenience functions and operator overloadings for expression construction. // 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> template<TypeCategory C, int K>
Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) { Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
return {Negate<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); [](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) { \ template<typename A> A FUNC(const A &x, const A &y) { \
return {typename A::CONSTR{x, 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)}}; \ return {typename A::CONSTR{std::move(x), std::move(y)}}; \
} }
BINARY(operator+, Add) OLDBINARY(operator-, Subtract)
BINARY(operator-, Subtract) OLDBINARY(operator*, Multiply)
BINARY(operator*, Multiply) OLDBINARY(operator/, Divide)
BINARY(operator/, Divide) OLDBINARY(Power, Power)
BINARY(Power, Power) #undef OLDBINARY
#undef BINARY
#define BINARY(FUNC, OP) \ #define BINARY(FUNC, OP) \
template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \ template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \

View File

@ -62,6 +62,7 @@ public:
DataRef &base() { return *base_; } DataRef &base() { return *base_; }
const Symbol &symbol() const { return *symbol_; } const Symbol &symbol() const { return *symbol_; }
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::ostream &Dump(std::ostream &) const;
private: private:
CopyableIndirection<DataRef> base_; CopyableIndirection<DataRef> base_;
@ -78,6 +79,7 @@ public:
std::optional<Expr<SubscriptInteger>> lower() const; std::optional<Expr<SubscriptInteger>> lower() const;
std::optional<Expr<SubscriptInteger>> upper() const; std::optional<Expr<SubscriptInteger>> upper() const;
std::optional<Expr<SubscriptInteger>> stride() const; std::optional<Expr<SubscriptInteger>> stride() const;
std::ostream &Dump(std::ostream &) const;
private: private:
std::optional<IndirectSubscriptIntegerExpr> lower_, upper_, stride_; std::optional<IndirectSubscriptIntegerExpr> lower_, upper_, stride_;
@ -93,6 +95,7 @@ public:
: u_{IndirectSubscriptIntegerExpr::Make(std::move(s))} {} : u_{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
explicit Subscript(const Triplet &t) : u_{t} {} explicit Subscript(const Triplet &t) : u_{t} {}
explicit Subscript(Triplet &&t) : u_{std::move(t)} {} explicit Subscript(Triplet &&t) : u_{std::move(t)} {}
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<IndirectSubscriptIntegerExpr, Triplet> u_; std::variant<IndirectSubscriptIntegerExpr, Triplet> u_;
@ -111,6 +114,7 @@ public:
ArrayRef(Component &&c, std::vector<Subscript> &&ss) ArrayRef(Component &&c, std::vector<Subscript> &&ss)
: u_{std::move(c)}, subscript_(std::move(ss)) {} : u_{std::move(c)}, subscript_(std::move(ss)) {}
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<const Symbol *, Component> u_; std::variant<const Symbol *, Component> u_;
@ -133,6 +137,7 @@ public:
CoarrayRef &setStat(Variable &&); CoarrayRef &setStat(Variable &&);
CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false); CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false);
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::ostream &Dump(std::ostream &) const;
private: private:
std::vector<const Symbol *> base_; std::vector<const Symbol *> base_;
@ -154,6 +159,7 @@ public:
explicit DataRef(ArrayRef &&a) : u_{std::move(a)} {} explicit DataRef(ArrayRef &&a) : u_{std::move(a)} {}
explicit DataRef(CoarrayRef &&a) : u_{std::move(a)} {} explicit DataRef(CoarrayRef &&a) : u_{std::move(a)} {}
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u_; std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u_;
@ -176,6 +182,7 @@ public:
Expr<SubscriptInteger> last() const; Expr<SubscriptInteger> last() const;
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::optional<std::string> Fold(FoldingContext &); std::optional<std::string> Fold(FoldingContext &);
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<DataRef, std::string> u_; std::variant<DataRef, std::string> u_;
@ -192,6 +199,7 @@ public:
ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {} ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {}
const DataRef &complex() const { return complex_; } const DataRef &complex() const { return complex_; }
Part part() const { return part_; } Part part() const { return part_; }
std::ostream &Dump(std::ostream &) const;
private: private:
DataRef complex_; DataRef complex_;
@ -206,6 +214,7 @@ public:
explicit Designator(DataRef &&d) : u_{std::move(d)} {} explicit Designator(DataRef &&d) : u_{std::move(d)} {}
explicit Designator(Substring &&s) : u_{std::move(s)} {} explicit Designator(Substring &&s) : u_{std::move(s)} {}
explicit Designator(ComplexPart &&c) : u_{std::move(c)} {} explicit Designator(ComplexPart &&c) : u_{std::move(c)} {}
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<DataRef, Substring, ComplexPart> u_; std::variant<DataRef, Substring, ComplexPart> u_;
@ -219,6 +228,7 @@ public:
explicit ProcedureDesignator(const Component &c) : u_{c} {} explicit ProcedureDesignator(const Component &c) : u_{c} {}
explicit ProcedureDesignator(Component &&c) : u_{std::move(c)} {} explicit ProcedureDesignator(Component &&c) : u_{std::move(c)} {}
Expr<SubscriptInteger> LEN() const; Expr<SubscriptInteger> LEN() const;
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<IntrinsicProcedure, const Symbol *, Component> u_; std::variant<IntrinsicProcedure, const Symbol *, Component> u_;
@ -232,6 +242,7 @@ public:
: proc_{std::move(p)}, argument_(std::move(a)) {} : proc_{std::move(p)}, argument_(std::move(a)) {}
const ProcedureDesignator &proc() const { return proc_; } const ProcedureDesignator &proc() const { return proc_; }
const std::vector<ArgumentType> &argument() const { return argument_; } const std::vector<ArgumentType> &argument() const { return argument_; }
std::ostream &Dump(std::ostream &) const;
private: private:
ProcedureDesignator proc_; ProcedureDesignator proc_;
@ -245,6 +256,7 @@ public:
CLASS_BOILERPLATE(Variable) CLASS_BOILERPLATE(Variable)
explicit Variable(Designator &&d) : u_{std::move(d)} {} explicit Variable(Designator &&d) : u_{std::move(d)} {}
explicit Variable(FunctionRef &&p) : u_{std::move(p)} {} explicit Variable(FunctionRef &&p) : u_{std::move(p)} {}
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<Designator, FunctionRef> u_; std::variant<Designator, FunctionRef> u_;
@ -255,6 +267,7 @@ public:
CLASS_BOILERPLATE(ActualFunctionArg) CLASS_BOILERPLATE(ActualFunctionArg)
explicit ActualFunctionArg(Expr<SomeType> &&x) : u_{std::move(x)} {} explicit ActualFunctionArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
explicit ActualFunctionArg(Variable &&x) : u_{std::move(x)} {} explicit ActualFunctionArg(Variable &&x) : u_{std::move(x)} {}
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<CopyableIndirection<Expr<SomeType>>, Variable> u_; std::variant<CopyableIndirection<Expr<SomeType>>, Variable> u_;
@ -264,6 +277,7 @@ struct Label { // TODO: this is a placeholder
CLASS_BOILERPLATE(Label) CLASS_BOILERPLATE(Label)
explicit Label(int lab) : label{lab} {} explicit Label(int lab) : label{lab} {}
int label; int label;
std::ostream &Dump(std::ostream &) const;
}; };
class ActualSubroutineArg { class ActualSubroutineArg {
@ -272,6 +286,7 @@ public:
explicit ActualSubroutineArg(Expr<SomeType> &&x) : u_{std::move(x)} {} explicit ActualSubroutineArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
explicit ActualSubroutineArg(Variable &&x) : u_{std::move(x)} {} explicit ActualSubroutineArg(Variable &&x) : u_{std::move(x)} {}
explicit ActualSubroutineArg(const Label &l) : u_{&l} {} explicit ActualSubroutineArg(const Label &l) : u_{&l} {}
std::ostream &Dump(std::ostream &) const;
private: private:
std::variant<CopyableIndirection<Expr<SomeType>>, Variable, const Label *> u_; 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() { int main() {
using DefaultIntegerExpr = Expr<DefaultInteger>; using DefaultIntegerExpr = Expr<DefaultInteger>;
TEST(DefaultIntegerExpr::Result::Dump() == "Integer(4)"); TEST(DefaultIntegerExpr::Result::Dump() == "Integer(4)");
MATCH("666", Dump(DefaultIntegerExpr{666})); MATCH("666_4", Dump(DefaultIntegerExpr{666}));
MATCH("(-1)", Dump(-DefaultIntegerExpr{1})); MATCH("(-1_4)", Dump(-DefaultIntegerExpr{1}));
auto ex1{ auto ex1{
DefaultIntegerExpr{2} + DefaultIntegerExpr{3} * -DefaultIntegerExpr{4}}; 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::CharBlock src;
Fortran::parser::ContextualMessages messages{src, nullptr}; Fortran::parser::ContextualMessages messages{src, nullptr};
FoldingContext context{messages}; FoldingContext context{messages};
ex1.Fold(context); ex1.Fold(context);
MATCH("-10", Dump(ex1)); MATCH("-10_4", Dump(ex1));
MATCH("(Integer(4)::6.LE.7)", MATCH("(6_4.LE.7_4)",
Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7})); Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
DefaultIntegerExpr a{1}; DefaultIntegerExpr a{1};
DefaultIntegerExpr b{2}; DefaultIntegerExpr b{2};
MATCH("(1/2)", Dump(a / b)); MATCH("(1_4/2_4)", Dump(a / b));
MATCH("1", Dump(a)); MATCH("1_4", Dump(a));
a = b; a = b;
MATCH("2", Dump(a)); MATCH("2_4", Dump(a));
MATCH("2", Dump(b)); MATCH("2_4", Dump(b));
return testing::Complete(); return testing::Complete();
} }