glsl_lang/parse/
parsable.rs

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