3915: Prettify generated code r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2020-04-09 16:15:21 +00:00 committed by GitHub
commit 30f0ad159a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 7154 additions and 9746 deletions

View file

@ -21,7 +21,7 @@ pub use self::{
AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind, AttrKind, FieldKind, PathSegmentKind, SelfParamKind, SlicePatComponents, StructKind,
TypeBoundKind, VisibilityKind, TypeBoundKind, VisibilityKind,
}, },
generated::*, generated::{nodes::*, tokens::*},
tokens::*, tokens::*,
traits::*, traits::*,
}; };

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -227,6 +227,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
pub(crate) struct AstSrc<'a> { pub(crate) struct AstSrc<'a> {
pub(crate) nodes: &'a [AstNodeSrc<'a>], pub(crate) nodes: &'a [AstNodeSrc<'a>],
pub(crate) enums: &'a [AstEnumSrc<'a>], pub(crate) enums: &'a [AstEnumSrc<'a>],
pub(crate) token_enums: &'a [AstEnumSrc<'a>],
} }
pub(crate) struct AstNodeSrc<'a> { pub(crate) struct AstNodeSrc<'a> {
@ -753,6 +754,13 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
// macro calls are parsed as expression statements */ // macro calls are parsed as expression statements */
} }
enum FieldDefList {
RecordFieldDefList,
TupleFieldDefList,
}
},
token_enums: &ast_enums! {
enum LeftDelimiter { LParen, LBrack, LCurly } enum LeftDelimiter { LParen, LBrack, LCurly }
enum RightDelimiter { RParen, RBrack, RCurly } enum RightDelimiter { RParen, RBrack, RCurly }
enum RangeSeparator { Dotdot, Dotdotdot, Dotdoteq} enum RangeSeparator { Dotdot, Dotdotdot, Dotdoteq}
@ -817,10 +825,5 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
Ident, Ident,
IntNumber IntNumber
} }
enum FieldDefList {
RecordFieldDefList,
TupleFieldDefList,
}
}, },
}; };

View file

@ -22,8 +22,9 @@ const GRAMMAR_DIR: &str = "crates/ra_parser/src/grammar";
const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/ok"; const OK_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/ok";
const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err"; const ERR_INLINE_TESTS_DIR: &str = "crates/ra_syntax/test_data/parser/inline/err";
pub const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs"; const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/generated.rs";
pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs"; const AST_NODES: &str = "crates/ra_syntax/src/ast/generated/nodes.rs";
const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs";
const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs"; const ASSISTS_TESTS: &str = "crates/ra_assists/src/doc_tests/generated.rs";

View file

