}
template<int KIND>
-std::ostream &IntegerExpr<KIND>::Dump(std::ostream &o) const {
+std::ostream &Expr<Type<TypeCategory::Integer, KIND>>::Dump(
+ std::ostream &o) const {
std::visit(
common::visitors{[&](const Scalar<Result> &n) { o << n.SignedDecimal(); },
[&](const CopyableIndirection<DataRef> &d) { d->Dump(o); },
return o;
}
-template<int KIND> std::ostream &RealExpr<KIND>::Dump(std::ostream &o) const {
+template<int KIND>
+std::ostream &Expr<Type<TypeCategory::Real, KIND>>::Dump(
+ std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &n) {
o << n.DumpHexadecimal();
},
}
template<int KIND>
-std::ostream &ComplexExpr<KIND>::Dump(std::ostream &o) const {
+std::ostream &Expr<Type<TypeCategory::Complex, KIND>>::Dump(
+ std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &n) {
o << n.DumpHexadecimal();
},
}
template<int KIND>
-std::ostream &CharacterExpr<KIND>::Dump(std::ostream &o) const {
+std::ostream &Expr<Type<TypeCategory::Character, KIND>>::Dump(
+ std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &s) {
o << parser::QuoteCharacterLiteral(s);
},
}
template<int KIND>
-std::ostream &LogicalExpr<KIND>::Dump(std::ostream &o) const {
+std::ostream &Expr<Type<TypeCategory::Logical, KIND>>::Dump(
+ std::ostream &o) const {
std::visit(common::visitors{[&](const Scalar<Result> &tf) {
o << (tf.IsTrue() ? ".TRUE." : ".FALSE.");
},
}
// LEN()
-template<int KIND> Expr<SubscriptInteger> CharacterExpr<KIND>::LEN() const {
+template<int KIND>
+Expr<SubscriptInteger> Expr<Type<TypeCategory::Character, KIND>>::LEN() const {
return std::visit(
common::visitors{[](const Scalar<Result> &c) {
// std::string::size_type isn't convertible to uint64_t
}
template<int KIND>
-auto IntegerExpr<KIND>::ConvertInteger::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertInteger::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
}
template<int KIND>
-auto IntegerExpr<KIND>::ConvertReal::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::ConvertReal::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
}
template<int KIND>
-auto IntegerExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
- const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
+auto Expr<Type<TypeCategory::Integer, 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);
}
template<int KIND>
-auto IntegerExpr<KIND>::Add::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Add::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto sum{a.AddSigned(b)};
}
template<int KIND>
-auto IntegerExpr<KIND>::Subtract::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto diff{a.SubtractSigned(b)};
}
template<int KIND>
-auto IntegerExpr<KIND>::Multiply::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.MultiplySigned(b)};
}
template<int KIND>
-auto IntegerExpr<KIND>::Divide::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto qr{a.DivideSigned(b)};
}
template<int KIND>
-auto IntegerExpr<KIND>::Power::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, 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)};
}
template<int KIND>
-auto IntegerExpr<KIND>::Max::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Max::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (a.CompareSigned(b) == Ordering::Greater) {
}
template<int KIND>
-auto IntegerExpr<KIND>::Min::FoldScalar(
+auto Expr<Type<TypeCategory::Integer, KIND>>::Min::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (a.CompareSigned(b) == Ordering::Less) {
}
template<int KIND>
-auto IntegerExpr<KIND>::Fold(FoldingContext &context)
+auto Expr<Type<TypeCategory::Integer, KIND>>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto RealExpr<KIND>::ConvertInteger::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::ConvertInteger::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Integer> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
}
template<int KIND>
-auto RealExpr<KIND>::ConvertReal::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::ConvertReal::FoldScalar(
FoldingContext &context, const SomeKindScalar<TypeCategory::Real> &c)
-> std::optional<Scalar<Result>> {
return std::visit(
}
template<int KIND>
-auto RealExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
- const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
+auto Expr<Type<TypeCategory::Real, KIND>>::Negate::FoldScalar(
+ FoldingContext &context, const Scalar<Result> &c)
+ -> std::optional<Scalar<Result>> {
return {c.Negate()};
}
template<int KIND>
-auto RealExpr<KIND>::Add::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::Add::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto sum{a.Add(b, context.rounding)};
}
template<int KIND>
-auto RealExpr<KIND>::Subtract::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto difference{a.Subtract(b, context.rounding)};
}
template<int KIND>
-auto RealExpr<KIND>::Multiply::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.Multiply(b, context.rounding)};
}
template<int KIND>
-auto RealExpr<KIND>::Divide::FoldScalar(
+auto Expr<Type<TypeCategory::Real, KIND>>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto quotient{a.Divide(b, context.rounding)};
}
template<int KIND>
-auto RealExpr<KIND>::Power::FoldScalar(
+auto Expr<Type<TypeCategory::Real, 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<Result> &a, const SomeKindScalar<TypeCategory::Integer> &b)
+auto Expr<Type<TypeCategory::Real, KIND>>::IntPower::FoldScalar(
+ FoldingContext &context, const Scalar<Result> &a,
+ const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto RealExpr<KIND>::Max::FoldScalar(
+auto Expr<Type<TypeCategory::Real, 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) {
}
template<int KIND>
-auto RealExpr<KIND>::Min::FoldScalar(
+auto Expr<Type<TypeCategory::Real, 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) {
}
template<int KIND>
-auto RealExpr<KIND>::RealPart::FoldScalar(FoldingContext &context,
+auto Expr<Type<TypeCategory::Real, KIND>>::RealPart::FoldScalar(
+ FoldingContext &context,
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
-> std::optional<Scalar<Result>> {
return {z.REAL()};
}
template<int KIND>
-auto RealExpr<KIND>::AIMAG::FoldScalar(FoldingContext &context,
+auto Expr<Type<TypeCategory::Real, KIND>>::AIMAG::FoldScalar(
+ FoldingContext &context,
const Scalar<SameKind<TypeCategory::Complex, Result>> &z)
-> std::optional<Scalar<Result>> {
return {z.AIMAG()};
}
template<int KIND>
-auto RealExpr<KIND>::Fold(FoldingContext &context)
+auto Expr<Type<TypeCategory::Real, KIND>>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto ComplexExpr<KIND>::Negate::FoldScalar(FoldingContext &context,
- const Scalar<Result> &c) -> std::optional<Scalar<Result>> {
+auto Expr<Type<TypeCategory::Complex, KIND>>::Negate::FoldScalar(
+ FoldingContext &context, const Scalar<Result> &c)
+ -> std::optional<Scalar<Result>> {
return {c.Negate()};
}
template<int KIND>
-auto ComplexExpr<KIND>::Add::FoldScalar(
+auto Expr<Type<TypeCategory::Complex, KIND>>::Add::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto sum{a.Add(b, context.rounding)};
}
template<int KIND>
-auto ComplexExpr<KIND>::Subtract::FoldScalar(
+auto Expr<Type<TypeCategory::Complex, KIND>>::Subtract::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto difference{a.Subtract(b, context.rounding)};
}
template<int KIND>
-auto ComplexExpr<KIND>::Multiply::FoldScalar(
+auto Expr<Type<TypeCategory::Complex, KIND>>::Multiply::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto product{a.Multiply(b, context.rounding)};
}
template<int KIND>
-auto ComplexExpr<KIND>::Divide::FoldScalar(
+auto Expr<Type<TypeCategory::Complex, KIND>>::Divide::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
auto quotient{a.Divide(b, context.rounding)};
}
template<int KIND>
-auto ComplexExpr<KIND>::Power::FoldScalar(
+auto Expr<Type<TypeCategory::Complex, 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<Result> &a, const SomeKindScalar<TypeCategory::Integer> &b)
+auto Expr<Type<TypeCategory::Complex, KIND>>::IntPower::FoldScalar(
+ FoldingContext &context, const Scalar<Result> &a,
+ const SomeKindScalar<TypeCategory::Integer> &b)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](const auto &pow) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto ComplexExpr<KIND>::CMPLX::FoldScalar(FoldingContext &context,
+auto Expr<Type<TypeCategory::Complex, KIND>>::CMPLX::FoldScalar(
+ FoldingContext &context,
const Scalar<SameKind<TypeCategory::Real, Result>> &a,
const Scalar<SameKind<TypeCategory::Real, Result>> &b)
-> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto ComplexExpr<KIND>::Fold(FoldingContext &context)
+auto Expr<Type<TypeCategory::Complex, KIND>>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto CharacterExpr<KIND>::Concat::FoldScalar(
+auto Expr<Type<TypeCategory::Character, KIND>>::Concat::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if constexpr (KIND == 1) {
}
template<int KIND>
-auto CharacterExpr<KIND>::Max::FoldScalar(
+auto Expr<Type<TypeCategory::Character, KIND>>::Max::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (Compare(a, b) == Ordering::Less) {
}
template<int KIND>
-auto CharacterExpr<KIND>::Min::FoldScalar(
+auto Expr<Type<TypeCategory::Character, KIND>>::Min::FoldScalar(
FoldingContext &context, const Scalar<Result> &a, const Scalar<Result> &b)
-> std::optional<Scalar<Result>> {
if (Compare(a, b) == Ordering::Greater) {
}
template<int KIND>
-auto CharacterExpr<KIND>::Fold(FoldingContext &context)
+auto Expr<Type<TypeCategory::Character, KIND>>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar<Result>> {
}
template<int KIND>
-auto LogicalExpr<KIND>::Not::FoldScalar(FoldingContext &context,
- const Scalar<Result> &x) -> std::optional<Scalar<Result>> {
+auto Expr<Type<TypeCategory::Logical, 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(
+auto Expr<Type<TypeCategory::Logical, 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(
+auto Expr<Type<TypeCategory::Logical, 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(
+auto Expr<Type<TypeCategory::Logical, 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(
+auto Expr<Type<TypeCategory::Logical, 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)
+auto Expr<Type<TypeCategory::Logical, KIND>>::Fold(FoldingContext &context)
-> std::optional<Scalar<Result>> {
return std::visit(
[&](auto &x) -> std::optional<Scalar<Result>> {
// and manipulation in place.
#include "common.h"
-#include "expression-forward.h"
#include "type.h"
#include "variable.h"
#include "../lib/common/idioms.h"
namespace Fortran::evaluate {
+template<typename A> class Expr;
+
+// An expression whose result is within one particular type category and
+// of any supported kind.
+using SomeKindIntegerExpr = Expr<SomeKind<TypeCategory::Integer>>;
+using SomeKindRealExpr = Expr<SomeKind<TypeCategory::Real>>;
+using SomeKindComplexExpr = Expr<SomeKind<TypeCategory::Complex>>;
+using SomeKindCharacterExpr = Expr<SomeKind<TypeCategory::Character>>;
+using SomeKindLogicalExpr = Expr<SomeKind<TypeCategory::Logical>>;
+
// Helper base classes for packaging subexpressions.
template<typename CRTP, typename RESULT, typename A = RESULT> class Unary {
public:
Expr(const SomeKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
Expr(SomeKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
template<int K>
- Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{SomeKindIntegerExpr{x}}} {}
+ Expr(const Expr<Type<TypeCategory::Integer, K>> &x)
+ : u_{ConvertInteger{SomeKindIntegerExpr{x}}} {}
template<int K>
- Expr(IntegerExpr<K> &&x)
+ Expr(Expr<Type<TypeCategory::Integer, K>> &&x)
: u_{ConvertInteger{SomeKindIntegerExpr{std::move(x)}}} {}
Expr(const SomeKindRealExpr &x) : u_{ConvertReal{x}} {}
Expr(SomeKindRealExpr &&x) : u_{ConvertReal{std::move(x)}} {}
template<int K>
- Expr(const RealExpr<K> &x) : u_{ConvertReal{SomeKindRealExpr{x}}} {}
+ Expr(const Expr<Type<TypeCategory::Real, K>> &x)
+ : u_{ConvertReal{SomeKindRealExpr{x}}} {}
template<int K>
- Expr(RealExpr<K> &&x) : u_{ConvertReal{SomeKindRealExpr{std::move(x)}}} {}
+ Expr(Expr<Type<TypeCategory::Real, K>> &&x)
+ : u_{ConvertReal{SomeKindRealExpr{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> &&
Expr(const SomeKindIntegerExpr &x) : u_{ConvertInteger{x}} {}
Expr(SomeKindIntegerExpr &&x) : u_{ConvertInteger{std::move(x)}} {}
template<int K>
- Expr(const IntegerExpr<K> &x) : u_{ConvertInteger{SomeKindIntegerExpr{x}}} {}
+ Expr(const Expr<Type<TypeCategory::Integer, K>> &x)
+ : u_{ConvertInteger{SomeKindIntegerExpr{x}}} {}
template<int K>
- Expr(IntegerExpr<K> &&x)
+ Expr(Expr<Type<TypeCategory::Integer, K>> &&x)
: u_{ConvertInteger{SomeKindIntegerExpr{std::move(x)}}} {}
Expr(const SomeKindRealExpr &x) : u_{ConvertReal{x}} {}
Expr(SomeKindRealExpr &&x) : u_{ConvertReal{std::move(x)}} {}
template<int K>
- Expr(const RealExpr<K> &x) : u_{ConvertReal{SomeKindRealExpr{x}}} {}
+ Expr(const Expr<Type<TypeCategory::Real, K>> &x)
+ : u_{ConvertReal{SomeKindRealExpr{x}}} {}
template<int K>
- Expr(RealExpr<K> &&x) : u_{ConvertReal{SomeKindRealExpr{std::move(x)}}} {}
+ Expr(Expr<Type<TypeCategory::Real, K>> &&x)
+ : u_{ConvertReal{SomeKindRealExpr{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)} {}
#undef BINARY
#define BINARY(FUNC, OP) \
- template<typename A> LogicalExpr<1> FUNC(const A &x, const A &y) { \
+ template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
return {Comparison<ResultType<A>>{OP, x, y}}; \
} \
template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, LogicalExpr<1>> FUNC( \
+ std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
const A &x, A &&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( \
+ std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, const A &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( \
+ std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
A &&x, A &&y) { \
return {Comparison<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
}