CHECK(p_ && "assigning null pointer to Indirection");
p = nullptr;
}
+ Indirection(const A &x) : p_{new A(x)} {}
Indirection(A &&p) : p_{new A(std::move(p))} {}
template<typename... ARGS>
Indirection(ARGS &&... args) : p_{new A(std::forward<ARGS>(args)...)} {}
- Indirection(Indirection &&that) {
- CHECK(that.p_ && "constructing Indirection from null Indirection");
- p_ = that.p_;
+ Indirection(Indirection &&that) : p_{that.p_} {
+ CHECK(p_ && "move construction of Indirection from null Indirection");
that.p_ = nullptr;
}
~Indirection() {
p_ = nullptr;
}
Indirection &operator=(Indirection &&that) {
- CHECK(that.p_ && "assigning null Indirection to Indirection");
+ CHECK(that.p_ && "move assignment of null Indirection to Indirection");
auto tmp = p_;
p_ = that.p_;
that.p_ = tmp;
logical.cc
real.cc
)
+
+target_link_libraries(FortranEvaluate
+ FortranCommon
+)
#ifndef FORTRAN_EVALUATE_EXPRESSION_H_
#define FORTRAN_EVALUATE_EXPRESSION_H_
+#include "common.h"
#include "type.h"
#include "../common/indirection.h"
#include <variant>
namespace Fortran::evaluate {
-template<Classification C, int KIND> struct Expression;
+template<typename T> struct Expression;
-template<int KIND> struct Expression<Classification::Integer> {
- static constexpr Classification classification{Classification::Integer};
+template<typename T> struct ExprOperand {
+ template<typename... ARGS> ExprOperand(const ARGS &...args) : v{args...} {}
+ template<typename... ARGS> ExprOperand(ARGS &&...args) : v{std::forward<ARGS>(args)...} {}
+ common::Indirection<Expression<T>> v;
+};
+
+struct IntegerOperand {
+ std::variant<
+ ExprOperand<Type<Category::Integer, 1>>,
+ ExprOperand<Type<Category::Integer, 2>>,
+ ExprOperand<Type<Category::Integer, 4>>,
+ ExprOperand<Type<Category::Integer, 8>>,
+ ExprOperand<Type<Category::Integer, 16>>> u;
+};
+struct RealOperand {
+ std::variant<
+ ExprOperand<Type<Category::Real, 2>>,
+ ExprOperand<Type<Category::Real, 4>>,
+ ExprOperand<Type<Category::Real, 8>>,
+ ExprOperand<Type<Category::Real, 10>>,
+ ExprOperand<Type<Category::Real, 16>>> u;
+};
+struct ComplexOperand {
+ std::variant<
+ ExprOperand<Type<Category::Complex, 2>>,
+ ExprOperand<Type<Category::Complex, 4>>,
+ ExprOperand<Type<Category::Complex, 8>>,
+ ExprOperand<Type<Category::Complex, 10>>,
+ ExprOperand<Type<Category::Complex, 16>>> u;
+};
+struct CharacterOperand {
+ std::variant<ExprOperand<Type<Category::Character, 1>>> u;
+};
+
+struct FloatingOperand {
+ std::variant<RealOperand, ComplexOperand> u;
+};
+struct NumericOperand {
+ std::variant<IntegerOperand, FloatingOperand> u;
+};
+
+template<Category C, int KIND> struct NumericBase {
+ static constexpr Category category{C};
static constexpr int kind{KIND};
+ using Result = Type<category, kind>;
+ using Operand = ExprOperand<Result>;
+ using Constant = typename Result::Value;
+ struct Unary {
+ enum class Operator { Parentheses, Negate } op;
+ Operand x;
+ };
+ struct Binary {
+ enum class Operator { Add, Subtract, Multiply, Divide, Power } op;
+ Operand x, y;
+ };
+ struct Convert {
+ NumericOperand x;
+ };
};
-using<int KIND> IntegerExpression = Expression<Classification::Integer, KIND>;
-using<int KIND> RealExpression = Expression<Classification::Real, KIND>;
+template<int KIND> struct Expression<Type<Category::Integer, KIND>> : public NumericBase<Category::Integer, KIND> {
+ using Base = NumericBase<Category::Integer, KIND>;
+ using Result = typename Base::Result;
+ using Constant = typename Base::Constant;
+ using Convert = typename Base::Convert;
+ using Unary = typename Base::Unary;
+ using Binary = typename Base::Binary;
+ Expression() = delete;
+ Expression(Expression &&) = default;
+ Expression(const Constant &x) : u{x} {}
+ Expression(Convert &&x) : u{std::move(x)} {}
+ Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
+ Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
+ std::variant<Constant, Convert, Unary, Binary> u;
+};
+
+template<Category C, int KIND> struct FloatingBase : public NumericBase<C, KIND> {
+ using Result = typename NumericBase<C, KIND>::Result;
+ struct IntegerPower {
+ Result x;
+ IntegerOperand y;
+ };
+};
+template<int KIND> struct Expression<Type<Category::Real, KIND>> : public FloatingBase<Category::Real, KIND> {
+ using Base = FloatingBase<Category::Real, KIND>;
+ using Result = typename Base::Result;
+ using Constant = typename Base::Constant;
+ using Convert = typename Base::Convert;
+ using Unary = typename Base::Unary;
+ using Binary = typename Base::Binary;
+ using IntegerPower = typename Base::IntegerPower;
+ Expression() = delete;
+ Expression(Expression &&) = default;
+ Expression(const Constant &x) : u{x} {}
+ Expression(Convert &&x) : u{std::move(x)} {}
+ Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
+ Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
+ std::variant<Constant, Convert, Unary, Binary, IntegerPower> u;
+};
+
+template<int KIND> struct Expression<Type<Category::Complex, KIND>> : public FloatingBase<Category::Complex, KIND> {
+ using Base = FloatingBase<Category::Complex, KIND>;
+ using Result = typename Base::Result;
+ using Constant = typename Base::Constant;
+ using Convert = typename Base::Convert;
+ using Unary = typename Base::Unary;
+ using Binary = typename Base::Binary;
+ using IntegerPower = typename Base::IntegerPower;
+ Expression() = delete;
+ Expression(Expression &&) = default;
+ Expression(const Constant &x) : u{x} {}
+ Expression(Convert &&x) : u{std::move(x)} {}
+ Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
+ Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
+ std::variant<Constant, Convert, Unary, Binary, IntegerPower> u;
+};
+
+template<> struct Expression<Type<Category::Logical, 1>> {
+ // No need to distinguish the various kinds of LOGICAL in expressions.
+ static constexpr Category category{Category::Logical};
+ static constexpr int kind{1};
+ using Result = Type<category, kind>;
+ using Operand = ExprOperand<Result>;
+ using Constant = typename Result::Value;
+
+ struct Unary {
+ enum class Operator { Not } op;
+ Operand x;
+ };
+ struct Binary {
+ enum class Operator { And, Or, Eqv, Neqv } op;
+ Operand x, y;
+ };
+
+ enum class ComparisonOperator { LT, LE, EQ, NE, GE, GT }; // TODO: .UN.?
+ template<typename T>
+ struct Comparison {
+ ComparisonOperator op;
+ ExprOperand<T> x, y;
+ };
+
+ enum class EqualityOperator { EQ, NE };
+ template<int KIND>
+ struct ComplexComparison {
+ EqualityOperator op;
+ ExprOperand<Type<Category::Complex, KIND>> x, y;
+ };
+
+ Expression() = delete;
+ Expression(Expression &&) = default;
+ Expression(const Constant &x) : u{x} {}
+ Expression(typename Unary::Operator o, Expression &&a) : u{Unary{o, std::move(a)}} {}
+ Expression(typename Binary::Operator o, Expression &&a, Expression &&b) : u{Binary{o, std::move(a), std::move(b)}} {}
+ template<typename T>
+ Expression(ComparisonOperator o, Expression<T> &&a, Expression<T> &&b) : u{Comparison<T>{o, std::move(a), std::move(b)}} {}
+ template<int KIND>
+ Expression(EqualityOperator o, Expression<Type<Category::Complex, KIND>> &&a, Expression<Type<Category::Complex, KIND>> &&b) : u{ComplexComparison<KIND>{o, std::move(a), std::move(b)}} {}
+ std::variant<Constant, Unary, Binary,
+ Comparison<Type<Category::Integer, 1>>,
+ Comparison<Type<Category::Integer, 2>>,
+ Comparison<Type<Category::Integer, 4>>,
+ Comparison<Type<Category::Integer, 8>>,
+ Comparison<Type<Category::Integer, 16>>,
+ Comparison<Type<Category::Character, 1>>,
+ Comparison<Type<Category::Real, 2>>,
+ Comparison<Type<Category::Real, 4>>,
+ Comparison<Type<Category::Real, 8>>,
+ Comparison<Type<Category::Real, 10>>,
+ Comparison<Type<Category::Real, 16>>,
+ ComplexComparison<2>,
+ ComplexComparison<4>,
+ ComplexComparison<8>,
+ ComplexComparison<10>,
+ ComplexComparison<16>> u;
+};
+
+template<int KIND> struct Expression<Type<Category::Character, KIND>> {
+ static constexpr Category category{Category::Character};
+ static constexpr int kind{KIND};
+ using Result = Type<category, kind>;
+ using Constant = typename Result::Value;
+ struct Concat {
+ ExprOperand<Result> x, y;
+ };
+ Expression() = delete;
+ Expression(Expression &&) = default;
+ Expression(const Constant &x) : u{x} {}
+ Expression(Expression &&a, Expression &&b) : u{Concat{std::move(a), std::move(b)}} {}
+ std::variant<Constant, Concat> u;
+ // TODO: length
+};
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_EXPRESSION_H_
#include "real.h"
#include <string>
-namespace Fortran::evaluate::type {
+namespace Fortran::evaluate {
-enum class Classification { Integer, Real, Complex, Character, Logical };
+enum class Category { Integer, Real, Complex, Character, Logical, Derived };
-template<int KIND> struct Integer {
- static constexpr Classification classification{Classification::Integer};
+template<Category C, int KIND> struct TypeBase {
+ static constexpr Category category{C};
static constexpr int kind{KIND};
static constexpr bool hasLen{false};
- using ValueType = value::Integer<8 * kind>;
};
-template<int KIND> struct Real;
-template<> struct Real<2> {
- static constexpr Classification classification{Classification::Real};
- static constexpr int kind{2};
- static constexpr bool hasLen{false};
- using ValueType = value::Real<typename Integer<kind>::ValueType, 11>;
+template<Category C, int KIND> struct Type;
+
+template<int KIND> struct Type<Category::Integer, KIND>
+ : public TypeBase<Category::Integer, KIND> {
+ using Value = value::Integer<8 * KIND>;
};
-template<> struct Real<4> {
- static constexpr Classification classification{Classification::Real};
- static constexpr int kind{4};
- static constexpr bool hasLen{false};
- using ValueType = value::Real<typename Integer<kind>::ValueType, 24>;
+
+template<> struct Type<Category::Real, 2>
+ : public TypeBase<Category::Real, 2> {
+ using Value = value::Real<typename Type<Category::Integer, 2>::Value, 11>;
};
-template<> struct Real<8> {
- static constexpr Classification classification{Classification::Real};
- static constexpr int kind{8};
- static constexpr bool hasLen{false};
- using ValueType = value::Real<typename Integer<kind>::ValueType, 53>;
+
+template<> struct Type<Category::Real, 4>
+ : public TypeBase<Category::Real, 4> {
+ using Value = value::Real<typename Type<Category::Integer, 4>::Value, 24>;
};
-template<> struct Real<10> {
- static constexpr Classification classification{Classification::Real};
- static constexpr int kind{10};
- static constexpr bool hasLen{false};
- using ValueType = value::Real<value::Integer<80>, 64, false>;
+
+template<> struct Type<Category::Real, 8>
+ : public TypeBase<Category::Real, 8> {
+ using Value = value::Real<typename Type<Category::Integer, 8>::Value, 53>;
};
-template<> struct Real<16> {
- static constexpr Classification classification{Classification::Real};
- static constexpr int kind{16};
- static constexpr bool hasLen{false};
- using ValueType = value::Real<typename Integer<kind>::ValueType, 112>;
+
+template<> struct Type<Category::Real, 10>
+ : public TypeBase<Category::Real, 10> {
+ using Value = value::Real<value::Integer<80>, 64, false>;
+};
+
+template<> struct Type<Category::Real, 16>
+ : public TypeBase<Category::Real, 16> {
+ using Value = value::Real<typename Type<Category::Integer, 16>::Value, 112>;
};
// The KIND type parameter on COMPLEX is the kind of each of its components.
-template<int KIND> struct Complex {
- static constexpr Classification classification{Classification::Complex};
- static constexpr int kind{KIND};
- static constexpr bool hasLen{false};
- using ValueType = value::Complex<typename Real<kind>::ValueType>;
+template<int KIND> struct Type<Category::Complex, KIND>
+ : public TypeBase<Category::Complex, KIND> {
+ using Value = value::Complex<typename Type<Category::Real, KIND>::Value>;
};
-template<int KIND> struct Logical {
- static constexpr Classification classification{Classification::Logical};
- static constexpr int kind{KIND};
- static constexpr bool hasLen{false};
- using ValueType = value::Logical<8 * kind>;
+template<int KIND> struct Type<Category::Logical, KIND>
+ : public TypeBase<Category::Logical, KIND> {
+ using Value = value::Logical<8 * KIND>;
};
-template<int KIND> struct Character {
- static constexpr Classification classification{Classification::Character};
+template<int KIND> struct Type<Category::Character, KIND> {
+ static constexpr Category category{Category::Character};
static constexpr int kind{KIND};
static constexpr bool hasLen{true};
- using ValueType = std::string;
+ using Value = std::string;
};
// Default REAL just simply has to be IEEE-754 single precision today.
// storage unit, so their kinds are also forced. Default COMPLEX occupies
// two numeric storage units.
-using DefaultReal = Real<4>;
-using DefaultInteger = Integer<DefaultReal::kind>;
+using DefaultReal = Type<Category::Real, 4>;
+using DefaultInteger = Type<Category::Integer, DefaultReal::kind>;
using IntrinsicTypeParameterType = DefaultInteger;
-using DefaultComplex = Complex<DefaultReal::kind>;
-using DefaultLogical = Logical<DefaultReal::kind>;
-using DefaultCharacter = Character<1>;
-
+using DefaultComplex = Type<Category::Complex, DefaultReal::kind>;
+using DefaultLogical = Type<Category::Logical, DefaultReal::kind>;
+using DefaultCharacter = Type<Category::Character, 1>;
} // namespace Fortran::evaluate::type
#endif // FORTRAN_EVALUATE_TYPE_H_
m
)
+add_executable(expression-test
+ expression.cc
+)
+
+target_link_libraries(expression-test
+ FortranEvaluate
+ FortranEvaluateTesting
+)
+
+add_test(NAME Expression COMMAND expression-test)
add_test(NAME Leadz COMMAND leading-zero-bit-count-test)
add_test(NAME PopPar COMMAND bit-population-count-test)
add_test(NAME Integer COMMAND integer-test)
--- /dev/null
+// 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.
+
+#include "testing.h"
+#include "../../lib/evaluate/expression.h"
+#include <cstdio>
+#include <cstdlib>
+
+using namespace Fortran::evaluate;
+
+int main() {
+ using Int4 = Type<Category::Integer, 4>;
+ using IntEx4 = Expression<Int4>;
+ auto ie = IntEx4{value::Integer<32>(666)};
+ auto one = IntEx4{value::Integer<32>(1)};
+ auto incr = IntEx4{IntEx4::Binary::Operator::Add, std::move(ie), std::move(one)};
+ using Log = Expression<Type<Category::Logical, 1>>;
+ auto two = IntEx4{value::Integer<32>(2)};
+ auto cmp = Log{Log::ComparisonOperator::EQ, std::move(incr), std::move(two)};
+ return testing::Complete();
+}
#include "../../lib/evaluate/type.h"
#include <cstdio>
-using namespace Fortran::evaluate::type;
-
template<int KIND> void testKind() {
- using Type = Logical<KIND>;
- TEST(Type::classification == Classification::Logical);
+ using Type = Fortran::evaluate::Type<Fortran::evaluate::Category::Logical, KIND>;
+ TEST(Type::category == Fortran::evaluate::Category::Logical);
TEST(Type::kind == KIND);
TEST(!Type::hasLen);
- using Value = typename Type::ValueType;
+ using Value = typename Type::Value;
MATCH(8 * KIND, Value::bits);
TEST(!Value{}.IsTrue());
TEST(!Value{false}.IsTrue());
using namespace Fortran::evaluate;
-using Real2 = typename type::Real<2>::ValueType;
-using Real4 = typename type::Real<4>::ValueType;
-using Real8 = typename type::Real<8>::ValueType;
-using Real10 = typename type::Real<10>::ValueType;
-using Real16 = typename type::Real<16>::ValueType;
-using Integer4 = typename type::Integer<4>::ValueType;
-using Integer8 = typename type::Integer<8>::ValueType;
+using Real2 = typename Type<Category::Real, 2>::Value;
+using Real4 = typename Type<Category::Real, 4>::Value;
+using Real8 = typename Type<Category::Real, 8>::Value;
+using Real10 = typename Type<Category::Real, 10>::Value;
+using Real16 = typename Type<Category::Real, 16>::Value;
+using Integer4 = typename Type<Category::Integer, 4>::Value;
+using Integer8 = typename Type<Category::Integer, 8>::Value;
template<typename R> void basicTests(int rm, Rounding rounding) {
char desc[64];
roundTest(2, Rounding::Up, opds);
roundTest(3, Rounding::Down, opds);
// TODO: how to test Rounding::TiesAwayFromZero on x86?
+ return testing::Complete();
}