[flang] Include analyzed exprs in parse tree dump
authorTim Keith <tkeith@nvidia.com>
Wed, 18 Dec 2019 23:36:14 +0000 (15:36 -0800)
committerTim Keith <tkeith@nvidia.com>
Thu, 19 Dec 2019 00:29:08 +0000 (16:29 -0800)
When dumping the parse tree, if there are analyzed expressions,
assignments, or call statements, include the Fortran form of those
in the dump.

This uses the same `AnalyzedObjectsAsFortran` object that unparsing
does so it applies to the same nodes.

We already do something like this for `Name` nodes as well as some
predefined types, so abstract it into an `AsFortran` function which
returns the Fortran source for a node that is to be included in the
dump.

Original-commit: flang-compiler/f18@823b044d2a009f43fe5ce15755a8ae23f70dfed8
Reviewed-on: https://github.com/flang-compiler/f18/pull/878
Tree-same-pre-rewrite: false

flang/lib/parser/dump-parse-tree.h
flang/tools/f18/f18.cc

index 54d29a3..8f8e698 100644 (file)
 #include "format-specification.h"
 #include "parse-tree-visitor.h"
 #include "parse-tree.h"
+#include "unparse.h"
 #include "../common/idioms.h"
 #include "../common/indirection.h"
 #include <ostream>
+#include <sstream>
 #include <string>
 #include <type_traits>
 
