2018-06-18 21:09:56 +02:00
|
|
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
//
|
|
|
|
// 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-06-22 20:02:54 +02:00
|
|
|
// context-independent hash table or sharing of common subexpressions.
|
2018-08-29 00:15:18 +02:00
|
|
|
// Both deep copy and move semantics are supported for expression construction.
|
2018-06-22 20:02:54 +02:00
|
|
|
|
2018-06-19 23:16:01 +02:00
|
|
|
#include "common.h"
|
2018-06-18 21:09:56 +02:00
|
|
|
#include "type.h"
|
2018-07-07 00:12:33 +02:00
|
|
|
#include "variable.h"
|
2018-08-17 18:50:32 +02:00
|
|
|
#include "../lib/common/fortran.h"
|
2018-07-05 23:19:19 +02:00
|
|
|
#include "../lib/common/idioms.h"
|
2018-06-22 23:51:15 +02:00
|
|
|
#include "../lib/parser/char-block.h"
|
|
|
|
#include "../lib/parser/message.h"
|
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-08-29 00:15:18 +02:00
|
|
|
// Expressions are represented by specializations of Expr.
|
|
|
|
// Each of these specializations wraps a single data member "u" that
|
|
|
|
// is a std::variant<> discriminated union over 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:
|
|
|
|
// - Expr<Type<CATEGORY, KIND>> is an expression whose result is of a
|
|
|
|
// specific intrinsic type category and kind, e.g. Type<TypeCategory::Real, 4>
|
|
|
|
// - Expr<SomeKind<CATEGORY>> is a union of Expr<Type<CATEGORY, K>> for each
|
|
|
|
// kind type parameter value K in that intrinsic type category
|
|
|
|
// - Expr<SomeType> is a union of Expr<SomeKind<CATEGORY>> over the five
|
|
|
|
// intrinsic type categories of Fortran.
|
2018-08-14 23:35:51 +02:00
|
|
|
template<typename A> class Expr;
|
|
|
|
|
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>,
|
|
|
|
// or SomeType.
|
2018-08-20 18:29:08 +02:00
|
|
|
template<typename A> using ResultType = typename std::decay_t<A>::Result;
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// Wraps a constant value in a class to make its type clear.
|
|
|
|
CLASS_TRAIT(IsConstantTrait)
|
|
|
|
template<typename T> struct Constant {
|
|
|
|
using Result = T;
|
|
|
|
using Value = Scalar<Result>; // TODO rank > 0
|
|
|
|
using IsConstantTrait = std::true_type;
|
|
|
|
CLASS_BOILERPLATE(Constant)
|
|
|
|
template<typename A> Constant(const A &x) : value{x} {}
|
|
|
|
template<typename A>
|
|
|
|
Constant(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
|
|
|
: value(std::move(x)) {}
|
|
|
|
std::ostream &Dump(std::ostream &) const;
|
|
|
|
Value value;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Wrappers around data and function references so that their resolved
|
|
|
|
// types are clear.
|
|
|
|
template<typename T> struct DataReference {
|
|
|
|
using Result = T;
|
|
|
|
CopyableIndirection<DataRef> reference;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T> struct FunctionReference {
|
|
|
|
using Result = T;
|
|
|
|
CopyableIndirection<FunctionRef> reference;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Abstract Operation<> base class. The first type parameter is a "CRTP"
|
2018-08-22 22:36:45 +02:00
|
|
|
// reference to the specific operation class; e.g., Add is defined with
|
|
|
|
// struct Add : public Operation<Add, ...>.
|
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 {
|
2018-08-29 00:15:18 +02:00
|
|
|
using OperandTypes = std::tuple<OPERANDS...>;
|
|
|
|
static_assert(RESULT::kind > 0 || !"bad result Type");
|
|
|
|
|
2018-08-15 22:46:33 +02:00
|
|
|
public:
|
|
|
|
using Derived = DERIVED;
|
|
|
|
using Result = RESULT;
|
2018-08-29 00:15:18 +02:00
|
|
|
static constexpr auto operands() { return std::tuple_size_v<OperandTypes>; }
|
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
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-08-15 22:46:33 +02:00
|
|
|
|
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 =
|
|
|
|
std::conditional_t<operands() == 1, CopyableIndirection<Expr<Operand<0>>>,
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
Operation(const Expr<OPERANDS> &... x) : operand_{x...} {}
|
|
|
|
Operation(Expr<OPERANDS> &&... x)
|
|
|
|
: operand_{std::forward<Expr<OPERANDS>>(x)...} {}
|
|
|
|
|
|
|
|
Derived &derived() { return *static_cast<Derived *>(this); }
|
|
|
|
const Derived &derived() const { return *static_cast<const Derived *>(this); }
|
|
|
|
|
|
|
|
template<int J> Expr<Operand<J>> &operand() {
|
|
|
|
if constexpr (operands() == 1) {
|
|
|
|
static_assert(J == 0);
|
|
|
|
return *operand_;
|
|
|
|
} else {
|
|
|
|
return *std::get<J>(operand_);
|
|
|
|
}
|
|
|
|
}
|
2018-08-15 22:46:33 +02:00
|
|
|
template<int J> const Expr<Operand<J>> &operand() const {
|
2018-08-29 00:15:18 +02:00
|
|
|
if constexpr (operands() == 1) {
|
|
|
|
static_assert(J == 0);
|
|
|
|
return *operand_;
|
|
|
|
} else {
|
|
|
|
return *std::get<J>(operand_);
|
|
|
|
}
|
2018-08-15 22:46:33 +02:00
|
|
|
}
|
|
|
|
|
2018-08-17 18:50:32 +02:00
|
|
|
std::ostream &Dump(std::ostream &) const;
|
2018-08-29 00:15:18 +02:00
|
|
|
std::optional<Constant<Result>> Fold(FoldingContext &);
|
2018-08-15 22:46:33 +02:00
|
|
|
|
|
|
|
protected:
|
2018-08-17 18:50:32 +02:00
|
|
|
// Overridable string functions for Dump()
|
|
|
|
static const char *prefix() { return "("; }
|
|
|
|
static const char *infix() { return ","; }
|
|
|
|
static const char *suffix() { return ")"; }
|
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-08-29 00:15:18 +02:00
|
|
|
template<typename TO, TypeCategory FROMCAT>
|
|
|
|
struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> {
|
|
|
|
using Result = TO;
|
|
|
|
using Operand = SomeKind<FROMCAT>;
|
|
|
|
using Base = Operation<Convert, Result, Operand>;
|
2018-08-16 20:46:18 +02:00
|
|
|
using Base::Base;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &);
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &x) {
|
|
|
|
return {x};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &);
|
2018-08-17 18:50:32 +02:00
|
|
|
static const char *prefix() { return "(-"; }
|
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
|
|
|
|
|
|
|
std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &) const;
|
2018-08-23 19:55:16 +02:00
|
|
|
const char *suffix() const { return 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-08-16 20:46:18 +02:00
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &);
|
2018-08-17 18:50:32 +02:00
|
|
|
static const char *prefix() { return "(.NOT."; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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-08-18 00:38:37 +02:00
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
static constexpr const char *infix() { return "+"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
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-08-17 18:50:32 +02:00
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
2018-08-18 00:38:37 +02:00
|
|
|
static constexpr const char *infix() { return "-"; }
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
static constexpr const char *infix() { return "*"; }
|
|
|
|
};
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
static constexpr const char *infix() { return "/"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
static constexpr const char *infix() { return "**"; }
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(FoldingContext &,
|
2018-08-29 00:15:18 +02:00
|
|
|
const Scalar<BaseOperand> &, const Scalar<ExponentOperand> &);
|
2018-08-18 00:38:37 +02:00
|
|
|
static constexpr const char *infix() { return "**"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
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} {}
|
|
|
|
|
|
|
|
std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &) const;
|
|
|
|
const char *prefix() const {
|
|
|
|
return ordering == Ordering::Less ? "MIN(" : "MAX(";
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
static std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &);
|
|
|
|
static constexpr const char *infix() { return "//"; }
|
|
|
|
};
|
|
|
|
|
|
|
|
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(
|
|
|
|
const Expr<Operand> &x, const Expr<Operand> &y, LogicalOperator opr)
|
|
|
|
: Base{x, y}, logicalOperator{opr} {}
|
|
|
|
LogicalOperation(Expr<Operand> &&x, Expr<Operand> &&y, LogicalOperator opr)
|
|
|
|
: Base{std::move(x), std::move(y)}, logicalOperator{opr} {}
|
|
|
|
|
|
|
|
std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &, const Scalar<Operand> &, const Scalar<Operand> &) const;
|
|
|
|
const char *infix() const;
|
|
|
|
|
|
|
|
LogicalOperator logicalOperator;
|
2018-06-22 20:02:54 +02:00
|
|
|
};
|
|
|
|
|
2018-07-20 21:19:09 +02:00
|
|
|
// Per-category expressions
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
// Common Expr<> behaviors
|
|
|
|
template<typename RESULT> struct ExpressionBase {
|
|
|
|
using Result = RESULT;
|
|
|
|
using Derived = Expr<Result>;
|
|
|
|
|
|
|
|
Derived &derived() { return *static_cast<Derived *>(this); }
|
|
|
|
const Derived &derived() const { return *static_cast<const Derived *>(this); }
|
|
|
|
|
|
|
|
int Rank() const { return 0; } // TODO
|
|
|
|
|
|
|
|
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::ostream &Dump(std::ostream &) const;
|
|
|
|
std::optional<Constant<Result>> Fold(FoldingContext &c);
|
|
|
|
std::optional<Scalar<Result>> ScalarValue() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-07-09 21:46:51 +02:00
|
|
|
// TODO: R916 type-param-inquiry
|
2018-06-18 21:09:56 +02:00
|
|
|
|
2018-07-07 00:12:33 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
Expr(std::int64_t n) : u{Constant<Result>{n}} {}
|
|
|
|
Expr(std::uint64_t n) : u{Constant<Result>{n}} {}
|
|
|
|
Expr(int n) : u{Constant<Result>{n}} {}
|
|
|
|
template<typename A> Expr(const A &x) : u{x} {}
|
2018-07-04 00:14:48 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u(std::move(x)) {}
|
|
|
|
Expr(const DataRef &x) : u{DataReference<Result>{x}} {}
|
|
|
|
Expr(const FunctionRef &x) : u{FunctionReference<Result>{x}} {}
|
2018-06-21 21:47:28 +02:00
|
|
|
|
2018-07-12 01:36:43 +02:00
|
|
|
private:
|
2018-08-29 00:15:18 +02:00
|
|
|
using Conversions = std::variant<Convert<Result, TypeCategory::Integer>,
|
|
|
|
Convert<Result, TypeCategory::Real>>;
|
|
|
|
using Operations = std::variant<Parentheses<Result>, Negate<Result>,
|
2018-08-18 00:38:37 +02:00
|
|
|
Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
|
2018-08-29 00:15:18 +02:00
|
|
|
Power<Result>, Extremum<Result>>;
|
|
|
|
using Others = std::variant<Constant<Result>, DataReference<Result>,
|
|
|
|
FunctionReference<Result>>;
|
|
|
|
|
|
|
|
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::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-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-08-16 20:46:18 +02:00
|
|
|
|
2018-07-07 00:12:33 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
template<typename A> Expr(const A &x) : u{x} {}
|
2018-07-04 00:14:48 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
|
|
|
Expr(const DataRef &x) : u{DataReference<Result>{x}} {}
|
|
|
|
Expr(const FunctionRef &x) : u{FunctionReference<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>>;
|
|
|
|
using Others = std::variant<Constant<Result>, DataReference<Result>,
|
|
|
|
FunctionReference<Result>>;
|
|
|
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-07-07 00:12:33 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
template<typename A> Expr(const A &x) : u{x} {}
|
2018-07-04 00:14:48 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
|
|
|
Expr(const DataRef &x) : u{DataReference<Result>{x}} {}
|
|
|
|
Expr(const FunctionRef &x) : u{FunctionReference<Result>{x}} {}
|
2018-07-19 18:53:42 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
using Operations = std::variant<Parentheses<Result>, Negate<Result>,
|
2018-08-18 00:38:37 +02:00
|
|
|
Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>,
|
2018-08-29 00:15:18 +02:00
|
|
|
Power<Result>, RealToIntPower<Result>, ComplexConstructor<KIND>>;
|
|
|
|
using Others = std::variant<Constant<Result>, DataReference<Result>,
|
|
|
|
FunctionReference<Result>>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
common::CombineVariants<Operations, Others> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
|
|
|
|
2018-08-16 20:46:18 +02:00
|
|
|
extern template class Expr<Type<TypeCategory::Integer, 1>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Integer, 2>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Integer, 4>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Integer, 8>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Integer, 16>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Real, 2>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Real, 4>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Real, 8>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Real, 10>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Real, 16>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Complex, 2>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Complex, 4>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Complex, 8>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Complex, 10>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Complex, 16>>;
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-07-07 00:12:33 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
Expr(Scalar<Result> &&x) : u{Constant<Result>{std::move(x)}} {}
|
|
|
|
template<typename A> Expr(const A &x) : u{x} {}
|
2018-07-11 23:50:08 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
|
|
|
Expr(const DataRef &x) : u{DataReference<Result>{x}} {}
|
|
|
|
Expr(const FunctionRef &x) : u{FunctionReference<Result>{x}} {}
|
|
|
|
template<typename A> Expr(CopyableIndirection<A> &&x) : u{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-08-29 00:15:18 +02:00
|
|
|
std::variant<Constant<Result>, DataReference<Result>,
|
|
|
|
CopyableIndirection<Substring>, FunctionReference<Result>,
|
2018-08-18 00:38:37 +02:00
|
|
|
// TODO Parentheses<Result>,
|
|
|
|
Concat<KIND>, Extremum<Result>>
|
2018-08-29 00:15:18 +02:00
|
|
|
u;
|
2018-06-22 00:35:25 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 01:35:45 +02:00
|
|
|
extern template class Expr<Type<TypeCategory::Character, 1>>; // TODO more
|
|
|
|
|
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
|
|
|
|
// undergoing the same operand conversions that occur with the addition
|
|
|
|
// intrinsic operator first. 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> {
|
|
|
|
using Base = Operation<Relational, LogicalResult, A, A>;
|
2018-08-17 18:50:32 +02:00
|
|
|
using typename Base::Result;
|
|
|
|
using Operand = typename Base::template Operand<0>;
|
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-08-14 22:39:59 +02:00
|
|
|
std::optional<Scalar<Result>> FoldScalar(
|
|
|
|
FoldingContext &c, const Scalar<Operand> &, const Scalar<Operand> &);
|
2018-08-17 18:50:32 +02:00
|
|
|
std::string infix() const;
|
|
|
|
|
2018-07-05 23:19:19 +02:00
|
|
|
RelationalOperator opr;
|
2018-06-21 20:03:00 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
template<> struct Relational<SomeType> {
|
2018-08-16 20:46:18 +02:00
|
|
|
using Result = LogicalResult;
|
2018-08-29 00:15:18 +02:00
|
|
|
CLASS_BOILERPLATE(Relational)
|
|
|
|
template<typename A> Relational(const A &x) : u(x) {}
|
2018-08-23 23:49:28 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Relational(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
|
2018-08-23 23:49:28 +02:00
|
|
|
: u{std::move(x)} {}
|
2018-08-29 00:15:18 +02:00
|
|
|
std::ostream &Dump(std::ostream &o) const;
|
2018-08-23 23:49:28 +02:00
|
|
|
common::MapTemplate<Relational, std::variant, RelationalTypes> u;
|
2018-06-21 20:03:00 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 01:35:45 +02:00
|
|
|
extern template struct Relational<Type<TypeCategory::Integer, 1>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Integer, 2>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Integer, 4>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Integer, 8>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Integer, 16>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Real, 2>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Real, 4>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Real, 8>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Real, 10>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Real, 16>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Complex, 2>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Complex, 4>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Complex, 8>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Complex, 10>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Complex, 16>>;
|
|
|
|
extern template struct Relational<Type<TypeCategory::Character, 1>>; // TODO
|
|
|
|
// more
|
|
|
|
extern template struct Relational<SomeType>;
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-07-07 00:12:33 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {}
|
|
|
|
Expr(bool x) : u{Constant<Result>{x}} {}
|
|
|
|
template<typename A> Expr(const A &x) : u(x) {}
|
2018-07-04 00:14:48 +02:00
|
|
|
template<typename A>
|
2018-08-29 00:15:18 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
|
|
|
Expr(const DataRef &x) : u{DataReference<Result>{x}} {}
|
|
|
|
Expr(const FunctionRef &x) : u{FunctionReference<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
|
|
|
using Operations =
|
|
|
|
std::variant<Not<KIND>, LogicalOperation<KIND>, Relational<SomeType>>;
|
|
|
|
using Others = std::variant<Constant<Result>, DataReference<Result>,
|
|
|
|
FunctionReference<Result>>;
|
|
|
|
|
|
|
|
public:
|
|
|
|
common::CombineVariants<Operations, Others> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
|
|
|
|
2018-08-29 01:35:45 +02:00
|
|
|
extern template class Expr<Type<TypeCategory::Logical, 1>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Logical, 2>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Logical, 4>>;
|
|
|
|
extern template class Expr<Type<TypeCategory::Logical, 8>>;
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-07-24 00:04:08 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-16 20:46:18 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
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)} {}
|
2018-08-22 22:36:45 +02:00
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
common::MapTemplate<Expr, std::variant, CategoryTypes<CAT>> u;
|
2018-08-16 20:46:18 +02:00
|
|
|
};
|
2018-07-24 00:04:08 +02:00
|
|
|
|
2018-08-09 01:30:58 +02:00
|
|
|
// BOZ literal constants need to be wide enough to hold an integer or real
|
|
|
|
// value of any supported kind. They also need to be distinguishable from
|
|
|
|
// other integer constants, since they are permitted to be used in only a
|
|
|
|
// few situations.
|
|
|
|
using BOZLiteralConstant = value::Integer<128>;
|
|
|
|
|
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-08-29 00:15:18 +02:00
|
|
|
using IsFoldableTrait = std::true_type;
|
2018-08-14 22:39:59 +02:00
|
|
|
CLASS_BOILERPLATE(Expr)
|
2018-08-10 20:44:43 +02:00
|
|
|
|
2018-08-14 22:39:59 +02:00
|
|
|
template<typename A> Expr(const A &x) : u{x} {}
|
2018-08-10 20:44:43 +02:00
|
|
|
template<typename A>
|
2018-08-14 22:39:59 +02:00
|
|
|
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
|
2018-08-10 20:44:43 +02:00
|
|
|
|
2018-08-01 18:45:59 +02:00
|
|
|
template<TypeCategory CAT, int KIND>
|
2018-08-14 22:39:59 +02:00
|
|
|
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-08-14 22:39:59 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
using Others = std::variant<BOZLiteralConstant>;
|
2018-08-29 01:35:45 +02:00
|
|
|
using Categories = common::MapTemplate<Expr, std::variant, SomeCategory>;
|
|
|
|
common::CombineVariants<Others, Categories> u;
|
2018-06-19 23:16:01 +02:00
|
|
|
};
|
2018-06-20 20:55:10 +02:00
|
|
|
|
2018-08-16 20:46:18 +02:00
|
|
|
extern template class Expr<SomeInteger>;
|
|
|
|
extern template class Expr<SomeReal>;
|
|
|
|
extern template class Expr<SomeComplex>;
|
|
|
|
extern template class Expr<SomeCharacter>;
|
|
|
|
extern template class Expr<SomeLogical>;
|
|
|
|
extern template class Expr<SomeType>;
|
|
|
|
|
2018-08-29 00:15:18 +02:00
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Integer, 1>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Integer, 2>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Integer, 4>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Integer, 8>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Integer, 16>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Real, 2>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Real, 4>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Real, 8>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Real, 10>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Real, 16>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Complex, 2>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Complex, 4>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Complex, 8>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Complex, 10>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Complex, 16>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Character, 1>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Logical, 1>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Logical, 2>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Logical, 4>>;
|
|
|
|
extern template struct ExpressionBase<Type<TypeCategory::Logical, 8>>;
|
|
|
|
extern template struct ExpressionBase<SomeInteger>;
|
|
|
|
extern template struct ExpressionBase<SomeReal>;
|
|
|
|
extern template struct ExpressionBase<SomeComplex>;
|
|
|
|
extern template struct ExpressionBase<SomeCharacter>;
|
|
|
|
extern template struct ExpressionBase<SomeLogical>;
|
|
|
|
extern template struct ExpressionBase<SomeType>;
|
|
|
|
|
2018-06-18 21:09:56 +02:00
|
|
|
} // namespace Fortran::evaluate
|
|
|
|
#endif // FORTRAN_EVALUATE_EXPRESSION_H_
|