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