@ -3,10 +3,13 @@
//! Specifically, it generates the `SyntaxKind` enum and a number of newtype //! Specifically, it generates the `SyntaxKind` enum and a number of newtype
//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`. //! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
use std::{
borrow::Cow,
collections::{BTreeSet, HashSet},
};
use proc_macro2::{Punct, Spacing}; use proc_macro2::{Punct, Spacing};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use std::borrow::Cow;
use std::collections::{BTreeSet, HashMap, HashSet};
use crate::{ use crate::{
ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC},
@ -19,9 +22,13 @@ pub fn generate_syntax(mode: Mode) -> Result<()> {
let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
let ast_file = project_root().join(codegen::AST); let ast_nodes_file = project_root().join(codegen::AST_NODES);
let ast = generate_ast(KINDS_SRC, AST_SRC)?; let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
update(ast_file.as_path(), &ast, mode)?; update(ast_nodes_file.as_path(), &contents, mode)?;
let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
let contents = generate_tokens(KINDS_SRC, AST_SRC)?;
update(ast_tokens_file.as_path(), &contents, mode)?;
Ok(()) Ok(())
} }
@ -33,7 +40,7 @@ struct ElementKinds {
has_tokens: bool, has_tokens: bool,
} }
fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { fn generate_tokens(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
let all_token_kinds: Vec<_> = kinds let all_token_kinds: Vec<_> = kinds
.punct .punct
.into_iter() .into_iter()
@ -51,46 +58,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
.chain(kinds.tokens.into_iter().copied().map(|x| x.into())) .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
.collect(); .collect();
let mut element_kinds_map = HashMap::new();
for kind in &all_token_kinds {
let kind = &**kind;
let name = to_pascal_case(kind);
element_kinds_map.insert(
name,
ElementKinds {
kinds: Some(format_ident!("{}", kind)).into_iter().collect(),
has_nodes: false,
has_tokens: true,
},
);
}
for kind in kinds.nodes {
let name = to_pascal_case(kind);
element_kinds_map.insert(
name,
ElementKinds {
kinds: Some(format_ident!("{}", *kind)).into_iter().collect(),
has_nodes: true,
has_tokens: false,
},
);
}
for en in grammar.enums {
let mut element_kinds: ElementKinds = Default::default();
for variant in en.variants {
if let Some(variant_element_kinds) = element_kinds_map.get(*variant) {
element_kinds.kinds.extend(variant_element_kinds.kinds.iter().cloned());
element_kinds.has_tokens |= variant_element_kinds.has_tokens;
element_kinds.has_nodes |= variant_element_kinds.has_nodes;
} else {
panic!("Enum variant has type that does not exist or was not declared before the enum: {}", *variant);
}
}
element_kinds_map.insert(en.name.to_string(), element_kinds);
}
let tokens = all_token_kinds.iter().map(|kind_str| { let tokens = all_token_kinds.iter().map(|kind_str| {
let kind_str = &**kind_str; let kind_str = &**kind_str;
let kind = format_ident!("{}", kind_str); let kind = format_ident!("{}", kind_str);
@ -108,12 +75,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
impl AstToken for #name { impl AstToken for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
match kind {
#kind => true,
_ => false,
}
}
fn cast(syntax: SyntaxToken) -> Option<Self> { fn cast(syntax: SyntaxToken) -> Option<Self> {
if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
} }
@ -122,6 +84,99 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
}); });
let enums = grammar.token_enums.iter().map(|en| {
let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>();
let name = format_ident!("{}", en.name);
let kinds = variants
.iter()
.map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
.collect::<Vec<_>>();
assert!(en.traits.is_empty());
quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name {
#(#variants(#variants),)*
}
#(
impl From<#variants> for #name {
fn from(node: #variants) -> #name {
#name::#variants(node)
}
}
)*
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl AstToken for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: SyntaxToken) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &SyntaxToken {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
}
});
crate::reformat(quote! {
use crate::{SyntaxToken, SyntaxKind::{self, *}, ast::AstToken};
#(#tokens)*
#(#enums)*
})
}
fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
let all_token_kinds: Vec<_> = kinds
.punct
.into_iter()
.map(|(_, kind)| kind)
.copied()
.map(|x| x.into())
.chain(
kinds
.keywords
.into_iter()
.chain(kinds.contextual_keywords.into_iter())
.map(|name| Cow::Owned(format!("{}_KW", to_upper_snake_case(&name)))),
)
.chain(kinds.literals.into_iter().copied().map(|x| x.into()))
.chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
.collect();
let mut token_kinds = HashSet::new();
for kind in &all_token_kinds {
let kind = &**kind;
let name = to_pascal_case(kind);
token_kinds.insert(name);
}
for en in grammar.token_enums {
token_kinds.insert(en.name.to_string());
}
let nodes = grammar.nodes.iter().map(|node| { let nodes = grammar.nodes.iter().map(|node| {
let name = format_ident!("{}", node.name); let name = format_ident!("{}", node.name);
let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
@ -151,7 +206,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
} }
FieldSrc::Optional(_) | FieldSrc::Shorthand => { FieldSrc::Optional(_) | FieldSrc::Shorthand => {
let is_token = element_kinds_map[&ty.to_string()].has_tokens; let is_token = token_kinds.contains(&ty.to_string());
if is_token { if is_token {
quote! { quote! {
pub fn #method_name(&self) -> Option<#ty> { pub fn #method_name(&self) -> Option<#ty> {
@ -175,18 +230,9 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
pub(crate) syntax: SyntaxNode, pub(crate) syntax: SyntaxNode,
} }
impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
impl AstNode for #name { impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool { fn can_cast(kind: SyntaxKind) -> bool {
match kind { kind == #kind
#kind => true,
_ => false,
}
} }
fn cast(syntax: SyntaxNode) -> Option<Self> { fn cast(syntax: SyntaxNode) -> Option<Self> {
if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
@ -214,48 +260,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
quote!(impl ast::#trait_name for #name {}) quote!(impl ast::#trait_name for #name {})
}); });
let element_kinds = &element_kinds_map[&en.name.to_string()];
assert!(
element_kinds.has_nodes ^ element_kinds.has_tokens,
"{}: {:#?}",
name,
element_kinds
);
let specific_ast_trait = {
let (ast_trait, syntax_type) = if element_kinds.has_tokens {
(quote!(AstToken), quote!(SyntaxToken))
} else {
(quote!(AstNode), quote!(SyntaxNode))
};
quote! {
impl #ast_trait for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: #syntax_type) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &#syntax_type {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
}
};
quote! { quote! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name { pub enum #name {
@ -270,15 +274,47 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
)* )*
impl AstNode for #name {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#(#kinds)|* => true,
_ => false,
}
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
#(
#kinds => #name::#variants(#variants { syntax }),
)*
_ => return None,
};
Some(res)
}
fn syntax(&self) -> &SyntaxNode {
match self {
#(
#name::#variants(it) => &it.syntax,
)*
}
}
}
#(#traits)*
}
});
let displays = grammar
.enums
.iter()
.map(|it| format_ident!("{}", it.name))
.chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name)))
.map(|name| {
quote! {
impl std::fmt::Display for #name { impl std::fmt::Display for #name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f) std::fmt::Display::fmt(self.syntax(), f)
} }
} }
#specific_ast_trait
#(#traits)*
} }
}); });
@ -294,15 +330,16 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
} }
let ast = quote! { let ast = quote! {
#[allow(unused_imports)]
use crate::{ use crate::{
SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *}, SyntaxNode, SyntaxKind::{self, *},
ast::{self, AstNode, AstToken, AstChildren, support}, ast::{self, AstNode, AstChildren, support},
}; };
#(#tokens)* use super::tokens::*;
#(#nodes)* #(#nodes)*
#(#enums)* #(#enums)*
#(#displays)*
}; };
let pretty = crate::reformat(ast)?; let pretty = crate::reformat(ast)?;

View file

@ -67,6 +67,7 @@ fn reformat(text: impl std::fmt::Display) -> Result<String> {
let mut rustfmt = Command::new("rustup") let mut rustfmt = Command::new("rustup")
.args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"]) .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
.arg(project_root().join("rustfmt.toml")) .arg(project_root().join("rustfmt.toml"))
.args(&["--config", "fn_single_line=true"])
.stdin(Stdio::piped()) .stdin(Stdio::piped())
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()?;