Instantiate a stubbed SPIR-V parser if file ends in .spv

- spv parser just errors out for now
- link against SPIRV-Tools-opt
- Fixe CMake variable TINT_ENABLE_SPV_PARSER --> TINT_BUILD_SPV_PARSER

Bug: tint:3
Change-Id: Ie4ef9b03e001fca3cc11f65a425612755857feac
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/16600
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c20be8..1c4bffc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,6 +69,9 @@
 function(tint_default_compile_options TARGET)
   include_directories("${PROJECT_SOURCE_DIR}")
 
+  if (${TINT_BUILD_SPV_PARSER})
+    target_compile_definitions(${TARGET} PRIVATE -DTINT_BUILD_SPV_PARSER=1)
+  endif()
   if (${COMPILER_IS_LIKE_GNU})
     target_compile_options(${TARGET} PRIVATE
       -std=c++14
diff --git a/samples/main.cc b/samples/main.cc
index eb98ec6..4fa8166 100644
--- a/samples/main.cc
+++ b/samples/main.cc
@@ -26,6 +26,10 @@
 #include "src/writer/wgsl/generator.h"
 #include "src/writer/writer.h"
 
+#if TINT_BUILD_SPV_PARSER
+#include "src/reader/spv/parser.h"
+#endif
+
 namespace {
 
 enum class Format {
@@ -110,7 +114,18 @@
   return true;
 }
 
-std::vector<uint8_t> ReadFile(const std::string& input_file) {
+/// Copies the content from the file named |filename| to |buffer|,
+/// assuming each element in the file is of type |T|.  If any error occurs,
+/// writes error messages to the standard error stream and returns false.
+/// Assumes the size of a |T| object is divisible by its required alignment.
+/// @returns true if we successfully read the file.
+template <typename T>
+bool ReadFile(const std::string& input_file, std::vector<T>* buffer) {
+  if (!buffer) {
+    std::cerr << "The buffer pointer was null" << std::endl;
+    return false;
+  }
+
   FILE* file = nullptr;
 #if defined(_MSC_VER)
   fopen_s(&file, input_file.c_str(), "rb");
@@ -119,7 +134,7 @@
 #endif
   if (!file) {
     std::cerr << "Failed to open " << input_file << std::endl;
-    return {};
+    return false;
   }
 
   fseek(file, 0, SEEK_END);
@@ -129,21 +144,28 @@
     fclose(file);
     return {};
   }
+  const auto file_size = static_cast<size_t>(tell_file_size);
+  if (0 != (file_size % sizeof(T))) {
+    std::cerr << "File " << input_file
+              << " does not contain an integral number of objects: "
+              << file_size << " bytes in the file, require " << sizeof(T)
+              << " bytes per object" << std::endl;
+    fclose(file);
+    return false;
+  }
   fseek(file, 0, SEEK_SET);
 
-  size_t file_size = static_cast<size_t>(tell_file_size);
+  buffer->clear();
+  buffer->resize(file_size / sizeof(T));
 
-  std::vector<uint8_t> data;
-  data.resize(file_size);
-
-  size_t bytes_read = fread(data.data(), sizeof(uint8_t), file_size, file);
+  size_t bytes_read = fread(buffer->data(), 1, file_size, file);
   fclose(file);
   if (bytes_read != file_size) {
     std::cerr << "Failed to read " << input_file << std::endl;
-    return {};
+    return false;
   }
 
-  return data;
+  return true;
 }
 
 std::string Disassemble(const std::vector<uint32_t>& data) {
@@ -204,18 +226,28 @@
     return 1;
   }
 
-  auto data = ReadFile(options.input_filename);
-  if (data.size() == 0)
-    return 1;
-
   std::unique_ptr<tint::reader::Reader> reader;
-  std::string ext = "wgsl";
-  if (options.input_filename.size() > 4 &&
-      options.input_filename.substr(options.input_filename.size() - 4) ==
-          "wgsl") {
+  if (options.input_filename.size() > 5 &&
+      options.input_filename.substr(options.input_filename.size() - 5) ==
+          ".wgsl") {
+    std::vector<uint8_t> data;
+    if (!ReadFile<uint8_t>(options.input_filename, &data)) {
+      return 1;
+    }
     reader = std::make_unique<tint::reader::wgsl::Parser>(
         std::string(data.begin(), data.end()));
   }
+#if TINT_BUILD_SPV_PARSER
+  if (options.input_filename.size() > 4 &&
+      options.input_filename.substr(options.input_filename.size() - 4) ==
+          ".spv") {
+    std::vector<uint32_t> data;
+    if (!ReadFile<uint32_t>(options.input_filename, &data)) {
+      return 1;
+    }
+    reader = std::make_unique<tint::reader::spv::Parser>(data);
+  }
+#endif
   if (!reader) {
     std::cerr << "Failed to create reader for input file: "
               << options.input_filename << std::endl;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 05c61bb..86dd091 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -305,8 +305,9 @@
 tint_default_compile_options(libtint)
 set_target_properties(libtint PROPERTIES OUTPUT_NAME "tint")
 
-if(${TINT_ENABLE_SPV_PARSER})
-  target_link_libraries(libtint SPIRV-Tools)
+if(${TINT_BUILD_SPV_PARSER})
+  # We'll use the optimizer for its nice SPIR-V in-memory representation
+  target_link_libraries(libtint SPIRV-Tools-opt SPIRV-Tools)
 endif()
 
 add_executable(tint_unittests ${TINT_TEST_SRCS})
diff --git a/src/reader/spv/parser.cc b/src/reader/spv/parser.cc
index 3c56d39..12d23ae 100644
--- a/src/reader/spv/parser.cc
+++ b/src/reader/spv/parser.cc
@@ -25,6 +25,7 @@
 Parser::~Parser() = default;
 
 bool Parser::Parse() {
+  set_error("SPIR-V parsing is not supported yet");
   return false;
 }
 
diff --git a/src/reader/spv/parser.h b/src/reader/spv/parser.h
index c47d14f..e748ffa 100644
--- a/src/reader/spv/parser.h
+++ b/src/reader/spv/parser.h
@@ -31,6 +31,7 @@
   /// Creates a new parser
   /// @param input the input data to parse
   explicit Parser(const std::vector<uint32_t>& input);
+  /// Destructor
   ~Parser() override;
 
   /// Run the parser