[flang] Refactoring and renaming

Original-commit: flang-compiler/f18@29fc0bee8a
Reviewed-on: https://github.com/flang-compiler/f18/pull/183
Tree-same-pre-rewrite: false
This commit is contained in:
peter klausler 2018-08-14 13:39:59 -07:00
parent 94540975f3
commit c75c9f0a54
12 changed files with 564 additions and 516 deletions

View File

@ -25,8 +25,10 @@ namespace Fortran::evaluate {
// An expression of some specific result type.
template<typename A> class Expr;
// TODO: pmk: obsolete?
template<int KIND> using IntegerExpr = Expr<Type<TypeCategory::Integer, KIND>>;
using DefaultIntegerExpr = IntegerExpr<DefaultInteger::kind>;
using DefaultIntegerExpr = Expr<DefaultInteger>;
template<int KIND> using RealExpr = Expr<Type<TypeCategory::Real, KIND>>;
template<int KIND> using ComplexExpr = Expr<Type<TypeCategory::Complex, KIND>>;
template<int KIND>
@ -41,8 +43,5 @@ using SomeKindComplexExpr = Expr<SomeKind<TypeCategory::Complex>>;
using SomeKindCharacterExpr = Expr<SomeKind<TypeCategory::Character>>;
using SomeKindLogicalExpr = Expr<SomeKind<TypeCategory::Logical>>;
// A completely generic expression of any category and kind.
struct GenericExpr;
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_EXPRESSION_FORWARD_H_

View File

@ -59,7 +59,7 @@ std::ostream &CategoryComparison<CAT>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
std::ostream &GenericExpr::Dump(std::ostream &o) const {
std::ostream &Expr<SomeType>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
@ -77,7 +77,57 @@ std::ostream &Binary<CRTP, RESULT, A, B>::Dump(
template<int KIND>
std::ostream &IntegerExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar &n) { o << n.SignedDecimal(); },
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 Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &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 Max &m) { m.Dump(o, ",", "MAX("); },
[&](const Min &m) { m.Dump(o, ",", "MIN("); },
[&](const auto &convert) {
DumpExprWithType(o, convert.operand().u);
}},
u_);
return o;
}
template<int KIND> std::ostream &RealExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &n) {
o << n.DumpHexadecimal();
},
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &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 RealPart &z) { z.Dump(o, "REAL("); },
[&](const AIMAG &p) { p.Dump(o, "AIMAG("); },
[&](const auto &convert) {
DumpExprWithType(o, convert.operand().u);
}},
u_);
return o;
}
template<int KIND>
std::ostream &ComplexExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &n) {
o << n.DumpHexadecimal();
},
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
@ -87,62 +137,15 @@ std::ostream &IntegerExpr<KIND>::Dump(std::ostream &o) const {
[&](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 &convert) {
DumpExprWithType(o, convert.operand().u);
}},
u_);
return o;
}
template<int KIND> std::ostream &RealExpr<KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Scalar &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<ComplexPart> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &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 RealPart &z) { z.Dump(o, "REAL("); },
[&](const AIMAG &p) { p.Dump(o, "AIMAG("); },
[&](const auto &convert) {
DumpExprWithType(o, convert.operand().u);
}},
u_);
return o;
}
template<int KIND>
std::ostream &ComplexExpr<KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Scalar &n) { o << n.DumpHexadecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
[&](const CopyableIndirection<FunctionRef> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &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 CMPLX &c) { c.Dump(o, ","); }},
[&](const IntPower &p) { p.Dump(o, "**"); },
[&](const CMPLX &c) { c.Dump(o, ","); }},
u_);
return o;
}
template<int KIND>
std::ostream &CharacterExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar &s) {
std::visit(common::visitors{[&](const Scalar<Result> &s) {
o << parser::QuoteCharacterLiteral(s);
},
[&](const Concat &concat) { concat.Dump(o, "//"); },
@ -162,7 +165,7 @@ template<typename A> std::ostream &Comparison<A>::Dump(std::ostream &o) const {
template<int KIND>
std::ostream &LogicalExpr<KIND>::Dump(std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar &tf) {
std::visit(common::visitors{[&](const Scalar<Result> &tf) {
o << (tf.IsTrue() ? ".TRUE." : ".FALSE.");
},
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
@ -178,22 +181,22 @@ std::ostream &LogicalExpr<KIND>::Dump(std::ostream &o) const {
}
// LEN()
template<int KIND> SubscriptIntegerExpr CharacterExpr<KIND>::LEN() const {
template<int KIND> Expr<SubscriptInteger> CharacterExpr<KIND>::LEN() const {
return std::visit(
common::visitors{[](const Scalar &c) {
common::visitors{[](const Scalar<Result> &c) {
// std::string::size_type isn't convertible to uint64_t
// on Darwin
return SubscriptIntegerExpr{
return Expr<SubscriptInteger>{
static_cast<std::uint64_t>(c.size())};
},
[](const Concat &c) { return c.left().LEN() + c.right().LEN(); },
[](const Max &c) {
return SubscriptIntegerExpr{
SubscriptIntegerExpr::Max{c.left().LEN(), c.right().LEN()}};
return Expr<SubscriptInteger>{
Expr<SubscriptInteger>::Max{c.left().LEN(), c.right().LEN()}};
},
[](const Min &c) {
return SubscriptIntegerExpr{
SubscriptIntegerExpr::Max{c.left().LEN(), c.right().LEN()}};
return Expr<SubscriptInteger>{
Expr<SubscriptInteger>::Max{c.left().LEN(), c.right().LEN()}};
},
[](const CopyableIndirection<DataRef> &dr) { return dr->LEN(); },
[](const CopyableIndirection<Substring> &ss) { return ss->LEN(); },
@ -216,8 +219,8 @@ int Binary<CRTP, RESULT, A, B>::Rank() const {
// Folding
template<typename CRTP, typename RESULT, typename A>
auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
if (std::optional<OperandScalarConstant> c{operand_->Fold(context)}) {
-> std::optional<Scalar<Result>> {
if (std::optional<Scalar<Operand>> c{operand_->Fold(context)}) {
return static_cast<CRTP *>(this)->FoldScalar(context, *c);
}
return std::nullopt;
@ -225,9 +228,9 @@ auto Unary<CRTP, RESULT, A>::Fold(FoldingContext &context)
template<typename CRTP, typename RESULT, typename A, typename B>
auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
std::optional<LeftScalar> lc{left_->Fold(context)};
std::optional<RightScalar> rc{right_->Fold(context)};
-> std::optional<Scalar<Result>> {
std::optional<Scalar<Left>> lc{left_->Fold(context)};
std::optional<Scalar<Right>> rc{right_->Fold(context)};
if (lc.has_value() && rc.has_value()) {
return static_cast<CRTP *>(this)->FoldScalar(context, *lc, *rc);
}
@ -235,11 +238,12 @@ auto Binary<CRTP, RESULT, A, B>::Fold(FoldingContext &context)
}
template<int KIND>
auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
const SomeKindScalar<TypeCategory::Integer> &c) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::ConvertSigned(x)};
[&](auto &x) -> std::optional<Scalar<Result>> {
auto converted{Scalar<Result>::ConvertSigned(x)};
if (converted.overflow) {
context.messages.Say("integer conversion overflowed"_en_US);
return std::nullopt;
@ -250,11 +254,12 @@ auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
const SomeKindScalar<TypeCategory::Real> &c) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::ConvertReal::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{x.template ToInteger<Scalar>()};
[&](auto &x) -> std::optional<Scalar<Result>> {
auto converted{x.template ToInteger<Scalar<Result>>()};
if (converted.flags.test(RealFlag::Overflow)) {
context.messages.Say("real->integer conversion overflowed"_en_US);
return std::nullopt;
@ -270,8 +275,8 @@ auto IntegerExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Negate::FoldScalar(
FoldingContext &context, const Scalar &c) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
auto negated{c.Negate()};
if (negated.overflow) {
context.messages.Say("integer negation overflowed"_en_US);
@ -281,8 +286,9 @@ auto IntegerExpr<KIND>::Negate::FoldScalar(
}
template<int KIND>
auto IntegerExpr<KIND>::Add::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<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);
@ -292,8 +298,9 @@ auto IntegerExpr<KIND>::Add::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto diff{a.SubtractSigned(b)};
if (diff.overflow) {
context.messages.Say("integer subtraction overflowed"_en_US);
@ -303,8 +310,9 @@ auto IntegerExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.MultiplySigned(b)};
if (product.SignedMultiplicationOverflowed()) {
context.messages.Say("integer multiplication overflowed"_en_US);
@ -314,8 +322,9 @@ auto IntegerExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto qr{a.DivideSigned(b)};
if (qr.divisionByZero) {
context.messages.Say("integer division by zero"_en_US);
@ -329,9 +338,10 @@ auto IntegerExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Power::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
typename Scalar::PowerWithErrors power{a.Power(b)};
auto IntegerExpr<KIND>::Power::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
typename Scalar<Result>::PowerWithErrors power{a.Power(b)};
if (power.divisionByZero) {
context.messages.Say("zero to negative power"_en_US);
return std::nullopt;
@ -348,8 +358,9 @@ auto IntegerExpr<KIND>::Power::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Max::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Max::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (a.CompareSigned(b) == Ordering::Greater) {
return {a};
}
@ -357,8 +368,9 @@ auto IntegerExpr<KIND>::Max::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Min::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Min::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (a.CompareSigned(b) == Ordering::Less) {
return {a};
}
@ -366,11 +378,12 @@ auto IntegerExpr<KIND>::Min::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
auto IntegerExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
@ -386,11 +399,12 @@ auto IntegerExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
}
template<int KIND>
auto RealExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
const SomeKindScalar<TypeCategory::Integer> &c) -> std::optional<Scalar> {
auto RealExpr<KIND>::ConvertInteger::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::FromInteger(x)};
[&](auto &x) -> std::optional<Scalar<Result>> {
auto converted{Scalar<Result>::FromInteger(x)};
RealFlagWarnings(context, converted.flags, "integer->real conversion");
return {std::move(converted.value)};
},
@ -398,11 +412,12 @@ auto RealExpr<KIND>::ConvertInteger::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto RealExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
const SomeKindScalar<TypeCategory::Real> &c) -> std::optional<Scalar> {
auto RealExpr<KIND>::ConvertReal::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
auto converted{Scalar::Convert(x)};
[&](auto &x) -> std::optional<Scalar<Result>> {
auto converted{Scalar<Result>::Convert(x)};
RealFlagWarnings(context, converted.flags, "real conversion");
return {std::move(converted.value)};
},
@ -410,55 +425,60 @@ auto RealExpr<KIND>::ConvertReal::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto RealExpr<KIND>::Negate::FoldScalar(
FoldingContext &context, const Scalar &c) -> std::optional<Scalar> {
auto RealExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
return {c.Negate()};
}
template<int KIND>
auto RealExpr<KIND>::Add::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<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 RealExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto difference{a.Subtract(b, context.rounding)};
RealFlagWarnings(context, difference.flags, "real subtraction");
return {std::move(difference.value)};
}
template<int KIND>
auto RealExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.Multiply(b, context.rounding)};
RealFlagWarnings(context, product.flags, "real multiplication");
return {std::move(product.value)};
}
template<int KIND>
auto RealExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto quotient{a.Divide(b, context.rounding)};
RealFlagWarnings(context, quotient.flags, "real division");
return {std::move(quotient.value)};
}
template<int KIND>
auto RealExpr<KIND>::Power::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Power::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return std::nullopt; // TODO
}
template<int KIND>
auto RealExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
const Scalar &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
const Scalar<Result> &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
[&](const auto &pow) -> std::optional<Scalar<Result>> {
auto power{evaluate::IntPower(a, pow)};
RealFlagWarnings(context, power.flags, "raising to integer power");
return {std::move(power.value)};
@ -467,8 +487,9 @@ auto RealExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto RealExpr<KIND>::Max::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Max::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (b.IsNotANumber() || a.Compare(b) == Relation::Less) {
return {b};
}
@ -476,8 +497,9 @@ auto RealExpr<KIND>::Max::FoldScalar(FoldingContext &context, const Scalar &a,
}
template<int KIND>
auto RealExpr<KIND>::Min::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
auto RealExpr<KIND>::Min::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (b.IsNotANumber() || a.Compare(b) == Relation::Greater) {
return {b};
}
@ -486,22 +508,25 @@ auto RealExpr<KIND>::Min::FoldScalar(FoldingContext &context, const Scalar &a,
template<int KIND>
auto RealExpr<KIND>::RealPart::FoldScalar(FoldingContext &context,
const evaluate::Scalar<Complex> &z) -> std::optional<Scalar> {
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
-> std::optional<Scalar<Result>> {
return {z.REAL()};
}
template<int KIND>
auto RealExpr<KIND>::AIMAG::FoldScalar(FoldingContext &context,
const evaluate::Scalar<Complex> &z) -> std::optional<Scalar> {
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
-> std::optional<Scalar<Result>> {
return {z.AIMAG()};
}
template<int KIND>
auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
auto RealExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
@ -520,55 +545,60 @@ auto RealExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
}
template<int KIND>
auto ComplexExpr<KIND>::Negate::FoldScalar(
FoldingContext &context, const Scalar &c) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
return {c.Negate()};
}
template<int KIND>
auto ComplexExpr<KIND>::Add::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto ComplexExpr<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 ComplexExpr<KIND>::Subtract::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto difference{a.Subtract(b, context.rounding)};
RealFlagWarnings(context, difference.flags, "complex subtraction");
return {std::move(difference.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Multiply::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.Multiply(b, context.rounding)};
RealFlagWarnings(context, product.flags, "complex multiplication");
return {std::move(product.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Divide::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto quotient{a.Divide(b, context.rounding)};
RealFlagWarnings(context, quotient.flags, "complex division");
return {std::move(quotient.value)};
}
template<int KIND>
auto ComplexExpr<KIND>::Power::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Power::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return std::nullopt; // TODO
}
template<int KIND>
auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
const Scalar &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar> {
const Scalar<Result> &a, const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar> {
[&](const auto &pow) -> std::optional<Scalar<Result>> {
auto power{evaluate::IntPower(a, pow)};
RealFlagWarnings(context, power.flags, "raising to integer power");
return {std::move(power.value)};
@ -578,17 +608,19 @@ auto ComplexExpr<KIND>::IntPower::FoldScalar(FoldingContext &context,
template<int KIND>
auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
const evaluate::Scalar<Part> &a, const evaluate::Scalar<Part> &b)
-> std::optional<Scalar> {
return {Scalar{a, b}};
const Scalar<SameKind<TypeCategory::Real, Result>> &a,
const Scalar<SameKind<TypeCategory::Real, Result>> &b)
-> std::optional<Scalar<Result>> {
return {Scalar<Result>{a, b}};
}
template<int KIND>
auto ComplexExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
auto ComplexExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
@ -607,8 +639,9 @@ auto ComplexExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
}
template<int KIND>
auto CharacterExpr<KIND>::Concat::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto CharacterExpr<KIND>::Concat::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if constexpr (KIND == 1) {
return {a + b};
}
@ -616,8 +649,9 @@ auto CharacterExpr<KIND>::Concat::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto CharacterExpr<KIND>::Max::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto CharacterExpr<KIND>::Max::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (Compare(a, b) == Ordering::Less) {
return {b};
}
@ -625,8 +659,9 @@ auto CharacterExpr<KIND>::Max::FoldScalar(FoldingContext &context,
}
template<int KIND>
auto CharacterExpr<KIND>::Min::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
auto CharacterExpr<KIND>::Min::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (Compare(a, b) == Ordering::Greater) {
return {b};
}
@ -635,11 +670,11 @@ auto CharacterExpr<KIND>::Min::FoldScalar(FoldingContext &context,
template<int KIND>
auto CharacterExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
@ -655,9 +690,8 @@ auto CharacterExpr<KIND>::Fold(FoldingContext &context)
}
template<typename A>
auto Comparison<A>::FoldScalar(FoldingContext &c,
const OperandScalarConstant &a, const OperandScalarConstant &b)
-> std::optional<Scalar> {
auto Comparison<A>::FoldScalar(FoldingContext &c, const Scalar<Operand> &a,
const Scalar<Operand> &b) -> std::optional<Scalar<Result>> {
if constexpr (A::category == TypeCategory::Integer) {
switch (a.CompareSigned(b)) {
case Ordering::Less:
@ -707,45 +741,50 @@ auto Comparison<A>::FoldScalar(FoldingContext &c,
}
template<int KIND>
auto LogicalExpr<KIND>::Not::FoldScalar(
FoldingContext &context, const Scalar &x) -> std::optional<Scalar> {
return {Scalar{!x.IsTrue()}};
auto LogicalExpr<KIND>::Not::FoldScalar(FoldingContext &context,
const Scalar<Result> &x) -> std::optional<Scalar<Result>> {
return {Scalar<Result>{!x.IsTrue()}};
}
template<int KIND>
auto LogicalExpr<KIND>::And::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
return {Scalar{a.IsTrue() && b.IsTrue()}};
auto LogicalExpr<KIND>::And::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return {Scalar<Result>{a.IsTrue() && b.IsTrue()}};
}
template<int KIND>
auto LogicalExpr<KIND>::Or::FoldScalar(FoldingContext &context, const Scalar &a,
const Scalar &b) -> std::optional<Scalar> {
return {Scalar{a.IsTrue() || b.IsTrue()}};
auto LogicalExpr<KIND>::Or::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return {Scalar<Result>{a.IsTrue() || b.IsTrue()}};
}
template<int KIND>
auto LogicalExpr<KIND>::Eqv::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
return {Scalar{a.IsTrue() == b.IsTrue()}};
auto LogicalExpr<KIND>::Eqv::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return {Scalar<Result>{a.IsTrue() == b.IsTrue()}};
}
template<int KIND>
auto LogicalExpr<KIND>::Neqv::FoldScalar(FoldingContext &context,
const Scalar &a, const Scalar &b) -> std::optional<Scalar> {
return {Scalar{a.IsTrue() != b.IsTrue()}};
auto LogicalExpr<KIND>::Neqv::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
return {Scalar<Result>{a.IsTrue() != b.IsTrue()}};
}
template<int KIND>
auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
auto LogicalExpr<KIND>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
using Ty = std::decay_t<decltype(x)>;
if constexpr (std::is_same_v<Ty, Scalar>) {
if constexpr (std::is_same_v<Ty, Scalar<Result>>) {
return {x};
}
if constexpr (evaluate::FoldableTrait<Ty>) {
std::optional<Scalar> c{x.Fold(context)};
std::optional<Scalar<Result>> c{x.Fold(context)};
if (c.has_value()) {
u_ = *c;
return c;
@ -756,15 +795,15 @@ auto LogicalExpr<KIND>::Fold(FoldingContext &context) -> std::optional<Scalar> {
u_);
}
std::optional<GenericScalar> GenericExpr::ScalarValue() const {
auto Expr<SomeType>::ScalarValue() const -> std::optional<Scalar<Result>> {
return std::visit(
common::visitors{
[](const BOZLiteralConstant &) -> std::optional<GenericScalar> {
[](const BOZLiteralConstant &) -> std::optional<Scalar<Result>> {
return std::nullopt;
},
[](const auto &x) -> std::optional<GenericScalar> {
[](const auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.ScalarValue()}) {
return {GenericScalar{std::move(*c)}};
return {Scalar<Result>{std::move(*c)}};
}
return std::nullopt;
}},
@ -772,11 +811,11 @@ std::optional<GenericScalar> GenericExpr::ScalarValue() const {
}
template<TypeCategory CAT>
auto Expr<SomeKind<CAT>>::ScalarValue() const -> std::optional<Scalar> {
auto Expr<SomeKind<CAT>>::ScalarValue() const -> std::optional<Scalar<Result>> {
return std::visit(
[](const auto &x) -> std::optional<Scalar> {
[](const auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.ScalarValue()}) {
return {Scalar{std::move(*c)}};
return {Scalar<Result>{std::move(*c)}};
}
return std::nullopt;
},
@ -785,32 +824,34 @@ auto Expr<SomeKind<CAT>>::ScalarValue() const -> std::optional<Scalar> {
template<TypeCategory CAT>
auto Expr<SomeKind<CAT>>::Fold(FoldingContext &context)
-> std::optional<Scalar> {
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.Fold(context)}) {
return {Scalar{std::move(*c)}};
return {Scalar<Result>{std::move(*c)}};
}
return std::nullopt;
},
u);
}
std::optional<GenericScalar> GenericExpr::Fold(FoldingContext &context) {
auto Expr<SomeType>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
common::visitors{
[](BOZLiteralConstant &) -> std::optional<GenericScalar> {
[](BOZLiteralConstant &) -> std::optional<Scalar<Result>> {
return std::nullopt;
},
[&](auto &x) -> std::optional<GenericScalar> {
[&](auto &x) -> std::optional<Scalar<Result>> {
if (auto c{x.Fold(context)}) {
return {GenericScalar{std::move(*c)}};
return {Scalar<Result>{std::move(*c)}};
}
return std::nullopt;
}},
u);
}
template class Expr<SomeType>;
template class Expr<SomeKind<TypeCategory::Integer>>;
template class Expr<SomeKind<TypeCategory::Real>>;
template class Expr<SomeKind<TypeCategory::Complex>>;

View File

@ -35,60 +35,49 @@ namespace Fortran::evaluate {
// Helper base classes for packaging subexpressions.
template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
protected:
using OperandType = A;
using Operand = Expr<OperandType>;
using OperandScalarConstant = Scalar<OperandType>;
public:
using Result = RESULT;
using Scalar = Scalar<Result>;
using Operand = A;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Unary)
Unary(const Operand &a) : operand_{a} {}
Unary(Operand &&a) : operand_{std::move(a)} {}
Unary(CopyableIndirection<Operand> &&a) : operand_{std::move(a)} {}
const Operand &operand() const { return *operand_; }
Operand &operand() { return *operand_; }
Unary(const Expr<Operand> &a) : operand_{a} {}
Unary(Expr<Operand> &&a) : operand_{std::move(a)} {}
Unary(CopyableIndirection<Expr<Operand>> &&a) : operand_{std::move(a)} {}
const Expr<Operand> &operand() const { return *operand_; }
Expr<Operand> &operand() { return *operand_; }
std::ostream &Dump(std::ostream &, const char *opr) const;
int Rank() const { return operand_.Rank(); }
std::optional<Scalar> Fold(FoldingContext &); // TODO: array result
std::optional<Scalar<Result>> Fold(FoldingContext &); // TODO: array result
private:
CopyableIndirection<Operand> operand_;
CopyableIndirection<Expr<Operand>> operand_;
};
template<typename CRTP, typename RESULT, typename A = RESULT, typename B = A>
class Binary {
protected:
using LeftType = A;
using Left = Expr<LeftType>;
using LeftScalar = Scalar<LeftType>;
using RightType = B;
using Right = Expr<RightType>;
using RightScalar = Scalar<RightType>;
public:
using Result = RESULT;
using Scalar = Scalar<Result>;
using Left = A;
using Right = B;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Binary)
Binary(const Left &a, const Right &b) : left_{a}, right_{b} {}
Binary(Left &&a, Right &&b) : left_{std::move(a)}, right_{std::move(b)} {}
Binary(
CopyableIndirection<const Left> &&a, CopyableIndirection<const Right> &&b)
Binary(const Expr<Left> &a, const Expr<Right> &b) : left_{a}, right_{b} {}
Binary(Expr<Left> &&a, Expr<Right> &&b)
: left_{std::move(a)}, right_{std::move(b)} {}
const Left &left() const { return *left_; }
Left &left() { return *left_; }
const Right &right() const { return *right_; }
Right &right() { return *right_; }
Binary(CopyableIndirection<const Expr<Left>> &&a,
CopyableIndirection<const Expr<Right>> &&b)
: left_{std::move(a)}, right_{std::move(b)} {}
const Expr<Left> &left() const { return *left_; }
Expr<Left> &left() { return *left_; }
const Expr<Right> &right() const { return *right_; }
Expr<Right> &right() { return *right_; }
std::ostream &Dump(
std::ostream &, const char *opr, const char *before = "(") const;
int Rank() const;
std::optional<Scalar> Fold(FoldingContext &);
std::optional<Scalar<Result>> Fold(FoldingContext &);
private:
CopyableIndirection<Left> left_;
CopyableIndirection<Right> right_;
CopyableIndirection<Expr<Left>> left_;
CopyableIndirection<Expr<Right>> right_;
};
// Per-category expressions
@ -96,20 +85,19 @@ private:
template<int KIND> class Expr<Type<TypeCategory::Integer, KIND>> {
public:
using Result = Type<TypeCategory::Integer, KIND>;
using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
struct ConvertInteger
: public Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>> {
using Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
};
@ -117,56 +105,58 @@ public:
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Parentheses : public Un<Parentheses> {
using Un<Parentheses>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &x) {
return {x};
}
};
struct Negate : public Un<Negate> {
using Un<Negate>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &);
};
struct Add : public Bin<Add> {
using Bin<Add>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
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> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Multiply : public Bin<Multiply> {
using Bin<Multiply>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Divide : public Bin<Divide> {
using Bin<Divide>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Power : public Bin<Power> {
using Bin<Power>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Max : public Bin<Max> {
using Bin<Max>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Min : public Bin<Min> {
using Bin<Min>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
// TODO: R916 type-param-inquiry
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(std::int64_t n) : u_{Scalar{n}} {}
Expr(std::uint64_t n) : u_{Scalar{n}} {}
Expr(int n) : u_{Scalar{n}} {}
Expr(const Scalar<Result> &x) : u_{x} {}
Expr(std::int64_t n) : u_{Scalar<Result>{n}} {}
Expr(std::uint64_t n) : u_{Scalar<Result>{n}} {}
Expr(int n) : u_{Scalar<Result>{n}} {}
Expr(const SomeKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
Expr(SomeKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
template<int K>
@ -188,13 +178,13 @@ public:
: u_(std::move(x)) {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
std::optional<Scalar<Result>> ScalarValue() const {
return common::GetIf<Scalar<Result>>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
std::optional<Scalar<Result>> Fold(FoldingContext &c);
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, ConvertInteger, ConvertReal,
Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, Max, Min>
u_;
@ -203,9 +193,7 @@ private:
template<int KIND> class Expr<Type<TypeCategory::Real, KIND>> {
public:
using Result = Type<TypeCategory::Real, KIND>;
using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
using Complex = typename Result::Complex;
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
// and part access operations (resp.). Conversions between kinds of
@ -213,83 +201,87 @@ public:
struct ConvertInteger
: public Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>> {
using Unary<ConvertInteger, Result, SomeKind<TypeCategory::Integer>>::Unary;
static std::optional<Scalar> FoldScalar(
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct ConvertReal
: public Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>> {
using Unary<ConvertReal, Result, SomeKind<TypeCategory::Real>>::Unary;
static std::optional<Scalar> FoldScalar(
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const SomeKindScalar<TypeCategory::Real> &);
};
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Parentheses : public Un<Parentheses> {
using Un<Parentheses>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &x) {
return {x};
}
};
struct Negate : public Un<Negate> {
using Un<Negate>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &);
};
struct Add : public Bin<Add> {
using Bin<Add>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
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> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Multiply : public Bin<Multiply> {
using Bin<Multiply>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Divide : public Bin<Divide> {
using Bin<Divide>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Power : public Bin<Power> {
using Bin<Power>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct IntPower
: public Binary<IntPower, Result, Result, SomeKind<TypeCategory::Integer>> {
using Binary<IntPower, Result, Result,
SomeKind<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
const SomeKindScalar<TypeCategory::Integer> &);
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
const Scalar<Result> &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct Max : public Bin<Max> {
using Bin<Max>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Min : public Bin<Min> {
using Bin<Min>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
template<typename CRTP> using ComplexUn = Unary<CRTP, Result, Complex>;
template<typename CRTP>
using ComplexUn =
Unary<CRTP, Result, SameKind<TypeCategory::Complex, Result>>;
struct RealPart : public ComplexUn<RealPart> {
using ComplexUn<RealPart>::ComplexUn;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const evaluate::Scalar<Complex> &);
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
const Scalar<SameKind<TypeCategory::Complex, Result>> &);
};
struct AIMAG : public ComplexUn<AIMAG> {
using ComplexUn<AIMAG>::ComplexUn;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const evaluate::Scalar<Complex> &);
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
const Scalar<SameKind<TypeCategory::Complex, Result>> &);
};
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(const Scalar<Result> &x) : u_{x} {}
Expr(const SomeKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
Expr(SomeKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
template<int K>
@ -308,13 +300,13 @@ public:
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
std::optional<Scalar<Result>> ScalarValue() const {
return common::GetIf<Scalar<Result>>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
std::optional<Scalar<Result>> Fold(FoldingContext &c);
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<ComplexPart>, CopyableIndirection<FunctionRef>,
ConvertInteger, ConvertReal, Parentheses, Negate, Add, Subtract, Multiply,
Divide, Power, IntPower, Max, Min, RealPart, AIMAG>
@ -324,74 +316,76 @@ private:
template<int KIND> class Expr<Type<TypeCategory::Complex, KIND>> {
public:
using Result = Type<TypeCategory::Complex, KIND>;
using Scalar = Scalar<Result>;
using Part = typename Result::Part;
using FoldableTrait = std::true_type;
template<typename CRTP> using Un = Unary<CRTP, Result>;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Parentheses : public Un<Parentheses> {
using Un<Parentheses>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &x) {
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &x) {
return {x};
}
};
struct Negate : public Un<Negate> {
using Un<Negate>::Un;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &);
};
struct Add : public Bin<Add> {
using Bin<Add>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
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> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Multiply : public Bin<Multiply> {
using Bin<Multiply>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Divide : public Bin<Divide> {
using Bin<Divide>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Power : public Bin<Power> {
using Bin<Power>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct IntPower
: public Binary<IntPower, Result, Result, SomeKind<TypeCategory::Integer>> {
using Binary<IntPower, Result, Result,
SomeKind<TypeCategory::Integer>>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &,
const SomeKindScalar<TypeCategory::Integer> &);
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
const Scalar<Result> &, const SomeKindScalar<TypeCategory::Integer> &);
};
struct CMPLX : public Binary<CMPLX, Result, Part> {
using Binary<CMPLX, Result, Part>::Binary;
static std::optional<Scalar> FoldScalar(FoldingContext &,
const evaluate::Scalar<Part> &, const evaluate::Scalar<Part> &);
struct CMPLX
: public Binary<CMPLX, Result, SameKind<TypeCategory::Real, Result>> {
using Binary<CMPLX, Result, SameKind<TypeCategory::Real, Result>>::Binary;
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
const Scalar<SameKind<TypeCategory::Real, Result>> &,
const Scalar<SameKind<TypeCategory::Real, Result>> &);
};
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(const Scalar<Result> &x) : u_{x} {}
template<typename A> Expr(const A &x) : u_{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
std::optional<Scalar<Result>> ScalarValue() const {
return common::GetIf<Scalar<Result>>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
std::optional<Scalar<Result>> Fold(FoldingContext &c);
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Parentheses, Negate, Add, Subtract,
Multiply, Divide, Power, IntPower, CMPLX>
u_;
@ -400,41 +394,40 @@ private:
template<int KIND> class Expr<Type<TypeCategory::Character, KIND>> {
public:
using Result = Type<TypeCategory::Character, KIND>;
using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct Concat : public Bin<Concat> {
using Bin<Concat>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Max : public Bin<Max> {
using Bin<Max>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Min : public Bin<Min> {
using Bin<Min>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(Scalar &&x) : u_{std::move(x)} {}
Expr(const Scalar<Result> &x) : u_{x} {}
Expr(Scalar<Result> &&x) : u_{std::move(x)} {}
template<typename A> Expr(const A &x) : u_{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
std::optional<Scalar<Result>> ScalarValue() const {
return common::GetIf<Scalar<Result>>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
SubscriptIntegerExpr LEN() const;
std::optional<Scalar<Result>> Fold(FoldingContext &c);
Expr<SubscriptInteger> LEN() const;
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<Substring>, CopyableIndirection<FunctionRef>, Concat,
Max, Min>
u_;
@ -448,16 +441,17 @@ ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
template<typename A>
struct Comparison
: public Binary<Comparison<A>, Type<TypeCategory::Logical, 1>, A> {
using Base = Binary<Comparison, Type<TypeCategory::Logical, 1>, A>;
using typename Base::Scalar;
using OperandScalarConstant = typename Base::LeftScalar;
using Result = Type<TypeCategory::Logical, 1>;
using Operand = A;
using Base = Binary<Comparison, Result, Operand>;
CLASS_BOILERPLATE(Comparison)
Comparison(RelationalOperator r, const Expr<A> &a, const Expr<A> &b)
Comparison(
RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b)
: Base{a, b}, opr{r} {}
Comparison(RelationalOperator r, Expr<A> &&a, Expr<A> &&b)
Comparison(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b)
: Base{std::move(a), std::move(b)}, opr{r} {}
std::optional<Scalar> FoldScalar(FoldingContext &c,
const OperandScalarConstant &, const OperandScalarConstant &);
std::optional<Scalar<Result>> FoldScalar(
FoldingContext &c, const Scalar<Operand> &, const Scalar<Operand> &);
RelationalOperator opr;
};
@ -481,50 +475,50 @@ extern template struct Comparison<Type<TypeCategory::Character, 1>>;
// Dynamically polymorphic comparisons whose operands are expressions of
// the same supported kind of a particular type category.
template<TypeCategory CAT> struct CategoryComparison {
using Scalar = Scalar<Type<TypeCategory::Logical, 1>>;
using Result = Type<TypeCategory::Logical, 1>;
CLASS_BOILERPLATE(CategoryComparison)
template<int KIND> using KindComparison = Comparison<Type<CAT, KIND>>;
template<int KIND> CategoryComparison(const KindComparison<KIND> &x) : u{x} {}
template<int KIND>
CategoryComparison(KindComparison<KIND> &&x) : u{std::move(x)} {}
std::optional<Scalar> Fold(FoldingContext &c);
std::optional<Scalar<Result>> Fold(FoldingContext &c);
typename KindsVariant<CAT, KindComparison>::type u;
};
template<int KIND> class Expr<Type<TypeCategory::Logical, KIND>> {
public:
using Result = Type<TypeCategory::Logical, KIND>;
using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
struct Not : Unary<Not, Result> {
using Unary<Not, Result>::Unary;
static std::optional<Scalar> FoldScalar(FoldingContext &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &);
};
template<typename CRTP> using Bin = Binary<CRTP, Result>;
struct And : public Bin<And> {
using Bin<And>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Or : public Bin<Or> {
using Bin<Or>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Eqv : public Bin<Eqv> {
using Bin<Eqv>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
struct Neqv : public Bin<Neqv> {
using Bin<Neqv>::Bin;
static std::optional<Scalar> FoldScalar(
FoldingContext &, const Scalar &, const Scalar &);
static std::optional<Scalar<Result>> FoldScalar(
FoldingContext &, const Scalar<Result> &, const Scalar<Result> &);
};
CLASS_BOILERPLATE(Expr)
Expr(const Scalar &x) : u_{x} {}
Expr(bool x) : u_{Scalar{x}} {}
Expr(const Scalar<Result> &x) : u_{x} {}
Expr(bool x) : u_{Scalar<Result>{x}} {}
template<TypeCategory CAT, int K>
Expr(const Comparison<Type<CAT, K>> &x) : u_{CategoryComparison<CAT>{x}} {}
template<TypeCategory CAT, int K>
@ -535,13 +529,13 @@ public:
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u_{std::move(x)} {}
template<typename A> Expr(CopyableIndirection<A> &&x) : u_{std::move(x)} {}
std::optional<Scalar> ScalarValue() const {
return common::GetIf<Scalar>(u_);
std::optional<Scalar<Result>> ScalarValue() const {
return common::GetIf<Scalar<Result>>(u_);
}
std::optional<Scalar> Fold(FoldingContext &c);
std::optional<Scalar<Result>> Fold(FoldingContext &c);
private:
std::variant<Scalar, CopyableIndirection<DataRef>,
std::variant<Scalar<Result>, CopyableIndirection<DataRef>,
CopyableIndirection<FunctionRef>, Not, And, Or, Eqv, Neqv,
CategoryComparison<TypeCategory::Integer>,
CategoryComparison<TypeCategory::Real>,
@ -576,14 +570,13 @@ extern template class Expr<Type<TypeCategory::Logical, 8>>;
template<TypeCategory CAT> class Expr<SomeKind<CAT>> {
public:
using Result = SomeKind<CAT>;
using Scalar = Scalar<Result>;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Expr)
template<int KIND> using KindExpr = Expr<Type<CAT, KIND>>;
template<int KIND> Expr(const KindExpr<KIND> &x) : u{x} {}
template<int KIND> Expr(KindExpr<KIND> &&x) : u{std::move(x)} {}
std::optional<Scalar> ScalarValue() const;
std::optional<Scalar> Fold(FoldingContext &);
std::optional<Scalar<Result>> ScalarValue() const;
std::optional<Scalar<Result>> Fold(FoldingContext &);
typename KindsVariant<CAT, KindExpr>::type u;
};
@ -601,25 +594,24 @@ using BOZLiteralConstant = value::Integer<128>;
// A completely generic expression, polymorphic across the intrinsic type
// categories and each of their kinds.
struct GenericExpr {
using Scalar = GenericScalar;
template<> class Expr<SomeType> {
public:
using Result = SomeType;
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(GenericExpr)
CLASS_BOILERPLATE(Expr)
template<typename A> GenericExpr(const A &x) : u{x} {}
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
: u{std::move(x)} {}
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
template<TypeCategory CAT, int KIND>
GenericExpr(const Expr<Type<CAT, KIND>> &x) : u{Expr<SomeKind<CAT>>{x}} {}
Expr(const Expr<Type<CAT, KIND>> &x) : u{Expr<SomeKind<CAT>>{x}} {}
template<TypeCategory CAT, int KIND>
GenericExpr(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> ScalarValue() const;
std::optional<Scalar> Fold(FoldingContext &);
std::optional<Scalar<Result>> ScalarValue() const;
std::optional<Scalar<Result>> Fold(FoldingContext &);
int Rank() const { return 1; } // TODO
std::variant<SomeKindIntegerExpr, SomeKindRealExpr, SomeKindComplexExpr,
@ -627,6 +619,11 @@ struct GenericExpr {
u;
};
extern template class Expr<SomeType>;
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
@ -663,22 +660,22 @@ BINARY(Power, Power)
#define BINARY(FUNC, OP) \
template<typename A> LogicalExpr<1> FUNC(const A &x, const A &y) { \
return {Comparison<typename A::Result>{OP, x, y}}; \
return {Comparison<ResultType<A>>{OP, x, y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
const A &x, A &&y) { \
return {Comparison<typename A::Result>{OP, x, std::move(y)}}; \
return {Comparison<ResultType<A>>{OP, x, std::move(y)}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
A &&x, const A &y) { \
return {Comparison<typename A::Result>{OP, std::move(x), y}}; \
return {Comparison<ResultType<A>>{OP, std::move(x), y}}; \
} \
template<typename A> \
std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
A &&x, A &&y) { \
return {Comparison<typename A::Result>{OP, std::move(x), std::move(y)}}; \
return {Comparison<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
}
BINARY(operator<, RelationalOperator::LT)

View File

@ -32,21 +32,6 @@ SomeKindRealExpr ConvertToTypeOf(
[&](const auto &rk) { return SomeKindRealExpr{decltype(rk){to}}; }, to.u);
}
static void ConvertToSameRealKind(SomeKindRealExpr &x, SomeKindRealExpr &y) {
std::visit(
[&](auto &xk, auto &yk) {
using xt = std::decay_t<decltype(xk)>;
using yt = std::decay_t<decltype(yk)>;
constexpr int kindDiff{xt::Result::kind - yt::Result::kind};
if constexpr (kindDiff < 0) {
x.u = yt{xk};
} else if constexpr (kindDiff > 0) {
y.u = xt{yk};
}
},
x.u, y.u);
}
std::optional<std::pair<SomeKindRealExpr, SomeKindRealExpr>>
ConvertRealOperands(
parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) {
@ -68,7 +53,7 @@ ConvertRealOperands(
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](SomeKindRealExpr &&rx, SomeKindRealExpr &&ry) {
ConvertToSameRealKind(rx, ry);
ConvertToSameKind(rx, ry);
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](const auto &, const auto &)
@ -87,4 +72,10 @@ ConvertRealOperands(parser::ContextualMessages &messages,
}
return std::nullopt;
}
Expr<SomeType> GenericScalarToExpr(const Scalar<SomeType> &x) {
return std::visit(
[&](const auto &c) { return ToGenericExpr(SomeKindScalarToExpr(c)); },
x.u);
}
} // namespace Fortran::evaluate

View File

@ -36,5 +36,48 @@ using ConvertRealOperandsResult =
ConvertRealOperandsResult ConvertRealOperands(
parser::ContextualMessages &, GenericExpr &&, GenericExpr &&);
template<TypeCategory CAT>
void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {
std::visit(
[&](auto &xk, auto &yk) {
using xt = ResultType<decltype(xk)>;
using yt = ResultType<decltype(yk)>;
if constexpr (xt::kind < yt::kind) {
x.u = Expr<yt>{xk};
} else if constexpr (xt::kind > yt::kind) {
y.u = Expr<xt>{yk};
}
},
x.u, y.u);
}
template<typename A> Expr<ScalarValueType<A>> ScalarConstantToExpr(const A &x) {
return {x};
}
template<TypeCategory CAT, int KIND>
Expr<SomeKind<CAT>> ToSomeKindExpr(const Expr<Type<CAT, KIND>> &x) {
return Expr<SomeKind<CAT>>{x};
}
template<TypeCategory CAT>
Expr<SomeKind<CAT>> SomeKindScalarToExpr(const SomeKindScalar<CAT> &x) {
return std::visit(
[](const auto &c) { return ToSomeKindExpr(ScalarConstantToExpr(c)); },
x.u);
}
Expr<SomeType> GenericScalarToExpr(const Scalar<SomeType> &);
template<TypeCategory CAT>
Expr<SomeType> ToGenericExpr(const Expr<SomeKind<CAT>> &x) {
return Expr<SomeType>{x};
}
template<TypeCategory CAT>
Expr<SomeType> ToGenericExpr(Expr<SomeKind<CAT>> &&x) {
return Expr<SomeType>{std::move(x)};
}
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_TOOLS_H_

View File

@ -38,34 +38,4 @@ std::optional<std::string> GenericScalar::ToString() const {
}
return std::nullopt;
}
// TODO pmk: maybe transplant these templates to type.h/expression.h?
// There's some admittedly opaque type-fu going on below.
// Given a GenericScalar value, we want to be able to (re-)wrap it as
// a GenericExpr. So we extract its value, then build up an expression
// around it. The subtle magic is in the first template, whose result
// is a specific expression whose Fortran type category and kind are inferred
// from the type of the scalar constant.
template<typename A> Expr<ScalarValueType<A>> ScalarConstantToExpr(const A &x) {
return {x};
}
template<typename A>
Expr<SomeKind<A::category>> ToSomeKindExpr(const Expr<A> &x) {
return {x};
}
template<TypeCategory CAT>
Expr<SomeKind<CAT>> SomeKindScalarToExpr(const SomeKindScalar<CAT> &x) {
return std::visit(
[](const auto &c) { return ToSomeKindExpr(ScalarConstantToExpr(c)); },
x.u);
}
GenericExpr GenericScalar::ToGenericExpr() const {
return std::visit(
[&](const auto &c) { return GenericExpr{SomeKindScalarToExpr(c)}; }, u);
}
} // namespace Fortran::evaluate

View File

@ -35,8 +35,6 @@ namespace Fortran::evaluate {
using common::TypeCategory;
struct GenericExpr;
template<TypeCategory C, int KIND> struct TypeBase {
static constexpr TypeCategory category{C};
static constexpr TypeCategory GetCategory() { return C; };
@ -47,8 +45,6 @@ template<TypeCategory C, int KIND> struct TypeBase {
}
};
template<typename T> using Scalar = typename T::Scalar;
template<TypeCategory C, int KIND> struct Type;
template<int KIND>
@ -59,32 +55,30 @@ struct Type<TypeCategory::Integer, KIND>
template<>
struct Type<TypeCategory::Real, 2> : public TypeBase<TypeCategory::Real, 2> {
using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 2>>, 11>;
using Complex = Type<TypeCategory::Complex, 2>;
using Scalar =
value::Real<typename Type<TypeCategory::Integer, 2>::Scalar, 11>;
};
template<>
struct Type<TypeCategory::Real, 4> : public TypeBase<TypeCategory::Real, 4> {
using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 4>>, 24>;
using Complex = Type<TypeCategory::Complex, 4>;
using Scalar =
value::Real<typename Type<TypeCategory::Integer, 4>::Scalar, 24>;
};
template<>
struct Type<TypeCategory::Real, 8> : public TypeBase<TypeCategory::Real, 8> {
using Scalar = value::Real<Scalar<Type<TypeCategory::Integer, 8>>, 53>;
using Complex = Type<TypeCategory::Complex, 8>;
using Scalar =
value::Real<typename Type<TypeCategory::Integer, 8>::Scalar, 53>;
};
template<>
struct Type<TypeCategory::Real, 10> : public TypeBase<TypeCategory::Real, 10> {
using Scalar = value::Real<value::Integer<80>, 64, false>;
using Complex = Type<TypeCategory::Complex, 10>;
};
template<>
struct Type<TypeCategory::Real, 16> : public TypeBase<TypeCategory::Real, 16> {
using Scalar = value::Real<value::Integer<128>, 112>;
using Complex = Type<TypeCategory::Complex, 16>;
};
// The KIND type parameter on COMPLEX is the kind of each of its components.
@ -92,7 +86,7 @@ template<int KIND>
struct Type<TypeCategory::Complex, KIND>
: public TypeBase<TypeCategory::Complex, KIND> {
using Part = Type<TypeCategory::Real, KIND>;
using Scalar = value::Complex<Scalar<Part>>;
using Scalar = value::Complex<typename Part::Scalar>;
};
template<int KIND> struct Type<TypeCategory::Character, KIND> {
@ -111,6 +105,11 @@ struct Type<TypeCategory::Logical, KIND>
using Scalar = value::Logical<8 * KIND>;
};
// Type functions
template<typename T> using Scalar = typename std::decay_t<T>::Scalar;
template<TypeCategory C, typename T>
using SameKind = Type<C, std::decay_t<T>::kind>;
// Convenience type aliases:
// Default REAL just simply has to be IEEE-754 single precision today.
// It occupies one numeric storage unit by definition. The default INTEGER
@ -123,11 +122,12 @@ using DefaultReal = Type<TypeCategory::Real, 4>;
using DefaultDoublePrecision = Type<TypeCategory::Real, 2 * DefaultReal::kind>;
using DefaultInteger = Type<TypeCategory::Integer, DefaultReal::kind>;
using IntrinsicTypeParameterType = DefaultInteger;
using DefaultComplex = typename DefaultReal::Complex;
using DefaultComplex = SameKind<TypeCategory::Complex, DefaultReal>;
using DefaultLogical = Type<TypeCategory::Logical, DefaultInteger::kind>;
using DefaultCharacter = Type<TypeCategory::Character, 1>;
using SubscriptInteger = Type<TypeCategory::Integer, 8>;
using LogicalResult = Type<TypeCategory::Logical, 1>;
// These macros invoke other macros on each of the supported kinds of
// a given category.
@ -183,7 +183,8 @@ FOR_EACH_LOGICAL_KIND(M, )
#undef TOSV
template<typename CONST>
using ScalarValueType = typename GetTypeOfScalarValue<CONST>::type;
using ScalarValueType =
typename GetTypeOfScalarValue<std::decay_t<CONST>>::type;
// Holds a scalar value of any kind within a particular intrinsic type
// category.
@ -200,6 +201,13 @@ template<TypeCategory CAT> struct SomeKindScalar {
typename KindsVariant<CAT, KindScalar>::type u;
};
struct GenericScalar;
// Represents a completely generic type.
struct SomeType {
using Scalar = GenericScalar;
};
// Holds a scalar constant of any intrinsic category and size.
struct GenericScalar {
CLASS_BOILERPLATE(GenericScalar)
@ -217,7 +225,6 @@ struct GenericScalar {
std::optional<std::int64_t> ToInt64() const;
std::optional<std::string> ToString() const;
GenericExpr ToGenericExpr() const;
std::variant<SomeKindScalar<TypeCategory::Integer>,
SomeKindScalar<TypeCategory::Real>, SomeKindScalar<TypeCategory::Complex>,

View File

@ -26,9 +26,9 @@ namespace Fortran::evaluate {
// Constructors, accessors, mutators
Triplet::Triplet(std::optional<SubscriptIntegerExpr> &&l,
std::optional<SubscriptIntegerExpr> &&u,
std::optional<SubscriptIntegerExpr> &&s) {
Triplet::Triplet(std::optional<Expr<SubscriptInteger>> &&l,
std::optional<Expr<SubscriptInteger>> &&u,
std::optional<Expr<SubscriptInteger>> &&s) {
if (l.has_value()) {
lower_ = IndirectSubscriptIntegerExpr::Make(std::move(*l));
}
@ -40,21 +40,21 @@ Triplet::Triplet(std::optional<SubscriptIntegerExpr> &&l,
}
}
std::optional<SubscriptIntegerExpr> Triplet::lower() const {
std::optional<Expr<SubscriptInteger>> Triplet::lower() const {
if (lower_) {
return {**lower_};
}
return std::nullopt;
}
std::optional<SubscriptIntegerExpr> Triplet::upper() const {
std::optional<Expr<SubscriptInteger>> Triplet::upper() const {
if (upper_) {
return {**upper_};
}
return std::nullopt;
}
std::optional<SubscriptIntegerExpr> Triplet::stride() const {
std::optional<Expr<SubscriptInteger>> Triplet::stride() const {
if (stride_) {
return {**stride_};
}
@ -62,8 +62,8 @@ std::optional<SubscriptIntegerExpr> Triplet::stride() const {
}
CoarrayRef::CoarrayRef(std::vector<const Symbol *> &&c,
std::vector<SubscriptIntegerExpr> &&ss,
std::vector<SubscriptIntegerExpr> &&css)
std::vector<Expr<SubscriptInteger>> &&ss,
std::vector<Expr<SubscriptInteger>> &&css)
: base_(std::move(c)), subscript_(std::move(ss)),
cosubscript_(std::move(css)) {
CHECK(!base_.empty());
@ -80,8 +80,8 @@ CoarrayRef &CoarrayRef::setTeam(Variable &&v, bool isTeamNumber) {
return *this;
}
Substring::Substring(DataRef &&d, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
Substring::Substring(DataRef &&d, std::optional<Expr<SubscriptInteger>> &&f,
std::optional<Expr<SubscriptInteger>> &&l)
: u_{std::move(d)} {
if (f.has_value()) {
first_ = IndirectSubscriptIntegerExpr::Make(std::move(*f));
@ -91,8 +91,8 @@ Substring::Substring(DataRef &&d, std::optional<SubscriptIntegerExpr> &&f,
}
}
Substring::Substring(std::string &&s, std::optional<SubscriptIntegerExpr> &&f,
std::optional<SubscriptIntegerExpr> &&l)
Substring::Substring(std::string &&s, std::optional<Expr<SubscriptInteger>> &&f,
std::optional<Expr<SubscriptInteger>> &&l)
: u_{std::move(s)} {
if (f.has_value()) {
first_ = IndirectSubscriptIntegerExpr::Make(std::move(*f));
@ -102,14 +102,14 @@ Substring::Substring(std::string &&s, std::optional<SubscriptIntegerExpr> &&f,
}
}
SubscriptIntegerExpr Substring::first() const {
Expr<SubscriptInteger> Substring::first() const {
if (first_.has_value()) {
return **first_;
}
return {1};
}
SubscriptIntegerExpr Substring::last() const {
Expr<SubscriptInteger> Substring::last() const {
if (last_.has_value()) {
return **last_;
}
@ -117,7 +117,7 @@ SubscriptIntegerExpr Substring::last() const {
common::visitors{[](const std::string &s) {
// std::string::size_type isn't convertible to uint64_t
// on Darwin
return SubscriptIntegerExpr{
return Expr<SubscriptInteger>{
static_cast<std::uint64_t>(s.size())};
},
[](const DataRef &x) { return x.LEN(); }},
@ -125,14 +125,14 @@ SubscriptIntegerExpr Substring::last() const {
}
std::optional<std::string> Substring::Fold(FoldingContext &context) {
std::optional<SubscriptIntegerExpr::Scalar> lbValue, ubValue;
std::optional<Scalar<SubscriptInteger>> lbValue, ubValue;
if (first_.has_value()) {
lbValue = (*first_)->Fold(context);
} else {
lbValue = first().Fold(context);
}
if (lbValue.has_value()) {
first_ = IndirectSubscriptIntegerExpr{SubscriptIntegerExpr{*lbValue}};
first_ = IndirectSubscriptIntegerExpr{Expr<SubscriptInteger>{*lbValue}};
}
if (last_.has_value()) {
ubValue = (*last_)->Fold(context);
@ -140,7 +140,7 @@ std::optional<std::string> Substring::Fold(FoldingContext &context) {
ubValue = last().Fold(context);
}
if (ubValue.has_value()) {
last_ = IndirectSubscriptIntegerExpr{SubscriptIntegerExpr{*ubValue}};
last_ = IndirectSubscriptIntegerExpr{Expr<SubscriptInteger>{*ubValue}};
}
if (lbValue.has_value() && ubValue.has_value()) {
std::int64_t lbi{lbValue->ToInt64()};
@ -148,8 +148,8 @@ std::optional<std::string> Substring::Fold(FoldingContext &context) {
if (ubi < lbi) {
// These cases are well defined, and they produce zero-length results.
u_ = ""s;
first_ = SubscriptIntegerExpr{1};
last_ = SubscriptIntegerExpr{0};
first_ = Expr<SubscriptInteger>{1};
last_ = Expr<SubscriptInteger>{0};
return {""s};
}
if (lbi <= 0) {
@ -157,11 +157,11 @@ std::optional<std::string> Substring::Fold(FoldingContext &context) {
"lower bound on substring (%jd) is less than one"_en_US,
static_cast<std::intmax_t>(lbi));
lbi = 1;
first_ = SubscriptIntegerExpr{lbi};
first_ = Expr<SubscriptInteger>{lbi};
}
if (ubi <= 0) {
u_ = ""s;
last_ = SubscriptIntegerExpr{0};
last_ = Expr<SubscriptInteger>{0};
return {""s};
}
if (std::string * str{std::get_if<std::string>(&u_)}) {
@ -171,7 +171,7 @@ std::optional<std::string> Substring::Fold(FoldingContext &context) {
"upper bound on substring (%jd) is greater than character length (%jd)"_en_US,
static_cast<std::intmax_t>(ubi), static_cast<std::intmax_t>(len));
ubi = len;
last_ = SubscriptIntegerExpr{ubi};
last_ = Expr<SubscriptInteger>{ubi};
}
std::string result{str->substr(lbi - 1, ubi - lbi + 1)};
u_ = result;
@ -337,36 +337,36 @@ std::ostream &Label::Dump(std::ostream &o) const {
}
// LEN()
static SubscriptIntegerExpr SymbolLEN(const Symbol &sym) {
return SubscriptIntegerExpr{0}; // TODO
static Expr<SubscriptInteger> SymbolLEN(const Symbol &sym) {
return Expr<SubscriptInteger>{0}; // TODO
}
SubscriptIntegerExpr Component::LEN() const { return SymbolLEN(symbol()); }
SubscriptIntegerExpr ArrayRef::LEN() const {
Expr<SubscriptInteger> Component::LEN() const { return SymbolLEN(symbol()); }
Expr<SubscriptInteger> ArrayRef::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(*s); },
[](const Component &x) { return x.LEN(); }},
u_);
}
SubscriptIntegerExpr CoarrayRef::LEN() const {
Expr<SubscriptInteger> CoarrayRef::LEN() const {
return SymbolLEN(*base_.back());
}
SubscriptIntegerExpr DataRef::LEN() const {
Expr<SubscriptInteger> DataRef::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(*s); },
[](const auto &x) { return x.LEN(); }},
u_);
}
SubscriptIntegerExpr Substring::LEN() const {
return SubscriptIntegerExpr::Max{
SubscriptIntegerExpr{0}, last() - first() + SubscriptIntegerExpr{1}};
Expr<SubscriptInteger> Substring::LEN() const {
return Expr<SubscriptInteger>::Max{
Expr<SubscriptInteger>{0}, last() - first() + Expr<SubscriptInteger>{1}};
}
SubscriptIntegerExpr ProcedureDesignator::LEN() const {
Expr<SubscriptInteger> ProcedureDesignator::LEN() const {
return std::visit(
common::visitors{[](const Symbol *s) { return SymbolLEN(*s); },
[](const Component &c) { return c.LEN(); },
[](const auto &) {
CRASH_NO_CASE;
return SubscriptIntegerExpr{0};
return Expr<SubscriptInteger>{0};
}},
u_);
}

View File

@ -42,8 +42,8 @@ class ActualFunctionArg;
// Subscript and cosubscript expressions are of a kind that matches the
// address size, at least at the top level.
using SubscriptIntegerExpr = IntegerExpr<SubscriptInteger::kind>;
using IndirectSubscriptIntegerExpr = CopyableIndirection<SubscriptIntegerExpr>;
using IndirectSubscriptIntegerExpr =
CopyableIndirection<Expr<SubscriptInteger>>;
// R913 structure-component & C920: Defined to be a multi-part
// data-ref whose last part has no subscripts (or image-selector, although
@ -60,7 +60,7 @@ public:
const DataRef &base() const { return *base_; }
DataRef &base() { return *base_; }
const Symbol &symbol() const { return *symbol_; }
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> LEN() const;
private:
CopyableIndirection<DataRef> base_;
@ -71,12 +71,12 @@ private:
class Triplet {
public:
CLASS_BOILERPLATE(Triplet)
Triplet(std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
std::optional<SubscriptIntegerExpr> lower() const;
std::optional<SubscriptIntegerExpr> upper() const;
std::optional<SubscriptIntegerExpr> stride() const;
Triplet(std::optional<Expr<SubscriptInteger>> &&,
std::optional<Expr<SubscriptInteger>> &&,
std::optional<Expr<SubscriptInteger>> &&);
std::optional<Expr<SubscriptInteger>> lower() const;
std::optional<Expr<SubscriptInteger>> upper() const;
std::optional<Expr<SubscriptInteger>> stride() const;
private:
std::optional<IndirectSubscriptIntegerExpr> lower_, upper_, stride_;
@ -86,9 +86,9 @@ private:
class Subscript {
public:
CLASS_BOILERPLATE(Subscript)
explicit Subscript(const SubscriptIntegerExpr &s)
explicit Subscript(const Expr<SubscriptInteger> &s)
: u_{IndirectSubscriptIntegerExpr::Make(s)} {}
explicit Subscript(SubscriptIntegerExpr &&s)
explicit Subscript(Expr<SubscriptInteger> &&s)
: u_{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
explicit Subscript(const Triplet &t) : u_{t} {}
explicit Subscript(Triplet &&t) : u_{std::move(t)} {}
@ -109,7 +109,7 @@ public:
: u_{&n}, subscript_(std::move(ss)) {}
ArrayRef(Component &&c, std::vector<Subscript> &&ss)
: u_{std::move(c)}, subscript_(std::move(ss)) {}
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> LEN() const;
private:
std::variant<const Symbol *, Component> u_;
@ -127,15 +127,15 @@ class CoarrayRef {
public:
CLASS_BOILERPLATE(CoarrayRef)
CoarrayRef(std::vector<const Symbol *> &&,
std::vector<SubscriptIntegerExpr> &&,
std::vector<SubscriptIntegerExpr> &&); // TODO: stat & team?
std::vector<Expr<SubscriptInteger>> &&,
std::vector<Expr<SubscriptInteger>> &&); // TODO: stat & team?
CoarrayRef &setStat(Variable &&);
CoarrayRef &setTeam(Variable &&, bool isTeamNumber = false);
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> LEN() const;
private:
std::vector<const Symbol *> base_;
std::vector<SubscriptIntegerExpr> subscript_, cosubscript_;
std::vector<Expr<SubscriptInteger>> subscript_, cosubscript_;
std::optional<CopyableIndirection<Variable>> stat_, team_;
bool teamIsTeamNumber_{false}; // false: TEAM=, true: TEAM_NUMBER=
};
@ -152,7 +152,7 @@ public:
explicit DataRef(Component &&c) : u_{std::move(c)} {}
explicit DataRef(ArrayRef &&a) : u_{std::move(a)} {}
explicit DataRef(CoarrayRef &&a) : u_{std::move(a)} {}
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> LEN() const;
private:
std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u_;
@ -166,14 +166,14 @@ class Substring {
public:
using FoldableTrait = std::true_type;
CLASS_BOILERPLATE(Substring)
Substring(DataRef &&, std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
Substring(std::string &&, std::optional<SubscriptIntegerExpr> &&,
std::optional<SubscriptIntegerExpr> &&);
Substring(DataRef &&, std::optional<Expr<SubscriptInteger>> &&,
std::optional<Expr<SubscriptInteger>> &&);
Substring(std::string &&, std::optional<Expr<SubscriptInteger>> &&,
std::optional<Expr<SubscriptInteger>> &&);
SubscriptIntegerExpr first() const;
SubscriptIntegerExpr last() const;
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> first() const;
Expr<SubscriptInteger> last() const;
Expr<SubscriptInteger> LEN() const;
std::optional<std::string> Fold(FoldingContext &);
private:
@ -217,7 +217,7 @@ public:
explicit ProcedureDesignator(const Symbol &n) : u_{&n} {}
explicit ProcedureDesignator(const Component &c) : u_{c} {}
explicit ProcedureDesignator(Component &&c) : u_{std::move(c)} {}
SubscriptIntegerExpr LEN() const;
Expr<SubscriptInteger> LEN() const;
private:
std::variant<IntrinsicProcedure, const Symbol *, Component> u_;
@ -252,11 +252,11 @@ private:
class ActualFunctionArg {
public:
CLASS_BOILERPLATE(ActualFunctionArg)
explicit ActualFunctionArg(GenericExpr &&x) : u_{std::move(x)} {}
explicit ActualFunctionArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
explicit ActualFunctionArg(Variable &&x) : u_{std::move(x)} {}
private:
std::variant<CopyableIndirection<GenericExpr>, Variable> u_;
std::variant<CopyableIndirection<Expr<SomeType>>, Variable> u_;
};
struct Label { // TODO: this is a placeholder
@ -268,12 +268,12 @@ struct Label { // TODO: this is a placeholder
class ActualSubroutineArg {
public:
CLASS_BOILERPLATE(ActualSubroutineArg)
explicit ActualSubroutineArg(GenericExpr &&x) : u_{std::move(x)} {}
explicit ActualSubroutineArg(Expr<SomeType> &&x) : u_{std::move(x)} {}
explicit ActualSubroutineArg(Variable &&x) : u_{std::move(x)} {}
explicit ActualSubroutineArg(const Label &l) : u_{&l} {}
private:
std::variant<CopyableIndirection<GenericExpr>, Variable, const Label *> u_;
std::variant<CopyableIndirection<Expr<SomeType>>, Variable, const Label *> u_;
};
using SubroutineRef = ProcedureRef<ActualSubroutineArg>;

View File

@ -62,10 +62,6 @@ namespace Fortran::semantics {
class Symbol;
} // namespace Fortran::semantics
namespace Fortran::evaluate {
struct GenericExpr;
} // namespace Fortran::evaluate
// Most non-template classes in this file use these default definitions
// for their move constructor and move assignment operator=, and disable
// their copy constructor and copy assignment operator=.

View File

@ -75,6 +75,9 @@ MaybeExpr AnalyzeHelper(
return result;
}
// TODO: Return
// std::optional<evaluate::Expr<evaluate::SomeKind<TypeCategory::Integer>>> here
// instead
template<typename A>
MaybeExpr AnalyzeHelper(
ExpressionAnalyzer &ea, const parser::Integer<A> &tree) {
@ -106,8 +109,8 @@ static std::optional<evaluate::SomeKindCharacterExpr> AnalyzeLiteral(
}
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
std::function<evaluate::GenericExpr(A &&)> f{
[](A &&y) -> evaluate::GenericExpr { return {std::move(y)}; }};
std::function<GenericExpr(A &&)> f{
[](A &&y) -> GenericExpr { return {std::move(y)}; }};
return common::MapOptional(f, std::move(x));
}
@ -124,11 +127,11 @@ MaybeExpr AnalyzeHelper(
}
// TODO: ensure that any kind parameter is 1
std::string str{std::get<parser::CharLiteralConstant>(x.t).GetString()};
std::optional<evaluate::SubscriptIntegerExpr> lb, ub;
std::optional<evaluate::Expr<evaluate::SubscriptInteger>> lb, ub;
if (lbTree.has_value()) {
if (MaybeExpr lbExpr{AnalyzeHelper(ea, *lbTree)}) {
if (auto *ie{std::get_if<evaluate::SomeKindIntegerExpr>(&lbExpr->u)}) {
lb = evaluate::SubscriptIntegerExpr{std::move(*ie)};
lb = evaluate::Expr<evaluate::SubscriptInteger>{std::move(*ie)};
} else {
ea.context().messages.Say(
"scalar integer expression required for substring lower bound"_err_en_US);
@ -138,7 +141,7 @@ MaybeExpr AnalyzeHelper(
if (ubTree.has_value()) {
if (MaybeExpr ubExpr{AnalyzeHelper(ea, *ubTree)}) {
if (auto *ie{std::get_if<evaluate::SomeKindIntegerExpr>(&ubExpr->u)}) {
ub = evaluate::SubscriptIntegerExpr{std::move(*ie)};
ub = evaluate::Expr<evaluate::SubscriptInteger>{std::move(*ie)};
} else {
ea.context().messages.Say(
"scalar integer expression required for substring upper bound"_err_en_US);
@ -152,8 +155,7 @@ MaybeExpr AnalyzeHelper(
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
evaluate::CharacterExpr<1> chExpr{std::move(ind)};
chExpr.Fold(ea.context());
return {evaluate::GenericExpr{
evaluate::SomeKindCharacterExpr{std::move(chExpr)}}};
return {GenericExpr{evaluate::SomeKindCharacterExpr{std::move(chExpr)}}};
}
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
@ -165,8 +167,7 @@ std::optional<evaluate::SomeKindIntegerExpr> IntLiteralConstant(
auto value{std::get<0>(x.t)}; // std::[u]int64_t
switch (kind) {
#define CASE(k) \
case k: \
return {evaluate::SomeKindIntegerExpr{evaluate::IntegerExpr<k>{value}}};
case k: return {evaluate::ToSomeKindExpr(evaluate::IntegerExpr<k>{value})};
FOR_EACH_INTEGER_KIND(CASE, )
#undef CASE
default:
@ -214,9 +215,9 @@ static std::optional<evaluate::BOZLiteralConstant> AnalyzeLiteral(
template<int KIND>
std::optional<evaluate::SomeKindRealExpr> ReadRealLiteral(
parser::CharBlock source, evaluate::FoldingContext &context) {
using valueType = typename evaluate::RealExpr<KIND>::Scalar;
const char *p{source.begin()};
auto valWithFlags{valueType::Read(p, context.rounding)};
using RealType = evaluate::Type<evaluate::TypeCategory::Real, KIND>;
auto valWithFlags{evaluate::Scalar<RealType>::Read(p, context.rounding)};
CHECK(p == source.end());
evaluate::RealFlagWarnings(
context, valWithFlags.flags, "conversion of REAL literal");
@ -224,7 +225,7 @@ std::optional<evaluate::SomeKindRealExpr> ReadRealLiteral(
if (context.flushDenormalsToZero) {
value = value.FlushDenormalToZero();
}
return {evaluate::SomeKindRealExpr{evaluate::RealExpr<KIND>{value}}};
return {evaluate::ToSomeKindExpr(evaluate::Expr<RealType>{value})};
}
static std::optional<evaluate::SomeKindRealExpr> AnalyzeLiteral(
@ -589,19 +590,21 @@ ExpressionAnalyzer::KindParam ExpressionAnalyzer::Analyze(
std::optional<evaluate::SomeKindComplexExpr>
ExpressionAnalyzer::ConstructComplex(MaybeExpr &&real, MaybeExpr &&imaginary) {
// TODO: pmk abstract further, this will be a common pattern
auto partial{[&](evaluate::GenericExpr &&x, evaluate::GenericExpr &&y) {
auto partial{[&](GenericExpr &&x, GenericExpr &&y) {
return evaluate::ConvertRealOperands(
context_.messages, std::move(x), std::move(y));
}};
using fType = evaluate::ConvertRealOperandsResult(
evaluate::GenericExpr &&, evaluate::GenericExpr &&);
using fType =
evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&);
std::function<fType> f{partial};
auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
if (auto joined{common::JoinOptionals(std::move(converted))}) {
return {std::visit(
[](auto &&rx, auto &&ix) -> evaluate::SomeKindComplexExpr {
using realExpr = std::decay_t<decltype(rx)>;
using zExpr = evaluate::Expr<typename realExpr::Complex>;
using realType = evaluate::ResultType<decltype(rx)>;
using zType =
evaluate::SameKind<evaluate::TypeCategory::Complex, realType>;
using zExpr = evaluate::Expr<zType>;
return {zExpr{typename zExpr::CMPLX{std::move(rx), std::move(ix)}}};
},
std::move(joined->first.u), std::move(joined->second.u))};

View File

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