chromium/third_party/dawn/src/tint/lang/wgsl/reader/parser/parser.cc

// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "src/tint/lang/wgsl/reader/parser/parser.h"

#include <limits>
#include <utility>

#include "src/tint/lang/core/attribute.h"
#include "src/tint/lang/core/type/depth_texture.h"
#include "src/tint/lang/core/type/external_texture.h"
#include "src/tint/lang/core/type/multisampled_texture.h"
#include "src/tint/lang/core/type/sampled_texture.h"
#include "src/tint/lang/core/type/texture_dimension.h"
#include "src/tint/lang/wgsl/ast/assignment_statement.h"
#include "src/tint/lang/wgsl/ast/break_if_statement.h"
#include "src/tint/lang/wgsl/ast/break_statement.h"
#include "src/tint/lang/wgsl/ast/call_statement.h"
#include "src/tint/lang/wgsl/ast/continue_statement.h"
#include "src/tint/lang/wgsl/ast/discard_statement.h"
#include "src/tint/lang/wgsl/ast/id_attribute.h"
#include "src/tint/lang/wgsl/ast/if_statement.h"
#include "src/tint/lang/wgsl/ast/increment_decrement_statement.h"
#include "src/tint/lang/wgsl/ast/input_attachment_index_attribute.h"
#include "src/tint/lang/wgsl/ast/invariant_attribute.h"
#include "src/tint/lang/wgsl/ast/loop_statement.h"
#include "src/tint/lang/wgsl/ast/return_statement.h"
#include "src/tint/lang/wgsl/ast/stage_attribute.h"
#include "src/tint/lang/wgsl/ast/switch_statement.h"
#include "src/tint/lang/wgsl/ast/unary_op_expression.h"
#include "src/tint/lang/wgsl/ast/var.h"
#include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
#include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
#include "src/tint/lang/wgsl/reader/parser/classify_template_args.h"
#include "src/tint/lang/wgsl/reader/parser/lexer.h"
#include "src/tint/utils/containers/reverse.h"
#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/text/string.h"
#include "src/tint/utils/text/string_stream.h"

