Skip to main content

xtask/codegen/
grammar.rs

1//! This module generates AST datatype used by rust-analyzer.
2//!
3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
4//! wrappers around `SyntaxNode` which implement `syntax::AstNode`.
5
6use std::{
7    collections::{BTreeSet, HashSet},
8    fmt::Write,
9    fs,
10};
11
12use either::Either;
13use itertools::Itertools;
14use proc_macro2::{Punct, Spacing};
15use quote::{format_ident, quote};
16use stdx::panic_context;
17use ungrammar::{Grammar, Rule};
18
19use crate::{
20    codegen::{add_preamble, ensure_file_contents, grammar::ast_src::generate_kind_src, reformat},
21    project_root,
22};
23
24mod ast_src;
25use self::ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc};
26
27pub(crate) fn generate(check: bool) {
28    let grammar = fs::read_to_string(project_root().join("crates/syntax/rust.ungram"))
29        .unwrap()
30        .parse()
31        .unwrap();
32    let ast = lower(&grammar);
33    let kinds_src = generate_kind_src(&ast.nodes, &ast.enums, &grammar);
34
35    let syntax_kinds = generate_syntax_kinds(kinds_src);
36    let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
37    ensure_file_contents(
38        crate::flags::CodegenType::Grammar,
39        syntax_kinds_file.as_path(),
40        &syntax_kinds,
41        check,
42    );
43
44    let ast_tokens = generate_tokens(&ast);
45    let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
46    ensure_file_contents(
47        crate::flags::CodegenType::Grammar,
48        ast_tokens_file.as_path(),
49        &ast_tokens,
50        check,
51    );
52
53    let ast_nodes = generate_nodes(kinds_src, &ast);
54    let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
55    ensure_file_contents(
56        crate::flags::CodegenType::Grammar,
57        ast_nodes_file.as_path(),
58        &ast_nodes,
59        check,
60    );
61}
62
63fn generate_tokens(grammar: &AstSrc) -> String {
64    let tokens = grammar.tokens.iter().map(|token| {
65        let name = format_ident!("{}", token);
66        let kind = format_ident!("{}", to_upper_snake_case(token));
67        quote! {
68            pub struct #name {
69                pub(crate) syntax: SyntaxToken,
70            }
71            impl std::fmt::Display for #name {
72                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73                    std::fmt::Display::fmt(&self.syntax, f)
74                }
75            }
76            impl AstToken for #name {
77                fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
78                fn cast(syntax: SyntaxToken) -> Option<Self> {
79                    if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
80                }
81                fn syntax(&self) -> &SyntaxToken { &self.syntax }
82            }
83
84            impl fmt::Debug for #name {
85                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86                    f.debug_struct(#token).field("syntax", &self.syntax).finish()
87                }
88            }
89            impl Clone for #name {
90                fn clone(&self) -> Self {
91                    Self { syntax: self.syntax.clone() }
92                }
93            }
94            impl hash::Hash for #name {
95                fn hash<H: hash::Hasher>(&self, state: &mut H) {
96                    self.syntax.hash(state);
97                }
98            }
99
100            impl Eq for #name {}
101            impl PartialEq for #name {
102                fn eq(&self, other: &Self) -> bool {
103                    self.syntax == other.syntax
104                }
105            }
106        }
107    });
108
109    add_preamble(
110        crate::flags::CodegenType::Grammar,
111        reformat(
112            quote! {
113                use std::{fmt, hash};
114
115                use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};
116
117                #(#tokens)*
118            }
119            .to_string(),
120        ),
121    )
122    .replace("#[derive", "\n#[derive")
123}
124
125fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String {
126    let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
127        .nodes
128        .iter()
129        .map(|node| {
130            let node_str_name = &node.name;
131            let name = format_ident!("{}", node.name);
132            let kind = format_ident!("{}", to_upper_snake_case(&node.name));
133            let traits = node
134                .traits
135                .iter()
136                .filter(|trait_name| {
137                    // Loops have two expressions so this might collide, therefore manual impl it
138                    node.name != "ForExpr" && node.name != "WhileExpr"
139                        || trait_name.as_str() != "HasLoopBody"
140                })
141                .map(|trait_name| {
142                    let trait_name = format_ident!("{}", trait_name);
143                    quote!(impl ast::#trait_name for #name {})
144                });
145
146            let methods = node.fields.iter().map(|field| {
147                let method_name = format_ident!("{}", field.method_name());
148                let ty = field.ty();
149
150                if field.is_many() {
151                    quote! {
152                        #[inline]
153                        pub fn #method_name(&self) -> AstChildren<#ty> {
154                            support::children(&self.syntax)
155                        }
156                    }
157                } else if let Some(token_kind) = field.token_kind() {
158                    quote! {
159                        #[inline]
160                        pub fn #method_name(&self) -> Option<#ty> {
161                            support::token(&self.syntax, #token_kind)
162                        }
163                    }
164                } else {
165                    quote! {
166                        #[inline]
167                        pub fn #method_name(&self) -> Option<#ty> {
168                            support::child(&self.syntax)
169                        }
170                    }
171                }
172            });
173            (
174                quote! {
175                    #[pretty_doc_comment_placeholder_workaround]
176                    pub struct #name {
177                        pub(crate) syntax: SyntaxNode,
178                    }
179
180                    #(#traits)*
181
182                    impl #name {
183                        #(#methods)*
184                    }
185                },
186                quote! {
187                    impl AstNode for #name {
188                        #[inline]
189                        fn kind() -> SyntaxKind
190                        where
191                            Self: Sized
192                        {
193                            #kind
194                        }
195                        #[inline]
196                        fn can_cast(kind: SyntaxKind) -> bool {
197                            kind == #kind
198                        }
199                        #[inline]
200                        fn cast(syntax: SyntaxNode) -> Option<Self> {
201                            if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
202                        }
203                        #[inline]
204                        fn syntax(&self) -> &SyntaxNode { &self.syntax }
205                    }
206
207                    impl hash::Hash for #name {
208                        fn hash<H: hash::Hasher>(&self, state: &mut H) {
209                            self.syntax.hash(state);
210                        }
211                    }
212
213                    impl Eq for #name {}
214                    impl PartialEq for #name {
215                        fn eq(&self, other: &Self) -> bool {
216                            self.syntax == other.syntax
217                        }
218                    }
219
220                    impl Clone for #name {
221                        fn clone(&self) -> Self {
222                            Self { syntax: self.syntax.clone() }
223                        }
224                    }
225
226                    impl fmt::Debug for #name {
227                        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228                            f.debug_struct(#node_str_name).field("syntax", &self.syntax).finish()
229                        }
230                    }
231                },
232            )
233        })
234        .unzip();
235
236    let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
237        .enums
238        .iter()
239        .map(|en| {
240            let variants: Vec<_> =
241                en.variants.iter().map(|var| format_ident!("{}", var)).sorted().collect();
242            let name = format_ident!("{}", en.name);
243            let kinds: Vec<_> = variants
244                .iter()
245                .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
246                .collect();
247            let traits = en.traits.iter().sorted().map(|trait_name| {
248                let trait_name = format_ident!("{}", trait_name);
249                quote!(impl ast::#trait_name for #name {})
250            });
251
252            let ast_node = if en.name == "Stmt" {
253                quote! {}
254            } else {
255                quote! {
256                    impl AstNode for #name {
257                        #[inline]
258                        fn can_cast(kind: SyntaxKind) -> bool {
259                            matches!(kind, #(#kinds)|*)
260                        }
261                        #[inline]
262                        fn cast(syntax: SyntaxNode) -> Option<Self> {
263                            let res = match syntax.kind() {
264                                #(
265                                #kinds => #name::#variants(#variants { syntax }),
266                                )*
267                                _ => return None,
268                            };
269                            Some(res)
270                        }
271                        #[inline]
272                        fn syntax(&self) -> &SyntaxNode {
273                            match self {
274                                #(
275                                #name::#variants(it) => &it.syntax,
276                                )*
277                            }
278                        }
279                    }
280                }
281            };
282
283            (
284                quote! {
285                    #[pretty_doc_comment_placeholder_workaround]
286                    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
287                    pub enum #name {
288                        #(#variants(#variants),)*
289                    }
290
291                    #(#traits)*
292                },
293                quote! {
294                    #(
295                        impl From<#variants> for #name {
296                            #[inline]
297                            fn from(node: #variants) -> #name {
298                                #name::#variants(node)
299                            }
300                        }
301                    )*
302                    #ast_node
303                },
304            )
305        })
306        .unzip();
307    let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
308        .nodes
309        .iter()
310        .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
311        .into_group_map()
312        .into_iter()
313        .sorted_by_key(|(name, _)| *name)
314        .map(|(trait_name, nodes)| {
315            let name = format_ident!("Any{}", trait_name);
316            let node_str_name = name.to_string();
317            let trait_name = format_ident!("{}", trait_name);
318            let kinds: Vec<_> = nodes
319                .iter()
320                .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
321                .collect();
322            let nodes = nodes.iter().map(|node| format_ident!("{}", node.name));
323            (
324                quote! {
325                    #[pretty_doc_comment_placeholder_workaround]
326                    pub struct #name {
327                        pub(crate) syntax: SyntaxNode,
328                    }
329                    impl #name {
330                        #[inline]
331                        pub fn new<T: ast::#trait_name>(node: T) -> #name {
332                            #name {
333                                syntax: node.syntax().clone()
334                            }
335                        }
336                    }
337                },
338                quote! {
339                    impl ast::#trait_name for #name {}
340                    impl AstNode for #name {
341                        #[inline]
342                        fn can_cast(kind: SyntaxKind) -> bool {
343                            matches!(kind, #(#kinds)|*)
344                        }
345                        #[inline]
346                        fn cast(syntax: SyntaxNode) -> Option<Self> {
347                            Self::can_cast(syntax.kind()).then_some(#name { syntax })
348                        }
349                        #[inline]
350                        fn syntax(&self) -> &SyntaxNode {
351                            &self.syntax
352                        }
353                    }
354
355                    impl hash::Hash for #name {
356                        fn hash<H: hash::Hasher>(&self, state: &mut H) {
357                            self.syntax.hash(state);
358                        }
359                    }
360
361                    impl Eq for #name {}
362                    impl PartialEq for #name {
363                        fn eq(&self, other: &Self) -> bool {
364                            self.syntax == other.syntax
365                        }
366                    }
367
368                    impl Clone for #name {
369                        fn clone(&self) -> Self {
370                            Self { syntax: self.syntax.clone() }
371                        }
372                    }
373
374                    impl fmt::Debug for #name {
375                        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376                            f.debug_struct(#node_str_name).field("syntax", &self.syntax).finish()
377                        }
378                    }
379
380                    #(
381                        impl From<#nodes> for #name {
382                            #[inline]
383                            fn from(node: #nodes) -> #name {
384                                #name { syntax: node.syntax }
385                            }
386                        }
387                    )*
388                },
389            )
390        })
391        .unzip();
392
393    let enum_names = grammar.enums.iter().map(|it| &it.name);
394    let node_names = grammar.nodes.iter().map(|it| &it.name);
395
396    let display_impls =
397        enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
398            quote! {
399                impl std::fmt::Display for #name {
400                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
401                        std::fmt::Display::fmt(self.syntax(), f)
402                    }
403                }
404            }
405        });
406
407    let defined_nodes: HashSet<_> = node_names.collect();
408
409    for node in kinds
410        .nodes
411        .iter()
412        .map(|kind| to_pascal_case(kind))
413        .filter(|name| !defined_nodes.iter().any(|&it| it == name))
414    {
415        eprintln!("Warning: node {node} not defined in AST source");
416        drop(node);
417    }
418
419    let ast = quote! {
420        #![allow(non_snake_case)]
421        use std::{fmt, hash};
422
423        use crate::{
424            SyntaxNode, SyntaxToken, SyntaxKind::{self, *},
425            ast::{self, AstNode, AstChildren, support},
426            T,
427        };
428
429        #(#node_defs)*
430        #(#enum_defs)*
431        #(#any_node_defs)*
432        #(#node_boilerplate_impls)*
433        #(#enum_boilerplate_impls)*
434        #(#any_node_boilerplate_impls)*
435        #(#display_impls)*
436    };
437
438    let ast = ast.to_string().replace("T ! [", "T![");
439
440    let mut res = String::with_capacity(ast.len() * 2);
441
442    let mut docs =
443        grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
444
445    for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {
446        res.push_str(chunk);
447        if let Some(doc) = docs.next() {
448            write_doc_comment(doc, &mut res);
449        }
450    }
451
452    let res = add_preamble(crate::flags::CodegenType::Grammar, reformat(res));
453    res.replace("#[derive", "\n#[derive")
454}
455
456fn write_doc_comment(contents: &[String], dest: &mut String) {
457    for line in contents {
458        writeln!(dest, "///{line}").unwrap();
459    }
460}
461
462fn generate_syntax_kinds(grammar: KindsSrc) -> String {
463    let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
464        .punct
465        .iter()
466        .filter(|(token, _name)| token.len() == 1)
467        .map(|(token, name)| (token.chars().next().unwrap(), format_ident!("{}", name)))
468        .unzip();
469
470    let punctuation_values = grammar.punct.iter().map(|(token, _name)| {
471        if "{}[]()".contains(token) {
472            let c = token.chars().next().unwrap();
473            quote! { #c }
474            // underscore is an identifier in the proc-macro api
475        } else if *token == "_" {
476            quote! { _ }
477        } else {
478            let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));
479            quote! { #(#cs)* }
480        }
481    });
482    let punctuation =
483        grammar.punct.iter().map(|(_token, name)| format_ident!("{}", name)).collect::<Vec<_>>();
484    let punctuation_texts = grammar.punct.iter().map(|&(text, _name)| text);
485
486    let fmt_kw_as_variant = |&name| match name {
487        "Self" => format_ident!("SELF_TYPE_KW"),
488        name => format_ident!("{}_KW", to_upper_snake_case(name)),
489    };
490    let strict_keywords = grammar.keywords;
491    let strict_keywords_variants =
492        strict_keywords.iter().map(fmt_kw_as_variant).collect::<Vec<_>>();
493    let strict_keywords_tokens = strict_keywords.iter().map(|it| format_ident!("{it}"));
494
495    let edition_dependent_keywords_variants_match_arm = grammar
496        .edition_dependent_keywords
497        .iter()
498        .map(|(kw, ed)| {
499            let kw = fmt_kw_as_variant(kw);
500            quote! { #kw if #ed <= edition }
501        })
502        .collect::<Vec<_>>();
503    let edition_dependent_keywords_str_match_arm = grammar
504        .edition_dependent_keywords
505        .iter()
506        .map(|(kw, ed)| {
507            quote! { #kw if #ed <= edition }
508        })
509        .collect::<Vec<_>>();
510    let edition_dependent_keywords = grammar.edition_dependent_keywords.iter().map(|&(it, _)| it);
511    let edition_dependent_keywords_variants = grammar
512        .edition_dependent_keywords
513        .iter()
514        .map(|(kw, _)| fmt_kw_as_variant(kw))
515        .collect::<Vec<_>>();
516    let edition_dependent_keywords_tokens =
517        grammar.edition_dependent_keywords.iter().map(|(it, _)| format_ident!("{it}"));
518
519    let contextual_keywords = grammar.contextual_keywords;
520    let contextual_keywords_variants =
521        contextual_keywords.iter().map(fmt_kw_as_variant).collect::<Vec<_>>();
522    let contextual_keywords_tokens = contextual_keywords.iter().map(|it| format_ident!("{it}"));
523    let contextual_keywords_str_match_arm = grammar.contextual_keywords.iter().map(|kw| {
524        match grammar.edition_dependent_keywords.iter().find(|(ed_kw, _)| ed_kw == kw) {
525            Some((_, ed)) => quote! { #kw if edition < #ed },
526            None => quote! { #kw },
527        }
528    });
529    let contextual_keywords_variants_match_arm = grammar
530        .contextual_keywords
531        .iter()
532        .map(|kw_s| {
533            let kw = fmt_kw_as_variant(kw_s);
534            match grammar.edition_dependent_keywords.iter().find(|(ed_kw, _)| ed_kw == kw_s) {
535                Some((_, ed)) => quote! { #kw if edition < #ed },
536                None => quote! { #kw },
537            }
538        })
539        .collect::<Vec<_>>();
540
541    let non_strict_keyword_variants = contextual_keywords_variants
542        .iter()
543        .chain(edition_dependent_keywords_variants.iter())
544        .sorted()
545        .dedup()
546        .collect::<Vec<_>>();
547
548    let literals =
549        grammar.literals.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
550
551    let tokens = grammar.tokens.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
552
553    let nodes = grammar.nodes.iter().map(|name| format_ident!("{}", name)).collect::<Vec<_>>();
554
555    let ast = quote! {
556        #![allow(bad_style, missing_docs, unreachable_pub)]
557        use crate::Edition;
558
559        /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
560        #[derive(Debug)]
561        #[repr(u16)]
562        pub enum SyntaxKind {
563            // Technical SyntaxKinds: they appear temporally during parsing,
564            // but never end up in the final tree
565            #[doc(hidden)]
566            TOMBSTONE,
567            #[doc(hidden)]
568            EOF,
569            #(#punctuation,)*
570            #(#strict_keywords_variants,)*
571            #(#non_strict_keyword_variants,)*
572            #(#literals,)*
573            #(#tokens,)*
574            #(#nodes,)*
575
576            // Technical kind so that we can cast from u16 safely
577            #[doc(hidden)]
578            __LAST,
579        }
580        use self::SyntaxKind::*;
581
582        impl SyntaxKind {
583            #[allow(unreachable_patterns)]
584            pub const fn text(self) -> &'static str {
585                match self {
586                    TOMBSTONE | EOF | __LAST
587                    #( | #literals )*
588                    #( | #nodes )*
589                    #( | #tokens )* => panic!("no text for these `SyntaxKind`s"),
590                    #( #punctuation => #punctuation_texts ,)*
591                    #( #strict_keywords_variants => #strict_keywords ,)*
592                    #( #contextual_keywords_variants => #contextual_keywords ,)*
593                    #( #edition_dependent_keywords_variants => #edition_dependent_keywords ,)*
594                }
595            }
596
597            /// Checks whether this syntax kind is a strict keyword for the given edition.
598            /// Strict keywords are identifiers that are always considered keywords.
599            pub fn is_strict_keyword(self, edition: Edition) -> bool {
600                matches!(self, #(#strict_keywords_variants)|*)
601                || match self {
602                    #(#edition_dependent_keywords_variants_match_arm => true,)*
603                    _ => false,
604                }
605            }
606
607            /// Checks whether this syntax kind is a weak keyword for the given edition.
608            /// Weak keywords are identifiers that are considered keywords only in certain contexts.
609            pub fn is_contextual_keyword(self, edition: Edition) -> bool {
610                match self {
611                    #(#contextual_keywords_variants_match_arm => true,)*
612                    _ => false,
613                }
614            }
615
616            /// Checks whether this syntax kind is a strict or weak keyword for the given edition.
617            pub fn is_keyword(self, edition: Edition) -> bool {
618                matches!(self, #(#strict_keywords_variants)|*)
619                || match self {
620                    #(#edition_dependent_keywords_variants_match_arm => true,)*
621                    #(#contextual_keywords_variants_match_arm => true,)*
622                    _ => false,
623                }
624            }
625
626            pub fn is_punct(self) -> bool {
627                matches!(self, #(#punctuation)|*)
628            }
629
630            pub fn is_literal(self) -> bool {
631                matches!(self, #(#literals)|*)
632            }
633
634            pub fn from_keyword(ident: &str, edition: Edition) -> Option<SyntaxKind> {
635                let kw = match ident {
636                    #(#strict_keywords => #strict_keywords_variants,)*
637                    #(#edition_dependent_keywords_str_match_arm => #edition_dependent_keywords_variants,)*
638                    _ => return None,
639                };
640                Some(kw)
641            }
642
643            pub fn from_contextual_keyword(ident: &str, edition: Edition) -> Option<SyntaxKind> {
644                let kw = match ident {
645                    #(#contextual_keywords_str_match_arm => #contextual_keywords_variants,)*
646                    _ => return None,
647                };
648                Some(kw)
649            }
650
651            pub fn from_char(c: char) -> Option<SyntaxKind> {
652                let tok = match c {
653                    #(#single_byte_tokens_values => #single_byte_tokens,)*
654                    _ => return None,
655                };
656                Some(tok)
657            }
658        }
659
660        /// `T![]`
661        #[macro_export]
662        macro_rules! T_ {
663            #([#punctuation_values] => { $crate::SyntaxKind::#punctuation };)*
664            #([#strict_keywords_tokens] => { $crate::SyntaxKind::#strict_keywords_variants };)*
665            #([#contextual_keywords_tokens] => { $crate::SyntaxKind::#contextual_keywords_variants };)*
666            #([#edition_dependent_keywords_tokens] => { $crate::SyntaxKind::#edition_dependent_keywords_variants };)*
667            [lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
668            [int_number] => { $crate::SyntaxKind::INT_NUMBER };
669            [ident] => { $crate::SyntaxKind::IDENT };
670            [string] => { $crate::SyntaxKind::STRING };
671            [shebang] => { $crate::SyntaxKind::SHEBANG };
672            [frontmatter] => { $crate::SyntaxKind::FRONTMATTER };
673            [inner_doc_comment] => { $crate::SyntaxKind::INNER_DOC_COMMENT };
674            [outer_doc_comment] => { $crate::SyntaxKind::OUTER_DOC_COMMENT };
675        }
676
677        impl ::core::marker::Copy for SyntaxKind {}
678        impl ::core::clone::Clone for SyntaxKind {
679            #[inline]
680            fn clone(&self) -> Self {
681                *self
682            }
683        }
684        impl ::core::cmp::PartialEq for SyntaxKind {
685            #[inline]
686            fn eq(&self, other: &Self) -> bool {
687                (*self as u16) == (*other as u16)
688            }
689        }
690        impl ::core::cmp::Eq for SyntaxKind {}
691        impl ::core::cmp::PartialOrd for SyntaxKind {
692            #[inline]
693            fn partial_cmp(&self, other: &Self) -> core::option::Option<core::cmp::Ordering> {
694                Some(self.cmp(other))
695            }
696        }
697        impl ::core::cmp::Ord for SyntaxKind {
698            #[inline]
699            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
700                (*self as u16).cmp(&(*other as u16))
701            }
702        }
703        impl ::core::hash::Hash for SyntaxKind {
704            fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
705                ::core::mem::discriminant(self).hash(state);
706            }
707        }
708    };
709
710    let result = add_preamble(crate::flags::CodegenType::Grammar, reformat(ast.to_string()));
711
712    if let Some(start) = result.find("macro_rules ! T_")
713        && let Some(macro_end) = result[start..].find("\nimpl ::core::marker::Copy")
714    {
715        let macro_section = &result[start..start + macro_end];
716        let formatted_macro = macro_section
717            .replace("T_ { [", "T_ {\n    [")
718            .replace(" ; [", ";\n    [")
719            .replace(" ; }", ";\n}")
720            .trim_end()
721            .to_owned()
722            + "\n";
723        return result.replace(macro_section, &formatted_macro);
724    }
725
726    result
727}
728
729fn to_upper_snake_case(s: &str) -> String {
730    let mut buf = String::with_capacity(s.len());
731    let mut prev = false;
732    for c in s.chars() {
733        if c.is_ascii_uppercase() && prev {
734            buf.push('_')
735        }
736        prev = true;
737
738        buf.push(c.to_ascii_uppercase());
739    }
740    buf
741}
742
743fn to_lower_snake_case(s: &str) -> String {
744    let mut buf = String::with_capacity(s.len());
745    let mut prev = false;
746    for c in s.chars() {
747        if c.is_ascii_uppercase() && prev {
748            buf.push('_')
749        }
750        prev = true;
751
752        buf.push(c.to_ascii_lowercase());
753    }
754    buf
755}
756
757fn to_pascal_case(s: &str) -> String {
758    let mut buf = String::with_capacity(s.len());
759    let mut prev_is_underscore = true;
760    for c in s.chars() {
761        if c == '_' {
762            prev_is_underscore = true;
763        } else if prev_is_underscore {
764            buf.push(c.to_ascii_uppercase());
765            prev_is_underscore = false;
766        } else {
767            buf.push(c.to_ascii_lowercase());
768        }
769    }
770    buf
771}
772
773fn pluralize(s: &str) -> String {
774    format!("{s}s")
775}
776
777impl Field {
778    fn is_many(&self) -> bool {
779        matches!(self, Field::Node { cardinality: Cardinality::Many, .. })
780    }
781    fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
782        match self {
783            Field::Token { token, .. } => {
784                let token: proc_macro2::TokenStream = token.parse().unwrap();
785                Some(quote! { T![#token] })
786            }
787            _ => None,
788        }
789    }
790    fn method_name(&self) -> String {
791        match self {
792            Field::Token { name, token, .. } => {
793                if let Some(name) = name {
794                    return name.clone();
795                }
796                let name = match token.as_str() {
797                    ";" => "semicolon",
798                    "->" => "thin_arrow",
799                    "'{'" => "l_curly",
800                    "'}'" => "r_curly",
801                    "'('" => "l_paren",
802                    "')'" => "r_paren",
803                    "'['" => "l_brack",
804                    "']'" => "r_brack",
805                    "<" => "l_angle",
806                    ">" => "r_angle",
807                    "=" => "eq",
808                    "!" => "excl",
809                    "*" => "star",
810                    "&" => "amp",
811                    "-" => "minus",
812                    "_" => "underscore",
813                    "." => "dot",
814                    ".." => "dotdot",
815                    "..." => "dotdotdot",
816                    "..=" => "dotdoteq",
817                    "=>" => "fat_arrow",
818                    "@" => "at",
819                    ":" => "colon",
820                    "::" => "coloncolon",
821                    "#" => "pound",
822                    "?" => "question_mark",
823                    "," => "comma",
824                    "|" => "pipe",
825                    "~" => "tilde",
826                    _ => token,
827                };
828                format!("{name}_token",)
829            }
830            Field::Node { name, .. } => {
831                if name == "type" {
832                    String::from("ty")
833                } else {
834                    name.to_owned()
835                }
836            }
837        }
838    }
839    fn ty(&self) -> proc_macro2::Ident {
840        match self {
841            Field::Token { .. } => format_ident!("SyntaxToken"),
842            Field::Node { ty, .. } => format_ident!("{}", ty),
843        }
844    }
845}
846
847fn clean_token_name(name: &str) -> String {
848    let cleaned = name.trim_start_matches(['@', '#', '?']);
849    if cleaned.is_empty() { name.to_owned() } else { cleaned.to_owned() }
850}
851
852fn lower(grammar: &Grammar) -> AstSrc {
853    let mut res = AstSrc {
854        tokens:
855            "Whitespace Comment String ByteString CString IntNumber FloatNumber Char Byte Ident"
856                .split_ascii_whitespace()
857                .map(|it| it.to_owned())
858                .collect::<Vec<_>>(),
859        ..Default::default()
860    };
861
862    let nodes = grammar.iter().collect::<Vec<_>>();
863
864    for &node in &nodes {
865        let name = grammar[node].name.clone();
866        let rule = &grammar[node].rule;
867        let _g = panic_context::enter(name.clone());
868        match lower_enum(grammar, rule) {
869            Some(variants) => {
870                let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
871                res.enums.push(enum_src);
872            }
873            None => {
874                let mut fields = Vec::new();
875                lower_rule(&mut fields, grammar, None, rule);
876                res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
877            }
878        }
879    }
880
881    deduplicate_fields(&mut res);
882    extract_enums(&mut res);
883    extract_struct_traits(&mut res);
884    extract_enum_traits(&mut res);
885    res.nodes.sort_by_key(|it| it.name.clone());
886    res.enums.sort_by_key(|it| it.name.clone());
887    res.tokens.sort();
888    res.nodes.iter_mut().for_each(|it| {
889        it.traits.sort();
890        it.fields.sort_by_key(|it| match it {
891            Field::Token { token, .. } => (true, token.clone()),
892            Field::Node { name, .. } => (false, name.clone()),
893        });
894    });
895    res.enums.iter_mut().for_each(|it| {
896        it.traits.sort();
897        it.variants.sort();
898    });
899    res
900}
901
902fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
903    let alternatives = match rule {
904        Rule::Alt(it) => it,
905        _ => return None,
906    };
907    let mut variants = Vec::new();
908    for alternative in alternatives {
909        match alternative {
910            Rule::Node(it) => variants.push(grammar[*it].name.clone()),
911            Rule::Token(it) if grammar[*it].name == ";" => (),
912            _ => return None,
913        }
914    }
915    Some(variants)
916}
917
918fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
919    if lower_separated_list(acc, grammar, label, rule) {
920        return;
921    }
922
923    match rule {
924        Rule::Node(node) => {
925            let ty = grammar[*node].name.clone();
926            let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
927            let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
928            acc.push(field);
929        }
930        Rule::Token(token) => {
931            let mut token = clean_token_name(&grammar[*token].name);
932            if "[]{}()".contains(&token) {
933                token = format!("'{token}'");
934            }
935            let field = Field::Token { name: label.cloned(), token };
936            acc.push(field);
937        }
938        Rule::Rep(inner) => {
939            if let Rule::Node(node) = &**inner {
940                let ty = grammar[*node].name.clone();
941                let name = label.cloned().unwrap_or_else(|| {
942                    if ty == "AnyAttr" {
943                        "attrs".to_owned()
944                    } else {
945                        pluralize(&to_lower_snake_case(&ty))
946                    }
947                });
948                let field = Field::Node { name, ty, cardinality: Cardinality::Many };
949                acc.push(field);
950                return;
951            }
952            panic!("unhandled rule: {rule:?}")
953        }
954        Rule::Labeled { label: l, rule } => {
955            assert!(label.is_none());
956            let manually_implemented = matches!(
957                l.as_str(),
958                "lhs"
959                    | "rhs"
960                    | "then_branch"
961                    | "else_branch"
962                    | "start"
963                    | "end"
964                    | "op"
965                    | "index"
966                    | "base"
967                    | "value"
968                    | "trait"
969                    | "self_ty"
970                    | "iterable"
971                    | "condition"
972                    | "args"
973                    | "body"
974            );
975            if manually_implemented {
976                return;
977            }
978            lower_rule(acc, grammar, Some(l), rule);
979        }
980        Rule::Seq(rules) | Rule::Alt(rules) => {
981            for rule in rules {
982                lower_rule(acc, grammar, label, rule)
983            }
984        }
985        Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
986    }
987}
988
989// (T (',' T)* ','?)
990fn lower_separated_list(
991    acc: &mut Vec<Field>,
992    grammar: &Grammar,
993    label: Option<&String>,
994    rule: &Rule,
995) -> bool {
996    let rule = match rule {
997        Rule::Seq(it) => it,
998        _ => return false,
999    };
1000
1001    let (nt, repeat, trailing_sep) = match rule.as_slice() {
1002        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
1003            (Either::Left(node), repeat, Some(trailing_sep))
1004        }
1005        [Rule::Node(node), Rule::Rep(repeat)] => (Either::Left(node), repeat, None),
1006        [Rule::Token(token), Rule::Rep(repeat), Rule::Opt(trailing_sep)] => {
1007            (Either::Right(token), repeat, Some(trailing_sep))
1008        }
1009        [Rule::Token(token), Rule::Rep(repeat)] => (Either::Right(token), repeat, None),
1010        _ => return false,
1011    };
1012    let repeat = match &**repeat {
1013        Rule::Seq(it) => it,
1014        _ => return false,
1015    };
1016    if !matches!(
1017        repeat.as_slice(),
1018        [comma, nt_]
1019            if trailing_sep.is_none_or(|it| comma == &**it) && match (nt, nt_) {
1020                (Either::Left(node), Rule::Node(nt_)) => node == nt_,
1021                (Either::Right(token), Rule::Token(nt_)) => token == nt_,
1022                _ => false,
1023            }
1024    ) {
1025        return false;
1026    }
1027    match nt {
1028        Either::Right(token) => {
1029            let token = clean_token_name(&grammar[*token].name);
1030            let field = Field::Token { token, name: None };
1031            acc.push(field);
1032        }
1033        Either::Left(node) => {
1034            let ty = grammar[*node].name.clone();
1035            let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
1036            let field = Field::Node { name, ty, cardinality: Cardinality::Many };
1037            acc.push(field);
1038        }
1039    }
1040    true
1041}
1042
1043fn deduplicate_fields(ast: &mut AstSrc) {
1044    for node in &mut ast.nodes {
1045        let mut i = 0;
1046        'outer: while i < node.fields.len() {
1047            for j in 0..i {
1048                let f1 = &node.fields[i];
1049                let f2 = &node.fields[j];
1050                if f1 == f2 {
1051                    node.fields.remove(i);
1052                    continue 'outer;
1053                }
1054            }
1055            i += 1;
1056        }
1057    }
1058}
1059
1060fn extract_enums(ast: &mut AstSrc) {
1061    for node in &mut ast.nodes {
1062        for enm in &ast.enums {
1063            let mut to_remove = Vec::new();
1064            for (i, field) in node.fields.iter().enumerate() {
1065                let ty = field.ty().to_string();
1066                if enm.variants.iter().any(|it| it == &ty) {
1067                    to_remove.push(i);
1068                }
1069            }
1070            if to_remove.len() == enm.variants.len() {
1071                node.remove_field(to_remove);
1072                let ty = enm.name.clone();
1073                let name = to_lower_snake_case(&ty);
1074                node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
1075            }
1076        }
1077    }
1078}
1079
1080const TRAITS: &[(&str, &[&str])] = &[
1081    ("HasAttrs", &["attrs"]),
1082    ("HasName", &["name"]),
1083    ("HasVisibility", &["visibility"]),
1084    ("HasGenericParams", &["generic_param_list", "where_clause"]),
1085    ("HasGenericArgs", &["generic_arg_list"]),
1086    ("HasTypeBounds", &["type_bound_list", "colon_token"]),
1087    ("HasModuleItem", &["items"]),
1088    ("HasLoopBody", &["label", "loop_body"]),
1089    ("HasArgList", &["arg_list"]),
1090];
1091
1092fn extract_struct_traits(ast: &mut AstSrc) {
1093    for node in &mut ast.nodes {
1094        for (name, methods) in TRAITS {
1095            extract_struct_trait(node, name, methods);
1096        }
1097    }
1098}
1099
1100fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
1101    let mut to_remove = Vec::new();
1102    for (i, field) in node.fields.iter().enumerate() {
1103        let method_name = field.method_name();
1104        if methods.iter().any(|&it| it == method_name) {
1105            to_remove.push(i);
1106        }
1107    }
1108    if to_remove.len() == methods.len() {
1109        node.traits.push(trait_name.to_owned());
1110        node.remove_field(to_remove);
1111    }
1112}
1113
1114fn extract_enum_traits(ast: &mut AstSrc) {
1115    for enm in &mut ast.enums {
1116        if enm.name == "Stmt" {
1117            continue;
1118        }
1119        let nodes = &ast.nodes;
1120        let mut variant_traits = enm
1121            .variants
1122            .iter()
1123            .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
1124            .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
1125
1126        let mut enum_traits = match variant_traits.next() {
1127            Some(it) => it,
1128            None => continue,
1129        };
1130        for traits in variant_traits {
1131            enum_traits = enum_traits.intersection(&traits).cloned().collect();
1132        }
1133        enm.traits = enum_traits.into_iter().collect();
1134    }
1135}
1136
1137impl AstNodeSrc {
1138    fn remove_field(&mut self, to_remove: Vec<usize>) {
1139        to_remove.into_iter().rev().for_each(|idx| {
1140            self.fields.remove(idx);
1141        });
1142    }
1143}
1144
1145#[test]
1146fn test() {
1147    generate(true);
1148}