#include "expression.h"
#include "common.h"
#include "int-power.h"
+#include "tools.h"
#include "variable.h"
#include "../common/idioms.h"
#include "../parser/characters.h"
// wrap discriminated unions.
template<typename A> class Expr;
+template<typename A> using ResultType = typename std::decay_t<A>::Result;
+
template<typename DERIVED, typename RESULT, typename... OPERAND>
class Operation {
public:
u;
};
-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.
-
-template<TypeCategory C, int K>
-Expr<Type<C, K>> operator-(const Expr<Type<C, K>> &x) {
- return {Negate<Type<C, K>>{x}};
-}
-template<TypeCategory C>
-Expr<SomeKind<C>> operator-(const Expr<SomeKind<C>> &x) {
- return std::visit(
- [](const auto &y) -> Expr<SomeKind<C>> { return {-y}; }, x.u);
-}
-
-#define BINARY(op, CONSTR) \
- template<TypeCategory C, int K> \
- Expr<Type<C, K>> operator op( \
- const Expr<Type<C, K>> &x, const Expr<Type<C, K>> &y) { \
- return {CONSTR<Type<C, K>>{x, y}}; \
- } \
- template<TypeCategory C> \
- Expr<SomeKind<C>> operator op( \
- const Expr<SomeKind<C>> &x, const Expr<SomeKind<C>> &y) { \
- return std::visit( \
- [](const auto &xk, const auto &yk) -> Expr<SomeKind<C>> { \
- return {xk op yk}; \
- }, \
- x.u, y.u); \
- }
-
-BINARY(+, Add)
-BINARY(-, Subtract)
-BINARY(*, Multiply)
-BINARY(/, Divide)
-#undef BINARY
-
-#if 0
-#define OLDBINARY(FUNC, CONSTR) \
- template<typename A> A FUNC(const A &x, const A &y) { \
- return {CONSTR<typename A::Result>{x, y}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, A> FUNC(const A &x, A &&y) { \
- return {CONSTR<typename A::Result>{A{x}, std::move(y)}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, const A &y) { \
- return {CONSTR<typename A::Result>{std::move(x), A{y}}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, A> FUNC(A &&x, A &&y) { \
- return {CONSTR<typename A::Result>{std::move(x), std::move(y)}}; \
- }
-#undef OLDBINARY
-#endif
-
-#define BINARY(FUNC, OP) \
- template<typename A> Expr<LogicalResult> FUNC(const A &x, const A &y) { \
- return {Relational<ResultType<A>>{OP, x, y}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
- const A &x, A &&y) { \
- return {Relational<ResultType<A>>{OP, x, std::move(y)}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
- A &&x, const A &y) { \
- return {Relational<ResultType<A>>{OP, std::move(x), y}}; \
- } \
- template<typename A> \
- std::enable_if_t<!std::is_reference_v<A>, Expr<LogicalResult>> FUNC( \
- A &&x, A &&y) { \
- return {Relational<ResultType<A>>{OP, std::move(x), std::move(y)}}; \
- }
-
-BINARY(operator<, RelationalOperator::LT)
-BINARY(operator<=, RelationalOperator::LE)
-BINARY(operator==, RelationalOperator::EQ)
-BINARY(operator!=, RelationalOperator::NE)
-BINARY(operator>=, RelationalOperator::GE)
-BINARY(operator>, RelationalOperator::GT)
-#undef BINARY
-
extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO others
extern template struct Relational<Type<TypeCategory::Integer, 1>>;
extern template struct Relational<Type<TypeCategory::Integer, 2>>;
namespace Fortran::evaluate {
-Expr<SomeReal> ConvertToTypeOf(
- const Expr<SomeReal> &to, const Expr<SomeInteger> &from) {
- return std::visit(
- [&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
-}
-
-Expr<SomeReal> ConvertToTypeOf(
- const Expr<SomeReal> &to, const Expr<SomeReal> &from) {
- return std::visit(
- [&](const auto &rk) { return Expr<SomeReal>{decltype(rk){to}}; }, to.u);
-}
-
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
- parser::ContextualMessages &messages, GenericExpr &&x, GenericExpr &&y) {
+ parser::ContextualMessages &messages, Expr<SomeType> &&x,
+ Expr<SomeType> &&y) {
return std::visit(
common::visitors{[&](Expr<SomeInteger> &&ix, Expr<SomeInteger> &&iy) {
// Can happen in a CMPLX() constructor. Per F'2018,
Expr<SomeReal>{Expr<DefaultReal>{std::move(iy)}})};
},
[&](Expr<SomeInteger> &&ix, Expr<SomeReal> &&ry) {
- auto rx{ConvertToTypeOf(ry, std::move(ix))};
+ auto rx{ConvertToTypeAndKindOf(ry, std::move(ix))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](Expr<SomeReal> &&rx, Expr<SomeInteger> &&iy) {
- auto ry{ConvertToTypeOf(rx, std::move(iy))};
+ auto ry{ConvertToTypeAndKindOf(rx, std::move(iy))};
return std::optional{std::make_pair(std::move(rx), std::move(ry))};
},
[&](Expr<SomeReal> &&rx, Expr<SomeReal> &&ry) {
}
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>> ConvertRealOperands(
- parser::ContextualMessages &messages, std::optional<GenericExpr> &&x,
- std::optional<GenericExpr> &&y) {
+ parser::ContextualMessages &messages, std::optional<Expr<SomeType>> &&x,
+ std::optional<Expr<SomeType>> &&y) {
if (x.has_value() && y.has_value()) {
return ConvertRealOperands(messages, std::move(*x), std::move(*y));
}
namespace Fortran::evaluate {
-// Convert the second argument to the same type and kind of the first.
-Expr<SomeReal> ConvertToTypeOf(
- const Expr<SomeReal> &to, const Expr<SomeInteger> &from);
-Expr<SomeReal> ConvertToTypeOf(
- const Expr<SomeReal> &to, const Expr<SomeReal> &from);
+// Convenience functions and operator overloadings for expression construction.
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x) {
+ return {Negate<Type<C, K>>{std::move(x)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator+(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+ return {Add<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator-(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+ return {Subtract<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator*(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+ return {Multiply<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C, int K>
+Expr<Type<C, K>> operator/(Expr<Type<C, K>> &&x, Expr<Type<C, K>> &&y) {
+ return {Divide<Type<C, K>>{std::move(x), std::move(y)}};
+}
+
+template<TypeCategory C> Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x) {
+ return std::visit(
+ [](auto &xk) { return Expr<SomeKind<C>>{-std::move(xk)}; }, x.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator+(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+ return std::visit(
+ [](auto &xk, auto &yk) {
+ return Expr<SomeKind<C>>{std::move(xk) + std::move(yk)};
+ },
+ x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator-(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+ return std::visit(
+ [](auto &xk, auto &yk) {
+ return Expr<SomeKind<C>>{std::move(xk) - std::move(yk)};
+ },
+ x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator*(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+ return std::visit(
+ [](auto &xk, auto &yk) {
+ return Expr<SomeKind<C>>{std::move(xk) * std::move(yk)};
+ },
+ x.u, y.u);
+}
+
+template<TypeCategory C>
+Expr<SomeKind<C>> operator/(Expr<SomeKind<C>> &&x, Expr<SomeKind<C>> &&y) {
+ return std::visit(
+ [](auto &xk, auto &yk) {
+ return Expr<SomeKind<C>>{std::move(xk) / std::move(yk)};
+ },
+ x.u, y.u);
+}
+
+// Convert the second argument expression to an expression of the same type
+// and kind as that of the first.
+template<TypeCategory TC, typename F>
+Expr<SomeKind<TC>> ConvertToTypeAndKindOf(
+ const Expr<SomeKind<TC>> &to, Expr<F> &&from) {
+ return std::visit(
+ [&](const auto &tk) -> Expr<SomeKind<TC>> {
+ using SpecificExpr = std::decay_t<decltype(tk)>;
+ return {SpecificExpr{std::move(from)}};
+ },
+ to.u);
+}
// Ensure that both operands of an intrinsic REAL operation or CMPLX()
// are INTEGER or REAL, and convert them as necessary to the same REAL type.
using ConvertRealOperandsResult =
std::optional<std::pair<Expr<SomeReal>, Expr<SomeReal>>>;
ConvertRealOperandsResult ConvertRealOperands(
- parser::ContextualMessages &, GenericExpr &&, GenericExpr &&);
+ parser::ContextualMessages &, Expr<SomeType> &&, Expr<SomeType> &&);
template<TypeCategory CAT>
void ConvertToSameKind(Expr<SomeKind<CAT>> &x, Expr<SomeKind<CAT>> &y) {
// limitations under the License.
#include "variable.h"
+#include "tools.h"
#include "../common/idioms.h"
#include "../parser/char-block.h"
#include "../parser/characters.h"
using common::TypeCategory;
using evaluate::Expr;
-using evaluate::GenericExpr;
+using evaluate::SomeType;
using evaluate::Type;
using MaybeIntExpr = std::optional<Expr<evaluate::SomeInteger>>;
}
template<typename A> MaybeExpr PackageGeneric(std::optional<A> &&x) {
- std::function<GenericExpr(A &&)> f{
- [](A &&y) { return GenericExpr{std::move(y)}; }};
+ std::function<Expr<SomeType>(A &&)> f{
+ [](A &&y) { return Expr<SomeType>{std::move(y)}; }};
return common::MapOptional(f, std::move(x));
}
evaluate::CopyableIndirection<evaluate::Substring> ind{std::move(substring)};
Expr<evaluate::DefaultCharacter> chExpr{std::move(ind)};
chExpr.Fold(ea.context());
- return {GenericExpr{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
+ return {Expr<SomeType>{Expr<evaluate::SomeCharacter>{std::move(chExpr)}}};
}
// Common handling of parser::IntLiteralConstant and SignedIntLiteralConstant
AnalyzeLiteral(ea, std::get<parser::RealLiteralConstant>(x.t))}) {
if (auto sign{std::get<std::optional<parser::Sign>>(x.t)}) {
if (sign == parser::Sign::Negative) {
- return {-*result};
+ return {-std::move(*result)};
}
}
return result;
std::optional<Expr<evaluate::SomeComplex>> ExpressionAnalyzer::ConstructComplex(
MaybeExpr &&real, MaybeExpr &&imaginary) {
// TODO: pmk abstract further, this will be a common pattern
- auto partial{[&](GenericExpr &&x, GenericExpr &&y) {
+ auto partial{[&](Expr<SomeType> &&x, Expr<SomeType> &&y) {
return evaluate::ConvertRealOperands(
context_.messages, std::move(x), std::move(y));
}};
using fType =
- evaluate::ConvertRealOperandsResult(GenericExpr &&, GenericExpr &&);
+ evaluate::ConvertRealOperandsResult(Expr<SomeType> &&, Expr<SomeType> &&);
std::function<fType> f{partial};
auto converted{common::MapOptional(f, std::move(real), std::move(imaginary))};
if (auto joined{common::JoinOptionals(std::move(converted))}) {
namespace Fortran::semantics {
-using MaybeExpr = std::optional<evaluate::GenericExpr>;
+using MaybeExpr = std::optional<evaluate::Expr<evaluate::SomeType>>;
class ExpressionAnalyzer {
public:
// limitations under the License.
#include "../../lib/evaluate/expression.h"
+#include "../../lib/evaluate/tools.h"
#include "testing.h"
#include "../../lib/parser/message.h"
#include <cstdio>
FoldingContext context{messages};
ex1.Fold(context);
MATCH("-10_4", Dump(ex1));
- MATCH("(6_4.LE.7_4)",
- Dump(DefaultIntegerExpr{6} <= DefaultIntegerExpr{7}));
+ MATCH("(1_4/2_4)", Dump(DefaultIntegerExpr{1} / DefaultIntegerExpr{2}));
DefaultIntegerExpr a{1};
DefaultIntegerExpr b{2};
- MATCH("(1_4/2_4)", Dump(a / b));
MATCH("1_4", Dump(a));
a = b;
MATCH("2_4", Dump(a));