[flang] Better error recovery, some debugging.
authorpeter klausler <pklausler@nvidia.com>
Mon, 2 Apr 2018 23:06:18 +0000 (16:06 -0700)
committerpeter klausler <pklausler@nvidia.com>
Mon, 2 Apr 2018 23:06:18 +0000 (16:06 -0700)
Original-commit: flang-compiler/f18@b7509f0e5be796e0b29a481215f3950c8276d76d
Reviewed-on: https://github.com/flang-compiler/f18/pull/38
Tree-same-pre-rewrite: false

flang/lib/parser/grammar.h
flang/lib/parser/parsing.cc
flang/lib/parser/parsing.h
flang/tools/f18/f18.cc
flang/tools/f18/test-sema.cc
flang/tools/f18/test-type.cc

index 57ab8c8..e3a91f4 100644 (file)
@@ -176,7 +176,7 @@ template<typename PA> inline constexpr auto unterminatedStatement(const PA &p) {
 }
 
 constexpr auto endOfLine = "\n"_ch / skipEmptyLines ||
-    fail<const char *>("expected end of line"_en_US);
+    fail<const char *>("expected end of line"_err_en_US);
 
 constexpr auto endOfStmt = space >>
     (";"_ch / skipMany(";"_tok) / maybe(endOfLine) || endOfLine);
@@ -558,7 +558,7 @@ constexpr auto executableConstruct =
 constexpr auto obsoleteExecutionPartConstruct = recovery(
     ignoredStatementPrefix >>
         fail<ExecutionPartConstruct>(
-            "obsolete legacy extension is not supported"_en_US),
+            "obsolete legacy extension is not supported"_err_en_US),
     construct<ExecutionPartConstruct>{}(
         statement("REDIMENSION" >> name >>
             parenthesized(nonemptyList(Parser<AllocateShapeSpec>{})) >> ok) >>
@@ -872,7 +872,11 @@ TYPE_PARSER(construct<PrivateOrSequence>{}(Parser<PrivateStmt>{}) ||
     construct<PrivateOrSequence>{}(Parser<SequenceStmt>{}))
 
 // R730 end-type-stmt -> END TYPE [type-name]
-TYPE_PARSER("END TYPE" >> construct<EndTypeStmt>{}(maybe(name)))
+constexpr auto noNameEnd = "END" >> defaulted(cut >> maybe(name));
+constexpr auto bareEnd = noNameEnd / lookAhead(endOfStmt);
+constexpr auto endStmtErrorRecovery = noNameEnd / SkipTo<'\n'>{};
+TYPE_PARSER(construct<EndTypeStmt>{}(
+    recovery("END TYPE" >> maybe(name), endStmtErrorRecovery)))
 
 // R731 sequence-stmt -> SEQUENCE
 TYPE_PARSER("SEQUENCE" >> construct<SequenceStmt>{})
@@ -1070,7 +1074,8 @@ TYPE_PARSER(
     construct<Enumerator>{}(namedConstant, maybe("=" >> scalarIntConstantExpr)))
 
 // R763 end-enum-stmt -> END ENUM
-TYPE_PARSER("END ENUM" >> construct<EndEnumStmt>{})
+TYPE_PARSER(recovery("END ENUM"_tok, "END" >> SkipTo<'\n'>{}) >>
+    construct<EndEnumStmt>{})
 
 // R764 boz-literal-constant -> binary-constant | octal-constant | hex-constant
 // R765 binary-constant -> B ' digit [digit]... ' | B " digit [digit]... "
@@ -3237,9 +3242,9 @@ TYPE_CONTEXT_PARSER("PROGRAM statement"_en_US,
         "PROGRAM" >> name / maybe(extension(parenthesized(ok)))))
 
 // R1403 end-program-stmt -> END [PROGRAM [program-name]]
