// Based on https://www.w3.org/TR/WGSL with some modifications. token Enable='enable' Requires='requires' Fn='fn' Alias='alias' Struct='struct' Var='var' ConstAssert='const_assert' If='if' For='for' Else='else' Loop='loop' Break='break' While='while' Return='return' Switch='switch' Discard='discard' Continuing='continuing' Const='const' Case='case' Default='default' Override='override' Continue='continue' Let='let' True='true' False='false' Diagnostic='diagnostic'; token Semi=';' LPar='(' RPar=')' Comma=',' Eq='=' Colon=':' LBrace='{' RBrace='}' MinusGt='->' Lt='<' Gt='>' Dot='.' At='@' LBrak='[' RBrak=']' And='&' Excl='!' Star='*' Minus='-' Tilde='~' Plus='+' Eq2='==' Pipe='|' And2='&&' Slash='/' Caret='^' Pipe2='||' ExclEq='!=' Percent='%' Underscore='_' AndEq='&=' StarEq='*=' PlusEq='+=' PipeEq='|=' MinusEq='-=' SlashEq='/=' CaretEq='^=' PercentEq='%=' Plus2='++' Minus2='--'; token Ident='' FloatLiteral='' IntLiteral=''; token Whitespace Comment; skip Whitespace Comment; start translation_unit; // later validate that directives come before declarations to improve error messages translation_unit: (global_item | ';')*; global_item^: global_directive | global_decl | global_assert; global_assert: 'const_assert' expression ';'; // §10 global_directive: 'diagnostic' diagnostic_control ';' @diagnostic_directive // §4.2 | 'enable' Ident (?1 ',' Ident)* [','] ';' @enable_directive // §4.1.1 | 'requires' Ident (?1 ',' Ident)* [','] ';' @requires_directive // §4.1.2 ; diagnostic_control: '(' severity_control_name ',' diagnostic_rule_name [','] ')'; severity_control_name: Ident; diagnostic_rule_name: Ident ['.' Ident]; global_decl: attribute* ( function_header compound_statement @function_decl | variable_decl ';' @global_variable_decl | override_decl ';' @global_value_decl | let_decl ';' @global_let_decl ) | const_decl ';' @global_value_decl | 'alias' Ident '=' Ident template_list ';' @type_alias_decl | 'struct' Ident struct_body @struct_decl ; function_header: 'fn' Ident '(' parameters ')' return_type; parameters: [param (?1 ',' param)* [',']]; param: attribute* Ident ':' type_specifier; return_type: ['->' attribute* Ident template_list]; struct_body: '{' struct_member (?1 ',' struct_member)* [','] '}'; struct_member: attribute* Ident ':' type_specifier; attribute: '@' ( 'diagnostic' diagnostic_control @diagnostic_attr | Ident ['(' [expression (?1 ',' expression)* [',']] ')'] ) ; typed_ident: Ident (':' type_specifier | ()); // extra rule for better error message typed_ident_init: Ident (':' type_specifier | ()) @typed_ident; type_specifier: Ident template_list; template_list^: [#1 template_args >]; expr_template_list^: #1 [?1 template_args >template_list]; template_args^: '<' expression (?1 ',' expression)* [','] '>'; expression: expression '[' expression ']' @indexing_expression // §8.5 | expression '.' (?1 Ident @swizzle_expression | Ident @named_component_expression) // §8.5 | ('-' | '!' | '~' | '*' | '&') expression @unary_expression // §8.6, §8.7, §8.9, §8.13, §8.14 | expression ('*' | '/' | '%') expression @binary_expression // §8.7 | expression ('+' | '-') expression @binary_expression // §8.7 | ?2 expression ('<' '<' | '>' '>') expression @binary_expression // §8.9 | ?3 expression (?4 '<' | ?4 '>' | '<' '=' | '>' '=' | '==' | '!=') expression @binary_expression // §8.8 | expression '&' expression @binary_expression // §8.9 | expression '^' expression @binary_expression // §8.9 | expression '|' expression @binary_expression // §8.9 | expression '&&' expression @binary_expression // §8.6 | expression '||' expression @binary_expression // §8.6 | Ident expr_template_list @ident_expression [argument_expression_list_expr @call_expression] // §8.10, §8.11 | '(' expression ')' @paren_expression // §8.4 | IntLiteral @int_expression // §8.3 | FloatLiteral @float_expression // §8.3 | 'true' @bool_expression // §8.3 | 'false' @bool_expression // §8.3 ; argument_expression_list: '(' [expression (?1 ',' expression)* [',']] ')'; // extra rule for better error handling argument_expression_list_expr: '(' [expression (?1 ',' expression)* [',']] ')' @argument_expression_list; statement: attribute* ( if_clause (?1 else_if_clause)* [else_clause] @if_statement // §9.4.1 | 'switch' expression attribute* '{' switch_clause * '}' @switch_statement // §9.4.2 | 'loop' attribute* '{' statement* [continuing_statement] '}' @loop_statement // §9.4.3 | 'for' '(' [for_init] ';' [expression] ';' [for_update] ')' compound_statement @for_statement // §9.4.4 | 'while' expression compound_statement @while_statement // §9.4.5 | '{' statement* '}' @compound_statement // §9.1 ) | ?2 func_call ';' @func_call_statement // §9.5 | variable_or_value ';' @variable_or_value_statement | lhs_expression ( '=' expression @simple_assignment_statement // §9.2.1 | compound_assignment_operator expression @compound_assignment_statement // §9.2.3 | '++' @increment_statement // §9.3 | '--' @decrement_statement // §9.3 ) ';' | '_' '=' expression ';' @phony_assignment_statement // §9.2.2 | 'const_assert' expression ';' @assert_statement // §10.1 | 'break' ';' @break_statement // §9.4.6 | 'continue' ';' @continue_statement // §9.4.8 | ';' @empty_statement | 'discard' ';' @discard_statement // §9.4.11 | 'return' [expression] ';' @return_statement // §9.4.10 ; continuing_statement: 'continuing' attribute* '{' (?1 statement)* [break_if_statement] '}'; // §9.4.9 break_if_statement: 'break' 'if' expression ';'; // §9.4.7 for_init: ?1 func_call | variable_or_value | variable_updating ; for_update: ?1 func_call | variable_updating; if_clause: 'if' expression compound_statement; else_if_clause: 'else' 'if' expression compound_statement; else_clause: 'else' compound_statement; switch_clause^: case_clause | default_alone_clause; case_clause: 'case' case_selectors [':'] compound_statement; case_selectors: case_selector (?1 ',' case_selector)* [',']; case_selector: 'default' | expression; default_alone_clause: 'default' [':'] compound_statement; compound_statement: attribute* '{' & statement* '}'; // §9.1 func_call: Ident template_list argument_expression_list; variable_or_value^: variable_decl | let_decl | const_decl; variable_decl: 'var' template_list typed_ident ['=' expression]; let_decl: 'let' typed_ident_init '=' #1 expression; const_decl: 'const' typed_ident_init '=' #1 expression; override_decl: 'override' typed_ident ['=' expression]; // duplicated so it can be used in `for` statement without semicolon variable_updating: lhs_expression ( '=' expression @simple_assignment_statement // §9.2.1 | compound_assignment_operator expression @compound_assignment_statement // §9.2.3 | '++' @increment_statement // §9.3 | '--' @decrement_statement // §9.3 ) | '_' '=' expression @phony_assignment_statement // §9.2.2 ; compound_assignment_operator^: ?1 '<' '<' '=' | ?1 '>' '>' '=' | '%=' | '&=' | '*=' | '+=' | '-=' | '/=' | '^=' | '|=' ; lhs_expression: lhs_expression '[' expression ']' @indexing_expression // §8.5 | lhs_expression '.' (?1 Ident @swizzle_expression | Ident @named_component_expression) // §8.5 | '*' lhs_expression @unary_expression // §8.14 | '&' lhs_expression @unary_expression // §8.13 | '(' lhs_expression ')' @paren_expression // §8.4 | Ident @ident_expression // §8.11 ;