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