1use super::*;
2
3pub fn parse_schema<T: AsRef<str>>(input: T) -> Result<ServiceDocument> {
9 let mut pc = PositionCalculator::new(input.as_ref());
10 Ok(parse_service_document(
11 exactly_one(GraphQLParser::parse(
12 Rule::service_document,
13 input.as_ref(),
14 )?),
15 &mut pc,
16 )?)
17}
18
19fn parse_service_document(
20 pair: Pair<Rule>,
21 pc: &mut PositionCalculator,
22) -> Result<ServiceDocument> {
23 debug_assert_eq!(pair.as_rule(), Rule::service_document);
24
25 Ok(ServiceDocument {
26 definitions: pair
27 .into_inner()
28 .filter(|pair| pair.as_rule() != Rule::EOI)
29 .map(|pair| parse_type_system_definition(pair, pc))
30 .collect::<Result<_>>()?,
31 })
32}
33
34fn parse_type_system_definition(
35 pair: Pair<Rule>,
36 pc: &mut PositionCalculator,
37) -> Result<TypeSystemDefinition> {
38 debug_assert_eq!(pair.as_rule(), Rule::type_system_definition);
39
40 let pair = exactly_one(pair.into_inner());
41 Ok(match pair.as_rule() {
42 Rule::schema_definition => TypeSystemDefinition::Schema(parse_schema_definition(pair, pc)?),
43 Rule::type_definition => TypeSystemDefinition::Type(parse_type_definition(pair, pc)?),
44 Rule::directive_definition => {
45 TypeSystemDefinition::Directive(parse_directive_definition(pair, pc)?)
46 }
47 _ => unreachable!(),
48 })
49}
50
51fn parse_schema_definition(
52 pair: Pair<Rule>,
53 pc: &mut PositionCalculator,
54) -> Result<Positioned<SchemaDefinition>> {
55 debug_assert_eq!(pair.as_rule(), Rule::schema_definition);
56
57 let pos = pc.step(&pair);
58 let mut pairs = pair.into_inner();
59
60 let extend = next_if_rule(&mut pairs, Rule::extend).is_some();
61 let directives = parse_opt_const_directives(&mut pairs, pc)?;
62
63 let mut query = None;
64 let mut mutation = None;
65 let mut subscription = None;
66
67 for pair in pairs {
68 debug_assert_eq!(pair.as_rule(), Rule::operation_type_definition);
69
70 let mut pairs = pair.into_inner();
71
72 let operation_type = parse_operation_type(pairs.next().unwrap(), pc)?;
73 let name = parse_name(pairs.next().unwrap(), pc)?;
74
75 match operation_type.node {
76 OperationType::Query if query.is_none() => query = Some(name),
77 OperationType::Mutation if mutation.is_none() => mutation = Some(name),
78 OperationType::Subscription if subscription.is_none() => subscription = Some(name),
79 _ => {
80 return Err(Error::MultipleRoots {
81 root: operation_type.node,
82 schema: pos,
83 pos: operation_type.pos,
84 })
85 }
86 }
87
88 debug_assert_eq!(pairs.next(), None);
89 }
90
91 if !extend && query.is_none() {
92 return Err(Error::MissingQueryRoot { pos });
93 }
94
95 Ok(Positioned::new(
96 SchemaDefinition {
97 extend,
98 directives,
99 query,
100 mutation,
101 subscription,
102 },
103 pos,
104 ))
105}
106
107fn parse_type_definition(
108 pair: Pair<Rule>,
109 pc: &mut PositionCalculator,
110) -> Result<Positioned<TypeDefinition>> {
111 debug_assert_eq!(pair.as_rule(), Rule::type_definition);
112
113 let pos = pc.step(&pair);
114 let pair = exactly_one(pair.into_inner());
115 let rule = pair.as_rule();
116 let mut pairs = pair.into_inner();
117
118 let description = parse_if_rule(&mut pairs, Rule::string, |pair| parse_string(pair, pc))?;
119 let extend = next_if_rule(&mut pairs, Rule::extend).is_some();
120 let name = parse_name(pairs.next().unwrap(), pc)?;
121
122 let (directives, kind) = match rule {
123 Rule::scalar_type => {
124 let directives = parse_opt_const_directives(&mut pairs, pc)?;
125 (directives, TypeKind::Scalar)
126 }
127 Rule::object_type => {
128 let implements = parse_if_rule(&mut pairs, Rule::implements_interfaces, |pair| {
129 debug_assert_eq!(pair.as_rule(), Rule::implements_interfaces);
130
131 pair.into_inner()
132 .map(|pair| parse_name(pair, pc))
133 .collect::<Result<_>>()
134 })?;
135
136 let directives = parse_opt_const_directives(&mut pairs, pc)?;
137
138 let fields = parse_if_rule(&mut pairs, Rule::fields_definition, |pair| {
139 parse_fields_definition(pair, pc)
140 })?
141 .unwrap_or_default();
142
143 (
144 directives,
145 TypeKind::Object(ObjectType {
146 implements: implements.unwrap_or_default(),
147 fields,
148 }),
149 )
150 }
151 Rule::interface_type => {
152 let implements = parse_if_rule(&mut pairs, Rule::implements_interfaces, |pair| {
153 debug_assert_eq!(pair.as_rule(), Rule::implements_interfaces);
154
155 pair.into_inner()
156 .map(|pair| parse_name(pair, pc))
157 .collect::<Result<_>>()
158 })?;
159
160 let directives = parse_opt_const_directives(&mut pairs, pc)?;
161 let fields = parse_if_rule(&mut pairs, Rule::fields_definition, |pair| {
162 parse_fields_definition(pair, pc)
163 })?
164 .unwrap_or_default();
165 (
166 directives,
167 TypeKind::Interface(InterfaceType {
168 implements: implements.unwrap_or_default(),
169 fields,
170 }),
171 )
172 }
173 Rule::union_type => {
174 let directives = parse_opt_const_directives(&mut pairs, pc)?;
175 let members = parse_if_rule(&mut pairs, Rule::union_member_types, |pair| {
176 debug_assert_eq!(pair.as_rule(), Rule::union_member_types);
177
178 pair.into_inner().map(|pair| parse_name(pair, pc)).collect()
179 })?
180 .unwrap_or_default();
181 (directives, TypeKind::Union(UnionType { members }))
182 }
183 Rule::enum_type => {
184 let directives = parse_opt_const_directives(&mut pairs, pc)?;
185 let values = parse_if_rule(&mut pairs, Rule::enum_values, |pair| {
186 debug_assert_eq!(pair.as_rule(), Rule::enum_values);
187
188 pair.into_inner()
189 .map(|pair| {
190 debug_assert_eq!(pair.as_rule(), Rule::enum_value_definition);
191
192 let pos = pc.step(&pair);
193 let mut pairs = pair.into_inner();
194
195 let description =
196 parse_if_rule(&mut pairs, Rule::string, |pair| parse_string(pair, pc))?;
197 let value = parse_enum_value(pairs.next().unwrap(), pc)?;
198 let directives = parse_opt_const_directives(&mut pairs, pc)?;
199
200 debug_assert_eq!(pairs.next(), None);
201
202 Ok(Positioned::new(
203 EnumValueDefinition {
204 description,
205 value,
206 directives,
207 },
208 pos,
209 ))
210 })
211 .collect()
212 })?
213 .unwrap_or_default();
214 (directives, TypeKind::Enum(EnumType { values }))
215 }
216 Rule::input_object_type => {
217 let directives = parse_opt_const_directives(&mut pairs, pc)?;
218 let fields = parse_if_rule(&mut pairs, Rule::input_fields_definition, |pair| {
219 debug_assert_eq!(pair.as_rule(), Rule::input_fields_definition);
220
221 pair.into_inner()
222 .map(|pair| parse_input_value_definition(pair, pc))
223 .collect()
224 })?
225 .unwrap_or_default();
226
227 (
228 directives,
229 TypeKind::InputObject(InputObjectType { fields }),
230 )
231 }
232 _ => unreachable!(),
233 };
234
235 debug_assert_eq!(pairs.next(), None);
236
237 Ok(Positioned::new(
238 TypeDefinition {
239 extend,
240 description,
241 name,
242 directives,
243 kind,
244 },
245 pos,
246 ))
247}
248
249fn parse_fields_definition(
250 pair: Pair<Rule>,
251 pc: &mut PositionCalculator,
252) -> Result<Vec<Positioned<FieldDefinition>>> {
253 debug_assert_eq!(pair.as_rule(), Rule::fields_definition);
254
255 pair.into_inner()
256 .map(|pair| parse_field_definition(pair, pc))
257 .collect()
258}
259
260fn parse_field_definition(
261 pair: Pair<Rule>,
262 pc: &mut PositionCalculator,
263) -> Result<Positioned<FieldDefinition>> {
264 debug_assert_eq!(pair.as_rule(), Rule::field_definition);
265
266 let pos = pc.step(&pair);
267 let mut pairs = pair.into_inner();
268
269 let description = parse_if_rule(&mut pairs, Rule::string, |pair| parse_string(pair, pc))?;
270 let name = parse_name(pairs.next().unwrap(), pc)?;
271 let arguments = parse_if_rule(&mut pairs, Rule::arguments_definition, |pair| {
272 parse_arguments_definition(pair, pc)
273 })?
274 .unwrap_or_default();
275 let ty = parse_type(pairs.next().unwrap(), pc)?;
276 let directives = parse_opt_const_directives(&mut pairs, pc)?;
277
278 debug_assert_eq!(pairs.next(), None);
279
280 Ok(Positioned::new(
281 FieldDefinition {
282 description,
283 name,
284 arguments,
285 ty,
286 directives,
287 },
288 pos,
289 ))
290}
291
292fn parse_directive_definition(
293 pair: Pair<Rule>,
294 pc: &mut PositionCalculator,
295) -> Result<Positioned<DirectiveDefinition>> {
296 debug_assert_eq!(pair.as_rule(), Rule::directive_definition);
297
298 let pos = pc.step(&pair);
299 let mut pairs = pair.into_inner();
300
301 let description = parse_if_rule(&mut pairs, Rule::string, |pair| parse_string(pair, pc))?;
302 let name = parse_name(pairs.next().unwrap(), pc)?;
303 let arguments = parse_if_rule(&mut pairs, Rule::arguments_definition, |pair| {
304 debug_assert_eq!(pair.as_rule(), Rule::arguments_definition);
305 pair.into_inner()
306 .map(|pair| parse_input_value_definition(pair, pc))
307 .collect()
308 })?
309 .unwrap_or_default();
310 let is_repeatable = parse_if_rule(&mut pairs, Rule::repeatable, |pair| {
311 debug_assert_eq!(pair.as_rule(), Rule::repeatable);
312 Ok(())
313 })
314 .unwrap_or_default()
315 .is_some();
316 let locations = {
317 let pair = pairs.next().unwrap();
318 debug_assert_eq!(pair.as_rule(), Rule::directive_locations);
319 pair.into_inner()
320 .map(|pair| {
321 let pos = pc.step(&pair);
322 debug_assert_eq!(pair.as_rule(), Rule::directive_location);
323 Positioned::new(
324 match pair.as_str() {
325 "QUERY" => DirectiveLocation::Query,
326 "MUTATION" => DirectiveLocation::Mutation,
327 "SUBSCRIPTION" => DirectiveLocation::Subscription,
328 "FIELD" => DirectiveLocation::Field,
329 "FRAGMENT_DEFINITION" => DirectiveLocation::FragmentDefinition,
330 "FRAGMENT_SPREAD" => DirectiveLocation::FragmentSpread,
331 "INLINE_FRAGMENT" => DirectiveLocation::InlineFragment,
332 "VARIABLE_DEFINITION" => DirectiveLocation::VariableDefinition,
333 "SCHEMA" => DirectiveLocation::Schema,
334 "SCALAR" => DirectiveLocation::Scalar,
335 "OBJECT" => DirectiveLocation::Object,
336 "FIELD_DEFINITION" => DirectiveLocation::FieldDefinition,
337 "ARGUMENT_DEFINITION" => DirectiveLocation::ArgumentDefinition,
338 "INTERFACE" => DirectiveLocation::Interface,
339 "UNION" => DirectiveLocation::Union,
340 "ENUM" => DirectiveLocation::Enum,
341 "ENUM_VALUE" => DirectiveLocation::EnumValue,
342 "INPUT_OBJECT" => DirectiveLocation::InputObject,
343 "INPUT_FIELD_DEFINITION" => DirectiveLocation::InputFieldDefinition,
344 _ => unreachable!(),
345 },
346 pos,
347 )
348 })
349 .collect()
350 };
351
352 debug_assert_eq!(pairs.next(), None);
353
354 Ok(Positioned::new(
355 DirectiveDefinition {
356 description,
357 name,
358 arguments,
359 is_repeatable,
360 locations,
361 },
362 pos,
363 ))
364}
365
366fn parse_arguments_definition(
367 pair: Pair<Rule>,
368 pc: &mut PositionCalculator,
369) -> Result<Vec<Positioned<InputValueDefinition>>> {
370 debug_assert_eq!(pair.as_rule(), Rule::arguments_definition);
371
372 pair.into_inner()
373 .map(|pair| parse_input_value_definition(pair, pc))
374 .collect()
375}
376
377fn parse_input_value_definition(
378 pair: Pair<Rule>,
379 pc: &mut PositionCalculator,
380) -> Result<Positioned<InputValueDefinition>> {
381 debug_assert_eq!(pair.as_rule(), Rule::input_value_definition);
382
383 let pos = pc.step(&pair);
384 let mut pairs = pair.into_inner();
385
386 let description = parse_if_rule(&mut pairs, Rule::string, |pair| parse_string(pair, pc))?;
387 let name = parse_name(pairs.next().unwrap(), pc)?;
388 let ty = parse_type(pairs.next().unwrap(), pc)?;
389 let default_value = parse_if_rule(&mut pairs, Rule::default_value, |pair| {
390 parse_default_value(pair, pc)
391 })?;
392 let directives = parse_opt_const_directives(&mut pairs, pc)?;
393
394 Ok(Positioned::new(
395 InputValueDefinition {
396 description,
397 name,
398 ty,
399 default_value,
400 directives,
401 },
402 pos,
403 ))
404}
405
406#[cfg(test)]
407mod tests {
408 use std::fs;
409
410 use super::*;
411
412 #[test]
413 fn test_parser() {
414 for entry in fs::read_dir("tests/services").unwrap() {
415 let entry = entry.unwrap();
416 eprintln!("Parsing file {}", entry.path().display());
417 GraphQLParser::parse(
418 Rule::service_document,
419 &fs::read_to_string(entry.path()).unwrap(),
420 )
421 .unwrap();
422 }
423 }
424
425 #[test]
426 fn test_parser_ast() {
427 for entry in fs::read_dir("tests/services").unwrap() {
428 let entry = entry.unwrap();
429 parse_schema(fs::read_to_string(entry.path()).unwrap()).unwrap();
430 }
431 }
432}