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