// Copyright (c) 2018-2019, 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 "semantics.h" #include "symbol.h" #include "tools.h" #include "../common/indirection.h" #include "../parser/parse-tree-visitor.h" #include "../parser/parse-tree.h" #include namespace Fortran::semantics { using namespace parser::literals; /// Convert mis-identified statement functions to array element assignments. /// Convert mis-identified format expressions to namelist group names. class RewriteMutator { public: RewriteMutator(parser::Messages &messages) : messages_{messages} {} // Default action for a parse tree node is to visit children. template bool Pre(T &) { return true; } template void Post(T &) {} void Post(parser::Name &); void Post(parser::SpecificationPart &); bool Pre(parser::ExecutionPart &); void Post(parser::ReadStmt &); void Post(parser::WriteStmt &); // Name resolution yet implemented: bool Pre(parser::EquivalenceStmt &) { return false; } bool Pre(parser::Keyword &) { return false; } bool Pre(parser::EntryStmt &) { return false; } bool Pre(parser::CompilerDirective &) { return false; } // Don't bother resolving names in end statements. bool Pre(parser::EndBlockDataStmt &) { return false; } bool Pre(parser::EndFunctionStmt &) { return false; } bool Pre(parser::EndModuleStmt &) { return false; } bool Pre(parser::EndMpSubprogramStmt &) { return false; } bool Pre(parser::EndProgramStmt &) { return false; } bool Pre(parser::EndSubmoduleStmt &) { return false; } bool Pre(parser::EndSubroutineStmt &) { return false; } bool Pre(parser::EndTypeStmt &) { return false; } private: using stmtFuncType = parser::Statement>; bool errorOnUnresolvedName_{true}; parser::Messages &messages_; std::list stmtFuncsToConvert_; }; // Check that name has been resolved to a symbol void RewriteMutator::Post(parser::Name &name) { if (name.symbol == nullptr && errorOnUnresolvedName_) { messages_.Say(name.source, "Internal: no symbol found for '%s'"_err_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>(x.t)}; for (auto it{list.begin()}; it != list.end();) { if (auto stmt{std::get_if(&it->u)}) { Symbol *symbol{std::get(stmt->statement.value().t).symbol}; if (symbol && symbol->has()) { // 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.value().ConvertToAssignment()}; stmt.source = sf.source; x.v.insert(origFirst, parser::ExecutionPartConstruct{ parser::ExecutableConstruct{std::move(stmt)}}); } stmtFuncsToConvert_.clear(); return true; } // When a namelist group name appears (without NML=) in a READ or WRITE // statement in such a way that it can be misparsed as a format expression, // rewrite the I/O statement's parse tree node as if the namelist group // name had appeared with NML=. template void FixMisparsedUntaggedNamelistName(READ_OR_WRITE &x) { if (x.iounit.has_value() && x.format.has_value()) { if (auto *charExpr{ std::get_if(&x.format.value().u)}) { parser::Expr &expr{charExpr->thing.value()}; parser::Name *name{GetSimpleName(expr)}; if (name != nullptr && name->symbol != nullptr && name->symbol->has()) { x.controls.emplace_front(parser::IoControlSpec{std::move(*name)}); x.format.reset(); } } } } void RewriteMutator::Post(parser::ReadStmt &x) { FixMisparsedUntaggedNamelistName(x); } void RewriteMutator::Post(parser::WriteStmt &x) { FixMisparsedUntaggedNamelistName(x); } bool RewriteParseTree(SemanticsContext &context, parser::Program &program) { RewriteMutator mutator{context.messages()}; parser::Walk(program, mutator); return !context.AnyFatalError(); } }