1 // Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "unparse-with-symbols.h"
16 #include "symbol.h"
17 #include "../parser/parse-tree-visitor.h"
18 #include "../parser/parse-tree.h"
19 #include "../parser/unparse.h"
20 #include <map>
21 #include <ostream>
22 #include <set>
23
24 namespace Fortran::semantics {
25
26 // Walk the parse tree and collection information about which statements
27 // reference symbols. Then PrintSymbols outputs information by statement.
28 // The first reference to a symbol is treated as its definition and more
29 // information is included.
30 class SymbolDumpVisitor {
31 public:
32 // Write out symbols referenced at this statement.
33 void PrintSymbols(const parser::CharBlock &, std::ostream &, int);
34
Pre(const T &)35 template<typename T> bool Pre(const T &) { return true; }
Post(const T &)36 template<typename T> void Post(const T &) {}
Pre(const parser::Statement<T> & stmt)37 template<typename T> bool Pre(const parser::Statement<T> &stmt) {
38 currStmt_ = stmt.source;
39 return true;
40 }
Post(const parser::Statement<T> &)41 template<typename T> void Post(const parser::Statement<T> &) {
42 currStmt_ = std::nullopt;
43 }
44 void Post(const parser::Name &name);
45
46 private:
47 std::optional<SourceName> currStmt_; // current statement we are processing
48 std::multimap<const char *, const Symbol *> symbols_; // location to symbol
49 std::set<const Symbol *> symbolsDefined_; // symbols that have been processed
50 void Indent(std::ostream &, int) const;
51 };
52
PrintSymbols(const parser::CharBlock & location,std::ostream & out,int indent)53 void SymbolDumpVisitor::PrintSymbols(
54 const parser::CharBlock &location, std::ostream &out, int indent) {
55 std::set<const Symbol *> done; // prevent duplicates on this line
56 auto range{symbols_.equal_range(location.begin())};
57 for (auto it{range.first}; it != range.second; ++it) {
58 const auto *symbol{it->second};
59 if (done.insert(symbol).second) {
60 bool firstTime{symbolsDefined_.insert(symbol).second};
61 Indent(out, indent);
62 out << '!' << (firstTime ? "DEF"s : "REF"s) << ": ";
63 DumpForUnparse(out, *symbol, firstTime);
64 out << '\n';
65 }
66 }
67 }
68
Indent(std::ostream & out,int indent) const69 void SymbolDumpVisitor::Indent(std::ostream &out, int indent) const {
70 for (int i{0}; i < indent; ++i) {
71 out << ' ';
72 }
73 }
74
Post(const parser::Name & name)75 void SymbolDumpVisitor::Post(const parser::Name &name) {
76 if (const auto *symbol{name.symbol}) {
77 if (!symbol->has<MiscDetails>()) {
78 symbols_.emplace(currStmt_.value().begin(), symbol);
79 }
80 }
81 }
82
UnparseWithSymbols(std::ostream & out,const parser::Program & program,parser::Encoding encoding)83 void UnparseWithSymbols(std::ostream &out, const parser::Program &program,
84 parser::Encoding encoding) {
85 SymbolDumpVisitor visitor;
86 parser::Walk(program, visitor);
87 parser::preStatementType preStatement{
88 [&](const parser::CharBlock &location, std::ostream &out, int indent) {
89 visitor.PrintSymbols(location, out, indent);
90 }};
91 parser::Unparse(out, program, encoding, false, true, &preStatement);
92 }
93 }
94