use crate::lexer::Token;
use crate::error::ParseError;
// this grammar follows closely the wgsl spec.
// following the spec at this date: https://www.w3.org/TR/2024/WD-WGSL-20240731/
grammar;
extern {
type Location = usize;
type Error = (usize, ParseError, usize);
enum Token {
// syntactic tokens
// https://www.w3.org/TR/WGSL/#syntactic-tokens
"&" => Token::SymAnd,
"&&" => Token::SymAndAnd,
"->" => Token::SymArrow,
"@" => Token::SymAttr,
"/" => Token::SymForwardSlash,
"!" => Token::SymBang,
"[" => Token::SymBracketLeft,
"]" => Token::SymBracketRight,
"{" => Token::SymBraceLeft,
"}" => Token::SymBraceRight,
":" => Token::SymColon,
"," => Token::SymComma,
"=" => Token::SymEqual,
"==" => Token::SymEqualEqual,
"!=" => Token::SymNotEqual,
">" => Token::SymGreaterThan,
">=" => Token::SymGreaterThanEqual,
">>" => Token::SymShiftRight,
"<" => Token::SymLessThan,
"<=" => Token::SymLessThanEqual,
"<<" => Token::SymShiftLeft,
"%" => Token::SymModulo,
"-" => Token::SymMinus,
"--" => Token::SymMinusMinus,
"." => Token::SymPeriod,
"+" => Token::SymPlus,
"++" => Token::SymPlusPlus,
"|" => Token::SymOr,
"||" => Token::SymOrOr,
"(" => Token::SymParenLeft,
")" => Token::SymParenRight,
";" => Token::SymSemicolon,
"*" => Token::SymStar,
"~" => Token::SymTilde,
"_" => Token::SymUnderscore,
"^" => Token::SymXor,
"+=" => Token::SymPlusEqual,
"-=" => Token::SymMinusEqual,
"*=" => Token::SymTimesEqual,
"/=" => Token::SymDivisionEqual,
"%=" => Token::SymModuloEqual,
"&=" => Token::SymAndEqual,
"|=" => Token::SymOrEqual,
"^=" => Token::SymXorEqual,
">>=" => Token::SymShiftRightAssign,
"<<=" => Token::SymShiftLeftAssign,
// keywords
// https://www.w3.org/TR/WGSL/#keyword-summary
"alias" => Token::KwAlias,
"break" => Token::KwBreak,
"case" => Token::KwCase,
"const" => Token::KwConst,
"const_assert" => Token::KwConstAssert,
"continue" => Token::KwContinue,
"continuing" => Token::KwContinuing,
"default" => Token::KwDefault,
"diagnostic" => Token::KwDiagnostic,
"discard" => Token::KwDiscard,
"else" => Token::KwElse,
"enable" => Token::KwEnable,
"false" => Token::KwFalse,
"fn" => Token::KwFn,
"for" => Token::KwFor,
"if" => Token::KwIf,
"let" => Token::KwLet,
"loop" => Token::KwLoop,
"override" => Token::KwOverride,
"requires" => Token::KwRequires,
"return" => Token::KwReturn,
"struct" => Token::KwStruct,
"switch" => Token::KwSwitch,
"true" => Token::KwTrue,
"var" => Token::KwVar,
"while" => Token::KwWhile,
IdentPatternToken => Token::Ident(<String>),
TokAbstractInt => Token::AbstractInt(<i64>),
TokAbstractFloat => Token::AbstractFloat(<f64>),
TokI32 => Token::I32(<i32>),
TokU32 => Token::U32(<u32>),
TokF32 => Token::F32(<f32>),
TokF16 => Token::F16(<f32>),
TokTemplateArgsStart => Token::TemplateArgsStart,
TokTemplateArgsEnd => Token::TemplateArgsEnd,
}
}
// the grammar rules are laid out in the same order as in the spec.
// following the spec at this date: https://www.w3.org/TR/2024/WD-WGSL-20240731/
// custom entrypoint called by the lexer when it sees [Token::Ident, Token::SymLessThan].
// if this parse succeeds, the next token emitted by the lexer will be TokTemplateList.
pub TryTemplateList: () = TemplateList;
// =====================
// === Begin grammar ===
// =====================
// 2. WGSL MODULE
// https://www.w3.org/TR/WGSL/#wgsl-module
pub TranslationUnit: () = GlobalDirective * GlobalDecl *;
GlobalDecl: () = {
";",
GlobalVariableDecl ";",
GlobalValueDecl ";",
TypeAliasDecl ";",
StructDecl,
FunctionDecl,
ConstAssertStatement ";",
};
DiagnosticRuleName: () = {
DiagnosticNameToken,
DiagnosticNameToken "." DiagnosticNameToken,
};
// 3. TEXTUAL STRUCTURE
// https://www.w3.org/TR/WGSL/textual-structure#
// XXX: non-conformant
// https://www.w3.org/TR/WGSL/#syntax-literal
Literal: () = {
TokAbstractInt,
TokAbstractFloat,
TokI32,
TokU32,
TokF32,
TokF16,
BoolLiteral,
};
BoolLiteral: () = {
"true",
"false"
};
Ident: () = IdentPatternToken /* _DisambiguateTemplate */;
MemberIdent: () = IdentPatternToken;
// TODO: check context-dependent names below.
BuiltinValueName: () = IdentPatternToken;
DiagnosticNameToken: () = IdentPatternToken;
SeverityControlName: () = IdentPatternToken;
EnableExtensionName: () = IdentPatternToken;
SoftwareExtensionName: () = IdentPatternToken;
InterpolateSamplingName: () = IdentPatternToken;
SwizzleName: () = IdentPatternToken;
TemplateList: () = TokTemplateArgsStart TemplateArgCommaList TokTemplateArgsEnd;
TemplateArgCommaList: () = TemplateArgExpression ( "," TemplateArgExpression ) * "," ?;
TemplateArgExpression: () = Expression;
// 4. DIRECTIVES
// https://www.w3.org/TR/WGSL/#directives
GlobalDirective: () = {
DiagnosticDirective,
EnableDirective,
RequiresDirective,
};
EnableDirective: () = "enable" EnableExtensionList ";";
EnableExtensionList: () = EnableExtensionName ( "," EnableExtensionName ) * "," ?;
RequiresDirective: () = "requires" SoftwareExtensionList ";";
SoftwareExtensionList: () = SoftwareExtensionName ( "," SoftwareExtensionName ) * "," ?;
DiagnosticDirective: () = "diagnostic" DiagnosticControl ";";
// 5. DECLARATION AND SCOPE
// https://www.w3.org/TR/WGSL/#declaration-and-scope
// 6. TYPES
// https://www.w3.org/TR/WGSL/#types
StructDecl: () = "struct" Ident StructBodyDecl;
StructBodyDecl: () = "{" StructMember ( "," StructMember ) * "," ? "}";
StructMember: () = Attribute * MemberIdent ":" TypeSpecifier;
TypeAliasDecl: () = "alias" Ident "=" TypeSpecifier;
TypeSpecifier: () = TemplateElaboratedIdent;
TemplateElaboratedIdent: () = Ident /* DisambiguateTemplate */ TemplateList ?;
// 7. VARIABLE AND VALUE DECLARATIONS
// https://www.w3.org/TR/WGSL/#var-and-value
VariableOrValueStatement: () = {
VariableDecl,
VariableDecl "=" Expression,
"let" OptionallyTypedIdent "=" Expression,
"const" OptionallyTypedIdent "=" Expression,
};
VariableDecl: () = "var" /* DisambiguateTemplate */ TemplateList ? OptionallyTypedIdent;
OptionallyTypedIdent: () = Ident ( ":" TypeSpecifier ) ?;
GlobalVariableDecl: () = Attribute * VariableDecl ( "=" Expression ) ?;
GlobalValueDecl: () = {
"const" OptionallyTypedIdent "=" Expression,
Attribute * "override" OptionallyTypedIdent ( "=" Expression ) ?,
};
// 8. EXPRESSIONS
// https://www.w3.org/TR/WGSL/#expressions
PrimaryExpression: () = {
TemplateElaboratedIdent,
CallExpression,
Literal,
ParenExpression,
};
CallExpression: () = CallPhrase;
CallPhrase: () = TemplateElaboratedIdent ArgumentExpressionList;
ParenExpression: () = "(" Expression ")";
ArgumentExpressionList: () = "(" ExpressionCommaList ? ")";
ExpressionCommaList: () = Expression ( "," Expression ) * "," ?;
ComponentOrSwizzleSpecifier: () = {
"[" Expression "]" ComponentOrSwizzleSpecifier ?,
"." MemberIdent ComponentOrSwizzleSpecifier ?,
// "." SwizzleName ComponentOrSwizzleSpecifier ?,
};
UnaryExpression: () = {
SingularExpression,
"-" UnaryExpression,
"!" UnaryExpression,
"~" UnaryExpression,
"*" UnaryExpression,
"&" UnaryExpression,
};
SingularExpression: () = PrimaryExpression ComponentOrSwizzleSpecifier ?;
LhsExpression: () = {
CoreLhsExpression ComponentOrSwizzleSpecifier ?,
"*" LhsExpression,
"&" LhsExpression,
};
CoreLhsExpression: () = {
Ident /* DisambiguateTemplate */,
"(" LhsExpression ")",
};
MultiplicativeExpression: () = {
UnaryExpression,
MultiplicativeExpression MultiplicativeOperator UnaryExpression,
};
MultiplicativeOperator: () = {
"*",
"/",
"%",
};
AdditiveExpression: () = {
MultiplicativeExpression,
AdditiveExpression AdditiveOperator MultiplicativeExpression,
};
AdditiveOperator: () = {
"+",
"-",
};
ShiftExpression: () = {
AdditiveExpression,
UnaryExpression "<<" UnaryExpression,
UnaryExpression ">>" UnaryExpression,
};
RelationalExpression: () = {
ShiftExpression,
ShiftExpression "<" ShiftExpression,
ShiftExpression ">" ShiftExpression,
ShiftExpression "<=" ShiftExpression,
ShiftExpression ">=" ShiftExpression,
ShiftExpression "==" ShiftExpression,
ShiftExpression "!=" ShiftExpression,
};
ShortCircuitAndExpression: () = {
RelationalExpression,
ShortCircuitAndExpression "&&" RelationalExpression,
};
ShortCircuitOrExpression: () = {
RelationalExpression,
ShortCircuitOrExpression "||" RelationalExpression,
};
BinaryOrExpression: () = {
UnaryExpression,
BinaryOrExpression "|" UnaryExpression,
};
BinaryAndExpression: () = {
UnaryExpression,
BinaryAndExpression "&" UnaryExpression,
};
BinaryXorExpression: () = {
UnaryExpression,
BinaryXorExpression "^" UnaryExpression,
};
BitwiseExpression: () = {
BinaryAndExpression "&" UnaryExpression,
BinaryOrExpression "|" UnaryExpression,
BinaryXorExpression "^" UnaryExpression,
};
Expression: () = {
RelationalExpression,
ShortCircuitOrExpression "||" RelationalExpression,
ShortCircuitAndExpression "&&" RelationalExpression,
BitwiseExpression,
};
// 9. STATEMENTS
// https://www.w3.org/TR/WGSL/#statements
CompoundStatement: () = Attribute * "{" Statement * "}";
AssignmentStatement: () = {
LhsExpression "=" Expression,
LhsExpression CompoundAssignmentOperator Expression,
"_" "=" Expression,
};
CompoundAssignmentOperator: () = {
"+=",
"-=",
"*=",
"/=",
"%=",
"&=",
"|=",
"^=",
">>=",
"<<=",
};
IncrementStatement: () = LhsExpression "++";
DecrementStatement: () = LhsExpression "--";
IfStatement: () = Attribute * IfClause ElseIfClause * ElseClause ?;
IfClause: () = "if" Expression CompoundStatement;
ElseIfClause: () = "else" "if" Expression CompoundStatement;
ElseClause: () = "else" CompoundStatement;
SwitchStatement: () = Attribute * "switch" Expression SwitchBody;
SwitchBody: () = Attribute * "{" SwitchClause + "}";
SwitchClause: () = {
CaseClause,
DefaultAloneClause,
};
CaseClause: () = "case" CaseSelectors ":" ? CompoundStatement;
DefaultAloneClause: () = "default" ":" ? CompoundStatement;
CaseSelectors: () = CaseSelector ( "," CaseSelector ) * "," ?;
CaseSelector: () = {
"default",
Expression,
};
LoopStatement: () = Attribute * "loop" Attribute * "{" Statement * ContinuingStatement ? "}";
ForStatement: () = Attribute * "for" "(" ForHeader ")" CompoundStatement;
ForHeader: () = ForInit ? ";" Expression ? ";" ForUpdate ?;
ForInit: () = {
VariableOrValueStatement,
VariableUpdatingStatement,
FuncCallStatement,
};
ForUpdate: () = {
VariableUpdatingStatement,
FuncCallStatement,
};
WhileStatement: () = Attribute * "while" Expression CompoundStatement;
BreakStatement: () = "break";
BreakIfStatement: () = "break" "if" Expression ";";
ContinueStatement: () = "continue";
ContinuingStatement: () = "continuing" ContinuingCompoundStatement;
ContinuingCompoundStatement: () = Attribute * "{" Statement * BreakIfStatement ? "}";
ReturnStatement: () = "return" Expression ?;
FuncCallStatement: () = CallPhrase;
ConstAssertStatement: () = "const_assert" Expression;
Statement: () = {
";",
ReturnStatement ";",
IfStatement,
SwitchStatement,
LoopStatement,
ForStatement,
WhileStatement,
FuncCallStatement ";",
VariableOrValueStatement ";",
BreakStatement ";",
ContinueStatement ";",
"discard" ";",
VariableUpdatingStatement ";",
CompoundStatement,
ConstAssertStatement ";",
};
VariableUpdatingStatement: () = {
AssignmentStatement,
IncrementStatement,
DecrementStatement,
};
// 10. FUNCTIONS
// https://www.w3.org/TR/WGSL/#functions
FunctionDecl: () = Attribute * FunctionHeader CompoundStatement;
FunctionHeader: () = "fn" Ident "(" ParamList ? ")" ( "->" Attribute * TemplateElaboratedIdent ) ?;
ParamList: () = Param ( "," Param ) * "," ?;
Param: () = Attribute * Ident ":" TypeSpecifier;
// 11. ATTRIBUTES
// https://www.w3.org/TR/WGSL/#attributes
// TODO: maybe parse the well-known attributes.
Attribute: () = "@" IdentPatternToken ArgumentExpressionList ?;
DiagnosticControl: () = "(" SeverityControlName "," DiagnosticRuleName "," ? ")";
// ===================
// === End grammar ===
// ===================
// ----------- below: macros -----------
Comma<T>: () = (T ",")* (T)?;