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 #ifndef FORTRAN_SEMANTICS_SCOPE_H_
16 #define FORTRAN_SEMANTICS_SCOPE_H_
17 
18 #include "attr.h"
19 #include "symbol.h"
20 #include "../common/Fortran.h"
21 #include "../common/idioms.h"
22 #include "../parser/message.h"
23 #include "../parser/provenance.h"
24 #include <list>
25 #include <map>
26 #include <optional>
27 #include <set>
28 #include <string>
29 
30 namespace Fortran::semantics {
31 
32 using namespace parser::literals;
33 
34 using common::ConstantSubscript;
35 
36 // An equivalence object is represented by a symbol for the variable name,
37 // the indices for an array element, and the lower bound for a substring.
38 struct EquivalenceObject {
EquivalenceObjectEquivalenceObject39   EquivalenceObject(Symbol &symbol, std::vector<ConstantSubscript> subscripts,
40       std::optional<ConstantSubscript> substringStart)
41     : symbol{symbol}, subscripts{subscripts}, substringStart{substringStart} {}
42   bool operator==(const EquivalenceObject &) const;
43   bool operator<(const EquivalenceObject &) const;
44   std::string AsFortran() const;
45 
46   Symbol &symbol;
47   std::vector<ConstantSubscript> subscripts;  // for array elem
48   std::optional<ConstantSubscript> substringStart;
49 };
50 using EquivalenceSet = std::vector<EquivalenceObject>;
51 
52 class Scope {
53   using mapType = std::map<SourceName, Symbol *>;
54 
55 public:
56   ENUM_CLASS(Kind, Global, Module, MainProgram, Subprogram, DerivedType, Block,
57       Forall, ImpliedDos)
58   using ImportKind = common::ImportKind;
59 
60   // Create the Global scope -- the root of the scope tree
Scope()61   Scope() : Scope{*this, Kind::Global, nullptr} {}
Scope(Scope & parent,Kind kind,Symbol * symbol)62   Scope(Scope &parent, Kind kind, Symbol *symbol)
63     : parent_{parent}, kind_{kind}, symbol_{symbol} {
64     if (symbol) {
65       symbol->set_scope(this);
66     }
67   }
68   Scope(const Scope &) = delete;
69 
70   bool operator==(const Scope &that) const { return this == &that; }
71   bool operator!=(const Scope &that) const { return this != &that; }
72 
parent()73   Scope &parent() {
74     CHECK(&parent_ != this);
75     return parent_;
76   }
parent()77   const Scope &parent() const {
78     CHECK(&parent_ != this);
79     return parent_;
80   }
kind()81   Kind kind() const { return kind_; }
IsGlobal()82   bool IsGlobal() const { return kind_ == Kind::Global; }
83   bool IsModule() const;  // only module, not submodule
IsDerivedType()84   bool IsDerivedType() const { return kind_ == Kind::DerivedType; }
85   bool IsParameterizedDerivedType() const;
symbol()86   Symbol *symbol() { return symbol_; }
symbol()87   const Symbol *symbol() const { return symbol_; }
88 
89   const Symbol *GetSymbol() const;
90   const Scope *GetDerivedTypeParent() const;
91 
GetName()92   std::optional<SourceName> GetName() const {
93     if (const auto *sym{GetSymbol()}) {
94       return sym->name();
95     } else {
96       return std::nullopt;
97     }
98   }
99 
100   /// Make a scope nested in this one
101   Scope &MakeScope(Kind kind, Symbol *symbol = nullptr);
102 
103   using size_type = mapType::size_type;
104   using iterator = mapType::iterator;
105   using const_iterator = mapType::const_iterator;
106 
begin()107   iterator begin() { return symbols_.begin(); }
end()108   iterator end() { return symbols_.end(); }
begin()109   const_iterator begin() const { return symbols_.begin(); }
end()110   const_iterator end() const { return symbols_.end(); }
cbegin()111   const_iterator cbegin() const { return symbols_.cbegin(); }
cend()112   const_iterator cend() const { return symbols_.cend(); }
113 
114   iterator find(const SourceName &name);
find(const SourceName & name)115   const_iterator find(const SourceName &name) const {
116     return symbols_.find(name);
117   }
118   size_type erase(const SourceName &);
size()119   size_type size() const { return symbols_.size(); }
empty()120   bool empty() const { return symbols_.empty(); }
121 
122   // Look for symbol by name in this scope and host (depending on imports).
123   Symbol *FindSymbol(const SourceName &) const;
124 
125   /// Make a Symbol with unknown details.
126   std::pair<iterator, bool> try_emplace(
127       const SourceName &name, Attrs attrs = Attrs()) {
128     return try_emplace(name, attrs, UnknownDetails());
129   }
130   /// Make a Symbol with provided details.
131   template<typename D>
try_emplace(const SourceName & name,D && details)132   common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
133       const SourceName &name, D &&details) {
134     return try_emplace(name, Attrs(), std::move(details));
135   }
136   /// Make a Symbol with attrs and details
137   template<typename D>
try_emplace(const SourceName & name,Attrs attrs,D && details)138   common::IfNoLvalue<std::pair<iterator, bool>, D> try_emplace(
139       const SourceName &name, Attrs attrs, D &&details) {
140     Symbol &symbol{MakeSymbol(name, attrs, std::move(details))};
141     return symbols_.emplace(name, &symbol);
142   }
143 
144   const std::list<EquivalenceSet> &equivalenceSets() const;
145   void add_equivalenceSet(EquivalenceSet &&);
146   // Cray pointers are saved as map of pointee name -> pointer symbol
crayPointers()147   const mapType &crayPointers() const { return crayPointers_; }
148   void add_crayPointer(const SourceName &, Symbol &);
commonBlocks()149   mapType &commonBlocks() { return commonBlocks_; }
commonBlocks()150   const mapType &commonBlocks() const { return commonBlocks_; }
151   Symbol &MakeCommonBlock(const SourceName &);
152   Symbol *FindCommonBlock(const SourceName &);
153 
154   /// Make a Symbol but don't add it to the scope.
155   template<typename D>
MakeSymbol(const SourceName & name,Attrs attrs,D && details)156   common::IfNoLvalue<Symbol &, D> MakeSymbol(
157       const SourceName &name, Attrs attrs, D &&details) {
158     return allSymbols.Make(*this, name, attrs, std::move(details));
159   }
160 
children()161   std::list<Scope> &children() { return children_; }
children()162   const std::list<Scope> &children() const { return children_; }
163 
164   // For Module scope, maintain a mapping of all submodule scopes with this
165   // module as its ancestor module. AddSubmodule returns false if already there.
166   Scope *FindSubmodule(const SourceName &) const;
167   bool AddSubmodule(const SourceName &, Scope &);
168 
169   const DeclTypeSpec *FindType(const DeclTypeSpec &) const;
170   const DeclTypeSpec &MakeNumericType(TypeCategory, KindExpr &&kind);
171   const DeclTypeSpec &MakeLogicalType(KindExpr &&kind);
172   const DeclTypeSpec &MakeCharacterType(
173       ParamValue &&length, KindExpr &&kind = KindExpr{0});
174   DeclTypeSpec &MakeDerivedType(DeclTypeSpec::Category, DerivedTypeSpec &&);
175   const DeclTypeSpec &MakeTypeStarType();
176   const DeclTypeSpec &MakeClassStarType();
177 
178   // For modules read from module files, this is the stream of characters
179   // that are referenced by SourceName objects.
180   void set_chars(parser::CookedSource &);
181 
182   ImportKind GetImportKind() const;
183   // Names appearing in IMPORT statements in this scope
importNames()184   std::set<SourceName> importNames() const { return importNames_; }
185 
186   // Set the kind of imports from host into this scope.
187   // Return an error message for incompatible kinds.
188   std::optional<parser::MessageFixedText> SetImportKind(ImportKind);
189 
190   void add_importName(const SourceName &);
191 
derivedTypeSpec()192   const DerivedTypeSpec *derivedTypeSpec() const { return derivedTypeSpec_; }
set_derivedTypeSpec(const DerivedTypeSpec & spec)193   void set_derivedTypeSpec(const DerivedTypeSpec &spec) {
194     derivedTypeSpec_ = &spec;
195   }
196 
197   // The range of the source of this and nested scopes.
sourceRange()198   const parser::CharBlock &sourceRange() const { return sourceRange_; }
199   void AddSourceRange(const parser::CharBlock &);
200   // Find the smallest scope under this one that contains source
201   const Scope *FindScope(parser::CharBlock) const;
202   Scope *FindScope(parser::CharBlock);
203 
204   // Attempts to find a match for a derived type instance
205   const DeclTypeSpec *FindInstantiatedDerivedType(const DerivedTypeSpec &,
206       DeclTypeSpec::Category = DeclTypeSpec::TypeDerived) const;
207 
IsModuleFile()208   bool IsModuleFile() const {
209     return kind_ == Kind::Module && symbol_ != nullptr &&
210         symbol_->test(Symbol::Flag::ModFile);
211   }
212 
213 private:
214   Scope &parent_;  // this is enclosing scope, not extended derived type base
215   const Kind kind_;
216   parser::CharBlock sourceRange_;
217   Symbol *const symbol_;  // if not null, symbol_->scope() == this
218   std::list<Scope> children_;
219   mapType symbols_;
220   mapType commonBlocks_;
221   std::list<EquivalenceSet> equivalenceSets_;
222   mapType crayPointers_;
223   std::map<SourceName, Scope *> submodules_;
224   std::list<DeclTypeSpec> declTypeSpecs_;
225   std::string chars_;
226   std::optional<ImportKind> importKind_;
227   std::set<SourceName> importNames_;
228   const DerivedTypeSpec *derivedTypeSpec_{nullptr};  // dTS->scope() == this
229   // When additional data members are added to Scope, remember to
230   // copy them, if appropriate, in InstantiateDerivedType().
231 
232   // Storage for all Symbols. Every Symbol is in allSymbols and every Symbol*
233   // or Symbol& points to one in there.
234   static Symbols<1024> allSymbols;
235 
236   bool CanImport(const SourceName &) const;
237   const DeclTypeSpec &MakeLengthlessType(DeclTypeSpec &&);
238 
239   friend std::ostream &operator<<(std::ostream &, const Scope &);
240 };
241 }
242 #endif  // FORTRAN_SEMANTICS_SCOPE_H_
243