@@ -39,7 +41,9 @@ struct HasSource<T, decltype((void)T::source, 0)> : std::true_type {};
 
 class ParseTreeDumper {
 public:
-  explicit ParseTreeDumper(std::ostream &out) : out_(out) {}
+  explicit ParseTreeDumper(
+      std::ostream &out, const AnalyzedObjectsAsFortran *asFortran = nullptr)
+    : out_(out), asFortran_{asFortran} {}
 
   constexpr const char *GetNodeName(const char *) { return "char *"; }
 #define NODE_NAME(T, N) \
@@ -51,6 +55,9 @@ public:
 #define NODE(T1, T2) NODE_NAME(T1::T2, #T2)
   NODE_NAME(bool, "bool")
   NODE_NAME(int, "int")
+  NODE(std, string)
+  NODE(std, int64_t)
+  NODE(std, uint64_t)
   NODE(format, ControlEditDesc)
   NODE(format::ControlEditDesc, Kind)
   NODE(format, DerivedTypeDataEditDesc)
@@ -367,6 +374,7 @@ public:
   NODE(parser, LengthSelector)
   NODE(parser, LetterSpec)
   NODE(parser, LiteralConstant)
+  NODE(parser, IntLiteralConstant)
   NODE(parser, LocalitySpec)
   NODE(parser::LocalitySpec, DefaultNone)
   NODE(parser::LocalitySpec, Local)
@@ -391,6 +399,7 @@ public:
   NODE(parser, ModuleSubprogramPart)
   NODE(parser, MpSubprogramStmt)
   NODE(parser, MsgVariable)
+  NODE(parser, Name)
   NODE(parser, NamedConstant)
   NODE(parser, NamedConstantDef)
   NODE(parser, NamelistStmt)
@@ -601,6 +610,7 @@ public:
   NODE(parser, SequenceStmt)
   NODE(parser, Sign)
   NODE(parser, SignedComplexLiteralConstant)
+  NODE(parser, SignedIntLiteralConstant)
   NODE(parser, SignedRealLiteralConstant)
   NODE(parser, SpecificationConstruct)
   NODE(parser, SpecificationExpr)
@@ -679,13 +689,14 @@ public:
 #undef NODE_NAME
 
   template<typename T> bool Pre(const T &x) {
-    if constexpr (!HasSource<T>::value && (UnionTrait<T> || WrapperTrait<T>)) {
+    std::string fortran{AsFortran<T>(x)};
+    if (fortran.empty() && (UnionTrait<T> || WrapperTrait<T>)) {
       Prefix(GetNodeName(x));
     } else {
       IndentEmptyLine();
       out_ << GetNodeName(x);
-      if constexpr (HasSource<T>::value) {
-        out_ << " = '" << x.source.ToString() << '\'';
+      if (!fortran.empty()) {
+        out_ << " = '" << fortran << '\'';
       }
       EndLine();
       ++indent_;
@@ -693,73 +704,14 @@ public:
     return true;
   }
 
-  template<typename T> void Post(const T &) {
-    if constexpr (!HasSource<T>::value && (UnionTrait<T> || WrapperTrait<T>)) {
+  template<typename T> void Post(const T &x) {
+    if (AsFortran<T>(x).empty() && (UnionTrait<T> || WrapperTrait<T>)) {
       EndLineIfNonempty();
     } else {
       --indent_;
     }
   }
 
-  bool Pre(const parser::Name &x) {
-    IndentEmptyLine();
-    out_ << "Name = '" << x.ToString() << '\'';
-    EndLine();
-    return false;
-  }
-  bool Pre(const std::string &x) {
-    IndentEmptyLine();
-    out_ << "string = '" << x << '\'';
-    EndLine();
-    return false;
-  }
-
-  bool Pre(const std::int64_t &x) {
-    IndentEmptyLine();
-    out_ << "int = '" << x << '\'';
-    ++indent_;
-    EndLine();
-    return true;
-  }
-  void Post(const std::int64_t &) { --indent_; }
-
-  bool Pre(const std::uint64_t &x) {
-    IndentEmptyLine();
-    out_ << "int = '" << x << '\'';
-    EndLine();
-    return false;
-  }
-
-  bool Pre(const parser::IntLiteralConstant &x) {
-    IndentEmptyLine();
-    out_ << "int = '" << std::get<parser::CharBlock>(x.t).ToString() << '\'';
-    EndLine();
-    ++indent_;
-    Walk(std::get<std::optional<KindParam>>(x.t), *this);
-    --indent_;
-    return false;
-  }
-
-  bool Pre(const parser::SignedIntLiteralConstant &x) {
-    IndentEmptyLine();
-    out_ << "int = '" << std::get<parser::CharBlock>(x.t).ToString() << '\'';
-    EndLine();
-    ++indent_;
-    Walk(std::get<std::optional<KindParam>>(x.t), *this);
-    --indent_;
-    return false;
-  }
-
-  bool Pre(const parser::RealLiteralConstant &x) {
-    Prefix(GetNodeName(x));
-    out_ << "Real = '" << x.real.source.ToString() << '\'';
-    EndLine();
-    ++indent_;
-    Walk(x.kind, *this);
-    --indent_;
-    return false;
-  }
-
   // A few types we want to ignore
 
   bool Pre(const parser::CharBlock &) { return true; }
@@ -822,6 +774,42 @@ public:
   template<typename... A> void Post(const std::variant<A...> &) {}
 
 protected:
+  // Return a Fortran representation of this node to include in the dump
+  template<typename T> std::string AsFortran(const T &x) {
+    std::ostringstream ss;
+    if constexpr (std::is_same_v<T, Expr>) {
+      if (asFortran_ && x.typedExpr) {
+        asFortran_->expr(ss, *x.typedExpr);
+      }
+    } else if constexpr (std::is_same_v<T, AssignmentStmt>) {
+      if (asFortran_ && x.typedAssignment) {
+        asFortran_->assignment(ss, *x.typedAssignment);
+      }
+    } else if constexpr (std::is_same_v<T, CallStmt>) {
+      if (asFortran_ && x.typedCall) {
+        asFortran_->call(ss, *x.typedCall);
+      }
+    } else if constexpr (std::is_same_v<T, IntLiteralConstant> ||
+        std::is_same_v<T, SignedIntLiteralConstant>) {
+      ss << std::get<CharBlock>(x.t);
+    } else if constexpr (std::is_same_v<T, RealLiteralConstant::Real>) {
+      ss << x.source;
+    } else if constexpr (std::is_same_v<T, std::string> ||
+        std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::uint64_t>) {
+      ss << x;
+    }
+    if (ss.tellp() != 0) {
+      return ss.str();
+    }
+    if constexpr (std::is_same_v<T, Name> || HasSource<T>::value) {
+      return x.source.ToString();
+    } else if constexpr (std::is_same_v<T, std::string>) {
+      return x;
+    } else {
+      return "";
+    }
+  }
+
   void IndentEmptyLine() {
     if (emptyline_ && indent_ > 0) {
       for (int i{0}; i < indent_; ++i) {
@@ -857,12 +845,16 @@ protected:
 private:
   int indent_{0};
   std::ostream &out_;
+  const AnalyzedObjectsAsFortran *const asFortran_;
   bool emptyline_{false};
 };
 
-template<typename T> void DumpTree(std::ostream &out, const T &x) {
-  ParseTreeDumper dumper{out};
+template<typename T>
+void DumpTree(std::ostream &out, const T &x,
+    const AnalyzedObjectsAsFortran *asFortran = nullptr) {
+  ParseTreeDumper dumper{out, asFortran};
   parser::Walk(x, dumper);
 }
+
 }
 #endif  // FORTRAN_PARSER_DUMP_PARSE_TREE_H_
index 32ffa7c..7db4695 100644 (file)
@@ -169,6 +169,31 @@ std::string RelocatableName(const DriverOptions &driver, std::string path) {
 
 int exitStatus{EXIT_SUCCESS};
 
+static Fortran::parser::AnalyzedObjectsAsFortran asFortran{
+    [](std::ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
+      if (x.v) {
+        x.v->AsFortran(o);
+      } else {
+        o << "(bad expression)";
+      }
+    },
+    [](std::ostream &o, const Fortran::evaluate::GenericAssignmentWrapper &x) {
+      std::visit(
+          Fortran::common::visitors{
+              [&](const Fortran::evaluate::Assignment::IntrinsicAssignment &y) {
+                y.rhs.AsFortran(y.lhs.AsFortran(o) << '=');
+              },
+              [&](const Fortran::evaluate::ProcedureRef &y) {
+                y.AsFortran(o << "CALL ");
+              },
+          },
+          x.v.u);
+    },
+    [](std::ostream &o, const Fortran::evaluate::ProcedureRef &x) {
+      x.AsFortran(o << "CALL ");
+    },
+};
+
 std::string CompileFortran(std::string path, Fortran::parser::Options options,
     DriverOptions &driver,
     const Fortran::common::IntrinsicTypeDefaultKinds &defaultKinds) {
@@ -246,7 +271,7 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
       std::cerr << driver.prefix << "semantic errors in " << path << '\n';
       exitStatus = EXIT_FAILURE;
       if (driver.dumpParseTree) {
-        Fortran::parser::DumpTree(std::cout, parseTree);
+        Fortran::parser::DumpTree(std::cout, parseTree, &asFortran);
       }
       return {};
     }
@@ -286,34 +311,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
     }
   }
   if (driver.dumpParseTree) {
-    Fortran::parser::DumpTree(std::cout, parseTree);
+    Fortran::parser::DumpTree(std::cout, parseTree, &asFortran);
   }
-
-  Fortran::parser::AnalyzedObjectsAsFortran asFortran{
-      [](std::ostream &o, const Fortran::evaluate::GenericExprWrapper &x) {
-        if (x.v) {
-          x.v->AsFortran(o);
-        } else {
-          o << "(bad expression)";
-        }
-      },
-      [](std::ostream &o,
-          const Fortran::evaluate::GenericAssignmentWrapper &x) {
-        std::visit(
-            Fortran::common::visitors{
-                [&](const Fortran::evaluate::Assignment::IntrinsicAssignment
-                        &y) { y.rhs.AsFortran(y.lhs.AsFortran(o) << '='); },
-                [&](const Fortran::evaluate::ProcedureRef &y) {
-                  y.AsFortran(o << "CALL ");
-                },
-            },
-            x.v.u);
-      },
-      [](std::ostream &o, const Fortran::evaluate::ProcedureRef &x) {
-        x.AsFortran(o << "CALL ");
-      },
-  };
-
   if (driver.dumpUnparse) {
     Unparse(std::cout, parseTree, driver.encoding, true /*capitalize*/,
         options.features.IsEnabled(