1 // Copyright (c) 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_RESOLVE_NAMES_UTILS_H_
16 #define FORTRAN_SEMANTICS_RESOLVE_NAMES_UTILS_H_
17 
18 // Utility functions and class for use in resolve-names.cc.
19 
20 #include "scope.h"
21 #include "symbol.h"
22 #include "type.h"
23 #include "../parser/message.h"
24 #include <forward_list>
25 
26 namespace Fortran::parser {
27 class CharBlock;
28 struct ArraySpec;
29 struct CoarraySpec;
30 struct ComponentArraySpec;
31 struct DataRef;
32 struct DefinedOpName;
33 struct Designator;
34 struct Expr;
35 struct GenericSpec;
36 struct Name;
37 }
38 
39 namespace Fortran::semantics {
40 
41 using SourceName = parser::CharBlock;
42 class SemanticsContext;
43 
44 // Record that a Name has been resolved to a Symbol
45 Symbol &Resolve(const parser::Name &, Symbol &);
46 Symbol *Resolve(const parser::Name &, Symbol *);
47 
48 // Create a copy of msg with a new isFatal value.
49 parser::MessageFixedText WithIsFatal(
50     const parser::MessageFixedText &msg, bool isFatal);
51 
52 // Is this the name of a defined operator, e.g. ".foo."
53 bool IsDefinedOperator(const SourceName &);
54 bool IsIntrinsicOperator(const SemanticsContext &, const SourceName &);
55 bool IsLogicalConstant(const SemanticsContext &, const SourceName &);
56 
57 // Analyze a generic-spec and generate a symbol name and GenericKind for it.
58 class GenericSpecInfo {
59 public:
GenericSpecInfo(const parser::DefinedOpName & x)60   GenericSpecInfo(const parser::DefinedOpName &x) { Analyze(x); }
GenericSpecInfo(const parser::GenericSpec & x)61   GenericSpecInfo(const parser::GenericSpec &x) { Analyze(x); }
62 
kind()63   GenericKind kind() const { return kind_; }
symbolName()64   const SourceName &symbolName() const { return symbolName_.value(); }
65   // Some intrinsic operators have more than one name (e.g. `operator(.eq.)` and
66   // `operator(==)`). GetAllNames() returns them all, including symbolName.
67   std::forward_list<std::string> GetAllNames() const;
68   // Set the GenericKind in this symbol and resolve the corresponding
69   // name if there is one
70   void Resolve(Symbol *) const;
71   Symbol *FindInScope(const Scope &) const;
72 
73 private:
74   GenericKind kind_;
75   const parser::Name *parseName_{nullptr};
76   std::optional<SourceName> symbolName_;
77 
78   void Analyze(const parser::DefinedOpName &);
79   void Analyze(const parser::GenericSpec &);
80 };
81 
82 // Analyze a parser::ArraySpec or parser::CoarraySpec
83 ArraySpec AnalyzeArraySpec(SemanticsContext &, const parser::ArraySpec &);
84 ArraySpec AnalyzeArraySpec(
85     SemanticsContext &, const parser::ComponentArraySpec &);
86 ArraySpec AnalyzeCoarraySpec(
87     SemanticsContext &context, const parser::CoarraySpec &);
88 
89 // Perform consistency checks on equivalence sets
90 class EquivalenceSets {
91 public:
EquivalenceSets(SemanticsContext & context)92   EquivalenceSets(SemanticsContext &context) : context_{context} {}
sets()93   std::vector<EquivalenceSet> &sets() { return sets_; };
94   // Resolve this designator and add to the current equivalence set
95   void AddToSet(const parser::Designator &);
96   // Finish the current equivalence set: determine if it overlaps
97   // with any of the others and perform necessary merges if it does.
98   void FinishSet(const parser::CharBlock &);
99 
100 private:
101   bool CheckCanEquivalence(
102       const parser::CharBlock &, const Symbol &, const Symbol &);
103   void MergeInto(const parser::CharBlock &, EquivalenceSet &, std::size_t);
104   const EquivalenceObject *Find(const EquivalenceSet &, const Symbol &);
105   bool CheckDesignator(const parser::Designator &);
106   bool CheckDataRef(const parser::CharBlock &, const parser::DataRef &);
107   bool CheckObject(const parser::Name &);
108   bool CheckArrayBound(const parser::Expr &);
109   bool CheckSubstringBound(const parser::Expr &, bool);
110   bool IsCharacterSequenceType(const DeclTypeSpec *);
111   bool IsDefaultKindNumericType(const IntrinsicTypeSpec &);
112   bool IsNumericSequenceType(const DeclTypeSpec *);
113   bool IsSequenceType(
114       const DeclTypeSpec *, std::function<bool(const IntrinsicTypeSpec &)>);
115 
116   SemanticsContext &context_;
117   std::vector<EquivalenceSet> sets_;  // all equivalence sets in this scope
118   // Map object to index of set it is in
119   std::map<EquivalenceObject, std::size_t> objectToSet_;
120   EquivalenceSet currSet_;  // equivalence set currently being constructed
121   struct {
122     Symbol *symbol{nullptr};
123     std::vector<ConstantSubscript> subscripts;
124     std::optional<ConstantSubscript> substringStart;
125   } currObject_;  // equivalence object currently being constructed
126 };
127 
128 }
129 #endif  // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
130