Add negative parsing tests using mlir-opt.

Add parsing tests with errors. Follows direct path of splitting file into test groups (using a marker) and parsing each section individually. The expected errors are checked using FileCheck and parser error does not result in terminating parsing the rest of the file if check-parser-error.

This is an interim approach until refactoring lexer/parser.

PiperOrigin-RevId: 201867941
diff --git a/tools/mlir-opt/mlir-opt.cpp b/tools/mlir-opt/mlir-opt.cpp
index a75ba76..75ed4f5 100644
--- a/tools/mlir-opt/mlir-opt.cpp
+++ b/tools/mlir-opt/mlir-opt.cpp
@@ -39,6 +39,9 @@
 outputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"),
                cl::init("-"));
 
+static cl::opt<bool>
+checkParserErrors("check-parser-errors", cl::desc("Check for parser errors"),
+                  cl::init(false));
 
 /// Open the specified output file and return it, exiting if there is any I/O or
 /// other errors.
@@ -54,11 +57,43 @@
   return result;
 }
 
+/// Parses the memory buffer and, if successfully parsed, prints the parsed
+/// output. Returns whether parsing succeeded.
+bool parseAndPrintMemoryBuffer(std::unique_ptr<MemoryBuffer> buffer) {
+  // Tell sourceMgr about this buffer, which is what the parser will pick up.
+  SourceMgr sourceMgr;
+  sourceMgr.AddNewSourceBuffer(std::move(buffer), SMLoc());
+
+  // Parse the input file and emit any errors.
+  MLIRContext context;
+  std::unique_ptr<Module> module(parseSourceFile(sourceMgr, &context));
+  if (!module) return false;
+
+  // Print the output.
+  auto output = getOutputStream();
+  module->print(output->os());
+  output->keep();
+
+  // Success.
+  return true;
+}
+
+/// Split the memory buffer into multiple buffers using the marker -----.
+bool splitMemoryBufferForErrorChecking(std::unique_ptr<MemoryBuffer> buffer) {
+  const char marker[] = "-----";
+  SmallVector<StringRef, 2> sourceBuffers;
+  buffer->getBuffer().split(sourceBuffers, marker);
+  for (auto& subbuffer : sourceBuffers)
+    parseAndPrintMemoryBuffer(MemoryBuffer::getMemBufferCopy(subbuffer));
+
+  // Ignore errors returned by parseAndPrintMemoryBuffer when checking parse
+  // errors reported.
+  return true;
+}
+
 int main(int argc, char **argv) {
   InitLLVM x(argc, argv);
 
-  MLIRContext context;
-
   cl::ParseCommandLineOptions(argc, argv, "MLIR modular optimizer driver\n");
 
   // Set up the input file.
@@ -69,19 +104,7 @@
     return 1;
   }
 
-  // Tell sourceMgr about this buffer, which is what the parser will pick up.
-  SourceMgr sourceMgr;
-  sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), SMLoc());
-
-  // Parse the input file and emit any errors.
-  std::unique_ptr<Module> module(parseSourceFile(sourceMgr, &context));
-  if (!module) return 1;
-
-  // Print the output.
-  auto output = getOutputStream();
-  module->print(output->os());
-  output->keep();
-
-  // Success.
-  return 0;
+  if (checkParserErrors)
+    return !splitMemoryBufferForErrorChecking(std::move(*fileOrErr));
+  return !parseAndPrintMemoryBuffer(std::move(*fileOrErr));
 }