glsl_lang/
parse.rs

1//! Parsing utilities and entry points
2
3use lang_util::position::LexerPosition;
4
5use crate::{ast, parser};
6
7use glsl_lang_lexer::{HasLexerError, LangLexer, Token};
8
9pub use glsl_lang_lexer::{ParseContext, ParseContextData, ParseOptions};
10
11mod builder;
12pub use builder::*;
13
14mod parsable;
15pub use parsable::Extractable;
16pub use parsable::Parsable;
17
18/// GLSL language parser
19pub trait LangParser: Sized {
20    /// AST node returned by this parser
21    type Item;
22
23    /// Instantiate the parser
24    fn new() -> Self;
25
26    /// Parse the input
27    fn parse<
28        L: HasLexerError + Iterator<Item = Result<(LexerPosition, Token, LexerPosition), L::Error>>,
29    >(
30        &self,
31        ctx: ParseContext,
32        input: &mut L,
33    ) -> Result<Self::Item, lalrpop_util::ParseError<LexerPosition, Token, L::Error>>;
34}
35
36/// GLSL language parsing capability
37pub trait HasParser: Sized {
38    /// Type of the parser to create
39    type Parser: LangParser<Item = Self>;
40}
41
42/// GLSL language parsing functions
43#[allow(clippy::result_large_err)]
44pub trait Parse: HasParser {
45    /// Parse the input source
46    fn parse<'i, L: LangLexer<'i>>(
47        source: L::Input,
48    ) -> Result<Self, ParseError<<L::Iter as HasLexerError>::Error>>;
49
50    /// Parse the input source with the given options
51    fn parse_with_options<'i, L: LangLexer<'i>>(
52        source: L::Input,
53        opts: &ParseOptions,
54    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self>;
55
56    /// Parse the input source with the given context
57    fn parse_with_context<'i, L: LangLexer<'i>>(
58        source: L::Input,
59        ctx: &ParseContext,
60    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self>;
61}
62
63impl<T: HasParser> Parse for T {
64    fn parse<'i, L: LangLexer<'i>>(
65        source: L::Input,
66    ) -> Result<Self, ParseError<<L::Iter as HasLexerError>::Error>> {
67        ParseBuilder::<L, Self>::new(source)
68            .parse()
69            .map(|(parsed, _names, _lexer)| parsed)
70    }
71
72    fn parse_with_options<'i, L: LangLexer<'i>>(
73        source: L::Input,
74        opts: &ParseOptions,
75    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self> {
76        ParseBuilder::<L, Self>::new(source).opts(opts).parse()
77    }
78
79    fn parse_with_context<'i, L: LangLexer<'i>>(
80        source: L::Input,
81        ctx: &ParseContext,
82    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self> {
83        ParseBuilder::<L, Self>::new(source).context(ctx).parse()
84    }
85}
86
87/// Result of a parsing operation
88pub type ParseResult<L, E, T> = Result<(T, ParseContext, L), ParseError<E>>;
89
90/// Errors returned by the parsing operation
91pub type ParseError<E> = lang_util::error::ParseError<E>;
92
93/// Default lexer to use for parsing sources
94#[cfg(not(feature = "lexer-full"))]
95pub type DefaultLexer<'i> = glsl_lang_lexer::min::str::Lexer<'i>;
96
97/// Default lexer to use for parsing sources
98#[cfg(feature = "lexer-full")]
99pub type DefaultLexer<'i> = glsl_lang_lexer::full::str::Lexer<'i>;
100
101/// GLSL parsing with the default lexer
102pub trait DefaultParse: Parse {
103    /// Parse the input source
104    fn parse<'i>(
105        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
106    ) -> Result<Self, ParseError<<<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error>>;
107
108    /// Parse the input source with the given options
109    fn parse_with_options<'i>(
110        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
111        opts: &ParseOptions,
112    ) -> ParseResult<
113        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
114        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
115        Self,
116    >;
117
118    /// Parse the input source with the given context
119    fn parse_with_context<'i>(
120        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
121        ctx: &ParseContext,
122    ) -> ParseResult<
123        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
124        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
125        Self,
126    >;
127}
128
129impl<T: Parse> DefaultParse for T {
130    fn parse<'i>(
131        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
132    ) -> Result<Self, ParseError<<<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error>>
133    {
134        <T as Parse>::parse::<DefaultLexer<'i>>(source)
135    }
136
137    fn parse_with_options<'i>(
138        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
139        opts: &ParseOptions,
140    ) -> ParseResult<
141        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
142        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
143        Self,
144    > {
145        <T as Parse>::parse_with_options::<DefaultLexer<'i>>(source, opts)
146    }
147
148    fn parse_with_context<'i>(
149        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
150        ctx: &ParseContext,
151    ) -> ParseResult<
152        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
153        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
154        Self,
155    > {
156        <T as Parse>::parse_with_context::<DefaultLexer<'i>>(source, ctx)
157    }
158}
159
160macro_rules! impl_parse {
161    ($t:ty => $p:ty) => {
162        impl LangParser for $p {
163            type Item = $t;
164
165            fn new() -> Self {
166                <$p>::new()
167            }
168
169            fn parse<
170                L: HasLexerError
171                    + Iterator<Item = Result<(LexerPosition, Token, LexerPosition), L::Error>>,
172            >(
173                &self,
174                ctx: ParseContext,
175                input: &mut L,
176            ) -> Result<Self::Item, lalrpop_util::ParseError<LexerPosition, Token, L::Error>> {
177                self.parse::<L, _, _>(&ctx, input)
178            }
179        }
180
181        impl HasParser for $t {
182            type Parser = $p;
183        }
184    };
185}
186
187#[cfg(feature = "parser-expr")]
188impl_parse!(ast::Expr            => parser::ExprParser);
189#[cfg(feature = "parser-statement")]
190impl_parse!(ast::Statement       => parser::StatementParser);
191impl_parse!(ast::TranslationUnit => parser::TranslationUnitParser);