// Defines a smart pointer class template that's rather like std::unique_ptr<>
// but further restricted, like a C++ reference, to be non-null when constructed
// or assigned. Users need not check whether these pointers are null.
-// Intended to be as invisible as possible.
+// Supports copy construction, too.
+// Intended to be as invisible as a reference, wherever possible.
#include "../common/idioms.h"
#include <utility>
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(A &&x) : p_{new A(std::move(x))} {}
+ Indirection(const Indirection &that) {
+ CHECK(that.p_ && "copy construction of Indirection from null Indirection");
+ p_ = new A(*that.p_);
+ }
Indirection(Indirection &&that) : p_{that.p_} {
CHECK(p_ && "move construction of Indirection from null Indirection");
that.p_ = nullptr;
delete p_;
p_ = nullptr;
}
+ Indirection &operator=(const Indirection &that) {
+ CHECK(that.p_ && "copy assignment of Indirection from null Indirection");
+ *p_ = *that.p_;
+ return *this;
+ }
Indirection &operator=(Indirection &&that) {
CHECK(that.p_ && "move assignment of null Indirection to Indirection");
auto tmp = p_;
A *operator->() { return p_; }
const A *operator->() const { return p_; }
+ template<typename... ARGS> static Indirection Make(ARGS &&... args) {
+ return {new A(std::forward<ARGS>(args)...)};
+ }
+
private:
A *p_{nullptr};
};
+
} // namespace Fortran::common
#endif // FORTRAN_COMMON_INDIRECTION_H_
integer.cc
logical.cc
real.cc
+ variable.cc
)
target_link_libraries(FortranEvaluate
using HostUnsignedInt =
typename SmallestUInt<BITS <= 8, BITS <= 16, BITS <= 32, BITS <= 64>::type;
+// Many classes in this library follow a common paradigm.
+// - There is no default constructor (Class() {}), usually to prevent the
+// need for std::monostate as a default constituent in a std::variant<>.
+// - There are full copy and move semantics for construction and assignment.
+// - There's a Dump(std::ostream &) member function.
+#define CLASS_BOILERPLATE(t) \
+ t(const t &) = default; \
+ t(t &&) = default; \
+ t &operator=(const t &) = default; \
+ t &operator=(t &&) = default; \
+ std::ostream &Dump(std::ostream &) const;
+
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_COMMON_H_
--- /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.
+
+#ifndef FORTRAN_EVALUATE_EXPRESSION_FORWARD_H_
+#define FORTRAN_EVALUATE_EXPRESSION_FORWARD_H_
+
+// Some forward definitions for expression.h that need to be available
+// in variable.h to resolve cases of mutual references between class
+// definitions.
+
+#include "type.h"
+
+namespace Fortran::evaluate {
+
+// An expression of some specific result type.
+template<Category CAT, int KIND> struct Expr;
+
+// An expression of some supported kind of a category of result type.
+template<Category CAT> struct CategoryExpr;
+
+template<int KIND> using IntegerExpr = Expr<Category::Integer, KIND>;
+using DefaultIntegerExpr = IntegerExpr<DefaultInteger::kind>;
+template<int KIND> using RealExpr = Expr<Category::Real, KIND>;
+template<int KIND> using ComplexExpr = Expr<Category::Complex, KIND>;
+template<int KIND> using CharacterExpr = Expr<Category::Character, KIND>;
+using LogicalExpr = Expr<Category::Logical, 1>;
+using GenericIntegerExpr = CategoryExpr<Category::Integer>;
+using GenericRealExpr = CategoryExpr<Category::Real>;
+using GenericComplexExpr = CategoryExpr<Category::Complex>;
+using GenericCharacterExpr = CategoryExpr<Category::Character>;
+
+// A completely generic expression.
+struct GenericExpr;
+
+} // namespace Fortran::evaluate
+#endif // FORTRAN_EVALUATE_EXPRESSION_FORWARD_H_
// limitations under the License.
#include "expression.h"
+#include "variable.h"
#include "../common/idioms.h"
+#include "../parser/characters.h"
#include <ostream>
#include <string>
#include <type_traits>
}
template<Category CAT>
-std::ostream &AnyKindExpr<CAT>::Dump(std::ostream &o) const {
+std::ostream &CategoryExpr<CAT>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
template<Category CAT>
-std::ostream &AnyKindComparison<CAT>::Dump(std::ostream &o) const {
+std::ostream &CategoryComparison<CAT>::Dump(std::ostream &o) const {
return DumpExpr(o, u);
}
-std::ostream &AnyExpr::Dump(std::ostream &o) const { return DumpExpr(o, u); }
+std::ostream &GenericExpr::Dump(std::ostream &o) const {
+ return DumpExpr(o, u);
+}
template<typename A>
std::ostream &Unary<A>::Dump(std::ostream &o, const char *opr) const {
std::ostream &Expr<Category::Integer, KIND>::Dump(std::ostream &o) const {
std::visit(
common::visitors{[&](const Constant &n) { o << n.SignedDecimal(); },
+ [&](const common::Indirection<Designator> &d) { d->Dump(o); },
[&](const Parentheses &p) { p.Dump(o, "("); },
[&](const Negate &n) { n.Dump(o, "(-"); },
[&](const Add &a) { a.Dump(o, "+"); },
template<int KIND>
std::ostream &Expr<Category::Character, KIND>::Dump(std::ostream &o) const {
- std::visit(common::visitors{[&](const Constant &s) { o << '"' << s << '"'; },
- [&](const Concat &c) { c.y->Dump(c.x->Dump(o) << "//"); }},
+ std::visit(common::visitors{[&](const Constant &s) {
+ o << parser::QuoteCharacterLiteral(s);
+ },
+ [&](const auto &concat) {
+ concat.y->Dump(concat.x->Dump(o) << "//");
+ }},
u);
return o;
}
template<int KIND>
void Expr<Category::Integer, KIND>::Fold(FoldingContext &context) {
- std::visit(common::visitors{[&](const Parentheses &p) {
+ std::visit(common::visitors{[&](Parentheses &p) {
p.x->Fold(context);
if (auto c{std::get_if<Constant>(&p.x->u)}) {
u = std::move(*c);
}
},
- [&](const Negate &n) {
+ [&](Negate &n) {
n.x->Fold(context);
if (auto c{std::get_if<Constant>(&n.x->u)}) {
auto negated{c->Negate()};
u = std::move(negated.value);
}
},
- [&](const Add &a) {
+ [&](Add &a) {
a.x->Fold(context);
a.y->Fold(context);
if (auto xc{std::get_if<Constant>(&a.x->u)}) {
}
}
},
- [&](const Multiply &a) {
+ [&](Multiply &a) {
a.x->Fold(context);
a.y->Fold(context);
if (auto xc{std::get_if<Constant>(&a.x->u)}) {
}
}
},
- [&](const Bin &b) {
+ [&](Bin &b) {
b.x->Fold(context);
b.y->Fold(context);
},
template<int KIND>
typename CharacterExpr<KIND>::LengthExpr CharacterExpr<KIND>::LEN() const {
- return std::visit(
- common::visitors{
- [](const std::string &str) { return LengthExpr{str.size()}; },
- [](const Concat &c) {
- return LengthExpr{LengthExpr::Add{c.x->LEN(), c.y->LEN()}};
- }},
+ return std::visit(common::visitors{[](const std::string &str) {
+ return LengthExpr{str.size()};
+ },
+ [](const auto &concat) {
+ return LengthExpr{LengthExpr::Add{
+ concat.x->LEN(), concat.y->LEN()}};
+ }},
u);
}
// context-independent hash table or sharing of common subexpressions.
// Both deep copy and move semantics are supported for expression construction
// and manipulation in place.
-// TODO: variable and function references
// TODO: elevate some intrinsics to operations
// TODO: convenience wrappers for constructing conversions
#include "common.h"
#include "type.h"
+#include "variable.h"
#include "../lib/common/idioms.h"
+#include "../lib/common/indirection.h"
#include "../lib/parser/char-block.h"
#include "../lib/parser/message.h"
-#include <memory>
#include <ostream>
#include <variant>
namespace Fortran::evaluate {
-// Some forward definitions
-template<Category CAT, int KIND> struct Expr;
-template<Category CAT> struct AnyKindExpr;
-
-template<int KIND> using IntegerExpr = Expr<Category::Integer, KIND>;
-using DefaultIntegerExpr = IntegerExpr<DefaultInteger::kind>;
-template<int KIND> using RealExpr = Expr<Category::Real, KIND>;
-template<int KIND> using ComplexExpr = Expr<Category::Complex, KIND>;
-template<int KIND> using CharacterExpr = Expr<Category::Character, KIND>;
-using LogicalExpr = Expr<Category::Logical, 1>;
-using AnyKindIntegerExpr = AnyKindExpr<Category::Integer>;
-using AnyKindRealExpr = AnyKindExpr<Category::Real>;
-using AnyKindComplexExpr = AnyKindExpr<Category::Complex>;
-using AnyKindCharacterExpr = AnyKindExpr<Category::Character>;
-
struct FoldingContext {
const parser::CharBlock &at;
parser::Messages *messages;
};
-// Helper base classes to manage subexpressions, which are known as data
+// Helper base classes for packaging subexpressions, which are known as data
// members named 'x' and, for binary operations, 'y'.
template<typename A> struct Unary {
- Unary(const A &a) : x{std::make_unique<A>(a)} {}
- Unary(std::unique_ptr<A> &&a) : x{std::move(a)} {}
- Unary(A &&a) : x{std::make_unique<A>(std::move(a))} {}
- Unary(const Unary &that) : x{std::make_unique<A>(*that.x)} {}
- Unary(Unary &&) = default;
- Unary &operator=(const Unary &that) {
- x = std::make_unique<A>(*that.x);
- return *this;
- }
- Unary &operator=(Unary &&) = default;
+ CLASS_BOILERPLATE(Unary)
+ Unary(const A &a) : x{a} {}
+ Unary(common::Indirection<A> &&a) : x{std::move(a)} {}
+ Unary(A &&a) : x{std::move(a)} {}
std::ostream &Dump(std::ostream &, const char *opr) const;
- std::unique_ptr<A> x;
+ common::Indirection<A> x;
};
template<typename A, typename B = A> struct Binary {
- Binary(const A &a, const B &b)
- : x{std::make_unique<A>(a)}, y{std::make_unique<B>(b)} {}
- Binary(std::unique_ptr<const A> &&a, std::unique_ptr<const B> &&b)
+ CLASS_BOILERPLATE(Binary)
+ Binary(const A &a, const B &b) : x{a}, y{b} {}
+ Binary(common::Indirection<const A> &&a, common::Indirection<const B> &&b)
: x{std::move(a)}, y{std::move(b)} {}
- Binary(A &&a, B &&b)
- : x{std::make_unique<A>(std::move(a))}, y{std::make_unique<B>(
- std::move(b))} {}
- Binary(const Binary &that)
- : x{std::make_unique<A>(*that.x)}, y{std::make_unique<B>(*that.y)} {}
- Binary(Binary &&) = default;
- Binary &operator=(const Binary &that) {
- x = std::make_unique<A>(*that.x);
- y = std::make_unique<B>(*that.y);
- return *this;
- }
- Binary &operator=(Binary &&) = default;
+ Binary(A &&a, B &&b) : x{std::move(a)}, y{std::move(b)} {}
std::ostream &Dump(std::ostream &, const char *opr) const;
- std::unique_ptr<A> x;
- std::unique_ptr<B> y;
+ common::Indirection<A> x;
+ common::Indirection<B> y;
};
template<int KIND> struct Expr<Category::Integer, KIND> {
using Result = Type<Category::Integer, KIND>;
using Constant = typename Result::Value;
- template<typename A> struct Convert : Unary<A> { using Unary<A>::Unary; };
+ template<typename A> struct Convert : public Unary<A> {
+ using Unary<A>::Unary;
+ };
using Un = Unary<Expr>;
using Bin = Binary<Expr>;
struct Parentheses : public Un {
using Bin::Bin;
};
- Expr() = delete;
- Expr(const Expr &) = default;
- Expr(Expr &&) = default;
+ CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u{x} {}
Expr(std::int64_t n) : u{Constant{n}} {}
+ Expr(std::uint64_t n) : u{Constant{n}} {}
Expr(int n) : u{Constant{n}} {}
template<Category CAT, int K>
Expr(const Expr<CAT, K> &x)
- : u{Convert<AnyKindExpr<CAT>>{AnyKindExpr<CAT>{x}}} {}
+ : u{Convert<CategoryExpr<CAT>>{CategoryExpr<CAT>{x}}} {}
template<Category CAT, int K>
Expr(Expr<CAT, K> &&x)
- : u{Convert<AnyKindExpr<CAT>>{AnyKindExpr<CAT>{std::move(x)}}} {}
+ : u{Convert<CategoryExpr<CAT>>{CategoryExpr<CAT>{std::move(x)}}} {}
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
- Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u(std::move(x)) {}
- Expr &operator=(const Expr &) = default;
- Expr &operator=(Expr &&) = default;
+ Expr(std::enable_if_t<!std::is_reference_v<A> &&
+ (std::is_base_of_v<Un, A> || std::is_base_of_v<Bin, A>),
+ A> &&x)
+ : u(std::move(x)) {}
- std::ostream &Dump(std::ostream &) const;
void Fold(FoldingContext &);
- std::variant<Constant, Convert<AnyKindIntegerExpr>, Convert<AnyKindRealExpr>,
- Parentheses, Negate, Add, Subtract, Multiply, Divide, Power>
+ std::variant<Constant, common::Indirection<Designator>,
+ Convert<GenericIntegerExpr>, Convert<GenericRealExpr>, Parentheses,
+ Negate, Add, Subtract, Multiply, Divide, Power>
u;
};
// 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.
- template<typename A> struct Convert : Unary<A> { using Unary<A>::Unary; };
+ template<typename A> struct Convert : public Unary<A> {
+ using Unary<A>::Unary;
+ };
using Un = Unary<Expr>;
using Bin = Binary<Expr>;
struct Parentheses : public Un {
struct Power : public Bin {
using Bin::Bin;
};
- struct IntPower : public Binary<Expr, AnyKindIntegerExpr> {
- using Binary<Expr, AnyKindIntegerExpr>::Binary;
+ struct IntPower : public Binary<Expr, GenericIntegerExpr> {
+ using Binary<Expr, GenericIntegerExpr>::Binary;
};
using CplxUn = Unary<ComplexExpr<KIND>>;
struct RealPart : public CplxUn {
using CplxUn::CplxUn;
};
- Expr() = delete;
- Expr(const Expr &) = default;
- Expr(Expr &&) = default;
+ CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u{x} {}
template<Category CAT, int K>
Expr(const Expr<CAT, K> &x)
- : u{Convert<AnyKindExpr<CAT>>{AnyKindExpr<CAT>{x}}} {}
+ : u{Convert<CategoryExpr<CAT>>{CategoryExpr<CAT>{x}}} {}
template<Category CAT, int K>
Expr(Expr<CAT, K> &&x)
- : u{Convert<AnyKindExpr<CAT>>{AnyKindExpr<CAT>{std::move(x)}}} {}
+ : u{Convert<CategoryExpr<CAT>>{CategoryExpr<CAT>{std::move(x)}}} {}
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
- Expr &operator=(const Expr &) = default;
- Expr &operator=(Expr &&) = default;
-
- std::ostream &Dump(std::ostream &) const;
- std::variant<Constant, Convert<AnyKindIntegerExpr>, Convert<AnyKindRealExpr>,
+ std::variant<Constant, Convert<GenericIntegerExpr>, Convert<GenericRealExpr>,
Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, IntPower,
RealPart, AIMAG>
u;
struct Power : public Bin {
using Bin::Bin;
};
- struct IntPower : public Binary<Expr, AnyKindIntegerExpr> {
- using Binary<Expr, AnyKindIntegerExpr>::Binary;
+ struct IntPower : public Binary<Expr, GenericIntegerExpr> {
+ using Binary<Expr, GenericIntegerExpr>::Binary;
};
struct CMPLX : public Binary<RealExpr<KIND>> {
using Binary<RealExpr<KIND>>::Binary;
};
- Expr() = delete;
- Expr(const Expr &) = default;
- Expr(Expr &&) = default;
+ CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u{x} {}
template<typename A> Expr(const A &x) : u{x} {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
- Expr &operator=(const Expr &) = default;
- Expr &operator=(Expr &&) = default;
-
- std::ostream &Dump(std::ostream &) const;
std::variant<Constant, Parentheses, Negate, Add, Subtract, Multiply, Divide,
Power, IntPower, CMPLX>
using Result = Type<Category::Character, KIND>;
using Constant = typename Result::Value;
using LengthExpr = IntegerExpr<IntrinsicTypeParameterType::kind>;
- struct Concat : public Binary<Expr> {
- using Binary<Expr>::Binary;
- };
- Expr() = delete;
- Expr(const Expr &) = default;
- Expr(Expr &&) = default;
+ CLASS_BOILERPLATE(Expr)
Expr(const Constant &x) : u{x} {}
Expr(Constant &&x) : u{std::move(x)} {}
- Expr(const Concat &x) : u{x} {}
- Expr(Concat &&x) : u{std::move(x)} {}
- Expr &operator=(const Expr &) = default;
- Expr &operator=(Expr &&) = default;
+ Expr(const Expr &x, const Expr &y) : u{Binary<Expr>{x, y}} {}
+ Expr(Expr &&x, Expr &&y) : u{Binary<Expr>{std::move(x), std::move(y)}} {}
LengthExpr LEN() const;
- std::ostream &Dump(std::ostream &) const;
- std::variant<Constant, Concat> u;
+ std::variant<Constant, Binary<Expr>> u;
};
// The Comparison class template is a helper for constructing logical
ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT)
template<typename EXPR> struct Comparison : Binary<EXPR> {
- Comparison(const Comparison &) = default;
- Comparison(Comparison &&) = default;
+ CLASS_BOILERPLATE(Comparison)
Comparison(RelationalOperator r, const EXPR &a, const EXPR &b)
: Binary<EXPR>{a, b}, opr{r} {}
Comparison(RelationalOperator r, EXPR &&a, EXPR &&b)
: Binary<EXPR>{std::move(a), std::move(b)}, opr{r} {}
- Comparison &operator=(const Comparison &) = default;
- Comparison &operator=(Comparison &&) = default;
-
- std::ostream &Dump(std::ostream &) const;
RelationalOperator opr;
};
extern template struct Comparison<ComplexExpr<16>>;
extern template struct Comparison<CharacterExpr<1>>;
-// Dynamically polymorphic comparisonsq that can hold any supported kind
-// of a category.
-template<Category CAT> struct AnyKindComparison {
- AnyKindComparison() = delete;
- AnyKindComparison(const AnyKindComparison &) = default;
- AnyKindComparison(AnyKindComparison &&) = default;
+// Dynamically polymorphic comparisons that can hold any supported kind
+// of a specific category.
+template<Category CAT> struct CategoryComparison {
+ CLASS_BOILERPLATE(CategoryComparison)
template<int KIND>
- AnyKindComparison(const Comparison<Expr<CAT, KIND>> &x) : u{x} {}
+ CategoryComparison(const Comparison<Expr<CAT, KIND>> &x) : u{x} {}
template<int KIND>
- AnyKindComparison(Comparison<Expr<CAT, KIND>> &&x) : u{std::move(x)} {}
- AnyKindComparison &operator=(const AnyKindComparison &) = default;
- AnyKindComparison &operator=(AnyKindComparison &&) = default;
- std::ostream &Dump(std::ostream &) const;
+ CategoryComparison(Comparison<Expr<CAT, KIND>> &&x) : u{std::move(x)} {}
template<int K> using KindComparison = Comparison<Expr<CAT, K>>;
typename KindsVariant<CAT, KindComparison>::type u;
};
using Bin::Bin;
};
- Expr() = delete;
- Expr(const Expr &) = default;
- Expr(Expr &&) = default;
+ CLASS_BOILERPLATE(Expr)
Expr(Constant x) : u{x} {}
template<Category CAT, int KIND>
- Expr(const Comparison<Expr<CAT, KIND>> &x) : u{AnyKindComparison<CAT>{x}} {}
+ Expr(const Comparison<Expr<CAT, KIND>> &x) : u{CategoryComparison<CAT>{x}} {}
template<Category CAT, int KIND>
Expr(Comparison<Expr<CAT, KIND>> &&x)
- : u{AnyKindComparison<CAT>{std::move(x)}} {}
- template<typename A> Expr(const A &x) : u{x} {}
+ : u{CategoryComparison<CAT>{std::move(x)}} {}
+ template<typename A> Expr(const A &x) : u(x) {}
template<typename A>
Expr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
- Expr &operator=(const Expr &) = default;
- Expr &operator=(Expr &&) = default;
-
- std::ostream &Dump(std::ostream &) const;
std::variant<Constant, Not, And, Or, Eqv, Neqv,
- AnyKindComparison<Category::Integer>, AnyKindComparison<Category::Real>,
- AnyKindComparison<Category::Complex>,
- AnyKindComparison<Category::Character>>
+ CategoryComparison<Category::Integer>, CategoryComparison<Category::Real>,
+ CategoryComparison<Category::Complex>,
+ CategoryComparison<Category::Character>>
u;
};
extern template struct Expr<Category::Logical, 1>;
// Dynamically polymorphic expressions that can hold any supported kind
-// of a category.
-template<Category CAT> struct AnyKindExpr {
- AnyKindExpr() = delete;
- AnyKindExpr(const AnyKindExpr &) = default;
- AnyKindExpr(AnyKindExpr &&) = default;
- template<int KIND> AnyKindExpr(const Expr<CAT, KIND> &x) : u{x} {}
- template<int KIND> AnyKindExpr(Expr<CAT, KIND> &&x) : u{std::move(x)} {}
- AnyKindExpr &operator=(const AnyKindExpr &) = default;
- AnyKindExpr &operator=(AnyKindExpr &&) = default;
- std::ostream &Dump(std::ostream &) const;
+// of a specific category.
+template<Category CAT> struct CategoryExpr {
+ CLASS_BOILERPLATE(CategoryExpr)
+ template<int KIND> CategoryExpr(const Expr<CAT, KIND> &x) : u{x} {}
+ template<int KIND> CategoryExpr(Expr<CAT, KIND> &&x) : u{std::move(x)} {}
template<int K> using KindExpr = Expr<CAT, K>;
typename KindsVariant<CAT, KindExpr>::type u;
};
-struct AnyExpr {
- AnyExpr() = delete;
- AnyExpr(const AnyExpr &) = default;
- AnyExpr(AnyExpr &&) = default;
+// A completely generic expression, polymorphic across the type categories.
+struct GenericExpr {
+ CLASS_BOILERPLATE(GenericExpr)
template<Category CAT, int KIND>
- AnyExpr(const Expr<CAT, KIND> &x) : u{AnyKindExpr<CAT>{x}} {}
+ GenericExpr(const Expr<CAT, KIND> &x) : u{CategoryExpr<CAT>{x}} {}
template<Category CAT, int KIND>
- AnyExpr(Expr<CAT, KIND> &&x) : u{AnyKindExpr<CAT>{std::move(x)}} {}
- template<typename A> AnyExpr(const A &x) : u{x} {}
+ GenericExpr(Expr<CAT, KIND> &&x) : u{CategoryExpr<CAT>{std::move(x)}} {}
+ template<typename A> GenericExpr(const A &x) : u{x} {}
template<typename A>
- AnyExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x) : u{std::move(x)} {}
- AnyExpr &operator=(const AnyExpr &) = default;
- AnyExpr &operator=(AnyExpr &&) = default;
- std::ostream &Dump(std::ostream &) const;
- std::variant<AnyKindIntegerExpr, AnyKindRealExpr, AnyKindComplexExpr,
- AnyKindCharacterExpr, LogicalExpr>
+ GenericExpr(std::enable_if_t<!std::is_reference_v<A>, A> &&x)
+ : u{std::move(x)} {}
+ std::variant<GenericIntegerExpr, GenericRealExpr, GenericComplexExpr,
+ GenericCharacterExpr, LogicalExpr>
u;
};
--- /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 "variable.h"
+#include "../common/idioms.h"
+#include "../parser/char-block.h"
+#include "../parser/characters.h"
+#include "../semantics/symbol.h"
+#include <ostream>
+
+namespace Fortran::evaluate {
+
+Triplet::Triplet(std::optional<SubscriptExpr> &&l,
+ std::optional<SubscriptExpr> &&u, std::optional<SubscriptExpr> &&s) {
+ if (l.has_value()) {
+ lower = SubscriptExpr{std::move(*l)};
+ }
+ if (u.has_value()) {
+ upper = SubscriptExpr{std::move(*u)};
+ }
+ if (s.has_value()) {
+ stride = SubscriptExpr{std::move(*s)};
+ }
+}
+
+// Variable dumping
+
+template<typename A> std::ostream &Emit(std::ostream &o, const A &x) {
+ return x.Dump(o);
+}
+
+template<> std::ostream &Emit(std::ostream &o, const std::string &lit) {
+ return o << parser::QuoteCharacterLiteral(lit);
+}
+
+template<typename A>
+std::ostream &Emit(std::ostream &o, const A *p, const char *kw = nullptr) {
+ if (p != nullptr) {
+ if (kw != nullptr) {
+ o << kw;
+ }
+ Emit(o, *p);
+ }
+ return o;
+}
+
+template<typename A>
+std::ostream &Emit(
+ std::ostream &o, const std::optional<A> &x, const char *kw = nullptr) {
+ if (x.has_value()) {
+ if (kw != nullptr) {
+ o << kw;
+ }
+ Emit(o, *x);
+ }
+ return o;
+}
+
+template<typename A>
+std::ostream &Emit(std::ostream &o, const common::Indirection<A> &p,
+ const char *kw = nullptr) {
+ if (kw != nullptr) {
+ o << kw;
+ }
+ Emit(o, *p);
+ return o;
+}
+
+template<typename... A>
+std::ostream &Emit(std::ostream &o, const std::variant<A...> &u) {
+ std::visit([&](const auto &x) { Emit(o, x); }, u);
+ return o;
+}
+
+template<> std::ostream &Emit(std::ostream &o, const Symbol &symbol) {
+ return o << symbol.name().ToString();
+}
+
+std::ostream &Component::Dump(std::ostream &o) const {
+ base->Dump(o);
+ return Emit(o << '%', sym);
+}
+
+std::ostream &Triplet::Dump(std::ostream &o) const {
+ Emit(o, lower) << ':';
+ Emit(o, upper);
+ if (stride) {
+ Emit(o << ':', stride);
+ }
+ return o;
+}
+
+std::ostream &Subscript::Dump(std::ostream &o) const { return Emit(o, u); }
+
+std::ostream &ArrayRef::Dump(std::ostream &o) const {
+ Emit(o, u);
+ char separator{'('};
+ for (const Subscript &ss : subscript) {
+ ss.Dump(o << separator);
+ separator = ',';
+ }
+ return o << ')';
+}
+
+std::ostream &CoarrayRef::Dump(std::ostream &o) const {
+ Emit(o, u);
+ char separator{'['};
+ for (const SubscriptExpr &css : cosubscript) {
+ Emit(o << separator, css);
+ separator = ',';
+ }
+ Emit(o, stat, "STAT=");
+ Emit(o, team, "TEAM=");
+ Emit(o, teamNumber, "TEAM_NUMBER=");
+ return o << ']';
+}
+
+std::ostream &DataRef::Dump(std::ostream &o) const { return Emit(o, u); }
+
+std::ostream &Substring::Dump(std::ostream &o) const {
+ Emit(o, u) << '(';
+ Emit(o, first) << ':';
+ return Emit(o, last);
+}
+
+std::ostream &ComplexPart::Dump(std::ostream &o) const {
+ return complex.Dump(o) << '%' << EnumToString(part);
+}
+
+std::ostream &Designator::Dump(std::ostream &o) const { return Emit(o, u); }
+
+std::ostream &ProcedureDesignator::Dump(std::ostream &o) const {
+ return Emit(o, u);
+}
+
+std::ostream &ProcedureRef::Dump(std::ostream &o) const {
+ Emit(o, proc);
+ char separator{'('};
+ for (const auto &arg : argument) {
+ Emit(o << separator, arg);
+ separator = ',';
+ }
+ if (separator == '(') {
+ o << '(';
+ }
+ return o << ')';
+}
+
+std::ostream &Variable::Dump(std::ostream &o) const { return Emit(o, u); }
+
+std::ostream &ActualArg::Dump(std::ostream &o) const { return Emit(o, u); }
+
+std::ostream &Label::Dump(std::ostream &o) const {
+ return o << '*' << std::dec << label;
+}
+} // namespace Fortran::evaluate
#ifndef FORTRAN_EVALUATE_VARIABLE_H_
#define FORTRAN_EVALUATE_VARIABLE_H_
-#include "expression.h"
-#include "traverse.h"
-#include <memory>
+#include "common.h"
+#include "expression-forward.h"
+#include "../common/idioms.h"
+#include "../common/indirection.h"
+#include "../semantics/symbol.h"
#include <optional>
+#include <ostream>
#include <variant>
#include <vector>
struct DataRef;
struct Variable;
struct ActualArg;
-struct Label; // TODO
+struct Label;
using semantics::Symbol;
struct Component {
- Component(const Symbol &c, std::unique_ptr<DataRef> &&b)
- : sym{c}, base{std::move(b)} {}
- const Symbol &sym;
- template<typename V> void DefaultTraverse(V &v) { v(base); }
- std::unique_ptr<DataRef> base;
+ CLASS_BOILERPLATE(Component)
+ Component(const DataRef &b, const Symbol &c) : base{b}, sym{&c} {}
+ Component(common::Indirection<DataRef> &&b, const Symbol &c)
+ : base{std::move(b)}, sym{&c} {}
+ common::Indirection<DataRef> base;
+ const Symbol *sym;
};
-using SubscriptExpr = DefaultIntExpr;
+using SubscriptExpr = common::Indirection<DefaultIntegerExpr>;
struct Triplet {
- Triplet(std::optional<SubscriptExpr> &&l, std::optional<SubscriptExpr> &&u,
- std::optional<SubscriptExpr> &&s)
- : lower{std::move(l)}, upper{std::move(u)}, stride{std::move(s)} {}
- template<typename V> void DefaultTraverse(V &v) {
- v(lower);
- v(upper);
- v(stride);
- }
+ CLASS_BOILERPLATE(Triplet)
+ Triplet(std::optional<SubscriptExpr> &&, std::optional<SubscriptExpr> &&,
+ std::optional<SubscriptExpr> &&);
std::optional<SubscriptExpr> lower, upper, stride;
};
struct Subscript {
- Subscript() = delete;
+ CLASS_BOILERPLATE(Subscript)
+ explicit Subscript(const SubscriptExpr &s) : u{s} {}
explicit Subscript(SubscriptExpr &&s) : u{std::move(s)} {}
+ explicit Subscript(const Triplet &t) : u{t} {}
explicit Subscript(Triplet &&t) : u{std::move(t)} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
std::variant<SubscriptExpr, Triplet> u;
};
struct ArrayRef {
- ArrayRef() = delete;
- ArrayRef(const Symbol &n, std::vector<Subscript> &&s)
- : u{n}, subscript{std::move(ss)} {}
- ArrayRef(Component &&c, std::vector<Subscript> &&s)
- : u{std::move(c)}, subscript{std::move(ss)} {}
- template<typename V> void DefaultTraverse(V &v) {
- v(u);
- v(subscript);
- }
- std::variant<const Symbol &, Component> u;
+ CLASS_BOILERPLATE(ArrayRef)
+ ArrayRef(const Symbol &n, std::vector<Subscript> &&ss)
+ : u{&n}, subscript(std::move(ss)) {}
+ ArrayRef(Component &&c, std::vector<Subscript> &&ss)
+ : u{std::move(c)}, subscript(std::move(ss)) {}
+ std::variant<const Symbol *, Component> u;
std::vector<Subscript> subscript;
};
struct CoarrayRef {
- CoarrayRef() = delete;
+ CLASS_BOILERPLATE(CoarrayRef)
CoarrayRef(const Symbol &n, std::vector<SubscriptExpr> &&s)
- : u{n}, cosubscript{std::move(s)} {}
+ : u{&n}, cosubscript(std::move(s)) {}
CoarrayRef(Component &&c, std::vector<SubscriptExpr> &&s)
- : u{std::move(c)}, cosubscript{std::move(s)} {}
+ : u{std::move(c)}, cosubscript(std::move(s)) {}
CoarrayRef(ArrayRef &&a, std::vector<SubscriptExpr> &&s)
- : u{std::move(a)}, cosubscript{std::move(s)} {}
- template<typename V> void DefaultTraverse(V &v) {
- v(u);
- v(cosubscript);
- v(stat);
- v(team);
- v(teamNumber);
- }
- std::variant<const Symbol &, Component, ArrayRef> u;
+ : u{std::move(a)}, cosubscript(std::move(s)) {}
+ std::variant<const Symbol *, Component, ArrayRef> u;
std::vector<SubscriptExpr> cosubscript;
- std::unique_ptr<Variable> stat, team, teamNumber; // nullable
+ std::optional<common::Indirection<Variable>> stat, team, teamNumber;
};
struct DataRef {
- DataRef() = delete;
- explicit DataRef(const Symbol &n) : u{n} {}
+ CLASS_BOILERPLATE(DataRef)
+ explicit DataRef(const Symbol &n) : u{&n} {}
explicit DataRef(Component &&c) : u{std::move(c)} {}
explicit DataRef(ArrayRef &&a) : u{std::move(a)} {}
explicit DataRef(CoarrayRef &&c) : u{std::move(c)} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
- std::variant<const Symbol &, Component, ArrayRef, CoarrayRef> u;
+ std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u;
};
struct Substring {
- Substring() = delete;
+ CLASS_BOILERPLATE(Substring)
Substring(DataRef &&d, std::optional<SubscriptExpr> &&f,
std::optional<SubscriptExpr> &&l)
: u{std::move(d)}, first{std::move(f)}, last{std::move(l)} {}
Substring(std::string &&s, std::optional<SubscriptExpr> &&f,
std::optional<SubscriptExpr> &&l)
: u{std::move(s)}, first{std::move(f)}, last{std::move(l)} {}
- template<typename V> void DefaultTraverse(V &v) {
- v(u);
- v(first);
- v(last);
- }
std::variant<DataRef, std::string> u;
std::optional<SubscriptExpr> first, last;
};
struct ComplexPart {
- enum class Part { RE, IM };
+ ENUM_CLASS(Part, RE, IM)
+ CLASS_BOILERPLATE(ComplexPart)
ComplexPart(DataRef &&z, Part p) : complex{std::move(z)}, part{p} {}
- template<typename V> void DefaultTraverse(V &v) { v(complex); }
DataRef complex;
Part part;
};
struct Designator {
- Designator() = delete;
+ CLASS_BOILERPLATE(Designator)
explicit Designator(DataRef &&d) : u{std::move(d)} {}
explicit Designator(Substring &&s) : u{std::move(s)} {}
explicit Designator(ComplexPart &&c) : u{std::move(c)} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
std::variant<DataRef, Substring, ComplexPart> u;
};
struct ProcedureDesignator {
- ProcedureDesignator() = delete;
- ProcedureDesignator(std::unique_ptr<Variable> &&v, const Symbol &n)
- : u{std::move(v)}, sym{n} {}
- ProcedureDesignator(DataRef &&d, const Symbol &n) : u{std::move(d)}, sym{n} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
- std::variant<std::unique_ptr<Variable>, DataRef> u;
- const Symbol &sym;
+ CLASS_BOILERPLATE(ProcedureDesignator)
+ explicit ProcedureDesignator(const Symbol &n) : u{&n} {}
+ explicit ProcedureDesignator(const Component &c) : u{c} {}
+ explicit ProcedureDesignator(Component &&c) : u{std::move(c)} {}
+ std::variant<const Symbol *, Component> u;
};
-struct ProcedureRef {
- ProcedureRef() = delete;
+struct ProcedureRef { // TODO split off FunctionRef without alt returns
+ CLASS_BOILERPLATE(ProcedureRef)
ProcedureRef(
- ProcedureDesignator &&p, std::vector<std::unique_ptr<ActualArg>> &&a)
- : proc{std::move(p)}, arg{std::move(a)} {}
- template<typename V> void DefaultTraverse(V &v) {
- v(proc);
- v(arg);
- }
+ ProcedureDesignator &&p, std::vector<common::Indirection<ActualArg>> &&a)
+ : proc{std::move(p)}, argument(std::move(a)) {}
ProcedureDesignator proc;
- std::vector<std::unique_ptr<ActualArg>> arg; // nullable
+ std::vector<common::Indirection<ActualArg>> argument;
};
struct Variable {
- Variable() = delete;
- explicit Variable(Designator &&d) : u{std::move(u)} {}
+ CLASS_BOILERPLATE(Variable)
+ explicit Variable(Designator &&d) : u{std::move(d)} {}
explicit Variable(ProcedureRef &&p) : u{std::move(p)} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
std::variant<Designator, ProcedureRef> u;
};
+struct Label { // TODO: this is a placeholder
+ CLASS_BOILERPLATE(Label)
+ explicit Label(int lab) : label{lab} {}
+ int label;
+};
+
struct ActualArg {
- ActualArg() = delete;
- explicit ActualArg(AnyExpr &&x) : u{std::move(x)} {}
+ CLASS_BOILERPLATE(ActualArg)
+ explicit ActualArg(GenericExpr &&x) : u{std::move(x)} {}
explicit ActualArg(Variable &&x) : u{std::move(x)} {}
- explicit ActualArg(const Label &l) : u{l} {}
- template<typename V> void DefaultTraverse(V &v) { v(u); }
- std::variant<AnyExpr, Variable, const Label &> u;
+ explicit ActualArg(const Label &l) : u{&l} {}
+ std::variant<common::Indirection<GenericExpr>, Variable, const Label *> u;
};
} // namespace Fortran::evaluate
+
+// This inclusion must follow the definitions in this header due to
+// mutual references.
+#include "expression.h"
+
#endif // FORTRAN_EVALUATE_VARIABLE_H_
return {chars};
}
+std::string QuoteCharacterLiteral(const std::string &str) {
+ std::string result{'"'};
+ const auto emit = [&](char ch) { result += ch; };
+ for (char ch : str) {
+ EmitQuotedChar(ch, emit, emit);
+ }
+ result += '"';
+ return result;
+}
} // namespace Fortran::parser
}
}
+std::string QuoteCharacterLiteral(const std::string &);
+
std::optional<int> UTF8CharacterBytes(const char *);
std::optional<int> EUC_JPCharacterBytes(const char *);
std::optional<std::size_t> CountCharacters(
// R1520 function-reference -> procedure-designator ( [actual-arg-spec-list] )
TYPE_CONTEXT_PARSER("function reference"_en_US,
construct<FunctionReference>(construct<Call>(Parser<ProcedureDesignator>{},
- parenthesized(optionalList(actualArgSpec)))) / !"["_tok)
+ parenthesized(optionalList(actualArgSpec)))) /
+ !"["_tok)
// R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )]
TYPE_PARSER(
for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
PartRef &pr{prl.front()};
if (!first) {
- u = common::Indirection<StructureComponent>{
- std::move(*this), std::move(pr.name)};
+ u = common::Indirection<StructureComponent>::Make(
+ std::move(*this), std::move(pr.name));
}
if (!pr.subscripts.empty()) {
- u = common::Indirection<ArrayElement>{
- std::move(*this), std::move(pr.subscripts)};
+ u = common::Indirection<ArrayElement>::Make(
+ std::move(*this), std::move(pr.subscripts));
}
if (pr.imageSelector.has_value()) {
- u = common::Indirection<CoindexedNamedObject>{
- std::move(*this), std::move(*pr.imageSelector)};
+ u = common::Indirection<CoindexedNamedObject>::Make(
+ std::move(*this), std::move(*pr.imageSelector));
}
}
}
// R1001 - R1022 expression
-Expr::Expr(Designator &&x) : u{common::Indirection<Designator>(std::move(x))} {}
+Expr::Expr(Designator &&x)
+ : u{common::Indirection<Designator>::Make(std::move(x))} {}
Expr::Expr(FunctionReference &&x)
- : u{common::Indirection<FunctionReference>(std::move(x))} {}
+ : u{common::Indirection<FunctionReference>::Make(std::move(x))} {}
static Designator MakeArrayElementRef(Name &name, std::list<Expr> &subscripts) {
ArrayElement arrayElement{name, std::list<SectionSubscript>{}};
Walk(*k), Put('_');
}
}
- PutQuoted(std::get<std::string>(x.t));
+ Put(QuoteCharacterLiteral(std::get<std::string>(x.t)));
}
void Before(const HollerithLiteralConstant &x) {
std::optional<std::size_t> chars{CountCharacters(x.v.data(), x.v.size(),
if (x.repeatCount.has_value()) {
Walk(*x.repeatCount);
}
- std::visit(common::visitors{[&](const std::string &y) { PutQuoted(y); },
+ std::visit(common::visitors{[&](const std::string &y) {
+ Put(QuoteCharacterLiteral(y));
+ },
[&](const std::list<format::FormatItem> &y) {
Walk("(", y, ",", ")");
},
void Put(const char *);
void Put(const std::string &);
void PutKeywordLetter(char);
- void PutQuoted(const std::string &);
void Word(const char *);
void Word(const std::string &);
void Indent() { indent_ += indentationAmount_; }
}
}
-void UnparseVisitor::PutQuoted(const std::string &str) {
- Put('"');
- const auto emit = [&](char ch) { Put(ch); };
- for (char ch : str) {
- EmitQuotedChar(ch, emit, emit);
- }
- Put('"');
-}
-
void UnparseVisitor::Word(const char *str) {
for (; *str != '\0'; ++str) {
PutKeywordLetter(*str);
target_link_libraries(expression-test
FortranEvaluate
FortranEvaluateTesting
+ FortranParser
)
add_test(NAME Expression COMMAND expression-test)