Use the new diagnostics for wgsl the parser

Keep the `ParserImpl::error()` format identical to the old error style for now.
Use the explicit `ParserImpl::diagnostics()` method for the error message tests, updating the tests to match the new, improved output.

Bug: tint:282
Change-Id: Ia7e1237170f0f5203a8cfa256322df29e90e2791
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/31481
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 7951a53..174bada 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -132,27 +132,15 @@
 }
 
 void ParserImpl::set_error(const Token& t, const std::string& err) {
-  auto prefix = std::to_string(t.source().range.begin.line) + ":" +
-                std::to_string(t.source().range.begin.column) + ": ";
-
-  if (t.IsReservedKeyword()) {
-    error_ = prefix + "reserved token (" + t.to_str() + ") found";
-    return;
-  }
-  if (t.IsError()) {
-    error_ = prefix + t.to_str();
-    return;
-  }
-
-  if (err.size() != 0) {
-    error_ = prefix + err;
-  } else {
-    error_ = prefix + "invalid token (" + t.to_name() + ") encountered";
-  }
+  diag::Diagnostic diagnostic;
+  diagnostic.severity = diag::Severity::Error;
+  diagnostic.message = err;
+  diagnostic.source = t.source();
+  diags_.add(std::move(diagnostic));
 }
 
 void ParserImpl::set_error(const Token& t) {
-  set_error(t, "");
+  set_error(t, "invalid token (" + t.to_name() + ") encountered");
 }
 
 Token ParserImpl::next() {
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 82d04ab..882093a 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -45,6 +45,8 @@
 #include "src/ast/variable.h"
 #include "src/ast/variable_decoration.h"
 #include "src/context.h"
+#include "src/diagnostic/diagnostic.h"
+#include "src/diagnostic/formatter.h"
 #include "src/reader/wgsl/token.h"
 
 namespace tint {
@@ -99,9 +101,15 @@
   bool Parse();
 
   /// @returns true if an error was encountered.
-  bool has_error() const { return error_.size() > 0; }
+  bool has_error() const { return diags_.contains_errors(); }
+
   /// @returns the parser error string
-  const std::string& error() const { return error_; }
+  std::string error() const {
+    return diag::Formatter::create(false, false, false)->format(diags_);
+  }
+
+  /// @returns the diagnostic messages
+  const diag::List& diagnostics() const { return diags_; }
 
   /// @returns the module. The module in the parser will be reset after this.
   ast::Module module() { return std::move(module_); }
@@ -418,7 +426,7 @@
       uint32_t depth);
 
   Context& ctx_;
-  std::string error_;
+  diag::List diags_;
   std::unique_ptr<Lexer> lexer_;
   std::deque<Token> token_queue_;
   std::unordered_map<std::string, ast::type::Type*> registered_constructs_;
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index 075f656..e111fd2 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -21,761 +21,1167 @@
 namespace wgsl {
 namespace {
 
-class ParserImplErrorTest : public ParserImplTest {
- public:
-  void expect(const char* source, const char* expected) {
-    auto* p = parser(source);
-    EXPECT_EQ(p->Parse(), false);
-    EXPECT_EQ(p->has_error(), true);
-    EXPECT_EQ(p->error(), expected);
-  }
-};
+class ParserImplErrorTest : public ParserImplTest {};
+
+#define EXPECT(SOURCE, EXPECTED)                                              \
+  do {                                                                        \
+    std::string source = SOURCE;                                              \
+    std::string expected = EXPECTED;                                          \
+    auto* p = parser(source);                                                 \
+    EXPECT_EQ(false, p->Parse());                                             \
+    EXPECT_EQ(true, p->diagnostics().contains_errors());                      \
+    EXPECT_EQ(                                                                \
+        expected,                                                             \
+        diag::Formatter::create(true, true, true)->format(p->diagnostics())); \
+  } while (false)
 
 TEST_F(ParserImplErrorTest, AdditiveInvalidExpr) {
-  expect("fn f() -> void { return 1.0 + <; }",
-         "1:31: unable to parse right side of + expression");
+  EXPECT("fn f() -> void { return 1.0 + <; }",
+         "test.wgsl:1:31 error: unable to parse right side of + expression\n"
+         "fn f() -> void { return 1.0 + <; }\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, AndInvalidExpr) {
-  expect("fn f() -> void { return 1 & >; }",
-         "1:29: unable to parse right side of & expression");
+  EXPECT("fn f() -> void { return 1 & >; }",
+         "test.wgsl:1:29 error: unable to parse right side of & expression\n"
+         "fn f() -> void { return 1 & >; }\n"
+         "                            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ArrayIndexExprInvalidExpr) {
-  expect("fn f() -> void { x = y[^]; }",
-         "1:24: unable to parse expression inside []");
+  EXPECT("fn f() -> void { x = y[^]; }",
+         "test.wgsl:1:24 error: unable to parse expression inside []\n"
+         "fn f() -> void { x = y[^]; }\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ArrayIndexExprMissingRBracket) {
-  expect("fn f() -> void { x = y[1; }", "1:25: missing ] for array accessor");
+  EXPECT("fn f() -> void { x = y[1; }",
+         "test.wgsl:1:25 error: missing ] for array accessor\n"
+         "fn f() -> void { x = y[1; }\n"
+         "                        ^\n");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment) {
-  expect("fn f() -> void { a; }", "1:19: missing = for assignment");
+  EXPECT("fn f() -> void { a; }",
+         "test.wgsl:1:19 error: missing = for assignment\n"
+         "fn f() -> void { a; }\n"
+         "                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) {
-  expect("fn f() -> void { a : i32; }", "1:20: missing = for assignment");
+  EXPECT("fn f() -> void { a : i32; }",
+         "test.wgsl:1:20 error: missing = for assignment\n"
+         "fn f() -> void { a : i32; }\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingSemicolon) {
-  expect("fn f() -> void { a = 1 }", "1:24: missing ;");
+  EXPECT("fn f() -> void { a = 1 }",
+         "test.wgsl:1:24 error: missing ;\n"
+         "fn f() -> void { a = 1 }\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtInvalidRHS) {
-  expect("fn f() -> void { a = >; }",
-         "1:22: unable to parse right side of assignment");
+  EXPECT("fn f() -> void { a = >; }",
+         "test.wgsl:1:22 error: unable to parse right side of assignment\n"
+         "fn f() -> void { a = >; }\n"
+         "                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingLessThan) {
-  expect("fn f() -> void { x = bitcast(y); }",
-         "1:29: missing < for bitcast expression");
+  EXPECT("fn f() -> void { x = bitcast(y); }",
+         "test.wgsl:1:29 error: missing < for bitcast expression\n"
+         "fn f() -> void { x = bitcast(y); }\n"
+         "                            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingGreaterThan) {
-  expect("fn f() -> void { x = bitcast<u32(y); }",
-         "1:33: missing > for bitcast expression");
+  EXPECT("fn f() -> void { x = bitcast<u32(y); }",
+         "test.wgsl:1:33 error: missing > for bitcast expression\n"
+         "fn f() -> void { x = bitcast<u32(y); }\n"
+         "                                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingType) {
-  expect("fn f() -> void { x = bitcast<>(y); }",
-         "1:30: missing type for bitcast expression");
+  EXPECT("fn f() -> void { x = bitcast<>(y); }",
+         "test.wgsl:1:30 error: missing type for bitcast expression\n"
+         "fn f() -> void { x = bitcast<>(y); }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, BreakStmtMissingSemicolon) {
-  expect("fn f() -> void { loop { break } }", "1:31: missing ;");
+  EXPECT("fn f() -> void { loop { break } }",
+         "test.wgsl:1:31 error: missing ;\n"
+         "fn f() -> void { loop { break } }\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, CallExprMissingRParen) {
-  expect("fn f() -> void { x = f(1.; }", "1:26: missing ) for call expression");
+  EXPECT("fn f() -> void { x = f(1.; }",
+         "test.wgsl:1:26 error: missing ) for call expression\n"
+         "fn f() -> void { x = f(1.; }\n"
+         "                         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtMissingRParen) {
-  expect("fn f() -> void { f(1.; }", "1:22: missing ) for call statement");
+  EXPECT("fn f() -> void { f(1.; }",
+         "test.wgsl:1:22 error: missing ) for call statement\n"
+         "fn f() -> void { f(1.; }\n"
+         "                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtInvalidArgument0) {
-  expect("fn f() -> void { f(<); }",
-         "1:20: unable to parse argument expression");
+  EXPECT("fn f() -> void { f(<); }",
+         "test.wgsl:1:20 error: unable to parse argument expression\n"
+         "fn f() -> void { f(<); }\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtInvalidArgument1) {
-  expect("fn f() -> void { f(1.0, <); }",
-         "1:25: unable to parse argument expression after comma");
+  EXPECT(
+      "fn f() -> void { f(1.0, <); }",
+      "test.wgsl:1:25 error: unable to parse argument expression after comma\n"
+      "fn f() -> void { f(1.0, <); }\n"
+      "                        ^\n");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtMissingSemicolon) {
-  expect("fn f() -> void { f() }", "1:22: missing ;");
+  EXPECT("fn f() -> void { f() }",
+         "test.wgsl:1:22 error: missing ;\n"
+         "fn f() -> void { f() }\n"
+         "                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstructorExprMissingLParen) {
-  expect("fn f() -> void { x = vec2<u32>1,2); }",
-         "1:31: missing ( for type constructor");
+  EXPECT("fn f() -> void { x = vec2<u32>1,2); }",
+         "test.wgsl:1:31 error: missing ( for type constructor\n"
+         "fn f() -> void { x = vec2<u32>1,2); }\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstructorExprMissingRParen) {
-  expect("fn f() -> void { x = vec2<u32>(1,2; }",
-         "1:35: missing ) for type constructor");
+  EXPECT("fn f() -> void { x = vec2<u32>(1,2; }",
+         "test.wgsl:1:35 error: missing ) for type constructor\n"
+         "fn f() -> void { x = vec2<u32>(1,2; }\n"
+         "                                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) {
-  expect("fn f() -> void { const >; }",
-         "1:24: unable to parse variable declaration");
+  EXPECT("fn f() -> void { const >; }",
+         "test.wgsl:1:24 error: unable to parse variable declaration\n"
+         "fn f() -> void { const >; }\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) {
-  expect("fn f() -> void { const a : i32; }",
-         "1:31: missing = for constant declaration");
+  EXPECT("fn f() -> void { const a : i32; }",
+         "test.wgsl:1:31 error: missing = for constant declaration\n"
+         "fn f() -> void { const a : i32; }\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingConstructor) {
-  expect("fn f() -> void { const a : i32 = >; }",
-         "1:34: missing constructor for const declaration");
+  EXPECT("fn f() -> void { const a : i32 = >; }",
+         "test.wgsl:1:34 error: missing constructor for const declaration\n"
+         "fn f() -> void { const a : i32 = >; }\n"
+         "                                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ContinueStmtMissingSemicolon) {
-  expect("fn f() -> void { loop { continue } }", "1:34: missing ;");
+  EXPECT("fn f() -> void { loop { continue } }",
+         "test.wgsl:1:34 error: missing ;\n"
+         "fn f() -> void { loop { continue } }\n"
+         "                                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, DiscardStmtMissingSemicolon) {
-  expect("fn f() -> void { discard }", "1:26: missing ;");
+  EXPECT("fn f() -> void { discard }",
+         "test.wgsl:1:26 error: missing ;\n"
+         "fn f() -> void { discard }\n"
+         "                         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, EqualityInvalidExpr) {
-  expect("fn f() -> void { return 1 == >; }",
-         "1:30: unable to parse right side of == expression");
+  EXPECT("fn f() -> void { return 1 == >; }",
+         "test.wgsl:1:30 error: unable to parse right side of == expression\n"
+         "fn f() -> void { return 1 == >; }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopInitializerMissingSemicolon) {
-  expect("fn f() -> void { for (var i : i32 = 0 i < 8; i=i+1) {} }",
-         "1:39: missing ';' after initializer in for loop");
+  EXPECT("fn f() -> void { for (var i : i32 = 0 i < 8; i=i+1) {} }",
+         "test.wgsl:1:39 error: missing ';' after initializer in for loop\n"
+         "fn f() -> void { for (var i : i32 = 0 i < 8; i=i+1) {} }\n"
+         "                                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopConditionMissingSemicolon) {
-  expect("fn f() -> void { for (var i : i32 = 0; i < 8 i=i+1) {} }",
-         "1:46: missing ';' after condition in for loop");
+  EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8 i=i+1) {} }",
+         "test.wgsl:1:46 error: missing ';' after condition in for loop\n"
+         "fn f() -> void { for (var i : i32 = 0; i < 8 i=i+1) {} }\n"
+         "                                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingLParen) {
-  expect("fn f() -> void { for var i : i32 = 0; i < 8; i=i+1) {} }",
-         "1:22: missing for loop (");
+  EXPECT("fn f() -> void { for var i : i32 = 0; i < 8; i=i+1) {} }",
+         "test.wgsl:1:22 error: missing for loop (\n"
+         "fn f() -> void { for var i : i32 = 0; i < 8; i=i+1) {} }\n"
+         "                     ^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingRParen) {
-  expect("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1 {} }",
-         "1:53: missing for loop )");
+  EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1 {} }",
+         "test.wgsl:1:53 error: missing for loop )\n"
+         "fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1 {} }\n"
+         "                                                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingLBrace) {
-  expect("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }",
-         "1:54: missing for loop {");
+  EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }",
+         "test.wgsl:1:54 error: missing for loop {\n"
+         "fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) } }\n"
+         "                                                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingRBrace) {
-  expect("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {",
-         "1:55: missing for loop }");
+  EXPECT("fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {",
+         "test.wgsl:1:55 error: missing for loop }\n"
+         "fn f() -> void { for (var i : i32 = 0; i < 8; i=i+1) {\n"
+         "                                                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclInvalid) {
-  expect("[[stage(vertex)]] x;", "1:19: error parsing function declaration");
+  EXPECT("[[stage(vertex)]] x;",
+         "test.wgsl:1:19 error: error parsing function declaration\n"
+         "[[stage(vertex)]] x;\n"
+         "                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoMissingEnd) {
-  expect("[[stage(vertex) fn f() -> void {}",
-         "1:17: missing ]] for function decorations");
+  EXPECT("[[stage(vertex) fn f() -> void {}",
+         "test.wgsl:1:17 error: missing ]] for function decorations\n"
+         "[[stage(vertex) fn f() -> void {}\n"
+         "                ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoStageMissingLParen) {
-  expect("[[stage vertex]] fn f() -> void {}",
-         "1:9: missing ( for stage decoration");
+  EXPECT("[[stage vertex]] fn f() -> void {}",
+         "test.wgsl:1:9 error: missing ( for stage decoration\n"
+         "[[stage vertex]] fn f() -> void {}\n"
+         "        ^^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoStageMissingRParen) {
-  expect("[[stage(vertex]] fn f() -> void {}",
-         "1:15: missing ) for stage decoration");
+  EXPECT("[[stage(vertex]] fn f() -> void {}",
+         "test.wgsl:1:15 error: missing ) for stage decoration\n"
+         "[[stage(vertex]] fn f() -> void {}\n"
+         "              ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoStageInvalid) {
-  expect("[[stage(x)]] fn f() -> void {}",
-         "1:9: invalid value for stage decoration");
+  EXPECT("[[stage(x)]] fn f() -> void {}",
+         "test.wgsl:1:9 error: invalid value for stage decoration\n"
+         "[[stage(x)]] fn f() -> void {}\n"
+         "        ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeMissingLParen) {
-  expect("[[workgroup_size 1]] fn f() -> void {}",
-         "1:18: missing ( for workgroup_size");
+  EXPECT("[[workgroup_size 1]] fn f() -> void {}",
+         "test.wgsl:1:18 error: missing ( for workgroup_size\n"
+         "[[workgroup_size 1]] fn f() -> void {}\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeMissingRParen) {
-  expect("[[workgroup_size(1]] fn f() -> void {}",
-         "1:19: missing ) for workgroup_size");
+  EXPECT("[[workgroup_size(1]] fn f() -> void {}",
+         "test.wgsl:1:19 error: missing ) for workgroup_size\n"
+         "[[workgroup_size(1]] fn f() -> void {}\n"
+         "                  ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeXInvalid) {
-  expect("[[workgroup_size(x)]] fn f() -> void {}",
-         "1:18: missing x value for workgroup_size");
+  EXPECT("[[workgroup_size(x)]] fn f() -> void {}",
+         "test.wgsl:1:18 error: missing x value for workgroup_size\n"
+         "[[workgroup_size(x)]] fn f() -> void {}\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeXNegative) {
-  expect("[[workgroup_size(-1)]] fn f() -> void {}",
-         "1:18: invalid value for workgroup_size x parameter");
+  EXPECT("[[workgroup_size(-1)]] fn f() -> void {}",
+         "test.wgsl:1:18 error: invalid value for workgroup_size x parameter\n"
+         "[[workgroup_size(-1)]] fn f() -> void {}\n"
+         "                 ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeYInvalid) {
-  expect("[[workgroup_size(1, x)]] fn f() -> void {}",
-         "1:21: missing y value for workgroup_size");
+  EXPECT("[[workgroup_size(1, x)]] fn f() -> void {}",
+         "test.wgsl:1:21 error: missing y value for workgroup_size\n"
+         "[[workgroup_size(1, x)]] fn f() -> void {}\n"
+         "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeYNegative) {
-  expect("[[workgroup_size(1, -1)]] fn f() -> void {}",
-         "1:21: invalid value for workgroup_size y parameter");
+  EXPECT("[[workgroup_size(1, -1)]] fn f() -> void {}",
+         "test.wgsl:1:21 error: invalid value for workgroup_size y parameter\n"
+         "[[workgroup_size(1, -1)]] fn f() -> void {}\n"
+         "                    ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeZInvalid) {
-  expect("[[workgroup_size(1, 2, x)]] fn f() -> void {}",
-         "1:24: missing z value for workgroup_size");
+  EXPECT("[[workgroup_size(1, 2, x)]] fn f() -> void {}",
+         "test.wgsl:1:24 error: missing z value for workgroup_size\n"
+         "[[workgroup_size(1, 2, x)]] fn f() -> void {}\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclDecoWorkgroupSizeZNegative) {
-  expect("[[workgroup_size(1, 2, -1)]] fn f() -> void {}",
-         "1:24: invalid value for workgroup_size z parameter");
+  EXPECT("[[workgroup_size(1, 2, -1)]] fn f() -> void {}",
+         "test.wgsl:1:24 error: invalid value for workgroup_size z parameter\n"
+         "[[workgroup_size(1, 2, -1)]] fn f() -> void {}\n"
+         "                       ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingIdentifier) {
-  expect("fn () -> void {}", "1:4: missing identifier for function");
+  EXPECT("fn () -> void {}",
+         "test.wgsl:1:4 error: missing identifier for function\n"
+         "fn () -> void {}\n"
+         "   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingLParen) {
-  expect("fn f) -> void {}", "1:5: missing ( for function declaration");
+  EXPECT("fn f) -> void {}",
+         "test.wgsl:1:5 error: missing ( for function declaration\n"
+         "fn f) -> void {}\n"
+         "    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingRParen) {
-  expect("fn f( -> void {}", "1:7: missing ) for function declaration");
+  EXPECT("fn f( -> void {}",
+         "test.wgsl:1:7 error: missing ) for function declaration\n"
+         "fn f( -> void {}\n"
+         "      ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) {
-  expect("fn f() void {}", "1:8: missing -> for function declaration");
+  EXPECT("fn f() void {}",
+         "test.wgsl:1:8 error: missing -> for function declaration\n"
+         "fn f() void {}\n"
+         "       ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclInvalidReturnType) {
-  expect("fn f() -> 1 {}", "1:11: unable to determine function return type");
+  EXPECT("fn f() -> 1 {}",
+         "test.wgsl:1:11 error: unable to determine function return type\n"
+         "fn f() -> 1 {}\n"
+         "          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamMissingColon) {
-  expect("fn f(x) -> void {}", "1:7: missing : for identifier declaration");
+  EXPECT("fn f(x) -> void {}",
+         "test.wgsl:1:7 error: missing : for identifier declaration\n"
+         "fn f(x) -> void {}\n"
+         "      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamInvalidType) {
-  expect("fn f(x : 1) -> void {}",
-         "1:10: invalid type for identifier declaration");
+  EXPECT("fn f(x : 1) -> void {}",
+         "test.wgsl:1:10 error: invalid type for identifier declaration\n"
+         "fn f(x : 1) -> void {}\n"
+         "         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
-  expect("fn f(x : i32, ) -> void {}",
-         "1:13: found , but no variable declaration");
+  EXPECT("fn f(x : i32, ) -> void {}",
+         "test.wgsl:1:13 error: found , but no variable declaration\n"
+         "fn f(x : i32, ) -> void {}\n"
+         "            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
-  expect("fn f() -> void }", "1:16: missing {");
+  EXPECT("fn f() -> void }",
+         "test.wgsl:1:16 error: missing {\n"
+         "fn f() -> void }\n"
+         "               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
-  expect("fn f() -> void {", "1:17: missing }");
+  EXPECT("fn f() -> void {",
+         "test.wgsl:1:17 error: missing }\n"
+         "fn f() -> void {\n"
+         "                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
-  expect("const ^ : i32 = 1;",
-         "1:7: error parsing constant variable identifier");
+  EXPECT("const ^ : i32 = 1;",
+         "test.wgsl:1:7 error: error parsing constant variable identifier\n"
+         "const ^ : i32 = 1;\n"
+         "      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
-  expect("const i : i32 = 1", "1:18: missing ';' for constant declaration");
+  EXPECT("const i : i32 = 1",
+         "test.wgsl:1:18 error: missing ';' for constant declaration\n"
+         "const i : i32 = 1\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
-  expect("const i : vec2<i32> = vec2<i32>;",
-         "1:32: missing ( for type constructor");
+  EXPECT("const i : vec2<i32> = vec2<i32>;",
+         "test.wgsl:1:32 error: missing ( for type constructor\n"
+         "const i : vec2<i32> = vec2<i32>;\n"
+         "                               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
-  expect("const i : vec2<i32> = vec2<i32>(1., 2.;",
-         "1:39: missing ) for type constructor");
+  EXPECT("const i : vec2<i32> = vec2<i32>(1., 2.;",
+         "test.wgsl:1:39 error: missing ) for type constructor\n"
+         "const i : vec2<i32> = vec2<i32>(1., 2.;\n"
+         "                                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingAssignment) {
-  expect("const i : vec2<i32>;", "1:20: missing = for const declaration");
+  EXPECT("const i : vec2<i32>;",
+         "test.wgsl:1:20 error: missing = for const declaration\n"
+         "const i : vec2<i32>;\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
-  expect("const i : vec2<i32> = vec2<i32>(!);",
-         "1:33: unable to parse const literal");
+  EXPECT("const i : vec2<i32> = vec2<i32>(!);",
+         "test.wgsl:1:33 error: unable to parse const literal\n"
+         "const i : vec2<i32> = vec2<i32>(!);\n"
+         "                                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
-  std::stringstream out;
-  out << "const i : i32 = ";
-  for (size_t i = 0; i < 200; i++) {
-    out << "f32(";
+  uint32_t kMaxConstExprDepth = 128;
+
+  std::stringstream src;
+  std::stringstream mkr;
+  src << "const i : i32 = ";
+  mkr << "                ";
+  for (size_t i = 0; i < kMaxConstExprDepth + 8; i++) {
+    src << "f32(";
+    if (i < kMaxConstExprDepth + 1) {
+      mkr << "    ";
+    } else if (i == kMaxConstExprDepth + 1) {
+      mkr << "^^^";
+    }
   }
-  out << "1.0";
+  src << "1.0";
   for (size_t i = 0; i < 200; i++) {
-    out << ")";
+    src << ")";
   }
-  out << ";";
-  expect(out.str().c_str(), "1:533: max const_expr depth reached");
+  src << ";";
+  std::stringstream err;
+  err << "test.wgsl:1:533 error: max const_expr depth reached\n"
+      << src.str() << "\n"
+      << mkr.str() << "\n";
+  EXPECT(src.str().c_str(), err.str().c_str());
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
-  expect("const i : vec2<i32> = vec2<i32> 1, 2);",
-         "1:33: missing ( for type constructor");
+  EXPECT("const i : vec2<i32> = vec2<i32> 1, 2);",
+         "test.wgsl:1:33 error: missing ( for type constructor\n"
+         "const i : vec2<i32> = vec2<i32> 1, 2);\n"
+         "                                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
-  expect("const i : vec2<i32> = vec2<i32>(1, 2;",
-         "1:37: missing ) for type constructor");
+  EXPECT("const i : vec2<i32> = vec2<i32>(1, 2;",
+         "test.wgsl:1:37 error: missing ) for type constructor\n"
+         "const i : vec2<i32> = vec2<i32>(1, 2;\n"
+         "                                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingLessThan) {
-  expect("var x : texture_sampled_1d;",
-         "1:28: missing '<' for sampled texture type");
+  EXPECT("var x : texture_sampled_1d;",
+         "test.wgsl:1:28 error: missing '<' for sampled texture type\n"
+         "var x : texture_sampled_1d;\n"
+         "                           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingGreaterThan) {
-  expect("var x : texture_sampled_1d<f32;",
-         "1:32: missing '>' for sampled texture type");
+  EXPECT("var x : texture_sampled_1d<f32;",
+         "test.wgsl:1:32 error: missing '>' for sampled texture type\n"
+         "var x : texture_sampled_1d<f32;\n"
+         "                               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureInvalidSubtype) {
-  expect("var x : texture_sampled_1d<1>;",
-         "1:28: invalid subtype for sampled texture type");
+  EXPECT("var x : texture_sampled_1d<1>;",
+         "test.wgsl:1:28 error: invalid subtype for sampled texture type\n"
+         "var x : texture_sampled_1d<1>;\n"
+         "                           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingLessThan) {
-  expect("var x : texture_multisampled_2d;",
-         "1:33: missing '<' for multisampled texture type");
+  EXPECT("var x : texture_multisampled_2d;",
+         "test.wgsl:1:33 error: missing '<' for multisampled texture type\n"
+         "var x : texture_multisampled_2d;\n"
+         "                                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingGreaterThan) {
-  expect("var x : texture_multisampled_2d<f32;",
-         "1:37: missing '>' for multisampled texture type");
+  EXPECT("var x : texture_multisampled_2d<f32;",
+         "test.wgsl:1:37 error: missing '>' for multisampled texture type\n"
+         "var x : texture_multisampled_2d<f32;\n"
+         "                                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureInvalidSubtype) {
-  expect("var x : texture_multisampled_2d<1>;",
-         "1:33: invalid subtype for multisampled texture type");
+  EXPECT("var x : texture_multisampled_2d<1>;",
+         "test.wgsl:1:33 error: invalid subtype for multisampled texture type\n"
+         "var x : texture_multisampled_2d<1>;\n"
+         "                                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingLessThan) {
-  expect("var x : texture_ro_2d;",
-         "1:23: missing '<' for storage texture type");
+  EXPECT("var x : texture_ro_2d;",
+         "test.wgsl:1:23 error: missing '<' for storage texture type\n"
+         "var x : texture_ro_2d;\n"
+         "                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingGreaterThan) {
-  expect("var x : texture_ro_2d<r8uint;",
-         "1:30: missing '>' for storage texture type");
+  EXPECT("var x : texture_ro_2d<r8uint;",
+         "test.wgsl:1:30 error: missing '>' for storage texture type\n"
+         "var x : texture_ro_2d<r8uint;\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingInvalidSubtype) {
-  expect("var x : texture_ro_2d<1>;",
-         "1:23: invalid format for storage texture type");
+  EXPECT("var x : texture_ro_2d<1>;",
+         "test.wgsl:1:23 error: invalid format for storage texture type\n"
+         "var x : texture_ro_2d<1>;\n"
+         "                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDecoMissingStruct) {
-  expect("[[block]];", "1:10: missing struct declaration");
+  EXPECT("[[block]];",
+         "test.wgsl:1:10 error: missing struct declaration\n"
+         "[[block]];\n"
+         "         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDecoMissingEnd) {
-  expect("[[block struct {};", "1:9: missing ]] for struct decoration");
+  EXPECT("[[block struct {};",
+         "test.wgsl:1:9 error: missing ]] for struct decoration\n"
+         "[[block struct {};\n"
+         "        ^^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingIdentifier) {
-  expect("struct {};", "1:8: missing identifier for struct declaration");
+  EXPECT("struct {};",
+         "test.wgsl:1:8 error: missing identifier for struct declaration\n"
+         "struct {};\n"
+         "       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingSemicolon) {
-  expect("struct S {}", "1:12: missing ';' for struct declaration");
+  EXPECT("struct S {}",
+         "test.wgsl:1:12 error: missing ';' for struct declaration\n"
+         "struct S {}\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingLBrace) {
-  expect("struct S };", "1:10: missing { for struct declaration");
+  EXPECT("struct S };",
+         "test.wgsl:1:10 error: missing { for struct declaration\n"
+         "struct S };\n"
+         "         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingRBrace) {
-  expect("struct S { i : i32;", "1:20: missing } for struct declaration");
+  EXPECT("struct S { i : i32;",
+         "test.wgsl:1:20 error: missing } for struct declaration\n"
+         "struct S { i : i32;\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberDecoEmpty) {
-  expect("struct S { [[]] i : i32; };",
-         "1:14: empty struct member decoration found");
+  EXPECT("struct S { [[]] i : i32; };",
+         "test.wgsl:1:14 error: empty struct member decoration found\n"
+         "struct S { [[]] i : i32; };\n"
+         "             ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberDecoMissingEnd) {
-  expect("struct S { [[ i : i32; };",
-         "1:15: missing ]] for struct member decoration");
+  EXPECT("struct S { [[ i : i32; };",
+         "test.wgsl:1:15 error: missing ]] for struct member decoration\n"
+         "struct S { [[ i : i32; };\n"
+         "              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberInvalidIdentifier) {
-  expect("struct S { 1 : i32; };", "1:12: invalid identifier declaration");
+  EXPECT("struct S { 1 : i32; };",
+         "test.wgsl:1:12 error: invalid identifier declaration\n"
+         "struct S { 1 : i32; };\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberMissingSemicolon) {
-  expect("struct S { i : i32 };", "1:20: missing ; for struct member");
+  EXPECT("struct S { i : i32 };",
+         "test.wgsl:1:20 error: missing ; for struct member\n"
+         "struct S { i : i32 };\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetMissingLParen) {
-  expect("struct S { [[offset 1)]] i : i32 };", "1:21: missing ( for offset");
+  EXPECT("struct S { [[offset 1)]] i : i32 };",
+         "test.wgsl:1:21 error: missing ( for offset\n"
+         "struct S { [[offset 1)]] i : i32 };\n"
+         "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetMissingRParen) {
-  expect("struct S { [[offset(1]] i : i32 };", "1:22: missing ) for offset");
+  EXPECT("struct S { [[offset(1]] i : i32 };",
+         "test.wgsl:1:22 error: missing ) for offset\n"
+         "struct S { [[offset(1]] i : i32 };\n"
+         "                     ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetInvaldValue) {
-  expect("struct S { [[offset(x)]] i : i32 };",
-         "1:21: invalid value for offset decoration");
+  EXPECT("struct S { [[offset(x)]] i : i32 };",
+         "test.wgsl:1:21 error: invalid value for offset decoration\n"
+         "struct S { [[offset(x)]] i : i32 };\n"
+         "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberOffsetNegativeValue) {
-  expect("struct S { [[offset(-2)]] i : i32 };",
-         "1:21: offset value must be >= 0");
+  EXPECT("struct S { [[offset(-2)]] i : i32 };",
+         "test.wgsl:1:21 error: offset value must be >= 0\n"
+         "struct S { [[offset(-2)]] i : i32 };\n"
+         "                    ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingIdentifier) {
-  expect("type 1 = f32;", "1:6: missing identifier for type alias");
+  EXPECT("type 1 = f32;",
+         "test.wgsl:1:6 error: missing identifier for type alias\n"
+         "type 1 = f32;\n"
+         "     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasInvalidType) {
-  expect("type meow = 1;", "1:13: invalid type alias");
+  EXPECT("type meow = 1;",
+         "test.wgsl:1:13 error: invalid type alias\n"
+         "type meow = 1;\n"
+         "            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingAssignment) {
-  expect("type meow f32", "1:11: missing = for type alias");
+  EXPECT("type meow f32",
+         "test.wgsl:1:11 error: missing = for type alias\n"
+         "type meow f32\n"
+         "          ^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingSemicolon) {
-  expect("type meow = f32", "1:16: missing ';' for type alias");
+  EXPECT("type meow = f32",
+         "test.wgsl:1:16 error: missing ';' for type alias\n"
+         "type meow = f32\n"
+         "               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeInvalid) {
-  expect("var x : fish;", "1:9: unknown constructed type 'fish'");
+  EXPECT("var x : fish;",
+         "test.wgsl:1:9 error: unknown constructed type 'fish'\n"
+         "var x : fish;\n"
+         "        ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeDecoInvalid) {
-  expect("var x : [[]] i32;", "1:9: invalid type for identifier declaration");
+  EXPECT("var x : [[]] i32;",
+         "test.wgsl:1:9 error: invalid type for identifier declaration\n"
+         "var x : [[]] i32;\n"
+         "        ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingLessThan) {
-  expect("var i : array;", "1:14: missing < for array declaration");
+  EXPECT("var i : array;",
+         "test.wgsl:1:14 error: missing < for array declaration\n"
+         "var i : array;\n"
+         "             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
-  expect("var i : array<u32, 3;", "1:21: missing > for array declaration");
+  EXPECT("var i : array<u32, 3;",
+         "test.wgsl:1:21 error: missing > for array declaration\n"
+         "var i : array<u32, 3;\n"
+         "                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoNotArray) {
-  expect("var i : [[stride(1)]] i32;",
-         "1:23: found array decoration but no array");
+  EXPECT("var i : [[stride(1)]] i32;",
+         "test.wgsl:1:23 error: found array decoration but no array\n"
+         "var i : [[stride(1)]] i32;\n"
+         "                      ^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoMissingEnd) {
-  expect("var i : [[stride(1) array<i32>;",
-         "1:21: missing ]] for array decoration");
+  EXPECT("var i : [[stride(1) array<i32>;",
+         "test.wgsl:1:21 error: missing ]] for array decoration\n"
+         "var i : [[stride(1) array<i32>;\n"
+         "                    ^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideMissingLParen) {
-  expect("var i : [[stride 1)]] array<i32>;",
-         "1:18: missing ( for stride attribute");
+  EXPECT("var i : [[stride 1)]] array<i32>;",
+         "test.wgsl:1:18 error: missing ( for stride attribute\n"
+         "var i : [[stride 1)]] array<i32>;\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideMissingRParen) {
-  expect("var i : [[stride(1]] array<i32>;",
-         "1:19: missing ) for stride attribute");
+  EXPECT("var i : [[stride(1]] array<i32>;",
+         "test.wgsl:1:19 error: missing ) for stride attribute\n"
+         "var i : [[stride(1]] array<i32>;\n"
+         "                  ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideInvalid) {
-  expect("var i : [[stride(x)]] array<i32>;",
-         "1:18: missing value for stride decoration");
+  EXPECT("var i : [[stride(x)]] array<i32>;",
+         "test.wgsl:1:18 error: missing value for stride decoration\n"
+         "var i : [[stride(x)]] array<i32>;\n"
+         "                 ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayDecoStrideNegative) {
-  expect("var i : [[stride(-1)]] array<i32>;",
-         "1:18: invalid stride value: -1");
+  EXPECT("var i : [[stride(-1)]] array<i32>;",
+         "test.wgsl:1:18 error: invalid stride value: -1\n"
+         "var i : [[stride(-1)]] array<i32>;\n"
+         "                 ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
-  expect("var i : array<1, 3>;", "1:15: invalid type for array declaration");
+  EXPECT("var i : array<1, 3>;",
+         "test.wgsl:1:15 error: invalid type for array declaration\n"
+         "var i : array<1, 3>;\n"
+         "              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
-  expect("var i : array<u32, x>;", "1:20: missing size of array declaration");
+  EXPECT("var i : array<u32, x>;",
+         "test.wgsl:1:20 error: missing size of array declaration\n"
+         "var i : array<u32, x>;\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayNegativeSize) {
-  expect("var i : array<u32, -3>;", "1:20: invalid size for array declaration");
+  EXPECT("var i : array<u32, -3>;",
+         "test.wgsl:1:20 error: invalid size for array declaration\n"
+         "var i : array<u32, -3>;\n"
+         "                   ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListEmpty) {
-  expect("[[]] var i : i32;", "1:3: empty variable decoration list");
+  EXPECT("[[]] var i : i32;",
+         "test.wgsl:1:3 error: empty variable decoration list\n"
+         "[[]] var i : i32;\n"
+         "  ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListInvalid) {
-  expect("[[location(1), meow]] var i : i32;",
-         "1:16: missing variable decoration after comma");
+  EXPECT("[[location(1), meow]] var i : i32;",
+         "test.wgsl:1:16 error: missing variable decoration after comma\n"
+         "[[location(1), meow]] var i : i32;\n"
+         "               ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListMissingComma) {
-  expect("[[location(1) set(2)]] var i : i32;",
-         "1:15: missing comma in variable decoration list");
+  EXPECT("[[location(1) set(2)]] var i : i32;",
+         "test.wgsl:1:15 error: missing comma in variable decoration list\n"
+         "[[location(1) set(2)]] var i : i32;\n"
+         "              ^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoListMissingEnd) {
-  expect("[[location(1) meow]] var i : i32;",
-         "1:15: missing ]] for variable decoration");
+  EXPECT("[[location(1) meow]] var i : i32;",
+         "test.wgsl:1:15 error: missing ]] for variable decoration\n"
+         "[[location(1) meow]] var i : i32;\n"
+         "              ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoLocationMissingLParen) {
-  expect("[[location 1]] var i : i32;",
-         "1:12: missing ( for location decoration");
+  EXPECT("[[location 1]] var i : i32;",
+         "test.wgsl:1:12 error: missing ( for location decoration\n"
+         "[[location 1]] var i : i32;\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoLocationMissingRParen) {
-  expect("[[location (1]] var i : i32;",
-         "1:14: missing ) for location decoration");
+  EXPECT("[[location (1]] var i : i32;",
+         "test.wgsl:1:14 error: missing ) for location decoration\n"
+         "[[location (1]] var i : i32;\n"
+         "             ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoLocationInvalidValue) {
-  expect("[[location(x)]] var i : i32;",
-         "1:12: invalid value for location decoration");
+  EXPECT("[[location(x)]] var i : i32;",
+         "test.wgsl:1:12 error: invalid value for location decoration\n"
+         "[[location(x)]] var i : i32;\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBuiltinMissingLParen) {
-  expect("[[builtin position]] var i : i32;",
-         "1:11: missing ( for builtin decoration");
+  EXPECT("[[builtin position]] var i : i32;",
+         "test.wgsl:1:11 error: missing ( for builtin decoration\n"
+         "[[builtin position]] var i : i32;\n"
+         "          ^^^^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBuiltinMissingRParen) {
-  expect("[[builtin(position]] var i : i32;",
-         "1:19: missing ) for builtin decoration");
+  EXPECT("[[builtin(position]] var i : i32;",
+         "test.wgsl:1:19 error: missing ) for builtin decoration\n"
+         "[[builtin(position]] var i : i32;\n"
+         "                  ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBuiltinInvalidIdentifer) {
-  expect("[[builtin(1)]] var i : i32;",
-         "1:11: expected identifier for builtin");
+  EXPECT("[[builtin(1)]] var i : i32;",
+         "test.wgsl:1:11 error: expected identifier for builtin\n"
+         "[[builtin(1)]] var i : i32;\n"
+         "          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBuiltinInvalidValue) {
-  expect("[[builtin(x)]] var i : i32;",
-         "1:11: invalid value for builtin decoration");
+  EXPECT("[[builtin(x)]] var i : i32;",
+         "test.wgsl:1:11 error: invalid value for builtin decoration\n"
+         "[[builtin(x)]] var i : i32;\n"
+         "          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingMissingLParen) {
-  expect("[[binding 1]] var i : i32;",
-         "1:11: missing ( for binding decoration");
+  EXPECT("[[binding 1]] var i : i32;",
+         "test.wgsl:1:11 error: missing ( for binding decoration\n"
+         "[[binding 1]] var i : i32;\n"
+         "          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingMissingRParen) {
-  expect("[[binding(1]] var i : i32;",
-         "1:12: missing ) for binding decoration");
+  EXPECT("[[binding(1]] var i : i32;",
+         "test.wgsl:1:12 error: missing ) for binding decoration\n"
+         "[[binding(1]] var i : i32;\n"
+         "           ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingInvalidValue) {
-  expect("[[binding(x)]] var i : i32;",
-         "1:11: invalid value for binding decoration");
+  EXPECT("[[binding(x)]] var i : i32;",
+         "test.wgsl:1:11 error: invalid value for binding decoration\n"
+         "[[binding(x)]] var i : i32;\n"
+         "          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoSetMissingLParen) {
-  expect("[[set 1]] var i : i32;", "1:7: missing ( for set decoration");
+  EXPECT("[[set 1]] var i : i32;",
+         "test.wgsl:1:7 error: missing ( for set decoration\n"
+         "[[set 1]] var i : i32;\n"
+         "      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoSetMissingRParen) {
-  expect("[[set(1]] var i : i32;", "1:8: missing ) for set decoration");
+  EXPECT("[[set(1]] var i : i32;",
+         "test.wgsl:1:8 error: missing ) for set decoration\n"
+         "[[set(1]] var i : i32;\n"
+         "       ^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarDecoBindingSetValue) {
-  expect("[[set(x)]] var i : i32;", "1:7: invalid value for set decoration");
+  EXPECT("[[set(x)]] var i : i32;",
+         "test.wgsl:1:7 error: invalid value for set decoration\n"
+         "[[set(x)]] var i : i32;\n"
+         "      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) {
-  expect("var ^ : mat4x4;", "1:5: invalid identifier declaration");
+  EXPECT("var ^ : mat4x4;",
+         "test.wgsl:1:5 error: invalid identifier declaration\n"
+         "var ^ : mat4x4;\n"
+         "    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingLessThan) {
-  expect("var i : mat4x4;", "1:15: missing < for matrix");
+  EXPECT("var i : mat4x4;",
+         "test.wgsl:1:15 error: missing < for matrix\n"
+         "var i : mat4x4;\n"
+         "              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) {
-  expect("var i : mat4x4<u32;", "1:19: missing > for matrix");
+  EXPECT("var i : mat4x4<u32;",
+         "test.wgsl:1:19 error: missing > for matrix\n"
+         "var i : mat4x4<u32;\n"
+         "                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingType) {
-  expect("var i : mat4x4<1>;", "1:16: unable to determine subtype for matrix");
+  EXPECT("var i : mat4x4<1>;",
+         "test.wgsl:1:16 error: unable to determine subtype for matrix\n"
+         "var i : mat4x4<1>;\n"
+         "               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMissingSemicolon) {
-  expect("var i : i32", "1:12: missing ';' for variable declaration");
+  EXPECT("var i : i32",
+         "test.wgsl:1:12 error: missing ';' for variable declaration\n"
+         "var i : i32\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingLessThan) {
-  expect("var i : ptr;", "1:12: missing < for ptr declaration");
+  EXPECT("var i : ptr;",
+         "test.wgsl:1:12 error: missing < for ptr declaration\n"
+         "var i : ptr;\n"
+         "           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingGreaterThan) {
-  expect("var i : ptr<in, u32;", "1:20: missing > for ptr declaration");
+  EXPECT("var i : ptr<in, u32;",
+         "test.wgsl:1:20 error: missing > for ptr declaration\n"
+         "var i : ptr<in, u32;\n"
+         "                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingComma) {
-  expect("var i : ptr<in u32>;", "1:16: missing , for ptr declaration");
+  EXPECT("var i : ptr<in u32>;",
+         "test.wgsl:1:16 error: missing , for ptr declaration\n"
+         "var i : ptr<in u32>;\n"
+         "               ^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingStorageClass) {
-  expect("var i : ptr<meow, u32>;",
-         "1:13: missing storage class for ptr declaration");
+  EXPECT("var i : ptr<meow, u32>;",
+         "test.wgsl:1:13 error: missing storage class for ptr declaration\n"
+         "var i : ptr<meow, u32>;\n"
+         "            ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingType) {
-  expect("var i : ptr<in, 1>;", "1:17: missing type for ptr declaration");
+  EXPECT("var i : ptr<in, 1>;",
+         "test.wgsl:1:17 error: missing type for ptr declaration\n"
+         "var i : ptr<in, 1>;\n"
+         "                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
-  expect("var<fish> i : i32",
-         "1:5: invalid storage class for variable decoration");
+  EXPECT("var<fish> i : i32",
+         "test.wgsl:1:5 error: invalid storage class for variable decoration\n"
+         "var<fish> i : i32\n"
+         "    ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclMissingGThan) {
-  expect("var<in i : i32", "1:8: missing > for variable decoration");
+  EXPECT("var<in i : i32",
+         "test.wgsl:1:8 error: missing > for variable decoration\n"
+         "var<in i : i32\n"
+         "       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingLessThan) {
-  expect("var i : vec3;", "1:13: missing < for vector");
+  EXPECT("var i : vec3;",
+         "test.wgsl:1:13 error: missing < for vector\n"
+         "var i : vec3;\n"
+         "            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingGreaterThan) {
-  expect("var i : vec3<u32;", "1:17: missing > for vector");
+  EXPECT("var i : vec3<u32;",
+         "test.wgsl:1:17 error: missing > for vector\n"
+         "var i : vec3<u32;\n"
+         "                ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingType) {
-  expect("var i : vec3<1>;", "1:14: unable to determine subtype for vector");
+  EXPECT("var i : vec3<1>;",
+         "test.wgsl:1:14 error: unable to determine subtype for vector\n"
+         "var i : vec3<1>;\n"
+         "             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, IfStmtMissingLParen) {
-  expect("fn f() -> void { if true) {} }", "1:21: expected (");
+  EXPECT("fn f() -> void { if true) {} }",
+         "test.wgsl:1:21 error: expected (\n"
+         "fn f() -> void { if true) {} }\n"
+         "                    ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, IfStmtMissingRParen) {
-  expect("fn f() -> void { if (true {} }", "1:27: expected )");
+  EXPECT("fn f() -> void { if (true {} }",
+         "test.wgsl:1:27 error: expected )\n"
+         "fn f() -> void { if (true {} }\n"
+         "                          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, IfStmtInvalidCond) {
-  expect("fn f() -> void { if (>) {} }", "1:22: unable to parse expression");
+  EXPECT("fn f() -> void { if (>) {} }",
+         "test.wgsl:1:22 error: unable to parse expression\n"
+         "fn f() -> void { if (>) {} }\n"
+         "                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, LogicalAndInvalidExpr) {
-  expect("fn f() -> void { return 1 && >; }",
-         "1:30: unable to parse right side of && expression");
+  EXPECT("fn f() -> void { return 1 && >; }",
+         "test.wgsl:1:30 error: unable to parse right side of && expression\n"
+         "fn f() -> void { return 1 && >; }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, LogicalOrInvalidExpr) {
-  expect("fn f() -> void { return 1 || >; }",
-         "1:30: unable to parse right side of || expression");
+  EXPECT("fn f() -> void { return 1 || >; }",
+         "test.wgsl:1:30 error: unable to parse right side of || expression\n"
+         "fn f() -> void { return 1 || >; }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, LoopMissingLBrace) {
-  expect("fn f() -> void { loop } }", "1:23: missing { for loop");
+  EXPECT("fn f() -> void { loop } }",
+         "test.wgsl:1:23 error: missing { for loop\n"
+         "fn f() -> void { loop } }\n"
+         "                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, LoopMissingRBrace) {
-  expect("fn f() -> void { loop {", "1:24: missing } for loop");
+  EXPECT("fn f() -> void { loop {",
+         "test.wgsl:1:24 error: missing } for loop\n"
+         "fn f() -> void { loop {\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, MemberExprMissingIdentifier) {
-  expect("fn f() -> void { x = a.; }",
-         "1:24: missing identifier for member accessor");
+  EXPECT("fn f() -> void { x = a.; }",
+         "test.wgsl:1:24 error: missing identifier for member accessor\n"
+         "fn f() -> void { x = a.; }\n"
+         "                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, MultiplicativeInvalidExpr) {
-  expect("fn f() -> void { return 1.0 * <; }",
-         "1:31: unable to parse right side of * expression");
+  EXPECT("fn f() -> void { return 1.0 * <; }",
+         "test.wgsl:1:31 error: unable to parse right side of * expression\n"
+         "fn f() -> void { return 1.0 * <; }\n"
+         "                              ^\n");
 }
 
 TEST_F(ParserImplErrorTest, OrInvalidExpr) {
-  expect("fn f() -> void { return 1 | >; }",
-         "1:29: unable to parse right side of | expression");
+  EXPECT("fn f() -> void { return 1 | >; }",
+         "test.wgsl:1:29 error: unable to parse right side of | expression\n"
+         "fn f() -> void { return 1 | >; }\n"
+         "                            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, RelationalInvalidExpr) {
-  expect("fn f() -> void { return 1 < >; }",
-         "1:29: unable to parse right side of < expression");
+  EXPECT("fn f() -> void { return 1 < >; }",
+         "test.wgsl:1:29 error: unable to parse right side of < expression\n"
+         "fn f() -> void { return 1 < >; }\n"
+         "                            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ReturnStmtMissingSemicolon) {
-  expect("fn f() -> void { return }", "1:25: missing ;");
+  EXPECT("fn f() -> void { return }",
+         "test.wgsl:1:25 error: missing ;\n"
+         "fn f() -> void { return }\n"
+         "                        ^\n");
 }
 
 TEST_F(ParserImplErrorTest, ShiftInvalidExpr) {
-  expect("fn f() -> void { return 1 << >; }",
-         "1:30: unable to parse right side of << expression");
+  EXPECT("fn f() -> void { return 1 << >; }",
+         "test.wgsl:1:30 error: unable to parse right side of << expression\n"
+         "fn f() -> void { return 1 << >; }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtMissingLBrace) {
-  expect("fn f() -> void { switch(1) }",
-         "1:28: missing { for switch statement");
+  EXPECT("fn f() -> void { switch(1) }",
+         "test.wgsl:1:28 error: missing { for switch statement\n"
+         "fn f() -> void { switch(1) }\n"
+         "                           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtMissingRBrace) {
-  expect("fn f() -> void { switch(1) {",
-         "1:29: missing } for switch statement");
+  EXPECT("fn f() -> void { switch(1) {",
+         "test.wgsl:1:29 error: missing } for switch statement\n"
+         "fn f() -> void { switch(1) {\n"
+         "                            ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase) {
-  expect("fn f() -> void { switch(1) { case ^: } }",
-         "1:35: unable to parse case selectors");
+  EXPECT("fn f() -> void { switch(1) { case ^: } }",
+         "test.wgsl:1:35 error: unable to parse case selectors\n"
+         "fn f() -> void { switch(1) { case ^: } }\n"
+         "                                  ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase2) {
-  expect("fn f() -> void { switch(1) { case false: } }",
-         "1:35: invalid case selector must be an integer value");
+  EXPECT(
+      "fn f() -> void { switch(1) { case false: } }",
+      "test.wgsl:1:35 error: invalid case selector must be an integer value\n"
+      "fn f() -> void { switch(1) { case false: } }\n"
+      "                                  ^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingColon) {
-  expect("fn f() -> void { switch(1) { case 1 {} } }",
-         "1:37: missing : for case statement");
+  EXPECT("fn f() -> void { switch(1) { case 1 {} } }",
+         "test.wgsl:1:37 error: missing : for case statement\n"
+         "fn f() -> void { switch(1) { case 1 {} } }\n"
+         "                                    ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingLBrace) {
-  expect("fn f() -> void { switch(1) { case 1: } } }",
-         "1:38: missing { for case statement");
+  EXPECT("fn f() -> void { switch(1) { case 1: } } }",
+         "test.wgsl:1:38 error: missing { for case statement\n"
+         "fn f() -> void { switch(1) { case 1: } } }\n"
+         "                                     ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingRBrace) {
-  expect("fn f() -> void { switch(1) { case 1: {",
-         "1:39: missing } for case statement");
+  EXPECT("fn f() -> void { switch(1) { case 1: {",
+         "test.wgsl:1:39 error: missing } for case statement\n"
+         "fn f() -> void { switch(1) { case 1: {\n"
+         "                                      ^\n");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseFallthroughMissingSemicolon) {
-  expect("fn f() -> void { switch(1) { case 1: { fallthrough } case 2: {} } }",
-         "1:52: missing ;");
+  EXPECT("fn f() -> void { switch(1) { case 1: { fallthrough } case 2: {} } }",
+         "test.wgsl:1:52 error: missing ;\n"
+         "fn f() -> void { switch(1) { case 1: { fallthrough } case 2: {} } }\n"
+         "                                                   ^\n");
 }
 
 TEST_F(ParserImplErrorTest, VarStmtMissingSemicolon) {
-  expect("fn f() -> void { var a : u32 }", "1:30: missing ;");
+  EXPECT("fn f() -> void { var a : u32 }",
+         "test.wgsl:1:30 error: missing ;\n"
+         "fn f() -> void { var a : u32 }\n"
+         "                             ^\n");
 }
 
 TEST_F(ParserImplErrorTest, VarStmtInvalidAssignment) {
-  expect("fn f() -> void { var a : u32 = >; }",
-         "1:32: missing constructor for variable declaration");
+  EXPECT("fn f() -> void { var a : u32 = >; }",
+         "test.wgsl:1:32 error: missing constructor for variable declaration\n"
+         "fn f() -> void { var a : u32 = >; }\n"
+         "                               ^\n");
 }
 
 TEST_F(ParserImplErrorTest, UnaryInvalidExpr) {
-  expect("fn f() -> void { return !<; }",
-         "1:26: unable to parse right side of ! expression");
+  EXPECT("fn f() -> void { return !<; }",
+         "test.wgsl:1:26 error: unable to parse right side of ! expression\n"
+         "fn f() -> void { return !<; }\n"
+         "                         ^\n");
 }
 
 TEST_F(ParserImplErrorTest, UnexpectedToken) {
-  expect("unexpected", "1:1: invalid token (kIdentifier) encountered");
+  EXPECT("unexpected",
+         "test.wgsl:1:1 error: invalid token (kIdentifier) encountered\n"
+         "unexpected\n"
+         "^^^^^^^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, XorInvalidExpr) {
-  expect("fn f() -> void { return 1 ^ >; }",
-         "1:29: unable to parse right side of ^ expression");
+  EXPECT("fn f() -> void { return 1 ^ >; }",
+         "test.wgsl:1:29 error: unable to parse right side of ^ expression\n"
+         "fn f() -> void { return 1 ^ >; }\n"
+         "                            ^\n");
 }
 
 }  // namespace