[flang] Include analyzed exprs in parse tree dump

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@823b044d2a
Reviewed-on: https://github.com/flang-compiler/f18/pull/878
Tree-same-pre-rewrite: false
This commit is contained in:
Tim Keith 2019-12-18 15:36:14 -08:00
parent 47f6ebda61
commit 37de6803e3
2 changed files with 86 additions and 95 deletions

View File

@ -17,9 +17,11 @@
#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_

View 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(