forked from OSchip/llvm-project
[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:
parent
94540975f3
commit
c75c9f0a54
|
@ -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_
|
||||
|
|
|
@ -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>>;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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=.
|
||||
|
|
|
@ -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))};
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
|
||||
namespace Fortran::semantics {
|
||||
|
||||
using MaybeExpr = std::optional<evaluate::GenericExpr>;
|
||||
using evaluate::GenericExpr;
|
||||
using MaybeExpr = std::optional<GenericExpr>;
|
||||
|
||||
class ExpressionAnalyzer {
|
||||
public:
|
||||
|
|
Loading…
Reference in New Issue