wsgl parser: Add optional Source* out params

... to match() and expect_ident().

The uses of these two functions frequently want to know the souce of the matched token.

Bug: tint:282
Change-Id: I5279fc2e0834f48d419c6d8c9888189f6212c44a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31732
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index d3e7536..e7b49a4 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -457,10 +457,8 @@
     if (!expect("builtin decoration", Token::Type::kParenLeft))
       return nullptr;
 
-    source = peek().source();
-
     std::string ident;
-    if (!expect_ident("builtin", &ident))
+    if (!expect_ident("builtin", &ident, &source))
       return nullptr;
 
     ast::Builtin builtin = ident_to_builtin(ident);
@@ -1280,9 +1278,8 @@
   next();  // consume the peek of [[
 
   for (;;) {
-    auto source = peek().source();
-
-    if (!match(Token::Type::kStride)) {
+    Source source;
+    if (!match(Token::Type::kStride, &source)) {
       add_error(source, "unknown array decoration");
       return false;
     }
@@ -1596,9 +1593,8 @@
 //   : OFFSET PAREN_LEFT INT_LITERAL PAREN_RIGHT
 std::unique_ptr<ast::StructMemberDecoration>
 ParserImpl::struct_member_decoration() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kOffset))
+  Source source;
+  if (!match(Token::Type::kOffset, &source))
     return nullptr;
 
   const char* use = "offset decoration";
@@ -1779,9 +1775,8 @@
 // function_header
 //   : FN IDENT PAREN_LEFT param_list PAREN_RIGHT ARROW function_type_decl
 std::unique_ptr<ast::Function> ParserImpl::function_header() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kFn))
+  Source source;
+  if (!match(Token::Type::kFn, &source))
     return nullptr;
 
   const char* use = "function declaration";
@@ -2071,9 +2066,8 @@
 // return_stmt
 //   : RETURN logical_or_expression?
 std::unique_ptr<ast::ReturnStatement> ParserImpl::return_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kReturn))
+  Source source;
+  if (!match(Token::Type::kReturn, &source))
     return nullptr;
 
   std::unique_ptr<ast::Expression> expr = nullptr;
@@ -2149,9 +2143,8 @@
 // if_stmt
 //   : IF paren_rhs_stmt body_stmt elseif_stmt? else_stmt?
 std::unique_ptr<ast::IfStatement> ParserImpl::if_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kIf))
+  Source source;
+  if (!match(Token::Type::kIf, &source))
     return nullptr;
 
   auto condition = paren_rhs_stmt();
@@ -2239,9 +2232,8 @@
 // switch_stmt
 //   : SWITCH paren_rhs_stmt BRACKET_LEFT switch_body+ BRACKET_RIGHT
 std::unique_ptr<ast::SwitchStatement> ParserImpl::switch_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kSwitch))
+  Source source;
+  if (!match(Token::Type::kSwitch, &source))
     return nullptr;
 
   auto condition = paren_rhs_stmt();
@@ -2387,9 +2379,8 @@
 // loop_stmt
 //   : LOOP BRACKET_LEFT statements continuing_stmt? BRACKET_RIGHT
 std::unique_ptr<ast::LoopStatement> ParserImpl::loop_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kLoop))
+  Source source;
+  if (!match(Token::Type::kLoop, &source))
     return nullptr;
 
   auto t = next();
@@ -2483,9 +2474,8 @@
 // for_statement
 //   : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT
 std::unique_ptr<ast::Statement> ParserImpl::for_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kFor))
+  Source source;
+  if (!match(Token::Type::kFor, &source))
     return nullptr;
 
   if (!expect("for loop", Token::Type::kParenLeft))
@@ -2591,9 +2581,8 @@
 // break_stmt
 //   : BREAK
 std::unique_ptr<ast::BreakStatement> ParserImpl::break_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kBreak))
+  Source source;
+  if (!match(Token::Type::kBreak, &source))
     return nullptr;
 
   return std::make_unique<ast::BreakStatement>(source);
@@ -2602,9 +2591,8 @@
 // continue_stmt
 //   : CONTINUE
 std::unique_ptr<ast::ContinueStatement> ParserImpl::continue_stmt() {
-  auto source = peek().source();
-
-  if (!match(Token::Type::kContinue))
+  Source source;
+  if (!match(Token::Type::kContinue, &source))
     return nullptr;
 
   return std::make_unique<ast::ContinueStatement>(source);
@@ -2760,10 +2748,8 @@
   } else if (t.IsPeriod()) {
     next();  // Consume the peek
 
-    source = peek().source();
-
     std::string ident;
-    if (!expect_ident("member accessor", &ident))
+    if (!expect_ident("member accessor", &ident, &source))
       return nullptr;
 
     expr = std::make_unique<ast::MemberAccessorExpression>(
@@ -3402,8 +3388,12 @@
                                                             std::move(lit));
 }
 
-bool ParserImpl::match(Token::Type tok) {
+bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
   auto t = peek();
+
+  if (source != nullptr)
+    *source = t.source();
+
   if (t.Is(tok)) {
     next();
     return true;
@@ -3464,12 +3454,19 @@
   return true;
 }
 
-bool ParserImpl::expect_ident(const std::string& use, std::string* out) {
+bool ParserImpl::expect_ident(const std::string& use,
+                              std::string* out,
+                              Source* source /* = nullptr */) {
   auto t = next();
+
+  if (source != nullptr)
+    *source = t.source();
+
   if (!t.IsIdentifier()) {
     add_error(t, "expected identifier", use);
     return false;
   }
+
   *out = t.to_str();
   return true;
 }
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 8156017..3cf023f 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -429,7 +429,9 @@
 
  private:
   /// @returns true and consumes the next token if it equals |tok|.
-  bool match(Token::Type tok);
+  /// @param source if not nullptr, the next token's source is written to this
+  /// pointer, regardless of success or error
+  bool match(Token::Type tok, Source* source = nullptr);
   /// Errors if the next token is not equal to |tok|.
   /// Always consumes the next token.
   /// @param use a description of what was being parsed if an error was raised.
@@ -461,8 +463,12 @@
   /// Always consumes the next token.
   /// @param use a description of what was being parsed if an error was raised
   /// @param out the pointer to write the parsed identifier to
+  /// @param source if not nullptr, the next token's source is written to this
+  /// pointer, regardless of success or error
   /// @returns true if the identifier was parsed without error
-  bool expect_ident(const std::string& use, std::string* out);
+  bool expect_ident(const std::string& use,
+                    std::string* out,
+                    Source* source = nullptr);
 
   ast::type::Type* type_decl_pointer(Token t);
   ast::type::Type* type_decl_vector(Token t);