aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_syntax.rs296
-rw-r--r--xtask/src/codegen/rust.ungram544
2 files changed, 814 insertions, 26 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 745a25862..d6a72ccc0 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,34 +3,43 @@
3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype 3//! Specifically, it generates the `SyntaxKind` enum and a number of newtype
4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. 4//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
5 5
6use std::{collections::HashSet, fmt::Write}; 6use std::{
7 collections::{BTreeSet, HashSet},
8 fmt::Write,
9};
7 10
8use proc_macro2::{Punct, Spacing}; 11use proc_macro2::{Punct, Spacing};
9use quote::{format_ident, quote}; 12use quote::{format_ident, quote};
13use ungrammar::{Grammar, Rule};
10 14
11use crate::{ 15use crate::{
12 ast_src::{AstSrc, Field, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
13 codegen::{self, update, Mode}, 17 codegen::{self, update, Mode},
14 project_root, Result, 18 project_root, Result,
15}; 19};
16 20
17pub fn generate_syntax(mode: Mode) -> Result<()> { 21pub fn generate_syntax(mode: Mode) -> Result<()> {
22 let grammar = include_str!("rust.ungram")
23 .parse::<Grammar>()
24 .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err));
25 let ast = lower(&grammar);
26
18 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); 27 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
19 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 28 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
20 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 29 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
21 30
22 let ast_tokens_file = project_root().join(codegen::AST_TOKENS); 31 let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
23 let contents = generate_tokens(AST_SRC)?; 32 let contents = generate_tokens(&ast)?;
24 update(ast_tokens_file.as_path(), &contents, mode)?; 33 update(ast_tokens_file.as_path(), &contents, mode)?;
25 34
26 let ast_nodes_file = project_root().join(codegen::AST_NODES); 35 let ast_nodes_file = project_root().join(codegen::AST_NODES);
27 let contents = generate_nodes(KINDS_SRC, AST_SRC)?; 36 let contents = generate_nodes(KINDS_SRC, &ast)?;
28 update(ast_nodes_file.as_path(), &contents, mode)?; 37 update(ast_nodes_file.as_path(), &contents, mode)?;
29 38
30 Ok(()) 39 Ok(())
31} 40}
32 41
33fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { 42fn generate_tokens(grammar: &AstSrc) -> Result<String> {
34 let tokens = grammar.tokens.iter().map(|token| { 43 let tokens = grammar.tokens.iter().map(|token| {
35 let name = format_ident!("{}", token); 44 let name = format_ident!("{}", token);
36 let kind = format_ident!("{}", to_upper_snake_case(token)); 45 let kind = format_ident!("{}", to_upper_snake_case(token));
@@ -62,13 +71,13 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> {
62 Ok(pretty) 71 Ok(pretty)
63} 72}
64 73
65fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 74fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
66 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar 75 let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
67 .nodes 76 .nodes
68 .iter() 77 .iter()
69 .map(|node| { 78 .map(|node| {
70 let name = format_ident!("{}", node.name); 79 let name = format_ident!("{}", node.name);
71 let kind = format_ident!("{}", to_upper_snake_case(node.name)); 80 let kind = format_ident!("{}", to_upper_snake_case(&node.name));
72 let traits = node.traits.iter().map(|trait_name| { 81 let traits = node.traits.iter().map(|trait_name| {
73 let trait_name = format_ident!("{}", trait_name); 82 let trait_name = format_ident!("{}", trait_name);
74 quote!(impl ast::#trait_name for #name {}) 83 quote!(impl ast::#trait_name for #name {})
@@ -192,8 +201,8 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
192 }) 201 })
193 .unzip(); 202 .unzip();
194 203
195 let enum_names = grammar.enums.iter().map(|it| it.name); 204 let enum_names = grammar.enums.iter().map(|it| &it.name);
196 let node_names = grammar.nodes.iter().map(|it| it.name); 205 let node_names = grammar.nodes.iter().map(|it| &it.name);
197 206
198 let display_impls = 207 let display_impls =
199 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { 208 enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| {
@@ -212,9 +221,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
212 .nodes 221 .nodes
213 .iter() 222 .iter()
214 .map(|kind| to_pascal_case(kind)) 223 .map(|kind| to_pascal_case(kind))
215 .filter(|name| !defined_nodes.contains(name.as_str())) 224 .filter(|name| !defined_nodes.iter().any(|&it| it == name))
216 { 225 {
217 eprintln!("Warning: node {} not defined in ast source", node); 226 drop(node)
227 // TODO: restore this
228 // eprintln!("Warning: node {} not defined in ast source", node);
218 } 229 }
219 230
220 let ast = quote! { 231 let ast = quote! {
@@ -236,12 +247,12 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
236 let mut res = String::with_capacity(ast.len() * 2); 247 let mut res = String::with_capacity(ast.len() * 2);
237 248
238 let mut docs = 249 let mut docs =
239 grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc)); 250 grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc));
240 251
241 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") { 252 for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") {
242 res.push_str(chunk); 253 res.push_str(chunk);
243 if let Some(doc) = docs.next() { 254 if let Some(doc) = docs.next() {
244 write_doc_comment(doc, &mut res); 255 write_doc_comment(&doc, &mut res);
245 } 256 }
246 } 257 }
247 258
@@ -249,7 +260,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
249 Ok(pretty) 260 Ok(pretty)
250} 261}
251 262
252fn write_doc_comment(contents: &[&str], dest: &mut String) { 263fn write_doc_comment(contents: &[String], dest: &mut String) {
253 for line in contents { 264 for line in contents {
254 writeln!(dest, "///{}", line).unwrap(); 265 writeln!(dest, "///{}", line).unwrap();
255 } 266 }
@@ -296,7 +307,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
296 307
297 let ast = quote! { 308 let ast = quote! {
298 #![allow(bad_style, missing_docs, unreachable_pub)] 309 #![allow(bad_style, missing_docs, unreachable_pub)]
299 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`. 310 /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
300 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 311 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
301 #[repr(u16)] 312 #[repr(u16)]
302 pub enum SyntaxKind { 313 pub enum SyntaxKind {
@@ -363,6 +374,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
363 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)* 374 #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
364 [lifetime] => { $crate::SyntaxKind::LIFETIME }; 375 [lifetime] => { $crate::SyntaxKind::LIFETIME };
365 [ident] => { $crate::SyntaxKind::IDENT }; 376 [ident] => { $crate::SyntaxKind::IDENT };
377 [shebang] => { $crate::SyntaxKind::SHEBANG };
366 } 378 }
367 }; 379 };
368 380
@@ -413,9 +425,13 @@ fn to_pascal_case(s: &str) -> String {
413 buf 425 buf
414} 426}
415 427
416impl Field<'_> { 428fn pluralize(s: &str) -> String {
429 format!("{}s", s)
430}
431
432impl Field {
417 fn is_many(&self) -> bool { 433 fn is_many(&self) -> bool {
418 matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) 434 matches!(self, Field::Node { cardinality: Cardinality::Many, .. })
419 } 435 }
420 fn token_kind(&self) -> Option<proc_macro2::TokenStream> { 436 fn token_kind(&self) -> Option<proc_macro2::TokenStream> {
421 match self { 437 match self {
@@ -429,7 +445,7 @@ impl Field<'_> {
429 fn method_name(&self) -> proc_macro2::Ident { 445 fn method_name(&self) -> proc_macro2::Ident {
430 match self { 446 match self {
431 Field::Token(name) => { 447 Field::Token(name) => {
432 let name = match *name { 448 let name = match name.as_str() {
433 ";" => "semicolon", 449 ";" => "semicolon",
434 "->" => "thin_arrow", 450 "->" => "thin_arrow",
435 "'{'" => "l_curly", 451 "'{'" => "l_curly",
@@ -448,29 +464,257 @@ impl Field<'_> {
448 "." => "dot", 464 "." => "dot",
449 ".." => "dotdot", 465 ".." => "dotdot",
450 "..." => "dotdotdot", 466 "..." => "dotdotdot",
467 "..=" => "dotdoteq",
451 "=>" => "fat_arrow", 468 "=>" => "fat_arrow",
452 "@" => "at", 469 "@" => "at",
453 ":" => "colon", 470 ":" => "colon",
454 "::" => "coloncolon", 471 "::" => "coloncolon",
455 "#" => "pound", 472 "#" => "pound",
456 "?" => "question_mark", 473 "?" => "question_mark",
474 "," => "comma",
457 _ => name, 475 _ => name,
458 }; 476 };
459 format_ident!("{}_token", name) 477 format_ident!("{}_token", name)
460 } 478 }
461 Field::Node { name, src } => match src { 479 Field::Node { name, .. } => {
462 FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(name)), 480 if name == "type" {
463 _ => format_ident!("{}", name), 481 format_ident!("ty")
464 }, 482 } else {
483 format_ident!("{}", name)
484 }
485 }
465 } 486 }
466 } 487 }
467 fn ty(&self) -> proc_macro2::Ident { 488 fn ty(&self) -> proc_macro2::Ident {
468 match self { 489 match self {
469 Field::Token(_) => format_ident!("SyntaxToken"), 490 Field::Token(_) => format_ident!("SyntaxToken"),
470 Field::Node { name, src } => match src { 491 Field::Node { ty, .. } => format_ident!("{}", ty),
471 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => format_ident!("{}", ty), 492 }
472 FieldSrc::Shorthand => format_ident!("{}", name), 493 }
473 }, 494}
495
496fn lower(grammar: &Grammar) -> AstSrc {
497 let mut res = AstSrc::default();
498 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()];
499
500 let nodes = grammar
501 .iter()
502 .filter(|&node| match grammar[node].rule {
503 Rule::Node(it) if it == node => false,
504 _ => true,
505 })
506 .collect::<Vec<_>>();
507
508 for &node in &nodes {
509 let name = grammar[node].name.clone();
510 let rule = &grammar[node].rule;
511 match lower_enum(grammar, rule) {
512 Some(variants) => {
513 let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants };
514 res.enums.push(enum_src);
515 }
516 None => {
517 let mut fields = Vec::new();
518 lower_rule(&mut fields, grammar, None, rule);
519 res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields });
520 }
521 }
522 }
523
524 deduplicate_fields(&mut res);
525 extract_enums(&mut res);
526 extract_struct_traits(&mut res);
527 extract_enum_traits(&mut res);
528 res
529}
530
531fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
532 let alternatives = match rule {
533 Rule::Alt(it) => it,
534 _ => return None,
535 };
536 let mut variants = Vec::new();
537 for alternative in alternatives {
538 match alternative {
539 Rule::Node(it) => variants.push(grammar[*it].name.clone()),
540 _ => return None,
541 }
542 }
543 Some(variants)
544}
545
546fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) {
547 if lower_comma_list(acc, grammar, label, rule) {
548 return;
549 }
550
551 match rule {
552 Rule::Node(node) => {
553 let ty = grammar[*node].name.clone();
554 let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
555 let field = Field::Node { name, ty, cardinality: Cardinality::Optional };
556 acc.push(field);
557 }
558 Rule::Token(token) => {
559 assert!(label.is_none());
560 let mut name = grammar[*token].name.clone();
561 if name != "int_number" && name != "string" {
562 if "[]{}()".contains(&name) {
563 name = format!("'{}'", name);
564 }
565 let field = Field::Token(name);
566 acc.push(field);
567 }
568 }
569 Rule::Rep(inner) => {
570 if let Rule::Node(node) = &**inner {
571 let ty = grammar[*node].name.clone();
572 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
573 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
574 acc.push(field);
575 return;
576 }
577 todo!("{:?}", rule)
578 }
579 Rule::Labeled { label: l, rule } => {
580 assert!(label.is_none());
581 lower_rule(acc, grammar, Some(l), rule);
582 }
583 Rule::Seq(rules) | Rule::Alt(rules) => {
584 for rule in rules {
585 lower_rule(acc, grammar, label, rule)
586 }
474 } 587 }
588 Rule::Opt(rule) => lower_rule(acc, grammar, label, rule),
589 }
590}
591
592// (T (',' T)* ','?)
593fn lower_comma_list(
594 acc: &mut Vec<Field>,
595 grammar: &Grammar,
596 label: Option<&String>,
597 rule: &Rule,
598) -> bool {
599 let rule = match rule {
600 Rule::Seq(it) => it,
601 _ => return false,
602 };
603 let (node, repeat, trailing_comma) = match rule.as_slice() {
604 [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
605 (node, repeat, trailing_comma)
606 }
607 _ => return false,
608 };
609 let repeat = match &**repeat {
610 Rule::Seq(it) => it,
611 _ => return false,
612 };
613 match repeat.as_slice() {
614 [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
615 _ => return false,
616 }
617 let ty = grammar[*node].name.clone();
618 let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
619 let field = Field::Node { name, ty, cardinality: Cardinality::Many };
620 acc.push(field);
621 true
622}
623
624fn deduplicate_fields(ast: &mut AstSrc) {
625 for node in &mut ast.nodes {
626 let mut i = 0;
627 'outer: while i < node.fields.len() {
628 for j in 0..i {
629 let f1 = &node.fields[i];
630 let f2 = &node.fields[j];
631 if f1 == f2 {
632 node.fields.remove(i);
633 continue 'outer;
634 }
635 }
636 i += 1;
637 }
638 }
639}
640
641fn extract_enums(ast: &mut AstSrc) {
642 for node in &mut ast.nodes {
643 for enm in &ast.enums {
644 let mut to_remove = Vec::new();
645 for (i, field) in node.fields.iter().enumerate() {
646 let ty = field.ty().to_string();
647 if enm.variants.iter().any(|it| it == &ty) {
648 to_remove.push(i);
649 }
650 }
651 if to_remove.len() == enm.variants.len() {
652 node.remove_field(to_remove);
653 let ty = enm.name.clone();
654 let name = to_lower_snake_case(&ty);
655 node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional });
656 }
657 }
658 }
659}
660
661fn extract_struct_traits(ast: &mut AstSrc) {
662 let traits: &[(&str, &[&str])] = &[
663 ("AttrsOwner", &["attrs"]),
664 ("NameOwner", &["name"]),
665 ("VisibilityOwner", &["visibility"]),
666 ("GenericParamsOwner", &["generic_param_list", "where_clause"]),
667 ("TypeBoundsOwner", &["type_bound_list", "colon_token"]),
668 ("ModuleItemOwner", &["items"]),
669 ("LoopBodyOwner", &["label", "loop_body"]),
670 ("ArgListOwner", &["arg_list"]),
671 ];
672
673 for node in &mut ast.nodes {
674 for (name, methods) in traits {
675 extract_struct_trait(node, name, methods);
676 }
677 }
678}
679
680fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
681 let mut to_remove = Vec::new();
682 for (i, field) in node.fields.iter().enumerate() {
683 let method_name = field.method_name().to_string();
684 if methods.iter().any(|&it| it == &method_name) {
685 to_remove.push(i);
686 }
687 }
688 if to_remove.len() == methods.len() {
689 node.traits.push(trait_name.to_string());
690 node.remove_field(to_remove);
691 }
692}
693
694fn extract_enum_traits(ast: &mut AstSrc) {
695 for enm in &mut ast.enums {
696 let nodes = &ast.nodes;
697 let mut variant_traits = enm
698 .variants
699 .iter()
700 .map(|var| nodes.iter().find(|it| &it.name == var).unwrap())
701 .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>());
702
703 let mut enum_traits = match variant_traits.next() {
704 Some(it) => it,
705 None => continue,
706 };
707 for traits in variant_traits {
708 enum_traits = enum_traits.intersection(&traits).cloned().collect();
709 }
710 enm.traits = enum_traits.into_iter().collect();
711 }
712}
713
714impl AstNodeSrc {
715 fn remove_field(&mut self, to_remove: Vec<usize>) {
716 to_remove.into_iter().rev().for_each(|idx| {
717 self.fields.remove(idx);
718 });
475 } 719 }
476} 720}
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
new file mode 100644
index 000000000..8f0e66278
--- /dev/null
+++ b/xtask/src/codegen/rust.ungram
@@ -0,0 +1,544 @@
1SourceFile =
2 'shebang'?
3 Attr*
4 Item*
5
6Item =
7 Const
8| Enum
9| ExternBlock
10| ExternCrate
11| Fn
12| Impl
13| MacroCall
14| Module
15| Static
16| Struct
17| Trait
18| TypeAlias
19| Union
20| Use
21
22Module =
23 Attr* Visibility? 'mod' Name
24 (ItemList | ';')
25
26ItemList =
27 '{' Attr* Item* '}'
28
29ExternCrate =
30 Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
31
32Rename =
33 'as' (Name | '_')
34
35Use =
36 Attr* Visibility? 'use' UseTree ';'
37
38UseTree =
39 (Path? '::')? ('*' | UseTreeList )
40| Path Rename?
41
42UseTreeList =
43 '{' (UseTree (',' UseTree)* ','?)? '}'
44
45Fn =
46 Attr* Visibility?
47 'default'? ('async' | 'const')? 'unsafe'? Abi?
48 'fn' Name GenericParamList? ParamList RetType?
49 WhereClause?
50 (body:BlockExpr | ';')
51
52Abi =
53 'extern' 'string'?
54
55ParamList =
56 '('(
57 SelfParam
58 | (SelfParam ',')? (Param (',' Param)* ','?)?
59 )')'
60
61SelfParam =
62 Attr* (
63 ('&' 'lifetime'?)? 'mut'? 'self'
64 | 'mut'? 'self' ':' Type
65 )
66
67Param =
68 Attr* (
69 Pat (':' Type)
70 | Type
71 | '...'
72 )
73
74RetType =
75 '->' Type
76
77TypeAlias =
78 Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
79 '=' Type ';'
80
81Struct =
82 Attr* Visibility? 'struct' Name GenericParamList? (
83 WhereClause? (RecordFieldList | ';')
84 | TupleFieldList WhereClause? ';'
85 )
86
87RecordFieldList =
88 '{' fields:(RecordField (',' RecordField)* ','?)? '}'
89
90RecordField =
91 Attr* Visibility? Name ':' Type
92
93TupleFieldList =
94 '(' fields:(TupleField (',' TupleField)* ','?)? ')'
95
96TupleField =
97 Attr* Visibility? Type
98
99FieldList =
100 RecordFieldList
101| TupleFieldList
102
103Enum =
104 Attr* Visibility? 'enum' Name GenericParamList? WhereClause?
105 VariantList
106
107VariantList =
108 '{' (Variant (',' Variant)* ','?)? '}'
109
110Variant =
111 Attr* Visibility? Name FieldList ('=' Expr)?
112
113Union =
114 Attr* Visibility? 'union' Name GenericParamList? WhereClause?
115 RecordFieldList
116
117AdtDef =
118 Struct
119| Enum
120| Union
121
122Const =
123 Attr* Visibility? 'default'? 'const' (Name | '_') ':' Type
124 '=' body:Expr ';'
125
126Static =
127 Attr* Visibility? 'static'? 'mut'? Name ':' Type
128 '=' body:Expr ';'
129
130Trait =
131 Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList
132 (':' TypeBoundList?)? WhereClause
133 AssocItemList
134
135AssocItemList =
136 '{' Attr* AssocItem* '}'
137
138AssocItem =
139 Fn
140| TypeAlias
141| Const
142| MacroCall
143
144Impl =
145 Attr* Visibility?
146 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? (
147 Type
148 | '!'? Type 'for' Type
149 ) WhereClause?
150 AssocItemList
151
152ExternBlock =
153 Attr* Abi ExternItemList
154
155ExternItemList =
156 '{' Attr* ExternItem* '}'
157
158ExternItem =
159 Fn | Static | MacroCall
160
161GenericParamList =
162 '<' (GenericParam (',' GenericParam)* ','?)? '>'
163
164GenericParam =
165 LifetimeParam
166| TypeParam
167| ConstParam
168
169TypeParam =
170 Attr* Name (':' TypeBoundList?)?
171 ('=' default_type:Type)?
172
173ConstParam =
174 Attr* 'const' Name ':' Type
175 ('=' default_val:Expr)?
176
177LifetimeParam =
178 Attr* 'lifetime'
179
180Visibility =
181 'pub' ('('
182 'super'
183 | 'self'
184 | 'crate'
185 | 'in' Path
186 ')')?
187
188Attr =
189 '#' '!'? '[' Path ('=' Literal | TokenTree)? ']'
190
191Type =
192 ParenType
193| TupleType
194| NeverType
195| PathType
196| PointerType
197| ArrayType
198| SliceType
199| ReferenceType
200| PlaceholderType
201| FnPointerType
202| ForType
203| ImplTraitType
204| DynTraitType
205
206ParenType =
207 '(' Type ')'
208
209TupleType =
210 '(' fields:Type* ')'
211
212NeverType =
213 '!'
214
215PathType =
216 Path
217
218PointerType =
219 '*' ('const' | 'mut') Type
220
221ArrayType =
222 '[' Type ';' Expr ']'
223
224SliceType =
225 '[' Type ']'
226
227ReferenceType =
228 '&' 'lifetime'? 'mut'? Type
229
230PlaceholderType =
231 '_'
232
233FnPointerType =
234 Abi 'unsafe'? 'fn' ParamList RetType?
235
236ForType =
237 'for' GenericParamList Type
238
239ImplTraitType =
240 'impl' TypeBoundList
241
242DynTraitType =
243 'dyn' TypeBoundList
244
245TupleExpr =
246 Attr* '(' Expr* ')'
247
248ArrayExpr =
249 Attr* '[' (Expr* | Expr ';' Expr) ']'
250
251ParenExpr =
252 Attr* '(' Expr ')'
253
254PathExpr =
255 Path
256
257LambdaExpr =
258 Attr* 'static'? 'async'? 'move'? ParamList RetType?
259 body:Expr
260
261IfExpr =
262 Attr* 'if' Condition
263
264Condition =
265 'let' Pat '=' Expr
266| Expr
267
268EffectExpr =
269 Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr
270
271LoopExpr =
272 Attr* Label? 'loop'
273 loop_body:BlockExpr?
274
275ForExpr =
276 Attr* Label? 'for' Pat 'in' iterable:Expr
277 loop_body:BlockExpr?
278
279WhileExpr =
280 Attr* Label? 'while' Condition
281 loop_body:BlockExpr?
282
283ContinueExpr =
284 Attr* 'continue' 'lifetime'?
285
286BreakExpr =
287 Attr* 'break' 'lifetime'? Expr?
288
289Label =
290 'lifetime'
291
292BlockExpr =
293 Attr* Label
294 '{'
295 Item*
296 statements:Stmt*
297 Expr?
298 '}'
299
300ReturnExpr =
301 Attr* 'return' Expr
302
303CallExpr =
304 Attr* Expr ArgList
305
306MethodCallExpr =
307 Attr* Expr '.' NameRef TypeArgList? ArgList
308
309ArgList =
310 '(' args:Expr* ')'
311
312FieldExpr =
313 Attr* Expr '.' NameRef
314
315IndexExpr =
316 Attr* '[' ']'
317
318AwaitExpr =
319 Attr* Expr '.' 'await'
320
321TryExpr =
322 Attr* Expr '?'
323
324CastExpr =
325 Attr* Expr 'as' Type
326
327RefExpr =
328 Attr* '&' ('raw' | 'mut' | 'const') Expr
329
330PrefixExpr =
331 Attr* Expr
332
333BoxExpr =
334 Attr* 'box' Expr
335
336RangeExpr =
337 Attr*
338
339BinExpr =
340 Attr*
341
342Literal =
343 'int_number'
344
345MatchExpr =
346 Attr* 'match' Expr MatchArmList
347
348MatchArmList =
349 '{' arms:MatchArm* '}'
350
351MatchArm =
352 Attr* Pat guard:MatchGuard? '=>' Expr
353
354MatchGuard =
355 'if' Expr
356
357RecordExpr =
358 Path RecordExprFieldList
359
360RecordExprFieldList =
361 '{'
362 fields:RecordExprField*
363 ('..' spread:Expr)?
364 '}'
365
366RecordExprField =
367 Attr* NameRef (':' Expr)?
368
369OrPat =
370 Pat*
371
372ParenPat =
373 '(' Pat ')'
374
375RefPat =
376 '&' 'mut'? Pat
377
378BoxPat =
379 'box' Path
380
381BindPat =
382 Attr* 'ref'? 'mut'? Name ('@' Pat)?
383
384PlaceholderPat =
385 '_'
386
387DotDotPat =
388 '..'
389
390PathPat =
391 Path
392
393SlicePat =
394 '[' args:Pat* ']'
395
396RangePat =
397 '..' | '..='
398
399LiteralPat =
400 Literal
401
402MacroPat =
403 MacroCall
404
405RecordPat =
406 Path RecordFieldPatList
407
408RecordFieldPatList =
409 '{'
410 record_field_pats:RecordFieldPat*
411 BindPat*
412 '..'?
413 '}'
414
415RecordFieldPat =
416 Attr* NameRef ':' Pat
417
418TupleStructPat =
419 Path '(' args:Pat* ')'
420
421TuplePat =
422 '(' args:Pat* ')'
423
424Name =
425 'ident'
426
427NameRef =
428 'ident' | 'int_number'
429
430MacroCall =
431 Attr* Path '!' Name? TokenTree ';'?
432
433MacroDef =
434 Name TokenTree
435
436TokenTree =
437 '(' ')' | '{' '}' | '[' ']'
438
439MacroItems =
440 Item*
441
442MacroStmts =
443 statements:Stmt*
444 Expr?
445
446TypeBound =
447 'lifetime' | 'const'? Type
448
449TypeBoundList =
450 bounds:TypeBound*
451
452WherePred =
453 ('for' GenericParamList)? ('lifetime' | Type) ':' TypeBoundList
454
455WhereClause =
456 'where' predicates:WherePred*
457
458ExprStmt =
459 Attr* Expr ';'
460
461LetStmt =
462 Attr* 'let' Pat (':' Type)
463 '=' initializer:Expr ';'
464
465Path =
466 (qualifier:Path '::')? segment:PathSegment
467
468PathSegment =
469 '::' | 'crate' | 'self' | 'super'
470| '<' NameRef TypeArgList ParamList RetType PathType '>'
471
472TypeArgList =
473 '::'? '<'
474 TypeArg*
475 LifetimeArg*
476 AssocTypeArg*
477 ConstArg*
478 '>'
479
480TypeArg =
481 Type
482
483AssocTypeArg =
484 NameRef (':' TypeBoundList | '=' Type)
485
486LifetimeArg =
487 'lifetime'
488
489ConstArg =
490 Literal | BlockExpr BlockExpr
491
492Stmt =
493 LetStmt
494| ExprStmt
495
496Pat =
497 OrPat
498| ParenPat
499| RefPat
500| BoxPat
501| BindPat
502| PlaceholderPat
503| DotDotPat
504| PathPat
505| RecordPat
506| TupleStructPat
507| TuplePat
508| SlicePat
509| RangePat
510| LiteralPat
511| MacroPat
512
513Expr =
514 TupleExpr
515| ArrayExpr
516| ParenExpr
517| PathExpr
518| LambdaExpr
519| IfExpr
520| LoopExpr
521| ForExpr
522| WhileExpr
523| ContinueExpr
524| BreakExpr
525| Label
526| BlockExpr
527| ReturnExpr
528| MatchExpr
529| RecordExpr
530| CallExpr
531| IndexExpr
532| MethodCallExpr
533| FieldExpr
534| AwaitExpr
535| TryExpr
536| EffectExpr
537| CastExpr
538| RefExpr
539| PrefixExpr
540| RangeExpr
541| BinExpr
542| Literal
543| MacroCall
544| BoxExpr