Skip to main content

wgsl_parse/
parser.rs

1use std::str::FromStr;
2
3use crate::{
4    error::Error,
5    lexer::{Lexer, Token, TokenIterator},
6    syntax::*,
7};
8
9use lalrpop_util::lalrpop_mod;
10
11lalrpop_mod!(
12    #[allow(clippy::all, reason = "generated code")]
13    wgsl
14);
15lalrpop_mod!(
16    #[allow(clippy::all, reason = "generated code")]
17    wgsl_recognize
18);
19
20pub use crate::parser_support::ParseEntryPoint;
21use wgsl::EntryPointParser;
22
23macro_rules! parse {
24    ($source:expr, $token:ident, $entrypoint:ident) => {{
25        match parse_tokens(Lexer::new($source), Token::$token) {
26            Ok(ParseEntryPoint::$entrypoint(res)) => Ok(res),
27            Ok(_) => unreachable!("parser parsed the wrong entrypoint"),
28            Err(e) => Err(e),
29        }
30    }};
31}
32
33/// Parse a token stream into a syntax tree.
34///
35/// Low-level implementation, you probably don't want to use this. See [`parse_str`].
36///
37/// The `entrypoint` parameter must be one of the `EntryPointXXX` tokens, which tells the
38/// parser which syntax node to expect. It returns the [`ParseEntryPoint`] union type.
39pub fn parse_tokens(
40    lexer: impl TokenIterator,
41    entrypoint: Token,
42) -> Result<ParseEntryPoint, Error> {
43    let lexer = std::iter::once(Ok((0, entrypoint, 0))).chain(lexer);
44    let parser = EntryPointParser::new();
45    parser.parse(lexer).map_err(Into::into)
46}
47
48/// Parse a string into a syntax tree ([`TranslationUnit`]).
49///
50/// Identical to [`TranslationUnit::from_str`].
51pub fn parse_str(source: &str) -> Result<TranslationUnit, Error> {
52    parse!(source, EntryPointTranslationUnit, TranslationUnit)
53}
54
55/// Test whether a string represent a valid WGSL module ([`TranslationUnit`]).
56///
57/// Warning: it does not take WESL extensions into account.
58pub fn recognize_str(source: &str) -> Result<(), Error> {
59    let lexer = Lexer::new(source);
60    let parser = wgsl_recognize::TranslationUnitParser::new();
61    parser.parse(lexer).map_err(Into::into)
62}
63
64pub fn recognize_template_list(lexer: impl TokenIterator) -> Result<(), Error> {
65    match parse_tokens(lexer, Token::EntryPointTryTemplateList) {
66        Ok(ParseEntryPoint::TryTemplateList(_)) => Ok(()),
67        Ok(_) => unreachable!("parser parsed the wrong entrypoint"),
68        Err(e) => Err(e),
69    }
70}
71
72impl FromStr for TranslationUnit {
73    type Err = Error;
74
75    fn from_str(source: &str) -> Result<Self, Self::Err> {
76        parse!(source, EntryPointTranslationUnit, TranslationUnit)
77    }
78}
79impl FromStr for GlobalDirective {
80    type Err = Error;
81
82    fn from_str(source: &str) -> Result<Self, Self::Err> {
83        parse!(source, EntryPointGlobalDirective, GlobalDirective)
84    }
85}
86impl FromStr for GlobalDeclaration {
87    type Err = Error;
88
89    fn from_str(source: &str) -> Result<Self, Self::Err> {
90        parse!(source, EntryPointGlobalDecl, GlobalDecl)
91    }
92}
93impl FromStr for Statement {
94    type Err = Error;
95
96    fn from_str(source: &str) -> Result<Self, Self::Err> {
97        parse!(source, EntryPointStatement, Statement)
98    }
99}
100impl FromStr for Expression {
101    type Err = Error;
102
103    fn from_str(source: &str) -> Result<Self, Self::Err> {
104        parse!(source, EntryPointExpression, Expression)
105    }
106}
107impl FromStr for LiteralExpression {
108    type Err = Error;
109
110    fn from_str(source: &str) -> Result<Self, Self::Err> {
111        parse!(source, EntryPointLiteral, Literal)
112    }
113}
114#[cfg(feature = "imports")]
115impl FromStr for crate::syntax::ImportStatement {
116    type Err = Error;
117
118    fn from_str(source: &str) -> Result<Self, Self::Err> {
119        parse!(source, EntryPointImportStatement, ImportStatement)
120    }
121}