[spirv-reader] Update to create BlockStatements

This CL updates the SPIR-V Reader to create BlockStatements instead of
StatementLists.

Bug: tint:136
Change-Id: I957019446ca00306187de701f86ae3e0dd5c5eb8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25740
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/ast/block_statement.h b/src/ast/block_statement.h
index eb408de..4ee0806 100644
--- a/src/ast/block_statement.h
+++ b/src/ast/block_statement.h
@@ -51,6 +51,10 @@
   const ast::Statement* last() const {
     return statements_.empty() ? nullptr : statements_.back().get();
   }
+  /// @returns the last statement in the block or nullptr if block empty
+  ast::Statement* last() {
+    return statements_.empty() ? nullptr : statements_.back().get();
+  }
 
   /// Retrieves the statement at |idx|
   /// @param idx the index. The index is not bounds checked.
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 844cc01..8ca69c7 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -460,7 +460,7 @@
     const Construct* construct,
     uint32_t end_id,
     CompletionAction completion_action,
-    ast::StatementList statements,
+    std::unique_ptr<ast::BlockStatement> statements,
     std::unique_ptr<ast::CaseStatementList> cases)
     : construct_(construct),
       end_id_(end_id),
@@ -476,7 +476,8 @@
                                             uint32_t end_id,
                                             CompletionAction action) {
   statements_stack_.emplace_back(
-      StatementBlock{construct, end_id, action, ast::StatementList{}, nullptr});
+      StatementBlock{construct, end_id, action,
+                     std::make_unique<ast::BlockStatement>(), nullptr});
 }
 
 void FunctionEmitter::PushGuard(const std::string& guard_name,
@@ -509,9 +510,9 @@
                         });
 }
 
-const ast::StatementList& FunctionEmitter::ast_body() {
+const ast::BlockStatement* FunctionEmitter::ast_body() {
   assert(!statements_stack_.empty());
-  return statements_stack_[0].statements_;
+  return statements_stack_[0].statements_.get();
 }
 
 ast::Statement* FunctionEmitter::AddStatement(
@@ -519,7 +520,7 @@
   assert(!statements_stack_.empty());
   auto* result = statement.get();
   if (result != nullptr) {
-    statements_stack_.back().statements_.emplace_back(std::move(statement));
+    statements_stack_.back().statements_->append(std::move(statement));
   }
   return result;
 }
@@ -527,8 +528,8 @@
 ast::Statement* FunctionEmitter::LastStatement() {
   assert(!statements_stack_.empty());
   const auto& statement_list = statements_stack_.back().statements_;
-  assert(!statement_list.empty());
-  return statement_list.back().get();
+  assert(!statement_list->empty());
+  return statement_list->last();
 }
 
 bool FunctionEmitter::Emit() {
@@ -554,7 +555,7 @@
                      "element but has "
                   << statements_stack_.size();
   }
-  ast::StatementList body(std::move(statements_stack_[0].statements_));
+  auto body = std::move(statements_stack_[0].statements_);
   parser_impl_.get_module().functions().back()->set_body(std::move(body));
   // Maintain the invariant by repopulating the one and only element.
   statements_stack_.clear();
@@ -1984,7 +1985,7 @@
     // Push the else clause onto the stack first.
     PushNewStatementBlock(construct, else_end, [if_stmt](StatementBlock* s) {
       // Only set the else-clause if there are statements to fill it.
-      if (!s->statements_.empty()) {
+      if (!s->statements_->empty()) {
         // The "else" consists of the statement list from the top of statments
         // stack, without an elseif condition.
         ast::ElseStatementList else_stmts;
@@ -2136,8 +2137,8 @@
     if ((default_info == clause_heads[i]) && has_selectors &&
         construct->ContainsPos(default_info->pos)) {
       // Generate a default clause with a just fallthrough.
-      ast::StatementList stmts;
-      stmts.emplace_back(std::make_unique<ast::FallthroughStatement>());
+      auto stmts = std::make_unique<ast::BlockStatement>();
+      stmts->append(std::make_unique<ast::FallthroughStatement>());
       auto case_stmt = std::make_unique<ast::CaseStatement>();
       case_stmt->set_body(std::move(stmts));
       cases->emplace_back(std::move(case_stmt));
@@ -2362,13 +2363,13 @@
   auto if_stmt = std::make_unique<ast::IfStatement>();
   if_stmt->set_condition(std::move(condition));
   if (then_stmt != nullptr) {
-    ast::StatementList stmts;
-    stmts.emplace_back(std::move(then_stmt));
+    auto stmts = std::make_unique<ast::BlockStatement>();
+    stmts->append(std::move(then_stmt));
     if_stmt->set_body(std::move(stmts));
   }
   if (else_stmt != nullptr) {
-    ast::StatementList stmts;
-    stmts.emplace_back(std::move(else_stmt));
+    auto stmts = std::make_unique<ast::BlockStatement>();
+    stmts->append(std::move(else_stmt));
     ast::ElseStatementList else_stmts;
     else_stmts.emplace_back(
         std::make_unique<ast::ElseStatement>(nullptr, std::move(stmts)));
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index 91e0913..32a062c 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -293,7 +293,7 @@
   /// Returns the body of the function.  It is the bottom of the statement
   /// stack.
   /// @returns the body of the function.
-  const ast::StatementList& ast_body();
+  const ast::BlockStatement* ast_body();
 
   /// Records failure.
   /// @returns a FailStream on which to emit diagnostics.
@@ -713,7 +713,7 @@
     StatementBlock(const Construct* construct,
                    uint32_t end_id,
                    CompletionAction completion_action,
-                   ast::StatementList statements,
+                   std::unique_ptr<ast::BlockStatement> statements,
                    std::unique_ptr<ast::CaseStatementList> cases);
     StatementBlock(StatementBlock&&);
     ~StatementBlock();
@@ -730,7 +730,7 @@
     // Only one of |statements| or |cases| is active.
 
     // The list of statements being built, if this construct is not a switch.
-    ast::StatementList statements_;
+    std::unique_ptr<ast::BlockStatement> statements_;
     // The list of switch cases being built, if this construct is a switch.
     // The algorithm will cache a pointer to the vector.  We want that pointer
     // to be stable no matter how |statements_stack_| is resized.  That's
diff --git a/src/reader/spirv/parser_impl_test_helper.h b/src/reader/spirv/parser_impl_test_helper.h
index 3be8566..cc7d5cd 100644
--- a/src/reader/spirv/parser_impl_test_helper.h
+++ b/src/reader/spirv/parser_impl_test_helper.h
@@ -70,9 +70,9 @@
 /// Returns the string dump of a function body.
 /// @param body the statement in the body
 /// @returnss the string dump of a function body.
-inline std::string ToString(const ast::StatementList& body) {
+inline std::string ToString(const ast::BlockStatement* body) {
   std::ostringstream outs;
-  for (const auto& stmt : body) {
+  for (const auto& stmt : *body) {
     stmt->to_str(outs, 0);
   }
   return outs.str();