diff options
Diffstat (limited to 'xtask/src')
| -rw-r--r-- | xtask/src/ast_src.rs | 2080 | ||||
| -rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 290 | ||||
| -rw-r--r-- | xtask/src/codegen/rust.ungram | 544 | ||||
| -rw-r--r-- | xtask/src/dist.rs | 56 | ||||
| -rw-r--r-- | xtask/src/install.rs | 14 | ||||
| -rw-r--r-- | xtask/src/lib.rs | 3 | ||||
| -rw-r--r-- | xtask/src/main.rs | 29 | ||||
| -rw-r--r-- | xtask/src/metrics.rs | 279 | ||||
| -rw-r--r-- | xtask/src/not_bash.rs | 20 | ||||
| -rw-r--r-- | xtask/src/release.rs | 36 |
10 files changed, 1259 insertions, 2092 deletions
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 392648d71..114898e38 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
| @@ -93,19 +93,19 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 93 | ], | 93 | ], |
| 94 | nodes: &[ | 94 | nodes: &[ |
| 95 | "SOURCE_FILE", | 95 | "SOURCE_FILE", |
| 96 | "STRUCT_DEF", | 96 | "STRUCT", |
| 97 | "UNION_DEF", | 97 | "UNION", |
| 98 | "ENUM_DEF", | 98 | "ENUM", |
| 99 | "FN_DEF", | 99 | "FN", |
| 100 | "RET_TYPE", | 100 | "RET_TYPE", |
| 101 | "EXTERN_CRATE_ITEM", | 101 | "EXTERN_CRATE", |
| 102 | "MODULE", | 102 | "MODULE", |
| 103 | "USE_ITEM", | 103 | "USE", |
| 104 | "STATIC_DEF", | 104 | "STATIC", |
| 105 | "CONST_DEF", | 105 | "CONST", |
| 106 | "TRAIT_DEF", | 106 | "TRAIT", |
| 107 | "IMPL_DEF", | 107 | "IMPL", |
| 108 | "TYPE_ALIAS_DEF", | 108 | "TYPE_ALIAS", |
| 109 | "MACRO_CALL", | 109 | "MACRO_CALL", |
| 110 | "TOKEN_TREE", | 110 | "TOKEN_TREE", |
| 111 | "MACRO_DEF", | 111 | "MACRO_DEF", |
| @@ -159,9 +159,9 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 159 | "MATCH_ARM_LIST", | 159 | "MATCH_ARM_LIST", |
| 160 | "MATCH_ARM", | 160 | "MATCH_ARM", |
| 161 | "MATCH_GUARD", | 161 | "MATCH_GUARD", |
| 162 | "RECORD_LIT", | 162 | "RECORD_EXPR", |
| 163 | "RECORD_FIELD_LIST", | 163 | "RECORD_EXPR_FIELD_LIST", |
| 164 | "RECORD_FIELD", | 164 | "RECORD_EXPR_FIELD", |
| 165 | "EFFECT_EXPR", | 165 | "EFFECT_EXPR", |
| 166 | "BOX_EXPR", | 166 | "BOX_EXPR", |
| 167 | // postfix | 167 | // postfix |
| @@ -179,13 +179,14 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 179 | "BIN_EXPR", | 179 | "BIN_EXPR", |
| 180 | "EXTERN_BLOCK", | 180 | "EXTERN_BLOCK", |
| 181 | "EXTERN_ITEM_LIST", | 181 | "EXTERN_ITEM_LIST", |
| 182 | "ENUM_VARIANT", | 182 | "VARIANT", |
| 183 | "RECORD_FIELD_DEF_LIST", | 183 | "RECORD_FIELD_LIST", |
| 184 | "RECORD_FIELD_DEF", | 184 | "RECORD_FIELD", |
| 185 | "TUPLE_FIELD_DEF_LIST", | 185 | "TUPLE_FIELD_LIST", |
| 186 | "TUPLE_FIELD_DEF", | 186 | "TUPLE_FIELD", |
| 187 | "ENUM_VARIANT_LIST", | 187 | "VARIANT_LIST", |
| 188 | "ITEM_LIST", | 188 | "ITEM_LIST", |
| 189 | "ASSOC_ITEM_LIST", | ||
| 189 | "ATTR", | 190 | "ATTR", |
| 190 | "META_ITEM", // not an item actually | 191 | "META_ITEM", // not an item actually |
| 191 | "USE_TREE", | 192 | "USE_TREE", |
| @@ -193,7 +194,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 193 | "PATH", | 194 | "PATH", |
| 194 | "PATH_SEGMENT", | 195 | "PATH_SEGMENT", |
| 195 | "LITERAL", | 196 | "LITERAL", |
| 196 | "ALIAS", | 197 | "RENAME", |
| 197 | "VISIBILITY", | 198 | "VISIBILITY", |
| 198 | "WHERE_CLAUSE", | 199 | "WHERE_CLAUSE", |
| 199 | "WHERE_PRED", | 200 | "WHERE_PRED", |
| @@ -202,7 +203,8 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 202 | "NAME_REF", | 203 | "NAME_REF", |
| 203 | "LET_STMT", | 204 | "LET_STMT", |
| 204 | "EXPR_STMT", | 205 | "EXPR_STMT", |
| 205 | "TYPE_PARAM_LIST", | 206 | "GENERIC_PARAM_LIST", |
| 207 | "GENERIC_PARAM", | ||
| 206 | "LIFETIME_PARAM", | 208 | "LIFETIME_PARAM", |
| 207 | "TYPE_PARAM", | 209 | "TYPE_PARAM", |
| 208 | "CONST_PARAM", | 210 | "CONST_PARAM", |
| @@ -223,2021 +225,37 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
| 223 | ], | 225 | ], |
| 224 | }; | 226 | }; |
| 225 | 227 | ||
| 226 | pub(crate) struct AstSrc<'a> { | 228 | #[derive(Default, Debug)] |
| 227 | pub(crate) tokens: &'a [&'a str], | 229 | pub(crate) struct AstSrc { |
| 228 | pub(crate) nodes: &'a [AstNodeSrc<'a>], | 230 | pub(crate) tokens: Vec<String>, |
| 229 | pub(crate) enums: &'a [AstEnumSrc<'a>], | 231 | pub(crate) nodes: Vec<AstNodeSrc>, |
| 230 | } | 232 | pub(crate) enums: Vec<AstEnumSrc>, |
| 231 | |||
| 232 | pub(crate) struct AstNodeSrc<'a> { | ||
| 233 | pub(crate) doc: &'a [&'a str], | ||
| 234 | pub(crate) name: &'a str, | ||
| 235 | pub(crate) traits: &'a [&'a str], | ||
| 236 | pub(crate) fields: &'a [Field<'a>], | ||
| 237 | } | ||
| 238 | |||
| 239 | pub(crate) enum Field<'a> { | ||
| 240 | Token(&'a str), | ||
| 241 | Node { name: &'a str, src: FieldSrc<'a> }, | ||
| 242 | } | ||
| 243 | |||
| 244 | pub(crate) enum FieldSrc<'a> { | ||
| 245 | Shorthand, | ||
| 246 | Optional(&'a str), | ||
| 247 | Many(&'a str), | ||
| 248 | } | 233 | } |
| 249 | 234 | ||
| 250 | pub(crate) struct AstEnumSrc<'a> { | 235 | #[derive(Debug)] |
| 251 | pub(crate) doc: &'a [&'a str], | 236 | pub(crate) struct AstNodeSrc { |
| 252 | pub(crate) name: &'a str, | 237 | pub(crate) doc: Vec<String>, |
| 253 | pub(crate) traits: &'a [&'a str], | 238 | pub(crate) name: String, |
| 254 | pub(crate) variants: &'a [&'a str], | 239 | pub(crate) traits: Vec<String>, |
| 240 | pub(crate) fields: Vec<Field>, | ||
| 255 | } | 241 | } |
| 256 | 242 | ||
| 257 | macro_rules! ast_nodes { | 243 | #[derive(Debug, Eq, PartialEq)] |
| 258 | ($( | 244 | pub(crate) enum Field { |
| 259 | $(#[doc = $doc:expr])+ | 245 | Token(String), |
| 260 | struct $name:ident$(: $($trait:ident),*)? { | 246 | Node { name: String, ty: String, cardinality: Cardinality }, |
| 261 | $($field_name:ident $(![$token:tt])? $(: $ty:tt)?),*$(,)? | ||
| 262 | } | ||
| 263 | )*) => { | ||
| 264 | [$( | ||
| 265 | AstNodeSrc { | ||
| 266 | doc: &[$($doc),*], | ||
| 267 | name: stringify!($name), | ||
| 268 | traits: &[$($(stringify!($trait)),*)?], | ||
| 269 | fields: &[ | ||
| 270 | $(field!($(T![$token])? $field_name $($ty)?)),* | ||
| 271 | ], | ||
| 272 | |||
| 273 | } | ||
| 274 | ),*] | ||
| 275 | }; | ||
| 276 | } | 247 | } |
| 277 | 248 | ||
| 278 | macro_rules! field { | 249 | #[derive(Debug, Eq, PartialEq)] |
| 279 | (T![$token:tt] T) => { | 250 | pub(crate) enum Cardinality { |
| 280 | Field::Token(stringify!($token)) | 251 | Optional, |
| 281 | }; | 252 | Many, |
| 282 | ($field_name:ident) => { | ||
| 283 | Field::Node { name: stringify!($field_name), src: FieldSrc::Shorthand } | ||
| 284 | }; | ||
| 285 | ($field_name:ident [$ty:ident]) => { | ||
| 286 | Field::Node { name: stringify!($field_name), src: FieldSrc::Many(stringify!($ty)) } | ||
| 287 | }; | ||
| 288 | ($field_name:ident $ty:ident) => { | ||
| 289 | Field::Node { name: stringify!($field_name), src: FieldSrc::Optional(stringify!($ty)) } | ||
| 290 | }; | ||
| 291 | } | 253 | } |
| 292 | 254 | ||
| 293 | macro_rules! ast_enums { | 255 | #[derive(Debug)] |
| 294 | ($( | 256 | pub(crate) struct AstEnumSrc { |
| 295 | $(#[doc = $doc:expr])+ | 257 | pub(crate) doc: Vec<String>, |
| 296 | enum $name:ident $(: $($trait:ident),*)? { | 258 | pub(crate) name: String, |
| 297 | $($variant:ident),*$(,)? | 259 | pub(crate) traits: Vec<String>, |
| 298 | } | 260 | pub(crate) variants: Vec<String>, |
| 299 | )*) => { | ||
| 300 | [$( | ||
| 301 | AstEnumSrc { | ||
| 302 | doc: &[$($doc),*], | ||
| 303 | name: stringify!($name), | ||
| 304 | traits: &[$($(stringify!($trait)),*)?], | ||
| 305 | variants: &[$(stringify!($variant)),*], | ||
| 306 | } | ||
| 307 | ),*] | ||
| 308 | }; | ||
| 309 | } | 261 | } |
| 310 | |||
| 311 | pub(crate) const AST_SRC: AstSrc = AstSrc { | ||
| 312 | tokens: &["Whitespace", "Comment", "String", "RawString"], | ||
| 313 | nodes: &ast_nodes! { | ||
| 314 | /// The entire Rust source file. Includes all top-level inner attributes and module items. | ||
| 315 | /// | ||
| 316 | /// [Reference](https://doc.rust-lang.org/reference/crates-and-source-files.html) | ||
| 317 | struct SourceFile: ModuleItemOwner, AttrsOwner, DocCommentsOwner { | ||
| 318 | modules: [Module], | ||
| 319 | } | ||
| 320 | |||
| 321 | /// Function definition either with body or not. | ||
| 322 | /// Includes all of its attributes and doc comments. | ||
| 323 | /// | ||
| 324 | /// ``` | ||
| 325 | /// ❰ | ||
| 326 | /// /// Docs | ||
| 327 | /// #[attr] | ||
| 328 | /// pub extern "C" fn foo<T>(#[attr] Patern {p}: Pattern) -> u32 | ||
| 329 | /// where | ||
| 330 | /// T: Debug | ||
| 331 | /// { | ||
| 332 | /// 42 | ||
| 333 | /// } | ||
| 334 | /// ❱ | ||
| 335 | /// | ||
| 336 | /// extern "C" { | ||
| 337 | /// ❰ fn fn_decl(also_variadic_ffi: u32, ...) -> u32; ❱ | ||
| 338 | /// } | ||
| 339 | /// ``` | ||
| 340 | /// | ||
| 341 | /// - [Reference](https://doc.rust-lang.org/reference/items/functions.html) | ||
| 342 | /// - [Nomicon](https://doc.rust-lang.org/nomicon/ffi.html#variadic-functions) | ||
| 343 | struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { | ||
| 344 | Abi, | ||
| 345 | T![const], | ||
| 346 | T![default], | ||
| 347 | T![async], | ||
| 348 | T![unsafe], | ||
| 349 | T![fn], | ||
| 350 | ParamList, | ||
| 351 | RetType, | ||
| 352 | body: BlockExpr, | ||
| 353 | T![;] | ||
| 354 | } | ||
| 355 | |||
| 356 | /// Return type annotation. | ||
| 357 | /// | ||
| 358 | /// ``` | ||
| 359 | /// fn foo(a: u32) ❰ -> Option<u32> ❱ { Some(a) } | ||
| 360 | /// ``` | ||
| 361 | /// | ||
| 362 | /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) | ||
| 363 | struct RetType { T![->], TypeRef } | ||
| 364 | |||
| 365 | /// Struct definition. | ||
| 366 | /// Includes all of its attributes and doc comments. | ||
| 367 | /// | ||
| 368 | /// ``` | ||
| 369 | /// ❰ | ||
| 370 | /// /// Docs | ||
| 371 | /// #[attr] | ||
| 372 | /// struct Foo<T> where T: Debug { | ||
| 373 | /// /// Docs | ||
| 374 | /// #[attr] | ||
| 375 | /// pub a: u32, | ||
| 376 | /// b: T, | ||
| 377 | /// } | ||
| 378 | /// ❱ | ||
| 379 | /// | ||
| 380 | /// ❰ struct Foo; ❱ | ||
| 381 | /// ❰ struct Foo<T>(#[attr] T) where T: Debug; ❱ | ||
| 382 | /// ``` | ||
| 383 | /// | ||
| 384 | /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) | ||
| 385 | struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { | ||
| 386 | T![struct], | ||
| 387 | FieldDefList, | ||
| 388 | T![;] | ||
| 389 | } | ||
| 390 | |||
| 391 | /// Union definition. | ||
| 392 | /// Includes all of its attributes and doc comments. | ||
| 393 | /// | ||
| 394 | /// ``` | ||
| 395 | /// ❰ | ||
| 396 | /// /// Docs | ||
| 397 | /// #[attr] | ||
| 398 | /// pub union Foo<T> where T: Debug { | ||
| 399 | /// /// Docs | ||
| 400 | /// #[attr] | ||
| 401 | /// a: T, | ||
| 402 | /// b: u32, | ||
| 403 | /// } | ||
| 404 | /// ❱ | ||
| 405 | /// ``` | ||
| 406 | /// | ||
| 407 | /// [Reference](https://doc.rust-lang.org/reference/items/unions.html) | ||
| 408 | struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { | ||
| 409 | T![union], | ||
| 410 | RecordFieldDefList, | ||
| 411 | } | ||
| 412 | |||
| 413 | /// Record field definition list including enclosing curly braces. | ||
| 414 | /// | ||
| 415 | /// ``` | ||
| 416 | /// struct Foo // same for union | ||
| 417 | /// ❰ | ||
| 418 | /// { | ||
| 419 | /// a: u32, | ||
| 420 | /// b: bool, | ||
| 421 | /// } | ||
| 422 | /// ❱ | ||
| 423 | /// ``` | ||
| 424 | /// | ||
| 425 | /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) | ||
| 426 | struct RecordFieldDefList { T!['{'], fields: [RecordFieldDef], T!['}'] } | ||
| 427 | |||
| 428 | /// Record field definition including its attributes and doc comments. | ||
| 429 | /// | ||
| 430 | /// ` `` | ||
| 431 | /// same for union | ||
| 432 | /// struct Foo { | ||
| 433 | /// ❰ | ||
| 434 | /// /// Docs | ||
| 435 | /// #[attr] | ||
| 436 | /// pub a: u32 | ||
| 437 | /// ❱ | ||
| 438 | /// | ||
| 439 | /// ❰ b: bool ❱ | ||
| 440 | /// } | ||
| 441 | /// ``` | ||
| 442 | /// | ||
| 443 | /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) | ||
| 444 | struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } | ||
| 445 | |||
| 446 | /// Tuple field definition list including enclosing parens. | ||
| 447 | /// | ||
| 448 | /// ``` | ||
| 449 | /// struct Foo ❰ (u32, String, Vec<u32>) ❱; | ||
| 450 | /// ``` | ||
| 451 | /// | ||
| 452 | /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) | ||
| 453 | struct TupleFieldDefList { T!['('], fields: [TupleFieldDef], T![')'] } | ||
| 454 | |||
| 455 | /// Tuple field definition including its attributes. | ||
| 456 | /// | ||
| 457 | /// ``` | ||
| 458 | /// struct Foo(❰ #[attr] u32 ❱); | ||
| 459 | /// ``` | ||
| 460 | /// | ||
| 461 | /// [Reference](https://doc.rust-lang.org/reference/items/structs.html) | ||
| 462 | struct TupleFieldDef: VisibilityOwner, AttrsOwner { | ||
| 463 | TypeRef, | ||
| 464 | } | ||
| 465 | |||
| 466 | /// Enum definition. | ||
| 467 | /// Includes all of its attributes and doc comments. | ||
| 468 | /// | ||
| 469 | /// ``` | ||
| 470 | /// ❰ | ||
| 471 | /// /// Docs | ||
| 472 | /// #[attr] | ||
| 473 | /// pub enum Foo<T> where T: Debug { | ||
| 474 | /// /// Docs | ||
| 475 | /// #[attr] | ||
| 476 | /// Bar, | ||
| 477 | /// Baz(#[attr] u32), | ||
| 478 | /// Bruh { | ||
| 479 | /// a: u32, | ||
| 480 | /// /// Docs | ||
| 481 | /// #[attr] | ||
| 482 | /// b: T, | ||
| 483 | /// } | ||
| 484 | /// } | ||
| 485 | /// ❱ | ||
| 486 | /// ``` | ||
| 487 | /// | ||
| 488 | /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) | ||
| 489 | struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { | ||
| 490 | T![enum], | ||
| 491 | variant_list: EnumVariantList, | ||
| 492 | } | ||
| 493 | |||
| 494 | /// Enum variant definition list including enclosing curly braces. | ||
| 495 | /// | ||
| 496 | /// ``` | ||
| 497 | /// enum Foo | ||
| 498 | /// ❰ | ||
| 499 | /// { | ||
| 500 | /// Bar, | ||
| 501 | /// Baz(u32), | ||
| 502 | /// Bruh { | ||
| 503 | /// a: u32 | ||
| 504 | /// } | ||
| 505 | /// } | ||
| 506 | /// ❱ | ||
| 507 | /// ``` | ||
| 508 | /// | ||
| 509 | /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) | ||
| 510 | struct EnumVariantList { | ||
| 511 | T!['{'], | ||
| 512 | variants: [EnumVariant], | ||
| 513 | T!['}'] | ||
| 514 | } | ||
| 515 | |||
| 516 | /// Enum variant definition including its attributes and discriminant value definition. | ||
| 517 | /// | ||
| 518 | /// ``` | ||
| 519 | /// enum Foo { | ||
| 520 | /// ❰ | ||
| 521 | /// /// Docs | ||
| 522 | /// #[attr] | ||
| 523 | /// Bar | ||
| 524 | /// ❱ | ||
| 525 | /// | ||
| 526 | /// // same for tuple and record variants | ||
| 527 | /// } | ||
| 528 | /// ``` | ||
| 529 | /// | ||
| 530 | /// [Reference](https://doc.rust-lang.org/reference/items/enumerations.html) | ||
| 531 | struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner { | ||
| 532 | FieldDefList, | ||
| 533 | T![=], | ||
| 534 | Expr | ||
| 535 | } | ||
| 536 | |||
| 537 | /// Trait definition. | ||
| 538 | /// Includes all of its attributes and doc comments. | ||
| 539 | /// | ||
| 540 | /// ``` | ||
| 541 | /// ❰ | ||
| 542 | /// /// Docs | ||
| 543 | /// #[attr] | ||
| 544 | /// pub unsafe trait Foo<T>: Debug where T: Debug { | ||
| 545 | /// // ... | ||
| 546 | /// } | ||
| 547 | /// ❱ | ||
| 548 | /// ``` | ||
| 549 | /// | ||
| 550 | /// [Reference](https://doc.rust-lang.org/reference/items/traits.html) | ||
| 551 | struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { | ||
| 552 | T![unsafe], | ||
| 553 | T![auto], | ||
| 554 | T![trait], | ||
| 555 | ItemList, | ||
| 556 | } | ||
| 557 | |||
| 558 | /// Module definition either with body or not. | ||
| 559 | /// Includes all of its inner and outer attributes, module items, doc comments. | ||
| 560 | /// | ||
| 561 | /// ``` | ||
| 562 | /// ❰ | ||
| 563 | /// /// Docs | ||
| 564 | /// #[attr] | ||
| 565 | /// pub mod foo; | ||
| 566 | /// ❱ | ||
| 567 | /// | ||
| 568 | /// ❰ | ||
| 569 | /// /// Docs | ||
| 570 | /// #[attr] | ||
| 571 | /// pub mod bar { | ||
| 572 | /// //! Inner docs | ||
| 573 | /// #![inner_attr] | ||
| 574 | /// } | ||
| 575 | /// ❱ | ||
| 576 | /// ``` | ||
| 577 | /// | ||
| 578 | /// [Reference](https://doc.rust-lang.org/reference/items/modules.html) | ||
| 579 | struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { | ||
| 580 | T![mod], | ||
| 581 | ItemList, | ||
| 582 | T![;] | ||
| 583 | } | ||
| 584 | |||
| 585 | /// Item defintion list. | ||
| 586 | /// This is used for both top-level items and impl block items. | ||
| 587 | /// | ||
| 588 | /// ``` | ||
| 589 | /// ❰ | ||
| 590 | /// fn foo {} | ||
| 591 | /// struct Bar; | ||
| 592 | /// enum Baz; | ||
| 593 | /// trait Bruh; | ||
| 594 | /// const BRUUH: u32 = 42; | ||
| 595 | /// ❱ | ||
| 596 | /// | ||
| 597 | /// impl Foo | ||
| 598 | /// ❰ | ||
| 599 | /// { | ||
| 600 | /// fn bar() {} | ||
| 601 | /// const BAZ: u32 = 42; | ||
| 602 | /// } | ||
| 603 | /// ❱ | ||
| 604 | /// ``` | ||
| 605 | /// | ||
| 606 | /// [Reference](https://doc.rust-lang.org/reference/items.html) | ||
| 607 | struct ItemList: ModuleItemOwner { | ||
| 608 | T!['{'], | ||
| 609 | assoc_items: [AssocItem], | ||
| 610 | T!['}'] | ||
| 611 | } | ||
| 612 | |||
| 613 | /// Constant variable definition. | ||
| 614 | /// Includes all of its attributes and doc comments. | ||
| 615 | /// | ||
| 616 | /// ``` | ||
| 617 | /// ❰ | ||
| 618 | /// /// Docs | ||
| 619 | /// #[attr] | ||
| 620 | /// pub const FOO: u32 = 42; | ||
| 621 | /// ❱ | ||
| 622 | /// ``` | ||
| 623 | /// | ||
| 624 | /// [Reference](https://doc.rust-lang.org/reference/items/constant-items.html) | ||
| 625 | struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { | ||
| 626 | T![default], | ||
| 627 | T![const], | ||
| 628 | T![=], | ||
| 629 | body: Expr, | ||
| 630 | T![;] | ||
| 631 | } | ||
| 632 | |||
| 633 | |||
| 634 | /// Static variable definition. | ||
| 635 | /// Includes all of its attributes and doc comments. | ||
| 636 | /// | ||
| 637 | /// ``` | ||
| 638 | /// ❰ | ||
| 639 | /// /// Docs | ||
| 640 | /// #[attr] | ||
| 641 | /// pub static mut FOO: u32 = 42; | ||
| 642 | /// ❱ | ||
| 643 | /// ``` | ||
| 644 | /// | ||
| 645 | /// [Reference](https://doc.rust-lang.org/reference/items/static-items.html) | ||
| 646 | struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { | ||
| 647 | T![static], | ||
| 648 | T![mut], | ||
| 649 | T![=], | ||
| 650 | body: Expr, | ||
| 651 | T![;] | ||
| 652 | } | ||
| 653 | |||
| 654 | /// Type alias definition. | ||
| 655 | /// Includes associated type clauses with type bounds. | ||
| 656 | /// | ||
| 657 | /// ``` | ||
| 658 | /// ❰ | ||
| 659 | /// /// Docs | ||
| 660 | /// #[attr] | ||
| 661 | /// pub type Foo<T> where T: Debug = T; | ||
| 662 | /// ❱ | ||
| 663 | /// | ||
| 664 | /// trait Bar { | ||
| 665 | /// ❰ type Baz: Debug; ❱ | ||
| 666 | /// ❰ type Bruh = String; ❱ | ||
| 667 | /// ❰ type Bruuh: Debug = u32; ❱ | ||
| 668 | /// } | ||
| 669 | /// ``` | ||
| 670 | /// | ||
| 671 | /// [Reference](https://doc.rust-lang.org/reference/items/type-aliases.html) | ||
| 672 | struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { | ||
| 673 | T![default], | ||
| 674 | T![type], | ||
| 675 | T![=], | ||
| 676 | TypeRef, | ||
| 677 | T![;] | ||
| 678 | } | ||
| 679 | |||
| 680 | /// Inherent and trait impl definition. | ||
| 681 | /// Includes all of its inner and outer attributes. | ||
| 682 | /// | ||
| 683 | /// ``` | ||
| 684 | /// ❰ | ||
| 685 | /// #[attr] | ||
| 686 | /// unsafe impl<T> const !Foo for Bar where T: Debug { | ||
| 687 | /// #![inner_attr] | ||
| 688 | /// // ... | ||
| 689 | /// } | ||
| 690 | /// ❱ | ||
| 691 | /// ``` | ||
| 692 | /// | ||
| 693 | /// [Reference](https://doc.rust-lang.org/reference/items/implementations.html) | ||
| 694 | struct ImplDef: TypeParamsOwner, AttrsOwner, DocCommentsOwner { | ||
| 695 | T![default], | ||
| 696 | T![const], | ||
| 697 | T![unsafe], | ||
| 698 | T![impl], | ||
| 699 | T![!], | ||
| 700 | T![for], | ||
| 701 | ItemList, | ||
| 702 | } | ||
| 703 | |||
| 704 | |||
| 705 | /// Parenthesized type reference. | ||
| 706 | /// Note: parens are only used for grouping, this is not a tuple type. | ||
| 707 | /// | ||
| 708 | /// ``` | ||
| 709 | /// // This is effectively just `u32`. | ||
| 710 | /// // Single-item tuple must be defined with a trailing comma: `(u32,)` | ||
| 711 | /// type Foo = ❰ (u32) ❱; | ||
| 712 | /// | ||
| 713 | /// let bar: &'static ❰ (dyn Debug) ❱ = "bruh"; | ||
| 714 | /// ``` | ||
| 715 | struct ParenType { T!['('], TypeRef, T![')'] } | ||
| 716 | |||
| 717 | /// Unnamed tuple type. | ||
| 718 | /// | ||
| 719 | /// ``` | ||
| 720 | /// let foo: ❰ (u32, bool) ❱ = (42, true); | ||
| 721 | /// ``` | ||
| 722 | /// | ||
| 723 | /// [Reference](https://doc.rust-lang.org/reference/types/tuple.html) | ||
| 724 | struct TupleType { T!['('], fields: [TypeRef], T![')'] } | ||
| 725 | |||
| 726 | /// The never type (i.e. the exclamation point). | ||
| 727 | /// | ||
| 728 | /// ``` | ||
| 729 | /// type T = ❰ ! ❱; | ||
| 730 | /// | ||
| 731 | /// fn no_return() -> ❰ ! ❱ { | ||
| 732 | /// loop {} | ||
| 733 | /// } | ||
| 734 | /// ``` | ||
| 735 | /// | ||
| 736 | /// [Reference](https://doc.rust-lang.org/reference/types/never.html) | ||
| 737 | struct NeverType { T![!] } | ||
| 738 | |||
| 739 | /// Path to a type. | ||
| 740 | /// Includes single identifier type names and elaborate paths with | ||
| 741 | /// generic parameters. | ||
| 742 | /// | ||
| 743 | /// ``` | ||
| 744 | /// type Foo = ❰ String ❱; | ||
| 745 | /// type Bar = ❰ std::vec::Vec<T> ❱; | ||
| 746 | /// type Baz = ❰ ::bruh::<Bruuh as Iterator>::Item ❱; | ||
| 747 | /// ``` | ||
| 748 | /// | ||
| 749 | /// [Reference](https://doc.rust-lang.org/reference/paths.html) | ||
| 750 | struct PathType { Path } | ||
| 751 | |||
| 752 | /// Raw pointer type. | ||
| 753 | /// | ||
| 754 | /// ``` | ||
| 755 | /// type Foo = ❰ *const u32 ❱; | ||
| 756 | /// type Bar = ❰ *mut u32 ❱; | ||
| 757 | /// ``` | ||
| 758 | /// | ||
| 759 | /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html#raw-pointers-const-and-mut) | ||
| 760 | struct PointerType { T![*], T![const], T![mut], TypeRef } | ||
| 761 | |||
| 762 | /// Array type. | ||
| 763 | /// | ||
| 764 | /// ``` | ||
| 765 | /// type Foo = ❰ [u32; 24 - 3] ❱; | ||
| 766 | /// ``` | ||
| 767 | /// | ||
| 768 | /// [Reference](https://doc.rust-lang.org/reference/types/array.html) | ||
| 769 | struct ArrayType { T!['['], TypeRef, T![;], Expr, T![']'] } | ||
| 770 | |||
| 771 | /// Slice type. | ||
| 772 | /// | ||
| 773 | /// ``` | ||
| 774 | /// type Foo = ❰ [u8] ❱; | ||
| 775 | /// ``` | ||
| 776 | /// | ||
| 777 | /// [Reference](https://doc.rust-lang.org/reference/types/slice.html) | ||
| 778 | struct SliceType { T!['['], TypeRef, T![']'] } | ||
| 779 | |||
| 780 | /// Reference type. | ||
| 781 | /// | ||
| 782 | /// ``` | ||
| 783 | /// type Foo = ❰ &'static str ❱; | ||
| 784 | /// ``` | ||
| 785 | /// | ||
| 786 | /// [Reference](https://doc.rust-lang.org/reference/types/pointer.html) | ||
| 787 | struct ReferenceType { T![&], T![lifetime], T![mut], TypeRef } | ||
| 788 | |||
| 789 | /// Placeholder type (i.e. the underscore). | ||
| 790 | /// | ||
| 791 | /// ``` | ||
| 792 | /// let foo: ❰ _ ❱ = 42_u32; | ||
| 793 | /// ``` | ||
| 794 | /// | ||
| 795 | /// [Reference](https://doc.rust-lang.org/reference/types/inferred.html) | ||
| 796 | struct PlaceholderType { T![_] } | ||
| 797 | |||
| 798 | /// Function pointer type (not to be confused with `Fn*` family of traits). | ||
| 799 | /// | ||
| 800 | /// ``` | ||
| 801 | /// type Foo = ❰ async fn(#[attr] u32, named: bool) -> u32 ❱; | ||
| 802 | /// | ||
| 803 | /// type Bar = ❰ extern "C" fn(variadic: u32, #[attr] ...) ❱; | ||
| 804 | /// ``` | ||
| 805 | /// | ||
| 806 | /// [Reference](https://doc.rust-lang.org/reference/types/function-pointer.html) | ||
| 807 | struct FnPointerType { Abi, T![unsafe], T![fn], ParamList, RetType } | ||
| 808 | |||
| 809 | /// Higher order type. | ||
| 810 | /// | ||
| 811 | /// ``` | ||
| 812 | /// type Foo = ❰ for<'a> fn(&'a str) ❱; | ||
| 813 | /// ``` | ||
| 814 | /// | ||
| 815 | /// [Reference](https://doc.rust-lang.org/nomicon/hrtb.html) | ||
| 816 | struct ForType { T![for], TypeParamList, TypeRef } | ||
| 817 | |||
| 818 | /// Opaque `impl Trait` type. | ||
| 819 | /// | ||
| 820 | /// ``` | ||
| 821 | /// fn foo(bar: ❰ impl Debug + Eq ❱) {} | ||
| 822 | /// ``` | ||
| 823 | /// | ||
| 824 | /// [Reference](https://doc.rust-lang.org/reference/types/impl-trait.html) | ||
| 825 | struct ImplTraitType: TypeBoundsOwner { T![impl] } | ||
| 826 | |||
| 827 | /// Trait object type. | ||
| 828 | /// | ||
| 829 | /// ``` | ||
| 830 | /// type Foo = ❰ dyn Debug ❱; | ||
| 831 | /// ``` | ||
| 832 | /// | ||
| 833 | /// [Reference](https://doc.rust-lang.org/reference/types/trait-object.html) | ||
| 834 | struct DynTraitType: TypeBoundsOwner { T![dyn] } | ||
| 835 | |||
| 836 | /// Tuple literal. | ||
| 837 | /// | ||
| 838 | /// ``` | ||
| 839 | /// ❰ (42, true) ❱; | ||
| 840 | /// ``` | ||
| 841 | /// | ||
| 842 | /// [Reference](https://doc.rust-lang.org/reference/expressions/tuple-expr.html) | ||
| 843 | struct TupleExpr: AttrsOwner { T!['('], exprs: [Expr], T![')'] } | ||
| 844 | |||
| 845 | /// Array literal. | ||
| 846 | /// | ||
| 847 | /// ``` | ||
| 848 | /// ❰ [#![inner_attr] true, false, true] ❱; | ||
| 849 | /// | ||
| 850 | /// ❰ ["baz"; 24] ❱; | ||
| 851 | /// ``` | ||
| 852 | /// | ||
| 853 | /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html) | ||
| 854 | struct ArrayExpr: AttrsOwner { T!['['], exprs: [Expr], T![;], T![']'] } | ||
| 855 | |||
| 856 | /// Parenthesized expression. | ||
| 857 | /// Note: parens are only used for grouping, this is not a tuple literal. | ||
| 858 | /// | ||
| 859 | /// ``` | ||
| 860 | /// ❰ (#![inner_attr] 2 + 2) ❱ * 2; | ||
| 861 | /// ``` | ||
| 862 | /// | ||
| 863 | /// [Reference](https://doc.rust-lang.org/reference/expressions/grouped-expr.html) | ||
| 864 | struct ParenExpr: AttrsOwner { T!['('], Expr, T![')'] } | ||
| 865 | |||
| 866 | /// Path to a symbol in expression context. | ||
| 867 | /// Includes single identifier variable names and elaborate paths with | ||
| 868 | /// generic parameters. | ||
| 869 | /// | ||
| 870 | /// ``` | ||
| 871 | /// ❰ Some::<i32> ❱; | ||
| 872 | /// ❰ foo ❱ + 42; | ||
| 873 | /// ❰ Vec::<i32>::push ❱; | ||
| 874 | /// ❰ <[i32]>::reverse ❱; | ||
| 875 | /// ❰ <String as std::borrow::Borrow<str>>::borrow ❱; | ||
| 876 | /// ``` | ||
| 877 | /// | ||
| 878 | /// [Reference](https://doc.rust-lang.org/reference/expressions/path-expr.html) | ||
| 879 | struct PathExpr { Path } | ||
| 880 | |||
| 881 | /// Anonymous callable object literal a.k.a. closure, lambda or functor. | ||
| 882 | /// | ||
| 883 | /// ``` | ||
| 884 | /// ❰ || 42 ❱; | ||
| 885 | /// ❰ |a: u32| val + 1 ❱; | ||
| 886 | /// ❰ async |#[attr] Pattern(_): Pattern| { bar } ❱; | ||
| 887 | /// ❰ move || baz ❱; | ||
| 888 | /// ❰ || -> u32 { closure_with_ret_type_annotation_requires_block_expr } ❱ | ||
| 889 | /// ``` | ||
| 890 | /// | ||
| 891 | /// [Reference](https://doc.rust-lang.org/reference/expressions/closure-expr.html) | ||
| 892 | struct LambdaExpr: AttrsOwner { | ||
| 893 | T![static], // Note(@matklad): I belive this is (used to be?) syntax for generators | ||
| 894 | T![async], | ||
| 895 | T![move], | ||
| 896 | ParamList, | ||
| 897 | RetType, | ||
| 898 | body: Expr, | ||
| 899 | } | ||
| 900 | |||
| 901 | /// If expression. Includes both regular `if` and `if let` forms. | ||
| 902 | /// Beware that `else if` is a special case syntax sugar, because in general | ||
| 903 | /// there has to be block expression after `else`. | ||
| 904 | /// | ||
| 905 | /// ``` | ||
| 906 | /// ❰ if bool_cond { 42 } ❱ | ||
| 907 | /// ❰ if bool_cond { 42 } else { 24 } ❱ | ||
| 908 | /// ❰ if bool_cond { 42 } else if bool_cond2 { 42 } ❱ | ||
| 909 | /// | ||
| 910 | /// ❰ | ||
| 911 | /// if let Pattern(foo) = bar { | ||
| 912 | /// foo | ||
| 913 | /// } else { | ||
| 914 | /// panic!(); | ||
| 915 | /// } | ||
| 916 | /// ❱ | ||
| 917 | /// ``` | ||
| 918 | /// | ||
| 919 | /// [Reference](https://doc.rust-lang.org/reference/expressions/if-expr.html) | ||
| 920 | struct IfExpr: AttrsOwner { T![if], Condition } | ||
| 921 | |||
| 922 | /// Unconditional loop expression. | ||
| 923 | /// | ||
| 924 | /// ``` | ||
| 925 | /// ❰ | ||
| 926 | /// loop { | ||
| 927 | /// // yeah, it's that simple... | ||
| 928 | /// } | ||
| 929 | /// ❱ | ||
| 930 | /// ``` | ||
| 931 | /// | ||
| 932 | /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html) | ||
| 933 | struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } | ||
| 934 | |||
| 935 | /// Block expression with an optional prefix (label, try ketword, | ||
| 936 | /// unsafe keyword, async keyword...). | ||
| 937 | /// | ||
| 938 | /// ``` | ||
| 939 | /// ❰ | ||
| 940 | /// 'label: try { | ||
| 941 | /// None? | ||
| 942 | /// } | ||
| 943 | /// ❱ | ||
| 944 | /// ``` | ||
| 945 | /// | ||
| 946 | /// - [try block](https://doc.rust-lang.org/unstable-book/language-features/try-blocks.html) | ||
| 947 | /// - [unsafe block](https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks) | ||
| 948 | /// - [async block](https://doc.rust-lang.org/reference/expressions/block-expr.html#async-blocks) | ||
| 949 | struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr } | ||
| 950 | |||
| 951 | |||
| 952 | /// For loop expression. | ||
| 953 | /// Note: record struct literals are not valid as iterable expression | ||
| 954 | /// due to ambiguity. | ||
| 955 | /// | ||
| 956 | /// ``` | ||
| 957 | /// ❰ | ||
| 958 | /// for i in (0..4) { | ||
| 959 | /// dbg!(i); | ||
| 960 | /// } | ||
| 961 | /// ❱ | ||
| 962 | /// ``` | ||
| 963 | /// | ||
| 964 | /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops) | ||
| 965 | struct ForExpr: AttrsOwner, LoopBodyOwner { | ||
| 966 | T![for], | ||
| 967 | Pat, | ||
| 968 | T![in], | ||
| 969 | iterable: Expr, | ||
| 970 | } | ||
| 971 | |||
| 972 | /// While loop expression. Includes both regular `while` and `while let` forms. | ||
| 973 | /// | ||
| 974 | /// ``` | ||
| 975 | /// ❰ | ||
| 976 | /// while bool_cond { | ||
| 977 | /// 42; | ||
| 978 | /// } | ||
| 979 | /// ❱ | ||
| 980 | /// ❰ | ||
| 981 | /// while let Pattern(foo) = bar { | ||
| 982 | /// bar += 1; | ||
| 983 | /// } | ||
| 984 | /// ❱ | ||
| 985 | /// ``` | ||
| 986 | /// | ||
| 987 | /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops) | ||
| 988 | struct WhileExpr: AttrsOwner, LoopBodyOwner { T![while], Condition } | ||
| 989 | |||
| 990 | /// Continue expression. | ||
| 991 | /// | ||
| 992 | /// ``` | ||
| 993 | /// while bool_cond { | ||
| 994 | /// ❰ continue ❱; | ||
| 995 | /// } | ||
| 996 | /// | ||
| 997 | /// 'outer: loop { | ||
| 998 | /// loop { | ||
| 999 | /// ❰ continue 'outer ❱; | ||
| 1000 | /// } | ||
| 1001 | /// } | ||
| 1002 | /// | ||
| 1003 | /// ``` | ||
| 1004 | /// | ||
| 1005 | /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#continue-expressions) | ||
| 1006 | struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } | ||
| 1007 | |||
| 1008 | /// Break expression. | ||
| 1009 | /// | ||
| 1010 | /// ``` | ||
| 1011 | /// while bool_cond { | ||
| 1012 | /// ❰ break ❱; | ||
| 1013 | /// } | ||
| 1014 | /// 'outer: loop { | ||
| 1015 | /// for foo in bar { | ||
| 1016 | /// ❰ break 'outer ❱; | ||
| 1017 | /// } | ||
| 1018 | /// } | ||
| 1019 | /// 'outer: loop { | ||
| 1020 | /// loop { | ||
| 1021 | /// ❰ break 'outer 42 ❱; | ||
| 1022 | /// } | ||
| 1023 | /// } | ||
| 1024 | /// ``` | ||
| 1025 | /// | ||
| 1026 | /// [Refernce](https://doc.rust-lang.org/reference/expressions/loop-expr.html#break-expressions) | ||
| 1027 | struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } | ||
| 1028 | |||
| 1029 | /// Label. | ||
| 1030 | /// | ||
| 1031 | /// ``` | ||
| 1032 | /// ❰ 'outer: ❱ loop {} | ||
| 1033 | /// | ||
| 1034 | /// let foo = ❰ 'bar: ❱ loop {} | ||
| 1035 | /// | ||
| 1036 | /// ❰ 'baz: ❱ { | ||
| 1037 | /// break 'baz; | ||
| 1038 | /// } | ||
| 1039 | /// ``` | ||
| 1040 | /// | ||
| 1041 | /// [Reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html?highlight=label#loop-labels) | ||
| 1042 | /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) | ||
| 1043 | struct Label { T![lifetime] } | ||
| 1044 | |||
| 1045 | /// Block expression. Includes unsafe blocks and block labels. | ||
| 1046 | /// | ||
| 1047 | /// ``` | ||
| 1048 | /// let foo = ❰ | ||
| 1049 | /// { | ||
| 1050 | /// #![inner_attr] | ||
| 1051 | /// ❰ { } ❱ | ||
| 1052 | /// | ||
| 1053 | /// ❰ 'label: { break 'label } ❱ | ||
| 1054 | /// } | ||
| 1055 | /// ❱; | ||
| 1056 | /// ``` | ||
| 1057 | /// | ||
| 1058 | /// [Reference](https://doc.rust-lang.org/reference/expressions/block-expr.html) | ||
| 1059 | /// [Labels for blocks RFC](https://github.com/rust-lang/rfcs/blob/master/text/2046-label-break-value.md) | ||
| 1060 | struct BlockExpr: AttrsOwner, ModuleItemOwner { | ||
| 1061 | Label, T!['{'], statements: [Stmt], Expr, T!['}'], | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | /// Return expression. | ||
| 1065 | /// | ||
| 1066 | /// ``` | ||
| 1067 | /// || ❰ return 42 ❱; | ||
| 1068 | /// | ||
| 1069 | /// fn bar() { | ||
| 1070 | /// ❰ return ❱; | ||
| 1071 | /// } | ||
| 1072 | /// ``` | ||
| 1073 | /// | ||
| 1074 | /// [Reference](https://doc.rust-lang.org/reference/expressions/return-expr.html) | ||
| 1075 | struct ReturnExpr: AttrsOwner { Expr } | ||
| 1076 | |||
| 1077 | /// Call expression (not to be confused with method call expression, it is | ||
| 1078 | /// a separate ast node). | ||
| 1079 | /// | ||
| 1080 | /// ``` | ||
| 1081 | /// ❰ foo() ❱; | ||
| 1082 | /// ❰ &str::len("bar") ❱; | ||
| 1083 | /// ❰ <&str as PartialEq<&str>>::eq(&"", &"") ❱; | ||
| 1084 | /// ``` | ||
| 1085 | /// | ||
| 1086 | /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html) | ||
| 1087 | struct CallExpr: ArgListOwner { Expr } | ||
| 1088 | |||
| 1089 | /// Method call expression. | ||
| 1090 | /// | ||
| 1091 | /// ``` | ||
| 1092 | /// ❰ receiver_expr.method() ❱; | ||
| 1093 | /// ❰ receiver_expr.method::<T>(42, true) ❱; | ||
| 1094 | /// | ||
| 1095 | /// ❰ ❰ ❰ foo.bar() ❱ .baz() ❱ .bruh() ❱; | ||
| 1096 | /// ``` | ||
| 1097 | /// | ||
| 1098 | /// [Reference](https://doc.rust-lang.org/reference/expressions/method-call-expr.html) | ||
| 1099 | struct MethodCallExpr: AttrsOwner, ArgListOwner { | ||
| 1100 | Expr, T![.], NameRef, TypeArgList, | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | /// Index expression a.k.a. subscript operator call. | ||
| 1104 | /// | ||
| 1105 | /// ``` | ||
| 1106 | /// ❰ foo[42] ❱; | ||
| 1107 | /// ``` | ||
| 1108 | /// | ||
| 1109 | /// [Reference](https://doc.rust-lang.org/reference/expressions/array-expr.html) | ||
| 1110 | struct IndexExpr: AttrsOwner { T!['['], T![']'] } | ||
| 1111 | |||
| 1112 | /// Field access expression. | ||
| 1113 | /// | ||
| 1114 | /// ``` | ||
| 1115 | /// ❰ expr.bar ❱; | ||
| 1116 | /// | ||
| 1117 | /// ❰ ❰ ❰ foo.bar ❱ .baz ❱ .bruh ❱; | ||
| 1118 | /// ``` | ||
| 1119 | /// | ||
| 1120 | /// [Reference](https://doc.rust-lang.org/reference/expressions/field-expr.html) | ||
| 1121 | struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } | ||
| 1122 | |||
| 1123 | /// Await operator call expression. | ||
| 1124 | /// | ||
| 1125 | /// ``` | ||
| 1126 | /// ❰ expr.await ❱; | ||
| 1127 | /// ``` | ||
| 1128 | /// | ||
| 1129 | /// [Reference](https://doc.rust-lang.org/reference/expressions/await-expr.html) | ||
| 1130 | struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } | ||
| 1131 | |||
| 1132 | /// The question mark operator call. | ||
| 1133 | /// | ||
| 1134 | /// ``` | ||
| 1135 | /// ❰ expr? ❱; | ||
| 1136 | /// ``` | ||
| 1137 | /// | ||
| 1138 | /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator) | ||
| 1139 | struct TryExpr: AttrsOwner { Expr, T![?] } | ||
| 1140 | |||
| 1141 | /// Type cast expression. | ||
| 1142 | /// | ||
| 1143 | /// ``` | ||
| 1144 | /// ❰ expr as T ❱; | ||
| 1145 | /// ``` | ||
| 1146 | /// | ||
| 1147 | /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions) | ||
| 1148 | struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } | ||
| 1149 | |||
| 1150 | |||
| 1151 | /// Borrow operator call. | ||
| 1152 | /// | ||
| 1153 | /// ``` | ||
| 1154 | /// ❰ &foo ❱; | ||
| 1155 | /// ❰ &mut bar ❱; | ||
| 1156 | /// ❰ &raw const bar ❱; | ||
| 1157 | /// ❰ &raw mut bar ❱; | ||
| 1158 | /// ``` | ||
| 1159 | /// | ||
| 1160 | /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators) | ||
| 1161 | struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], T![const], Expr } | ||
| 1162 | |||
| 1163 | /// Prefix operator call. This is either `!` or `*` or `-`. | ||
| 1164 | /// | ||
| 1165 | /// ``` | ||
| 1166 | /// ❰ !foo ❱; | ||
| 1167 | /// ❰ *bar ❱; | ||
| 1168 | /// ❰ -42 ❱; | ||
| 1169 | /// ``` | ||
| 1170 | /// | ||
| 1171 | /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html) | ||
| 1172 | struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } | ||
| 1173 | |||
| 1174 | /// Box operator call. | ||
| 1175 | /// | ||
| 1176 | /// ``` | ||
| 1177 | /// ❰ box 42 ❱; | ||
| 1178 | /// ``` | ||
| 1179 | /// | ||
| 1180 | /// [RFC](https://github.com/rust-lang/rfcs/blob/0806be4f282144cfcd55b1d20284b43f87cbe1c6/text/0809-box-and-in-for-stdlib.md) | ||
| 1181 | struct BoxExpr: AttrsOwner { T![box], Expr } | ||
| 1182 | |||
| 1183 | /// Range operator call. | ||
| 1184 | /// | ||
| 1185 | /// ``` | ||
| 1186 | /// ❰ 0..42 ❱; | ||
| 1187 | /// ❰ ..42 ❱; | ||
| 1188 | /// ❰ 0.. ❱; | ||
| 1189 | /// ❰ .. ❱; | ||
| 1190 | /// ❰ 0..=42 ❱; | ||
| 1191 | /// ❰ ..=42 ❱; | ||
| 1192 | /// ``` | ||
| 1193 | /// | ||
| 1194 | /// [Reference](https://doc.rust-lang.org/reference/expressions/range-expr.html) | ||
| 1195 | struct RangeExpr: AttrsOwner { /*RangeOp*/ } | ||
| 1196 | |||
| 1197 | |||
| 1198 | /// Binary operator call. | ||
| 1199 | /// Includes all arithmetic, logic, bitwise and assignment operators. | ||
| 1200 | /// | ||
| 1201 | /// ``` | ||
| 1202 | /// ❰ 2 + ❰ 2 * 2 ❱ ❱; | ||
| 1203 | /// ❰ ❰ true && false ❱ || true ❱; | ||
| 1204 | /// ``` | ||
| 1205 | /// | ||
| 1206 | /// [Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators) | ||
| 1207 | struct BinExpr: AttrsOwner { /*BinOp*/ } | ||
| 1208 | |||
| 1209 | |||
| 1210 | /// [Raw] string, [raw] byte string, char, byte, integer, float or bool literal. | ||
| 1211 | /// | ||
| 1212 | /// ``` | ||
| 1213 | /// ❰ "str" ❱; | ||
| 1214 | /// ❰ br##"raw byte str"## ❱; | ||
| 1215 | /// ❰ 'c' ❱; | ||
| 1216 | /// ❰ b'c' ❱; | ||
| 1217 | /// ❰ 42 ❱; | ||
| 1218 | /// ❰ 1e9 ❱; | ||
| 1219 | /// ❰ true ❱; | ||
| 1220 | /// ``` | ||
| 1221 | /// | ||
| 1222 | /// [Reference](https://doc.rust-lang.org/reference/expressions/literal-expr.html) | ||
| 1223 | struct Literal { /*LiteralToken*/ } | ||
| 1224 | |||
| 1225 | /// Match expression. | ||
| 1226 | /// | ||
| 1227 | /// ``` | ||
| 1228 | /// ❰ | ||
| 1229 | /// match expr { | ||
| 1230 | /// Pat1 => {} | ||
| 1231 | /// Pat2(_) => 42, | ||
| 1232 | /// } | ||
| 1233 | /// ❱ | ||
| 1234 | /// ``` | ||
| 1235 | /// | ||
| 1236 | /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) | ||
| 1237 | struct MatchExpr: AttrsOwner { T![match], Expr, MatchArmList } | ||
| 1238 | |||
| 1239 | /// Match arm list part of match expression. Includes its inner attributes. | ||
| 1240 | /// | ||
| 1241 | /// ``` | ||
| 1242 | /// match expr | ||
| 1243 | /// ❰ | ||
| 1244 | /// { | ||
| 1245 | /// #![inner_attr] | ||
| 1246 | /// Pat1 => {} | ||
| 1247 | /// Pat2(_) => 42, | ||
| 1248 | /// } | ||
| 1249 | /// ❱ | ||
| 1250 | /// ``` | ||
| 1251 | /// | ||
| 1252 | /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) | ||
| 1253 | struct MatchArmList: AttrsOwner { T!['{'], arms: [MatchArm], T!['}'] } | ||
| 1254 | |||
| 1255 | |||
| 1256 | /// Match arm. | ||
| 1257 | /// Note: record struct literals are not valid as target match expression | ||
| 1258 | /// due to ambiguity. | ||
| 1259 | /// ``` | ||
| 1260 | /// match expr { | ||
| 1261 | /// ❰ #[attr] Pattern(it) if bool_cond => it ❱, | ||
| 1262 | /// } | ||
| 1263 | /// ``` | ||
| 1264 | /// | ||
| 1265 | /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html) | ||
| 1266 | struct MatchArm: AttrsOwner { | ||
| 1267 | pat: Pat, | ||
| 1268 | guard: MatchGuard, | ||
| 1269 | T![=>], | ||
| 1270 | Expr, | ||
| 1271 | } | ||
| 1272 | |||
| 1273 | /// Match guard. | ||
| 1274 | /// | ||
| 1275 | /// ``` | ||
| 1276 | /// match expr { | ||
| 1277 | /// Pattern(it) ❰ if bool_cond ❱ => it, | ||
| 1278 | /// } | ||
| 1279 | /// ``` | ||
| 1280 | /// | ||
| 1281 | /// [Reference](https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards) | ||
| 1282 | struct MatchGuard { T![if], Expr } | ||
| 1283 | |||
| 1284 | /// Record literal expression. The same syntax is used for structs, | ||
| 1285 | /// unions and record enum variants. | ||
| 1286 | /// | ||
| 1287 | /// ``` | ||
| 1288 | /// ❰ | ||
| 1289 | /// foo::Bar { | ||
| 1290 | /// #![inner_attr] | ||
| 1291 | /// baz: 42, | ||
| 1292 | /// bruh: true, | ||
| 1293 | /// ..spread | ||
| 1294 | /// } | ||
| 1295 | /// ❱ | ||
| 1296 | /// ``` | ||
| 1297 | /// | ||
| 1298 | /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) | ||
| 1299 | struct RecordLit { Path, RecordFieldList} | ||
| 1300 | |||
| 1301 | /// Record field list including enclosing curly braces. | ||
| 1302 | /// | ||
| 1303 | /// foo::Bar ❰ | ||
| 1304 | /// { | ||
| 1305 | /// baz: 42, | ||
| 1306 | /// ..spread | ||
| 1307 | /// } | ||
| 1308 | /// ❱ | ||
| 1309 | /// | ||
| 1310 | /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) | ||
| 1311 | struct RecordFieldList { | ||
| 1312 | T!['{'], | ||
| 1313 | fields: [RecordField], | ||
| 1314 | T![..], | ||
| 1315 | spread: Expr, | ||
| 1316 | T!['}'] | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /// Record field. | ||
| 1320 | /// | ||
| 1321 | /// ``` | ||
| 1322 | /// foo::Bar { | ||
| 1323 | /// ❰ #[attr] baz: 42 ❱ | ||
| 1324 | /// } | ||
| 1325 | /// ``` | ||
| 1326 | /// | ||
| 1327 | /// [Reference](https://doc.rust-lang.org/reference/expressions/struct-expr.html) | ||
| 1328 | struct RecordField: AttrsOwner { NameRef, T![:], Expr } | ||
| 1329 | |||
| 1330 | /// Disjunction of patterns. | ||
| 1331 | /// | ||
| 1332 | /// ``` | ||
| 1333 | /// let ❰ Foo(it) | Bar(it) | Baz(it) ❱ = bruh; | ||
| 1334 | /// ``` | ||
| 1335 | /// | ||
| 1336 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html) | ||
| 1337 | struct OrPat { pats: [Pat] } | ||
| 1338 | |||
| 1339 | /// Parenthesized pattern. | ||
| 1340 | /// Note: parens are only used for grouping, this is not a tuple pattern. | ||
| 1341 | /// | ||
| 1342 | /// ``` | ||
| 1343 | /// if let ❰ &(0..=42) ❱ = foo {} | ||
| 1344 | /// ``` | ||
| 1345 | /// | ||
| 1346 | /// https://doc.rust-lang.org/reference/patterns.html#grouped-patterns | ||
| 1347 | struct ParenPat { T!['('], Pat, T![')'] } | ||
| 1348 | |||
| 1349 | /// Reference pattern. | ||
| 1350 | /// Note: this has nothing to do with `ref` keyword, the latter is used in bind patterns. | ||
| 1351 | /// | ||
| 1352 | /// ``` | ||
| 1353 | /// let ❰ &mut foo ❱ = bar; | ||
| 1354 | /// | ||
| 1355 | /// let ❰ & ❰ &mut ❰ &_ ❱ ❱ ❱ = baz; | ||
| 1356 | /// ``` | ||
| 1357 | /// | ||
| 1358 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#reference-patterns) | ||
| 1359 | struct RefPat { T![&], T![mut], Pat } | ||
| 1360 | |||
| 1361 | /// Box pattern. | ||
| 1362 | /// | ||
| 1363 | /// ``` | ||
| 1364 | /// let ❰ box foo ❱ = box 42; | ||
| 1365 | /// ``` | ||
| 1366 | /// | ||
| 1367 | /// [Unstable book](https://doc.rust-lang.org/unstable-book/language-features/box-patterns.html) | ||
| 1368 | struct BoxPat { T![box], Pat } | ||
| 1369 | |||
| 1370 | /// Bind pattern. | ||
| 1371 | /// | ||
| 1372 | /// ``` | ||
| 1373 | /// match foo { | ||
| 1374 | /// Some(❰ ref mut bar ❱) => {} | ||
| 1375 | /// ❰ baz @ None ❱ => {} | ||
| 1376 | /// } | ||
| 1377 | /// ``` | ||
| 1378 | /// | ||
| 1379 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#identifier-patterns) | ||
| 1380 | struct BindPat: AttrsOwner, NameOwner { T![ref], T![mut], T![@], Pat } | ||
| 1381 | |||
| 1382 | /// Placeholder pattern a.k.a. the wildcard pattern or the underscore. | ||
| 1383 | /// | ||
| 1384 | /// ``` | ||
| 1385 | /// let ❰ _ ❱ = foo; | ||
| 1386 | /// ``` | ||
| 1387 | /// | ||
| 1388 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#wildcard-pattern) | ||
| 1389 | struct PlaceholderPat { T![_] } | ||
| 1390 | |||
| 1391 | /// Rest-of-the record/tuple pattern. | ||
| 1392 | /// Note: this is not the unbonded range pattern (even more: it doesn't exist). | ||
| 1393 | /// | ||
| 1394 | /// ``` | ||
| 1395 | /// let Foo { bar, ❰ .. ❱ } = baz; | ||
| 1396 | /// let (❰ .. ❱, bruh) = (42, 24, 42); | ||
| 1397 | /// let Bruuh(❰ .. ❱) = bruuuh; | ||
| 1398 | /// ``` | ||
| 1399 | /// | ||
| 1400 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) | ||
| 1401 | struct DotDotPat { T![..] } | ||
| 1402 | |||
| 1403 | /// Path pattern. | ||
| 1404 | /// Doesn't include the underscore pattern (it is a special case, namely `PlaceholderPat`). | ||
| 1405 | /// | ||
| 1406 | /// ``` | ||
| 1407 | /// let ❰ foo::bar::Baz ❱ { .. } = bruh; | ||
| 1408 | /// if let ❰ CONST ❱ = 42 {} | ||
| 1409 | /// ``` | ||
| 1410 | /// | ||
| 1411 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#path-patterns) | ||
| 1412 | struct PathPat { Path } | ||
| 1413 | |||
| 1414 | /// Slice pattern. | ||
| 1415 | /// | ||
| 1416 | /// ``` | ||
| 1417 | /// let ❰ [foo, bar, baz] ❱ = [1, 2, 3]; | ||
| 1418 | /// ``` | ||
| 1419 | /// | ||
| 1420 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#slice-patterns) | ||
| 1421 | struct SlicePat { T!['['], args: [Pat], T![']'] } | ||
| 1422 | |||
| 1423 | /// Range pattern. | ||
| 1424 | /// | ||
| 1425 | /// ``` | ||
| 1426 | /// match foo { | ||
| 1427 | /// ❰ 0..42 ❱ => {} | ||
| 1428 | /// ❰ 0..=42 ❱ => {} | ||
| 1429 | /// } | ||
| 1430 | /// ``` | ||
| 1431 | /// | ||
| 1432 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#range-patterns) | ||
| 1433 | struct RangePat { } // FIXME(@matklad): here should be T![..], T![..=] I think, if we don't already have an accessor in expresions_ext | ||
| 1434 | |||
| 1435 | /// Literal pattern. | ||
| 1436 | /// Includes only bool, number, char, and string literals. | ||
| 1437 | /// | ||
| 1438 | /// ``` | ||
| 1439 | /// match foo { | ||
| 1440 | /// Number(❰ 42 ❱) => {} | ||
| 1441 | /// String(❰ "42" ❱) => {} | ||
| 1442 | /// Bool(❰ true ❱) => {} | ||
| 1443 | /// } | ||
| 1444 | /// ``` | ||
| 1445 | /// | ||
| 1446 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#literal-patterns) | ||
| 1447 | struct LiteralPat { Literal } | ||
| 1448 | |||
| 1449 | /// Macro invocation in pattern position. | ||
| 1450 | /// | ||
| 1451 | /// ``` | ||
| 1452 | /// let ❰ foo!(my custom syntax) ❱ = baz; | ||
| 1453 | /// | ||
| 1454 | /// ``` | ||
| 1455 | /// [Reference](https://doc.rust-lang.org/reference/macros.html#macro-invocation) | ||
| 1456 | struct MacroPat { MacroCall } | ||
| 1457 | |||
| 1458 | /// Record literal pattern. | ||
| 1459 | /// | ||
| 1460 | /// ``` | ||
| 1461 | /// let ❰ foo::Bar { baz, .. } ❱ = bruh; | ||
| 1462 | /// ``` | ||
| 1463 | /// | ||
| 1464 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) | ||
| 1465 | struct RecordPat { RecordFieldPatList, Path } | ||
| 1466 | |||
| 1467 | /// Record literal's field patterns list including enclosing curly braces. | ||
| 1468 | /// | ||
| 1469 | /// ``` | ||
| 1470 | /// let foo::Bar ❰ { baz, bind @ bruh, .. } ❱ = bruuh; | ||
| 1471 | /// `` | ||
| 1472 | /// | ||
| 1473 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) | ||
| 1474 | struct RecordFieldPatList { | ||
| 1475 | T!['{'], | ||
| 1476 | pats: [RecordInnerPat], | ||
| 1477 | record_field_pats: [RecordFieldPat], | ||
| 1478 | bind_pats: [BindPat], | ||
| 1479 | T![..], | ||
| 1480 | T!['}'] | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | /// Record literal's field pattern. | ||
| 1484 | /// Note: record literal can also match tuple structs. | ||
| 1485 | /// | ||
| 1486 | /// ``` | ||
| 1487 | /// let Foo { ❰ bar: _ ❱ } = baz; | ||
| 1488 | /// let TupleStruct { ❰ 0: _ ❱ } = bruh; | ||
| 1489 | /// ``` | ||
| 1490 | /// | ||
| 1491 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#struct-patterns) | ||
| 1492 | struct RecordFieldPat: AttrsOwner { NameRef, T![:], Pat } | ||
| 1493 | |||
| 1494 | /// Tuple struct literal pattern. | ||
| 1495 | /// | ||
| 1496 | /// ``` | ||
| 1497 | /// let ❰ foo::Bar(baz, bruh) ❱ = bruuh; | ||
| 1498 | /// ``` | ||
| 1499 | /// | ||
| 1500 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-struct-patterns) | ||
| 1501 | struct TupleStructPat { Path, T!['('], args: [Pat], T![')'] } | ||
| 1502 | |||
| 1503 | /// Tuple pattern. | ||
| 1504 | /// Note: this doesn't include tuple structs (see `TupleStructPat`) | ||
| 1505 | /// | ||
| 1506 | /// ``` | ||
| 1507 | /// let ❰ (foo, bar, .., baz) ❱ = bruh; | ||
| 1508 | /// ``` | ||
| 1509 | /// | ||
| 1510 | /// [Reference](https://doc.rust-lang.org/reference/patterns.html#tuple-patterns) | ||
| 1511 | struct TuplePat { T!['('], args: [Pat], T![')'] } | ||
| 1512 | |||
| 1513 | /// Visibility. | ||
| 1514 | /// | ||
| 1515 | /// ``` | ||
| 1516 | /// ❰ pub mod ❱ foo; | ||
| 1517 | /// ❰ pub(crate) ❱ struct Bar; | ||
| 1518 | /// ❰ pub(self) ❱ enum Baz {} | ||
| 1519 | /// ❰ pub(super) ❱ fn bruh() {} | ||
| 1520 | /// ❰ pub(in bruuh::bruuuh) ❱ type T = u64; | ||
| 1521 | /// ``` | ||
| 1522 | /// | ||
| 1523 | /// [Reference](https://doc.rust-lang.org/reference/visibility-and-privacy.html) | ||
| 1524 | struct Visibility { T![pub], T![super], T![self], T![crate] } | ||
| 1525 | |||
| 1526 | /// Single identifier. | ||
| 1527 | /// Note(@matklad): `Name` is for things that install a new name into the scope, | ||
| 1528 | /// `NameRef` is a usage of a name. Most of the time, this definition/reference | ||
| 1529 | /// distinction can be determined purely syntactically, ie in | ||
| 1530 | /// ``` | ||
| 1531 | /// fn foo() { foo() } | ||
| 1532 | /// ``` | ||
| 1533 | /// the first foo is `Name`, the second one is `NameRef`. | ||
| 1534 | /// The notable exception are patterns, where in | ||
| 1535 | /// `` | ||
| 1536 | /// let x = 92 | ||
| 1537 | /// ``` | ||
| 1538 | /// `x` can be semantically either a name or a name ref, depeding on | ||
| 1539 | /// wether there's an `x` constant in scope. | ||
| 1540 | /// We use `Name` for patterns, and disambiguate semantically (see `NameClass` in ide_db). | ||
| 1541 | /// | ||
| 1542 | /// ``` | ||
| 1543 | /// let ❰ foo ❱ = bar; | ||
| 1544 | /// struct ❰ Baz ❱; | ||
| 1545 | /// fn ❰ bruh ❱() {} | ||
| 1546 | /// ``` | ||
| 1547 | /// | ||
| 1548 | /// [Reference](https://doc.rust-lang.org/reference/identifiers.html) | ||
| 1549 | struct Name { T![ident] } | ||
| 1550 | |||
| 1551 | /// Reference to a name. | ||
| 1552 | /// See the explanation on the difference between `Name` and `NameRef` | ||
| 1553 | /// in `Name` ast node docs. | ||
| 1554 | /// | ||
| 1555 | /// ``` | ||
| 1556 | /// let foo = ❰ bar ❱(❰ Baz(❰ bruh ❱) ❱; | ||
| 1557 | /// ``` | ||
| 1558 | /// | ||
| 1559 | /// [Reference](https://doc.rust-lang.org/reference/identifiers.html) | ||
| 1560 | struct NameRef { } | ||
| 1561 | |||
| 1562 | /// Macro call. | ||
| 1563 | /// Includes all of its attributes and doc comments. | ||
| 1564 | /// | ||
| 1565 | /// ``` | ||
| 1566 | /// ❰ | ||
| 1567 | /// /// Docs | ||
| 1568 | /// #[attr] | ||
| 1569 | /// macro_rules! foo { // macro rules is also a macro call | ||
| 1570 | /// ($bar: tt) => {} | ||
| 1571 | /// } | ||
| 1572 | /// ❱ | ||
| 1573 | /// | ||
| 1574 | /// // semicolon is a part of `MacroCall` when it is used in item positions | ||
| 1575 | /// ❰ foo!(); ❱ | ||
| 1576 | /// | ||
| 1577 | /// fn main() { | ||
| 1578 | /// ❰ foo!() ❱; // macro call in expression positions doesn't include the semi | ||
| 1579 | /// } | ||
| 1580 | /// ``` | ||
| 1581 | /// | ||
| 1582 | /// [Reference](https://doc.rust-lang.org/reference/macros.html) | ||
| 1583 | struct MacroCall: NameOwner, AttrsOwner, DocCommentsOwner { | ||
| 1584 | Path, T![!], TokenTree, T![;] | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | /// Attribute. | ||
| 1588 | /// | ||
| 1589 | /// ``` | ||
| 1590 | /// ❰ #![inner_attr] ❱ | ||
| 1591 | /// | ||
| 1592 | /// ❰ #[attr] ❱ | ||
| 1593 | /// ❰ #[foo = "bar"] ❱ | ||
| 1594 | /// ❰ #[baz(bruh::bruuh = "42")] ❱ | ||
| 1595 | /// struct Foo; | ||
| 1596 | /// ``` | ||
| 1597 | /// | ||
| 1598 | /// [Reference](https://doc.rust-lang.org/reference/attributes.html) | ||
| 1599 | struct Attr { T![#], T![!], T!['['], Path, T![=], input: AttrInput, T![']'] } | ||
| 1600 | |||
| 1601 | /// Stores a list of lexer tokens and other `TokenTree`s. | ||
| 1602 | /// It appears in attributes, macro_rules and macro call (foo!) | ||
| 1603 | /// | ||
| 1604 | /// ``` | ||
| 1605 | /// macro_call! ❰ { my syntax here } ❱; | ||
| 1606 | /// ``` | ||
| 1607 | /// | ||
| 1608 | /// [Reference](https://doc.rust-lang.org/reference/macros.html) | ||
| 1609 | struct TokenTree {} | ||
| 1610 | |||
| 1611 | /// Generic lifetime, type and constants parameters list **declaration**. | ||
| 1612 | /// | ||
| 1613 | /// ``` | ||
| 1614 | /// fn foo❰ <'a, 'b, T, U, const BAR: u64> ❱() {} | ||
| 1615 | /// | ||
| 1616 | /// struct Baz❰ <T> ❱(T); | ||
| 1617 | /// | ||
| 1618 | /// impl❰ <T> ❱ Bruh<T> {} | ||
| 1619 | /// | ||
| 1620 | /// type Bruuh = for❰ <'a> ❱ fn(&'a str) -> &'a str; | ||
| 1621 | /// ``` | ||
| 1622 | /// | ||
| 1623 | /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) | ||
| 1624 | struct TypeParamList { | ||
| 1625 | T![<], | ||
| 1626 | generic_params: [GenericParam], | ||
| 1627 | type_params: [TypeParam], | ||
| 1628 | lifetime_params: [LifetimeParam], | ||
| 1629 | const_params: [ConstParam], | ||
| 1630 | T![>] | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | /// Single type parameter **declaration**. | ||
| 1634 | /// | ||
| 1635 | /// ``` | ||
| 1636 | /// fn foo<❰ K ❱, ❰ I ❱, ❰ E: Debug ❱, ❰ V = DefaultType ❱>() {} | ||
| 1637 | /// ``` | ||
| 1638 | /// | ||
| 1639 | /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) | ||
| 1640 | struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { | ||
| 1641 | T![=], | ||
| 1642 | default_type: TypeRef, | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | /// Const generic parameter **declaration**. | ||
| 1646 | /// ``` | ||
| 1647 | /// fn foo<T, U, ❰ const BAR: usize ❱, ❰ const BAZ: bool ❱>() {} | ||
| 1648 | /// ``` | ||
| 1649 | /// | ||
| 1650 | /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter) | ||
| 1651 | struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { | ||
| 1652 | T![=], | ||
| 1653 | default_val: Expr, | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | /// Lifetime parameter **declaration**. | ||
| 1657 | /// | ||
| 1658 | /// ``` | ||
| 1659 | /// fn foo<❰ 'a ❱, ❰ 'b ❱, V, G, D>(bar: &'a str, baz: &'b mut str) {} | ||
| 1660 | /// ``` | ||
| 1661 | /// | ||
| 1662 | /// [Reference](https://doc.rust-lang.org/reference/items/generics.html) | ||
| 1663 | struct LifetimeParam: AttrsOwner { T![lifetime] } | ||
| 1664 | |||
| 1665 | /// Type bound declaration clause. | ||
| 1666 | /// | ||
| 1667 | /// ``` | ||
| 1668 | /// fn foo<T: ❰ ?Sized ❱ + ❰ Debug ❱>() {} | ||
| 1669 | /// | ||
| 1670 | /// trait Bar<T> | ||
| 1671 | /// where | ||
| 1672 | /// T: ❰ Send ❱ + ❰ Sync ❱ | ||
| 1673 | /// { | ||
| 1674 | /// type Baz: ❰ !Sync ❱ + ❰ Debug ❱ + ❰ ?const Add ❱; | ||
| 1675 | /// } | ||
| 1676 | /// ``` | ||
| 1677 | /// | ||
| 1678 | /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html) | ||
| 1679 | struct TypeBound { T![lifetime], /* Question, */ T![const], /* Question, */ TypeRef } | ||
| 1680 | |||
| 1681 | /// Type bounds list. | ||
| 1682 | /// | ||
| 1683 | /// ``` | ||
| 1684 | /// | ||
| 1685 | /// fn foo<T: ❰ ?Sized + Debug ❱>() {} | ||
| 1686 | /// | ||
| 1687 | /// trait Bar<T> | ||
| 1688 | /// where | ||
| 1689 | /// T: ❰ Send + Sync ❱ | ||
| 1690 | /// { | ||
| 1691 | /// type Baz: ❰ !Sync + Debug ❱; | ||
| 1692 | /// } | ||
| 1693 | /// ``` | ||
| 1694 | /// | ||
| 1695 | /// [Reference](https://doc.rust-lang.org/reference/trait-bounds.html) | ||
| 1696 | struct TypeBoundList { bounds: [TypeBound] } | ||
| 1697 | |||
| 1698 | /// Single where predicate. | ||
| 1699 | /// | ||
| 1700 | /// ``` | ||
| 1701 | /// trait Foo<'a, 'b, T> | ||
| 1702 | /// where | ||
| 1703 | /// ❰ 'a: 'b ❱, | ||
| 1704 | /// ❰ T: IntoIterator ❱, | ||
| 1705 | /// ❰ for<'c> <T as IntoIterator>::Item: Bar<'c> ❱ | ||
| 1706 | /// {} | ||
| 1707 | /// ``` | ||
| 1708 | /// | ||
| 1709 | /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses) | ||
| 1710 | struct WherePred: TypeBoundsOwner { T![for], TypeParamList, T![lifetime], TypeRef } | ||
| 1711 | |||
| 1712 | /// Where clause. | ||
| 1713 | /// | ||
| 1714 | /// ``` | ||
| 1715 | /// trait Foo<'a, T> ❰ where 'a: 'static, T: Debug ❱ {} | ||
| 1716 | /// | ||
| 1717 | /// ``` | ||
| 1718 | /// | ||
| 1719 | /// [Reference](https://doc.rust-lang.org/reference/items/generics.html#where-clauses) | ||
| 1720 | struct WhereClause { T![where], predicates: [WherePred] } | ||
| 1721 | |||
| 1722 | /// Abi declaration. | ||
| 1723 | /// Note: the abi string is optional. | ||
| 1724 | /// | ||
| 1725 | /// ``` | ||
| 1726 | /// ❰ extern "C" ❱ { | ||
| 1727 | /// fn foo() {} | ||
| 1728 | /// } | ||
| 1729 | /// | ||
| 1730 | /// type Bar = ❰ extern ❱ fn() -> u32; | ||
| 1731 | /// | ||
| 1732 | /// type Baz = ❰ extern r#"stdcall"# ❱ fn() -> bool; | ||
| 1733 | /// ``` | ||
| 1734 | /// | ||
| 1735 | /// - [Extern blocks reference](https://doc.rust-lang.org/reference/items/external-blocks.html) | ||
| 1736 | /// - [FFI function pointers reference](https://doc.rust-lang.org/reference/items/functions.html#functions) | ||
| 1737 | struct Abi { /*String*/ } | ||
| 1738 | |||
| 1739 | /// Expression statement. | ||
| 1740 | /// | ||
| 1741 | /// ``` | ||
| 1742 | /// ❰ 42; ❱ | ||
| 1743 | /// ❰ foo(); ❱ | ||
| 1744 | /// ❰ (); ❱ | ||
| 1745 | /// ❰ {}; ❱ | ||
| 1746 | /// | ||
| 1747 | /// // constructions with trailing curly brace can omit the semicolon | ||
| 1748 | /// // but only when there are satements immediately after them (this is important!) | ||
| 1749 | /// ❰ if bool_cond { } ❱ | ||
| 1750 | /// ❰ loop {} ❱ | ||
| 1751 | /// ❰ somestatment; ❱ | ||
| 1752 | /// ``` | ||
| 1753 | /// | ||
| 1754 | /// [Reference](https://doc.rust-lang.org/reference/statements.html) | ||
| 1755 | struct ExprStmt: AttrsOwner { Expr, T![;] } | ||
| 1756 | |||
| 1757 | /// Let statement. | ||
| 1758 | /// | ||
| 1759 | /// ``` | ||
| 1760 | /// ❰ #[attr] let foo; ❱ | ||
| 1761 | /// ❰ let bar: u64; ❱ | ||
| 1762 | /// ❰ let baz = 42; ❱ | ||
| 1763 | /// ❰ let bruh: bool = true; ❱ | ||
| 1764 | /// ``` | ||
| 1765 | /// | ||
| 1766 | /// [Reference](https://doc.rust-lang.org/reference/statements.html#let-statements) | ||
| 1767 | struct LetStmt: AttrsOwner, TypeAscriptionOwner { | ||
| 1768 | T![let], | ||
| 1769 | Pat, | ||
| 1770 | T![=], | ||
| 1771 | initializer: Expr, | ||
| 1772 | T![;], | ||
| 1773 | } | ||
| 1774 | |||
| 1775 | /// Condition of `if` or `while` expression. | ||
| 1776 | /// | ||
| 1777 | /// ``` | ||
| 1778 | /// if ❰ true ❱ {} | ||
| 1779 | /// if ❰ let Pat(foo) = bar ❱ {} | ||
| 1780 | /// | ||
| 1781 | /// while ❰ true ❱ {} | ||
| 1782 | /// while ❰ let Pat(baz) = bruh ❱ {} | ||
| 1783 | /// ``` | ||
| 1784 | /// | ||
| 1785 | /// [If expression reference](https://doc.rust-lang.org/reference/expressions/if-expr.html) | ||
| 1786 | /// [While expression reference](https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-loops) | ||
| 1787 | struct Condition { T![let], Pat, T![=], Expr } | ||
| 1788 | |||
| 1789 | /// Parameter list **declaration**. | ||
| 1790 | /// | ||
| 1791 | /// ``` | ||
| 1792 | /// fn foo❰ (a: u32, b: bool) ❱ -> u32 {} | ||
| 1793 | /// let bar = ❰ |a, b| ❱ {}; | ||
| 1794 | /// | ||
| 1795 | /// impl Baz { | ||
| 1796 | /// fn bruh❰ (&self, a: u32) ❱ {} | ||
| 1797 | /// } | ||
| 1798 | /// ``` | ||
| 1799 | /// | ||
| 1800 | /// [Reference](https://doc.rust-lang.org/reference/items/functions.html)ocs to codegen script | ||
| 1801 | struct ParamList { // FIXME: this node is used by closure expressions too, but hey use pipes instead of parens... | ||
| 1802 | T!['('], | ||
| 1803 | SelfParam, | ||
| 1804 | params: [Param], | ||
| 1805 | T![')'] | ||
| 1806 | } | ||
| 1807 | |||
| 1808 | /// Self parameter **declaration**. | ||
| 1809 | /// | ||
| 1810 | /// ``` | ||
| 1811 | /// impl Bruh { | ||
| 1812 | /// fn foo(❰ self ❱) {} | ||
| 1813 | /// fn bar(❰ &self ❱) {} | ||
| 1814 | /// fn baz(❰ &mut self ❱) {} | ||
| 1815 | /// fn blah<'a>(❰ &'a self ❱) {} | ||
| 1816 | /// fn blin(❰ self: Box<Self> ❱) {} | ||
| 1817 | /// } | ||
| 1818 | /// ``` | ||
| 1819 | /// | ||
| 1820 | /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) | ||
| 1821 | struct SelfParam: TypeAscriptionOwner, AttrsOwner { T![&], T![mut], T![lifetime], T![self] } | ||
| 1822 | |||
| 1823 | /// Parameter **declaration**. | ||
| 1824 | /// | ||
| 1825 | /// ``` | ||
| 1826 | /// fn foo(❰ #[attr] Pat(bar): Pat(u32) ❱, ❰ #[attr] _: bool ❱) {} | ||
| 1827 | /// | ||
| 1828 | /// extern "C" { | ||
| 1829 | /// fn bar(❰ baz: u32 ❱, ❰ ... ❱) -> u32; | ||
| 1830 | /// } | ||
| 1831 | /// ``` | ||
| 1832 | /// | ||
| 1833 | /// [Reference](https://doc.rust-lang.org/reference/items/functions.html) | ||
| 1834 | struct Param: TypeAscriptionOwner, AttrsOwner { | ||
| 1835 | Pat, | ||
| 1836 | T![...] | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | /// Use declaration. | ||
| 1840 | /// | ||
| 1841 | /// ``` | ||
| 1842 | /// ❰ #[attr] pub use foo; ❱ | ||
| 1843 | /// ❰ use bar as baz; ❱ | ||
| 1844 | /// ❰ use bruh::{self, bruuh}; ❱ | ||
| 1845 | /// ❰ use { blin::blen, blah::* }; | ||
| 1846 | /// ``` | ||
| 1847 | /// | ||
| 1848 | /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) | ||
| 1849 | struct UseItem: AttrsOwner, VisibilityOwner { | ||
| 1850 | T![use], | ||
| 1851 | UseTree, | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | /// Use tree. | ||
| 1855 | /// | ||
| 1856 | /// ``` | ||
| 1857 | /// pub use ❰ foo::❰ * ❱ ❱; | ||
| 1858 | /// use ❰ bar as baz ❱; | ||
| 1859 | /// use ❰ bruh::bruuh::{ ❰ self ❱, ❰ blin ❱ } ❱; | ||
| 1860 | /// use ❰ { ❰ blin::blen ❱ } ❱ | ||
| 1861 | /// ``` | ||
| 1862 | /// | ||
| 1863 | /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) | ||
| 1864 | struct UseTree { | ||
| 1865 | Path, T![*], UseTreeList, Alias | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | /// Item alias. | ||
| 1869 | /// Note: this is not the type alias. | ||
| 1870 | /// | ||
| 1871 | /// ``` | ||
| 1872 | /// use foo ❰ as bar ❱; | ||
| 1873 | /// use baz::{bruh ❰ as _ ❱}; | ||
| 1874 | /// extern crate bruuh ❰ as blin ❱; | ||
| 1875 | /// ``` | ||
| 1876 | /// | ||
| 1877 | /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) | ||
| 1878 | struct Alias: NameOwner { T![as] } | ||
| 1879 | |||
| 1880 | /// Sublist of use trees. | ||
| 1881 | /// | ||
| 1882 | /// ``` | ||
| 1883 | /// use bruh::bruuh::❰ { ❰ self ❱, ❰ blin ❱ } ❱; | ||
| 1884 | /// use ❰ { blin::blen::❰ {} ❱ } ❱ | ||
| 1885 | /// ``` | ||
| 1886 | /// | ||
| 1887 | /// [Reference](https://doc.rust-lang.org/reference/items/use-declarations.html) | ||
| 1888 | struct UseTreeList { T!['{'], use_trees: [UseTree], T!['}'] } | ||
| 1889 | |||
| 1890 | /// Extern crate item. | ||
| 1891 | /// | ||
| 1892 | /// ``` | ||
| 1893 | /// ❰ #[attr] pub extern crate foo; ❱ | ||
| 1894 | /// ❰ extern crate self as bar; ❱ | ||
| 1895 | /// ``` | ||
| 1896 | /// | ||
| 1897 | /// [Reference](https://doc.rust-lang.org/reference/items/extern-crates.html) | ||
| 1898 | struct ExternCrateItem: AttrsOwner, VisibilityOwner { | ||
| 1899 | T![extern], T![crate], NameRef, Alias, | ||
| 1900 | } | ||
| 1901 | |||
| 1902 | /// Call site arguments list. | ||
| 1903 | /// | ||
| 1904 | /// ``` | ||
| 1905 | /// foo::<T, U>❰ (42, true) ❱; | ||
| 1906 | /// ``` | ||
| 1907 | /// | ||
| 1908 | /// [Reference](https://doc.rust-lang.org/reference/expressions/call-expr.html) | ||
| 1909 | struct ArgList { | ||
| 1910 | T!['('], | ||
| 1911 | args: [Expr], | ||
| 1912 | T![')'] | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | /// Path to a symbol. Includes single identifier names and elaborate paths with | ||
| 1916 | /// generic parameters. | ||
| 1917 | /// | ||
| 1918 | /// ``` | ||
| 1919 | /// (0..10).❰ ❰ collect ❱ ::<Vec<_>> ❱(); | ||
| 1920 | /// ❰ ❰ ❰ Vec ❱ ::<u8> ❱ ::with_capacity ❱(1024); | ||
| 1921 | /// ❰ ❰ <❰ Foo ❱ as ❰ ❰ bar ❱ ::Bar ❱> ❱ ::baz ❱(); | ||
| 1922 | /// ❰ ❰ <❰ bruh ❱> ❱ ::bruuh ❱(); | ||
| 1923 | /// ``` | ||
| 1924 | /// | ||
| 1925 | /// [Reference](https://doc.rust-lang.org/reference/paths.html) | ||
| 1926 | struct Path { | ||
| 1927 | segment: PathSegment, | ||
| 1928 | T![::], | ||
| 1929 | qualifier: Path, | ||
| 1930 | } | ||
| 1931 | |||
| 1932 | /// Segment of the path to a symbol. | ||
| 1933 | /// Only path segment of an absolute path holds the `::` token, | ||
| 1934 | /// all other `::` tokens that connect path segments reside under `Path` itself.` | ||
| 1935 | /// | ||
| 1936 | /// ``` | ||
| 1937 | /// (0..10).❰ collect ❱ :: ❰ <Vec<_>> ❱(); | ||
| 1938 | /// ❰ Vec ❱ :: ❰ <u8> ❱ :: ❰ with_capacity ❱(1024); | ||
| 1939 | /// ❰ <❰ Foo ❱ as ❰ bar ❱ :: ❰ Bar ❱> ❱ :: ❰ baz ❱(); | ||
| 1940 | /// ❰ <❰ bruh ❱> ❱ :: ❰ bruuh ❱(); | ||
| 1941 | /// | ||
| 1942 | /// // Note that only in this case `::` token is inlcuded: | ||
| 1943 | /// ❰ ::foo ❱; | ||
| 1944 | /// ``` | ||
| 1945 | /// | ||
| 1946 | /// [Reference](https://doc.rust-lang.org/reference/paths.html) | ||
| 1947 | struct PathSegment { | ||
| 1948 | T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | /// List of type arguments that are passed at generic instantiation site. | ||
| 1952 | /// | ||
| 1953 | /// ``` | ||
| 1954 | /// type _ = Foo ❰ ::<'a, u64, Item = Bar, 42, {true}> ❱::Bar; | ||
| 1955 | /// | ||
| 1956 | /// Vec❰ ::<bool> ❱::(); | ||
| 1957 | /// ``` | ||
| 1958 | /// | ||
| 1959 | /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) | ||
| 1960 | struct TypeArgList { | ||
| 1961 | T![::], | ||
| 1962 | T![<], | ||
| 1963 | generic_args: [GenericArg], | ||
| 1964 | type_args: [TypeArg], | ||
| 1965 | lifetime_args: [LifetimeArg], | ||
| 1966 | assoc_type_args: [AssocTypeArg], | ||
| 1967 | const_args: [ConstArg], | ||
| 1968 | T![>] | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | /// Type argument that is passed at generic instantiation site. | ||
| 1972 | /// | ||
| 1973 | /// ``` | ||
| 1974 | /// type _ = Foo::<'a, ❰ u64 ❱, ❰ bool ❱, Item = Bar, 42>::Baz; | ||
| 1975 | /// ``` | ||
| 1976 | /// | ||
| 1977 | /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) | ||
| 1978 | struct TypeArg { TypeRef } | ||
| 1979 | |||
| 1980 | /// Associated type argument that is passed at generic instantiation site. | ||
| 1981 | /// ``` | ||
| 1982 | /// type Foo = Bar::<'a, u64, bool, ❰ Item = Baz ❱, 42>::Bruh; | ||
| 1983 | /// | ||
| 1984 | /// trait Bruh<T>: Iterator<❰ Item: Debug ❱> {} | ||
| 1985 | /// ``` | ||
| 1986 | /// | ||
| 1987 | struct AssocTypeArg : TypeBoundsOwner { NameRef, T![=], TypeRef } | ||
| 1988 | |||
| 1989 | /// Lifetime argument that is passed at generic instantiation site. | ||
| 1990 | /// | ||
| 1991 | /// ``` | ||
| 1992 | /// fn foo<'a>(s: &'a str) { | ||
| 1993 | /// bar::<❰ 'a ❱>(s); | ||
| 1994 | /// } | ||
| 1995 | /// ``` | ||
| 1996 | /// | ||
| 1997 | /// [Reference](https://doc.rust-lang.org/reference/paths.html#paths-in-expressions) | ||
| 1998 | struct LifetimeArg { T![lifetime] } | ||
| 1999 | |||
| 2000 | /// Constant value argument that is passed at generic instantiation site. | ||
| 2001 | /// | ||
| 2002 | /// ``` | ||
| 2003 | /// foo::<u32, ❰ { true } ❱>(); | ||
| 2004 | /// | ||
| 2005 | /// bar::<❰ { 2 + 2} ❱>(); | ||
| 2006 | /// ``` | ||
| 2007 | /// | ||
| 2008 | /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md#declaring-a-const-parameter) | ||
| 2009 | struct ConstArg { Literal, BlockExpr } | ||
| 2010 | |||
| 2011 | |||
| 2012 | /// FIXME: (@edwin0cheng) Remove it to use ItemList instead | ||
| 2013 | /// https://github.com/rust-analyzer/rust-analyzer/pull/4083#discussion_r422666243 | ||
| 2014 | /// | ||
| 2015 | /// [Reference](https://doc.rust-lang.org/reference/macros.html) | ||
| 2016 | struct MacroItems: ModuleItemOwner { } | ||
| 2017 | |||
| 2018 | /// FIXME: (@edwin0cheng) add some documentation here. As per the writing | ||
| 2019 | /// of this comment this ast node is not used. | ||
| 2020 | /// | ||
| 2021 | /// ``` | ||
| 2022 | /// // FIXME: example here | ||
| 2023 | /// ``` | ||
| 2024 | /// | ||
| 2025 | /// [Reference](https://doc.rust-lang.org/reference/macros.html) | ||
| 2026 | struct MacroStmts { | ||
| 2027 | statements: [Stmt], | ||
| 2028 | Expr, | ||
| 2029 | } | ||
| 2030 | |||
| 2031 | /// List of items in an extern block. | ||
| 2032 | /// | ||
| 2033 | /// ``` | ||
| 2034 | /// extern "C" ❰ | ||
| 2035 | /// { | ||
| 2036 | /// fn foo(); | ||
| 2037 | /// static var: u32; | ||
| 2038 | /// } | ||
| 2039 | /// ❱ | ||
| 2040 | /// ``` | ||
| 2041 | /// | ||
| 2042 | /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html) | ||
| 2043 | struct ExternItemList: ModuleItemOwner { | ||
| 2044 | T!['{'], | ||
| 2045 | extern_items: [ExternItem], | ||
| 2046 | T!['}'] | ||
| 2047 | } | ||
| 2048 | |||
| 2049 | /// Extern block. | ||
| 2050 | /// | ||
| 2051 | /// ``` | ||
| 2052 | /// ❰ | ||
| 2053 | /// extern "C" { | ||
| 2054 | /// fn foo(); | ||
| 2055 | /// } | ||
| 2056 | /// ❱ | ||
| 2057 | /// | ||
| 2058 | /// ``` | ||
| 2059 | /// | ||
| 2060 | /// [Reference](https://doc.rust-lang.org/reference/items/external-blocks.html) | ||
| 2061 | struct ExternBlock { | ||
| 2062 | Abi, | ||
| 2063 | ExternItemList | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | /// Meta item in an attribute. | ||
| 2067 | /// | ||
| 2068 | /// ``` | ||
| 2069 | /// #[❰ bar::baz = "42" ❱] | ||
| 2070 | /// #[❰ bruh(bruuh("true")) ❱] | ||
| 2071 | /// struct Foo; | ||
| 2072 | /// ``` | ||
| 2073 | /// | ||
| 2074 | /// [Reference](https://doc.rust-lang.org/reference/attributes.html?highlight=meta,item#meta-item-attribute-syntax) | ||
| 2075 | struct MetaItem { | ||
| 2076 | Path, T![=], AttrInput, nested_meta_items: [MetaItem] | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | /// Macro 2.0 definition. | ||
| 2080 | /// Their syntax is still WIP by rustc team... | ||
| 2081 | /// ``` | ||
| 2082 | /// ❰ | ||
| 2083 | /// macro foo { } | ||
| 2084 | /// ❱ | ||
| 2085 | /// ``` | ||
| 2086 | /// | ||
| 2087 | /// [RFC](https://github.com/rust-lang/rfcs/blob/master/text/1584-macros.md) | ||
| 2088 | struct MacroDef { | ||
| 2089 | Name, TokenTree | ||
| 2090 | } | ||
| 2091 | }, | ||
| 2092 | enums: &ast_enums! { | ||
| 2093 | /// Any kind of nominal type definition. | ||
| 2094 | enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { | ||
| 2095 | StructDef, EnumDef, UnionDef, | ||
| 2096 | } | ||
| 2097 | |||
| 2098 | /// Any kind of **declared** generic parameter | ||
| 2099 | enum GenericParam { | ||
| 2100 | LifetimeParam, | ||
| 2101 | TypeParam, | ||
| 2102 | ConstParam | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | /// Any kind of generic argument passed at instantiation site | ||
| 2106 | enum GenericArg { | ||
| 2107 | LifetimeArg, | ||
| 2108 | TypeArg, | ||
| 2109 | ConstArg, | ||
| 2110 | AssocTypeArg | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | /// Any kind of construct valid in type context | ||
| 2114 | enum TypeRef { | ||
| 2115 | ParenType, | ||
| 2116 | TupleType, | ||
| 2117 | NeverType, | ||
| 2118 | PathType, | ||
| 2119 | PointerType, | ||
| 2120 | ArrayType, | ||
| 2121 | SliceType, | ||
| 2122 | ReferenceType, | ||
| 2123 | PlaceholderType, | ||
| 2124 | FnPointerType, | ||
| 2125 | ForType, | ||
| 2126 | ImplTraitType, | ||
| 2127 | DynTraitType, | ||
| 2128 | } | ||
| 2129 | |||
| 2130 | /// Any kind of top-level item that may appear in a module | ||
| 2131 | enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner { | ||
| 2132 | StructDef, | ||
| 2133 | UnionDef, | ||
| 2134 | EnumDef, | ||
| 2135 | FnDef, | ||
| 2136 | TraitDef, | ||
| 2137 | TypeAliasDef, | ||
| 2138 | ImplDef, | ||
| 2139 | UseItem, | ||
| 2140 | ExternCrateItem, | ||
| 2141 | ConstDef, | ||
| 2142 | StaticDef, | ||
| 2143 | Module, | ||
| 2144 | MacroCall, | ||
| 2145 | ExternBlock | ||
| 2146 | } | ||
| 2147 | |||
| 2148 | |||
| 2149 | |||
| 2150 | /// Any kind of item that may appear in an impl block | ||
| 2151 | /// | ||
| 2152 | /// // FIXME: impl blocks can also contain MacroCall | ||
| 2153 | enum AssocItem: NameOwner, AttrsOwner { | ||
| 2154 | FnDef, TypeAliasDef, ConstDef | ||
| 2155 | } | ||
| 2156 | |||
| 2157 | /// Any kind of item that may appear in an extern block | ||
| 2158 | /// | ||
| 2159 | /// // FIXME: extern blocks can also contain MacroCall | ||
| 2160 | enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner { | ||
| 2161 | FnDef, StaticDef | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | /// Any kind of expression | ||
| 2165 | enum Expr: AttrsOwner { | ||
| 2166 | TupleExpr, | ||
| 2167 | ArrayExpr, | ||
| 2168 | ParenExpr, | ||
| 2169 | PathExpr, | ||
| 2170 | LambdaExpr, | ||
| 2171 | IfExpr, | ||
| 2172 | LoopExpr, | ||
| 2173 | ForExpr, | ||
| 2174 | WhileExpr, | ||
| 2175 | ContinueExpr, | ||
| 2176 | BreakExpr, | ||
| 2177 | Label, | ||
| 2178 | BlockExpr, | ||
| 2179 | ReturnExpr, | ||
| 2180 | MatchExpr, | ||
| 2181 | RecordLit, | ||
| 2182 | CallExpr, | ||
| 2183 | IndexExpr, | ||
| 2184 | MethodCallExpr, | ||
| 2185 | FieldExpr, | ||
| 2186 | AwaitExpr, | ||
| 2187 | TryExpr, | ||
| 2188 | EffectExpr, | ||
| 2189 | CastExpr, | ||
| 2190 | RefExpr, | ||
| 2191 | PrefixExpr, | ||
| 2192 | RangeExpr, | ||
| 2193 | BinExpr, | ||
| 2194 | Literal, | ||
| 2195 | MacroCall, | ||
| 2196 | BoxExpr, | ||
| 2197 | } | ||
| 2198 | |||
| 2199 | /// Any kind of pattern | ||
| 2200 | enum Pat { | ||
| 2201 | OrPat, | ||
| 2202 | ParenPat, | ||
| 2203 | RefPat, | ||
| 2204 | BoxPat, | ||
| 2205 | BindPat, | ||
| 2206 | PlaceholderPat, | ||
| 2207 | DotDotPat, | ||
| 2208 | PathPat, | ||
| 2209 | RecordPat, | ||
| 2210 | TupleStructPat, | ||
| 2211 | TuplePat, | ||
| 2212 | SlicePat, | ||
| 2213 | RangePat, | ||
| 2214 | LiteralPat, | ||
| 2215 | MacroPat, | ||
| 2216 | } | ||
| 2217 | |||
| 2218 | /// Any kind of pattern that appears directly inside of the curly | ||
| 2219 | /// braces of a record pattern | ||
| 2220 | enum RecordInnerPat { | ||
| 2221 | RecordFieldPat, | ||
| 2222 | BindPat | ||
| 2223 | } | ||
| 2224 | |||
| 2225 | /// Any kind of input to an attribute | ||
| 2226 | enum AttrInput { Literal, TokenTree } | ||
| 2227 | |||
| 2228 | /// Any kind of statement | ||
| 2229 | /// Note: there are no empty statements, these are just represented as | ||
| 2230 | /// bare semicolons without a dedicated statement ast node. | ||
| 2231 | enum Stmt { | ||
| 2232 | LetStmt, | ||
| 2233 | ExprStmt, | ||
| 2234 | // macro calls are parsed as expression statements | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | /// Any kind of fields list (record or tuple field lists) | ||
| 2238 | enum FieldDefList { | ||
| 2239 | RecordFieldDefList, | ||
| 2240 | TupleFieldDefList, | ||
| 2241 | } | ||
| 2242 | }, | ||
| 2243 | }; | ||
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index 745a25862..45b788bdb 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
| @@ -3,34 +3,43 @@ | |||
| 3 | //! Specifically, it generates the `SyntaxKind` enum and a number of newtype | 3 | //! Specifically, it generates the `SyntaxKind` enum and a number of newtype |
| 4 | //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. | 4 | //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. |
| 5 | 5 | ||
| 6 | use std::{collections::HashSet, fmt::Write}; | 6 | use std::{ |
| 7 | collections::{BTreeSet, HashSet}, | ||
| 8 | fmt::Write, | ||
| 9 | }; | ||
| 7 | 10 | ||
| 8 | use proc_macro2::{Punct, Spacing}; | 11 | use proc_macro2::{Punct, Spacing}; |
| 9 | use quote::{format_ident, quote}; | 12 | use quote::{format_ident, quote}; |
| 13 | use ungrammar::{Grammar, Rule}; | ||
| 10 | 14 | ||
| 11 | use crate::{ | 15 | use 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 | ||
| 17 | pub fn generate_syntax(mode: Mode) -> Result<()> { | 21 | pub fn generate_syntax(mode: Mode) -> Result<()> { |
| 22 | let grammar = include_str!("rust.ungram") | ||
| 23 | .parse::<Grammar>() | ||
| 24 | .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err)); | ||
| 25 | let ast = lower(&grammar); | ||
| 26 | |||
| 18 | let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); | 27 | let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); |
| 19 | let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; | 28 | let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; |
| 20 | update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; | 29 | update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; |
| 21 | 30 | ||
| 22 | let ast_tokens_file = project_root().join(codegen::AST_TOKENS); | 31 | let ast_tokens_file = project_root().join(codegen::AST_TOKENS); |
| 23 | let contents = generate_tokens(AST_SRC)?; | 32 | let contents = generate_tokens(&ast)?; |
| 24 | update(ast_tokens_file.as_path(), &contents, mode)?; | 33 | update(ast_tokens_file.as_path(), &contents, mode)?; |
| 25 | 34 | ||
| 26 | let ast_nodes_file = project_root().join(codegen::AST_NODES); | 35 | let ast_nodes_file = project_root().join(codegen::AST_NODES); |
| 27 | let contents = generate_nodes(KINDS_SRC, AST_SRC)?; | 36 | let contents = generate_nodes(KINDS_SRC, &ast)?; |
| 28 | update(ast_nodes_file.as_path(), &contents, mode)?; | 37 | update(ast_nodes_file.as_path(), &contents, mode)?; |
| 29 | 38 | ||
| 30 | Ok(()) | 39 | Ok(()) |
| 31 | } | 40 | } |
| 32 | 41 | ||
| 33 | fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { | 42 | fn generate_tokens(grammar: &AstSrc) -> Result<String> { |
| 34 | let tokens = grammar.tokens.iter().map(|token| { | 43 | let tokens = grammar.tokens.iter().map(|token| { |
| 35 | let name = format_ident!("{}", token); | 44 | let name = format_ident!("{}", token); |
| 36 | let kind = format_ident!("{}", to_upper_snake_case(token)); | 45 | let kind = format_ident!("{}", to_upper_snake_case(token)); |
| @@ -62,13 +71,13 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { | |||
| 62 | Ok(pretty) | 71 | Ok(pretty) |
| 63 | } | 72 | } |
| 64 | 73 | ||
| 65 | fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | 74 | fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> { |
| 66 | let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar | 75 | let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar |
| 67 | .nodes | 76 | .nodes |
| 68 | .iter() | 77 | .iter() |
| 69 | .map(|node| { | 78 | .map(|node| { |
| 70 | let name = format_ident!("{}", node.name); | 79 | let name = format_ident!("{}", node.name); |
| 71 | let kind = format_ident!("{}", to_upper_snake_case(node.name)); | 80 | let kind = format_ident!("{}", to_upper_snake_case(&node.name)); |
| 72 | let traits = node.traits.iter().map(|trait_name| { | 81 | let traits = node.traits.iter().map(|trait_name| { |
| 73 | let trait_name = format_ident!("{}", trait_name); | 82 | let trait_name = format_ident!("{}", trait_name); |
| 74 | quote!(impl ast::#trait_name for #name {}) | 83 | quote!(impl ast::#trait_name for #name {}) |
| @@ -192,8 +201,8 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
| 192 | }) | 201 | }) |
| 193 | .unzip(); | 202 | .unzip(); |
| 194 | 203 | ||
| 195 | let enum_names = grammar.enums.iter().map(|it| it.name); | 204 | let enum_names = grammar.enums.iter().map(|it| &it.name); |
| 196 | let node_names = grammar.nodes.iter().map(|it| it.name); | 205 | let node_names = grammar.nodes.iter().map(|it| &it.name); |
| 197 | 206 | ||
| 198 | let display_impls = | 207 | let display_impls = |
| 199 | enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { | 208 | enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { |
| @@ -212,9 +221,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
| 212 | .nodes | 221 | .nodes |
| 213 | .iter() | 222 | .iter() |
| 214 | .map(|kind| to_pascal_case(kind)) | 223 | .map(|kind| to_pascal_case(kind)) |
| 215 | .filter(|name| !defined_nodes.contains(name.as_str())) | 224 | .filter(|name| !defined_nodes.iter().any(|&it| it == name)) |
| 216 | { | 225 | { |
| 217 | eprintln!("Warning: node {} not defined in ast source", node); | 226 | drop(node) |
| 227 | // TODO: restore this | ||
| 228 | // eprintln!("Warning: node {} not defined in ast source", node); | ||
| 218 | } | 229 | } |
| 219 | 230 | ||
| 220 | let ast = quote! { | 231 | let ast = quote! { |
| @@ -236,12 +247,12 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
| 236 | let mut res = String::with_capacity(ast.len() * 2); | 247 | let mut res = String::with_capacity(ast.len() * 2); |
| 237 | 248 | ||
| 238 | let mut docs = | 249 | let mut docs = |
| 239 | grammar.nodes.iter().map(|it| it.doc).chain(grammar.enums.iter().map(|it| it.doc)); | 250 | grammar.nodes.iter().map(|it| &it.doc).chain(grammar.enums.iter().map(|it| &it.doc)); |
| 240 | 251 | ||
| 241 | for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") { | 252 | for chunk in ast.split("# [ pretty_doc_comment_placeholder_workaround ]") { |
| 242 | res.push_str(chunk); | 253 | res.push_str(chunk); |
| 243 | if let Some(doc) = docs.next() { | 254 | if let Some(doc) = docs.next() { |
| 244 | write_doc_comment(doc, &mut res); | 255 | write_doc_comment(&doc, &mut res); |
| 245 | } | 256 | } |
| 246 | } | 257 | } |
| 247 | 258 | ||
| @@ -249,7 +260,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
| 249 | Ok(pretty) | 260 | Ok(pretty) |
| 250 | } | 261 | } |
| 251 | 262 | ||
| 252 | fn write_doc_comment(contents: &[&str], dest: &mut String) { | 263 | fn write_doc_comment(contents: &[String], dest: &mut String) { |
| 253 | for line in contents { | 264 | for line in contents { |
| 254 | writeln!(dest, "///{}", line).unwrap(); | 265 | writeln!(dest, "///{}", line).unwrap(); |
| 255 | } | 266 | } |
| @@ -296,7 +307,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> { | |||
| 296 | 307 | ||
| 297 | let ast = quote! { | 308 | let ast = quote! { |
| 298 | #![allow(bad_style, missing_docs, unreachable_pub)] | 309 | #![allow(bad_style, missing_docs, unreachable_pub)] |
| 299 | /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT_DEF`. | 310 | /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`. |
| 300 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | 311 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
| 301 | #[repr(u16)] | 312 | #[repr(u16)] |
| 302 | pub enum SyntaxKind { | 313 | pub enum SyntaxKind { |
| @@ -363,6 +374,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> { | |||
| 363 | #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)* | 374 | #([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)* |
| 364 | [lifetime] => { $crate::SyntaxKind::LIFETIME }; | 375 | [lifetime] => { $crate::SyntaxKind::LIFETIME }; |
| 365 | [ident] => { $crate::SyntaxKind::IDENT }; | 376 | [ident] => { $crate::SyntaxKind::IDENT }; |
| 377 | [shebang] => { $crate::SyntaxKind::SHEBANG }; | ||
| 366 | } | 378 | } |
| 367 | }; | 379 | }; |
| 368 | 380 | ||
| @@ -413,9 +425,13 @@ fn to_pascal_case(s: &str) -> String { | |||
| 413 | buf | 425 | buf |
| 414 | } | 426 | } |
| 415 | 427 | ||
| 416 | impl Field<'_> { | 428 | fn pluralize(s: &str) -> String { |
| 429 | format!("{}s", s) | ||
| 430 | } | ||
| 431 | |||
| 432 | impl Field { | ||
| 417 | fn is_many(&self) -> bool { | 433 | fn is_many(&self) -> bool { |
| 418 | matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) | 434 | matches!(self, Field::Node { cardinality: Cardinality::Many, .. }) |
| 419 | } | 435 | } |
| 420 | fn token_kind(&self) -> Option<proc_macro2::TokenStream> { | 436 | fn token_kind(&self) -> Option<proc_macro2::TokenStream> { |
| 421 | match self { | 437 | match self { |
| @@ -429,7 +445,7 @@ impl Field<'_> { | |||
| 429 | fn method_name(&self) -> proc_macro2::Ident { | 445 | fn method_name(&self) -> proc_macro2::Ident { |
| 430 | match self { | 446 | match self { |
| 431 | Field::Token(name) => { | 447 | Field::Token(name) => { |
| 432 | let name = match *name { | 448 | let name = match name.as_str() { |
| 433 | ";" => "semicolon", | 449 | ";" => "semicolon", |
| 434 | "->" => "thin_arrow", | 450 | "->" => "thin_arrow", |
| 435 | "'{'" => "l_curly", | 451 | "'{'" => "l_curly", |
| @@ -448,29 +464,251 @@ impl Field<'_> { | |||
| 448 | "." => "dot", | 464 | "." => "dot", |
| 449 | ".." => "dotdot", | 465 | ".." => "dotdot", |
| 450 | "..." => "dotdotdot", | 466 | "..." => "dotdotdot", |
| 467 | "..=" => "dotdoteq", | ||
| 451 | "=>" => "fat_arrow", | 468 | "=>" => "fat_arrow", |
| 452 | "@" => "at", | 469 | "@" => "at", |
| 453 | ":" => "colon", | 470 | ":" => "colon", |
| 454 | "::" => "coloncolon", | 471 | "::" => "coloncolon", |
| 455 | "#" => "pound", | 472 | "#" => "pound", |
| 456 | "?" => "question_mark", | 473 | "?" => "question_mark", |
| 474 | "," => "comma", | ||
| 457 | _ => name, | 475 | _ => name, |
| 458 | }; | 476 | }; |
| 459 | format_ident!("{}_token", name) | 477 | format_ident!("{}_token", name) |
| 460 | } | 478 | } |
| 461 | Field::Node { name, src } => match src { | 479 | Field::Node { name, .. } => format_ident!("{}", name), |
| 462 | FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(name)), | ||
| 463 | _ => format_ident!("{}", name), | ||
| 464 | }, | ||
| 465 | } | 480 | } |
| 466 | } | 481 | } |
| 467 | fn ty(&self) -> proc_macro2::Ident { | 482 | fn ty(&self) -> proc_macro2::Ident { |
| 468 | match self { | 483 | match self { |
| 469 | Field::Token(_) => format_ident!("SyntaxToken"), | 484 | Field::Token(_) => format_ident!("SyntaxToken"), |
| 470 | Field::Node { name, src } => match src { | 485 | Field::Node { ty, .. } => format_ident!("{}", ty), |
| 471 | FieldSrc::Optional(ty) | FieldSrc::Many(ty) => format_ident!("{}", ty), | ||
| 472 | FieldSrc::Shorthand => format_ident!("{}", name), | ||
| 473 | }, | ||
| 474 | } | 486 | } |
| 475 | } | 487 | } |
| 476 | } | 488 | } |
| 489 | |||
| 490 | fn lower(grammar: &Grammar) -> AstSrc { | ||
| 491 | let mut res = AstSrc::default(); | ||
| 492 | res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; | ||
| 493 | |||
| 494 | let nodes = grammar | ||
| 495 | .iter() | ||
| 496 | .filter(|&node| match grammar[node].rule { | ||
| 497 | Rule::Node(it) if it == node => false, | ||
| 498 | _ => true, | ||
| 499 | }) | ||
| 500 | .collect::<Vec<_>>(); | ||
| 501 | |||
| 502 | for &node in &nodes { | ||
| 503 | let name = grammar[node].name.clone(); | ||
| 504 | let rule = &grammar[node].rule; | ||
| 505 | match lower_enum(grammar, rule) { | ||
| 506 | Some(variants) => { | ||
| 507 | let enum_src = AstEnumSrc { doc: Vec::new(), name, traits: Vec::new(), variants }; | ||
| 508 | res.enums.push(enum_src); | ||
| 509 | } | ||
| 510 | None => { | ||
| 511 | let mut fields = Vec::new(); | ||
| 512 | lower_rule(&mut fields, grammar, None, rule); | ||
| 513 | res.nodes.push(AstNodeSrc { doc: Vec::new(), name, traits: Vec::new(), fields }); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | deduplicate_fields(&mut res); | ||
| 519 | extract_enums(&mut res); | ||
| 520 | extract_struct_traits(&mut res); | ||
| 521 | extract_enum_traits(&mut res); | ||
| 522 | res | ||
| 523 | } | ||
| 524 | |||
| 525 | fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> { | ||
| 526 | let alternatives = match rule { | ||
| 527 | Rule::Alt(it) => it, | ||
| 528 | _ => return None, | ||
| 529 | }; | ||
| 530 | let mut variants = Vec::new(); | ||
| 531 | for alternative in alternatives { | ||
| 532 | match alternative { | ||
| 533 | Rule::Node(it) => variants.push(grammar[*it].name.clone()), | ||
| 534 | _ => return None, | ||
| 535 | } | ||
| 536 | } | ||
| 537 | Some(variants) | ||
| 538 | } | ||
| 539 | |||
| 540 | fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, rule: &Rule) { | ||
| 541 | if lower_comma_list(acc, grammar, label, rule) { | ||
| 542 | return; | ||
| 543 | } | ||
| 544 | |||
| 545 | match rule { | ||
| 546 | Rule::Node(node) => { | ||
| 547 | let ty = grammar[*node].name.clone(); | ||
| 548 | let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty)); | ||
| 549 | let field = Field::Node { name, ty, cardinality: Cardinality::Optional }; | ||
| 550 | acc.push(field); | ||
| 551 | } | ||
| 552 | Rule::Token(token) => { | ||
| 553 | assert!(label.is_none()); | ||
| 554 | let mut name = grammar[*token].name.clone(); | ||
| 555 | if name != "int_number" && name != "string" { | ||
| 556 | if "[]{}()".contains(&name) { | ||
| 557 | name = format!("'{}'", name); | ||
| 558 | } | ||
| 559 | let field = Field::Token(name); | ||
| 560 | acc.push(field); | ||
| 561 | } | ||
| 562 | } | ||
| 563 | Rule::Rep(inner) => { | ||
| 564 | if let Rule::Node(node) = &**inner { | ||
| 565 | let ty = grammar[*node].name.clone(); | ||
| 566 | let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty))); | ||
| 567 | let field = Field::Node { name, ty, cardinality: Cardinality::Many }; | ||
| 568 | acc.push(field); | ||
| 569 | return; | ||
| 570 | } | ||
| 571 | todo!("{:?}", rule) | ||
| 572 | } | ||
| 573 | Rule::Labeled { label: l, rule } => { | ||
| 574 | assert!(label.is_none()); | ||
| 575 | lower_rule(acc, grammar, Some(l), rule); | ||
| 576 | } | ||
| 577 | Rule::Seq(rules) | Rule::Alt(rules) => { | ||
| 578 | for rule in rules { | ||
| 579 | lower_rule(acc, grammar, label, rule) | ||
| 580 | } | ||
| 581 | } | ||
| 582 | Rule::Opt(rule) => lower_rule(acc, grammar, label, rule), | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | // (T (',' T)* ','?) | ||
| 587 | fn lower_comma_list( | ||
| 588 | acc: &mut Vec<Field>, | ||
| 589 | grammar: &Grammar, | ||
| 590 | label: Option<&String>, | ||
| 591 | rule: &Rule, | ||
| 592 | ) -> bool { | ||
| 593 | let rule = match rule { | ||
| 594 | Rule::Seq(it) => it, | ||
| 595 | _ => return false, | ||
| 596 | }; | ||
| 597 | let (node, repeat, trailing_comma) = match rule.as_slice() { | ||
| 598 | [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => { | ||
| 599 | (node, repeat, trailing_comma) | ||
| 600 | } | ||
| 601 | _ => return false, | ||
| 602 | }; | ||
| 603 | let repeat = match &**repeat { | ||
| 604 | Rule::Seq(it) => it, | ||
| 605 | _ => return false, | ||
| 606 | }; | ||
| 607 | match repeat.as_slice() { | ||
| 608 | [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (), | ||
| 609 | _ => return false, | ||
| 610 | } | ||
| 611 | let ty = grammar[*node].name.clone(); | ||
| 612 | let name = label.cloned().unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty))); | ||
| 613 | let field = Field::Node { name, ty, cardinality: Cardinality::Many }; | ||
| 614 | acc.push(field); | ||
| 615 | true | ||
| 616 | } | ||
| 617 | |||
| 618 | fn deduplicate_fields(ast: &mut AstSrc) { | ||
| 619 | for node in &mut ast.nodes { | ||
| 620 | let mut i = 0; | ||
| 621 | 'outer: while i < node.fields.len() { | ||
| 622 | for j in 0..i { | ||
| 623 | let f1 = &node.fields[i]; | ||
| 624 | let f2 = &node.fields[j]; | ||
| 625 | if f1 == f2 { | ||
| 626 | node.fields.remove(i); | ||
| 627 | continue 'outer; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | i += 1; | ||
| 631 | } | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | fn extract_enums(ast: &mut AstSrc) { | ||
| 636 | for node in &mut ast.nodes { | ||
| 637 | for enm in &ast.enums { | ||
| 638 | let mut to_remove = Vec::new(); | ||
| 639 | for (i, field) in node.fields.iter().enumerate() { | ||
| 640 | let ty = field.ty().to_string(); | ||
| 641 | if enm.variants.iter().any(|it| it == &ty) { | ||
| 642 | to_remove.push(i); | ||
| 643 | } | ||
| 644 | } | ||
| 645 | if to_remove.len() == enm.variants.len() { | ||
| 646 | node.remove_field(to_remove); | ||
| 647 | let ty = enm.name.clone(); | ||
| 648 | let name = to_lower_snake_case(&ty); | ||
| 649 | node.fields.push(Field::Node { name, ty, cardinality: Cardinality::Optional }); | ||
| 650 | } | ||
| 651 | } | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | fn extract_struct_traits(ast: &mut AstSrc) { | ||
| 656 | let traits: &[(&str, &[&str])] = &[ | ||
| 657 | ("AttrsOwner", &["attrs"]), | ||
| 658 | ("NameOwner", &["name"]), | ||
| 659 | ("VisibilityOwner", &["visibility"]), | ||
| 660 | ("GenericParamsOwner", &["generic_param_list", "where_clause"]), | ||
| 661 | ("TypeBoundsOwner", &["type_bound_list", "colon_token"]), | ||
| 662 | ("ModuleItemOwner", &["items"]), | ||
| 663 | ("LoopBodyOwner", &["label", "loop_body"]), | ||
| 664 | ("ArgListOwner", &["arg_list"]), | ||
| 665 | ]; | ||
| 666 | |||
| 667 | for node in &mut ast.nodes { | ||
| 668 | for (name, methods) in traits { | ||
| 669 | extract_struct_trait(node, name, methods); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } | ||
| 673 | |||
| 674 | fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) { | ||
| 675 | let mut to_remove = Vec::new(); | ||
| 676 | for (i, field) in node.fields.iter().enumerate() { | ||
| 677 | let method_name = field.method_name().to_string(); | ||
| 678 | if methods.iter().any(|&it| it == &method_name) { | ||
| 679 | to_remove.push(i); | ||
| 680 | } | ||
| 681 | } | ||
| 682 | if to_remove.len() == methods.len() { | ||
| 683 | node.traits.push(trait_name.to_string()); | ||
| 684 | node.remove_field(to_remove); | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | fn extract_enum_traits(ast: &mut AstSrc) { | ||
| 689 | for enm in &mut ast.enums { | ||
| 690 | let nodes = &ast.nodes; | ||
| 691 | let mut variant_traits = enm | ||
| 692 | .variants | ||
| 693 | .iter() | ||
| 694 | .map(|var| nodes.iter().find(|it| &it.name == var).unwrap()) | ||
| 695 | .map(|node| node.traits.iter().cloned().collect::<BTreeSet<_>>()); | ||
| 696 | |||
| 697 | let mut enum_traits = match variant_traits.next() { | ||
| 698 | Some(it) => it, | ||
| 699 | None => continue, | ||
| 700 | }; | ||
| 701 | for traits in variant_traits { | ||
| 702 | enum_traits = enum_traits.intersection(&traits).cloned().collect(); | ||
| 703 | } | ||
| 704 | enm.traits = enum_traits.into_iter().collect(); | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | impl AstNodeSrc { | ||
| 709 | fn remove_field(&mut self, to_remove: Vec<usize>) { | ||
| 710 | to_remove.into_iter().rev().for_each(|idx| { | ||
| 711 | self.fields.remove(idx); | ||
| 712 | }); | ||
| 713 | } | ||
| 714 | } | ||
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram new file mode 100644 index 000000000..375df301f --- /dev/null +++ b/xtask/src/codegen/rust.ungram | |||
| @@ -0,0 +1,544 @@ | |||
| 1 | SourceFile = | ||
| 2 | 'shebang'? | ||
| 3 | Attr* | ||
| 4 | Item* | ||
| 5 | |||
| 6 | Item = | ||
| 7 | Const | ||
| 8 | | Enum | ||
| 9 | | ExternBlock | ||
| 10 | | ExternCrate | ||
| 11 | | Fn | ||
| 12 | | Impl | ||
| 13 | | MacroCall | ||
| 14 | | Module | ||
| 15 | | Static | ||
| 16 | | Struct | ||
| 17 | | Trait | ||
| 18 | | TypeAlias | ||
| 19 | | Union | ||
| 20 | | Use | ||
| 21 | |||
| 22 | Module = | ||
| 23 | Attr* Visibility? 'mod' Name | ||
| 24 | (ItemList | ';') | ||
| 25 | |||
| 26 | ItemList = | ||
| 27 | '{' Attr* Item* '}' | ||
| 28 | |||
| 29 | ExternCrate = | ||
| 30 | Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';' | ||
| 31 | |||
| 32 | Rename = | ||
| 33 | 'as' (Name | '_') | ||
| 34 | |||
| 35 | Use = | ||
| 36 | Attr* Visibility? 'use' UseTree ';' | ||
| 37 | |||
| 38 | UseTree = | ||
| 39 | (Path? '::')? ('*' | UseTreeList ) | ||
| 40 | | Path Rename? | ||
| 41 | |||
| 42 | UseTreeList = | ||
| 43 | '{' (UseTree (',' UseTree)* ','?)? '}' | ||
| 44 | |||
| 45 | Fn = | ||
| 46 | Attr* Visibility? | ||
| 47 | 'default'? ('async' | 'const')? 'unsafe'? Abi? | ||
| 48 | 'fn' Name GenericParamList? ParamList RetType? | ||
| 49 | WhereClause? | ||
| 50 | (body:BlockExpr | ';') | ||
| 51 | |||
| 52 | Abi = | ||
| 53 | 'extern' 'string'? | ||
| 54 | |||
| 55 | ParamList = | ||
| 56 | '('( | ||
| 57 | SelfParam | ||
| 58 | | (SelfParam ',')? (Param (',' Param)* ','?)? | ||
| 59 | )')' | ||
| 60 | |||
| 61 | SelfParam = | ||
| 62 | Attr* ( | ||
| 63 | ('&' 'lifetime'?)? 'mut'? 'self' | ||
| 64 | | 'mut'? 'self' ':' ty:TypeRef | ||
| 65 | ) | ||
| 66 | |||
| 67 | Param = | ||
| 68 | Attr* ( | ||
| 69 | Pat (':' ty:TypeRef) | ||
| 70 | | ty:TypeRef | ||
| 71 | | '...' | ||
| 72 | ) | ||
| 73 | |||
| 74 | RetType = | ||
| 75 | '->' ty:TypeRef | ||
| 76 | |||
| 77 | TypeAlias = | ||
| 78 | Attr* Visibility? 'default'? 'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause? | ||
| 79 | '=' ty:TypeRef ';' | ||
| 80 | |||
| 81 | Struct = | ||
| 82 | Attr* Visibility? 'struct' Name GenericParamList? ( | ||
| 83 | WhereClause? (RecordFieldList | ';') | ||
| 84 | | TupleFieldList WhereClause? ';' | ||
| 85 | ) | ||
| 86 | |||
| 87 | RecordFieldList = | ||
| 88 | '{' fields:(RecordField (',' RecordField)* ','?)? '}' | ||
| 89 | |||
| 90 | RecordField = | ||
| 91 | Attr* Visibility? Name ':' ty:TypeRef | ||
| 92 | |||
| 93 | TupleFieldList = | ||
| 94 | '(' fields:(TupleField (',' TupleField)* ','?)? ')' | ||
| 95 | |||
| 96 | TupleField = | ||
| 97 | Attr* Visibility? ty:TypeRef | ||
| 98 | |||
| 99 | FieldList = | ||
| 100 | RecordFieldList | ||
| 101 | | TupleFieldList | ||
| 102 | |||
| 103 | Enum = | ||
| 104 | Attr* Visibility? 'enum' Name GenericParamList? WhereClause? | ||
| 105 | VariantList | ||
| 106 | |||
| 107 | VariantList = | ||
| 108 | '{' (Variant (',' Variant)* ','?)? '}' | ||
| 109 | |||
| 110 | Variant = | ||
| 111 | Attr* Visibility? Name FieldList ('=' Expr)? | ||
| 112 | |||
| 113 | Union = | ||
| 114 | Attr* Visibility? 'union' Name GenericParamList? WhereClause? | ||
| 115 | RecordFieldList | ||
| 116 | |||
| 117 | Const = | ||
| 118 | Attr* Visibility? 'default'? 'const' (Name | '_') ':' ty:TypeRef | ||
| 119 | '=' body:Expr ';' | ||
| 120 | |||
| 121 | Static = | ||
| 122 | Attr* Visibility? 'static'? 'mut'? Name ':' ty:TypeRef | ||
| 123 | '=' body:Expr ';' | ||
| 124 | |||
| 125 | Trait = | ||
| 126 | Attr* Visibility? 'unsafe'? 'auto'? 'trait' Name GenericParamList | ||
| 127 | (':' TypeBoundList?)? WhereClause | ||
| 128 | AssocItemList | ||
| 129 | |||
| 130 | AssocItemList = | ||
| 131 | '{' Attr* AssocItem* '}' | ||
| 132 | |||
| 133 | AssocItem = | ||
| 134 | Fn | ||
| 135 | | TypeAlias | ||
| 136 | | Const | ||
| 137 | | MacroCall | ||
| 138 | |||
| 139 | Impl = | ||
| 140 | Attr* Visibility? | ||
| 141 | 'default'? 'unsafe'? 'impl' 'const'? GenericParamList? ( | ||
| 142 | TypeRef | ||
| 143 | | '!'? TypeRef 'for' TypeRef | ||
| 144 | ) WhereClause? | ||
| 145 | AssocItemList | ||
| 146 | |||
| 147 | ExternBlock = | ||
| 148 | Attr* Abi ExternItemList | ||
| 149 | |||
| 150 | ExternItemList = | ||
| 151 | '{' Attr* ExternItem* '}' | ||
| 152 | |||
| 153 | ExternItem = | ||
| 154 | Fn | Static | MacroCall | ||
| 155 | |||
| 156 | GenericParamList = | ||
| 157 | '<' (GenericParam (',' GenericParam)* ','?)? '>' | ||
| 158 | |||
| 159 | GenericParam = | ||
| 160 | LifetimeParam | ||
| 161 | | TypeParam | ||
| 162 | | ConstParam | ||
| 163 | |||
| 164 | TypeParam = | ||
| 165 | Attr* Name (':' TypeBoundList?)? | ||
| 166 | ('=' default_type:TypeRef)? | ||
| 167 | |||
| 168 | ConstParam = | ||
| 169 | Attr* 'const' Name ':' ty:TypeRef | ||
| 170 | ('=' default_val:Expr)? | ||
| 171 | |||
| 172 | LifetimeParam = | ||
| 173 | Attr* 'lifetime' | ||
| 174 | |||
| 175 | Visibility = | ||
| 176 | 'pub' ('(' | ||
| 177 | 'super' | ||
| 178 | | 'self' | ||
| 179 | | 'crate' | ||
| 180 | | 'in' Path | ||
| 181 | ')')? | ||
| 182 | |||
| 183 | Attr = | ||
| 184 | '#' '!'? '[' Path ('=' Literal | TokenTree)? ']' | ||
| 185 | |||
| 186 | ParenType = | ||
| 187 | '(' ty:TypeRef ')' | ||
| 188 | |||
| 189 | TupleType = | ||
| 190 | '(' fields:TypeRef* ')' | ||
| 191 | |||
| 192 | NeverType = | ||
| 193 | '!' | ||
| 194 | |||
| 195 | PathType = | ||
| 196 | Path | ||
| 197 | |||
| 198 | PointerType = | ||
| 199 | '*' ('const' | 'mut') ty:TypeRef | ||
| 200 | |||
| 201 | ArrayType = | ||
| 202 | '[' ty:TypeRef ';' Expr ']' | ||
| 203 | |||
| 204 | SliceType = | ||
| 205 | '[' ty:TypeRef ']' | ||
| 206 | |||
| 207 | ReferenceType = | ||
| 208 | '&' 'lifetime'? 'mut'? ty:TypeRef | ||
| 209 | |||
| 210 | PlaceholderType = | ||
| 211 | '_' | ||
| 212 | |||
| 213 | FnPointerType = | ||
| 214 | Abi 'unsafe'? 'fn' ParamList RetType? | ||
| 215 | |||
| 216 | ForType = | ||
| 217 | 'for' GenericParamList ty:TypeRef | ||
| 218 | |||
| 219 | ImplTraitType = | ||
| 220 | 'impl' TypeBoundList | ||
| 221 | |||
| 222 | DynTraitType = | ||
| 223 | 'dyn' TypeBoundList | ||
| 224 | |||
| 225 | TupleExpr = | ||
| 226 | Attr* '(' Expr* ')' | ||
| 227 | |||
| 228 | ArrayExpr = | ||
| 229 | Attr* '[' (Expr* | Expr ';' Expr) ']' | ||
| 230 | |||
| 231 | ParenExpr = | ||
| 232 | Attr* '(' Expr ')' | ||
| 233 | |||
| 234 | PathExpr = | ||
| 235 | Path | ||
| 236 | |||
| 237 | LambdaExpr = | ||
| 238 | Attr* 'static'? 'async'? 'move'? ParamList RetType? | ||
| 239 | body:Expr | ||
| 240 | |||
| 241 | IfExpr = | ||
| 242 | Attr* 'if' Condition | ||
| 243 | |||
| 244 | Condition = | ||
| 245 | 'let' Pat '=' Expr | ||
| 246 | | Expr | ||
| 247 | |||
| 248 | EffectExpr = | ||
| 249 | Attr* Label? ('try' | 'unsafe' | 'async') BlockExpr | ||
| 250 | |||
| 251 | LoopExpr = | ||
| 252 | Attr* Label? 'loop' | ||
| 253 | loop_body:BlockExpr? | ||
| 254 | |||
| 255 | ForExpr = | ||
| 256 | Attr* Label? 'for' Pat 'in' iterable:Expr | ||
| 257 | loop_body:BlockExpr? | ||
| 258 | |||
| 259 | WhileExpr = | ||
| 260 | Attr* Label? 'while' Condition | ||
| 261 | loop_body:BlockExpr? | ||
| 262 | |||
| 263 | ContinueExpr = | ||
| 264 | Attr* 'continue' 'lifetime'? | ||
| 265 | |||
| 266 | BreakExpr = | ||
| 267 | Attr* 'break' 'lifetime'? Expr? | ||
| 268 | |||
| 269 | Label = | ||
| 270 | 'lifetime' | ||
| 271 | |||
| 272 | BlockExpr = | ||
| 273 | Attr* Label | ||
| 274 | '{' | ||
| 275 | Item* | ||
| 276 | statements:Stmt* | ||
| 277 | Expr? | ||
| 278 | '}' | ||
| 279 | |||
| 280 | ReturnExpr = | ||
| 281 | Attr* 'return' Expr | ||
| 282 | |||
| 283 | CallExpr = | ||
| 284 | Attr* Expr ArgList | ||
| 285 | |||
| 286 | MethodCallExpr = | ||
| 287 | Attr* Expr '.' NameRef TypeArgList? ArgList | ||
| 288 | |||
| 289 | ArgList = | ||
| 290 | '(' args:Expr* ')' | ||
| 291 | |||
| 292 | FieldExpr = | ||
| 293 | Attr* Expr '.' NameRef | ||
| 294 | |||
| 295 | IndexExpr = | ||
| 296 | Attr* '[' ']' | ||
| 297 | |||
| 298 | AwaitExpr = | ||
| 299 | Attr* Expr '.' 'await' | ||
| 300 | |||
| 301 | TryExpr = | ||
| 302 | Attr* Expr '?' | ||
| 303 | |||
| 304 | CastExpr = | ||
| 305 | Attr* Expr 'as' ty:TypeRef | ||
| 306 | |||
| 307 | RefExpr = | ||
| 308 | Attr* '&' ('raw' | 'mut' | 'const') Expr | ||
| 309 | |||
| 310 | PrefixExpr = | ||
| 311 | Attr* Expr | ||
| 312 | |||
| 313 | BoxExpr = | ||
| 314 | Attr* 'box' Expr | ||
| 315 | |||
| 316 | RangeExpr = | ||
| 317 | Attr* | ||
| 318 | |||
| 319 | BinExpr = | ||
| 320 | Attr* | ||
| 321 | |||
| 322 | Literal = | ||
| 323 | 'int_number' | ||
| 324 | |||
| 325 | MatchExpr = | ||
| 326 | Attr* 'match' Expr MatchArmList | ||
| 327 | |||
| 328 | MatchArmList = | ||
| 329 | '{' arms:MatchArm* '}' | ||
| 330 | |||
| 331 | MatchArm = | ||
| 332 | Attr* Pat guard:MatchGuard? '=>' Expr | ||
| 333 | |||
| 334 | MatchGuard = | ||
| 335 | 'if' Expr | ||
| 336 | |||
| 337 | RecordExpr = | ||
| 338 | Path RecordExprFieldList | ||
| 339 | |||
| 340 | RecordExprFieldList = | ||
| 341 | '{' | ||
| 342 | fields:RecordExprField* | ||
| 343 | ('..' spread:Expr)? | ||
| 344 | '}' | ||
| 345 | |||
| 346 | RecordExprField = | ||
| 347 | Attr* NameRef (':' Expr)? | ||
| 348 | |||
| 349 | OrPat = | ||
| 350 | Pat* | ||
| 351 | |||
| 352 | ParenPat = | ||
| 353 | '(' Pat ')' | ||
| 354 | |||
| 355 | RefPat = | ||
| 356 | '&' 'mut'? Pat | ||
| 357 | |||
| 358 | BoxPat = | ||
| 359 | 'box' Path | ||
| 360 | |||
| 361 | BindPat = | ||
| 362 | Attr* 'ref'? 'mut'? Name ('@' Pat)? | ||
| 363 | |||
| 364 | PlaceholderPat = | ||
| 365 | '_' | ||
| 366 | |||
| 367 | DotDotPat = | ||
| 368 | '..' | ||
| 369 | |||
| 370 | PathPat = | ||
| 371 | Path | ||
| 372 | |||
| 373 | SlicePat = | ||
| 374 | '[' args:Pat* ']' | ||
| 375 | |||
| 376 | RangePat = | ||
| 377 | '..' | '..=' | ||
| 378 | |||
| 379 | LiteralPat = | ||
| 380 | Literal | ||
| 381 | |||
| 382 | MacroPat = | ||
| 383 | MacroCall | ||
| 384 | |||
| 385 | RecordPat = | ||
| 386 | Path RecordFieldPatList | ||
| 387 | |||
| 388 | RecordFieldPatList = | ||
| 389 | '{' | ||
| 390 | record_field_pats:RecordFieldPat* | ||
| 391 | BindPat* | ||
| 392 | '..'? | ||
| 393 | '}' | ||
| 394 | |||
| 395 | RecordFieldPat = | ||
| 396 | Attr* NameRef ':' Pat | ||
| 397 | |||
| 398 | TupleStructPat = | ||
| 399 | Path '(' args:Pat* ')' | ||
| 400 | |||
| 401 | TuplePat = | ||
| 402 | '(' args:Pat* ')' | ||
| 403 | |||
| 404 | Name = | ||
| 405 | 'ident' | ||
| 406 | |||
| 407 | NameRef = | ||
| 408 | 'ident' | 'int_number' | ||
| 409 | |||
| 410 | MacroCall = | ||
| 411 | Attr* Path '!' Name? TokenTree ';'? | ||
| 412 | |||
| 413 | MacroDef = | ||
| 414 | Name TokenTree | ||
| 415 | |||
| 416 | TokenTree = | ||
| 417 | '(' ')' | '{' '}' | '[' ']' | ||
| 418 | |||
| 419 | MacroItems = | ||
| 420 | Item* | ||
| 421 | |||
| 422 | MacroStmts = | ||
| 423 | statements:Stmt* | ||
| 424 | Expr? | ||
| 425 | |||
| 426 | TypeBound = | ||
| 427 | 'lifetime' | 'const'? TypeRef | ||
| 428 | |||
| 429 | TypeBoundList = | ||
| 430 | bounds:TypeBound* | ||
| 431 | |||
| 432 | WherePred = | ||
| 433 | ('for' GenericParamList)? ('lifetime' | TypeRef) ':' TypeBoundList | ||
| 434 | |||
| 435 | WhereClause = | ||
| 436 | 'where' predicates:WherePred* | ||
| 437 | |||
| 438 | ExprStmt = | ||
| 439 | Attr* Expr ';' | ||
| 440 | |||
| 441 | LetStmt = | ||
| 442 | Attr* 'let' Pat (':' ty:TypeRef) | ||
| 443 | '=' initializer:Expr ';' | ||
| 444 | |||
| 445 | Path = | ||
| 446 | (qualifier:Path '::')? segment:PathSegment | ||
| 447 | |||
| 448 | PathSegment = | ||
| 449 | '::' | 'crate' | 'self' | 'super' | ||
| 450 | | '<' NameRef TypeArgList ParamList RetType PathType '>' | ||
| 451 | |||
| 452 | TypeArgList = | ||
| 453 | '::'? '<' | ||
| 454 | TypeArg* | ||
| 455 | LifetimeArg* | ||
| 456 | AssocTypeArg* | ||
| 457 | ConstArg* | ||
| 458 | '>' | ||
| 459 | |||
| 460 | TypeArg = | ||
| 461 | TypeRef | ||
| 462 | |||
| 463 | AssocTypeArg = | ||
| 464 | NameRef (':' TypeBoundList | '=' TypeRef) | ||
| 465 | |||
| 466 | LifetimeArg = | ||
| 467 | 'lifetime' | ||
| 468 | |||
| 469 | ConstArg = | ||
| 470 | Literal | BlockExpr BlockExpr | ||
| 471 | |||
| 472 | AdtDef = | ||
| 473 | Struct | ||
| 474 | | Enum | ||
| 475 | | Union | ||
| 476 | |||
| 477 | TypeRef = | ||
| 478 | ParenType | ||
| 479 | | TupleType | ||
| 480 | | NeverType | ||
| 481 | | PathType | ||
| 482 | | PointerType | ||
| 483 | | ArrayType | ||
| 484 | | SliceType | ||
| 485 | | ReferenceType | ||
| 486 | | PlaceholderType | ||
| 487 | | FnPointerType | ||
| 488 | | ForType | ||
| 489 | | ImplTraitType | ||
| 490 | | DynTraitType | ||
| 491 | |||
| 492 | Stmt = | ||
| 493 | LetStmt | ||
| 494 | | ExprStmt | ||
| 495 | |||
| 496 | Pat = | ||
| 497 | OrPat | ||
| 498 | | ParenPat | ||
| 499 | | RefPat | ||
| 500 | | BoxPat | ||
| 501 | | BindPat | ||
| 502 | | PlaceholderPat | ||
| 503 | | DotDotPat | ||
| 504 | | PathPat | ||
| 505 | | RecordPat | ||
| 506 | | TupleStructPat | ||
| 507 | | TuplePat | ||
| 508 | | SlicePat | ||
| 509 | | RangePat | ||
| 510 | | LiteralPat | ||
| 511 | | MacroPat | ||
| 512 | |||
| 513 | Expr = | ||
| 514 | TupleExpr | ||
| 515 | | ArrayExpr | ||
| 516 | | ParenExpr | ||
| 517 | | PathExpr | ||
| 518 | | LambdaExpr | ||
| 519 | | IfExpr | ||
| 520 | | LoopExpr | ||
| 521 | | ForExpr | ||
| 522 | | WhileExpr | ||
| 523 | | ContinueExpr | ||
| 524 | | BreakExpr | ||
| 525 | | Label | ||
| 526 | | BlockExpr | ||
| 527 | | ReturnExpr | ||
| 528 | | MatchExpr | ||
| 529 | | RecordExpr | ||
| 530 | | CallExpr | ||
| 531 | | IndexExpr | ||
| 532 | | MethodCallExpr | ||
| 533 | | FieldExpr | ||
| 534 | | AwaitExpr | ||
| 535 | | TryExpr | ||
| 536 | | EffectExpr | ||
| 537 | | CastExpr | ||
| 538 | | RefExpr | ||
| 539 | | PrefixExpr | ||
| 540 | | RangeExpr | ||
| 541 | | BinExpr | ||
| 542 | | Literal | ||
| 543 | | MacroCall | ||
| 544 | | BoxExpr | ||
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index aef68089e..01d903cde 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
| @@ -1,4 +1,10 @@ | |||
| 1 | use std::path::PathBuf; | 1 | use flate2::{write::GzEncoder, Compression}; |
| 2 | use std::{ | ||
| 3 | env, | ||
| 4 | fs::File, | ||
| 5 | io, | ||
| 6 | path::{Path, PathBuf}, | ||
| 7 | }; | ||
| 2 | 8 | ||
| 3 | use anyhow::Result; | 9 | use anyhow::Result; |
| 4 | 10 | ||
| @@ -7,17 +13,24 @@ use crate::{ | |||
| 7 | project_root, | 13 | project_root, |
| 8 | }; | 14 | }; |
| 9 | 15 | ||
| 10 | pub fn run_dist(nightly: bool, client_version: Option<String>) -> Result<()> { | 16 | pub struct DistCmd { |
| 11 | let dist = project_root().join("dist"); | 17 | pub nightly: bool, |
| 12 | rm_rf(&dist)?; | 18 | pub client_version: Option<String>, |
| 13 | fs2::create_dir_all(&dist)?; | 19 | } |
| 20 | |||
| 21 | impl DistCmd { | ||
| 22 | pub fn run(self) -> Result<()> { | ||
| 23 | let dist = project_root().join("dist"); | ||
| 24 | rm_rf(&dist)?; | ||
| 25 | fs2::create_dir_all(&dist)?; | ||
| 14 | 26 | ||
| 15 | if let Some(version) = client_version { | 27 | if let Some(version) = self.client_version { |
| 16 | let release_tag = if nightly { "nightly".to_string() } else { date_iso()? }; | 28 | let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? }; |
| 17 | dist_client(&version, &release_tag)?; | 29 | dist_client(&version, &release_tag)?; |
| 30 | } | ||
| 31 | dist_server()?; | ||
| 32 | Ok(()) | ||
| 18 | } | 33 | } |
| 19 | dist_server(nightly)?; | ||
| 20 | Ok(()) | ||
| 21 | } | 34 | } |
| 22 | 35 | ||
| 23 | fn dist_client(version: &str, release_tag: &str) -> Result<()> { | 36 | fn dist_client(version: &str, release_tag: &str) -> Result<()> { |
| @@ -46,17 +59,12 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
| 46 | Ok(()) | 59 | Ok(()) |
| 47 | } | 60 | } |
| 48 | 61 | ||
| 49 | fn dist_server(nightly: bool) -> Result<()> { | 62 | fn dist_server() -> Result<()> { |
| 50 | if cfg!(target_os = "linux") { | 63 | if cfg!(target_os = "linux") { |
| 51 | std::env::set_var("CC", "clang"); | 64 | env::set_var("CC", "clang"); |
| 52 | run!( | 65 | run!( |
| 53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" | 66 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" |
| 54 | // We'd want to add, but that requires setting the right linker somehow | ||
| 55 | // --features=jemalloc | ||
| 56 | )?; | 67 | )?; |
| 57 | if !nightly { | ||
| 58 | run!("strip ./target/release/rust-analyzer")?; | ||
| 59 | } | ||
| 60 | } else { | 68 | } else { |
| 61 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; | 69 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; |
| 62 | } | 70 | } |
| @@ -71,8 +79,20 @@ fn dist_server(nightly: bool) -> Result<()> { | |||
| 71 | panic!("Unsupported OS") | 79 | panic!("Unsupported OS") |
| 72 | }; | 80 | }; |
| 73 | 81 | ||
| 74 | fs2::copy(src, dst)?; | 82 | let src = Path::new(src); |
| 83 | let dst = Path::new(dst); | ||
| 84 | |||
| 85 | fs2::copy(&src, &dst)?; | ||
| 86 | gzip(&src, &dst.with_extension("gz"))?; | ||
| 87 | |||
| 88 | Ok(()) | ||
| 89 | } | ||
| 75 | 90 | ||
| 91 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { | ||
| 92 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); | ||
| 93 | let mut input = io::BufReader::new(File::open(src_path)?); | ||
| 94 | io::copy(&mut input, &mut encoder)?; | ||
| 95 | encoder.finish()?; | ||
| 76 | Ok(()) | 96 | Ok(()) |
| 77 | } | 97 | } |
| 78 | 98 | ||
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index 9ba77a3aa..b25a6e301 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
| @@ -19,7 +19,12 @@ pub enum ClientOpt { | |||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | pub struct ServerOpt { | 21 | pub struct ServerOpt { |
| 22 | pub jemalloc: bool, | 22 | pub malloc: Malloc, |
| 23 | } | ||
| 24 | |||
| 25 | pub enum Malloc { | ||
| 26 | System, | ||
| 27 | Mimalloc, | ||
| 23 | } | 28 | } |
| 24 | 29 | ||
| 25 | impl InstallCmd { | 30 | impl InstallCmd { |
| @@ -130,8 +135,11 @@ fn install_server(opts: ServerOpt) -> Result<()> { | |||
| 130 | ) | 135 | ) |
| 131 | } | 136 | } |
| 132 | 137 | ||
| 133 | let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" }; | 138 | let malloc_feature = match opts.malloc { |
| 134 | let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", jemalloc); | 139 | Malloc::System => "", |
| 140 | Malloc::Mimalloc => "--features mimalloc", | ||
| 141 | }; | ||
| 142 | let res = run!("cargo install --path crates/rust-analyzer --locked --force {}", malloc_feature); | ||
| 135 | 143 | ||
| 136 | if res.is_err() && old_rust { | 144 | if res.is_err() && old_rust { |
| 137 | eprintln!( | 145 | eprintln!( |
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 747654c1f..2fdb08f2e 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
| @@ -7,6 +7,7 @@ pub mod install; | |||
| 7 | pub mod release; | 7 | pub mod release; |
| 8 | pub mod dist; | 8 | pub mod dist; |
| 9 | pub mod pre_commit; | 9 | pub mod pre_commit; |
| 10 | pub mod metrics; | ||
| 10 | 11 | ||
| 11 | pub mod codegen; | 12 | pub mod codegen; |
| 12 | mod ast_src; | 13 | mod ast_src; |
| @@ -20,7 +21,7 @@ use walkdir::{DirEntry, WalkDir}; | |||
| 20 | 21 | ||
| 21 | use crate::{ | 22 | use crate::{ |
| 22 | codegen::Mode, | 23 | codegen::Mode, |
| 23 | not_bash::{fs2, pushd, pushenv, rm_rf, run}, | 24 | not_bash::{fs2, pushd, pushenv, rm_rf}, |
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 26 | pub use anyhow::{bail, Context as _, Result}; | 27 | pub use anyhow::{bail, Context as _, Result}; |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index f7a79362d..b69b884e5 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
| @@ -13,11 +13,12 @@ use std::env; | |||
| 13 | use pico_args::Arguments; | 13 | use pico_args::Arguments; |
| 14 | use xtask::{ | 14 | use xtask::{ |
| 15 | codegen::{self, Mode}, | 15 | codegen::{self, Mode}, |
| 16 | dist::run_dist, | 16 | dist::DistCmd, |
| 17 | install::{ClientOpt, InstallCmd, ServerOpt}, | 17 | install::{ClientOpt, InstallCmd, Malloc, ServerOpt}, |
| 18 | metrics::MetricsCmd, | ||
| 18 | not_bash::pushd, | 19 | not_bash::pushd, |
| 19 | pre_commit, project_root, | 20 | pre_commit, project_root, |
| 20 | release::ReleaseCmd, | 21 | release::{PromoteCmd, ReleaseCmd}, |
| 21 | run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result, | 22 | run_clippy, run_fuzzer, run_pre_cache, run_rustfmt, Result, |
| 22 | }; | 23 | }; |
| 23 | 24 | ||
| @@ -45,7 +46,7 @@ USAGE: | |||
| 45 | FLAGS: | 46 | FLAGS: |
| 46 | --client-code Install only VS Code plugin | 47 | --client-code Install only VS Code plugin |
| 47 | --server Install only the language server | 48 | --server Install only the language server |
| 48 | --jemalloc Use jemalloc for server | 49 | --mimalloc Use mimalloc for server |
| 49 | -h, --help Prints help information | 50 | -h, --help Prints help information |
| 50 | " | 51 | " |
| 51 | ); | 52 | ); |
| @@ -61,13 +62,14 @@ FLAGS: | |||
| 61 | return Ok(()); | 62 | return Ok(()); |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | let jemalloc = args.contains("--jemalloc"); | 65 | let malloc = |
| 66 | if args.contains("--mimalloc") { Malloc::Mimalloc } else { Malloc::System }; | ||
| 65 | 67 | ||
| 66 | args.finish()?; | 68 | args.finish()?; |
| 67 | 69 | ||
| 68 | InstallCmd { | 70 | InstallCmd { |
| 69 | client: if server { None } else { Some(ClientOpt::VsCode) }, | 71 | client: if server { None } else { Some(ClientOpt::VsCode) }, |
| 70 | server: if client_code { None } else { Some(ServerOpt { jemalloc }) }, | 72 | server: if client_code { None } else { Some(ServerOpt { malloc }) }, |
| 71 | } | 73 | } |
| 72 | .run() | 74 | .run() |
| 73 | } | 75 | } |
| @@ -105,11 +107,21 @@ FLAGS: | |||
| 105 | args.finish()?; | 107 | args.finish()?; |
| 106 | ReleaseCmd { dry_run }.run() | 108 | ReleaseCmd { dry_run }.run() |
| 107 | } | 109 | } |
| 110 | "promote" => { | ||
| 111 | let dry_run = args.contains("--dry-run"); | ||
| 112 | args.finish()?; | ||
| 113 | PromoteCmd { dry_run }.run() | ||
| 114 | } | ||
| 108 | "dist" => { | 115 | "dist" => { |
| 109 | let nightly = args.contains("--nightly"); | 116 | let nightly = args.contains("--nightly"); |
| 110 | let client_version: Option<String> = args.opt_value_from_str("--client")?; | 117 | let client_version: Option<String> = args.opt_value_from_str("--client")?; |
| 111 | args.finish()?; | 118 | args.finish()?; |
| 112 | run_dist(nightly, client_version) | 119 | DistCmd { nightly, client_version }.run() |
| 120 | } | ||
| 121 | "metrics" => { | ||
| 122 | let dry_run = args.contains("--dry-run"); | ||
| 123 | args.finish()?; | ||
| 124 | MetricsCmd { dry_run }.run() | ||
| 113 | } | 125 | } |
| 114 | _ => { | 126 | _ => { |
| 115 | eprintln!( | 127 | eprintln!( |
| @@ -127,7 +139,8 @@ SUBCOMMANDS: | |||
| 127 | codegen | 139 | codegen |
| 128 | install | 140 | install |
| 129 | lint | 141 | lint |
| 130 | dist" | 142 | dist |
| 143 | promote" | ||
| 131 | ); | 144 | ); |
| 132 | Ok(()) | 145 | Ok(()) |
| 133 | } | 146 | } |
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs new file mode 100644 index 000000000..9ac3fa51d --- /dev/null +++ b/xtask/src/metrics.rs | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | use std::{ | ||
| 2 | collections::BTreeMap, | ||
| 3 | env, | ||
| 4 | fmt::{self, Write as _}, | ||
| 5 | io::Write as _, | ||
| 6 | path::Path, | ||
| 7 | time::{Instant, SystemTime, UNIX_EPOCH}, | ||
| 8 | }; | ||
| 9 | |||
| 10 | use anyhow::{bail, format_err, Result}; | ||
| 11 | |||
| 12 | use crate::not_bash::{fs2, pushd, pushenv, rm_rf, run}; | ||
| 13 | |||
| 14 | type Unit = String; | ||
| 15 | |||
| 16 | pub struct MetricsCmd { | ||
| 17 | pub dry_run: bool, | ||
| 18 | } | ||
| 19 | |||
| 20 | impl MetricsCmd { | ||
| 21 | pub fn run(self) -> Result<()> { | ||
| 22 | let mut metrics = Metrics::new()?; | ||
| 23 | if !self.dry_run { | ||
| 24 | rm_rf("./target/release")?; | ||
| 25 | } | ||
| 26 | if !Path::new("./target/rustc-perf").exists() { | ||
| 27 | fs2::create_dir_all("./target/rustc-perf")?; | ||
| 28 | run!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")?; | ||
| 29 | } | ||
| 30 | { | ||
| 31 | let _d = pushd("./target/rustc-perf"); | ||
| 32 | run!("git reset --hard 1d9288b0da7febf2599917da1b57dc241a1af033")?; | ||
| 33 | } | ||
| 34 | |||
| 35 | let _env = pushenv("RA_METRICS", "1"); | ||
| 36 | |||
| 37 | metrics.measure_build()?; | ||
| 38 | metrics.measure_analysis_stats_self()?; | ||
| 39 | metrics.measure_analysis_stats("ripgrep")?; | ||
| 40 | metrics.measure_analysis_stats("webrender")?; | ||
| 41 | |||
| 42 | if !self.dry_run { | ||
| 43 | let _d = pushd("target"); | ||
| 44 | let metrics_token = env::var("METRICS_TOKEN").unwrap(); | ||
| 45 | let repo = format!("https://{}@github.com/rust-analyzer/metrics.git", metrics_token); | ||
| 46 | run!("git clone --depth 1 {}", repo)?; | ||
| 47 | let _d = pushd("metrics"); | ||
| 48 | |||
| 49 | let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?; | ||
| 50 | writeln!(file, "{}", metrics.json())?; | ||
| 51 | run!("git add .")?; | ||
| 52 | run!("git -c user.name=Bot -c [email protected] commit --message 📈")?; | ||
| 53 | run!("git push origin master")?; | ||
| 54 | } | ||
| 55 | eprintln!("{:#?}", metrics); | ||
| 56 | Ok(()) | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | impl Metrics { | ||
| 61 | fn measure_build(&mut self) -> Result<()> { | ||
| 62 | eprintln!("\nMeasuring build"); | ||
| 63 | run!("cargo fetch")?; | ||
| 64 | |||
| 65 | let time = Instant::now(); | ||
| 66 | run!("cargo build --release --package rust-analyzer --bin rust-analyzer")?; | ||
| 67 | let time = time.elapsed(); | ||
| 68 | self.report("build", time.as_millis() as u64, "ms".into()); | ||
| 69 | Ok(()) | ||
| 70 | } | ||
| 71 | fn measure_analysis_stats_self(&mut self) -> Result<()> { | ||
| 72 | self.measure_analysis_stats_path("self", &".") | ||
| 73 | } | ||
| 74 | fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> { | ||
| 75 | self.measure_analysis_stats_path( | ||
| 76 | bench, | ||
| 77 | &format!("./target/rustc-perf/collector/benchmarks/{}", bench), | ||
| 78 | ) | ||
| 79 | } | ||
| 80 | fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> { | ||
| 81 | eprintln!("\nMeasuring analysis-stats/{}", name); | ||
| 82 | let output = run!("./target/release/rust-analyzer analysis-stats --quiet {}", path)?; | ||
| 83 | for (metric, value, unit) in parse_metrics(&output) { | ||
| 84 | self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into()); | ||
| 85 | } | ||
| 86 | Ok(()) | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | fn parse_metrics(output: &str) -> Vec<(&str, u64, &str)> { | ||
| 91 | output | ||
| 92 | .lines() | ||
| 93 | .filter_map(|it| { | ||
| 94 | let entry = it.split(':').collect::<Vec<_>>(); | ||
| 95 | match entry.as_slice() { | ||
| 96 | ["METRIC", name, value, unit] => Some((*name, value.parse().unwrap(), *unit)), | ||
| 97 | _ => None, | ||
| 98 | } | ||
| 99 | }) | ||
| 100 | .collect() | ||
| 101 | } | ||
| 102 | |||
| 103 | #[derive(Debug)] | ||
| 104 | struct Metrics { | ||
| 105 | host: Host, | ||
| 106 | timestamp: SystemTime, | ||
| 107 | revision: String, | ||
| 108 | metrics: BTreeMap<String, (u64, Unit)>, | ||
| 109 | } | ||
| 110 | |||
| 111 | #[derive(Debug)] | ||
| 112 | struct Host { | ||
| 113 | os: String, | ||
| 114 | cpu: String, | ||
| 115 | mem: String, | ||
| 116 | } | ||
| 117 | |||
| 118 | impl Metrics { | ||
| 119 | fn new() -> Result<Metrics> { | ||
| 120 | let host = Host::new()?; | ||
| 121 | let timestamp = SystemTime::now(); | ||
| 122 | let revision = run!("git rev-parse HEAD")?; | ||
| 123 | Ok(Metrics { host, timestamp, revision, metrics: BTreeMap::new() }) | ||
| 124 | } | ||
| 125 | |||
| 126 | fn report(&mut self, name: &str, value: u64, unit: Unit) { | ||
| 127 | self.metrics.insert(name.into(), (value, unit)); | ||
| 128 | } | ||
| 129 | |||
| 130 | fn json(&self) -> Json { | ||
| 131 | let mut json = Json::default(); | ||
| 132 | self.to_json(&mut json); | ||
| 133 | json | ||
| 134 | } | ||
| 135 | fn to_json(&self, json: &mut Json) { | ||
| 136 | json.begin_object(); | ||
| 137 | { | ||
| 138 | json.field("host"); | ||
| 139 | self.host.to_json(json); | ||
| 140 | |||
| 141 | json.field("timestamp"); | ||
| 142 | let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); | ||
| 143 | json.number(timestamp.as_secs() as f64); | ||
| 144 | |||
| 145 | json.field("revision"); | ||
| 146 | json.string(&self.revision); | ||
| 147 | |||
| 148 | json.field("metrics"); | ||
| 149 | json.begin_object(); | ||
| 150 | { | ||
| 151 | for (k, (value, unit)) in &self.metrics { | ||
| 152 | json.field(k); | ||
| 153 | json.begin_array(); | ||
| 154 | { | ||
| 155 | json.number(*value as f64); | ||
| 156 | json.string(unit); | ||
| 157 | } | ||
| 158 | json.end_array(); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | json.end_object() | ||
| 162 | } | ||
| 163 | json.end_object(); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | impl Host { | ||
| 168 | fn new() -> Result<Host> { | ||
| 169 | if cfg!(not(target_os = "linux")) { | ||
| 170 | bail!("can only collect metrics on Linux "); | ||
| 171 | } | ||
| 172 | |||
| 173 | let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string(); | ||
| 174 | |||
| 175 | let cpu = | ||
| 176 | read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string(); | ||
| 177 | |||
| 178 | let mem = read_field("/proc/meminfo", "MemTotal:")?; | ||
| 179 | |||
| 180 | return Ok(Host { os, cpu, mem }); | ||
| 181 | |||
| 182 | fn read_field<'a>(path: &str, field: &str) -> Result<String> { | ||
| 183 | let text = fs2::read_to_string(path)?; | ||
| 184 | |||
| 185 | let line = text | ||
| 186 | .lines() | ||
| 187 | .find(|it| it.starts_with(field)) | ||
| 188 | .ok_or_else(|| format_err!("can't parse {}", path))?; | ||
| 189 | Ok(line[field.len()..].trim().to_string()) | ||
| 190 | } | ||
| 191 | } | ||
| 192 | fn to_json(&self, json: &mut Json) { | ||
| 193 | json.begin_object(); | ||
| 194 | { | ||
| 195 | json.field("os"); | ||
| 196 | json.string(&self.os); | ||
| 197 | |||
| 198 | json.field("cpu"); | ||
| 199 | json.string(&self.cpu); | ||
| 200 | |||
| 201 | json.field("mem"); | ||
| 202 | json.string(&self.mem); | ||
| 203 | } | ||
| 204 | json.end_object(); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | struct State { | ||
| 209 | obj: bool, | ||
| 210 | first: bool, | ||
| 211 | } | ||
| 212 | |||
| 213 | #[derive(Default)] | ||
| 214 | struct Json { | ||
| 215 | stack: Vec<State>, | ||
| 216 | buf: String, | ||
| 217 | } | ||
| 218 | |||
| 219 | impl Json { | ||
| 220 | fn begin_object(&mut self) { | ||
| 221 | self.stack.push(State { obj: true, first: true }); | ||
| 222 | self.buf.push('{'); | ||
| 223 | } | ||
| 224 | fn end_object(&mut self) { | ||
| 225 | self.stack.pop(); | ||
| 226 | self.buf.push('}') | ||
| 227 | } | ||
| 228 | fn begin_array(&mut self) { | ||
| 229 | self.stack.push(State { obj: false, first: true }); | ||
| 230 | self.buf.push('['); | ||
| 231 | } | ||
| 232 | fn end_array(&mut self) { | ||
| 233 | self.stack.pop(); | ||
| 234 | self.buf.push(']') | ||
| 235 | } | ||
| 236 | fn field(&mut self, name: &str) { | ||
| 237 | self.object_comma(); | ||
| 238 | self.string_token(name); | ||
| 239 | self.buf.push(':'); | ||
| 240 | } | ||
| 241 | fn string(&mut self, value: &str) { | ||
| 242 | self.array_comma(); | ||
| 243 | self.string_token(value); | ||
| 244 | } | ||
| 245 | fn string_token(&mut self, value: &str) { | ||
| 246 | self.buf.push('"'); | ||
| 247 | self.buf.extend(value.escape_default()); | ||
| 248 | self.buf.push('"'); | ||
| 249 | } | ||
| 250 | fn number(&mut self, value: f64) { | ||
| 251 | self.array_comma(); | ||
| 252 | write!(self.buf, "{}", value).unwrap(); | ||
| 253 | } | ||
| 254 | |||
| 255 | fn array_comma(&mut self) { | ||
| 256 | let state = self.stack.last_mut().unwrap(); | ||
| 257 | if state.obj { | ||
| 258 | return; | ||
| 259 | } | ||
| 260 | if !state.first { | ||
| 261 | self.buf.push(','); | ||
| 262 | } | ||
| 263 | state.first = false; | ||
| 264 | } | ||
| 265 | |||
| 266 | fn object_comma(&mut self) { | ||
| 267 | let state = self.stack.last_mut().unwrap(); | ||
| 268 | if !state.first { | ||
| 269 | self.buf.push(','); | ||
| 270 | } | ||
| 271 | state.first = false; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | impl fmt::Display for Json { | ||
| 276 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
| 277 | write!(f, "{}", self.buf) | ||
| 278 | } | ||
| 279 | } | ||
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs index a6431e586..ef811e5bf 100644 --- a/xtask/src/not_bash.rs +++ b/xtask/src/not_bash.rs | |||
| @@ -54,7 +54,8 @@ pub mod fs2 { | |||
| 54 | } | 54 | } |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | macro_rules! _run { | 57 | #[macro_export] |
| 58 | macro_rules! run { | ||
| 58 | ($($expr:expr),*) => { | 59 | ($($expr:expr),*) => { |
| 59 | run!($($expr),*; echo = true) | 60 | run!($($expr),*; echo = true) |
| 60 | }; | 61 | }; |
| @@ -65,7 +66,7 @@ macro_rules! _run { | |||
| 65 | $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) | 66 | $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) |
| 66 | }; | 67 | }; |
| 67 | } | 68 | } |
| 68 | pub(crate) use _run as run; | 69 | pub use crate::run; |
| 69 | 70 | ||
| 70 | pub struct Pushd { | 71 | pub struct Pushd { |
| 71 | _p: (), | 72 | _p: (), |
| @@ -153,7 +154,17 @@ fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<Stri | |||
| 153 | 154 | ||
| 154 | // FIXME: some real shell lexing here | 155 | // FIXME: some real shell lexing here |
| 155 | fn shelx(cmd: &str) -> Vec<String> { | 156 | fn shelx(cmd: &str) -> Vec<String> { |
| 156 | cmd.split_whitespace().map(|it| it.to_string()).collect() | 157 | let mut res = Vec::new(); |
| 158 | for (string_piece, in_quotes) in cmd.split('\'').zip([false, true].iter().copied().cycle()) { | ||
| 159 | if in_quotes { | ||
| 160 | res.push(string_piece.to_string()) | ||
| 161 | } else { | ||
| 162 | if !string_piece.is_empty() { | ||
| 163 | res.extend(string_piece.split_ascii_whitespace().map(|it| it.to_string())) | ||
| 164 | } | ||
| 165 | } | ||
| 166 | } | ||
| 167 | res | ||
| 157 | } | 168 | } |
| 158 | 169 | ||
| 159 | struct Env { | 170 | struct Env { |
| @@ -175,7 +186,8 @@ impl Env { | |||
| 175 | fn pushd(&mut self, dir: PathBuf) { | 186 | fn pushd(&mut self, dir: PathBuf) { |
| 176 | let dir = self.cwd().join(dir); | 187 | let dir = self.cwd().join(dir); |
| 177 | self.pushd_stack.push(dir); | 188 | self.pushd_stack.push(dir); |
| 178 | env::set_current_dir(self.cwd()).unwrap(); | 189 | env::set_current_dir(self.cwd()) |
| 190 | .unwrap_or_else(|err| panic!("Failed to set cwd to {}: {}", self.cwd().display(), err)); | ||
| 179 | } | 191 | } |
| 180 | fn popd(&mut self) { | 192 | fn popd(&mut self) { |
| 181 | self.pushd_stack.pop().unwrap(); | 193 | self.pushd_stack.pop().unwrap(); |
diff --git a/xtask/src/release.rs b/xtask/src/release.rs index b6502b952..7fa0966aa 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | use crate::{ | 1 | use crate::{ |
| 2 | codegen, is_release_tag, | 2 | codegen, is_release_tag, |
| 3 | not_bash::{date_iso, fs2, run}, | 3 | not_bash::{date_iso, fs2, pushd, run}, |
| 4 | project_root, Mode, Result, | 4 | project_root, Mode, Result, |
| 5 | }; | 5 | }; |
| 6 | 6 | ||
| @@ -37,6 +37,8 @@ Release: release:{}[] | |||
| 37 | 37 | ||
| 38 | == Sponsors | 38 | == Sponsors |
| 39 | 39 | ||
| 40 | **Become a sponsor:** https://opencollective.com/rust-analyzer/[opencollective.com/rust-analyzer] | ||
| 41 | |||
| 40 | == New Features | 42 | == New Features |
| 41 | 43 | ||
| 42 | * pr:[] . | 44 | * pr:[] . |
| @@ -67,3 +69,35 @@ Release: release:{}[] | |||
| 67 | Ok(()) | 69 | Ok(()) |
| 68 | } | 70 | } |
| 69 | } | 71 | } |
| 72 | |||
| 73 | pub struct PromoteCmd { | ||
| 74 | pub dry_run: bool, | ||
| 75 | } | ||
| 76 | |||
| 77 | impl PromoteCmd { | ||
| 78 | pub fn run(self) -> Result<()> { | ||
| 79 | let _dir = pushd("../rust-rust-analyzer"); | ||
| 80 | run!("git switch master")?; | ||
| 81 | run!("git fetch upstream")?; | ||
| 82 | run!("git reset --hard upstream/master")?; | ||
| 83 | run!("git submodule update --recursive")?; | ||
| 84 | |||
| 85 | let branch = format!("rust-analyzer-{}", date_iso()?); | ||
| 86 | run!("git switch -c {}", branch)?; | ||
| 87 | { | ||
| 88 | let _dir = pushd("src/tools/rust-analyzer"); | ||
| 89 | run!("git fetch origin")?; | ||
| 90 | run!("git reset --hard origin/release")?; | ||
| 91 | } | ||
| 92 | run!("git add src/tools/rust-analyzer")?; | ||
| 93 | run!("git commit -m':arrow_up: rust-analyzer'")?; | ||
| 94 | if !self.dry_run { | ||
| 95 | run!("git push")?; | ||
| 96 | run!( | ||
| 97 | "xdg-open https://github.com/matklad/rust/pull/new/{}?body=r%3F%20%40ghost", | ||
| 98 | branch | ||
| 99 | )?; | ||
| 100 | } | ||
| 101 | Ok(()) | ||
| 102 | } | ||
| 103 | } | ||