-constexpr auto bareEnd = "END" >> defaulted(cut >> maybe(name));
 TYPE_CONTEXT_PARSER("END PROGRAM statement"_en_US,
-    construct<EndProgramStmt>{}("END PROGRAM" >> maybe(name) || bareEnd))
+    construct<EndProgramStmt>{}(recovery(
+        "END PROGRAM" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1404 module ->
 //         module-stmt [specification-part] [module-subprogram-part]
@@ -3255,7 +3260,8 @@ TYPE_CONTEXT_PARSER(
 
 // R1406 end-module-stmt -> END [MODULE [module-name]]
 TYPE_CONTEXT_PARSER("END MODULE statement"_en_US,
-    construct<EndModuleStmt>{}("END MODULE" >> maybe(name) || bareEnd))
+    construct<EndModuleStmt>{}(
+        recovery("END MODULE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1407 module-subprogram-part -> contains-stmt [module-subprogram]...
 TYPE_CONTEXT_PARSER("module subprogram part"_en_US,
@@ -3303,19 +3309,20 @@ TYPE_PARSER(construct<Only>{}(Parser<Rename>{}) ||
 TYPE_CONTEXT_PARSER("submodule"_en_US,
     construct<Submodule>{}(statement(Parser<SubmoduleStmt>{}),
         specificationPart, maybe(Parser<ModuleSubprogramPart>{}),
-        statement(Parser<EndSubmoduleStmt>{})))
+        unterminatedStatement(Parser<EndSubmoduleStmt>{})))
 
 // R1417 submodule-stmt -> SUBMODULE ( parent-identifier ) submodule-name
 TYPE_CONTEXT_PARSER("SUBMODULE statement"_en_US,
-    "SUBMODULE" >> construct<SubmoduleStmt>{}(
-                       parenthesized(Parser<ParentIdentifier>{}), name))
+    construct<SubmoduleStmt>{}(
+        "SUBMODULE" >> parenthesized(Parser<ParentIdentifier>{}), name))
 
 // R1418 parent-identifier -> ancestor-module-name [: parent-submodule-name]
 TYPE_PARSER(construct<ParentIdentifier>{}(name, maybe(":" >> name)))
 
 // R1419 end-submodule-stmt -> END [SUBMODULE [submodule-name]]
 TYPE_CONTEXT_PARSER("END SUBMODULE statement"_en_US,
-    construct<EndSubmoduleStmt>{}("END SUBMODULE" >> maybe(name) || bareEnd))
+    construct<EndSubmoduleStmt>{}(recovery(
+        "END SUBMODULE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1420 block-data -> block-data-stmt [specification-part] end-block-data-stmt
 TYPE_CONTEXT_PARSER("BLOCK DATA subprogram"_en_US,
@@ -3328,7 +3335,8 @@ TYPE_CONTEXT_PARSER("BLOCK DATA statement"_en_US,
 
 // R1422 end-block-data-stmt -> END [BLOCK DATA [block-data-name]]
 TYPE_CONTEXT_PARSER("END BLOCK DATA statement"_en_US,
-    construct<EndBlockDataStmt>{}("END BLOCK DATA" >> maybe(name) || bareEnd))
+    construct<EndBlockDataStmt>{}(recovery(
+        "END BLOCK DATA" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1501 interface-block ->
 //         interface-stmt [interface-specification]... end-interface-stmt
@@ -3461,7 +3469,7 @@ std::optional<FunctionReference> Parser<FunctionReference>::Parse(
         return {FunctionReference{std::move(call.value())}};
       }
     }
-    state->PutMessage("expected (arguments)"_en_US);
+    state->Say("expected (arguments)"_err_en_US);
   }
   state->PopContext();
   return {};
@@ -3554,8 +3562,8 @@ TYPE_PARSER(construct<Suffix>{}(
         "RESULT" >> parenthesized(name), maybe(languageBindingSpec)))
 
 // R1533 end-function-stmt -> END [FUNCTION [function-name]]
-TYPE_PARSER(
-    construct<EndFunctionStmt>{}("END FUNCTION" >> maybe(name) || bareEnd))
+TYPE_PARSER(construct<EndFunctionStmt>{}(
+    recovery("END FUNCTION" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1534 subroutine-subprogram ->
 //         subroutine-stmt [specification-part] [execution-part]
@@ -3579,8 +3587,8 @@ TYPE_PARSER(
 TYPE_PARSER(construct<DummyArg>{}(name) || construct<DummyArg>{}(star))
 
 // R1537 end-subroutine-stmt -> END [SUBROUTINE [subroutine-name]]
-TYPE_PARSER(
-    construct<EndSubroutineStmt>{}("END SUBROUTINE" >> maybe(name) || bareEnd))
+TYPE_PARSER(construct<EndSubroutineStmt>{}(
+    recovery("END SUBROUTINE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1538 separate-module-subprogram ->
 //         mp-subprogram-stmt [specification-part] [execution-part]
@@ -3596,7 +3604,8 @@ TYPE_CONTEXT_PARSER("MODULE PROCEDURE statement"_en_US,
 
 // R1540 end-mp-subprogram-stmt -> END [PROCEDURE [procedure-name]]
 TYPE_CONTEXT_PARSER("END PROCEDURE statement"_en_US,
-    construct<EndMpSubprogramStmt>{}("END PROCEDURE" >> maybe(name) || bareEnd))
+    construct<EndMpSubprogramStmt>{}(recovery(
+        "END PROCEDURE" >> maybe(name) || bareEnd, endStmtErrorRecovery)))
 
 // R1541 entry-stmt -> ENTRY entry-name [( [dummy-arg-list] ) [suffix]]
 TYPE_PARSER("ENTRY" >>
index 71ff71f..2ce013f 100644 (file)
@@ -80,27 +80,25 @@ void Parsing::Parse() {
   messages_.Annex(parseState.messages());
 }
 
-std::optional<Program> Parsing::ForTesting(
-    std::string path, std::ostream &err) {
-  Parsing parsing;
-  parsing.Prescan(path, Options{});
-  if (parsing.messages().AnyFatalError()) {
-    parsing.messages().Emit(err);
+bool Parsing::ForTesting(std::string path, std::ostream &err) {
+  Prescan(path, Options{});
+  if (messages_.AnyFatalError()) {
+    messages_.Emit(err);
     err << "could not scan " << path << '\n';
-    return {};
+    return false;
   }
-  parsing.Parse();
-  parsing.messages().Emit(err);
-  if (!parsing.consumedWholeFile()) {
+  Parse();
+  messages_.Emit(err);
+  if (!consumedWholeFile_) {
     err << "f18 parser FAIL; final position: ";
-    parsing.Identify(err, parsing.finalRestingPlace(), "   ");
-    return {};
+    Identify(err, finalRestingPlace_, "   ");
+    return false;
   }
-  if (parsing.messages().AnyFatalError()) {
+  if (messages_.AnyFatalError() || !parseTree_.has_value()) {
     err << "could not parse " << path << '\n';
-    return {};
+    return false;
   }
-  return std::move(parsing.parseTree());
+  return true;
 }
 }  // namespace parser
 }  // namespace Fortran
index 655d461..ed32613 100644 (file)
@@ -49,7 +49,7 @@ public:
         o, cooked_.GetProvenance(at).start(), prefix, echoSourceLine);
   }
 
-  static std::optional<Program> ForTesting(std::string path, std::ostream &);
+  bool ForTesting(std::string path, std::ostream &);
 
 private:
   Options options_;
index 1a7bc32..2089443 100644 (file)
@@ -163,8 +163,8 @@ std::string CompileFortran(std::string path, Fortran::parser::Options options,
     parsing.Identify(std::cerr, parsing.finalRestingPlace(), "   ");
     exit(EXIT_FAILURE);
   }
-  if (!parsing.messages().empty() &&
-      (driver.warningsAreErrors || parsing.messages().AnyFatalError()) ||
+  if ((!parsing.messages().empty() &&
+       (driver.warningsAreErrors || parsing.messages().AnyFatalError())) ||
       !parsing.parseTree().has_value()) {
     std::cerr << driver.prefix << "could not parse " << path << '\n';
     exit(EXIT_FAILURE);
index 38c98bf..1ec522a 100644 (file)
@@ -22,8 +22,9 @@ int main(int argc, char *const argv[]) {
     return EXIT_FAILURE;
   }
   std::string path{argv[1]};
-  if (std::optional<Program> parseTree{Parsing::ForTesting(path, std::cerr)}) {
-    DoSemanticAnalysis(parsing.messages().cooked(), *parseTree);
+  Parsing parsing;
+  if (parsing.ForTesting(path, std::cerr)) {
+    DoSemanticAnalysis(parsing.messages().cooked(), *parsing.parseTree());
     return EXIT_SUCCESS;
   }
   return EXIT_FAILURE;
index c584618..6dfd8bc 100644 (file)
@@ -15,8 +15,9 @@ int main(int argc, char *const argv[]) {
     return EXIT_FAILURE;
   }
   std::string path{argv[1]};
-  if (std::optional<Program> parseTree{Parsing::ForTesting(path, std::cerr)}) {
-    semantics::MakeTypes(std::cout, *parseTree);
+  Parsing parsing;
+  if (parsing.ForTesting(path, std::cerr)) {
+    semantics::MakeTypes(std::cout, *parsing.parseTree());
     return EXIT_SUCCESS;
   }
   return EXIT_FAILURE;