1use glsl_lang_lexer::{HasLexerError, LangLexerIterator, ParseOptions};
4
5use super::{Extractable, HasParser, LangLexer, LangParser, ParseContext, ParseResult};
6
7pub struct ParseBuilder<'i, 'o, 'c, 'p, L: LangLexer<'i>, T: HasParser> {
9 source: L::Input,
10 opts: Option<&'o ParseOptions>,
11 context: Option<&'c ParseContext>,
12 lexer: Option<L>,
13 parser: Option<&'p T::Parser>,
14}
15
16impl<'i, 'o, 'c, 'p, L: LangLexer<'i>, T: HasParser> ParseBuilder<'i, 'o, 'c, 'p, L, T> {
17 pub fn new(source: L::Input) -> Self {
19 Self {
20 source,
21 opts: None,
22 context: None,
23 lexer: None,
24 parser: None,
25 }
26 }
27
28 pub fn opts(self, opts: &'o ParseOptions) -> Self {
30 Self {
31 opts: Some(opts),
32 ..self
33 }
34 }
35
36 pub fn context(self, ctx: &'c ParseContext) -> Self {
38 Self {
39 context: Some(ctx),
40 ..self
41 }
42 }
43
44 pub fn parser(self, parser: &'p T::Parser) -> Self {
46 Self {
47 parser: Some(parser),
48 ..self
49 }
50 }
51
52 #[allow(clippy::result_large_err)]
54 fn parse_source(
55 source: L::Input,
56 opts: Option<&'o ParseOptions>,
57 mut context: Option<&'c ParseContext>,
58 mut lexer: Option<L>,
59 mut parser: Option<&'p T::Parser>,
60 ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, T> {
61 let default_opts = Default::default();
63 let opts = opts.unwrap_or(&default_opts);
64
65 let cloned_context = if let Some(existing) = context.take() {
67 existing.clone_inner()
68 } else {
69 Default::default()
70 };
71
72 let lexer = if let Some(lexer) = lexer.take() {
74 lexer
75 } else {
76 L::new(source, opts)
77 };
78
79 let created_parser;
81 let parser = if let Some(parser) = parser.take() {
82 parser
83 } else {
84 created_parser = <T as HasParser>::Parser::new();
85 &created_parser
86 };
87
88 let mut iter = lexer.run(cloned_context.clone());
90 match parser.parse(cloned_context.clone(), &mut iter) {
91 Ok(t) => Ok((t, cloned_context, iter)),
92 Err(err) => Err(iter.resolve_err(err)),
93 }
94 }
95
96 #[allow(clippy::result_large_err)]
98 pub fn parse(self) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, T> {
99 Self::parse_source(
100 self.source,
101 self.opts,
102 self.context,
103 self.lexer,
104 self.parser,
105 )
106 }
107
108 #[allow(clippy::result_large_err)]
110 pub fn extract<U: Extractable<T>>(
111 self,
112 ) -> ParseResult<L::Iter, <L::Iter as HasLexerError>::Error, Option<U>> {
113 Self::parse_source(
114 self.source,
115 self.opts,
116 self.context,
117 self.lexer,
118 self.parser,
119 )
120 .map(|(root, ctx, l)| (U::extract(root), ctx, l))
121 }
122}
123
124impl<'i, 'o, 'c, 'p, T: HasParser> ParseBuilder<'i, 'o, 'c, 'p, super::DefaultLexer<'i>, T> {
125 pub fn default(source: <super::DefaultLexer<'i> as LangLexer<'i>>::Input) -> Self {
127 Self {
128 source,
129 opts: None,
130 context: None,
131 lexer: None,
132 parser: None,
133 }
134 }
135}
136
137pub trait IntoParseBuilderExt<'i> {
139 type Lexer: LangLexer<'i>;
141
142 fn builder<'o, 'c, 'p, T>(self) -> ParseBuilder<'i, 'o, 'c, 'p, Self::Lexer, T>
144 where
145 T: HasParser;
146}
147
148impl<'i> IntoParseBuilderExt<'i> for &'i str {
149 type Lexer = super::DefaultLexer<'i>;
150
151 fn builder<'o, 'c, 'p, T>(self) -> ParseBuilder<'i, 'o, 'c, 'p, Self::Lexer, T>
152 where
153 T: HasParser,
154 {
155 ParseBuilder::default(self)
156 }
157}
158
159#[cfg(feature = "lexer-full")]
160impl<'r, 'p, F: glsl_lang_lexer::full::fs::FileSystem> IntoParseBuilderExt<'p>
161 for glsl_lang_lexer::full::fs::File<'r, 'p, F>
162where
163 glsl_lang_lexer::full::fs::File<'r, 'p, F>: 'p,
164{
165 type Lexer = glsl_lang_lexer::full::fs::Lexer<'r, 'p, F>;
166
167 fn builder<'o, 'c, 'q, T>(self) -> ParseBuilder<'p, 'o, 'c, 'q, Self::Lexer, T>
168 where
169 T: HasParser,
170 {
171 ParseBuilder::new(self)
172 }
173}