llvm/flang/lib/semantics/rewrite-parse-tree.cc

162 lines
5.8 KiB
C++
Raw Normal View History

// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rewrite-parse-tree.h"
#include "scope.h"
#include "symbol.h"
#include "../common/indirection.h"
#include "../parser/parse-tree-visitor.h"
#include "../parser/parse-tree.h"
#include <list>
namespace Fortran::semantics {
using namespace parser::literals;
// Symbols collected during name resolution that are added to parse tree.
using symbolMap = std::map<const char *, Symbol *>;
/// Walk the parse tree and add symbols from the symbolMap in Name nodes.
/// Convert mis-identified statement functions to array element assignments.
class RewriteMutator {
public:
RewriteMutator(parser::Messages &messages, const symbolMap &symbols)
: messages_{messages}, symbols_{symbols} {}
// Default action for a parse tree node is to visit children.
template<typename T> bool Pre(T &) { return true; }
template<typename T> void Post(T &) {}
void Post(parser::Name &);
void Post(parser::SpecificationPart &);
bool Pre(parser::ExecutionPart &);
void Post(parser::Variable &x) { ConvertFunctionRef(x); }
void Post(parser::Expr &x) { ConvertFunctionRef(x); }
// Don't bother resolving names in end statements.
bool Pre(parser::EndAssociateStmt &) { return false; }
bool Pre(parser::EndBlockDataStmt &) { return false; }
bool Pre(parser::EndBlockStmt &) { return false; }
bool Pre(parser::EndCriticalStmt &) { return false; }
bool Pre(parser::EndDoStmt &) { return false; }
bool Pre(parser::EndForallStmt &) { return false; }
bool Pre(parser::EndFunctionStmt &) { return false; }
bool Pre(parser::EndIfStmt &) { return false; }
bool Pre(parser::EndModuleStmt &) { return false; }
bool Pre(parser::EndMpSubprogramStmt &) { return false; }
bool Pre(parser::EndProgramStmt &) { return false; }
bool Pre(parser::EndSelectStmt &) { return false; }
bool Pre(parser::EndSubmoduleStmt &) { return false; }
bool Pre(parser::EndSubroutineStmt &) { return false; }
bool Pre(parser::EndTypeStmt &) { return false; }
bool Pre(parser::EndWhereStmt &) { return false; }
private:
using stmtFuncType =
parser::Statement<common::Indirection<parser::StmtFunctionStmt>>;
bool errorOnUnresolvedName_{true};
parser::Messages &messages_;
const symbolMap &symbols_;
std::list<stmtFuncType> stmtFuncsToConvert_;
// For T = Variable or Expr, if x has a function reference that really
// should be an array element reference (i.e. the name occurs in an
// entity declaration, convert it.
template<typename T> void ConvertFunctionRef(T &x) {
auto *funcRef{
std::get_if<common::Indirection<parser::FunctionReference>>(&x.u)};
if (!funcRef) {
return;
}
parser::Name *name{std::get_if<parser::Name>(
&std::get<parser::ProcedureDesignator>((*funcRef)->v.t).u)};
if (!name || !name->symbol || !name->symbol->has<ObjectEntityDetails>()) {
return;
}
x.u = common::Indirection{(*funcRef)->ConvertToArrayElementRef()};
}
};
// Fill in name.symbol if there is a corresponding symbol
void RewriteMutator::Post(parser::Name &name) {
const auto it{symbols_.find(name.source.begin())};
if (it != symbols_.end()) {
name.symbol = it->second;
} else if (errorOnUnresolvedName_) {
messages_.Say(name.source, "Internal: no symbol found for '%s'"_en_US,
name.ToString().c_str());
}
}
// Find mis-parsed statement functions and move to stmtFuncsToConvert_ list.
void RewriteMutator::Post(parser::SpecificationPart &x) {
auto &list{std::get<std::list<parser::DeclarationConstruct>>(x.t)};
for (auto it{list.begin()}; it != list.end();) {
if (auto stmt{std::get_if<stmtFuncType>(&it->u)}) {
Symbol *symbol{std::get<parser::Name>(stmt->statement->t).symbol};
if (symbol && symbol->has<ObjectEntityDetails>()) {
// not a stmt func: remove it here and add to ones to convert
stmtFuncsToConvert_.push_back(std::move(*stmt));
it = list.erase(it);
continue;
}
}
++it;
}
}
// Insert converted assignments at start of ExecutionPart.
bool RewriteMutator::Pre(parser::ExecutionPart &x) {
auto origFirst{x.v.begin()}; // insert each elem before origFirst
for (stmtFuncType &sf : stmtFuncsToConvert_) {
auto &&stmt = sf.statement->ConvertToAssignment();
stmt.source = sf.source;
x.v.insert(origFirst,
parser::ExecutionPartConstruct{parser::ExecutableConstruct{stmt}});
}
stmtFuncsToConvert_.clear();
return true;
}
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 17:21:19 +02:00
static void CollectSymbol(Symbol &symbol, symbolMap &symbols) {
for (const auto &name : symbol.occurrences()) {
symbols.emplace(name.begin(), &symbol);
}
}
static void CollectSymbols(const Scope &scope, symbolMap &symbols) {
for (auto &pair : scope) {
Symbol *symbol{pair.second};
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 17:21:19 +02:00
CollectSymbol(*symbol, symbols);
if (auto *details{symbol->detailsIf<GenericDetails>()}) {
[flang] Name resolution for derived types. This consists of: - a new kind of symbols to represent them with DerivedTypeDetails - creating symbols for derived types when they are declared - creating a new kind of scope for the type to hold component symbols - resolving entity declarations of objects of derived type - resolving references to objects of derived type and to components - handling derived types with same name as generic Type parameters are not yet implemented. Refactor DeclTypeSpec to be a value class wrapping an IntrinsicTypeSpec or a DerivedTypeSpec (or neither in the TypeStar and ClassStar cases). Store DerivedTypeSpec objects in a new structure the current scope MakeDerivedTypeSpec so that DeclTypeSpec can just contain a pointer to them, as it currently does for intrinsic types. In GenericDetails, add derivedType field to handle case where generic and derived type have the same name. The generic is in the scope and the derived type is referenced from the generic, similar to the case where a generic and specific have the same name. When one of these names is mis-recognized, we sometimes have to fix up the 'occurrences' lists of the symbols. Assign implicit types as soon as an entity is encountered that requires one. Otherwise implicit derived types won't work. When we see 'x%y' we have to know the type of x in order to resolve y. Add an Implicit flag to mark symbols that were implicitly typed For symbols that introduce a new scope, include a pointer back to that scope. Add CurrNonTypeScope() for the times when we want the current scope but ignoring derived type scopes. For example, that happens when looking for types or parameters, or creating implicit symbols. Original-commit: flang-compiler/f18@9bd16da020b64b78ed3928e0244765cd2e2d8068 Reviewed-on: https://github.com/flang-compiler/f18/pull/109
2018-06-22 17:21:19 +02:00
if (details->derivedType()) {
CollectSymbol(*details->derivedType(), symbols);
}
}
}
for (auto &child : scope.children()) {
CollectSymbols(child, symbols);
}
}
void RewriteParseTree(
parser::Messages &messages, const Scope &scope, parser::Program &program) {
symbolMap symbols;
CollectSymbols(scope, symbols);
RewriteMutator mutator{messages, symbols};
parser::Walk(program, mutator);
}
} // namespace Fortran::semantics