//===-- lib/Semantics/program-tree.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Semantics/program-tree.h" #include "flang/Common/idioms.h" #include "flang/Parser/char-block.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/semantics.h" namespace Fortran::semantics { static void GetEntryStmts( ProgramTree &node, const parser::SpecificationPart &spec) { const auto &implicitPart{std::get(spec.t)}; for (const parser::ImplicitPartStmt &stmt : implicitPart.v) { if (const auto *entryStmt{std::get_if< parser::Statement>>( &stmt.u)}) { node.AddEntry(entryStmt->statement.value()); } } for (const auto &decl : std::get>(spec.t)) { if (const auto *entryStmt{std::get_if< parser::Statement>>( &decl.u)}) { node.AddEntry(entryStmt->statement.value()); } } } static void GetEntryStmts( ProgramTree &node, const parser::ExecutionPart &exec) { for (const auto &epConstruct : exec.v) { if (const auto *entryStmt{std::get_if< parser::Statement>>( &epConstruct.u)}) { node.AddEntry(entryStmt->statement.value()); } } } // Collects generics that define simple names that could include // identically-named subprograms as specific procedures. static void GetGenerics( ProgramTree &node, const parser::SpecificationPart &spec) { for (const auto &decl : std::get>(spec.t)) { if (const auto *spec{ std::get_if(&decl.u)}) { if (const auto *generic{std::get_if< parser::Statement>>( &spec->u)}) { const parser::GenericStmt &genericStmt{generic->statement.value()}; const auto &genericSpec{std::get(genericStmt.t)}; node.AddGeneric(genericSpec); } else if (const auto *interface{ std::get_if>( &spec->u)}) { const parser::InterfaceBlock &interfaceBlock{interface->value()}; const parser::InterfaceStmt &interfaceStmt{ std::get>(interfaceBlock.t) .statement}; const auto *genericSpec{ std::get_if>(&interfaceStmt.u)}; if (genericSpec && genericSpec->has_value()) { node.AddGeneric(**genericSpec); } } } } } template static ProgramTree BuildSubprogramTree( const parser::Name &name, SemanticsContext &context, const T &x) { const auto &spec{std::get(x.t)}; const auto &exec{std::get(x.t)}; const auto &subps{ std::get>(x.t)}; ProgramTree node{name, spec, &exec}; GetEntryStmts(node, spec); GetEntryStmts(node, exec); GetGenerics(node, spec); if (subps) { for (const auto &subp : std::get>(subps->t)) { common::visit( [&](const auto &y) { if (auto child{ProgramTree::Build(y.value(), context)}) { node.AddChild(std::move(*child)); } }, subp.u); } } return node; } static ProgramTree BuildSubprogramTree( const parser::Name &name, SemanticsContext &, const parser::BlockData &x) { const auto &spec{std::get(x.t)}; return ProgramTree{name, spec}; } template static ProgramTree BuildModuleTree( const parser::Name &name, SemanticsContext &context, const T &x) { const auto &spec{std::get(x.t)}; const auto &subps{std::get>(x.t)}; ProgramTree node{name, spec}; GetGenerics(node, spec); if (subps) { for (const auto &subp : std::get>(subps->t)) { common::visit( [&](const auto &y) { if (auto child{ProgramTree::Build(y.value(), context)}) { node.AddChild(std::move(*child)); } }, subp.u); } } return node; } ProgramTree &ProgramTree::Build( const parser::ProgramUnit &x, SemanticsContext &context) { return common::visit( [&](const auto &y) -> ProgramTree & { auto node{Build(y.value(), context)}; CHECK(node.has_value()); return context.SaveProgramTree(std::move(*node)); }, x.u); } std::optional ProgramTree::Build( const parser::MainProgram &x, SemanticsContext &context) { const auto &stmt{ std::get>>(x.t)}; const auto &end{std::get>(x.t)}; static parser::Name emptyName; auto result{stmt ? BuildSubprogramTree(stmt->statement.v, context, x).set_stmt(*stmt) : BuildSubprogramTree(emptyName, context, x)}; return std::move(result.set_endStmt(end)); } std::optional ProgramTree::Build( const parser::FunctionSubprogram &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{std::get>(x.t)}; const auto &name{std::get(stmt.statement.t)}; const parser::LanguageBindingSpec *bindingSpec{}; if (const auto &suffix{ std::get>(stmt.statement.t)}) { if (suffix->binding) { bindingSpec = &*suffix->binding; } } return BuildSubprogramTree(name, context, x) .set_stmt(stmt) .set_endStmt(end) .set_bindingSpec(bindingSpec); } std::optional ProgramTree::Build( const parser::SubroutineSubprogram &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{std::get>(x.t)}; const auto &name{std::get(stmt.statement.t)}; const parser::LanguageBindingSpec *bindingSpec{}; if (const auto &binding{std::get>( stmt.statement.t)}) { bindingSpec = &*binding; } return BuildSubprogramTree(name, context, x) .set_stmt(stmt) .set_endStmt(end) .set_bindingSpec(bindingSpec); } std::optional ProgramTree::Build( const parser::SeparateModuleSubprogram &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{ std::get>(x.t)}; const auto &name{stmt.statement.v}; return BuildSubprogramTree(name, context, x).set_stmt(stmt).set_endStmt(end); } std::optional ProgramTree::Build( const parser::Module &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{std::get>(x.t)}; const auto &name{stmt.statement.v}; return BuildModuleTree(name, context, x).set_stmt(stmt).set_endStmt(end); } std::optional ProgramTree::Build( const parser::Submodule &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{std::get>(x.t)}; const auto &name{std::get(stmt.statement.t)}; return BuildModuleTree(name, context, x).set_stmt(stmt).set_endStmt(end); } std::optional ProgramTree::Build( const parser::BlockData &x, SemanticsContext &context) { const auto &stmt{std::get>(x.t)}; const auto &end{std::get>(x.t)}; static parser::Name emptyName; auto result{stmt.statement.v ? BuildSubprogramTree(*stmt.statement.v, context, x) : BuildSubprogramTree(emptyName, context, x)}; return std::move(result.set_stmt(stmt).set_endStmt(end)); } std::optional ProgramTree::Build( const parser::CompilerDirective &x, SemanticsContext &context) { if (context.ShouldWarn(common::UsageWarning::IgnoredDirective)) { context.Say(x.source, "Compiler directive ignored here"_warn_en_US); } return std::nullopt; } std::optional ProgramTree::Build( const parser::OpenACCRoutineConstruct &, SemanticsContext &) { DIE("ProgramTree::Build() called for OpenACCRoutineConstruct"); } const parser::ParentIdentifier &ProgramTree::GetParentId() const { const auto *stmt{ std::get *>(stmt_)}; return std::get(stmt->statement.t); } bool ProgramTree::IsModule() const { auto kind{GetKind()}; return kind == Kind::Module || kind == Kind::Submodule; } Symbol::Flag ProgramTree::GetSubpFlag() const { return GetKind() == Kind::Function ? Symbol::Flag::Function : Symbol::Flag::Subroutine; } bool ProgramTree::HasModulePrefix() const { if (std::holds_alternative< const parser::Statement *>(stmt_)) { return true; // MODULE PROCEDURE foo } using ListType = std::list; const auto *prefixes{common::visit( common::visitors{ [](const parser::Statement *x) { return &std::get(x->statement.t); }, [](const parser::Statement *x) { return &std::get(x->statement.t); }, [](const auto *) -> const ListType * { return nullptr; }, }, stmt_)}; if (prefixes) { for (const auto &prefix : *prefixes) { if (std::holds_alternative(prefix.u)) { return true; } } } return false; } ProgramTree::Kind ProgramTree::GetKind() const { return common::visit( common::visitors{ [](const parser::Statement *) { return Kind::Program; }, [](const parser::Statement *) { return Kind::Function; }, [](const parser::Statement *) { return Kind::Subroutine; }, [](const parser::Statement *) { return Kind::MpSubprogram; }, [](const parser::Statement *) { return Kind::Module; }, [](const parser::Statement *) { return Kind::Submodule; }, [](const parser::Statement *) { return Kind::BlockData; }, }, stmt_); } void ProgramTree::set_scope(Scope &scope) { scope_ = &scope; CHECK(endStmt_); scope.AddSourceRange(*endStmt_); } void ProgramTree::AddChild(ProgramTree &&child) { children_.emplace_back(std::move(child)); } void ProgramTree::AddEntry(const parser::EntryStmt &entryStmt) { entryStmts_.emplace_back(entryStmt); } void ProgramTree::AddGeneric(const parser::GenericSpec &generic) { genericSpecs_.emplace_back(generic); } } // namespace Fortran::semantics