glsl_lang/parse/
parsable.rs

1use std::borrow::Cow;
2
3use crate::ast;
4
5#[cfg(any(
6    feature = "lexer-v1",
7    feature = "lexer-v2-min",
8    feature = "lexer-v2-full"
9))]
10use super::{DefaultLexer, HasLexerError, ParseContext, ParseError, ParseOptions};
11
12/// A parsable is something we can parse either directly, or embedded in some other syntax
13/// structure.
14///
15/// This allows us to parse specific AST items even though we don't export a LALR parser for it.
16/// Due to the way it is currently implemented, we have to generate extra code around the input,
17/// thus, if you are matching on span positions, you will get a different result than if using the
18/// parser directly.
19#[cfg(any(
20    feature = "lexer-v1",
21    feature = "lexer-v2-min",
22    feature = "lexer-v2-full"
23))]
24pub trait Parsable: Sized {
25    /// Parse the input source
26    fn parse(source: &str) -> Result<Self, ParseError<<DefaultLexer as HasLexerError>::Error>> {
27        <Self as Parsable>::parse_with_options(source, &Default::default())
28            .map(|(parsed, _names)| parsed)
29    }
30
31    /// Parse the input source with the given options
32    fn parse_with_options<'i>(
33        source: &'i str,
34        opts: &ParseOptions,
35    ) -> Result<(Self, ParseContext), ParseError<<DefaultLexer<'i> as HasLexerError>::Error>>;
36
37    /// Parse the input source with the given context
38    fn parse_with_context<'i>(
39        source: &'i str,
40        ctx: &ParseContext,
41    ) -> Result<(Self, ParseContext), ParseError<<DefaultLexer<'i> as HasLexerError>::Error>>;
42}
43
44#[cfg(any(
45    feature = "lexer-v1",
46    feature = "lexer-v2-min",
47    feature = "lexer-v2-full"
48))]
49impl<T: Extractable<ast::TranslationUnit>> Parsable for T {
50    fn parse_with_options<'i>(
51        source: &'i str,
52        opts: &ParseOptions,
53    ) -> Result<(Self, ParseContext), ParseError<<DefaultLexer<'i> as HasLexerError>::Error>> {
54        <ast::TranslationUnit as super::DefaultParse>::parse_with_options(&Self::wrap(source), opts)
55            .map(|(tu, oo, _lexer)| (Self::extract(tu).expect("invalid parse result"), oo))
56    }
57
58    fn parse_with_context<'i>(
59        source: &'i str,
60        ctx: &ParseContext,
61    ) -> Result<(Self, ParseContext), ParseError<<DefaultLexer<'i> as HasLexerError>::Error>> {
62        <ast::TranslationUnit as super::DefaultParse>::parse_with_context(&Self::wrap(source), ctx)
63            .map(|(tu, oo, _lexer)| (Self::extract(tu).expect("invalid parse result"), oo))
64    }
65}
66
67/// Part of the syntax tree that can be extracted from a parent tree
68pub trait Extractable<R>: Sized {
69    /// Wrap the given source which parses as Self into something that parses as R
70    fn wrap(source: &str) -> Cow<str>;
71    /// Extract the subtree for Self from a parent tree R
72    fn extract(tu: R) -> Option<Self>;
73}
74
75impl Extractable<ast::TranslationUnit> for ast::TranslationUnit {
76    fn wrap(source: &str) -> Cow<str> {
77        source.into()
78    }
79
80    fn extract(tu: ast::TranslationUnit) -> Option<Self> {
81        Some(tu)
82    }
83}
84
85impl Extractable<ast::TranslationUnit> for ast::FunctionDefinition {
86    fn wrap(source: &str) -> Cow<str> {
87        source.into()
88    }
89
90    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
91        if let ast::Node {
92            content: ast::ExternalDeclarationData::FunctionDefinition(fndef),
93            ..
94        } = extdecls.into_iter().next().unwrap()
95        {
96            return Some(fndef);
97        }
98
99        None
100    }
101}
102
103impl Extractable<ast::TranslationUnit> for ast::UnaryOp {
104    fn wrap(source: &str) -> Cow<str> {
105        format!("void main() {{ {}x; }}", source).into()
106    }
107
108    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
109        if let ast::Node {
110            content:
111                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
112                    content:
113                        ast::FunctionDefinitionData {
114                            statement:
115                                ast::Node {
116                                    content: ast::CompoundStatementData { statement_list, .. },
117                                    ..
118                                },
119                            ..
120                        },
121                    ..
122                }),
123            ..
124        } = extdecls.into_iter().next().unwrap()
125        {
126            if let ast::StatementData::Expression(ast::ExprStatement {
127                content:
128                    ast::ExprStatementData(Some(ast::Expr {
129                        content: ast::ExprData::Unary(u, _),
130                        ..
131                    })),
132                ..
133            }) = statement_list.into_iter().next().unwrap().into_inner()
134            {
135                return Some(u);
136            }
137        }
138
139        None
140    }
141}
142
143impl Extractable<ast::TranslationUnit> for ast::AssignmentOp {
144    fn wrap(source: &str) -> Cow<str> {
145        format!("void main() {{ x {} 2; }}", source).into()
146    }
147
148    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
149        if let ast::Node {
150            content:
151                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
152                    content:
153                        ast::FunctionDefinitionData {
154                            statement:
155                                ast::Node {
156                                    content: ast::CompoundStatementData { statement_list, .. },
157                                    ..
158                                },
159                            ..
160                        },
161                    ..
162                }),
163            ..
164        } = extdecls.into_iter().next().unwrap()
165        {
166            if let ast::StatementData::Expression(ast::ExprStatement {
167                content:
168                    ast::ExprStatementData(Some(ast::Expr {
169                        content: ast::ExprData::Assignment(_, o, _),
170                        ..
171                    })),
172                ..
173            }) = statement_list.into_iter().next().unwrap().into_inner()
174            {
175                return Some(o);
176            }
177        }
178
179        None
180    }
181}
182
183macro_rules! impl_parsable_statement {
184    ($i:ident => $t:ty) => {
185        impl Extractable<ast::TranslationUnit> for $t {
186            fn wrap(source: &str) -> Cow<str> {
187                format!("void main() {{ {} }}", source).into()
188            }
189
190            fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
191                if let ast::Node {
192                    content:
193                        ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
194                            content:
195                                ast::FunctionDefinitionData {
196                                    statement:
197                                        ast::Node {
198                                            content:
199                                                ast::CompoundStatementData { statement_list, .. },
200                                            ..
201                                        },
202                                    ..
203                                },
204                            ..
205                        }),
206                    ..
207                } = extdecls.into_iter().next().unwrap()
208                {
209                    if let ast::StatementData::$i(expr) =
210                        statement_list.into_iter().next().unwrap().into_inner()
211                    {
212                        return Some(expr);
213                    }
214                }
215
216                None
217            }
218        }
219    };
220}
221
222impl_parsable_statement!(Expression => ast::ExprStatement);
223impl_parsable_statement!(Selection => ast::SelectionStatement);
224impl_parsable_statement!(Switch => ast::SwitchStatement);
225impl_parsable_statement!(CaseLabel => ast::CaseLabel);
226impl_parsable_statement!(Iteration => ast::IterationStatement);
227impl_parsable_statement!(Jump => ast::JumpStatement);
228impl_parsable_statement!(Compound => ast::CompoundStatement);
229
230impl Extractable<ast::TranslationUnit> for ast::ArraySpecifierDimension {
231    fn wrap(source: &str) -> Cow<str> {
232        format!("void main() {{ vec2{}(); }}", source).into()
233    }
234
235    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
236        if let ast::Node {
237            content:
238                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
239                    content:
240                        ast::FunctionDefinitionData {
241                            statement:
242                                ast::Node {
243                                    content: ast::CompoundStatementData { statement_list, .. },
244                                    ..
245                                },
246                            ..
247                        },
248                    ..
249                }),
250            ..
251        } = extdecls.into_iter().next().unwrap()
252        {
253            if let ast::StatementData::Expression(ast::ExprStatement {
254                content:
255                    ast::ExprStatementData(Some(ast::Expr {
256                        content:
257                            ast::ExprData::FunCall(
258                                ast::FunIdentifier {
259                                    content: ast::FunIdentifierData::TypeSpecifier(type_specifier),
260                                    ..
261                                },
262                                _,
263                            ),
264                        ..
265                    })),
266                ..
267            }) = statement_list.into_iter().next().unwrap().into_inner()
268            {
269                if let ast::TypeSpecifier {
270                    content:
271                        ast::TypeSpecifierData {
272                            array_specifier: Some(ast::ArraySpecifier { content: array, .. }),
273                            ..
274                        },
275                    ..
276                } = *type_specifier
277                {
278                    return array.dimensions.into_iter().next();
279                }
280            }
281        }
282
283        None
284    }
285}
286
287impl Extractable<ast::TranslationUnit> for ast::ArraySpecifier {
288    fn wrap(source: &str) -> Cow<str> {
289        format!("void main() {{ vec2{}(); }}", source).into()
290    }
291
292    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
293        if let ast::Node {
294            content:
295                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
296                    content:
297                        ast::FunctionDefinitionData {
298                            statement:
299                                ast::Node {
300                                    content: ast::CompoundStatementData { statement_list, .. },
301                                    ..
302                                },
303                            ..
304                        },
305                    ..
306                }),
307            ..
308        } = extdecls.into_iter().next().unwrap()
309        {
310            if let ast::StatementData::Expression(ast::ExprStatement {
311                content:
312                    ast::ExprStatementData(Some(ast::Expr {
313                        content:
314                            ast::ExprData::FunCall(
315                                ast::FunIdentifier {
316                                    content: ast::FunIdentifierData::TypeSpecifier(type_specifier),
317                                    ..
318                                },
319                                _,
320                            ),
321                        ..
322                    })),
323                ..
324            }) = statement_list.into_iter().next().unwrap().into_inner()
325            {
326                if let ast::TypeSpecifier {
327                    content:
328                        ast::TypeSpecifierData {
329                            array_specifier: Some(array),
330                            ..
331                        },
332                    ..
333                } = *type_specifier
334                {
335                    return Some(array);
336                }
337            }
338        }
339
340        None
341    }
342}
343
344impl Extractable<ast::TranslationUnit> for ast::FunIdentifier {
345    fn wrap(source: &str) -> Cow<str> {
346        format!("void main() {{ {}(); }}", source).into()
347    }
348
349    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
350        if let ast::Node {
351            content:
352                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
353                    content:
354                        ast::FunctionDefinitionData {
355                            statement:
356                                ast::Node {
357                                    content: ast::CompoundStatementData { statement_list, .. },
358                                    ..
359                                },
360                            ..
361                        },
362                    ..
363                }),
364            ..
365        } = extdecls.into_iter().next().unwrap()
366        {
367            if let ast::StatementData::Expression(ast::ExprStatement {
368                content:
369                    ast::ExprStatementData(Some(ast::Expr {
370                        content: ast::ExprData::FunCall(fi, _),
371                        ..
372                    })),
373                ..
374            }) = statement_list.into_iter().next().unwrap().into_inner()
375            {
376                return Some(fi);
377            }
378        }
379
380        None
381    }
382}
383
384impl Extractable<ast::TranslationUnit> for ast::InterpolationQualifier {
385    fn wrap(source: &str) -> Cow<str> {
386        format!("{} float x;", source).into()
387    }
388
389    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
390        if let ast::Node {
391            content:
392                ast::ExternalDeclarationData::Declaration(ast::Node {
393                    content:
394                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
395                            content:
396                                ast::InitDeclaratorListData {
397                                    head:
398                                        ast::SingleDeclaration {
399                                            content:
400                                                ast::SingleDeclarationData {
401                                                    ty:
402                                                        ast::FullySpecifiedType {
403                                                            content:
404                                                                ast::FullySpecifiedTypeData {
405                                                                    qualifier:
406                                                                        Some(ast::TypeQualifier {
407                                                                            content:
408                                                                                ast::TypeQualifierData {
409                                                                                    qualifiers,
410                                                                                },
411                                                                            ..
412                                                                        }),
413                                                                    ..
414                                                                },
415                                                            ..
416                                                        },
417                                                    ..
418                                                },
419                                            ..
420                                        },
421                                    ..
422                                },
423                            ..
424                        }),
425                    ..
426                }),
427            ..
428        } = extdecls.into_iter().next().unwrap()
429        {
430            if let ast::TypeQualifierSpecData::Interpolation(interp) =
431                qualifiers.into_iter().next().unwrap().content
432            {
433                return Some(interp);
434            }
435        }
436
437        None
438    }
439}
440
441impl Extractable<ast::TranslationUnit> for ast::ArrayedIdentifier {
442    fn wrap(source: &str) -> Cow<str> {
443        format!("uniform Block {{ float x; }} {};", source).into()
444    }
445
446    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
447        if let ast::Node {
448            content:
449                ast::ExternalDeclarationData::Declaration(ast::Node {
450                    content:
451                        ast::DeclarationData::Block(ast::Block {
452                            content:
453                                ast::BlockData {
454                                    identifier: Some(a),
455                                    ..
456                                },
457                            ..
458                        }),
459                    ..
460                }),
461            ..
462        } = extdecls.into_iter().next().unwrap()
463        {
464            return Some(a);
465        }
466
467        None
468    }
469}
470
471impl Extractable<ast::TranslationUnit> for ast::PrecisionQualifier {
472    fn wrap(source: &str) -> Cow<str> {
473        format!("{} float x;", source).into()
474    }
475
476    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
477        if let ast::Node {
478            content:
479                ast::ExternalDeclarationData::Declaration(ast::Node {
480                    content:
481                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
482                            content:
483                                ast::InitDeclaratorListData {
484                                    head:
485                                        ast::SingleDeclaration {
486                                            content:
487                                                ast::SingleDeclarationData {
488                                                    ty:
489                                                        ast::FullySpecifiedType {
490                                                            content:
491                                                                ast::FullySpecifiedTypeData {
492                                                                    qualifier:
493                                                                        Some(ast::TypeQualifier {
494                                                                            content:
495                                                                                ast::TypeQualifierData {
496                                                                                    qualifiers,
497                                                                                },
498                                                                            ..
499                                                                        }),
500                                                                    ..
501                                                                },
502                                                            ..
503                                                        },
504                                                    ..
505                                                },
506                                            ..
507                                        },
508                                    ..
509                                },
510                            ..
511                        }),
512                    ..
513                }),
514            ..
515        } = extdecls.into_iter().next().unwrap()
516        {
517            if let ast::TypeQualifierSpecData::Precision(q) =
518                qualifiers.into_iter().next().unwrap().content
519            {
520                return Some(q);
521            }
522        }
523
524        None
525    }
526}
527
528impl Extractable<ast::TranslationUnit> for ast::StorageQualifier {
529    fn wrap(source: &str) -> Cow<str> {
530        format!("{} float x;", source).into()
531    }
532
533    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
534        if let ast::Node {
535            content:
536                ast::ExternalDeclarationData::Declaration(ast::Node {
537                    content:
538                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
539                            content:
540                                ast::InitDeclaratorListData {
541                                    head:
542                                        ast::SingleDeclaration {
543                                            content:
544                                                ast::SingleDeclarationData {
545                                                    ty:
546                                                        ast::FullySpecifiedType {
547                                                            content:
548                                                                ast::FullySpecifiedTypeData {
549                                                                    qualifier:
550                                                                        Some(ast::TypeQualifier {
551                                                                            content:
552                                                                                ast::TypeQualifierData {
553                                                                                    qualifiers,
554                                                                                },
555                                                                            ..
556                                                                        }),
557                                                                    ..
558                                                                },
559                                                            ..
560                                                        },
561                                                    ..
562                                                },
563                                            ..
564                                        },
565                                    ..
566                                },
567                            ..
568                        }),
569                    ..
570                }),
571            ..
572        } = extdecls.into_iter().next().unwrap()
573        {
574            if let ast::TypeQualifierSpecData::Storage(q) =
575                qualifiers.into_iter().next().unwrap().content
576            {
577                return Some(q);
578            }
579        }
580
581        None
582    }
583}
584
585impl Extractable<ast::TranslationUnit> for ast::LayoutQualifier {
586    fn wrap(source: &str) -> Cow<str> {
587        format!("{} float x;", source).into()
588    }
589
590    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
591        if let ast::Node {
592            content:
593                ast::ExternalDeclarationData::Declaration(ast::Node {
594                    content:
595                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
596                            content:
597                                ast::InitDeclaratorListData {
598                                    head:
599                                        ast::SingleDeclaration {
600                                            content:
601                                                ast::SingleDeclarationData {
602                                                    ty:
603                                                        ast::FullySpecifiedType {
604                                                            content:
605                                                                ast::FullySpecifiedTypeData {
606                                                                    qualifier:
607                                                                        Some(ast::TypeQualifier {
608                                                                            content:
609                                                                                ast::TypeQualifierData {
610                                                                                    qualifiers,
611                                                                                },
612                                                                            ..
613                                                                        }),
614                                                                    ..
615                                                                },
616                                                            ..
617                                                        },
618                                                    ..
619                                                },
620                                            ..
621                                        },
622                                    ..
623                                },
624                            ..
625                        }),
626                    ..
627                }),
628            ..
629        } = extdecls.into_iter().next().unwrap()
630        {
631            if let ast::TypeQualifierSpecData::Layout(q) =
632                qualifiers.into_iter().next().unwrap().content
633            {
634                return Some(q);
635            }
636        }
637
638        None
639    }
640}
641
642impl Extractable<ast::TranslationUnit> for ast::TypeQualifier {
643    fn wrap(source: &str) -> Cow<str> {
644        format!("{} float x;", source).into()
645    }
646
647    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
648        if let ast::Node {
649            content:
650                ast::ExternalDeclarationData::Declaration(ast::Node {
651                    content:
652                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
653                            content:
654                                ast::InitDeclaratorListData {
655                                    head:
656                                        ast::SingleDeclaration {
657                                            content:
658                                                ast::SingleDeclarationData {
659                                                    ty:
660                                                        ast::FullySpecifiedType {
661                                                            content:
662                                                                ast::FullySpecifiedTypeData {
663                                                                    qualifier: Some(q),
664                                                                    ..
665                                                                },
666                                                            ..
667                                                        },
668                                                    ..
669                                                },
670                                            ..
671                                        },
672                                    ..
673                                },
674                            ..
675                        }),
676                    ..
677                }),
678            ..
679        } = extdecls.into_iter().next().unwrap()
680        {
681            return Some(q);
682        }
683
684        None
685    }
686}
687
688impl Extractable<ast::TranslationUnit> for ast::TypeSpecifier {
689    fn wrap(source: &str) -> Cow<str> {
690        format!("{} x;", source).into()
691    }
692
693    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
694        if let ast::Node {
695            content:
696                ast::ExternalDeclarationData::Declaration(ast::Node {
697                    content:
698                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
699                            content:
700                                ast::InitDeclaratorListData {
701                                    head:
702                                        ast::SingleDeclaration {
703                                            content:
704                                                ast::SingleDeclarationData {
705                                                    ty:
706                                                        ast::FullySpecifiedType {
707                                                            content:
708                                                                ast::FullySpecifiedTypeData {
709                                                                    ty, ..
710                                                                },
711                                                            ..
712                                                        },
713                                                    ..
714                                                },
715                                            ..
716                                        },
717                                    ..
718                                },
719                            ..
720                        }),
721                    ..
722                }),
723            ..
724        } = extdecls.into_iter().next().unwrap()
725        {
726            return Some(ty);
727        }
728
729        None
730    }
731}
732
733impl Extractable<ast::TranslationUnit> for ast::TypeSpecifierNonArray {
734    fn wrap(source: &str) -> Cow<str> {
735        format!("{} x;", source).into()
736    }
737
738    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
739        if let ast::Node {
740            content:
741                ast::ExternalDeclarationData::Declaration(ast::Node {
742                    content:
743                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
744                            content:
745                                ast::InitDeclaratorListData {
746                                    head:
747                                        ast::SingleDeclaration {
748                                            content:
749                                                ast::SingleDeclarationData {
750                                                    ty:
751                                                        ast::FullySpecifiedType {
752                                                            content:
753                                                                ast::FullySpecifiedTypeData {
754                                                                    ty:
755                                                                        ast::TypeSpecifier {
756                                                                            content:
757                                                                                ast::TypeSpecifierData {
758                                                                                    ty,
759                                                                                    ..
760                                                                                },
761                                                                            ..
762                                                                        },
763                                                                    ..
764                                                                },
765                                                            ..
766                                                        },
767                                                    ..
768                                                },
769                                            ..
770                                        },
771                                    ..
772                                },
773                            ..
774                        }),
775                    ..
776                }),
777            ..
778        } = extdecls.into_iter().next().unwrap()
779        {
780            return Some(ty);
781        }
782
783        None
784    }
785}
786
787impl Extractable<ast::TranslationUnit> for ast::FullySpecifiedType {
788    fn wrap(source: &str) -> Cow<str> {
789        format!("{} x;", source).into()
790    }
791
792    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
793        if let ast::Node {
794            content:
795                ast::ExternalDeclarationData::Declaration(ast::Node {
796                    content:
797                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
798                            content:
799                                ast::InitDeclaratorListData {
800                                    head:
801                                        ast::SingleDeclaration {
802                                            content: ast::SingleDeclarationData { ty, .. },
803                                            ..
804                                        },
805                                    ..
806                                },
807                            ..
808                        }),
809                    ..
810                }),
811            ..
812        } = extdecls.into_iter().next().unwrap()
813        {
814            return Some(ty);
815        }
816
817        None
818    }
819}
820
821impl Extractable<ast::TranslationUnit> for ast::Declaration {
822    fn wrap(source: &str) -> Cow<str> {
823        format!("{};", source).into()
824    }
825
826    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
827        if let ast::Node {
828            content: ast::ExternalDeclarationData::Declaration(decl),
829            ..
830        } = extdecls.into_iter().next().unwrap()
831        {
832            return Some(decl);
833        }
834
835        None
836    }
837}
838
839impl Extractable<ast::TranslationUnit> for ast::StructFieldSpecifier {
840    fn wrap(source: &str) -> Cow<str> {
841        format!("struct A {{ {} }};", source).into()
842    }
843
844    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
845        if let ast::Node {
846            content:
847                ast::ExternalDeclarationData::Declaration(ast::Node {
848                    content:
849                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
850                            content: ast::InitDeclaratorListData {
851                                head:
852                                    ast::SingleDeclaration {
853                                        content: ast::SingleDeclarationData {
854                                            ty:
855                                                ast::FullySpecifiedType {
856                                                    content: ast::FullySpecifiedTypeData {
857                                                        ty:
858                                                            ast::TypeSpecifier {
859                                                                content: ast::TypeSpecifierData {
860                                                                    ty:
861                                                                        ast::TypeSpecifierNonArray {
862                                                                            content: ast::TypeSpecifierNonArrayData::Struct(
863                                                                                         ast::StructSpecifier {
864                                                                                             content: ast::StructSpecifierData {
865                                                                                                 fields,
866                                                                                                 ..
867                                                                                             },
868                                                                                             ..
869                                                                                         },
870                                                                                     ),
871                                                                                     ..
872                                                                        },
873                                                                        ..
874                                                                },
875                                                                ..
876                                                            },
877                                                            ..
878                                                    },
879                                                    ..
880                                                },
881                                                ..
882                                        },
883                                        ..
884                                    },
885                                    ..
886                            },
887                            .. }),
888                            ..
889                }),
890                ..
891        } = extdecls.into_iter().next().unwrap()
892        {
893            return fields.into_iter().next();
894        }
895
896        None
897    }
898}
899
900impl Extractable<ast::TranslationUnit> for ast::StructSpecifier {
901    fn wrap(source: &str) -> Cow<str> {
902        format!("{};", source).into()
903    }
904
905    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
906        if let ast::Node {
907            content:
908                ast::ExternalDeclarationData::Declaration(ast::Node {
909                    content:
910                        ast::DeclarationData::InitDeclaratorList(ast::InitDeclaratorList {
911                            content: ast::InitDeclaratorListData {
912                                head:
913                                    ast::SingleDeclaration {
914                                        content: ast::SingleDeclarationData {
915                                            ty:
916                                                ast::FullySpecifiedType {
917                                                    content: ast::FullySpecifiedTypeData {
918                                                        ty:
919                                                            ast::TypeSpecifier {
920                                                                content: ast::TypeSpecifierData {
921                                                                    ty:
922                                                                        ast::TypeSpecifierNonArray {
923                                                                            content: ast::TypeSpecifierNonArrayData::Struct(s),
924                                                                            ..
925                                                                        },
926                                                                        ..
927                                                                },
928                                                                ..
929                                                            },
930                                                            ..
931                                                    },
932                                                    ..
933                                                },
934                                                ..
935                                        },
936                                        ..
937                                    },
938                                    ..
939                            },
940                            .. }),
941                            ..
942                }),
943                ..
944        } = extdecls.into_iter().next().unwrap()
945        {
946            return Some(s);
947        }
948
949        None
950    }
951}
952
953impl Extractable<ast::TranslationUnit> for ast::Expr {
954    fn wrap(source: &str) -> Cow<str> {
955        format!("void main() {{ {}; }}", source).into()
956    }
957
958    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
959        if let ast::Node {
960            content:
961                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
962                    content:
963                        ast::FunctionDefinitionData {
964                            statement:
965                                ast::Node {
966                                    content: ast::CompoundStatementData { statement_list, .. },
967                                    ..
968                                },
969                            ..
970                        },
971                    ..
972                }),
973            ..
974        } = extdecls.into_iter().next().unwrap()
975        {
976            if let ast::StatementData::Expression(ast::ExprStatement {
977                content: ast::ExprStatementData(Some(expr)),
978                ..
979            }) = statement_list.into_iter().next().unwrap().into_inner()
980            {
981                return Some(expr);
982            }
983        }
984
985        None
986    }
987}
988
989impl Extractable<ast::TranslationUnit> for ast::Preprocessor {
990    fn wrap(source: &str) -> Cow<str> {
991        source.into()
992    }
993
994    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
995        if let ast::Node {
996            content: ast::ExternalDeclarationData::Preprocessor(pp),
997            ..
998        } = extdecls.into_iter().next().unwrap()
999        {
1000            return Some(pp);
1001        }
1002
1003        None
1004    }
1005}
1006
1007impl Extractable<ast::TranslationUnit> for ast::Statement {
1008    fn wrap(source: &str) -> Cow<str> {
1009        format!("void main() {{ {} }}", source).into()
1010    }
1011
1012    fn extract(ast::TranslationUnit(extdecls): ast::TranslationUnit) -> Option<Self> {
1013        if let ast::Node {
1014            content:
1015                ast::ExternalDeclarationData::FunctionDefinition(ast::Node {
1016                    content:
1017                        ast::FunctionDefinitionData {
1018                            statement:
1019                                ast::Node {
1020                                    content: ast::CompoundStatementData { statement_list, .. },
1021                                    ..
1022                                },
1023                            ..
1024                        },
1025                    ..
1026                }),
1027            ..
1028        } = extdecls.into_iter().next().unwrap()
1029        {
1030            return statement_list.into_iter().next();
1031        }
1032
1033        None
1034    }
1035}