1use 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;
16#[cfg(any(
17    feature = "lexer-v1",
18    feature = "lexer-v2-min",
19    feature = "lexer-v2-full"
20))]
21pub use parsable::Parsable;
22
23pub trait LangParser: Sized {
25    type Item;
27
28    fn new() -> Self;
30
31    fn parse<
33        L: HasLexerError + Iterator<Item = Result<(LexerPosition, Token, LexerPosition), L::Error>>,
34    >(
35        &self,
36        ctx: ParseContext,
37        input: &mut L,
38    ) -> Result<Self::Item, lalrpop_util::ParseError<LexerPosition, Token, L::Error>>;
39}
40
41pub trait HasParser: Sized {
43    type Parser: LangParser<Item = Self>;
45}
46
47#[allow(clippy::result_large_err)]
49pub trait Parse: HasParser {
50    fn parse<'i, L: LangLexer<'i>>(
52        source: L::Input,
53    ) -> Result<Self, ParseError<<L::Iter as HasLexerError>::Error>>;
54
55    fn parse_with_options<'i, L: LangLexer<'i>>(
57        source: L::Input,
58        opts: &ParseOptions,
59    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self>;
60
61    fn parse_with_context<'i, L: LangLexer<'i>>(
63        source: L::Input,
64        ctx: &ParseContext,
65    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self>;
66}
67
68impl<T: HasParser> Parse for T {
69    fn parse<'i, L: LangLexer<'i>>(
70        source: L::Input,
71    ) -> Result<Self, ParseError<<L::Iter as HasLexerError>::Error>> {
72        ParseBuilder::<L, Self>::new(source)
73            .parse()
74            .map(|(parsed, _names, _lexer)| parsed)
75    }
76
77    fn parse_with_options<'i, L: LangLexer<'i>>(
78        source: L::Input,
79        opts: &ParseOptions,
80    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self> {
81        ParseBuilder::<L, Self>::new(source).opts(opts).parse()
82    }
83
84    fn parse_with_context<'i, L: LangLexer<'i>>(
85        source: L::Input,
86        ctx: &ParseContext,
87    ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Self> {
88        ParseBuilder::<L, Self>::new(source).context(ctx).parse()
89    }
90}
91
92pub type ParseResult<L, E, T> = Result<(T, ParseContext, L), ParseError<E>>;
94
95pub type ParseError<E> = lang_util::error::ParseError<E>;
97
98#[cfg(all(
100    feature = "lexer-v1",
101    not(any(feature = "lexer-v2-min", feature = "lexer-v2-full"))
102))]
103pub type DefaultLexer<'i> = glsl_lang_lexer::v1::Lexer<'i>;
104
105#[cfg(all(feature = "lexer-v2-min", not(feature = "lexer-v2-full")))]
107pub type DefaultLexer<'i> = glsl_lang_lexer::v2_min::str::Lexer<'i>;
108
109#[cfg(feature = "lexer-v2-full")]
111pub type DefaultLexer<'i> = glsl_lang_lexer::v2_full::str::Lexer<'i>;
112
113#[cfg(any(
115    feature = "lexer-v1",
116    feature = "lexer-v2-min",
117    feature = "lexer-v2-full"
118))]
119pub trait DefaultParse: Parse {
120    fn parse<'i>(
122        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
123    ) -> Result<Self, ParseError<<<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error>>;
124
125    fn parse_with_options<'i>(
127        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
128        opts: &ParseOptions,
129    ) -> ParseResult<
130        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
131        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
132        Self,
133    >;
134
135    fn parse_with_context<'i>(
137        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
138        ctx: &ParseContext,
139    ) -> ParseResult<
140        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
141        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
142        Self,
143    >;
144}
145
146#[cfg(any(
147    feature = "lexer-v1",
148    feature = "lexer-v2-min",
149    feature = "lexer-v2-full"
150))]
151impl<T: Parse> DefaultParse for T {
152    fn parse<'i>(
153        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
154    ) -> Result<Self, ParseError<<<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error>>
155    {
156        <T as Parse>::parse::<DefaultLexer<'i>>(source)
157    }
158
159    fn parse_with_options<'i>(
160        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
161        opts: &ParseOptions,
162    ) -> ParseResult<
163        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
164        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
165        Self,
166    > {
167        <T as Parse>::parse_with_options::<DefaultLexer<'i>>(source, opts)
168    }
169
170    fn parse_with_context<'i>(
171        source: <DefaultLexer<'i> as LangLexer<'i>>::Input,
172        ctx: &ParseContext,
173    ) -> ParseResult<
174        <DefaultLexer<'i> as LangLexer<'i>>::Iter,
175        <<DefaultLexer<'i> as LangLexer<'i>>::Iter as HasLexerError>::Error,
176        Self,
177    > {
178        <T as Parse>::parse_with_context::<DefaultLexer<'i>>(source, ctx)
179    }
180}
181
182macro_rules! impl_parse {
183    ($t:ty => $p:ty) => {
184        impl LangParser for $p {
185            type Item = $t;
186
187            fn new() -> Self {
188                <$p>::new()
189            }
190
191            fn parse<
192                L: HasLexerError
193                    + Iterator<Item = Result<(LexerPosition, Token, LexerPosition), L::Error>>,
194            >(
195                &self,
196                ctx: ParseContext,
197                input: &mut L,
198            ) -> Result<Self::Item, lalrpop_util::ParseError<LexerPosition, Token, L::Error>> {
199                self.parse::<L, _, _>(&ctx, input)
200            }
201        }
202
203        impl HasParser for $t {
204            type Parser = $p;
205        }
206    };
207}
208
209#[cfg(feature = "parser-expr")]
210impl_parse!(ast::Expr            => parser::ExprParser);
211#[cfg(feature = "parser-statement")]
212impl_parse!(ast::Statement       => parser::StatementParser);
213impl_parse!(ast::TranslationUnit => parser::TranslationUnitParser);