From e6fc51c7316d90e1850a7af1a2f4c953c100c05b Mon Sep 17 00:00:00 2001 From: peter klausler Date: Fri, 6 Jul 2018 15:12:33 -0700 Subject: [PATCH] [flang] Use Indirection. Get variables to work in int expressions. Original-commit: flang-compiler/f18@1000717da820d87b330719034281a69eaf37bb89 Reviewed-on: https://github.com/flang-compiler/f18/pull/117 Tree-same-pre-rewrite: false --- flang/lib/common/indirection.h | 21 ++- flang/lib/evaluate/CMakeLists.txt | 1 + flang/lib/evaluate/common.h | 12 ++ flang/lib/evaluate/expression-forward.h | 47 +++++++ flang/lib/evaluate/expression.cc | 42 +++--- flang/lib/evaluate/expression.h | 218 +++++++++++--------------------- flang/lib/evaluate/variable.cc | 167 ++++++++++++++++++++++++ flang/lib/evaluate/variable.h | 147 ++++++++++----------- flang/lib/parser/characters.cc | 9 ++ flang/lib/parser/characters.h | 2 + flang/lib/parser/grammar.h | 3 +- flang/lib/parser/parse-tree.cc | 17 +-- flang/lib/parser/unparse.cc | 16 +-- flang/test/evaluate/CMakeLists.txt | 1 + 14 files changed, 436 insertions(+), 267 deletions(-) create mode 100644 flang/lib/evaluate/expression-forward.h create mode 100644 flang/lib/evaluate/variable.cc diff --git a/flang/lib/common/indirection.h b/flang/lib/common/indirection.h index 1a78f30..1778c98 100644 --- a/flang/lib/common/indirection.h +++ b/flang/lib/common/indirection.h @@ -18,7 +18,8 @@ // 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 @@ -34,9 +35,11 @@ public: p = nullptr; } Indirection(const A &x) : p_{new A(x)} {} - Indirection(A &&p) : p_{new A(std::move(p))} {} - template - Indirection(ARGS &&... args) : p_{new A(std::forward(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; @@ -45,6 +48,11 @@ public: 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_; @@ -57,8 +65,13 @@ public: A *operator->() { return p_; } const A *operator->() const { return p_; } + template static Indirection Make(ARGS &&... args) { + return {new A(std::forward(args)...)}; + } + private: A *p_{nullptr}; }; + } // namespace Fortran::common #endif // FORTRAN_COMMON_INDIRECTION_H_ diff --git a/flang/lib/evaluate/CMakeLists.txt b/flang/lib/evaluate/CMakeLists.txt index cf433660..fef2c87 100644 --- a/flang/lib/evaluate/CMakeLists.txt +++ b/flang/lib/evaluate/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(FortranEvaluate integer.cc logical.cc real.cc + variable.cc ) target_link_libraries(FortranEvaluate diff --git a/flang/lib/evaluate/common.h b/flang/lib/evaluate/common.h index dc05f46..f6779ec 100644 --- a/flang/lib/evaluate/common.h +++ b/flang/lib/evaluate/common.h @@ -108,5 +108,17 @@ template using HostUnsignedInt = typename SmallestUInt::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_ diff --git a/flang/lib/evaluate/expression-forward.h b/flang/lib/evaluate/expression-forward.h new file mode 100644 index 0000000..04e3782 --- /dev/null +++ b/flang/lib/evaluate/expression-forward.h @@ -0,0 +1,47 @@ +// 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 struct Expr; + +// An expression of some supported kind of a category of result type. +template struct CategoryExpr; + +template using IntegerExpr = Expr; +using DefaultIntegerExpr = IntegerExpr; +template using RealExpr = Expr; +template using ComplexExpr = Expr; +template using CharacterExpr = Expr; +using LogicalExpr = Expr; +using GenericIntegerExpr = CategoryExpr; +using GenericRealExpr = CategoryExpr; +using GenericComplexExpr = CategoryExpr; +using GenericCharacterExpr = CategoryExpr; + +// A completely generic expression. +struct GenericExpr; + +} // namespace Fortran::evaluate +#endif // FORTRAN_EVALUATE_EXPRESSION_FORWARD_H_ diff --git a/flang/lib/evaluate/expression.cc b/flang/lib/evaluate/expression.cc index fcf2fcd..5270d57 100644 --- a/flang/lib/evaluate/expression.cc +++ b/flang/lib/evaluate/expression.cc @@ -13,7 +13,9 @@ // limitations under the License. #include "expression.h" +#include "variable.h" #include "../common/idioms.h" +#include "../parser/characters.h" #include #include #include @@ -40,16 +42,18 @@ std::ostream &DumpExpr(std::ostream &o, const std::variant &u) { } template -std::ostream &AnyKindExpr::Dump(std::ostream &o) const { +std::ostream &CategoryExpr::Dump(std::ostream &o) const { return DumpExpr(o, u); } template -std::ostream &AnyKindComparison::Dump(std::ostream &o) const { +std::ostream &CategoryComparison::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 std::ostream &Unary::Dump(std::ostream &o, const char *opr) const { @@ -65,6 +69,7 @@ template std::ostream &Expr::Dump(std::ostream &o) const { std::visit( common::visitors{[&](const Constant &n) { o << n.SignedDecimal(); }, + [&](const common::Indirection &d) { d->Dump(o); }, [&](const Parentheses &p) { p.Dump(o, "("); }, [&](const Negate &n) { n.Dump(o, "(-"); }, [&](const Add &a) { a.Dump(o, "+"); }, @@ -115,8 +120,12 @@ std::ostream &Expr::Dump(std::ostream &o) const { template std::ostream &Expr::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; } @@ -144,13 +153,13 @@ std::ostream &Expr::Dump(std::ostream &o) const { template void Expr::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(&p.x->u)}) { u = std::move(*c); } }, - [&](const Negate &n) { + [&](Negate &n) { n.x->Fold(context); if (auto c{std::get_if(&n.x->u)}) { auto negated{c->Negate()}; @@ -161,7 +170,7 @@ void Expr::Fold(FoldingContext &context) { u = std::move(negated.value); } }, - [&](const Add &a) { + [&](Add &a) { a.x->Fold(context); a.y->Fold(context); if (auto xc{std::get_if(&a.x->u)}) { @@ -175,7 +184,7 @@ void Expr::Fold(FoldingContext &context) { } } }, - [&](const Multiply &a) { + [&](Multiply &a) { a.x->Fold(context); a.y->Fold(context); if (auto xc{std::get_if(&a.x->u)}) { @@ -190,7 +199,7 @@ void Expr::Fold(FoldingContext &context) { } } }, - [&](const Bin &b) { + [&](Bin &b) { b.x->Fold(context); b.y->Fold(context); }, @@ -201,12 +210,13 @@ void Expr::Fold(FoldingContext &context) { template typename CharacterExpr::LengthExpr CharacterExpr::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); } diff --git a/flang/lib/evaluate/expression.h b/flang/lib/evaluate/expression.h index d012889..5744b63 100644 --- a/flang/lib/evaluate/expression.h +++ b/flang/lib/evaluate/expression.h @@ -20,84 +20,54 @@ // 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 #include #include namespace Fortran::evaluate { -// Some forward definitions -template struct Expr; -template struct AnyKindExpr; - -template using IntegerExpr = Expr; -using DefaultIntegerExpr = IntegerExpr; -template using RealExpr = Expr; -template using ComplexExpr = Expr; -template using CharacterExpr = Expr; -using LogicalExpr = Expr; -using AnyKindIntegerExpr = AnyKindExpr; -using AnyKindRealExpr = AnyKindExpr; -using AnyKindComplexExpr = AnyKindExpr; -using AnyKindCharacterExpr = AnyKindExpr; - 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 struct Unary { - Unary(const A &a) : x{std::make_unique(a)} {} - Unary(std::unique_ptr &&a) : x{std::move(a)} {} - Unary(A &&a) : x{std::make_unique(std::move(a))} {} - Unary(const Unary &that) : x{std::make_unique(*that.x)} {} - Unary(Unary &&) = default; - Unary &operator=(const Unary &that) { - x = std::make_unique(*that.x); - return *this; - } - Unary &operator=(Unary &&) = default; + CLASS_BOILERPLATE(Unary) + Unary(const A &a) : x{a} {} + Unary(common::Indirection &&a) : x{std::move(a)} {} + Unary(A &&a) : x{std::move(a)} {} std::ostream &Dump(std::ostream &, const char *opr) const; - std::unique_ptr x; + common::Indirection x; }; template struct Binary { - Binary(const A &a, const B &b) - : x{std::make_unique(a)}, y{std::make_unique(b)} {} - Binary(std::unique_ptr &&a, std::unique_ptr &&b) + CLASS_BOILERPLATE(Binary) + Binary(const A &a, const B &b) : x{a}, y{b} {} + Binary(common::Indirection &&a, common::Indirection &&b) : x{std::move(a)}, y{std::move(b)} {} - Binary(A &&a, B &&b) - : x{std::make_unique(std::move(a))}, y{std::make_unique( - std::move(b))} {} - Binary(const Binary &that) - : x{std::make_unique(*that.x)}, y{std::make_unique(*that.y)} {} - Binary(Binary &&) = default; - Binary &operator=(const Binary &that) { - x = std::make_unique(*that.x); - y = std::make_unique(*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 x; - std::unique_ptr y; + common::Indirection x; + common::Indirection y; }; template struct Expr { using Result = Type; using Constant = typename Result::Value; - template struct Convert : Unary { using Unary::Unary; }; + template struct Convert : public Unary { + using Unary::Unary; + }; using Un = Unary; using Bin = Binary; struct Parentheses : public Un { @@ -122,29 +92,29 @@ template struct Expr { 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 Expr(const Expr &x) - : u{Convert>{AnyKindExpr{x}}} {} + : u{Convert>{CategoryExpr{x}}} {} template Expr(Expr &&x) - : u{Convert>{AnyKindExpr{std::move(x)}}} {} + : u{Convert>{CategoryExpr{std::move(x)}}} {} template Expr(const A &x) : u{x} {} template - Expr(std::enable_if_t, A> &&x) : u(std::move(x)) {} - Expr &operator=(const Expr &) = default; - Expr &operator=(Expr &&) = default; + Expr(std::enable_if_t && + (std::is_base_of_v || std::is_base_of_v), + A> &&x) + : u(std::move(x)) {} - std::ostream &Dump(std::ostream &) const; void Fold(FoldingContext &); - std::variant, Convert, - Parentheses, Negate, Add, Subtract, Multiply, Divide, Power> + std::variant, + Convert, Convert, Parentheses, + Negate, Add, Subtract, Multiply, Divide, Power> u; }; @@ -154,7 +124,9 @@ template struct Expr { // 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 struct Convert : Unary { using Unary::Unary; }; + template struct Convert : public Unary { + using Unary::Unary; + }; using Un = Unary; using Bin = Binary; struct Parentheses : public Un { @@ -178,8 +150,8 @@ template struct Expr { struct Power : public Bin { using Bin::Bin; }; - struct IntPower : public Binary { - using Binary::Binary; + struct IntPower : public Binary { + using Binary::Binary; }; using CplxUn = Unary>; struct RealPart : public CplxUn { @@ -189,25 +161,19 @@ template struct Expr { using CplxUn::CplxUn; }; - Expr() = delete; - Expr(const Expr &) = default; - Expr(Expr &&) = default; + CLASS_BOILERPLATE(Expr) Expr(const Constant &x) : u{x} {} template Expr(const Expr &x) - : u{Convert>{AnyKindExpr{x}}} {} + : u{Convert>{CategoryExpr{x}}} {} template Expr(Expr &&x) - : u{Convert>{AnyKindExpr{std::move(x)}}} {} + : u{Convert>{CategoryExpr{std::move(x)}}} {} template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr &operator=(const Expr &) = default; - Expr &operator=(Expr &&) = default; - - std::ostream &Dump(std::ostream &) const; - std::variant, Convert, + std::variant, Convert, Parentheses, Negate, Add, Subtract, Multiply, Divide, Power, IntPower, RealPart, AIMAG> u; @@ -239,24 +205,18 @@ template struct Expr { struct Power : public Bin { using Bin::Bin; }; - struct IntPower : public Binary { - using Binary::Binary; + struct IntPower : public Binary { + using Binary::Binary; }; struct CMPLX : public Binary> { using Binary>::Binary; }; - Expr() = delete; - Expr(const Expr &) = default; - Expr(Expr &&) = default; + CLASS_BOILERPLATE(Expr) Expr(const Constant &x) : u{x} {} template Expr(const A &x) : u{x} {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr &operator=(const Expr &) = default; - Expr &operator=(Expr &&) = default; - - std::ostream &Dump(std::ostream &) const; std::variant @@ -267,24 +227,16 @@ template struct Expr { using Result = Type; using Constant = typename Result::Value; using LengthExpr = IntegerExpr; - struct Concat : public Binary { - using Binary::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{x, y}} {} + Expr(Expr &&x, Expr &&y) : u{Binary{std::move(x), std::move(y)}} {} LengthExpr LEN() const; - std::ostream &Dump(std::ostream &) const; - std::variant u; + std::variant> u; }; // The Comparison class template is a helper for constructing logical @@ -293,16 +245,11 @@ template struct Expr { ENUM_CLASS(RelationalOperator, LT, LE, EQ, NE, GE, GT) template struct Comparison : Binary { - Comparison(const Comparison &) = default; - Comparison(Comparison &&) = default; + CLASS_BOILERPLATE(Comparison) Comparison(RelationalOperator r, const EXPR &a, const EXPR &b) : Binary{a, b}, opr{r} {} Comparison(RelationalOperator r, EXPR &&a, EXPR &&b) : Binary{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; }; @@ -323,19 +270,14 @@ extern template struct Comparison>; extern template struct Comparison>; extern template struct Comparison>; -// Dynamically polymorphic comparisonsq that can hold any supported kind -// of a category. -template 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 struct CategoryComparison { + CLASS_BOILERPLATE(CategoryComparison) template - AnyKindComparison(const Comparison> &x) : u{x} {} + CategoryComparison(const Comparison> &x) : u{x} {} template - AnyKindComparison(Comparison> &&x) : u{std::move(x)} {} - AnyKindComparison &operator=(const AnyKindComparison &) = default; - AnyKindComparison &operator=(AnyKindComparison &&) = default; - std::ostream &Dump(std::ostream &) const; + CategoryComparison(Comparison> &&x) : u{std::move(x)} {} template using KindComparison = Comparison>; typename KindsVariant::type u; }; @@ -360,27 +302,21 @@ template<> struct Expr { using Bin::Bin; }; - Expr() = delete; - Expr(const Expr &) = default; - Expr(Expr &&) = default; + CLASS_BOILERPLATE(Expr) Expr(Constant x) : u{x} {} template - Expr(const Comparison> &x) : u{AnyKindComparison{x}} {} + Expr(const Comparison> &x) : u{CategoryComparison{x}} {} template Expr(Comparison> &&x) - : u{AnyKindComparison{std::move(x)}} {} - template Expr(const A &x) : u{x} {} + : u{CategoryComparison{std::move(x)}} {} + template Expr(const A &x) : u(x) {} template Expr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - Expr &operator=(const Expr &) = default; - Expr &operator=(Expr &&) = default; - - std::ostream &Dump(std::ostream &) const; std::variant, AnyKindComparison, - AnyKindComparison, - AnyKindComparison> + CategoryComparison, CategoryComparison, + CategoryComparison, + CategoryComparison> u; }; @@ -403,36 +339,28 @@ extern template struct Expr; extern template struct Expr; // Dynamically polymorphic expressions that can hold any supported kind -// of a category. -template struct AnyKindExpr { - AnyKindExpr() = delete; - AnyKindExpr(const AnyKindExpr &) = default; - AnyKindExpr(AnyKindExpr &&) = default; - template AnyKindExpr(const Expr &x) : u{x} {} - template AnyKindExpr(Expr &&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 struct CategoryExpr { + CLASS_BOILERPLATE(CategoryExpr) + template CategoryExpr(const Expr &x) : u{x} {} + template CategoryExpr(Expr &&x) : u{std::move(x)} {} template using KindExpr = Expr; typename KindsVariant::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 - AnyExpr(const Expr &x) : u{AnyKindExpr{x}} {} + GenericExpr(const Expr &x) : u{CategoryExpr{x}} {} template - AnyExpr(Expr &&x) : u{AnyKindExpr{std::move(x)}} {} - template AnyExpr(const A &x) : u{x} {} + GenericExpr(Expr &&x) : u{CategoryExpr{std::move(x)}} {} + template GenericExpr(const A &x) : u{x} {} template - AnyExpr(std::enable_if_t, A> &&x) : u{std::move(x)} {} - AnyExpr &operator=(const AnyExpr &) = default; - AnyExpr &operator=(AnyExpr &&) = default; - std::ostream &Dump(std::ostream &) const; - std::variant + GenericExpr(std::enable_if_t, A> &&x) + : u{std::move(x)} {} + std::variant u; }; diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc new file mode 100644 index 0000000..0212354 --- /dev/null +++ b/flang/lib/evaluate/variable.cc @@ -0,0 +1,167 @@ +// 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 + +namespace Fortran::evaluate { + +Triplet::Triplet(std::optional &&l, + std::optional &&u, std::optional &&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 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 +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 +std::ostream &Emit( + std::ostream &o, const std::optional &x, const char *kw = nullptr) { + if (x.has_value()) { + if (kw != nullptr) { + o << kw; + } + Emit(o, *x); + } + return o; +} + +template +std::ostream &Emit(std::ostream &o, const common::Indirection &p, + const char *kw = nullptr) { + if (kw != nullptr) { + o << kw; + } + Emit(o, *p); + return o; +} + +template +std::ostream &Emit(std::ostream &o, const std::variant &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 diff --git a/flang/lib/evaluate/variable.h b/flang/lib/evaluate/variable.h index 286b708..621855c 100644 --- a/flang/lib/evaluate/variable.h +++ b/flang/lib/evaluate/variable.h @@ -15,10 +15,13 @@ #ifndef FORTRAN_EVALUATE_VARIABLE_H_ #define FORTRAN_EVALUATE_VARIABLE_H_ -#include "expression.h" -#include "traverse.h" -#include +#include "common.h" +#include "expression-forward.h" +#include "../common/idioms.h" +#include "../common/indirection.h" +#include "../semantics/symbol.h" #include +#include #include #include @@ -27,156 +30,138 @@ namespace Fortran::evaluate { struct DataRef; struct Variable; struct ActualArg; -struct Label; // TODO +struct Label; using semantics::Symbol; struct Component { - Component(const Symbol &c, std::unique_ptr &&b) - : sym{c}, base{std::move(b)} {} - const Symbol &sym; - template void DefaultTraverse(V &v) { v(base); } - std::unique_ptr base; + CLASS_BOILERPLATE(Component) + Component(const DataRef &b, const Symbol &c) : base{b}, sym{&c} {} + Component(common::Indirection &&b, const Symbol &c) + : base{std::move(b)}, sym{&c} {} + common::Indirection base; + const Symbol *sym; }; -using SubscriptExpr = DefaultIntExpr; +using SubscriptExpr = common::Indirection; struct Triplet { - Triplet(std::optional &&l, std::optional &&u, - std::optional &&s) - : lower{std::move(l)}, upper{std::move(u)}, stride{std::move(s)} {} - template void DefaultTraverse(V &v) { - v(lower); - v(upper); - v(stride); - } + CLASS_BOILERPLATE(Triplet) + Triplet(std::optional &&, std::optional &&, + std::optional &&); std::optional 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 void DefaultTraverse(V &v) { v(u); } std::variant u; }; struct ArrayRef { - ArrayRef() = delete; - ArrayRef(const Symbol &n, std::vector &&s) - : u{n}, subscript{std::move(ss)} {} - ArrayRef(Component &&c, std::vector &&s) - : u{std::move(c)}, subscript{std::move(ss)} {} - template void DefaultTraverse(V &v) { - v(u); - v(subscript); - } - std::variant u; + CLASS_BOILERPLATE(ArrayRef) + ArrayRef(const Symbol &n, std::vector &&ss) + : u{&n}, subscript(std::move(ss)) {} + ArrayRef(Component &&c, std::vector &&ss) + : u{std::move(c)}, subscript(std::move(ss)) {} + std::variant u; std::vector subscript; }; struct CoarrayRef { - CoarrayRef() = delete; + CLASS_BOILERPLATE(CoarrayRef) CoarrayRef(const Symbol &n, std::vector &&s) - : u{n}, cosubscript{std::move(s)} {} + : u{&n}, cosubscript(std::move(s)) {} CoarrayRef(Component &&c, std::vector &&s) - : u{std::move(c)}, cosubscript{std::move(s)} {} + : u{std::move(c)}, cosubscript(std::move(s)) {} CoarrayRef(ArrayRef &&a, std::vector &&s) - : u{std::move(a)}, cosubscript{std::move(s)} {} - template void DefaultTraverse(V &v) { - v(u); - v(cosubscript); - v(stat); - v(team); - v(teamNumber); - } - std::variant u; + : u{std::move(a)}, cosubscript(std::move(s)) {} + std::variant u; std::vector cosubscript; - std::unique_ptr stat, team, teamNumber; // nullable + std::optional> 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 void DefaultTraverse(V &v) { v(u); } - std::variant u; + std::variant u; }; struct Substring { - Substring() = delete; + CLASS_BOILERPLATE(Substring) Substring(DataRef &&d, std::optional &&f, std::optional &&l) : u{std::move(d)}, first{std::move(f)}, last{std::move(l)} {} Substring(std::string &&s, std::optional &&f, std::optional &&l) : u{std::move(s)}, first{std::move(f)}, last{std::move(l)} {} - template void DefaultTraverse(V &v) { - v(u); - v(first); - v(last); - } std::variant u; std::optional 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 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 void DefaultTraverse(V &v) { v(u); } std::variant u; }; struct ProcedureDesignator { - ProcedureDesignator() = delete; - ProcedureDesignator(std::unique_ptr &&v, const Symbol &n) - : u{std::move(v)}, sym{n} {} - ProcedureDesignator(DataRef &&d, const Symbol &n) : u{std::move(d)}, sym{n} {} - template void DefaultTraverse(V &v) { v(u); } - std::variant, 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 u; }; -struct ProcedureRef { - ProcedureRef() = delete; +struct ProcedureRef { // TODO split off FunctionRef without alt returns + CLASS_BOILERPLATE(ProcedureRef) ProcedureRef( - ProcedureDesignator &&p, std::vector> &&a) - : proc{std::move(p)}, arg{std::move(a)} {} - template void DefaultTraverse(V &v) { - v(proc); - v(arg); - } + ProcedureDesignator &&p, std::vector> &&a) + : proc{std::move(p)}, argument(std::move(a)) {} ProcedureDesignator proc; - std::vector> arg; // nullable + std::vector> 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 void DefaultTraverse(V &v) { v(u); } std::variant 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 void DefaultTraverse(V &v) { v(u); } - std::variant u; + explicit ActualArg(const Label &l) : u{&l} {} + std::variant, 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_ diff --git a/flang/lib/parser/characters.cc b/flang/lib/parser/characters.cc index 4836fea..4bf6585 100644 --- a/flang/lib/parser/characters.cc +++ b/flang/lib/parser/characters.cc @@ -82,4 +82,13 @@ std::optional CountCharacters( 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 diff --git a/flang/lib/parser/characters.h b/flang/lib/parser/characters.h index 4bc51fe..736b400 100644 --- a/flang/lib/parser/characters.h +++ b/flang/lib/parser/characters.h @@ -161,6 +161,8 @@ void EmitQuotedChar(char ch, const NORMAL &emit, const INSERTED &insert, } } +std::string QuoteCharacterLiteral(const std::string &); + std::optional UTF8CharacterBytes(const char *); std::optional EUC_JPCharacterBytes(const char *); std::optional CountCharacters( diff --git a/flang/lib/parser/grammar.h b/flang/lib/parser/grammar.h index e6ccce7..6240509 100644 --- a/flang/lib/parser/grammar.h +++ b/flang/lib/parser/grammar.h @@ -3123,7 +3123,8 @@ TYPE_PARSER("INTRINSIC" >> maybe("::"_tok) >> // R1520 function-reference -> procedure-designator ( [actual-arg-spec-list] ) TYPE_CONTEXT_PARSER("function reference"_en_US, construct(construct(Parser{}, - parenthesized(optionalList(actualArgSpec)))) / !"["_tok) + parenthesized(optionalList(actualArgSpec)))) / + !"["_tok) // R1521 call-stmt -> CALL procedure-designator [( [actual-arg-spec-list] )] TYPE_PARSER( diff --git a/flang/lib/parser/parse-tree.cc b/flang/lib/parser/parse-tree.cc index 2e1665f..06b56e0 100644 --- a/flang/lib/parser/parse-tree.cc +++ b/flang/lib/parser/parse-tree.cc @@ -44,24 +44,25 @@ DataRef::DataRef(std::list &&prl) : u{std::move(prl.front().name)} { for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) { PartRef &pr{prl.front()}; if (!first) { - u = common::Indirection{ - std::move(*this), std::move(pr.name)}; + u = common::Indirection::Make( + std::move(*this), std::move(pr.name)); } if (!pr.subscripts.empty()) { - u = common::Indirection{ - std::move(*this), std::move(pr.subscripts)}; + u = common::Indirection::Make( + std::move(*this), std::move(pr.subscripts)); } if (pr.imageSelector.has_value()) { - u = common::Indirection{ - std::move(*this), std::move(*pr.imageSelector)}; + u = common::Indirection::Make( + std::move(*this), std::move(*pr.imageSelector)); } } } // R1001 - R1022 expression -Expr::Expr(Designator &&x) : u{common::Indirection(std::move(x))} {} +Expr::Expr(Designator &&x) + : u{common::Indirection::Make(std::move(x))} {} Expr::Expr(FunctionReference &&x) - : u{common::Indirection(std::move(x))} {} + : u{common::Indirection::Make(std::move(x))} {} static Designator MakeArrayElementRef(Name &name, std::list &subscripts) { ArrayElement arrayElement{name, std::list{}}; diff --git a/flang/lib/parser/unparse.cc b/flang/lib/parser/unparse.cc index 3d7b65e..3ebe5b3 100644 --- a/flang/lib/parser/unparse.cc +++ b/flang/lib/parser/unparse.cc @@ -181,7 +181,7 @@ public: Walk(*k), Put('_'); } } - PutQuoted(std::get(x.t)); + Put(QuoteCharacterLiteral(std::get(x.t))); } void Before(const HollerithLiteralConstant &x) { std::optional chars{CountCharacters(x.v.data(), x.v.size(), @@ -1351,7 +1351,9 @@ public: 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 &y) { Walk("(", y, ",", ")"); }, @@ -2127,7 +2129,6 @@ private: 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_; } @@ -2249,15 +2250,6 @@ void UnparseVisitor::PutKeywordLetter(char ch) { } } -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); diff --git a/flang/test/evaluate/CMakeLists.txt b/flang/test/evaluate/CMakeLists.txt index 58afb2c..dd65bfc 100644 --- a/flang/test/evaluate/CMakeLists.txt +++ b/flang/test/evaluate/CMakeLists.txt @@ -70,6 +70,7 @@ add_executable(expression-test target_link_libraries(expression-test FortranEvaluate FortranEvaluateTesting + FortranParser ) add_test(NAME Expression COMMAND expression-test) -- 2.7.4