| //===-- lib/Parser/stmt-parser.h --------------------------------*- C++ -*-===// | |
| // | |
| // 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef FORTRAN_PARSER_STMT_PARSER_H_ | |
| #define FORTRAN_PARSER_STMT_PARSER_H_ | |
| // Basic parsing of statements. | |
| #include "basic-parsers.h" | |
| #include "token-parsers.h" | |
| namespace Fortran::parser { | |
| // statement(p) parses Statement<P> for some statement type P that is the | |
| // result type of the argument parser p, while also handling labels and | |
| // end-of-statement markers. | |
| // R611 label -> digit [digit]... | |
| constexpr auto label{space >> digitString64 / spaceCheck}; | |
| template <typename PA> | |
| inline constexpr auto unterminatedStatement(const PA &p) { | |
| return skipStuffBeforeStatement >> | |
| sourced(construct<Statement<typename PA::resultType>>( | |
| maybe(label / space), p)); | |
| } | |
| constexpr auto atEndOfStmt{space >> | |
| withMessage("expected end of statement"_err_en_US, lookAhead(";\n"_ch))}; | |
| constexpr auto checkEndOfKnownStmt{recovery(atEndOfStmt, SkipTo<'\n'>{})}; | |
| constexpr auto endOfLine{consumedAllInput || | |
| withMessage("expected end of line"_err_en_US, "\n"_ch >> ok)}; | |
| constexpr auto semicolons{";"_ch >> skipMany(";"_tok) / space}; | |
| constexpr auto endOfStmt{ | |
| space >> withMessage("expected end of statement"_err_en_US, | |
| (semicolons / maybe(endOfLine)) || endOfLine)}; | |
| constexpr auto skipToNextLineIfAny{consumedAllInput || SkipPast<'\n'>{}}; | |
| constexpr auto forceEndOfStmt{recovery(endOfStmt, skipToNextLineIfAny)}; | |
| template <typename PA> inline constexpr auto statement(const PA &p) { | |
| return unterminatedStatement(p) / endOfStmt; | |
| } | |
| // unlabeledStatement() is basically statement() for those few situations | |
| // in Fortran where a statement cannot have a label. | |
| template <typename PA> inline constexpr auto unlabeledStatement(const PA &p) { | |
| return space >> | |
| sourced(construct<UnlabeledStatement<typename PA::resultType>>(p)); | |
| } | |
| // This unambiguousStatement() variant of statement() provides better error | |
| // recovery for contexts containing statements that might have trailing | |
| // garbage, but it must be used only when no instance of the statement in | |
| // question could also be a legal prefix of some other statement that might | |
| // be valid at that point. It only makes sense to use this within "some()" | |
| // or "many()" so as to not end the list of statements. | |
| template <typename PA> inline constexpr auto unambiguousStatement(const PA &p) { | |
| return unterminatedStatement(p) / forceEndOfStmt; | |
| } | |
| constexpr auto ignoredStatementPrefix{ | |
| skipStuffBeforeStatement >> maybe(label) >> maybe(name / ":") >> space}; | |
| // Error recovery within a statement() call: skip *to* the end of the line, | |
| // unless at an END or CONTAINS statement. | |
| constexpr auto inStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> | |
| (consumedAllInput || SkipTo<'\n'>{}) >> construct<ErrorRecovery>()}; | |
| // Error recovery within statement sequences: skip *past* the end of the line, | |
| // but not over an END or CONTAINS statement. | |
| constexpr auto skipStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> | |
| (consumedAllInput || SkipPast<'\n'>{}) >> construct<ErrorRecovery>()}; | |
| // Error recovery across statements: skip the line, unless it looks | |
| // like it might end the containing construct. | |
| constexpr auto stmtErrorRecoveryStart{ignoredStatementPrefix}; | |
| constexpr auto skipBadLine{skipToNextLineIfAny >> construct<ErrorRecovery>()}; | |
| constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >> | |
| !"END"_tok >> !"CONTAINS"_tok >> !"ELSE"_tok >> !"CASE"_tok >> | |
| !"TYPE IS"_tok >> !"CLASS"_tok >> !"RANK"_tok >> | |
| !("!$ACC "_sptok >> "END"_tok) >> | |
| !("!$OMP "_sptok >> ("END"_tok || "SECTION"_id)) >> skipBadLine}; | |
| // END statement error recovery | |
| constexpr auto missingOptionalName{pure<std::optional<Name>>()}; | |
| constexpr auto noNameEnd{"END" >> missingOptionalName}; | |
| // For unrecognizable construct END statements. Be sure to not consume | |
| // a program unit's END statement. | |
| constexpr auto progUnitEndStmt{consumedAllInput || | |
| "END" >> (lookAhead("\n"_ch) || "SUBROUTINE"_tok || "FUNCTION"_tok || | |
| "PROCEDURE"_tok || "MODULE"_tok || "SUBMODULE"_tok || | |
| "PROGRAM"_tok || "BLOCK DATA"_tok)}; | |
| constexpr auto constructEndStmtErrorRecovery{ | |
| !progUnitEndStmt >> ("END"_tok >> SkipTo<'\n'>{} || ok)}; | |
| constexpr auto namedConstructEndStmtErrorRecovery{ | |
| constructEndStmtErrorRecovery >> missingOptionalName}; | |
| constexpr auto progUnitEndStmtErrorRecovery{ | |
| many(!"END"_tok >> SkipPast<'\n'>{}) >> | |
| maybe("END"_tok >> SkipTo<'\n'>{}) >> missingOptionalName}; | |
| constexpr auto beginDirective{skipStuffBeforeStatement >> "!"_ch}; | |
| constexpr auto endDirective{space >> endOfLine}; | |
| } // namespace Fortran::parser | |
| #endif // FORTRAN_PARSER_STMT_PARSER_H_ |