[flang] Use Indirection. Get variables to work in int expressions.
authorpeter klausler <pklausler@nvidia.com>
Fri, 6 Jul 2018 22:12:33 +0000 (15:12 -0700)
committerpeter klausler <pklausler@nvidia.com>
Mon, 9 Jul 2018 23:26:00 +0000 (16:26 -0700)
Original-commit: flang-compiler/f18@1000717da820d87b330719034281a69eaf37bb89
Reviewed-on: https://github.com/flang-compiler/f18/pull/117
Tree-same-pre-rewrite: false

14 files changed:
flang/lib/common/indirection.h
flang/lib/evaluate/CMakeLists.txt
flang/lib/evaluate/common.h
flang/lib/evaluate/expression-forward.h [new file with mode: 0644]
flang/lib/evaluate/expression.cc
flang/lib/evaluate/expression.h
flang/lib/evaluate/variable.cc [new file with mode: 0644]
flang/lib/evaluate/variable.h
flang/lib/parser/characters.cc
flang/lib/parser/characters.h
flang/lib/parser/grammar.h
flang/lib/parser/parse-tree.cc
flang/lib/parser/unparse.cc
flang/test/evaluate/CMakeLists.txt

index 1a78f30..1778c98 100644 (file)
@@ -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 <utility>
@@ -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<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;
@@ -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<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_
index cf43366..fef2c87 100644 (file)
@@ -18,6 +18,7 @@ add_library(FortranEvaluate
   integer.cc
   logical.cc
   real.cc
+  variable.cc
 )
 
 target_link_libraries(FortranEvaluate
index dc05f46..f6779ec 100644 (file)
@@ -108,5 +108,17 @@ template<int BITS>
 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_
diff --git a/flang/lib/evaluate/expression-forward.h b/flang/lib/evaluate/expression-forward.h
new file mode 100644 (file)
index 0000000..04e3782
--- /dev/null
@@ -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<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_
index fcf2fcd..5270d57 100644 (file)
@@ -13,7 +13,9 @@
 // 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>
@@ -40,16 +42,18 @@ std::ostream &DumpExpr(std::ostream &o, const std::variant<A...> &u) {
 }
 
 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 {
@@ -65,6 +69,7 @@ template<int KIND>
 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, "+"); },
@@ -115,8 +120,12 @@ std::ostream &Expr<Category::Complex, KIND>::Dump(std::ostream &o) const {
 
 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;
 }
@@ -144,13 +153,13 @@ std::ostream &Expr<Category::Logical, 1>::Dump(std::ostream &o) const {
 
 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()};
@@ -161,7 +170,7 @@ void Expr<Category::Integer, KIND>::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<Constant>(&a.x->u)}) {
@@ -175,7 +184,7 @@ void Expr<Category::Integer, KIND>::Fold(FoldingContext &context) {
                      }
                    }
                  },
-                 [&](const Multiply &a) {
+                 [&](Multiply &a) {
                    a.x->Fold(context);
                    a.y->Fold(context);
                    if (auto xc{std::get_if<Constant>(&a.x->u)}) {
@@ -190,7 +199,7 @@ void Expr<Category::Integer, KIND>::Fold(FoldingContext &context) {
                      }
                    }
                  },
-                 [&](const Bin &b) {
+                 [&](Bin &b) {
                    b.x->Fold(context);
                    b.y->Fold(context);
                  },
@@ -201,12 +210,13 @@ void Expr<Category::Integer, KIND>::Fold(FoldingContext &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);
 }
 
index d012889..5744b63 100644 (file)
 // 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 {
@@ -122,29 +92,29 @@ template<int KIND> struct Expr<Category::Integer, KIND> {
     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;
 };
 
@@ -154,7 +124,9 @@ template<int KIND> struct Expr<Category::Real, KIND> {
   // 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 {
@@ -178,8 +150,8 @@ template<int KIND> struct Expr<Category::Real, KIND> {
   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 {
@@ -189,25 +161,19 @@ template<int KIND> struct Expr<Category::Real, KIND> {
     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;
@@ -239,24 +205,18 @@ template<int KIND> struct Expr<Category::Complex, KIND> {
   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>
@@ -267,24 +227,16 @@ template<int KIND> struct Expr<Category::Character, KIND> {
   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
@@ -293,16 +245,11 @@ template<int KIND> struct Expr<Category::Character, KIND> {
 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;
 };
 
@@ -323,19 +270,14 @@ extern template struct Comparison<ComplexExpr<10>>;
 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;
 };
@@ -360,27 +302,21 @@ template<> struct Expr<Category::Logical, 1> {
     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;
 };
 
@@ -403,36 +339,28 @@ extern template struct Expr<Category::Character, 1>;
 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;
 };
 
diff --git a/flang/lib/evaluate/variable.cc b/flang/lib/evaluate/variable.cc
new file mode 100644 (file)
index 0000000..0212354
--- /dev/null
@@ -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 <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
index 286b708..621855c 100644 (file)
 #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>
 
@@ -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<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_
index 4836fea..4bf6585 100644 (file)
@@ -82,4 +82,13 @@ std::optional<std::size_t> 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
index 4bc51fe..736b400 100644 (file)
@@ -161,6 +161,8 @@ void EmitQuotedChar(char ch, const NORMAL &emit, const INSERTED &insert,
   }
 }
 
+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(
index e6ccce7..6240509 100644 (file)
@@ -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<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(
index 2e1665f..06b56e0 100644 (file)
@@ -44,24 +44,25 @@ DataRef::DataRef(std::list<PartRef> &&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<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>{}};
index 3d7b65e..3ebe5b3 100644 (file)
@@ -181,7 +181,7 @@ public:
         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(),
@@ -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<format::FormatItem> &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);
index 58afb2c..dd65bfc 100644 (file)
@@ -70,6 +70,7 @@ add_executable(expression-test
 target_link_libraries(expression-test
   FortranEvaluate
   FortranEvaluateTesting
+  FortranParser
 )
 
 add_test(NAME Expression COMMAND expression-test)