From 3d28292157e1b6c9675ef64eddf53786c3e7dc5f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 29 Jul 2020 15:45:23 +0200 Subject: Switch to ungrammar from ast_src The primary advantage of ungrammar is that it (eventually) allows one to describe concrete syntax tree structure -- with alternatives and specific sequence of tokens & nodes. That should be re-usable for: * generate `make` calls * Rust reference * Hypothetical parser's evented API We loose doc comments for the time being unfortunately. I don't think we should add support for doc comments to ungrammar -- they'll make grammar file hard to read. We might supply docs as out-of band info, or maybe just via a reference, but we'll think about that once things are no longer in flux --- xtask/Cargo.toml | 9 +- xtask/src/ast_src.rs | 1984 +-------------------------------------- xtask/src/codegen/gen_syntax.rs | 224 ++++- xtask/src/codegen/rust.ungram | 529 +++++++++++ 4 files changed, 759 insertions(+), 1987 deletions(-) create mode 100644 xtask/src/codegen/rust.ungram (limited to 'xtask') diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index d1cfb5909..8140da87f 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -10,9 +10,10 @@ license = "MIT OR Apache-2.0" doctest = false [dependencies] -walkdir = "2.3.1" -pico-args = "0.3.1" -quote = "1.0.2" -proc-macro2 = "1.0.8" anyhow = "1.0.26" flate2 = "1.0" +pico-args = "0.3.1" +proc-macro2 = "1.0.8" +quote = "1.0.2" +ungrammar = "0.1.0" +walkdir = "2.3.1" diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index a6a4d7c35..83449437b 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs @@ -223,12 +223,14 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { ], }; +#[derive(Default, Debug)] pub(crate) struct AstSrc { pub(crate) tokens: Vec, pub(crate) nodes: Vec, pub(crate) enums: Vec, } +#[derive(Debug)] pub(crate) struct AstNodeSrc { pub(crate) doc: Vec, pub(crate) name: String, @@ -236,1999 +238,23 @@ pub(crate) struct AstNodeSrc { pub(crate) fields: Vec, } +#[derive(Debug, Eq, PartialEq)] pub(crate) enum Field { Token(String), Node { name: String, src: FieldSrc }, } +#[derive(Debug, Eq, PartialEq)] pub(crate) enum FieldSrc { Shorthand, Optional(String), Many(String), } +#[derive(Debug)] pub(crate) struct AstEnumSrc { pub(crate) doc: Vec, pub(crate) name: String, pub(crate) traits: Vec, pub(crate) variants: Vec, } - -macro_rules! ast_nodes { - ($( - $(#[doc = $doc:expr])+ - struct $name:ident$(: $($trait:ident),*)? { - $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)? - } - )*) => { - vec![$( - AstNodeSrc { - doc: vec![$($doc.to_string()),*], - name: stringify!($name).to_string(), - traits: vec![$($(stringify!($trait).to_string()),*)?], - fields: vec![ - $(field!($(T![$token])? $field_name $($ty)?)),* - ], - - } - ),*] - }; -} - -macro_rules! field { - (T![$token:tt] T) => { - Field::Token(stringify!($token).to_string()) - }; - ($field_name:ident) => { - Field::Node { name: stringify!($field_name).to_string(), src: FieldSrc::Shorthand } - }; - ($field_name:ident [$ty:ident]) => { - Field::Node { - name: stringify!($field_name).to_string(), - src: FieldSrc::Many(stringify!($ty).to_string()), - } - }; - ($field_name:ident $ty:ident) => { - Field::Node { - name: stringify!($field_name).to_string(), - src: FieldSrc::Optional(stringify!($ty).to_string()), - } - }; -} - -macro_rules! ast_enums { - ($( - $(#[doc = $doc:expr])+ - enum $name:ident $(: $($trait:ident),*)? { - $($variant:ident),*$(,)? - } - )*) => { - vec![$( - AstEnumSrc { - doc: vec![$($doc.to_string()),*], - name: stringify!($name).to_string(), - traits: vec![$($(stringify!($trait).to_string()),*)?], - variants: vec![$(stringify!($variant).to_string()),*], - } - ),*] - }; -} - -pub(crate) fn rust_ast() -> AstSrc { - AstSrc { - tokens: vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()], - nodes: ast_nodes! { - /// The entire Rust source file. Includes all top-level inner attributes and module items. - /// - /// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html) - struct SourceFile: ModuleItemOwner, AttrsOwner, DocCommentsOwner { - } - - /// Function definition either with body or not. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub extern "C" fn foo(#[attr] Patern {p}: Pattern) -> u32 - /// where - /// T: Debug - /// { - /// 42 - /// } - /// ❱ - /// - /// extern "C" { - /// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱ - /// } - /// ``` - /// - /// - [Reference](https://doc.rust-lang.org/reference/items/functions.html) - /// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions) - struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { - Abi, - T![const], - T![default], - T![async], - T![unsafe], - T![fn], - ParamList, - RetType, - body: BlockExpr, - T![;] - } - - /// Return type annotation. - /// - /// ``` - /// fn foo(a: u32) ❰ -> Option ❱ { Some(a) } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) - struct RetType { T![->], TypeRef } - - /// Struct definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// struct Foo where T: Debug { - /// /// Docs - /// #[attr] - /// pub a: u32, - /// b: T, - /// } - /// ❱ - /// - /// ❰ struct Foo; ❱ - /// ❰ struct Foo(#[attr] T) where T: Debug; ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) - struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { - T![struct], - FieldDefList, - T![;] - } - - /// Union definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub union Foo where T: Debug { - /// /// Docs - /// #[attr] - /// a: T, - /// b: u32, - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/unions.html) - struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { - T![union], - RecordFieldDefList, - } - - /// Record field definition list including enclosing curly braces. - /// - /// ``` - /// struct Foo // same for union - /// ❰ - /// { - /// a: u32, - /// b: bool, - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) - struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] } - - /// Record field definition including its attributes and doc comments. - /// - /// ` `` - /// same for union - /// struct Foo { - /// ❰ - /// /// Docs - /// #[attr] - /// pub a: u32 - /// ❱ - /// - /// ❰ b: bool ❱ - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) - struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } - - /// Tuple field definition list including enclosing parens. - /// - /// ``` - /// struct Foo ❰ (u32, String, Vec) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) - struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] } - - /// Tuple field definition including its attributes. - /// - /// ``` - /// struct Foo(❰ #[attr] u32 ❱); - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) - struct TupleFieldDef: VisibilityOwner, AttrsOwner { - TypeRef, - } - - /// Enum definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub enum Foo where T: Debug { - /// /// Docs - /// #[attr] - /// Bar, - /// Baz(#[attr] u32), - /// Bruh { - /// a: u32, - /// /// Docs - /// #[attr] - /// b: T, - /// } - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) - struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { - T![enum], - variant_list: EnumVariantList, - } - - /// Enum variant definition list including enclosing curly braces. - /// - /// ``` - /// enum Foo - /// ❰ - /// { - /// Bar, - /// Baz(u32), - /// Bruh { - /// a: u32 - /// } - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) - struct EnumVariantList { - T!['{'], - variants: [EnumVariant], - T!['}'] - } - - /// Enum variant definition including its attributes and discriminant value definition. - /// - /// ``` - /// enum Foo { - /// ❰ - /// /// Docs - /// #[attr] - /// Bar - /// ❱ - /// - /// // same for tuple and record variants - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) - struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner { - FieldDefList, - T![=], - Expr - } - - /// Trait definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub unsafe trait Foo: Debug where T: Debug { - /// // ... - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/traits.html) - struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { - T![unsafe], - T![auto], - T![trait], - ItemList, - } - - /// Module definition either with body or not. - /// Includes all of its inner and outer attributes, module items, doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub mod foo; - /// ❱ - /// - /// ❰ - /// /// Docs - /// #[attr] - /// pub mod bar { - /// //! Inner docs - /// #![inner_attr] - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/modules.html) - struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { - T![mod], - ItemList, - T![;] - } - - /// Item defintion list. - /// This is used for both top-level items and impl block items. - /// - /// ``` - /// ❰ - /// fn foo {} - /// struct Bar; - /// enum Baz; - /// trait Bruh; - /// const BRUUH: u32 = 42; - /// ❱ - /// - /// impl Foo - /// ❰ - /// { - /// fn bar() {} - /// const BAZ: u32 = 42; - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items.html) - struct ItemList: ModuleItemOwner { - T!['{'], - assoc_items: [AssocItem], - T!['}'] - } - - /// Constant variable definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub const FOO: u32 = 42; - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html) - struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { - T![default], - T![const], - T![=], - body: Expr, - T![;] - } - - - /// Static variable definition. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub static mut FOO: u32 = 42; - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/static-items.html) - struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { - T![static], - T![mut], - T![=], - body: Expr, - T![;] - } - - /// Type alias definition. - /// Includes associated type clauses with type bounds. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// pub type Foo where T: Debug = T; - /// ❱ - /// - /// trait Bar { - /// ❰ type Baz: Debug; ❱ - /// ❰ type Bruh = String; ❱ - /// ❰ type Bruuh: Debug = u32; ❱ - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html) - struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { - T![default], - T![type], - T![=], - TypeRef, - T![;] - } - - /// Inherent and trait impl definition. - /// Includes all of its inner and outer attributes. - /// - /// ``` - /// ❰ - /// #[attr] - /// unsafe impl const !Foo for Bar where T: Debug { - /// #![inner_attr] - /// // ... - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/implementations.html) - struct ImplDef: TypeParamsOwner, AttrsOwner, DocCommentsOwner { - T![default], - T![const], - T![unsafe], - T![impl], - T![!], - T![for], - ItemList, - } - - - /// Parenthesized type reference. - /// Note: parens are only used for grouping, this is not a tuple type. - /// - /// ``` - /// // This is effectively just `u32`. - /// // Single-item tuple must be defined with a trailing comma: `(u32,)` - /// type Foo = ❰ (u32) ❱; - /// - /// let bar: &'static ❰ (dyn Debug) ❱ = "bruh"; - /// ``` - struct ParenType { T!['('], TypeRef, T![')'] } - - /// Unnamed tuple type. - /// - /// ``` - /// let foo: ❰ (u32, bool) ❱ = (42, true); - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/tuple.html) - struct TupleType { T!['('], fields: [TypeRef], T![')'] } - - /// The never type (i.e. the exclamation point). - /// - /// ``` - /// type T = ❰ ! ❱; - /// - /// fn no_return() -> ❰ ! ❱ { - /// loop {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/never.html) - struct NeverType { T![!] } - - /// Path to a type. - /// Includes single identifier type names and elaborate paths with - /// generic parameters. - /// - /// ``` - /// type Foo = ❰ String ❱; - /// type Bar = ❰ std::vec::Vec ❱; - /// type Baz = ❰ ::bruh::::Item ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html) - struct PathType { Path } - - /// Raw pointer type. - /// - /// ``` - /// type Foo = ❰ *const u32 ❱; - /// type Bar = ❰ *mut u32 ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut) - struct PointerType { T![*], T![const], T![mut], TypeRef } - - /// Array type. - /// - /// ``` - /// type Foo = ❰ [u32; 24 - 3] ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/array.html) - struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] } - - /// Slice type. - /// - /// ``` - /// type Foo = ❰ [u8] ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/slice.html) - struct SliceType { T!['['], TypeRef, T![']'] } - - /// Reference type. - /// - /// ``` - /// type Foo = ❰ &'static str ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html) - struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef } - - /// Placeholder type (i.e. the underscore). - /// - /// ``` - /// let foo: ❰ _ ❱ = 42_u32; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/inferred.html) - struct PlaceholderType { T![_] } - - /// Function pointer type (not to be confused with `Fn*` family of traits). - /// - /// ``` - /// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱; - /// - /// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html) - struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType } - - /// Higher order type. - /// - /// ``` - /// type Foo = ❰ for<'a> fn(&'a str) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html) - struct ForType { T![for], TypeParamList, TypeRef } - - /// Opaque `impl Trait` type. - /// - /// ``` - /// fn foo(bar: ❰ impl Debug + Eq ❱) {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html) - struct ImplTraitType: TypeBoundsOwner { T![impl] } - - /// Trait object type. - /// - /// ``` - /// type Foo = ❰ dyn Debug ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html) - struct DynTraitType: TypeBoundsOwner { T![dyn] } - - /// Tuple literal. - /// - /// ``` - /// ❰ (42, true) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html) - struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] } - - /// Array literal. - /// - /// ``` - /// ❰ [#![inner_attr] true, false, true] ❱; - /// - /// ❰ ["baz"; 24] ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html) - struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] } - - /// Parenthesized expression. - /// Note: parens are only used for grouping, this is not a tuple literal. - /// - /// ``` - /// ❰ (#![inner_attr] 2 + 2) ❱ * 2; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html) - struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] } - - /// Path to a symbol in expression context. - /// Includes single identifier variable names and elaborate paths with - /// generic parameters. - /// - /// ``` - /// ❰ Some:: ❱; - /// ❰ foo ❱ + 42; - /// ❰ Vec::::push ❱; - /// ❰ <[i32]>::reverse ❱; - /// ❰ >::borrow ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html) - struct PathExpr { Path } - - /// Anonymous callable object literal a.k.a. closure, lambda or functor. - /// - /// ``` - /// ❰ || 42 ❱; - /// ❰ |a: u32| val + 1 ❱; - /// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱; - /// ❰ move || baz ❱; - /// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html) - struct LambdaExpr: AttrsOwner { - T![static], // Note(@matklad): I belive this is (used to be?) syntax for generators - T![async], - T![move], - ParamList, - RetType, - body: Expr, - } - - /// If expression. Includes both regular `if` and `if let` forms. - /// Beware that `else if` is a special case syntax sugar, because in general - /// there has to be block expression after `else`. - /// - /// ``` - /// ❰ if bool_cond { 42 } ❱ - /// ❰ if bool_cond { 42 } else { 24 } ❱ - /// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱ - /// - /// ❰ - /// if let Pattern(foo) = bar { - /// foo - /// } else { - /// panic!(); - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html) - struct IfExpr: AttrsOwner { T![if], Condition } - - /// Unconditional loop expression. - /// - /// ``` - /// ❰ - /// loop { - /// // yeah, it's that simple... - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html) - struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } - - /// Block expression with an optional prefix (label, try ketword, - /// unsafe keyword, async keyword...). - /// - /// ``` - /// ❰ - /// 'label: try { - /// None? - /// } - /// ❱ - /// ``` - /// - /// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html) - /// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks) - /// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks) - struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr } - - - /// For loop expression. - /// Note: record struct literals are not valid as iterable expression - /// due to ambiguity. - /// - /// ``` - /// ❰ - /// for i in (0..4) { - /// dbg!(i); - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops) - struct ForExpr: AttrsOwner, LoopBodyOwner { - T![for], - Pat, - T![in], - iterable: Expr, - } - - /// While loop expression. Includes both regular `while` and `while let` forms. - /// - /// ``` - /// ❰ - /// while bool_cond { - /// 42; - /// } - /// ❱ - /// ❰ - /// while let Pattern(foo) = bar { - /// bar += 1; - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops) - struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition } - - /// Continue expression. - /// - /// ``` - /// while bool_cond { - /// ❰ continue ❱; - /// } - /// - /// 'outer: loop { - /// loop { - /// ❰ continue 'outer ❱; - /// } - /// } - /// - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions) - struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } - - /// Break expression. - /// - /// ``` - /// while bool_cond { - /// ❰ break ❱; - /// } - /// 'outer: loop { - /// for foo in bar { - /// ❰ break 'outer ❱; - /// } - /// } - /// 'outer: loop { - /// loop { - /// ❰ break 'outer 42 ❱; - /// } - /// } - /// ``` - /// - /// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions) - struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } - - /// Label. - /// - /// ``` - /// ❰ 'outer: ❱ loop {} - /// - /// let foo = ❰ 'bar: ❱ loop {} - /// - /// ❰ 'baz: ❱ { - /// break 'baz; - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels) - /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) - struct Label { T![lifetime] } - - /// Block expression. Includes unsafe blocks and block labels. - /// - /// ``` - /// let foo = ❰ - /// { - /// #![inner_attr] - /// ❰ { } ❱ - /// - /// ❰ 'label: { break 'label } ❱ - /// } - /// ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html) - /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) - struct BlockExpr: AttrsOwner, ModuleItemOwner { - Label, T!['{'], statements: [Stmt], Expr, T!['}'], - } - - /// Return expression. - /// - /// ``` - /// || ❰ return 42 ❱; - /// - /// fn bar() { - /// ❰ return ❱; - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html) - struct ReturnExpr: AttrsOwner { Expr } - - /// Call expression (not to be confused with method call expression, it is - /// a separate ast node). - /// - /// ``` - /// ❰ foo() ❱; - /// ❰ &str::len("bar") ❱; - /// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html) - struct CallExpr: ArgListOwner { Expr } - - /// Method call expression. - /// - /// ``` - /// ❰ receiver_expr.method() ❱; - /// ❰ receiver_expr.method::(42, true) ❱; - /// - /// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html) - struct MethodCallExpr: AttrsOwner, ArgListOwner { - Expr, T![.], NameRef, TypeArgList, - } - - /// Index expression a.k.a. subscript operator call. - /// - /// ``` - /// ❰ foo[42] ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html) - struct IndexExpr: AttrsOwner { T!['['], T![']'] } - - /// Field access expression. - /// - /// ``` - /// ❰ expr.bar ❱; - /// - /// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html) - struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } - - /// Await operator call expression. - /// - /// ``` - /// ❰ expr.await ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html) - struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } - - /// The question mark operator call. - /// - /// ``` - /// ❰ expr? ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) - struct TryExpr: AttrsOwner { Expr, T![?] } - - /// Type cast expression. - /// - /// ``` - /// ❰ expr as T ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions) - struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } - - - /// Borrow operator call. - /// - /// ``` - /// ❰ &foo ❱; - /// ❰ &mut bar ❱; - /// ❰ &raw const bar ❱; - /// ❰ &raw mut bar ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators) - struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr } - - /// Prefix operator call. This is either `!` or `*` or `-`. - /// - /// ``` - /// ❰ !foo ❱; - /// ❰ *bar ❱; - /// ❰ -42 ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html) - struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } - - /// Box operator call. - /// - /// ``` - /// ❰ box 42 ❱; - /// ``` - /// - /// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md) - struct BoxExpr: AttrsOwner { T![box], Expr } - - /// Range operator call. - /// - /// ``` - /// ❰ 0..42 ❱; - /// ❰ ..42 ❱; - /// ❰ 0.. ❱; - /// ❰ .. ❱; - /// ❰ 0..=42 ❱; - /// ❰ ..=42 ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html) - struct RangeExpr: AttrsOwner { /*RangeOp*/ } - - - /// Binary operator call. - /// Includes all arithmetic, logic, bitwise and assignment operators. - /// - /// ``` - /// ❰ 2 + ❰ 2 * 2 ❱ ❱; - /// ❰ ❰ true && false ❱ || true ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators) - struct BinExpr: AttrsOwner { /*BinOp*/ } - - - /// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal. - /// - /// ``` - /// ❰ "str" ❱; - /// ❰ br##"raw byte str"## ❱; - /// ❰ 'c' ❱; - /// ❰ b'c' ❱; - /// ❰ 42 ❱; - /// ❰ 1e9 ❱; - /// ❰ true ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html) - struct Literal { /*LiteralToken*/ } - - /// Match expression. - /// - /// ``` - /// ❰ - /// match expr { - /// Pat1 => {} - /// Pat2(_) => 42, - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) - struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList } - - /// Match arm list part of match expression. Includes its inner attributes. - /// - /// ``` - /// match expr - /// ❰ - /// { - /// #![inner_attr] - /// Pat1 => {} - /// Pat2(_) => 42, - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) - struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] } - - - /// Match arm. - /// Note: record struct literals are not valid as target match expression - /// due to ambiguity. - /// ``` - /// match expr { - /// ❰ #[attr] Pattern(it) if bool_cond => it ❱, - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) - struct MatchArm: AttrsOwner { - pat: Pat, - guard: MatchGuard, - T![=>], - Expr, - } - - /// Match guard. - /// - /// ``` - /// match expr { - /// Pattern(it) ❰ if bool_cond ❱ => it, - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards) - struct MatchGuard { T![if], Expr } - - /// Record literal expression. The same syntax is used for structs, - /// unions and record enum variants. - /// - /// ``` - /// ❰ - /// foo::Bar { - /// #![inner_attr] - /// baz: 42, - /// bruh: true, - /// ..spread - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) - struct RecordLit { Path, RecordFieldList} - - /// Record field list including enclosing curly braces. - /// - /// foo::Bar ❰ - /// { - /// baz: 42, - /// ..spread - /// } - /// ❱ - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) - struct RecordFieldList { - T!['{'], - fields: [RecordField], - T![..], - spread: Expr, - T!['}'] - } - - /// Record field. - /// - /// ``` - /// foo::Bar { - /// ❰ #[attr] baz: 42 ❱ - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) - struct RecordField: AttrsOwner { NameRef, T![:], Expr } - - /// Disjunction of patterns. - /// - /// ``` - /// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html) - struct OrPat { pats: [Pat] } - - /// Parenthesized pattern. - /// Note: parens are only used for grouping, this is not a tuple pattern. - /// - /// ``` - /// if let ❰ &(0..=42) ❱ = foo {} - /// ``` - /// - /// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns - struct ParenPat { T!['('], Pat, T![')'] } - - /// Reference pattern. - /// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns. - /// - /// ``` - /// let ❰ &mut foo ❱ = bar; - /// - /// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns) - struct RefPat { T![&], T![mut], Pat } - - /// Box pattern. - /// - /// ``` - /// let ❰ box foo ❱ = box 42; - /// ``` - /// - /// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html) - struct BoxPat { T![box], Pat } - - /// Bind pattern. - /// - /// ``` - /// match foo { - /// Some(❰ ref mut bar ❱) => {} - /// ❰ baz @ None ❱ => {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns) - struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat } - - /// Placeholder pattern a.k.a. the wildcard pattern or the underscore. - /// - /// ``` - /// let ❰ _ ❱ = foo; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern) - struct PlaceholderPat { T![_] } - - /// Rest-of-the record/tuple pattern. - /// Note: this is not the unbonded range pattern (even more: it doesn't exist). - /// - /// ``` - /// let Foo { bar, ❰ .. ❱ } = baz; - /// let (❰ .. ❱, bruh) = (42, 24, 42); - /// let Bruuh(❰ .. ❱) = bruuuh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) - struct DotDotPat { T![..] } - - /// Path pattern. - /// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`). - /// - /// ``` - /// let ❰ foo::bar::Baz ❱ { .. } = bruh; - /// if let ❰ CONST ❱ = 42 {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns) - struct PathPat { Path } - - /// Slice pattern. - /// - /// ``` - /// let ❰ [foo, bar, baz] ❱ = [1, 2, 3]; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns) - struct SlicePat { T!['['], args: [Pat], T![']'] } - - /// Range pattern. - /// - /// ``` - /// match foo { - /// ❰ 0..42 ❱ => {} - /// ❰ 0..=42 ❱ => {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns) - struct RangePat { } // FIXME(@matklad): here should be T![..], T![..=] I think, if we don't already have an accessor in expresions_ext - - /// Literal pattern. - /// Includes only bool, number, char, and string literals. - /// - /// ``` - /// match foo { - /// Number(❰ 42 ❱) => {} - /// String(❰ "42" ❱) => {} - /// Bool(❰ true ❱) => {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns) - struct LiteralPat { Literal } - - /// Macro invocation in pattern position. - /// - /// ``` - /// let ❰ foo!(my custom syntax) ❱ = baz; - /// - /// ``` - /// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation) - struct MacroPat { MacroCall } - - /// Record literal pattern. - /// - /// ``` - /// let ❰ foo::Bar { baz, .. } ❱ = bruh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) - struct RecordPat { RecordFieldPatList, Path } - - /// Record literal's field patterns list including enclosing curly braces. - /// - /// ``` - /// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh; - /// `` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) - struct RecordFieldPatList { - T!['{'], - record_field_pats: [RecordFieldPat], - bind_pats: [BindPat], - T![..], - T!['}'] - } - - /// Record literal's field pattern. - /// Note: record literal can also match tuple structs. - /// - /// ``` - /// let Foo { ❰ bar: _ ❱ } = baz; - /// let TupleStruct { ❰ 0: _ ❱ } = bruh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) - struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat } - - /// Tuple struct literal pattern. - /// - /// ``` - /// let ❰ foo::Bar(baz, bruh) ❱ = bruuh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns) - struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] } - - /// Tuple pattern. - /// Note: this doesn't include tuple structs (see `TupleStructPat`) - /// - /// ``` - /// let ❰ (foo, bar, .., baz) ❱ = bruh; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns) - struct TuplePat { T!['('], args: [Pat], T![')'] } - - /// Visibility. - /// - /// ``` - /// ❰ pub mod ❱ foo; - /// ❰ pub(crate) ❱ struct Bar; - /// ❰ pub(self) ❱ enum Baz {} - /// ❰ pub(super) ❱ fn bruh() {} - /// ❰ pub(in bruuh::bruuuh) ❱ type T = u64; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html) - struct Visibility { T![pub], T![super], T![self], T![crate] } - - /// Single identifier. - /// Note(@matklad): `Name` is for things that install a new name into the scope, - /// `NameRef` is a usage of a name. Most of the time, this definition/reference - /// distinction can be determined purely syntactically, ie in - /// ``` - /// fn foo() { foo() } - /// ``` - /// the first foo is `Name`, the second one is `NameRef`. - /// The notable exception are patterns, where in - /// `` - /// let x = 92 - /// ``` - /// `x` can be semantically either a name or a name ref, depeding on - /// wether there's an `x` constant in scope. - /// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db). - /// - /// ``` - /// let ❰ foo ❱ = bar; - /// struct ❰ Baz ❱; - /// fn ❰ bruh ❱() {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/identifiers.html) - struct Name { T![ident] } - - /// Reference to a name. - /// See the explanation on the difference between `Name` and `NameRef` - /// in `Name` ast node docs. - /// - /// ``` - /// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/identifiers.html) - struct NameRef { } - - /// Macro call. - /// Includes all of its attributes and doc comments. - /// - /// ``` - /// ❰ - /// /// Docs - /// #[attr] - /// macro_rules! foo { // macro rules is also a macro call - /// ($bar: tt) => {} - /// } - /// ❱ - /// - /// // semicolon is a part of `MacroCall` when it is used in item positions - /// ❰ foo!(); ❱ - /// - /// fn main() { - /// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/macros.html) - struct MacroCall: NameOwner, AttrsOwner, DocCommentsOwner { - Path, T![!], TokenTree, T![;] - } - - /// Attribute. - /// - /// ``` - /// ❰ #![inner_attr] ❱ - /// - /// ❰ #[attr] ❱ - /// ❰ #[foo = "bar"] ❱ - /// ❰ #[baz(bruh::bruuh = "42")] ❱ - /// struct Foo; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/attributes.html) - struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] } - - /// Stores a list of lexer tokens and other `TokenTree`s. - /// It appears in attributes, macro_rules and macro call (foo!) - /// - /// ``` - /// macro_call! ❰ { my syntax here } ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/macros.html) - struct TokenTree {} - - /// Generic lifetime, type and constants parameters list **declaration**. - /// - /// ``` - /// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {} - /// - /// struct Baz❰ ❱(T); - /// - /// impl❰ ❱ Bruh {} - /// - /// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) - struct TypeParamList { - T![<], - type_params: [TypeParam], - lifetime_params: [LifetimeParam], - const_params: [ConstParam], - T![>] - } - - /// Single type parameter **declaration**. - /// - /// ``` - /// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) - struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { - T![=], - default_type: TypeRef, - } - - /// Const generic parameter **declaration**. - /// ``` - /// fn foo() {} - /// ``` - /// - /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter) - struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { - T![=], - default_val: Expr, - } - - /// Lifetime parameter **declaration**. - /// - /// ``` - /// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) - struct LifetimeParam: AttrsOwner { T![lifetime] } - - /// Type bound declaration clause. - /// - /// ``` - /// fn foo() {} - /// - /// trait Bar - /// where - /// T: ❰ Send ❱ + ❰ Sync ❱ - /// { - /// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱; - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html) - struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef } - - /// Type bounds list. - /// - /// ``` - /// - /// fn foo() {} - /// - /// trait Bar - /// where - /// T: ❰ Send + Sync ❱ - /// { - /// type Baz: ❰ !Sync + Debug ❱; - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html) - struct TypeBoundList { bounds: [TypeBound] } - - /// Single where predicate. - /// - /// ``` - /// trait Foo<'a, 'b, T> - /// where - /// ❰ 'a: 'b ❱, - /// ❰ T: IntoIterator ❱, - /// ❰ for<'c> ::Item: Bar<'c> ❱ - /// {} - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses) - struct WherePred: TypeBoundsOwner { T![for], TypeParamList, T![lifetime], TypeRef } - - /// Where clause. - /// - /// ``` - /// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {} - /// - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses) - struct WhereClause { T![where], predicates: [WherePred] } - - /// Abi declaration. - /// Note: the abi string is optional. - /// - /// ``` - /// ❰ extern "C" ❱ { - /// fn foo() {} - /// } - /// - /// type Bar = ❰ extern ❱ fn() -> u32; - /// - /// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool; - /// ``` - /// - /// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html) - /// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions) - struct Abi { /*String*/ } - - /// Expression statement. - /// - /// ``` - /// ❰ 42; ❱ - /// ❰ foo(); ❱ - /// ❰ (); ❱ - /// ❰ {}; ❱ - /// - /// // constructions with trailing curly brace can omit the semicolon - /// // but only when there are satements immediately after them (this is important!) - /// ❰ if bool_cond { } ❱ - /// ❰ loop {} ❱ - /// ❰ somestatment; ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/statements.html) - struct ExprStmt: AttrsOwner { Expr, T![;] } - - /// Let statement. - /// - /// ``` - /// ❰ #[attr] let foo; ❱ - /// ❰ let bar: u64; ❱ - /// ❰ let baz = 42; ❱ - /// ❰ let bruh: bool = true; ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements) - struct LetStmt: AttrsOwner, TypeAscriptionOwner { - T![let], - Pat, - T![=], - initializer: Expr, - T![;], - } - - /// Condition of `if` or `while` expression. - /// - /// ``` - /// if ❰ true ❱ {} - /// if ❰ let Pat(foo) = bar ❱ {} - /// - /// while ❰ true ❱ {} - /// while ❰ let Pat(baz) = bruh ❱ {} - /// ``` - /// - /// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html) - /// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops) - struct Condition { T![let], Pat, T![=], Expr } - - /// Parameter list **declaration**. - /// - /// ``` - /// fn foo❰ (a: u32, b: bool) ❱ -> u32 {} - /// let bar = ❰ |a, b| ❱ {}; - /// - /// impl Baz { - /// fn bruh❰ (&self, a: u32) ❱ {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script - struct ParamList { // FIXME: this node is used by closure expressions too, but hey use pipes instead of parens... - T!['('], - SelfParam, - params: [Param], - T![')'] - } - - /// Self parameter **declaration**. - /// - /// ``` - /// impl Bruh { - /// fn foo(❰ self ❱) {} - /// fn bar(❰ &self ❱) {} - /// fn baz(❰ &mut self ❱) {} - /// fn blah<'a>(❰ &'a self ❱) {} - /// fn blin(❰ self: Box ❱) {} - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) - struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] } - - /// Parameter **declaration**. - /// - /// ``` - /// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {} - /// - /// extern "C" { - /// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32; - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) - struct Param: TypeAscriptionOwner, AttrsOwner { - Pat, - T![...] - } - - /// Use declaration. - /// - /// ``` - /// ❰ #[attr] pub use foo; ❱ - /// ❰ use bar as baz; ❱ - /// ❰ use bruh::{self, bruuh}; ❱ - /// ❰ use { blin::blen, blah::* }; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) - struct UseItem: AttrsOwner, VisibilityOwner { - T![use], - UseTree, - } - - /// Use tree. - /// - /// ``` - /// pub use ❰ foo::❰ * ❱ ❱; - /// use ❰ bar as baz ❱; - /// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱; - /// use ❰ { ❰ blin::blen ❱ } ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) - struct UseTree { - Path, T![*], UseTreeList, Alias - } - - /// Item alias. - /// Note: this is not the type alias. - /// - /// ``` - /// use foo ❰ as bar ❱; - /// use baz::{bruh ❰ as _ ❱}; - /// extern crate bruuh ❰ as blin ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) - struct Alias: NameOwner { T![as] } - - /// Sublist of use trees. - /// - /// ``` - /// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱; - /// use ❰ { blin::blen::❰ {} ❱ } ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) - struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] } - - /// Extern crate item. - /// - /// ``` - /// ❰ #[attr] pub extern crate foo; ❱ - /// ❰ extern crate self as bar; ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html) - struct ExternCrateItem: AttrsOwner, VisibilityOwner { - T![extern], T![crate], NameRef, Alias, - } - - /// Call site arguments list. - /// - /// ``` - /// foo::❰ (42, true) ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html) - struct ArgList { - T!['('], - args: [Expr], - T![')'] - } - - /// Path to a symbol. Includes single identifier names and elaborate paths with - /// generic parameters. - /// - /// ``` - /// (0..10).❰ ❰ collect ❱ ::> ❱(); - /// ❰ ❰ ❰ Vec ❱ :: ❱ ::with_capacity ❱(1024); - /// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱(); - /// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱(); - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html) - struct Path { - segment: PathSegment, - T![::], - qualifier: Path, - } - - /// Segment of the path to a symbol. - /// Only path segment of an absolute path holds the `::` token, - /// all other `::` tokens that connect path segments reside under `Path` itself.` - /// - /// ``` - /// (0..10).❰ collect ❱ :: ❰ > ❱(); - /// ❰ Vec ❱ :: ❰ ❱ :: ❰ with_capacity ❱(1024); - /// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱(); - /// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱(); - /// - /// // Note that only in this case `::` token is inlcuded: - /// ❰ ::foo ❱; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html) - struct PathSegment { - T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] - } - - /// List of type arguments that are passed at generic instantiation site. - /// - /// ``` - /// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar; - /// - /// Vec❰ :: ❱::(); - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) - struct TypeArgList { - T![::], - T![<], - generic_args: [GenericArg], - type_args: [TypeArg], - lifetime_args: [LifetimeArg], - assoc_type_args: [AssocTypeArg], - const_args: [ConstArg], - T![>] - } - - /// Type argument that is passed at generic instantiation site. - /// - /// ``` - /// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) - struct TypeArg { TypeRef } - - /// Associated type argument that is passed at generic instantiation site. - /// ``` - /// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh; - /// - /// trait Bruh: Iterator<❰ Item: Debug ❱> {} - /// ``` - /// - struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef } - - /// Lifetime argument that is passed at generic instantiation site. - /// - /// ``` - /// fn foo<'a>(s: &'a str) { - /// bar::<❰ 'a ❱>(s); - /// } - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) - struct LifetimeArg { T![lifetime] } - - /// Constant value argument that is passed at generic instantiation site. - /// - /// ``` - /// foo::(); - /// - /// bar::<❰ { 2 + 2} ❱>(); - /// ``` - /// - /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter) - struct ConstArg { Literal, BlockExpr } - - - /// FIXME: (@edwin0cheng) Remove it to use ItemList instead - /// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243 - /// - /// [Reference](https://doc.rust-lang.org/reference/macros.html) - struct MacroItems: ModuleItemOwner { } - - /// FIXME: (@edwin0cheng) add some documentation here. As per the writing - /// of this comment this ast node is not used. - /// - /// ``` - /// // FIXME: example here - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/macros.html) - struct MacroStmts { - statements: [Stmt], - Expr, - } - - /// List of items in an extern block. - /// - /// ``` - /// extern "C" ❰ - /// { - /// fn foo(); - /// static var: u32; - /// } - /// ❱ - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html) - struct ExternItemList: ModuleItemOwner { - T!['{'], - extern_items: [ExternItem], - T!['}'] - } - - /// Extern block. - /// - /// ``` - /// ❰ - /// extern "C" { - /// fn foo(); - /// } - /// ❱ - /// - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html) - struct ExternBlock { - Abi, - ExternItemList - } - - /// Meta item in an attribute. - /// - /// ``` - /// #[❰ bar::baz = "42" ❱] - /// #[❰ bruh(bruuh("true")) ❱] - /// struct Foo; - /// ``` - /// - /// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax) - struct MetaItem { - Path, T![=], AttrInput, nested_meta_items: [MetaItem] - } - - /// Macro 2.0 definition. - /// Their syntax is still WIP by rustc team... - /// ``` - /// ❰ - /// macro foo { } - /// ❱ - /// ``` - /// - /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md) - struct MacroDef { - Name, TokenTree - } - }, - enums: ast_enums! { - /// Any kind of nominal type definition. - enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { - StructDef, EnumDef, UnionDef, - } - - /// Any kind of generic argument passed at instantiation site - enum GenericArg { - LifetimeArg, - TypeArg, - ConstArg, - AssocTypeArg - } - - /// Any kind of construct valid in type context - enum TypeRef { - ParenType, - TupleType, - NeverType, - PathType, - PointerType, - ArrayType, - SliceType, - ReferenceType, - PlaceholderType, - FnPointerType, - ForType, - ImplTraitType, - DynTraitType, - } - - /// Any kind of top-level item that may appear in a module - enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner { - StructDef, - UnionDef, - EnumDef, - FnDef, - TraitDef, - TypeAliasDef, - ImplDef, - UseItem, - ExternCrateItem, - ConstDef, - StaticDef, - Module, - MacroCall, - ExternBlock - } - - - - /// Any kind of item that may appear in an impl block - /// - /// // FIXME: impl blocks can also contain MacroCall - enum AssocItem: NameOwner, AttrsOwner { - FnDef, TypeAliasDef, ConstDef - } - - /// Any kind of item that may appear in an extern block - /// - /// // FIXME: extern blocks can also contain MacroCall - enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner { - FnDef, StaticDef - } - - /// Any kind of expression - enum Expr: AttrsOwner { - TupleExpr, - ArrayExpr, - ParenExpr, - PathExpr, - LambdaExpr, - IfExpr, - LoopExpr, - ForExpr, - WhileExpr, - ContinueExpr, - BreakExpr, - Label, - BlockExpr, - ReturnExpr, - MatchExpr, - RecordLit, - CallExpr, - IndexExpr, - MethodCallExpr, - FieldExpr, - AwaitExpr, - TryExpr, - EffectExpr, - CastExpr, - RefExpr, - PrefixExpr, - RangeExpr, - BinExpr, - Literal, - MacroCall, - BoxExpr, - } - - /// Any kind of pattern - enum Pat { - OrPat, - ParenPat, - RefPat, - BoxPat, - BindPat, - PlaceholderPat, - DotDotPat, - PathPat, - RecordPat, - TupleStructPat, - TuplePat, - SlicePat, - RangePat, - LiteralPat, - MacroPat, - } - - /// Any kind of input to an attribute - enum AttrInput { Literal, TokenTree } - - /// Any kind of statement - /// Note: there are no empty statements, these are just represented as - /// bare semicolons without a dedicated statement ast node. - enum Stmt { - LetStmt, - ExprStmt, - // macro calls are parsed as expression statements - } - - /// Any kind of fields list (record or tuple field lists) - enum FieldDefList { - RecordFieldDefList, - TupleFieldDefList, - } - }, - } -} diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 5a18b3e2b..24e8be1fb 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs @@ -3,19 +3,27 @@ //! Specifically, it generates the `SyntaxKind` enum and a number of newtype //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. -use std::{collections::HashSet, fmt::Write}; +use std::{ + collections::{BTreeSet, HashSet}, + fmt::Write, +}; use proc_macro2::{Punct, Spacing}; use quote::{format_ident, quote}; +use ungrammar::{Grammar, Rule}; use crate::{ - ast_src::{rust_ast, AstSrc, Field, FieldSrc, KindsSrc, KINDS_SRC}, + ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Field, FieldSrc, KindsSrc, KINDS_SRC}, codegen::{self, update, Mode}, project_root, Result, }; pub fn generate_syntax(mode: Mode) -> Result<()> { - let ast = rust_ast(); + let grammar = include_str!("rust.ungram") + .parse::() + .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err)); + let ast = lower(&grammar); + let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; @@ -215,7 +223,9 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result { .map(|kind| to_pascal_case(kind)) .filter(|name| !defined_nodes.iter().any(|&it| it == name)) { - eprintln!("Warning: node {} not defined in ast source", node); + drop(node) + // TODO: restore this + // eprintln!("Warning: node {} not defined in ast source", node); } let ast = quote! { @@ -414,6 +424,10 @@ fn to_pascal_case(s: &str) -> String { buf } +fn pluralize(s: &str) -> String { + format!("{}s", s) +} + impl Field { fn is_many(&self) -> bool { matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) @@ -449,6 +463,7 @@ impl Field { "." => "dot", ".." => "dotdot", "..." => "dotdotdot", + "..=" => "dotdoteq", "=>" => "fat_arrow", "@" => "at", ":" => "colon", @@ -475,3 +490,204 @@ impl Field { } } } + +fn lower(grammar: &Grammar) -> AstSrc { + let mut res = AstSrc::default(); + res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; + + let nodes = grammar + .iter() + .filter(|&node| match grammar[node].rule { + Rule::Node(it) if it == node => false, + _ => true, + }) + .collect::>(); + + for &node in &nodes { + let name = grammar[node].name.clone(); + let rule = &grammar[node].rule; + match lower_enum(grammar, rule) { + Some(variants) => { + let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants }; + res.enums.push(enum_src); + } + None => { + let mut fields = Vec::new(); + lower_rule(&mut fields, grammar, rule); + res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields }); + } + } + } + + deduplicate_fields(&mut res); + extract_enums(&mut res); + extract_struct_traits(&mut res); + extract_enum_traits(&mut res); + res +} + +fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option> { + let alternatives = match rule { + Rule::Alt(it) => it, + _ => return None, + }; + let mut variants = Vec::new(); + for alternative in alternatives { + match alternative { + Rule::Node(it) => variants.push(grammar[*it].name.clone()), + _ => return None, + } + } + Some(variants) +} + +fn lower_rule(acc: &mut Vec, grammar: &Grammar, rule: &Rule) { + match rule { + Rule::Node(node) => { + let field = Field::Node { name: grammar[*node].name.clone(), src: FieldSrc::Shorthand }; + acc.push(field); + } + Rule::Token(token) => { + let mut name = grammar[*token].name.clone(); + if name != "int_number" && name != "string" { + if "[]{}()".contains(&name) { + name = format!("'{}'", name); + } + let field = Field::Token(name); + acc.push(field); + } + } + Rule::Rep(inner) => { + if let Rule::Node(node) = &**inner { + let name = grammar[*node].name.clone(); + let label = pluralize(&to_lower_snake_case(&name)); + let field = Field::Node { name: label.clone(), src: FieldSrc::Many(name) }; + acc.push(field); + return; + } + todo!("{:?}", rule) + } + Rule::Labeled { label, rule } => { + let node = match &**rule { + Rule::Rep(inner) | Rule::Opt(inner) => match &**inner { + Rule::Node(node) => node, + _ => todo!("{:?}", rule), + }, + Rule::Node(node) => node, + _ => todo!("{:?}", rule), + }; + let field = Field::Node { + name: label.clone(), + src: match &**rule { + Rule::Rep(_) => FieldSrc::Many(grammar[*node].name.clone()), + _ => FieldSrc::Optional(grammar[*node].name.clone()), + }, + }; + acc.push(field); + } + Rule::Seq(rules) | Rule::Alt(rules) => { + for rule in rules { + lower_rule(acc, grammar, rule) + } + } + Rule::Opt(rule) => lower_rule(acc, grammar, rule), + } +} + +fn deduplicate_fields(ast: &mut AstSrc) { + eprintln!(); + for node in &mut ast.nodes { + let mut i = 0; + 'outer: while i < node.fields.len() { + for j in 0..i { + let f1 = &node.fields[i]; + let f2 = &node.fields[j]; + if f1 == f2 { + node.fields.remove(i); + continue 'outer; + } + } + i += 1; + } + } +} + +fn extract_enums(ast: &mut AstSrc) { + for node in &mut ast.nodes { + for enm in &ast.enums { + let mut to_remove = Vec::new(); + for (i, field) in node.fields.iter().enumerate() { + let ty = field.ty().to_string(); + if enm.variants.iter().any(|it| it == &ty) { + to_remove.push(i); + } + } + if to_remove.len() == enm.variants.len() { + node.remove_field(to_remove); + node.fields.push(Field::Node { name: enm.name.clone(), src: FieldSrc::Shorthand }); + } + } + } +} + +fn extract_struct_traits(ast: &mut AstSrc) { + let traits: &[(&str, &[&str])] = &[ + ("AttrsOwner", &["attrs"]), + ("NameOwner", &["name"]), + ("VisibilityOwner", &["visibility"]), + ("TypeParamsOwner", &["type_param_list", "where_clause"]), + ("TypeBoundsOwner", &["type_bound_list", "colon_token"]), + ("ModuleItemOwner", &["items"]), + ("TypeAscriptionOwner", &["ascribed_type"]), + ("LoopBodyOwner", &["label", "loop_body"]), + ("ArgListOwner", &["arg_list"]), + ]; + + for node in &mut ast.nodes { + for (name, methods) in traits { + extract_struct_trait(node, name, methods); + } + } +} + +fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) { + let mut to_remove = Vec::new(); + for (i, field) in node.fields.iter().enumerate() { + let method_name = field.method_name().to_string(); + if methods.iter().any(|&it| it == &method_name) { + to_remove.push(i); + } + } + if to_remove.len() == methods.len() { + node.traits.push(trait_name.to_string()); + node.remove_field(to_remove); + } +} + +fn extract_enum_traits(ast: &mut AstSrc) { + for enm in &mut ast.enums { + let nodes = &ast.nodes; + let mut variant_traits = enm + .variants + .iter() + .map(|var| nodes.iter().find(|it| &it.name == var).unwrap()) + .map(|node| node.traits.iter().cloned().collect::>()); + + let mut enum_traits = match variant_traits.next() { + Some(it) => it, + None => continue, + }; + for traits in variant_traits { + enum_traits = enum_traits.intersection(&traits).cloned().collect(); + } + enm.traits = enum_traits.into_iter().collect(); + } +} + +impl AstNodeSrc { + fn remove_field(&mut self, to_remove: Vec) { + to_remove.into_iter().rev().for_each(|idx| { + self.fields.remove(idx); + }); + } +} diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram new file mode 100644 index 000000000..8a3eb7b29 --- /dev/null +++ b/xtask/src/codegen/rust.ungram @@ -0,0 +1,529 @@ +SourceFile = + Attr* + items:ModuleItem* + +FnDef = + Attr* Visibility? Abi? 'const' 'default' 'async' 'unsafe' 'fn' Name TypeParamList? + ParamList RetType? + WhereClause? + (body:BlockExpr | ';') + +RetType = + '->' TypeRef + +StructDef = + Attr* Visibility? 'struct' Name TypeParamList? ( + WhereClause? (RecordFieldDefList | ';') + | TupleFieldDefList WhereClause? ';' + ) + +UnionDef = + Attr* Visibility? 'union' Name TypeParamList? WhereClause? + RecordFieldDefList + +RecordFieldDefList = + '{' fields:RecordFieldDef* '}' + +RecordFieldDef = + Attr* Visibility? Name ':' ascribed_type:TypeRef + +TupleFieldDefList = + '(' fields:TupleFieldDef* ')' + +TupleFieldDef = + Attr* Visibility? Name TypeRef + +FieldDefList = + RecordFieldDefList +| TupleFieldDefList + +EnumDef = + Attr* Visibility? 'enum' Name TypeParamList? WhereClause? + variant_list:EnumVariantList + +EnumVariantList = + '{' variants:EnumVariant* '}' + +EnumVariant = + Attr* Visibility? Name FieldDefList ('=' Expr)? + +TraitDef = + Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name TypeParamList + (':' TypeBoundList?)? WhereClause + ItemList + +Module = + Attr* Visibility? 'mod' Name + (ItemList | ';') + +ItemList = + '{' + AssocItem* + items:ModuleItem* + '}' + +ConstDef = + Attr* Visibility? 'default'? 'const' Name ':' ascribed_type:TypeRef + '=' body:Expr ';' + +StaticDef = + Attr* Visibility? 'static'? 'mut'? 'static' Name ':' ascribed_type:TypeRef + '=' body:Expr ';' + +TypeAliasDef = + Attr* Visibility? 'default'? 'type' Name TypeParamList? WhereClause? (':' TypeBoundList?)? + '=' TypeRef ';' + +ImplDef = + Attr* Visibility? 'const'? 'default'? 'unsafe'? 'impl' TypeParamList? '!'? 'for' + WhereClause? + ItemList + +ParenType = + '(' TypeRef ')' + +TupleType = + '(' fields:TypeRef* ')' + +NeverType = + '!' + +PathType = + Path + +PointerType = + '*' ('const' | 'mut') TypeRef + +ArrayType = + '[' TypeRef ';' Expr ']' + +SliceType = + '[' TypeRef ']' + +ReferenceType = + '&' 'lifetime'? 'mut'? TypeRef + +PlaceholderType = + '_' + +FnPointerType = + Abi 'unsafe'? 'fn' ParamList RetType? + +ForType = + 'for' TypeParamList TypeRef + +ImplTraitType = + 'impl' TypeBoundList + +DynTraitType = + 'dyn' TypeBoundList + +TupleExpr = + Attr* '(' Expr* ')' + +ArrayExpr = + Attr* '[' (Expr* | Expr ';' Expr) ']' + +ParenExpr = + Attr* '(' Expr ')' + +PathExpr = + Path + +LambdaExpr = + Attr* 'static'? 'async'? 'move'? ParamList RetType? + body:Expr + +IfExpr = + Attr* 'if' Condition + +Condition = + 'let' Pat '=' Expr +| Expr + +EffectExpr = + Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr + +LoopExpr = + Attr* Label? 'loop' + loop_body:BlockExpr? + +ForExpr = + Attr* Label? 'for' Pat 'in' iterable:Expr + loop_body:BlockExpr? + +WhileExpr = + Attr* Label? 'while' Condition + loop_body:BlockExpr? + +ContinueExpr = + Attr* 'continue' 'lifetime'? + +BreakExpr = + Attr* 'break' 'lifetime'? Expr? + +Label = + 'lifetime' + +BlockExpr = + Attr* Label + '{' + items:ModuleItem* + statements:Stmt* + Expr? + '}' + +ReturnExpr = + Attr* 'return' Expr + +CallExpr = + Attr* Expr ArgList + +MethodCallExpr = + Attr* Expr '.' NameRef TypeArgList? ArgList + +ArgList = + '(' args:Expr* ')' + +FieldExpr = + Attr* Expr '.' NameRef + +IndexExpr = + Attr* '[' ']' + +AwaitExpr = + Attr* Expr '.' 'await' + +TryExpr = + Attr* Expr '?' + +CastExpr = + Attr* Expr 'as' TypeRef + +RefExpr = + Attr* '&' ('raw' | 'mut' | 'const') Expr + +PrefixExpr = + Attr* Expr + +BoxExpr = + Attr* 'box' Expr + +RangeExpr = + Attr* + +BinExpr = + Attr* + +Literal = + 'int_number' + +MatchExpr = + Attr* 'match' Expr MatchArmList + +MatchArmList = + '{' arms:MatchArm* '}' + +MatchArm = + Attr* Pat guard:MatchGuard? '=>' Expr + +MatchGuard = + 'if' Expr + +RecordLit = + Path RecordFieldList + +RecordFieldList = + '{' + fields:RecordField* + ('..' spread:Expr)? + '}' + +RecordField = + Attr* NameRef (':' Expr)? + +OrPat = + Pat* + +ParenPat = + '(' Pat ')' + +RefPat = + '&' 'mut'? Pat + +BoxPat = + 'box' Path + +BindPat = + Attr* 'ref'? 'mut'? Name ('@' Pat)? + +PlaceholderPat = + '_' + +DotDotPat = + '..' + +PathPat = + Path + +SlicePat = + '[' args:Pat* ']' + +RangePat = + '..' | '..=' + +LiteralPat = + Literal + +MacroPat = + MacroCall + +RecordPat = + Path RecordFieldPatList + +RecordFieldPatList = + '{' + record_field_pats:RecordFieldPat* + BindPat* + '..'? + '}' + +RecordFieldPat = + Attr* NameRef ':' Pat + +TupleStructPat = + Path '(' args:Pat* ')' + +TuplePat = + '(' args:Pat* ')' + +Visibility = + 'pub' ('(' 'super' | 'self' | 'crate' | 'in' Path ')')? + +Name = + 'ident' + +NameRef = + 'ident' | 'int_number' + +MacroCall = + Attr* Path '!' Name? TokenTree ';'? + +MacroDef = + Name TokenTree + +TokenTree = + '(' ')' | '{' '}' | '[' ']' + +MacroItems = + items:ModuleItem* + +MacroStmts = + statements:Stmt* + Expr? + +Attr = + '#' '!'? '[' Path ('=' input:AttrInput)? ']' + +TypeParamList = + '<' + TypeParam* + LifetimeParam* + ConstParam* + '>' + +TypeParam = + Attr* Name (':' TypeBoundList?)? + ('=' default_type:TypeRef)? + +ConstParam = + Attr* 'const' Name ':' ascribed_type:TypeRef + ('=' default_val:Expr)? + +LifetimeParam = + Attr* 'lifetime' + +TypeBound = + 'lifetime' | 'const'? TypeRef + +TypeBoundList = + bounds:TypeBound* + +WherePred = + ('for' TypeParamList)? ('lifetime' | TypeRef) ':' TypeBoundList + +WhereClause = + 'where' predicates:WherePred* + +Abi = + 'string' + +ExprStmt = + Attr* Expr ';' + +LetStmt = + Attr* 'let' Pat (':' ascribed_type:TypeRef) + '=' initializer:Expr ';' + +ParamList = + '(' SelfParam Param* ')' + +SelfParam = + Attr* ('&' 'lifetime'?)? 'mut'? 'self' (':' ascribed_type:TypeRef) + +Param = + Attr* Pat (':' ascribed_type:TypeRef) +| '...' + +UseItem = + Attr* Visibility? 'use' UseTree ';' + +UseTree = + Path ('::' ('*' | UseTreeList)) Alias? + +UseTreeList = + '{' UseTree* '}' + +Alias = + 'as' Name + +ExternCrateItem = + Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Alias? ';' + +Path = + (qualifier:Path '::')? segment:PathSegment + +PathSegment = + '::' | 'crate' | 'self' | 'super' +| '<' NameRef TypeArgList ParamList RetType PathType '>' + +TypeArgList = + '::'? '<' + TypeArg* + LifetimeArg* + AssocTypeArg* + ConstArg* + '>' + +TypeArg = + TypeRef + +AssocTypeArg = + NameRef (':' TypeBoundList | '=' TypeRef) + +LifetimeArg = + 'lifetime' + +ConstArg = + Literal | BlockExpr BlockExpr + +ExternBlock = + Attr* Abi ExternItemList + +ExternItemList = + '{' extern_items:ExternItem* '}' + +MetaItem = + Path '=' AttrInput nested_meta_items:MetaItem* + +NominalDef = + StructDef +| EnumDef +| UnionDef + +TypeRef = + ParenType +| TupleType +| NeverType +| PathType +| PointerType +| ArrayType +| SliceType +| ReferenceType +| PlaceholderType +| FnPointerType +| ForType +| ImplTraitType +| DynTraitType + +AssocItem = + FnDef +| TypeAliasDef +| ConstDef + +ExternItem = + FnDef | StaticDef + +ModuleItem = + StructDef +| UnionDef +| EnumDef +| FnDef +| TraitDef +| TypeAliasDef +| ImplDef +| UseItem +| ExternCrateItem +| ConstDef +| StaticDef +| Module +| MacroCall +| ExternBlock + +AttrInput = + Literal +| TokenTree + +Stmt = + LetStmt +| ExprStmt + +Pat = + OrPat +| ParenPat +| RefPat +| BoxPat +| BindPat +| PlaceholderPat +| DotDotPat +| PathPat +| RecordPat +| TupleStructPat +| TuplePat +| SlicePat +| RangePat +| LiteralPat +| MacroPat + +Expr = + TupleExpr +| ArrayExpr +| ParenExpr +| PathExpr +| LambdaExpr +| IfExpr +| LoopExpr +| ForExpr +| WhileExpr +| ContinueExpr +| BreakExpr +| Label +| BlockExpr +| ReturnExpr +| MatchExpr +| RecordLit +| CallExpr +| IndexExpr +| MethodCallExpr +| FieldExpr +| AwaitExpr +| TryExpr +| EffectExpr +| CastExpr +| RefExpr +| PrefixExpr +| RangeExpr +| BinExpr +| Literal +| MacroCall +| BoxExpr -- cgit v1.2.3