#include "basic-parsers.h"
#include "expr-parsers.h"
#include "misc-parsers.h"
#include "stmt-parser.h"
#include "token-parsers.h"
#include "type-parser-implementation.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/parse-tree.h"
namespace Fortran::parser {
static constexpr auto programUnit{
construct<ProgramUnit>(indirect(Parser<Module>{})) ||
construct<ProgramUnit>(indirect(functionSubprogram)) ||
construct<ProgramUnit>(indirect(subroutineSubprogram)) ||
construct<ProgramUnit>(indirect(Parser<Submodule>{})) ||
construct<ProgramUnit>(indirect(Parser<BlockData>{})) ||
construct<ProgramUnit>(indirect(Parser<MainProgram>{}))};
static constexpr auto normalProgramUnit{StartNewSubprogram{} >> programUnit /
skipMany(";"_tok) / space / recovery(endOfLine, SkipPast<'\n'>{})};
static constexpr auto globalCompilerDirective{
construct<ProgramUnit>(indirect(compilerDirective))};
static constexpr auto globalOpenACCCompilerDirective{
construct<ProgramUnit>(indirect(skipStuffBeforeStatement >>
"!$ACC "_sptok >> Parser<OpenACCRoutineConstruct>{}))};
TYPE_PARSER(
construct<Program>(extension<LanguageFeature::EmptySourceFile>(
"nonstandard usage: empty source file"_port_en_US,
skipStuffBeforeStatement >> !nextCh >>
pure<std::list<ProgramUnit>>()) ||
some(globalCompilerDirective || globalOpenACCCompilerDirective ||
normalProgramUnit) /
skipStuffBeforeStatement))
TYPE_CONTEXT_PARSER("specification part"_en_US,
construct<SpecificationPart>(many(openaccDeclarativeConstruct),
many(openmpDeclarativeConstruct), many(indirect(compilerDirective)),
many(statement(indirect(Parser<UseStmt>{}))),
many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
implicitPart, many(declarationConstruct)))
constexpr auto actionStmtLookAhead{first(actionStmt >> ok,
"ALLOCATE ("_tok, "CALL" >> name >> "("_tok, "GO TO"_tok, "OPEN ("_tok,
"PRINT"_tok / space / !"("_tok, "READ ("_tok, "WRITE ("_tok)};
constexpr auto execPartLookAhead{first(actionStmtLookAhead >> ok,
openaccConstruct >> ok, openmpConstruct >> ok, "ASSOCIATE ("_tok,
"BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok, "CRITICAL"_tok, "DO"_tok,
"IF ("_tok, "WHERE ("_tok, "FORALL ("_tok, "!$CUF"_tok)};
constexpr auto declErrorRecovery{
stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery};
constexpr auto misplacedSpecificationStmt{Parser<UseStmt>{} >>
fail<DeclarationConstruct>("misplaced USE statement"_err_en_US) ||
Parser<ImportStmt>{} >>
fail<DeclarationConstruct>(
"IMPORT statements must follow any USE statements and precede all other declarations"_err_en_US) ||
Parser<ImplicitStmt>{} >>
fail<DeclarationConstruct>(
"IMPLICIT statements must follow USE and IMPORT and precede all other declarations"_err_en_US)};
TYPE_PARSER(recovery(
withMessage("expected declaration construct"_err_en_US,
CONTEXT_PARSER("declaration construct"_en_US,
first(construct<DeclarationConstruct>(specificationConstruct),
construct<DeclarationConstruct>(statement(indirect(dataStmt))),
construct<DeclarationConstruct>(
statement(indirect(formatStmt))),
construct<DeclarationConstruct>(statement(indirect(entryStmt))),
construct<DeclarationConstruct>(
statement(indirect(Parser<StmtFunctionStmt>{}))),
misplacedSpecificationStmt))),
construct<DeclarationConstruct>(declErrorRecovery)))
constexpr auto invalidDeclarationStmt{formatStmt >>
fail<DeclarationConstruct>(
"FORMAT statements are not permitted in this specification part"_err_en_US) ||
entryStmt >>
fail<DeclarationConstruct>(
"ENTRY statements are not permitted in this specification part"_err_en_US)};
constexpr auto limitedDeclarationConstruct{recovery(
withMessage("expected declaration construct"_err_en_US,
inContext("declaration construct"_en_US,
first(construct<DeclarationConstruct>(specificationConstruct),
construct<DeclarationConstruct>(statement(indirect(dataStmt))),
misplacedSpecificationStmt, invalidDeclarationStmt))),
construct<DeclarationConstruct>(
stmtErrorRecoveryStart >> skipStmtErrorRecovery))};
constexpr auto limitedSpecificationPart{inContext("specification part"_en_US,
construct<SpecificationPart>(many(openaccDeclarativeConstruct),
many(openmpDeclarativeConstruct), many(indirect(compilerDirective)),
many(statement(indirect(Parser<UseStmt>{}))),
many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
implicitPart, many(limitedDeclarationConstruct)))};
TYPE_CONTEXT_PARSER("specification construct"_en_US,
first(construct<SpecificationConstruct>(indirect(Parser<DerivedTypeDef>{})),
construct<SpecificationConstruct>(indirect(Parser<EnumDef>{})),
construct<SpecificationConstruct>(
statement(indirect(Parser<GenericStmt>{}))),
construct<SpecificationConstruct>(indirect(interfaceBlock)),
construct<SpecificationConstruct>(statement(indirect(parameterStmt))),
construct<SpecificationConstruct>(
statement(indirect(oldParameterStmt))),
construct<SpecificationConstruct>(
statement(indirect(Parser<ProcedureDeclarationStmt>{}))),
construct<SpecificationConstruct>(
statement(Parser<OtherSpecificationStmt>{})),
construct<SpecificationConstruct>(
statement(indirect(typeDeclarationStmt))),
construct<SpecificationConstruct>(indirect(Parser<StructureDef>{})),
construct<SpecificationConstruct>(
indirect(openaccDeclarativeConstruct)),
construct<SpecificationConstruct>(indirect(openmpDeclarativeConstruct)),
construct<SpecificationConstruct>(indirect(compilerDirective))))
TYPE_PARSER(first(
construct<OtherSpecificationStmt>(indirect(Parser<AccessStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<AllocatableStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<AsynchronousStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<BindStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<CodimensionStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<ContiguousStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<DimensionStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<ExternalStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<IntentStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<IntrinsicStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<NamelistStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<OptionalStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<PointerStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<ProtectedStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<SaveStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<TargetStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<ValueStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<VolatileStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<CommonStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<EquivalenceStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<BasedPointerStmt>{})),
construct<OtherSpecificationStmt>(indirect(Parser<CUDAAttributesStmt>{}))))
TYPE_CONTEXT_PARSER("main program"_en_US,
construct<MainProgram>(maybe(statement(Parser<ProgramStmt>{})),
specificationPart, executionPart, maybe(internalSubprogramPart),
unterminatedStatement(Parser<EndProgramStmt>{})))
TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
construct<ProgramStmt>("PROGRAM" >> name /
maybe(extension<LanguageFeature::ProgramParentheses>(
"nonstandard usage: parentheses in PROGRAM statement"_port_en_US,
parenthesized(ok)))))
TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
construct<EndProgramStmt>(recovery(
"END PROGRAM" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
TYPE_CONTEXT_PARSER("module"_en_US,
construct<Module>(statement(Parser<ModuleStmt>{}), limitedSpecificationPart,
maybe(Parser<ModuleSubprogramPart>{}),
unterminatedStatement(Parser<EndModuleStmt>{})))
TYPE_CONTEXT_PARSER(
"MODULE statement"_en_US, construct<ModuleStmt>("MODULE" >> name))
TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
construct<EndModuleStmt>(recovery(
"END MODULE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
TYPE_CONTEXT_PARSER("module subprogram part"_en_US,
construct<ModuleSubprogramPart>(statement(containsStmt),
many(StartNewSubprogram{} >> Parser<ModuleSubprogram>{})))
TYPE_PARSER(construct<ModuleSubprogram>(indirect(functionSubprogram)) ||
construct<ModuleSubprogram>(indirect(subroutineSubprogram)) ||
construct<ModuleSubprogram>(indirect(Parser<SeparateModuleSubprogram>{})) ||
construct<ModuleSubprogram>(indirect(compilerDirective)))
constexpr auto moduleNature{
"INTRINSIC" >> pure(UseStmt::ModuleNature::Intrinsic) ||
"NON_INTRINSIC" >> pure(UseStmt::ModuleNature::Non_Intrinsic)};
TYPE_PARSER(construct<UseStmt>("USE" >> optionalBeforeColons(moduleNature),
name, ", ONLY :" >> optionalList(Parser<Only>{})) ||
construct<UseStmt>("USE" >> optionalBeforeColons(moduleNature), name,
defaulted("," >>
nonemptyList("expected renamings"_err_en_US, Parser<Rename>{})) /
lookAhead(endOfStmt)))
TYPE_PARSER(construct<Rename>("OPERATOR (" >>
construct<Rename::Operators>(
definedOpName / ") => OPERATOR (", definedOpName / ")")) ||
construct<Rename>(construct<Rename::Names>(name, "=>" >> name)))
TYPE_PARSER(construct<Only>(Parser<Rename>{}) ||
construct<Only>(indirect(genericSpec)) || construct<Only>(name))
TYPE_CONTEXT_PARSER("submodule"_en_US,
construct<Submodule>(statement(Parser<SubmoduleStmt>{}),
limitedSpecificationPart, maybe(Parser<ModuleSubprogramPart>{}),
unterminatedStatement(Parser<EndSubmoduleStmt>{})))
TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US,
construct<SubmoduleStmt>(
"SUBMODULE" >> parenthesized(Parser<ParentIdentifier>{}), name))
TYPE_PARSER(construct<ParentIdentifier>(name, maybe(":" >> name)))
TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
construct<EndSubmoduleStmt>(
recovery("END SUBMODULE" >> maybe(name) || bareEnd,
progUnitEndStmtErrorRecovery)))
TYPE_CONTEXT_PARSER("BLOCK DATA subprogram"_en_US,
construct<BlockData>(statement(Parser<BlockDataStmt>{}),
limitedSpecificationPart,
unterminatedStatement(Parser<EndBlockDataStmt>{})))
TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
construct<BlockDataStmt>("BLOCK DATA" >> maybe(name)))
TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
construct<EndBlockDataStmt>(
recovery("END BLOCK DATA" >> maybe(name) || bareEnd,
progUnitEndStmtErrorRecovery)))
TYPE_PARSER(construct<InterfaceBlock>(statement(Parser<InterfaceStmt>{}),
many(Parser<InterfaceSpecification>{}),
statement(Parser<EndInterfaceStmt>{})))
TYPE_PARSER(construct<InterfaceSpecification>(Parser<InterfaceBody>{}) ||
construct<InterfaceSpecification>(statement(Parser<ProcedureStmt>{})))
TYPE_PARSER(construct<InterfaceStmt>("INTERFACE" >> maybe(genericSpec)) ||
construct<InterfaceStmt>(construct<Abstract>("ABSTRACT INTERFACE"_sptok)))
TYPE_PARSER(
construct<EndInterfaceStmt>(recovery("END INTERFACE" >> maybe(genericSpec),
constructEndStmtErrorRecovery >> pure<std::optional<GenericSpec>>())))
TYPE_CONTEXT_PARSER("interface body"_en_US,
construct<InterfaceBody>(
construct<InterfaceBody::Function>(statement(functionStmt),
indirect(limitedSpecificationPart), statement(endFunctionStmt))) ||
construct<InterfaceBody>(construct<InterfaceBody::Subroutine>(
statement(subroutineStmt), indirect(limitedSpecificationPart),
statement(endSubroutineStmt))))
constexpr auto specificProcedures{
nonemptyList("expected specific procedure names"_err_en_US, name)};
TYPE_PARSER(construct<ProcedureStmt>("MODULE PROCEDURE"_sptok >>
pure(ProcedureStmt::Kind::ModuleProcedure),
maybe("::"_tok) >> specificProcedures) ||
construct<ProcedureStmt>(
"PROCEDURE" >> pure(ProcedureStmt::Kind::Procedure),
maybe("::"_tok) >> specificProcedures))
TYPE_PARSER(sourced(first(construct<GenericSpec>("OPERATOR" >>
parenthesized(Parser<DefinedOperator>{})),
construct<GenericSpec>(
construct<GenericSpec::Assignment>("ASSIGNMENT ( = )"_tok)),
construct<GenericSpec>(
construct<GenericSpec::ReadFormatted>("READ ( FORMATTED )"_tok)),
construct<GenericSpec>(
construct<GenericSpec::ReadUnformatted>("READ ( UNFORMATTED )"_tok)),
construct<GenericSpec>(
construct<GenericSpec::WriteFormatted>("WRITE ( FORMATTED )"_tok)),
construct<GenericSpec>(
construct<GenericSpec::WriteUnformatted>("WRITE ( UNFORMATTED )"_tok)),
construct<GenericSpec>(name))))
TYPE_PARSER(construct<GenericStmt>("GENERIC" >> maybe("," >> accessSpec),
"::" >> genericSpec, "=>" >> specificProcedures))
TYPE_PARSER(
"EXTERNAL" >> maybe("::"_tok) >> construct<ExternalStmt>(listOfNames))
TYPE_PARSER("PROCEDURE" >>
construct<ProcedureDeclarationStmt>(parenthesized(maybe(procInterface)),
optionalListBeforeColons(Parser<ProcAttrSpec>{}),
nonemptyList("expected procedure declarations"_err_en_US, procDecl)))
TYPE_PARSER(
construct<ProcInterface>(declarationTypeSpec / lookAhead(")"_tok)) ||
construct<ProcInterface>(name))
TYPE_PARSER(construct<ProcAttrSpec>(accessSpec) ||
construct<ProcAttrSpec>(languageBindingSpec) ||
construct<ProcAttrSpec>("INTENT" >> parenthesized(intentSpec)) ||
construct<ProcAttrSpec>(optional) || construct<ProcAttrSpec>(pointer) ||
construct<ProcAttrSpec>(protectedAttr) || construct<ProcAttrSpec>(save))
TYPE_PARSER(construct<ProcDecl>(name, maybe("=>" >> Parser<ProcPointerInit>{})))
TYPE_PARSER(
construct<ProcPointerInit>(nullInit) || construct<ProcPointerInit>(name))
TYPE_PARSER(
"INTRINSIC" >> maybe("::"_tok) >> construct<IntrinsicStmt>(listOfNames))
TYPE_CONTEXT_PARSER("function reference"_en_US,
sourced(construct<FunctionReference>(
construct<Call>(Parser<ProcedureDesignator>{},
parenthesized(optionalList(actualArgSpec))))) /
!"["_tok)
TYPE_PARSER(extension<LanguageFeature::CUDA>(
"<<<" >> construct<CallStmt::Chevrons>(scalarExpr, "," >> scalarExpr,
maybe("," >> scalarIntExpr), maybe("," >> scalarIntExpr)) /
">>>"))
constexpr auto actualArgSpecList{optionalList(actualArgSpec)};
TYPE_CONTEXT_PARSER("CALL statement"_en_US,
construct<CallStmt>(
sourced(construct<CallStmt>("CALL" >> Parser<ProcedureDesignator>{},
maybe(Parser<CallStmt::Chevrons>{}) / space,
"(" >> actualArgSpecList / ")" ||
lookAhead(endOfStmt) >> defaulted(actualArgSpecList)))))
TYPE_PARSER(construct<ProcedureDesignator>(Parser<ProcComponentRef>{}) ||
construct<ProcedureDesignator>(name))
TYPE_PARSER(construct<ActualArgSpec>(
maybe(keyword / "=" / !"="_ch), Parser<ActualArg>{}))
TYPE_PARSER(construct<ActualArg>(expr) ||
construct<ActualArg>(Parser<AltReturnSpec>{}) ||
extension<LanguageFeature::PercentRefAndVal>(
"nonstandard usage: %REF"_port_en_US,
construct<ActualArg>(
construct<ActualArg::PercentRef>("%REF" >> parenthesized(expr)))) ||
extension<LanguageFeature::PercentRefAndVal>(
"nonstandard usage: %VAL"_port_en_US,
construct<ActualArg>(
construct<ActualArg::PercentVal>("%VAL" >> parenthesized(expr)))))
TYPE_PARSER(construct<AltReturnSpec>(star >> label))
TYPE_PARSER(first("DEVICE" >> pure(common::CUDASubprogramAttrs::Device),
"GLOBAL" >> pure(common::CUDASubprogramAttrs::Global),
"GRID_GLOBAL" >> pure(common::CUDASubprogramAttrs::Grid_Global),
"HOST" >> pure(common::CUDASubprogramAttrs::Host)))
TYPE_PARSER(first(construct<PrefixSpec>(declarationTypeSpec),
construct<PrefixSpec>(construct<PrefixSpec::Elemental>("ELEMENTAL"_tok)),
construct<PrefixSpec>(construct<PrefixSpec::Impure>("IMPURE"_tok)),
construct<PrefixSpec>(construct<PrefixSpec::Module>("MODULE"_tok)),
construct<PrefixSpec>(
construct<PrefixSpec::Non_Recursive>("NON_RECURSIVE"_tok)),
construct<PrefixSpec>(construct<PrefixSpec::Pure>("PURE"_tok)),
construct<PrefixSpec>(construct<PrefixSpec::Recursive>("RECURSIVE"_tok)),
extension<LanguageFeature::CUDA>(
construct<PrefixSpec>(construct<PrefixSpec::Attributes>("ATTRIBUTES" >>
parenthesized(
optionalList(Parser<common::CUDASubprogramAttrs>{}))))),
extension<LanguageFeature::CUDA>(construct<PrefixSpec>(
construct<PrefixSpec::Launch_Bounds>("LAUNCH_BOUNDS" >>
parenthesized(nonemptyList(
"expected launch bounds"_err_en_US, scalarIntConstantExpr))))),
extension<LanguageFeature::CUDA>(construct<PrefixSpec>(
construct<PrefixSpec::Cluster_Dims>("CLUSTER_DIMS" >>
parenthesized(nonemptyList("expected cluster dimensions"_err_en_US,
scalarIntConstantExpr)))))))
TYPE_CONTEXT_PARSER("FUNCTION subprogram"_en_US,
construct<FunctionSubprogram>(statement(functionStmt), specificationPart,
executionPart, maybe(internalSubprogramPart),
unterminatedStatement(endFunctionStmt)))
TYPE_CONTEXT_PARSER("FUNCTION statement"_en_US,
construct<FunctionStmt>(many(prefixSpec), "FUNCTION" >> name,
parenthesized(optionalList(name)), maybe(suffix)) ||
extension<LanguageFeature::OmitFunctionDummies>(
"nonstandard usage: FUNCTION statement without dummy argument list"_port_en_US,
construct<FunctionStmt>(
many(prefixSpec), "FUNCTION" >> name,
construct<std::list<Name>>(),
construct<std::optional<Suffix>>())))
TYPE_PARSER(construct<Suffix>(
languageBindingSpec, maybe("RESULT" >> parenthesized(name))) ||
construct<Suffix>(
"RESULT" >> parenthesized(name), maybe(languageBindingSpec)))
TYPE_PARSER(construct<EndFunctionStmt>(recovery(
"END FUNCTION" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
TYPE_CONTEXT_PARSER("SUBROUTINE subprogram"_en_US,
construct<SubroutineSubprogram>(statement(subroutineStmt),
specificationPart, executionPart, maybe(internalSubprogramPart),
unterminatedStatement(endSubroutineStmt)))
TYPE_PARSER(
construct<SubroutineStmt>(many(prefixSpec), "SUBROUTINE" >> name,
parenthesized(optionalList(dummyArg)), maybe(languageBindingSpec)) ||
construct<SubroutineStmt>(many(prefixSpec), "SUBROUTINE" >> name,
pure<std::list<DummyArg>>(),
pure<std::optional<LanguageBindingSpec>>()))
TYPE_PARSER(construct<DummyArg>(name) || construct<DummyArg>(star))
TYPE_PARSER(construct<EndSubroutineStmt>(recovery(
"END SUBROUTINE" >> maybe(name) || bareEnd, progUnitEndStmtErrorRecovery)))
TYPE_CONTEXT_PARSER("separate module subprogram"_en_US,
construct<SeparateModuleSubprogram>(statement(Parser<MpSubprogramStmt>{}),
specificationPart, executionPart, maybe(internalSubprogramPart),
statement(Parser<EndMpSubprogramStmt>{})))
TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
construct<MpSubprogramStmt>("MODULE PROCEDURE"_sptok >> name))
TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
construct<EndMpSubprogramStmt>(
recovery("END PROCEDURE" >> maybe(name) || bareEnd,
progUnitEndStmtErrorRecovery)))
TYPE_PARSER(
"ENTRY" >> (construct<EntryStmt>(name,
parenthesized(optionalList(dummyArg)), maybe(suffix)) ||
construct<EntryStmt>(name, construct<std::list<DummyArg>>(),
construct<std::optional<Suffix>>())))
TYPE_CONTEXT_PARSER("RETURN statement"_en_US,
construct<ReturnStmt>("RETURN" >> maybe(scalarIntExpr)))
TYPE_PARSER(construct<ContainsStmt>("CONTAINS"_tok))
TYPE_CONTEXT_PARSER("statement function definition"_en_US,
construct<StmtFunctionStmt>(
name, parenthesized(optionalList(name)), "=" >> scalar(expr)))
}