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);