1use super::*;
2
3const MAX_RECURSION_DEPTH: usize = 64;
4
5macro_rules! recursion_depth {
6 ($remaining_depth:ident) => {{
7 if $remaining_depth == 0 {
8 return Err(Error::RecursionLimitExceeded);
9 }
10 $remaining_depth - 1
11 }};
12}
13
14pub fn parse_query<T: AsRef<str>>(input: T) -> Result<ExecutableDocument> {
20 let mut pc = PositionCalculator::new(input.as_ref());
21
22 let pairs = GraphQLParser::parse(Rule::executable_document, input.as_ref())?;
23 let items = parse_definition_items(exactly_one(pairs), &mut pc)?;
24
25 let mut operations = None;
26 let mut fragments: HashMap<_, Positioned<FragmentDefinition>> = HashMap::new();
27
28 for item in items {
29 match item {
30 DefinitionItem::Operation(item) => {
31 if let Some(name) = item.node.name {
32 let operations = operations
33 .get_or_insert_with(|| DocumentOperations::Multiple(HashMap::new()));
34 let operations = match operations {
35 DocumentOperations::Single(anonymous) => {
36 return Err(Error::MultipleOperations {
37 anonymous: anonymous.pos,
38 operation: item.pos,
39 })
40 }
41 DocumentOperations::Multiple(operations) => operations,
42 };
43
44 match operations.entry(name.node) {
45 hash_map::Entry::Occupied(entry) => {
46 let (name, first) = entry.remove_entry();
47 return Err(Error::OperationDuplicated {
48 operation: name,
49 first: first.pos,
50 second: item.pos,
51 });
52 }
53 hash_map::Entry::Vacant(entry) => {
54 entry.insert(Positioned::new(item.node.definition, item.pos));
55 }
56 }
57 } else {
58 match operations {
59 Some(operations) => {
60 return Err(Error::MultipleOperations {
61 anonymous: item.pos,
62 operation: match operations {
63 DocumentOperations::Single(single) => single.pos,
64 DocumentOperations::Multiple(map) => {
65 map.values().next().unwrap().pos
66 }
67 },
68 });
69 }
70 None => {
71 operations = Some(DocumentOperations::Single(Positioned::new(
72 item.node.definition,
73 item.pos,
74 )));
75 }
76 }
77 }
78 }
79 DefinitionItem::Fragment(item) => match fragments.entry(item.node.name.node) {
80 hash_map::Entry::Occupied(entry) => {
81 let (name, first) = entry.remove_entry();
82 return Err(Error::FragmentDuplicated {
83 fragment: name,
84 first: first.pos,
85 second: item.pos,
86 });
87 }
88 hash_map::Entry::Vacant(entry) => {
89 entry.insert(Positioned::new(item.node.definition, item.pos));
90 }
91 },
92 }
93 }
94
95 Ok(ExecutableDocument {
96 operations: operations.ok_or(Error::MissingOperation)?,
97 fragments,
98 })
99}
100
101fn parse_definition_items(
102 pair: Pair<Rule>,
103 pc: &mut PositionCalculator,
104) -> Result<Vec<DefinitionItem>> {
105 debug_assert_eq!(pair.as_rule(), Rule::executable_document);
106
107 Ok(pair
108 .into_inner()
109 .filter(|pair| pair.as_rule() != Rule::EOI)
110 .map(|pair| parse_definition_item(pair, pc))
111 .collect::<Result<_>>()?)
112}
113
114enum DefinitionItem {
115 Operation(Positioned<OperationDefinitionItem>),
116 Fragment(Positioned<FragmentDefinitionItem>),
117}
118
119fn parse_definition_item(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<DefinitionItem> {
120 debug_assert_eq!(pair.as_rule(), Rule::executable_definition);
121
122 let pair = exactly_one(pair.into_inner());
123 Ok(match pair.as_rule() {
124 Rule::operation_definition => {
125 DefinitionItem::Operation(parse_operation_definition_item(pair, pc)?)
126 }
127 Rule::fragment_definition => {
128 DefinitionItem::Fragment(parse_fragment_definition_item(pair, pc)?)
129 }
130 _ => unreachable!(),
131 })
132}
133
134struct OperationDefinitionItem {
135 name: Option<Positioned<Name>>,
136 definition: OperationDefinition,
137}
138
139fn parse_operation_definition_item(
140 pair: Pair<Rule>,
141 pc: &mut PositionCalculator,
142) -> Result<Positioned<OperationDefinitionItem>> {
143 debug_assert_eq!(pair.as_rule(), Rule::operation_definition);
144
145 let pos = pc.step(&pair);
146 let pair = exactly_one(pair.into_inner());
147 Ok(Positioned::new(
148 match pair.as_rule() {
149 Rule::named_operation_definition => parse_named_operation_definition(pair, pc)?,
150 Rule::selection_set => OperationDefinitionItem {
151 name: None,
152 definition: OperationDefinition {
153 ty: OperationType::Query,
154 variable_definitions: Vec::new(),
155 directives: Vec::new(),
156 selection_set: parse_selection_set(pair, pc, MAX_RECURSION_DEPTH)?,
157 },
158 },
159 _ => unreachable!(),
160 },
161 pos,
162 ))
163}
164
165fn parse_named_operation_definition(
166 pair: Pair<Rule>,
167 pc: &mut PositionCalculator,
168) -> Result<OperationDefinitionItem> {
169 debug_assert_eq!(pair.as_rule(), Rule::named_operation_definition);
170
171 let mut pairs = pair.into_inner();
172
173 let ty = parse_operation_type(pairs.next().unwrap(), pc)?;
174 let name = parse_if_rule(&mut pairs, Rule::name, |pair| parse_name(pair, pc))?;
175 let variable_definitions = parse_if_rule(&mut pairs, Rule::variable_definitions, |pair| {
176 parse_variable_definitions(pair, pc)
177 })?;
178 let directives = parse_opt_directives(&mut pairs, pc)?;
179 let selection_set = parse_selection_set(pairs.next().unwrap(), pc, MAX_RECURSION_DEPTH)?;
180
181 debug_assert_eq!(pairs.next(), None);
182
183 Ok(OperationDefinitionItem {
184 name,
185 definition: OperationDefinition {
186 ty: ty.node,
187 variable_definitions: variable_definitions.unwrap_or_default(),
188 directives,
189 selection_set,
190 },
191 })
192}
193
194fn parse_variable_definitions(
195 pair: Pair<Rule>,
196 pc: &mut PositionCalculator,
197) -> Result<Vec<Positioned<VariableDefinition>>> {
198 debug_assert_eq!(pair.as_rule(), Rule::variable_definitions);
199
200 pair.into_inner()
201 .map(|pair| parse_variable_definition(pair, pc))
202 .collect()
203}
204
205fn parse_variable_definition(
206 pair: Pair<Rule>,
207 pc: &mut PositionCalculator,
208) -> Result<Positioned<VariableDefinition>> {
209 debug_assert_eq!(pair.as_rule(), Rule::variable_definition);
210
211 let pos = pc.step(&pair);
212 let mut pairs = pair.into_inner();
213
214 let variable = parse_variable(pairs.next().unwrap(), pc)?;
215 let var_type = parse_type(pairs.next().unwrap(), pc)?;
216
217 let directives = parse_opt_directives(&mut pairs, pc)?;
218 let default_value = parse_if_rule(&mut pairs, Rule::default_value, |pair| {
219 parse_default_value(pair, pc)
220 })?;
221
222 debug_assert_eq!(pairs.next(), None);
223
224 Ok(Positioned::new(
225 VariableDefinition {
226 name: variable,
227 var_type,
228 directives,
229 default_value,
230 },
231 pos,
232 ))
233}
234
235fn parse_selection_set(
236 pair: Pair<Rule>,
237 pc: &mut PositionCalculator,
238 remaining_depth: usize,
239) -> Result<Positioned<SelectionSet>> {
240 debug_assert_eq!(pair.as_rule(), Rule::selection_set);
241
242 let pos = pc.step(&pair);
243
244 Ok(Positioned::new(
245 SelectionSet {
246 items: pair
247 .into_inner()
248 .map(|pair| parse_selection(pair, pc, remaining_depth))
249 .collect::<Result<_>>()?,
250 },
251 pos,
252 ))
253}
254
255fn parse_selection(
256 pair: Pair<Rule>,
257 pc: &mut PositionCalculator,
258 remaining_depth: usize,
259) -> Result<Positioned<Selection>> {
260 debug_assert_eq!(pair.as_rule(), Rule::selection);
261
262 let pos = pc.step(&pair);
263 let pair = exactly_one(pair.into_inner());
264
265 Ok(Positioned::new(
266 match pair.as_rule() {
267 Rule::field => Selection::Field(parse_field(pair, pc, remaining_depth)?),
268 Rule::fragment_spread => Selection::FragmentSpread(parse_fragment_spread(pair, pc)?),
269 Rule::inline_fragment => {
270 Selection::InlineFragment(parse_inline_fragment(pair, pc, remaining_depth)?)
271 }
272 _ => unreachable!(),
273 },
274 pos,
275 ))
276}
277
278fn parse_field(
279 pair: Pair<Rule>,
280 pc: &mut PositionCalculator,
281 remaining_depth: usize,
282) -> Result<Positioned<Field>> {
283 debug_assert_eq!(pair.as_rule(), Rule::field);
284
285 let pos = pc.step(&pair);
286 let mut pairs = pair.into_inner();
287
288 let alias = parse_if_rule(&mut pairs, Rule::alias, |pair| parse_alias(pair, pc))?;
289 let name = parse_name(pairs.next().unwrap(), pc)?;
290 let arguments = parse_if_rule(&mut pairs, Rule::arguments, |pair| {
291 parse_arguments(pair, pc)
292 })?;
293 let directives = parse_opt_directives(&mut pairs, pc)?;
294 let selection_set = parse_if_rule(&mut pairs, Rule::selection_set, |pair| {
295 parse_selection_set(pair, pc, recursion_depth!(remaining_depth))
296 })?;
297
298 debug_assert_eq!(pairs.next(), None);
299
300 Ok(Positioned::new(
301 Field {
302 alias,
303 name,
304 arguments: arguments.unwrap_or_default(),
305 directives,
306 selection_set: selection_set.unwrap_or_default(),
307 },
308 pos,
309 ))
310}
311
312fn parse_alias(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<Positioned<Name>> {
313 debug_assert_eq!(pair.as_rule(), Rule::alias);
314 parse_name(exactly_one(pair.into_inner()), pc)
315}
316
317fn parse_fragment_spread(
318 pair: Pair<Rule>,
319 pc: &mut PositionCalculator,
320) -> Result<Positioned<FragmentSpread>> {
321 debug_assert_eq!(pair.as_rule(), Rule::fragment_spread);
322
323 let pos = pc.step(&pair);
324 let mut pairs = pair.into_inner();
325
326 let fragment_name = parse_name(pairs.next().unwrap(), pc)?;
327 let directives = parse_opt_directives(&mut pairs, pc)?;
328
329 debug_assert_eq!(pairs.next(), None);
330
331 Ok(Positioned::new(
332 FragmentSpread {
333 fragment_name,
334 directives,
335 },
336 pos,
337 ))
338}
339
340fn parse_inline_fragment(
341 pair: Pair<Rule>,
342 pc: &mut PositionCalculator,
343 remaining_depth: usize,
344) -> Result<Positioned<InlineFragment>> {
345 debug_assert_eq!(pair.as_rule(), Rule::inline_fragment);
346
347 let pos = pc.step(&pair);
348 let mut pairs = pair.into_inner();
349
350 let type_condition = parse_if_rule(&mut pairs, Rule::type_condition, |pair| {
351 parse_type_condition(pair, pc)
352 })?;
353 let directives = parse_opt_directives(&mut pairs, pc)?;
354 let selection_set =
355 parse_selection_set(pairs.next().unwrap(), pc, recursion_depth!(remaining_depth))?;
356
357 debug_assert_eq!(pairs.next(), None);
358
359 Ok(Positioned::new(
360 InlineFragment {
361 type_condition,
362 directives,
363 selection_set,
364 },
365 pos,
366 ))
367}
368
369struct FragmentDefinitionItem {
370 name: Positioned<Name>,
371 definition: FragmentDefinition,
372}
373
374fn parse_fragment_definition_item(
375 pair: Pair<Rule>,
376 pc: &mut PositionCalculator,
377) -> Result<Positioned<FragmentDefinitionItem>> {
378 debug_assert_eq!(pair.as_rule(), Rule::fragment_definition);
379
380 let pos = pc.step(&pair);
381 let mut pairs = pair.into_inner();
382
383 let name = parse_name(pairs.next().unwrap(), pc)?;
384 let type_condition = parse_type_condition(pairs.next().unwrap(), pc)?;
385 let directives = parse_opt_directives(&mut pairs, pc)?;
386 let selection_set = parse_selection_set(pairs.next().unwrap(), pc, MAX_RECURSION_DEPTH)?;
387
388 debug_assert_eq!(pairs.next(), None);
389
390 Ok(Positioned::new(
391 FragmentDefinitionItem {
392 name,
393 definition: FragmentDefinition {
394 type_condition,
395 directives,
396 selection_set,
397 },
398 },
399 pos,
400 ))
401}
402
403fn parse_type_condition(
404 pair: Pair<Rule>,
405 pc: &mut PositionCalculator,
406) -> Result<Positioned<TypeCondition>> {
407 debug_assert_eq!(pair.as_rule(), Rule::type_condition);
408
409 let pos = pc.step(&pair);
410 Ok(Positioned::new(
411 TypeCondition {
412 on: parse_name(exactly_one(pair.into_inner()), pc)?,
413 },
414 pos,
415 ))
416}
417
418#[cfg(test)]
419mod tests {
420 use std::fs;
421
422 use super::*;
423
424 #[test]
425 fn test_parser() {
426 for entry in fs::read_dir("tests/executables").unwrap() {
427 let entry = entry.unwrap();
428 eprintln!("Parsing file {}", entry.path().display());
429
430 GraphQLParser::parse(
431 Rule::executable_document,
432 &fs::read_to_string(entry.path()).unwrap(),
433 )
434 .unwrap();
435 }
436 }
437
438 #[test]
439 fn test_parser_ast() {
440 for entry in fs::read_dir("tests/executables").unwrap() {
441 let entry = entry.unwrap();
442 eprintln!("Parsing and transforming file {}", entry.path().display());
443 parse_query(fs::read_to_string(entry.path()).unwrap()).unwrap();
444 }
445 }
446
447 #[test]
448 fn test_parse_overflowing_int() {
449 let query_ok = format!("mutation {{ add(big: {}) }} ", i32::MAX);
450 let query_overflow = format!("mutation {{ add(big: {}0000) }} ", i32::MAX);
451 assert!(parse_query(query_ok).is_ok());
452 assert!(parse_query(query_overflow).is_ok());
453 }
454}