2019-01-29 23:31:47 +01:00
|
|
|
// Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
|
2018-06-18 21:09:56 +02:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#ifndef FORTRAN_EVALUATE_EXPRESSION_H_
|
|
|
|
#define FORTRAN_EVALUATE_EXPRESSION_H_
|
|
|
|
|
2018-06-22 20:02:54 +02:00
|
|
|
// Represent Fortran expressions in a type-safe manner.
|
2018-06-22 22:40:56 +02:00
|
|
|
// Expressions are the sole owners of their constituents; i.e., there is no
|
2018-09-12 20:20:30 +02:00
|
|
|
// context-independent hash table or sharing of common subexpressions, and
|
|
|
|
// thus these are trees, not DAGs. Both deep copy and move semantics are
|
2019-01-04 23:05:53 +01:00
|
|
|
// supported for expression construction. Expressions may be compared
|
|
|
|
// for equality.
|
2018-06-22 20:02:54 +02:00
|
|
|
|
2018-06-19 23:16:01 +02:00
|
|
|
#include "common.h"
|
2019-01-28 23:38:17 +01:00
|
|
|
#include "constant.h"
|
2018-06-18 21:09:56 +02:00
|
|
|
#include "type.h"
|
2018-07-07 00:12:33 +02:00
|
|
|
#include "variable.h"
|
2019-02-28 19:48:41 +01:00
|
|
|
#include "../lib/common/Fortran.h"
|
2018-07-05 23:19:19 +02:00
|
|
|
#include "../lib/common/idioms.h"
|
2018-09-15 00:48:40 +02:00
|
|
|
#include "../lib/common/template.h"
|
2018-06-22 23:51:15 +02:00
|
|
|
#include "../lib/parser/char-block.h"
|
|
|
|
#include "../lib/parser/message.h"
|
2018-10-24 01:48:06 +02:00
|
|
|
#include <algorithm>
|
2019-01-23 01:30:32 +01:00
|
|
|
#include <list>
|
2018-06-20 20:55:10 +02:00
|
|
|
#include <ostream>
|
2018-08-15 22:46:33 +02:00
|
|
|
#include <tuple>
|
2018-08-29 00:15:18 +02:00
|
|
|
#include <type_traits>
|
2018-06-18 21:09:56 +02:00
|
|
|
#include <variant>
|
|
|
|
|
|
|
|
namespace Fortran::evaluate {
|
|
|
|
|
2018-08-17 18:50:32 +02:00
|
|
|
using common::RelationalOperator;
|
|
|
|
|
2018-09-08 00:25:10 +02:00
|
|
|
// Expressions are represented by specializations of the class template Expr.
|
2018-08-29 00:15:18 +02:00
|
|
|
// Each of these specializations wraps a single data member "u" that
|
2018-09-08 00:25:10 +02:00
|
|
|
// is a std::variant<> discriminated union over all of the representational
|
2018-08-29 01:35:45 +02:00
|
|
|
// types for the constants, variables, operations, and other entities that
|
2018-08-29 00:15:18 +02:00
|
|
|
// can be valid expressions in that context:
|
2018-09-08 00:25:10 +02:00
|
|
|
// - Expr<Type<CATEGORY, KIND>> represents an expression whose result is of a
|
2018-08-29 00:15:18 +02:00
|
|
|
// specific intrinsic type category and kind, e.g. Type<TypeCategory::Real, 4>
|
2018-10-09 00:35:19 +02:00
|
|
|
// - Expr<SomeDerived> wraps data and procedure references that result in an
|
|
|
|
// instance of a derived type
|
2018-08-29 00:15:18 +02:00
|
|
|
// - Expr<SomeKind<CATEGORY>> is a union of Expr<Type<CATEGORY, K>> for each
|
2018-09-08 00:25:10 +02:00
|
|
|
// kind type parameter value K in that intrinsic type category. It represents
|
|
|
|
// an expression with known category and any kind.
|
2018-08-29 00:15:18 +02:00
|
|
|
// - Expr<SomeType> is a union of Expr<SomeKind<CATEGORY>> over the five
|
2018-09-08 00:25:10 +02:00
|
|
|
// intrinsic type categories of Fortran. It represents any valid expression.
|
2018-10-09 00:35:19 +02:00
|
|
|
//
|
2018-08-29 00:15:18 +02:00
|
|
|
// Everything that can appear in, or as, a valid Fortran expression must be
|
|
|
|
// represented with an instance of some class containing a Result typedef that
|
|
|
|
// maps to some instantiation of Type<CATEGORY, KIND>, SomeKind<CATEGORY>,
|
2019-01-23 01:30:32 +01:00
|
|
|
// or SomeType. (Exception: BOZ literal constants in generic Expr<SomeType>.)
|
2018-08-20 18:29:08 +02:00
|
|
|
template<typename A> using ResultType = typename std::decay_t<A>::Result;
|
|
|
|
|
2018-10-30 20:44:09 +01:00
|
|
|
// Common Expr<> behaviors: every Expr<T> derives from ExpressionBase<T>.
|
|
|
|
template<typename RESULT> class ExpressionBase {
|
|
|
|
public:
|
|
|
|
using Result = RESULT;
|
|
|
|
|
|
|
|
private:
|
|
|
|
using Derived = Expr<Result>;
|
2019-01-03 17:45:27 +01:00
|
|
|
#if defined(__APPLE__) && defined(__GNUC__)
|
2018-12-20 18:39:29 +01:00
|
|
|
Derived &derived();
|
|
|
|
const Derived &derived() const;
|
2019-01-03 17:45:27 +01:00
|
|
|
#else
|
|
|
|
Derived &derived() { return *static_cast<Derived *>(this); }
|
|
|
|
const Derived &derived() const { return *static_cast<const Derived *>(this); }
|
|
|
|
#endif
|
2018-10-30 20:44:09 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
template<typename A> Derived &operator=(const A &x) {
|
|
|
|
Derived &d{derived()};
|
|
|
|
d.u = x;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
Derived &operator=(std::enable_if_t<!std::is_reference_v<A>, A> &&x) {
|
|
|
|
Derived &d{derived()};
|
|
|
|
d.u = std::move(x);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<DynamicType> GetType() const;
|
|
|
|
int Rank() const;
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
2018-10-30 20:44:09 +01:00
|
|
|
static Derived Rewrite(FoldingContext &, Derived &&);
|
|
|
|
};
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
// Operations always have specific Fortran result types (i.e., with known
|
|
|
|
// intrinsic type category and kind parameter value). The classes that
|
|
|
|
// represent the operations all inherit from this Operation<> base class
|
|
|
|
// template. Note that Operation has as its first type parameter (DERIVED) a
|
|
|
|
// "curiously reoccurring template pattern (CRTP)" reference to the specific
|
|
|
|
// operation class being derived from Operation; e.g., Add is defined with
|
|
|
|
// struct Add : public Operation<Add, ...>. Uses of instances of Operation<>,
|
|
|
|
// including its own member functions, can access each specific class derived
|
|
|
|
// from it via its derived() member function with compile-time type safety.
|
2018-08-29 00:15:18 +02:00
|
|
|
template<typename DERIVED, typename RESULT, typename... OPERANDS>
|
2018-08-15 22:46:33 +02:00
|
|
|
class Operation {
|
2019-01-17 22:52:10 +01:00
|
|
|
// The extra final member is a dummy that allows a safe unused reference
|
2018-09-07 19:33:32 +02:00
|
|
|
// to element 1 to arise indirectly in the definition of "right()" below
|
|
|
|
// when the operation has but a single operand.
|
2019-01-17 22:52:10 +01:00
|
|
|
using OperandTypes = std::tuple<OPERANDS..., std::monostate>;
|
2018-08-29 00:15:18 +02:00
|
|
|
|
2018-08-15 22:46:33 +02:00
|
|
|
public:
|
|
|
|
using Derived = DERIVED;
|
|
|
|
using Result = RESULT;
|
2018-11-29 19:25:46 +01:00
|
|
|
static_assert(IsSpecificIntrinsicType<Result>);
|
2018-09-07 19:33:32 +02:00
|
|
|
static constexpr std::size_t operands{sizeof...(OPERANDS)};
|
2018-08-15 22:46:33 +02:00
|
|
|
template<int J> using Operand = std::tuple_element_t<J, OperandTypes>;
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// Unary operations wrap a single Expr with a CopyableIndirection.
|
|
|
|
// Binary operations wrap a tuple of CopyableIndirections to Exprs.
|
|
|
|
private:
|
|
|
|
using Container =
|
2018-09-07 19:33:32 +02:00
|
|
|
std::conditional_t<operands == 1, CopyableIndirection<Expr<Operand<0>>>,
|
2018-08-29 00:15:18 +02:00
|
|
|
std::tuple<CopyableIndirection<Expr<OPERANDS>>...>>;
|
2018-08-16 20:46:18 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
public:
|
2018-08-15 22:46:33 +02:00
|
|
|
CLASS_BOILERPLATE(Operation)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Operation(const Expr<OPERANDS> &... x) : operand_{x...} {}
|
|
|
|
explicit Operation(Expr<OPERANDS> &&... x)
|
2018-08-29 00:15:18 +02:00
|
|
|
: operand_{std::forward<Expr<OPERANDS>>(x)...} {}
|
|
|
|
|
|
|
|
Derived &derived() { return *static_cast<Derived *>(this); }
|
|
|
|
const Derived &derived() const { return *static_cast<const Derived *>(this); }
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
// References to operand expressions from member functions of derived
|
|
|
|
// classes for specific operators can be made by index, e.g. operand<0>(),
|
|
|
|
// which must be spelled like "this->template operand<0>()" when
|
|
|
|
// inherited in a derived class template. There are convenience aliases
|
|
|
|
// left() and right() that are not templates.
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int J> Expr<Operand<J>> &operand() {
|
2018-09-07 19:33:32 +02:00
|
|
|
if constexpr (operands == 1) {
|
2018-08-29 00:15:18 +02:00
|
|
|
static_assert(J == 0);
|
2019-03-05 21:28:08 +01:00
|
|
|
return operand_.value();
|
2018-08-29 00:15:18 +02:00
|
|
|
} else {
|
2019-03-05 21:28:08 +01:00
|
|
|
return std::get<J>(operand_).value();
|
2018-08-29 00:15:18 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-15 22:46:33 +02:00
|
|
|
template<int J> const Expr<Operand<J>> &operand() const {
|
2018-09-07 19:33:32 +02:00
|
|
|
if constexpr (operands == 1) {
|
2018-08-29 00:15:18 +02:00
|
|
|
static_assert(J == 0);
|
2019-03-05 21:28:08 +01:00
|
|
|
return operand_.value();
|
2018-08-29 00:15:18 +02:00
|
|
|
} else {
|
2019-03-05 21:28:08 +01:00
|
|
|
return std::get<J>(operand_).value();
|
2018-08-29 00:15:18 +02:00
|
|
|
}
|
2018-08-15 22:46:33 +02:00
|
|
|
}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
Expr<Operand<0>> &left() { return operand<0>(); }
|
|
|
|
const Expr<Operand<0>> &left() const { return operand<0>(); }
|
|
|
|
|
|
|
|
std::conditional_t<(operands > 1), Expr<Operand<1>> &, void> right() {
|
|
|
|
if constexpr (operands > 1) {
|
|
|
|
return operand<1>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::conditional_t<(operands > 1), const Expr<Operand<1>> &, void>
|
|
|
|
right() const {
|
|
|
|
if constexpr (operands > 1) {
|
|
|
|
return operand<1>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-09 00:35:19 +02:00
|
|
|
static constexpr std::optional<DynamicType> GetType() {
|
|
|
|
return Result::GetType();
|
|
|
|
}
|
2018-09-18 18:34:59 +02:00
|
|
|
int Rank() const {
|
|
|
|
int rank{left().Rank()};
|
|
|
|
if constexpr (operands > 1) {
|
2018-10-24 01:48:06 +02:00
|
|
|
return std::max(rank, right().Rank());
|
|
|
|
} else {
|
|
|
|
return rank;
|
2018-09-18 18:34:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const Operation &that) const {
|
|
|
|
return operand_ == that.operand_;
|
|
|
|
}
|
|
|
|
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
2018-08-15 22:46:33 +02:00
|
|
|
|
|
|
|
protected:
|
2018-11-06 00:02:37 +01:00
|
|
|
// Overridable functions for AsFortran()
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Prefix(std::ostream &o) { return o << '('; }
|
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << ','; }
|
|
|
|
static std::ostream &Suffix(std::ostream &o) { return o << ')'; }
|
2018-08-15 22:46:33 +02:00
|
|
|
|
|
|
|
private:
|
2018-08-29 00:15:18 +02:00
|
|
|
Container operand_;
|
2018-08-15 22:46:33 +02:00
|
|
|
};
|
|
|
|
|
2018-08-17 18:50:32 +02:00
|
|
|
// Unary operations
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
// Conversions to specific types from expressions of known category and
|
|
|
|
// dynamic kind.
|
2019-02-20 00:38:55 +01:00
|
|
|
template<typename TO, TypeCategory FROMCAT = TO::category>
|
2018-08-29 00:15:18 +02:00
|
|
|
struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> {
|
2019-01-23 01:30:32 +01:00
|
|
|
// Fortran doesn't have conversions between kinds of CHARACTER apart from
|
|
|
|
// assignments, and in those the data must be convertible to/from 7-bit ASCII.
|
2018-09-07 19:33:32 +02:00
|
|
|
// Conversions between kinds of COMPLEX are represented piecewise.
|
|
|
|
static_assert(((TO::category == TypeCategory::Integer ||
|
|
|
|
TO::category == TypeCategory::Real) &&
|
|
|
|
(FROMCAT == TypeCategory::Integer ||
|
|
|
|
FROMCAT == TypeCategory::Real)) ||
|
2019-02-20 00:38:55 +01:00
|
|
|
(TO::category == TypeCategory::Character &&
|
|
|
|
FROMCAT == TypeCategory::Character) ||
|
2018-09-07 19:33:32 +02:00
|
|
|
(TO::category == TypeCategory::Logical &&
|
|
|
|
FROMCAT == TypeCategory::Logical));
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = TO;
|
|
|
|
using Operand = SomeKind<FROMCAT>;
|
|
|
|
using Base = Operation<Convert, Result, Operand>;
|
2018-08-16 20:46:18 +02:00
|
|
|
using Base::Base;
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
2018-08-16 20:46:18 +02:00
|
|
|
};
|
|
|
|
|
2018-08-15 22:46:33 +02:00
|
|
|
template<typename A>
|
2018-08-16 20:46:18 +02:00
|
|
|
struct Parentheses : public Operation<Parentheses<A>, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-15 22:46:33 +02:00
|
|
|
using Base = Operation<Parentheses, A, A>;
|
|
|
|
using Base::Base;
|
|
|
|
};
|
|
|
|
|
2018-08-16 20:46:18 +02:00
|
|
|
template<typename A> struct Negate : public Operation<Negate<A>, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-16 20:46:18 +02:00
|
|
|
using Base = Operation<Negate, A, A>;
|
2018-08-15 22:46:33 +02:00
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Prefix(std::ostream &o) { return o << "(-"; }
|
2018-08-15 22:46:33 +02:00
|
|
|
};
|
|
|
|
|
2018-08-17 18:50:32 +02:00
|
|
|
template<int KIND>
|
2018-08-16 20:46:18 +02:00
|
|
|
struct ComplexComponent
|
2018-08-17 18:50:32 +02:00
|
|
|
: public Operation<ComplexComponent<KIND>, Type<TypeCategory::Real, KIND>,
|
|
|
|
Type<TypeCategory::Complex, KIND>> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = Type<TypeCategory::Real, KIND>;
|
|
|
|
using Operand = Type<TypeCategory::Complex, KIND>;
|
|
|
|
using Base = Operation<ComplexComponent, Result, Operand>;
|
2018-08-17 18:50:32 +02:00
|
|
|
CLASS_BOILERPLATE(ComplexComponent)
|
2018-08-23 19:55:16 +02:00
|
|
|
ComplexComponent(bool isImaginary, const Expr<Operand> &x)
|
|
|
|
: Base{x}, isImaginaryPart{isImaginary} {}
|
|
|
|
ComplexComponent(bool isImaginary, Expr<Operand> &&x)
|
|
|
|
: Base{std::move(x)}, isImaginaryPart{isImaginary} {}
|
2018-08-17 18:50:32 +02:00
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
std::ostream &Suffix(std::ostream &o) const {
|
|
|
|
return o << (isImaginaryPart ? "%IM)" : "%RE)");
|
|
|
|
}
|
2018-08-17 18:50:32 +02:00
|
|
|
|
2018-08-23 19:55:16 +02:00
|
|
|
bool isImaginaryPart{true};
|
2018-08-16 20:46:18 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>,
|
|
|
|
Type<TypeCategory::Logical, KIND>> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = Type<TypeCategory::Logical, KIND>;
|
|
|
|
using Operand = Result;
|
|
|
|
using Base = Operation<Not, Result, Operand>;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Prefix(std::ostream &o) { return o << "(.NOT."; }
|
2018-08-17 18:50:32 +02:00
|
|
|
};
|
|
|
|
|
2019-02-28 00:51:03 +01:00
|
|
|
// Character lengths are determined by context in Fortran and do not
|
|
|
|
// have explicit syntax for changing them. Expressions represent
|
|
|
|
// changes of length (e.g., for assignments and structure constructors)
|
|
|
|
// with this operation.
|
|
|
|
template<int KIND>
|
|
|
|
struct SetLength
|
|
|
|
: public Operation<SetLength<KIND>, Type<TypeCategory::Character, KIND>,
|
|
|
|
Type<TypeCategory::Character, KIND>, SubscriptInteger> {
|
|
|
|
using Result = Type<TypeCategory::Character, KIND>;
|
|
|
|
using CharacterOperand = Result;
|
|
|
|
using LengthOperand = SubscriptInteger;
|
|
|
|
using Base = Operation<SetLength, Result, CharacterOperand, LengthOperand>;
|
|
|
|
using Base::Base;
|
|
|
|
static std::ostream &Prefix(std::ostream &o) { return o << "%SET_LENGTH("; }
|
|
|
|
};
|
|
|
|
|
2018-08-17 18:50:32 +02:00
|
|
|
// Binary operations
|
|
|
|
|
|
|
|
template<typename A> struct Add : public Operation<Add<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-17 18:50:32 +02:00
|
|
|
using Base = Operation<Add, A, A, A>;
|
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << '+'; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename A> struct Subtract : public Operation<Subtract<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Subtract, A, A, A>;
|
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << '-'; }
|
2018-06-22 20:02:54 +02:00
|
|
|
};
|
|
|
|
|
2018-08-18 00:38:37 +02:00
|
|
|
template<typename A> struct Multiply : public Operation<Multiply<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Multiply, A, A, A>;
|
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << '*'; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
2018-07-20 21:19:09 +02:00
|
|
|
|
2018-08-18 00:38:37 +02:00
|
|
|
template<typename A> struct Divide : public Operation<Divide<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Divide, A, A, A>;
|
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << '/'; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename A> struct Power : public Operation<Power<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Power, A, A, A>;
|
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << "**"; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<typename A>
|
|
|
|
struct RealToIntPower : public Operation<RealToIntPower<A>, A, A, SomeInteger> {
|
|
|
|
using Base = Operation<RealToIntPower, A, A, SomeInteger>;
|
|
|
|
using Result = A;
|
|
|
|
using BaseOperand = A;
|
|
|
|
using ExponentOperand = SomeInteger;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << "**"; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename A> struct Extremum : public Operation<Extremum<A>, A, A, A> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = A;
|
|
|
|
using Operand = A;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Extremum, A, A, A>;
|
|
|
|
CLASS_BOILERPLATE(Extremum)
|
|
|
|
Extremum(const Expr<Operand> &x, const Expr<Operand> &y,
|
|
|
|
Ordering ord = Ordering::Greater)
|
|
|
|
: Base{x, y}, ordering{ord} {}
|
|
|
|
Extremum(
|
|
|
|
Expr<Operand> &&x, Expr<Operand> &&y, Ordering ord = Ordering::Greater)
|
|
|
|
: Base{std::move(x), std::move(y)}, ordering{ord} {}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
std::ostream &Prefix(std::ostream &o) const {
|
|
|
|
return o << (ordering == Ordering::Less ? "MIN(" : "MAX(");
|
2018-08-18 00:38:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ordering ordering{Ordering::Greater};
|
|
|
|
};
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
struct ComplexConstructor
|
|
|
|
: public Operation<ComplexConstructor<KIND>,
|
|
|
|
Type<TypeCategory::Complex, KIND>, Type<TypeCategory::Real, KIND>,
|
|
|
|
Type<TypeCategory::Real, KIND>> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = Type<TypeCategory::Complex, KIND>;
|
|
|
|
using Operand = Type<TypeCategory::Real, KIND>;
|
|
|
|
using Base = Operation<ComplexConstructor, Result, Operand, Operand>;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base::Base;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
struct Concat
|
|
|
|
: public Operation<Concat<KIND>, Type<TypeCategory::Character, KIND>,
|
|
|
|
Type<TypeCategory::Character, KIND>,
|
|
|
|
Type<TypeCategory::Character, KIND>> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = Type<TypeCategory::Character, KIND>;
|
|
|
|
using Operand = Result;
|
|
|
|
using Base = Operation<Concat, Result, Operand, Operand>;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base::Base;
|
2018-09-07 19:33:32 +02:00
|
|
|
static std::ostream &Infix(std::ostream &o) { return o << "//"; }
|
2018-08-18 00:38:37 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
ENUM_CLASS(LogicalOperator, And, Or, Eqv, Neqv)
|
|
|
|
|
|
|
|
template<int KIND>
|
|
|
|
struct LogicalOperation
|
|
|
|
: public Operation<LogicalOperation<KIND>, Type<TypeCategory::Logical, KIND>,
|
|
|
|
Type<TypeCategory::Logical, KIND>, Type<TypeCategory::Logical, KIND>> {
|
2018-08-29 00:15:18 +02:00
|
|
|
using Result = Type<TypeCategory::Logical, KIND>;
|
|
|
|
using Operand = Result;
|
|
|
|
using Base = Operation<LogicalOperation, Result, Operand, Operand>;
|
2018-08-18 00:38:37 +02:00
|
|
|
CLASS_BOILERPLATE(LogicalOperation)
|
|
|
|
LogicalOperation(
|
2018-09-08 00:25:10 +02:00
|
|
|
LogicalOperator opr, const Expr<Operand> &x, const Expr<Operand> &y)
|
2018-08-18 00:38:37 +02:00
|
|
|
: Base{x, y}, logicalOperator{opr} {}
|
2018-09-08 00:25:10 +02:00
|
|
|
LogicalOperation(LogicalOperator opr, Expr<Operand> &&x, Expr<Operand> &&y)
|
2018-08-18 00:38:37 +02:00
|
|
|
: Base{std::move(x), std::move(y)}, logicalOperator{opr} {}
|
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
std::ostream &Infix(std::ostream &) const;
|
2018-08-18 00:38:37 +02:00
|
|
|
|
|
|
|
LogicalOperator logicalOperator;
|
2018-06-22 20:02:54 +02:00
|
|
|
};
|
|
|
|
|
2018-10-30 23:24:35 +01:00
|
|
|
// Array constructors
|
2019-02-09 01:35:02 +01:00
|
|
|
template<typename RESULT> class ArrayConstructorValues;
|
2018-10-30 23:24:35 +01:00
|
|
|
|
2019-01-23 01:30:32 +01:00
|
|
|
struct ImpliedDoIndex {
|
|
|
|
using Result = SubscriptInteger;
|
|
|
|
bool operator==(const ImpliedDoIndex &) const;
|
|
|
|
static constexpr int Rank() { return 0; }
|
|
|
|
parser::CharBlock name; // nested implied DOs must use distinct names
|
|
|
|
};
|
|
|
|
|
2019-03-05 21:28:08 +01:00
|
|
|
template<typename RESULT> class ImpliedDo {
|
|
|
|
public:
|
2019-01-23 01:30:32 +01:00
|
|
|
using Result = RESULT;
|
2019-03-05 21:28:08 +01:00
|
|
|
using Index = ResultType<ImpliedDoIndex>;
|
|
|
|
ImpliedDo(parser::CharBlock name, Expr<Index> &&lower, Expr<Index> &&upper,
|
|
|
|
Expr<Index> &&stride, ArrayConstructorValues<Result> &&values)
|
|
|
|
: name_{name}, lower_{std::move(lower)}, upper_{std::move(upper)},
|
|
|
|
stride_{std::move(stride)}, values_{std::move(values)} {}
|
|
|
|
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ImpliedDo)
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const ImpliedDo &) const;
|
2019-03-05 21:28:08 +01:00
|
|
|
parser::CharBlock name() const { return name_; }
|
|
|
|
Expr<Index> &lower() { return lower_.value(); }
|
|
|
|
const Expr<Index> &lower() const { return lower_.value(); }
|
|
|
|
Expr<Index> &upper() { return upper_.value(); }
|
|
|
|
const Expr<Index> &upper() const { return upper_.value(); }
|
|
|
|
Expr<Index> &stride() { return stride_.value(); }
|
|
|
|
const Expr<Index> &stride() const { return stride_.value(); }
|
|
|
|
ArrayConstructorValues<Result> &values() { return values_.value(); }
|
|
|
|
const ArrayConstructorValues<Result> &values() const {
|
|
|
|
return values_.value();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
parser::CharBlock name_;
|
|
|
|
CopyableIndirection<Expr<Index>> lower_, upper_, stride_;
|
|
|
|
CopyableIndirection<ArrayConstructorValues<Result>> values_;
|
2018-10-30 23:24:35 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename RESULT> struct ArrayConstructorValue {
|
|
|
|
using Result = RESULT;
|
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(ArrayConstructorValue)
|
2019-01-23 01:30:32 +01:00
|
|
|
std::variant<CopyableIndirection<Expr<Result>>, ImpliedDo<Result>> u;
|
2018-10-30 23:24:35 +01:00
|
|
|
};
|
|
|
|
|
2019-02-09 01:35:02 +01:00
|
|
|
template<typename RESULT> class ArrayConstructorValues {
|
|
|
|
public:
|
2018-10-30 23:24:35 +01:00
|
|
|
using Result = RESULT;
|
2019-02-09 01:35:02 +01:00
|
|
|
using Values = std::vector<ArrayConstructorValue<Result>>;
|
2019-01-23 01:30:32 +01:00
|
|
|
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructorValues)
|
|
|
|
ArrayConstructorValues() {}
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const ArrayConstructorValues &) const;
|
2019-02-09 01:35:02 +01:00
|
|
|
static constexpr int Rank() { return 1; }
|
|
|
|
template<typename A> void Push(A &&x) { values_.emplace_back(std::move(x)); }
|
|
|
|
Values &values() { return values_; }
|
|
|
|
const Values &values() const { return values_; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Values values_;
|
2018-10-30 23:24:35 +01:00
|
|
|
};
|
|
|
|
|
2019-02-09 01:35:02 +01:00
|
|
|
template<typename RESULT>
|
|
|
|
class ArrayConstructor : public ArrayConstructorValues<RESULT> {
|
|
|
|
public:
|
2018-10-30 23:24:35 +01:00
|
|
|
using Result = RESULT;
|
2019-02-09 01:35:02 +01:00
|
|
|
using Base = ArrayConstructorValues<Result>;
|
|
|
|
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor)
|
|
|
|
explicit ArrayConstructor(Base &&values) : Base{std::move(values)} {}
|
2019-02-08 19:39:10 +01:00
|
|
|
static constexpr DynamicType GetType() { return Result::GetType(); }
|
2019-01-23 01:30:32 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<int KIND>
|
2019-02-09 01:35:02 +01:00
|
|
|
class ArrayConstructor<Type<TypeCategory::Character, KIND>>
|
|
|
|
: public ArrayConstructorValues<Type<TypeCategory::Character, KIND>> {
|
|
|
|
public:
|
2019-01-23 01:30:32 +01:00
|
|
|
using Result = Type<TypeCategory::Character, KIND>;
|
2019-02-09 01:35:02 +01:00
|
|
|
using Base = ArrayConstructorValues<Result>;
|
2019-01-23 01:30:32 +01:00
|
|
|
CLASS_BOILERPLATE(ArrayConstructor)
|
2019-02-09 01:35:02 +01:00
|
|
|
ArrayConstructor(Expr<SubscriptInteger> &&len, Base &&v)
|
|
|
|
: Base{std::move(v)}, length_{std::move(len)} {}
|
|
|
|
bool operator==(const ArrayConstructor &) const;
|
2019-01-23 01:30:32 +01:00
|
|
|
static constexpr DynamicType GetType() { return Result::GetType(); }
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
2019-03-05 21:28:08 +01:00
|
|
|
const Expr<SubscriptInteger> &LEN() const { return length_.value(); }
|
2018-11-01 20:39:09 +01:00
|
|
|
|
2019-02-09 01:35:02 +01:00
|
|
|
private:
|
|
|
|
CopyableIndirection<Expr<SubscriptInteger>> length_;
|
2019-02-08 19:39:10 +01:00
|
|
|
};
|
|
|
|
|
2019-02-09 01:35:02 +01:00
|
|
|
template<>
|
|
|
|
class ArrayConstructor<SomeDerived>
|
|
|
|
: public ArrayConstructorValues<SomeDerived> {
|
|
|
|
public:
|
2019-02-08 19:39:10 +01:00
|
|
|
using Result = SomeDerived;
|
2019-02-09 01:35:02 +01:00
|
|
|
using Base = ArrayConstructorValues<Result>;
|
2019-02-08 19:39:10 +01:00
|
|
|
CLASS_BOILERPLATE(ArrayConstructor)
|
2019-02-09 01:35:02 +01:00
|
|
|
ArrayConstructor(const semantics::DerivedTypeSpec &spec, Base &&v)
|
|
|
|
: Base{std::move(v)}, derivedTypeSpec_{&spec} {}
|
|
|
|
bool operator==(const ArrayConstructor &) const;
|
2019-02-08 19:39:10 +01:00
|
|
|
const semantics::DerivedTypeSpec &derivedTypeSpec() const {
|
|
|
|
return *derivedTypeSpec_;
|
|
|
|
}
|
2019-02-27 00:59:25 +01:00
|
|
|
DynamicType GetType() const { return DynamicType{derivedTypeSpec()}; }
|
2019-02-08 19:39:10 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
2019-02-09 01:35:02 +01:00
|
|
|
|
|
|
|
private:
|
2019-02-08 19:39:10 +01:00
|
|
|
const semantics::DerivedTypeSpec *derivedTypeSpec_;
|
2018-10-30 23:24:35 +01:00
|
|
|
};
|
|
|
|
|
2019-01-04 23:05:53 +01:00
|
|
|
// Expression representations for each type category.
|
2018-07-20 21:19:09 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int KIND>
|
|
|
|
class Expr<Type<TypeCategory::Integer, KIND>>
|
|
|
|
: public ExpressionBase<Type<TypeCategory::Integer, KIND>> {
|
2018-07-12 01:36:43 +02:00
|
|
|
public:
|
2018-08-01 18:45:59 +02:00
|
|
|
using Result = Type<TypeCategory::Integer, KIND>;
|
2018-06-18 21:09:56 +02:00
|
|
|
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
2018-10-11 00:27:17 +02:00
|
|
|
template<typename INT>
|
|
|
|
explicit Expr(std::enable_if_t<std::is_integral_v<INT>, INT> n)
|
|
|
|
: u{Constant<Result>{n}} {}
|
2018-06-21 21:47:28 +02:00
|
|
|
|
2018-07-12 01:36:43 +02:00
|
|
|
private:
|
2019-01-23 01:30:32 +01:00
|
|
|
using Conversions = std::tuple<Convert<Result, TypeCategory::Integer>,
|
2018-10-11 00:27:17 +02:00
|
|
|
Convert<Result, TypeCategory::Real>>;
|
2019-01-23 01:30:32 +01:00
|
|
|
using Operations = std::tuple<Parentheses<Result>, Negate<Result>,
|
2018-10-11 00:27:17 +02:00
|
|
|
Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
|
|
|
|
Power<Result>, Extremum<Result>>;
|
2019-01-23 01:30:32 +01:00
|
|
|
using Indices = std::conditional_t<KIND == ImpliedDoIndex::Result::kind,
|
|
|
|
std::tuple<ImpliedDoIndex>, std::tuple<>>;
|
|
|
|
using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
|
2019-01-04 23:05:53 +01:00
|
|
|
TypeParamInquiry<KIND>, Designator<Result>, FunctionRef<Result>>;
|
2018-08-29 00:15:18 +02:00
|
|
|
|
|
|
|
public:
|
2019-01-23 01:30:32 +01:00
|
|
|
common::TupleToVariant<
|
|
|
|
common::CombineTuples<Operations, Conversions, Indices, Others>>
|
|
|
|
u;
|
2018-10-11 00:27:17 +02:00
|
|
|
};
|
2018-06-19 23:16:01 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int KIND>
|
|
|
|
class Expr<Type<TypeCategory::Real, KIND>>
|
|
|
|
: public ExpressionBase<Type<TypeCategory::Real, KIND>> {
|
2018-07-12 01:36:43 +02:00
|
|
|
public:
|
2018-08-01 18:45:59 +02:00
|
|
|
using Result = Type<TypeCategory::Real, KIND>;
|
2018-08-16 20:46:18 +02:00
|
|
|
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
|
2018-07-12 01:36:43 +02:00
|
|
|
private:
|
2018-08-29 00:15:18 +02:00
|
|
|
// N.B. Real->Complex and Complex->Real conversions are done with CMPLX
|
|
|
|
// and part access operations (resp.). Conversions between kinds of
|
|
|
|
// Complex are done via decomposition to Real and reconstruction.
|
|
|
|
using Conversions = std::variant<Convert<Result, TypeCategory::Integer>,
|
|
|
|
Convert<Result, TypeCategory::Real>>;
|
|
|
|
using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>,
|
|
|
|
Negate<Result>, Add<Result>, Subtract<Result>, Multiply<Result>,
|
|
|
|
Divide<Result>, Power<Result>, RealToIntPower<Result>, Extremum<Result>>;
|
2018-10-31 00:25:10 +01:00
|
|
|
using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
|
|
|
|
Designator<Result>, FunctionRef<Result>>;
|
2018-08-29 00:15:18 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
common::CombineVariants<Operations, Conversions, Others> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int KIND>
|
|
|
|
class Expr<Type<TypeCategory::Complex, KIND>>
|
|
|
|
: public ExpressionBase<Type<TypeCategory::Complex, KIND>> {
|
2018-07-12 01:36:43 +02:00
|
|
|
public:
|
2018-08-01 18:45:59 +02:00
|
|
|
using Result = Type<TypeCategory::Complex, KIND>;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
|
2018-09-08 00:25:10 +02:00
|
|
|
// Note that many COMPLEX operations are represented as REAL operations
|
|
|
|
// over their components (viz., conversions, negation, add, and subtract).
|
|
|
|
using Operations =
|
|
|
|
std::variant<Parentheses<Result>, Multiply<Result>, Divide<Result>,
|
|
|
|
Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
|
2018-10-31 00:25:10 +01:00
|
|
|
using Others = std::variant<Constant<Result>, ArrayConstructor<Result>,
|
|
|
|
Designator<Result>, FunctionRef<Result>>;
|
2018-08-29 00:15:18 +02:00
|
|
|
|
|
|
|
public:
|
|
|
|
common::CombineVariants<Operations, Others> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_INTEGER_KIND(extern template class Expr)
|
|
|
|
FOR_EACH_REAL_KIND(extern template class Expr)
|
|
|
|
FOR_EACH_COMPLEX_KIND(extern template class Expr)
|
2018-08-16 20:46:18 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int KIND>
|
|
|
|
class Expr<Type<TypeCategory::Character, KIND>>
|
|
|
|
: public ExpressionBase<Type<TypeCategory::Character, KIND>> {
|
2018-07-12 01:36:43 +02:00
|
|
|
public:
|
2018-08-01 18:45:59 +02:00
|
|
|
using Result = Type<TypeCategory::Character, KIND>;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
explicit Expr(Scalar<Result> &&x) : u{Constant<Result>{std::move(x)}} {}
|
2018-06-22 00:35:25 +02:00
|
|
|
|
2018-08-14 22:39:59 +02:00
|
|
|
Expr<SubscriptInteger> LEN() const;
|
2018-06-22 00:35:25 +02:00
|
|
|
|
2018-11-03 00:42:45 +01:00
|
|
|
std::variant<Constant<Result>, ArrayConstructor<Result>, Designator<Result>,
|
2019-02-20 00:38:55 +01:00
|
|
|
FunctionRef<Result>, Parentheses<Result>, Convert<Result>, Concat<KIND>,
|
2019-02-28 00:51:03 +01:00
|
|
|
Extremum<Result>, SetLength<KIND>>
|
2018-08-29 00:15:18 +02:00
|
|
|
u;
|
2018-06-22 00:35:25 +02:00
|
|
|
};
|
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_CHARACTER_KIND(extern template class Expr)
|
2018-08-29 01:35:45 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// The Relational class template is a helper for constructing logical
|
2018-06-22 22:00:13 +02:00
|
|
|
// expressions with polymorphism over the cross product of the possible
|
|
|
|
// categories and kinds of comparable operands.
|
2018-08-18 00:38:37 +02:00
|
|
|
// Fortran defines a numeric relation with distinct types or kinds as
|
2018-09-08 00:25:10 +02:00
|
|
|
// first undergoing the same operand conversions that occur with the intrinsic
|
|
|
|
// addition operator. Character relations must have the same kind.
|
2018-08-29 00:15:18 +02:00
|
|
|
// There are no relations between LOGICAL values.
|
2018-06-21 20:03:00 +02:00
|
|
|
|
2018-07-24 00:04:08 +02:00
|
|
|
template<typename A>
|
2018-08-18 00:38:37 +02:00
|
|
|
struct Relational : public Operation<Relational<A>, LogicalResult, A, A> {
|
2018-10-24 23:06:46 +02:00
|
|
|
using Result = LogicalResult;
|
2018-08-18 00:38:37 +02:00
|
|
|
using Base = Operation<Relational, LogicalResult, A, A>;
|
2018-08-17 18:50:32 +02:00
|
|
|
using Operand = typename Base::template Operand<0>;
|
2018-10-24 23:06:46 +02:00
|
|
|
static_assert(Operand::category == TypeCategory::Integer ||
|
|
|
|
Operand::category == TypeCategory::Real ||
|
|
|
|
Operand::category == TypeCategory::Character);
|
2018-08-18 00:38:37 +02:00
|
|
|
CLASS_BOILERPLATE(Relational)
|
|
|
|
Relational(
|
2018-08-14 22:39:59 +02:00
|
|
|
RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b)
|
2018-07-20 21:19:09 +02:00
|
|
|
: Base{a, b}, opr{r} {}
|
2018-08-18 00:38:37 +02:00
|
|
|
Relational(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b)
|
2018-07-20 21:19:09 +02:00
|
|
|
: Base{std::move(a), std::move(b)}, opr{r} {}
|
2018-08-17 18:50:32 +02:00
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
std::ostream &Infix(std::ostream &) const;
|
2018-08-17 18:50:32 +02:00
|
|
|
|
2018-07-05 23:19:19 +02:00
|
|
|
RelationalOperator opr;
|
2018-06-21 20:03:00 +02:00
|
|
|
};
|
|
|
|
|
2018-09-08 00:25:10 +02:00
|
|
|
template<> class Relational<SomeType> {
|
2018-09-08 01:54:33 +02:00
|
|
|
// COMPLEX data are compared piecewise.
|
2018-09-08 00:25:10 +02:00
|
|
|
using DirectlyComparableTypes =
|
|
|
|
common::CombineTuples<IntegerTypes, RealTypes, CharacterTypes>;
|
|
|
|
|
|
|
|
public:
|
2018-08-16 20:46:18 +02:00
|
|
|
using Result = LogicalResult;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Relational)
|
2018-11-01 19:18:12 +01:00
|
|
|
static constexpr DynamicType GetType() { return Result::GetType(); }
|
2018-09-18 18:34:59 +02:00
|
|
|
int Rank() const {
|
|
|
|
return std::visit([](const auto &x) { return x.Rank(); }, u);
|
|
|
|
}
|
2018-11-06 00:02:37 +01:00
|
|
|
std::ostream &AsFortran(std::ostream &o) const;
|
2018-09-08 00:25:10 +02:00
|
|
|
common::MapTemplate<Relational, DirectlyComparableTypes> u;
|
2018-06-21 20:03:00 +02:00
|
|
|
};
|
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_INTEGER_KIND(extern template struct Relational)
|
|
|
|
FOR_EACH_REAL_KIND(extern template struct Relational)
|
|
|
|
FOR_EACH_CHARACTER_KIND(extern template struct Relational)
|
2018-08-29 01:35:45 +02:00
|
|
|
extern template struct Relational<SomeType>;
|
|
|
|
|
2018-10-24 01:48:06 +02:00
|
|
|
// Logical expressions of a kind bigger than LogicalResult
|
2018-10-24 23:06:46 +02:00
|
|
|
// do not include Relational<> operations as possibilities,
|
|
|
|
// since the results of Relationals are always LogicalResult
|
|
|
|
// (kind=1).
|
2018-08-29 00:15:18 +02:00
|
|
|
template<int KIND>
|
|
|
|
class Expr<Type<TypeCategory::Logical, KIND>>
|
|
|
|
: public ExpressionBase<Type<TypeCategory::Logical, KIND>> {
|
2018-07-12 01:36:43 +02:00
|
|
|
public:
|
2018-08-01 18:45:59 +02:00
|
|
|
using Result = Type<TypeCategory::Logical, KIND>;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
explicit Expr(bool x) : u{Constant<Result>{x}} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
|
2018-07-12 01:36:43 +02:00
|
|
|
private:
|
2019-02-20 00:38:55 +01:00
|
|
|
using Operations = std::tuple<Convert<Result>, Parentheses<Result>, Not<KIND>,
|
|
|
|
LogicalOperation<KIND>>;
|
2018-10-24 01:48:06 +02:00
|
|
|
using Relations = std::conditional_t<KIND == LogicalResult::kind,
|
2019-01-23 01:30:32 +01:00
|
|
|
std::tuple<Relational<SomeType>>, std::tuple<>>;
|
|
|
|
using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>,
|
2018-10-31 00:25:10 +01:00
|
|
|
Designator<Result>, FunctionRef<Result>>;
|
2018-08-29 00:15:18 +02:00
|
|
|
|
|
|
|
public:
|
2019-01-23 01:30:32 +01:00
|
|
|
common::TupleToVariant<common::CombineTuples<Operations, Relations, Others>>
|
|
|
|
u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_LOGICAL_KIND(extern template class Expr)
|
2018-08-29 01:35:45 +02:00
|
|
|
|
2019-02-09 01:35:02 +01:00
|
|
|
// StructureConstructor pairs a StructureConstructorValues instance
|
|
|
|
// (a map associating symbols with expressions) with a derived type
|
|
|
|
// specification. There are two other similar classes:
|
|
|
|
// - ArrayConstructor<SomeDerived> comprises a derived type spec &
|
|
|
|
// zero or more instances of Expr<SomeDerived>; it has rank 1
|
|
|
|
// but not (in the most general case) a known shape.
|
|
|
|
// - Constant<SomeDerived> comprises a derived type spec, zero or more
|
|
|
|
// homogeneous instances of StructureConstructorValues whose type
|
|
|
|
// parameters and component expressions are all constant, and a
|
|
|
|
// known shape (possibly scalar).
|
|
|
|
// StructureConstructor represents a scalar value of derived type that
|
|
|
|
// is not necessarily a constant. It is used only as an Expr<SomeDerived>
|
|
|
|
// alternative and as the type Scalar<SomeDerived> (with an assumption
|
|
|
|
// of constant component value expressions).
|
2019-02-07 21:05:27 +01:00
|
|
|
class StructureConstructor {
|
|
|
|
public:
|
|
|
|
explicit StructureConstructor(const semantics::DerivedTypeSpec &spec)
|
|
|
|
: derivedTypeSpec_{&spec} {}
|
2019-02-08 19:39:10 +01:00
|
|
|
StructureConstructor(
|
|
|
|
const semantics::DerivedTypeSpec &, const StructureConstructorValues &);
|
|
|
|
StructureConstructor(
|
|
|
|
const semantics::DerivedTypeSpec &, StructureConstructorValues &&);
|
2019-02-09 01:35:02 +01:00
|
|
|
CLASS_BOILERPLATE(StructureConstructor)
|
2019-02-07 21:05:27 +01:00
|
|
|
|
|
|
|
const semantics::DerivedTypeSpec &derivedTypeSpec() const {
|
|
|
|
return *derivedTypeSpec_;
|
|
|
|
}
|
2019-02-08 19:39:10 +01:00
|
|
|
StructureConstructorValues &values() { return values_; }
|
|
|
|
const StructureConstructorValues &values() const { return values_; }
|
2019-02-07 21:05:27 +01:00
|
|
|
bool operator==(const StructureConstructor &) const;
|
|
|
|
|
|
|
|
StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&);
|
|
|
|
int Rank() const { return 0; }
|
|
|
|
DynamicType GetType() const;
|
|
|
|
std::ostream &AsFortran(std::ostream &) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
const semantics::DerivedTypeSpec *derivedTypeSpec_;
|
2019-02-08 19:39:10 +01:00
|
|
|
StructureConstructorValues values_;
|
2019-02-07 21:05:27 +01:00
|
|
|
};
|
|
|
|
|
2018-10-31 00:25:10 +01:00
|
|
|
// An expression whose result has a derived type.
|
|
|
|
template<> class Expr<SomeDerived> : public ExpressionBase<SomeDerived> {
|
|
|
|
public:
|
|
|
|
using Result = SomeDerived;
|
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2019-02-07 21:05:27 +01:00
|
|
|
std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor,
|
|
|
|
Designator<Result>, FunctionRef<Result>>
|
2018-10-31 00:25:10 +01:00
|
|
|
u;
|
|
|
|
};
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// A polymorphic expression of known intrinsic type category, but dynamic
|
|
|
|
// kind, represented as a discriminated union over Expr<Type<CAT, K>>
|
|
|
|
// for each supported kind K in the category.
|
|
|
|
template<TypeCategory CAT>
|
|
|
|
class Expr<SomeKind<CAT>> : public ExpressionBase<SomeKind<CAT>> {
|
2018-07-24 00:04:08 +02:00
|
|
|
public:
|
2018-08-13 22:33:31 +02:00
|
|
|
using Result = SomeKind<CAT>;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-12-04 01:44:25 +01:00
|
|
|
int GetKind() const {
|
|
|
|
return std::visit(
|
2018-12-04 02:20:28 +01:00
|
|
|
[](const auto &x) { return std::decay_t<decltype(x)>::Result::kind; },
|
|
|
|
u);
|
2018-12-04 01:44:25 +01:00
|
|
|
}
|
2018-09-15 00:48:40 +02:00
|
|
|
common::MapTemplate<Expr, CategoryTypes<CAT>> u;
|
|
|
|
};
|
|
|
|
|
2019-02-20 02:06:28 +01:00
|
|
|
// BOZ literal "typeless" constants must be wide enough to hold a numeric
|
|
|
|
// value of any supported kind of INTEGER or REAL. They must also be
|
|
|
|
// distinguishable from other integer constants, since they are permitted
|
|
|
|
// to be used in only a few situations.
|
|
|
|
using BOZLiteralConstant = typename LargestReal::Scalar::Word;
|
|
|
|
|
|
|
|
// Null pointers without MOLD= arguments are typed by context.
|
|
|
|
struct NullPointer {
|
|
|
|
constexpr bool operator==(const NullPointer &) const { return true; }
|
|
|
|
constexpr int Rank() const { return 0; }
|
|
|
|
};
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// A completely generic expression, polymorphic across all of the intrinsic type
|
2018-07-19 18:53:42 +02:00
|
|
|
// categories and each of their kinds.
|
2018-08-29 00:15:18 +02:00
|
|
|
template<> class Expr<SomeType> : public ExpressionBase<SomeType> {
|
2018-08-14 22:39:59 +02:00
|
|
|
public:
|
|
|
|
using Result = SomeType;
|
2018-09-15 00:48:40 +02:00
|
|
|
EVALUATE_UNION_CLASS_BOILERPLATE(Expr)
|
2018-08-10 20:44:43 +02:00
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
// Owning references to these generic expressions can appear in other
|
|
|
|
// compiler data structures (viz., the parse tree and symbol table), so
|
|
|
|
// its destructor is externalized to reduce redundant default instances.
|
|
|
|
~Expr();
|
|
|
|
|
2018-08-01 18:45:59 +02:00
|
|
|
template<TypeCategory CAT, int KIND>
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(const Expr<Type<CAT, KIND>> &x) : u{Expr<SomeKind<CAT>>{x}} {}
|
2018-08-10 20:44:43 +02:00
|
|
|
|
2018-08-01 18:45:59 +02:00
|
|
|
template<TypeCategory CAT, int KIND>
|
2018-09-13 01:27:51 +02:00
|
|
|
explicit Expr(Expr<Type<CAT, KIND>> &&x)
|
|
|
|
: u{Expr<SomeKind<CAT>>{std::move(x)}} {}
|
2018-08-10 20:44:43 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<TypeCategory CAT, int KIND>
|
|
|
|
Expr &operator=(const Expr<Type<CAT, KIND>> &x) {
|
|
|
|
u = Expr<SomeKind<CAT>>{x};
|
|
|
|
return *this;
|
|
|
|
}
|
2018-08-13 22:33:31 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<TypeCategory CAT, int KIND>
|
|
|
|
Expr &operator=(Expr<Type<CAT, KIND>> &&x) {
|
|
|
|
u = Expr<SomeKind<CAT>>{std::move(x)};
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-09-15 00:48:40 +02:00
|
|
|
private:
|
2019-02-20 02:06:28 +01:00
|
|
|
using Others = std::variant<BOZLiteralConstant, NullPointer>;
|
2018-08-29 21:26:22 +02:00
|
|
|
using Categories = common::MapTemplate<Expr, SomeCategory>;
|
2018-09-15 00:48:40 +02:00
|
|
|
|
|
|
|
public:
|
2018-08-29 01:35:45 +02:00
|
|
|
common::CombineVariants<Others, Categories> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
2018-06-20 20:55:10 +02:00
|
|
|
|
2018-09-07 19:33:32 +02:00
|
|
|
// This wrapper class is used, by means of a forward reference with
|
2019-03-04 22:44:04 +01:00
|
|
|
// OwningPointer, to implement owning pointers to analyzed expressions
|
2018-09-07 19:33:32 +02:00
|
|
|
// from parse tree nodes.
|
|
|
|
struct GenericExprWrapper {
|
|
|
|
GenericExprWrapper(Expr<SomeType> &&x) : v{std::move(x)} {}
|
2019-01-04 23:05:53 +01:00
|
|
|
bool operator==(const GenericExprWrapper &) const;
|
2018-09-07 19:33:32 +02:00
|
|
|
Expr<SomeType> v;
|
|
|
|
};
|
|
|
|
|
2019-02-08 19:39:10 +01:00
|
|
|
std::ostream &DerivedTypeSpecAsFortran(
|
|
|
|
std::ostream &, const semantics::DerivedTypeSpec &);
|
|
|
|
|
2018-10-27 01:31:20 +02:00
|
|
|
FOR_EACH_CATEGORY_TYPE(extern template class Expr)
|
2018-10-30 20:44:09 +01:00
|
|
|
FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase)
|
2019-02-09 01:35:02 +01:00
|
|
|
FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructorValues)
|
|
|
|
FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor)
|
2018-10-25 14:55:23 +02:00
|
|
|
}
|
2018-06-18 21:09:56 +02:00
|
|
|
#endif // FORTRAN_EVALUATE_EXPRESSION_H_
|