namespace tint::wgsl::reader {
namespace {

Void;

/// An instance of Void that can be used to signal success for functions that return Expect<Void> or
/// Maybe<NoError>.
static constexpr Void kSuccess;

Expect;

Maybe;

/// Controls the maximum number of times we'll call into the sync() and
/// unary_expression() functions from themselves. This is to guard against stack
/// overflow when there is an excessive number of blocks.
constexpr uint32_t kMaxParseDepth =;

/// The maximum number of tokens to look ahead to try and sync the
/// parser on error.
constexpr size_t const kMaxResynchronizeLookahead =;

// https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
//
// Must be called with an identifier token.
bool is_reserved(const Token& t) {}

/// Enter-exit counters for block token types.
/// Used by sync_to() to skip over closing block tokens that were opened during
/// the forward scan.
struct BlockCounters {};
}  // namespace

/// RAII helper that combines a Source on construction with the last token's
/// source when implicitly converted to `Source`.
class Parser::MultiTokenSource {};

Parser::TypedIdentifier::TypedIdentifier() = default;

Parser::TypedIdentifier::TypedIdentifier(const TypedIdentifier&) = default;

Parser::TypedIdentifier::TypedIdentifier(ast::Type type_in, const ast::Identifier* name_in)
    :{}

Parser::TypedIdentifier::~TypedIdentifier() = default;

Parser::FunctionHeader::FunctionHeader() = default;

Parser::FunctionHeader::FunctionHeader(const FunctionHeader&) = default;

Parser::FunctionHeader::FunctionHeader(Source src,
                                       const ast::Identifier* n,
                                       VectorRef<const ast::Parameter*> p,
                                       ast::Type ret_ty,
                                       VectorRef<const ast::Attribute*> ret_attrs)
    :{}

Parser::FunctionHeader::~FunctionHeader() = default;

Parser::FunctionHeader& Parser::FunctionHeader::operator=(const FunctionHeader& rhs) = default;

Parser::Parser(Source::File const* file) :{}

Parser::~Parser() = default;

Parser::Failure::Errored Parser::AddError(const Source& source,
                                          std::string_view err,
                                          std::string_view use) {}

Parser::Failure::Errored Parser::AddError(const Token& t, std::string_view err) {}

Parser::Failure::Errored Parser::AddError(const Source& source, std::string_view err) {}

Parser::Failure::Errored Parser::AddError(const Source& source, StyledText&& err) {}

void Parser::AddNote(const Source& source, std::string_view err) {}

void Parser::deprecated(const Source& source, std::string_view msg) {}

const Token& Parser::next() {}

const Token& Parser::peek(size_t count) {}

bool Parser::peek_is(Token::Type tok, size_t idx) {}

void Parser::split_token(Token::Type lhs, Token::Type rhs) {}

Source Parser::last_source() const {}

void Parser::InitializeLex() {}

bool Parser::Parse() {}

// translation_unit
//  : global_directive* global_decl* EOF
void Parser::translation_unit() {}

// global_directive
//  : diagnostic_directive
//  | requires_directive
//  | enable_directive
Maybe<Void> Parser::global_directive(bool have_parsed_decl) {}

// diagnostic_directive
//  : diagnostic diagnostic_control SEMICOLON
Maybe<Void> Parser::diagnostic_directive() {}

// enable_directive :
// | 'enable' identifier (COMMA identifier)* COMMA? SEMICOLON
Maybe<Void> Parser::enable_directive() {}

// requires_directive
//  : require identifier (COMMA identifier)* COMMA? SEMICOLON
Maybe<Void> Parser::requires_directive() {}

// global_decl
//  : SEMICOLON
//  | global_variable_decl SEMICOLON
//  | global_constant_decl SEMICOLON
//  | type_alias_decl SEMICOLON
//  | struct_decl
//  | function_decl
//  | const_assert_statement SEMICOLON
Maybe<Void> Parser::global_decl() {}

// global_variable_decl
//  : variable_attribute_list* variable_decl (EQUAL expression)?
Maybe<const ast::Variable*> Parser::global_variable_decl(AttributeList& attrs) {}

// global_constant_decl :
//  | LET optionally_typed_ident global_const_initializer
//  | attribute* override optionally_typed_ident (equal expression)?
// global_const_initializer
//  : EQUAL const_expr
Maybe<const ast::Variable*> Parser::global_constant_decl(AttributeList& attrs) {}

// variable_decl
//   : VAR variable_qualifier? optionally_typed_ident
//
// Note, the `( LESS_THAN address_space ( COMMA access_mode )? GREATER_THAN ) is pulled out into
// a `variable_qualifier` helper.
Maybe<Parser::VarDeclInfo> Parser::variable_decl() {}

Expect<Parser::TypedIdentifier> Parser::expect_ident_with_optional_type_specifier(
    std::string_view use,
    bool allow_inferred) {}

// optionally_typed_ident
//   : ident ( COLON typed_decl ) ?
Expect<Parser::TypedIdentifier> Parser::expect_optionally_typed_ident(std::string_view use) {}

// ident_with_type_specifier
//   : IDENT COLON type_specifier
Expect<Parser::TypedIdentifier> Parser::expect_ident_with_type_specifier(std::string_view use) {}

// variable_qualifier
//   : _template_args_start expression (COMMA expression)? _template_args_end
Maybe<Parser::VariableQualifier> Parser::variable_qualifier() {}

// type_alias_decl
//   : ALIAS IDENT EQUAL type_specifier
Maybe<const ast::Alias*> Parser::type_alias_decl() {}

// type_specifier
//   : IDENTIFIER template_arguments?
Maybe<ast::Type> Parser::type_specifier() {}

template <typename ENUM>
Expect<ENUM> Parser::expect_enum(std::string_view name,
                                 ENUM (*parse)(std::string_view str),
                                 Slice<const std::string_view> strings,
                                 std::string_view use) {}

Expect<ast::Type> Parser::expect_type(std::string_view use) {}

// struct_decl
//   : STRUCT IDENT struct_body_decl
Maybe<const ast::Struct*> Parser::struct_decl() {}

// struct_body_decl
//   : BRACE_LEFT (struct_member COMMA)* struct_member COMMA? BRACE_RIGHT
Expect<Parser::StructMemberList> Parser::expect_struct_body_decl() {}

// struct_member
//   : attribute* ident_with_type_specifier
Expect<const ast::StructMember*> Parser::expect_struct_member() {}

// const_assert_statement
//   : STATIC_ASSERT expression
Maybe<const ast::ConstAssert*> Parser::const_assert_statement() {}

// function_decl
//   : function_header compound_statement
Maybe<const ast::Function*> Parser::function_decl(AttributeList& attrs) {}

// function_header
//   : FN IDENT PAREN_LEFT param_list PAREN_RIGHT return_type_specifier_optional
// return_type_specifier_optional
//   :
//   | ARROW attribute_list* type_specifier
Maybe<Parser::FunctionHeader> Parser::function_header() {}

// param_list
//   :
//   | (param COMMA)* param COMMA?
Expect<Parser::ParameterList> Parser::expect_param_list() {}

// param
//   : attribute_list* ident COLON type_specifier
Expect<const ast::Parameter*> Parser::expect_param() {}

// compound_statement
//   : attribute* BRACE_LEFT statement* BRACE_RIGHT
Expect<ast::BlockStatement*> Parser::expect_compound_statement(std::string_view use) {}

// compound_statement
//   : attribute* BRACE_LEFT statement* BRACE_RIGHT
Expect<ast::BlockStatement*> Parser::expect_compound_statement(AttributeList& attrs,
                                                               std::string_view use) {}

// paren_expression
//   : PAREN_LEFT expression PAREN_RIGHT
Expect<const ast::Expression*> Parser::expect_paren_expression() {}

// statements
//   : statement*
Expect<Parser::StatementList> Parser::expect_statements() {}

// statement
//   : SEMICOLON
//   | if_statement
//   | switch_statement
//   | loop_statement
//   | for_statement
//   | while_statement
//   | compound_statement
//   | non_block_statement   // Note, we inject an extra rule in here for simpler parsing
Maybe<const ast::Statement*> Parser::statement() {}

// non_block_statement (continued)
//   : return_statement SEMICOLON
//   | func_call_statement SEMICOLON
//   | variable_statement SEMICOLON
//   | break_statement SEMICOLON
//   | continue_statement SEMICOLON
//   | DISCARD SEMICOLON
//   | variable_updating_statement SEMICOLON
//   | const_assert_statement SEMICOLON
Maybe<const ast::Statement*> Parser::non_block_statement() {}

// return_statement
//   : RETURN expression?
Maybe<const ast::ReturnStatement*> Parser::return_statement() {}

// variable_statement
//   : variable_decl
//   | variable_decl EQUAL expression
//   | LET optionally_typed_ident EQUAL expression
//   | CONST optionally_typed_ident EQUAL expression
Maybe<const ast::VariableDeclStatement*> Parser::variable_statement() {}

// if_statement
//   : attribute* if_clause else_if_clause* else_clause?
// if_clause:
//   : IF expression compound_stmt
// else_if_clause:
//   : ELSE IF expression compound_stmt
// else_clause
//   : ELSE compound_statement
Maybe<const ast::IfStatement*> Parser::if_statement(AttributeList& attrs) {}

// switch_statement
//   : attribute* SWITCH expression BRACKET_LEFT switch_body+ BRACKET_RIGHT
Maybe<const ast::SwitchStatement*> Parser::switch_statement(AttributeList& attrs) {}

// switch_body
//   : CASE case_selectors COLON? compound_statement
//   | DEFAULT COLON? compound_statement
Maybe<const ast::CaseStatement*> Parser::switch_body() {}

// case_selectors
//   : case_selector (COMMA case_selector)* COMMA?
Expect<Parser::CaseSelectorList> Parser::expect_case_selectors() {}

// case_selector
//   : DEFAULT
//   | expression
Maybe<const ast::CaseSelector*> Parser::case_selector() {}

// loop_statement
//   : attribute* LOOP attribute* BRACKET_LEFT statements continuing_statement? BRACKET_RIGHT
Maybe<const ast::LoopStatement*> Parser::loop_statement(AttributeList& attrs) {}

ForHeader::ForHeader(const ast::Statement* init,
                     const ast::Expression* cond,
                     const ast::Statement* cont)
    :{}

ForHeader::~ForHeader() = default;

// (variable_statement | variable_updating_statement | func_call_statement)?
Maybe<const ast::Statement*> Parser::for_header_initializer() {}

// (variable_updating_statement | func_call_statement)?
Maybe<const ast::Statement*> Parser::for_header_continuing() {}

// for_header
//   : for_header_initializer? SEMICOLON expression? SEMICOLON for_header_continuing?
Expect<std::unique_ptr<ForHeader>> Parser::expect_for_header() {}

// for_statement
//   : FOR PAREN_LEFT for_header PAREN_RIGHT compound_statement
Maybe<const ast::ForLoopStatement*> Parser::for_statement(AttributeList& attrs) {}

// while_statement
//   :  attribute* WHILE expression compound_statement
Maybe<const ast::WhileStatement*> Parser::while_statement(AttributeList& attrs) {}

// func_call_statement
//    : IDENT argument_expression_list
Maybe<const ast::CallStatement*> Parser::func_call_statement() {}

// break_statement
//   : BREAK
Maybe<const ast::BreakStatement*> Parser::break_statement() {}

// continue_statement
//   : CONTINUE
Maybe<const ast::ContinueStatement*> Parser::continue_statement() {}

// break_if_statement:
//    'break' 'if' expression semicolon
Maybe<const ast::Statement*> Parser::break_if_statement() {}

// continuing_compound_statement:
//   attribute* BRACE_LEFT statement* break_if_statement? BRACE_RIGHT
Maybe<const ast::BlockStatement*> Parser::continuing_compound_statement() {}

// continuing_statement
//   : CONTINUING continuing_compound_statement
Maybe<const ast::BlockStatement*> Parser::continuing_statement() {}

// primary_expression
//   : const_literal
//   | IDENT argument_expression_list?
//   | paren_expression
//
// Note, PAREN_LEFT ( expression ( COMMA expression ) * COMMA? )? PAREN_RIGHT is replaced
// with `argument_expression_list`.
Maybe<const ast::Expression*> Parser::primary_expression() {}

// component_or_swizzle_specifier
//   :
//   | BRACE_LEFT expression BRACE_RIGHT component_or_swizzle_specifier?
//   | PERIOD member_ident component_or_swizzle_specifier?
//   | PERIOD swizzle_name component_or_swizzle_specifier?
Maybe<const ast::Expression*> Parser::component_or_swizzle_specifier(
    const ast::Expression* prefix) {}

// argument_expression_list
//   : PAREN_LEFT ((expression COMMA)* expression COMMA?)? PAREN_RIGHT
Expect<Parser::ExpressionList> Parser::expect_argument_expression_list(std::string_view use) {}

// bitwise_expression.post.unary_expression
//   : AND unary_expression (AND unary_expression)*
//   | OR unary_expression (OR unary_expression)*
//   | XOR unary_expression (XOR unary_expression)*
Maybe<const ast::Expression*> Parser::bitwise_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

// multiplicative_operator
//   : FORWARD_SLASH
//   | MODULO
//   | STAR
Maybe<core::BinaryOp> Parser::multiplicative_operator() {}

// multiplicative_expression.post.unary_expression
//   : (multiplicative_operator unary_expression)*
Expect<const ast::Expression*> Parser::expect_multiplicative_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

// additive_operator
//   : MINUS
//   | PLUS
//
// Note, this also splits a `--` token. This is currently safe as the only way to get into
// here is through additive expression and rules for where `--` are allowed are very restrictive.
Maybe<core::BinaryOp> Parser::additive_operator() {}

// additive_expression.pos.unary_expression
//   : (additive_operator unary_expression expect_multiplicative_expression.post.unary_expression)*
//
// This is `( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*`
// split apart.
Expect<const ast::Expression*> Parser::expect_additive_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

// math_expression.post.unary_expression
//   : multiplicative_expression.post.unary_expression additive_expression.post.unary_expression
//
// This is `( multiplicative_operator unary_expression )* ( additive_operator unary_expression (
// multiplicative_operator unary_expression )* )*` split apart.
Expect<const ast::Expression*> Parser::expect_math_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

// shift_expression
//   : unary_expression shift_expression.post.unary_expression
Maybe<const ast::Expression*> Parser::shift_expression() {}

// shift_expression.post.unary_expression
//   : math_expression.post.unary_expression?
//   | SHIFT_LEFT unary_expression
//   | SHIFT_RIGHT unary_expression
//
// Note, add the `math_expression.post.unary_expression` is added here to make
// implementation simpler.
Expect<const ast::Expression*> Parser::expect_shift_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

// relational_expression
//   : unary_expression relational_expression.post.unary_expression
Maybe<const ast::Expression*> Parser::relational_expression() {}

// relational_expression.post.unary_expression
//   : shift_expression.post.unary_expression
//   | shift_expression.post.unary_expression EQUAL_EQUAL shift_expression
//   | shift_expression.post.unary_expression GREATER_THAN shift_expression
//   | shift_expression.post.unary_expression GREATER_THAN_EQUAL shift_expression
//   | shift_expression.post.unary_expression LESS_THAN shift_expression
//   | shift_expression.post.unary_expression LESS_THAN_EQUAL shift_expression
//   | shift_expression.post.unary_expression NOT_EQUAL shift_expression
//
// Note, a `shift_expression` element was added to simplify many of the right sides
Expect<const ast::Expression*> Parser::expect_relational_expression_post_unary_expression(
    const ast::Expression* lhs,
    const Source& lhs_source) {}

Expect<const ast::Expression*> Parser::expect_expression(std::string_view use) {}

Maybe<Parser::ExpressionList> Parser::expression_list(std::string_view use,
                                                      Token::Type terminator) {}

Expect<Parser::ExpressionList> Parser::expect_expression_list(std::string_view use,
                                                              Token::Type terminator) {}

// expression
//   : unary_expression bitwise_expression.post.unary_expression
//   | unary_expression relational_expression.post.unary_expression
//   | unary_expression relational_expression.post.unary_expression and_and
//        relational_expression ( and_and relational_expression )*
//   | unary_expression relational_expression.post.unary_expression or_or
//        relational_expression ( or_or relational_expression )*
//
// Note, a `relational_expression` element was added to simplify many of the right sides
Maybe<const ast::Expression*> Parser::expression() {}

// singular_expression
//   : primary_expression postfix_expr
Maybe<const ast::Expression*> Parser::singular_expression() {}

// unary_expression
//   : singular_expression
//   | MINUS unary_expression
//   | BANG unary_expression
//   | TILDE unary_expression
//   | STAR unary_expression
//   | AND unary_expression
//
// The `primary_expression component_or_swizzle_specifier ?` is moved out into a
// `singular_expression`
Maybe<const ast::Expression*> Parser::unary_expression() {}

// compound_assignment_operator
//   : plus_equal
//   | minus_equal
//   | times_equal
//   | division_equal
//   | modulo_equal
//   | and_equal
//   | or_equal
//   | xor_equal
//   | shift_right_equal
//   | shift_left_equal
Maybe<core::BinaryOp> Parser::compound_assignment_operator() {}

// core_lhs_expression
//   : ident
//   | PAREN_LEFT lhs_expression PAREN_RIGHT
Maybe<const ast::Expression*> Parser::core_lhs_expression() {}

// lhs_expression
//   : core_lhs_expression component_or_swizzle_specifier ?
//   | AND lhs_expression
//   | STAR lhs_expression
Maybe<const ast::Expression*> Parser::lhs_expression() {}

// variable_updating_statement
//   : lhs_expression ( EQUAL | compound_assignment_operator ) expression
//   | lhs_expression MINUS_MINUS
//   | lhs_expression PLUS_PLUS
//   | UNDERSCORE EQUAL expression
//
// Note, this is a simplification of the recursive grammar statement with the `lhs_expression`
// substituted back into the expression.
Maybe<const ast::Statement*> Parser::variable_updating_statement() {}

// const_literal
//   : INT_LITERAL
//   | FLOAT_LITERAL
//   | bool_literal
//
// bool_literal
//   : TRUE
//   | FALSE
Maybe<const ast::LiteralExpression*> Parser::const_literal() {}

Maybe<Parser::AttributeList> Parser::attribute_list() {}

Expect<const ast::Attribute*> Parser::expect_attribute() {}

// attribute
//   : ATTR identifier ( PAREN_LEFT expression ( COMMA expression )? COMMA? PAREN_RIGHT )?
Maybe<const ast::Attribute*> Parser::attribute() {}

Expect<Void> Parser::expect_attributes_consumed(VectorRef<const ast::Attribute*> in) {}

Expect<Void> Parser::expect_next_not_template_list(const Source& lhs_source) {}

Expect<Void> Parser::expect_not_templated_ident_expr(const ast::Expression* expr) {}

// severity_control_name
//   : 'error'
//   | 'warning'
//   | 'info'
//   | 'off'
Expect<wgsl::DiagnosticSeverity> Parser::expect_severity_control_name() {}

// diagnostic_control
// : PAREN_LEFT severity_control_name COMMA diagnostic_rule_name COMMA ? PAREN_RIGHT
Expect<ast::DiagnosticControl> Parser::expect_diagnostic_control() {}

// diagnostic_rule_name :
// | diagnostic_name_token
// | diagnostic_name_token '.' diagnostic_name_token
Expect<const ast::DiagnosticRuleName*> Parser::expect_diagnostic_rule_name() {}

bool Parser::match(Token::Type tok, Source* source /*= nullptr*/) {}

bool Parser::expect(std::string_view use, Token::Type tok) {}

Expect<int32_t> Parser::expect_sint(std::string_view use, Source* source /* = nullptr */) {}

Expect<uint32_t> Parser::expect_positive_sint(std::string_view use) {}

Expect<uint32_t> Parser::expect_nonzero_positive_sint(std::string_view use) {}

Expect<const ast::Identifier*> Parser::expect_ident(std::string_view use,
                                                    std::string_view kind /* = "identifier" */) {}

template <typename F, typename T>
T Parser::expect_block(Token::Type start, Token::Type end, std::string_view use, F&& body) {}

template <typename F, typename T>
T Parser::expect_paren_block(std::string_view use, F&& body) {}

template <typename F, typename T>
T Parser::expect_brace_block(std::string_view use, F&& body) {}

template <typename F, typename T>
T Parser::expect_lt_gt_block(std::string_view use, F&& body) {}

template <typename F, typename T>
T Parser::expect_template_arg_block(std::string_view use, F&& body) {}

template <typename F, typename T>
T Parser::sync(Token::Type tok, F&& body) {}

bool Parser::sync_to(Token::Type tok, bool consume) {}

bool Parser::is_sync_token(const Token& t) const {}

bool Parser::handle_error(const Token& t) {}

template <typename F, typename T>
T Parser::without_diag(F&& body) {}

}  // namespace tint::wgsl::reader