//===-- lib/Parser/parse-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/Parser/parse-tree.h" #include "flang/Common/idioms.h" #include "flang/Common/indirection.h" #include "flang/Parser/tools.h" #include "flang/Parser/user-state.h" #include "llvm/Support/raw_ostream.h" #include namespace Fortran::parser { // R867 ImportStmt::ImportStmt(common::ImportKind &&k, std::list &&n) : kind{k}, names(std::move(n)) { CHECK(kind == common::ImportKind::Default || kind == common::ImportKind::Only || names.empty()); } // R873 CommonStmt::CommonStmt(std::optional &&name, std::list &&objects, std::list &&others) { blocks.emplace_front(std::move(name), std::move(objects)); blocks.splice(blocks.end(), std::move(others)); } // R901 designator bool Designator::EndsInBareName() const { return common::visit( common::visitors{ [](const DataRef &dr) { return std::holds_alternative(dr.u) || std::holds_alternative>( dr.u); }, [](const Substring &) { return false; }, }, u); } // R911 data-ref -> part-ref [% part-ref]... DataRef::DataRef(std::list &&prl) : u{std::move(prl.front().name)} { for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) { PartRef &pr{prl.front()}; if (!first) { u = common::Indirection::Make( std::move(*this), std::move(pr.name)); } if (!pr.subscripts.empty()) { u = common::Indirection::Make( std::move(*this), std::move(pr.subscripts)); } if (pr.imageSelector) { u = common::Indirection::Make( std::move(*this), std::move(*pr.imageSelector)); } } } // R1001 - R1022 expression Expr::Expr(Designator &&x) : u{common::Indirection::Make(std::move(x))} {} Expr::Expr(FunctionReference &&x) : u{common::Indirection::Make(std::move(x))} {} const std::optional &DoConstruct::GetLoopControl() const { const NonLabelDoStmt &doStmt{ std::get>(t).statement}; const std::optional &control{ std::get>(doStmt.t)}; return control; } bool DoConstruct::IsDoNormal() const { const std::optional &control{GetLoopControl()}; return control && std::holds_alternative(control->u); } bool DoConstruct::IsDoWhile() const { const std::optional &control{GetLoopControl()}; return control && std::holds_alternative(control->u); } bool DoConstruct::IsDoConcurrent() const { const std::optional &control{GetLoopControl()}; return control && std::holds_alternative(control->u); } static Designator MakeArrayElementRef( const Name &name, std::list &&subscripts) { ArrayElement arrayElement{DataRef{Name{name}}, std::list{}}; for (Expr &expr : subscripts) { arrayElement.subscripts.push_back( SectionSubscript{Integer{common::Indirection{std::move(expr)}}}); } return Designator{DataRef{common::Indirection{std::move(arrayElement)}}}; } static Designator MakeArrayElementRef( StructureComponent &&sc, std::list &&subscripts) { ArrayElement arrayElement{DataRef{common::Indirection{std::move(sc)}}, std::list{}}; for (Expr &expr : subscripts) { arrayElement.subscripts.push_back( SectionSubscript{Integer{common::Indirection{std::move(expr)}}}); } return Designator{DataRef{common::Indirection{std::move(arrayElement)}}}; } // Set source in any type of node that has it. template T WithSource(CharBlock source, T &&x) { x.source = source; return std::move(x); } static Expr ActualArgToExpr(ActualArgSpec &arg) { return common::visit( common::visitors{ [&](common::Indirection &y) { return std::move(y.value()); }, [&](common::Indirection &y) { return common::visit( common::visitors{ [&](common::Indirection &z) { return WithSource( z.value().source, Expr{std::move(z.value())}); }, [&](common::Indirection &z) { return WithSource( z.value().source, Expr{std::move(z.value())}); }, }, y.value().u); }, [&](auto &) -> Expr { common::die("unexpected type"); }, }, std::get(arg.t).u); } Designator FunctionReference::ConvertToArrayElementRef() { std::list args; for (auto &arg : std::get>(v.t)) { args.emplace_back(ActualArgToExpr(arg)); } return common::visit( common::visitors{ [&](const Name &name) { return WithSource( source, MakeArrayElementRef(name, std::move(args))); }, [&](ProcComponentRef &pcr) { return WithSource(source, MakeArrayElementRef(std::move(pcr.v.thing), std::move(args))); }, }, std::get(v.t).u); } StructureConstructor FunctionReference::ConvertToStructureConstructor( const semantics::DerivedTypeSpec &derived) { Name name{std::get(std::get(v.t).u)}; std::list components; for (auto &arg : std::get>(v.t)) { std::optional keyword; if (auto &kw{std::get>(arg.t)}) { keyword.emplace(Keyword{Name{kw->v}}); } components.emplace_back( std::move(keyword), ComponentDataSource{ActualArgToExpr(arg)}); } DerivedTypeSpec spec{std::move(name), std::list{}}; spec.derivedTypeSpec = &derived; return StructureConstructor{std::move(spec), std::move(components)}; } StructureConstructor ArrayElement::ConvertToStructureConstructor( const semantics::DerivedTypeSpec &derived) { Name name{std::get(base.u)}; std::list components; for (auto &subscript : subscripts) { components.emplace_back(std::optional{}, ComponentDataSource{std::move(*Unwrap(subscript))}); } DerivedTypeSpec spec{std::move(name), std::list{}}; spec.derivedTypeSpec = &derived; return StructureConstructor{std::move(spec), std::move(components)}; } Substring ArrayElement::ConvertToSubstring() { auto iter{subscripts.begin()}; CHECK(iter != subscripts.end()); auto &triplet{std::get(iter->u)}; CHECK(!std::get<2>(triplet.t)); CHECK(++iter == subscripts.end()); return Substring{std::move(base), SubstringRange{std::get<0>(std::move(triplet.t)), std::get<1>(std::move(triplet.t))}}; } // R1544 stmt-function-stmt // Convert this stmt-function-stmt to an assignment to the result of a // pointer-valued function call -- which itself will be converted to a // much more likely array element assignment statement if it needs // to be. Statement StmtFunctionStmt::ConvertToAssignment() { auto &funcName{std::get(t)}; auto &funcArgs{std::get>(t)}; auto &funcExpr{std::get>(t).thing}; CharBlock source{funcName.source}; // Extend source to include closing parenthesis if (funcArgs.empty()) { CHECK(*source.end() == '('); source = CharBlock{source.begin(), source.end() + 1}; } std::list actuals; for (const Name &arg : funcArgs) { actuals.emplace_back(std::optional{}, ActualArg{Expr{WithSource( arg.source, Designator{DataRef{Name{arg.source, arg.symbol}}})}}); source.ExtendToCover(arg.source); } CHECK(*source.end() == ')'); source = CharBlock{source.begin(), source.end() + 1}; FunctionReference funcRef{ Call{ProcedureDesignator{Name{funcName.source, funcName.symbol}}, std::move(actuals)}}; funcRef.source = source; auto variable{Variable{common::Indirection{std::move(funcRef)}}}; return Statement{std::nullopt, ActionStmt{common::Indirection{ AssignmentStmt{std::move(variable), std::move(funcExpr)}}}}; } CharBlock Variable::GetSource() const { return common::visit( common::visitors{ [&](const common::Indirection &des) { return des.value().source; }, [&](const common::Indirection &call) { return call.value().source; }, }, u); } llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) { return os << x.ToString(); } OmpDependenceType::Value OmpDoacross::GetDepType() const { return common::visit( // common::visitors{ [](const OmpDoacross::Sink &) { return OmpDependenceType::Value::Sink; }, [](const OmpDoacross::Source &) { return OmpDependenceType::Value::Source; }, }, u); } OmpTaskDependenceType::Value OmpDependClause::TaskDep::GetTaskDepType() const { using Modifier = OmpDependClause::TaskDep::Modifier; auto &modifiers{std::get>>(t)}; if (modifiers) { for (auto &m : *modifiers) { if (auto *dep{std::get_if(&m.u)}) { return dep->v; } } llvm_unreachable("expecting OmpTaskDependenceType in TaskDep"); } else { llvm_unreachable("expecting modifiers on OmpDependClause::TaskDep"); } } } // namespace Fortran::parser template static llvm::omp::Clause getClauseIdForClass(C &&) { using namespace Fortran; using A = llvm::remove_cvref_t; // A is referenced in OMP.inc // The code included below contains a sequence of checks like the following // for each OpenMP clause // if constexpr (std::is_same_v) // return llvm::omp::Clause::OMPC_acq_rel; // [...] #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP #include "llvm/Frontend/OpenMP/OMP.inc" } namespace Fortran::parser { llvm::omp::Clause OmpClause::Id() const { return std::visit([](auto &&s) { return getClauseIdForClass(s); }, u); } } // namespace Fortran::parser