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,
TypeBoundKind, VisibilityKind,
},
generated::*,
generated::{nodes::*, tokens::*},
tokens::*,
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) nodes: &'a [AstNodeSrc<'a>],
pub(crate) enums: &'a [AstEnumSrc<'a>],
pub(crate) token_enums: &'a [AstEnumSrc<'a>],
}
pub(crate) struct AstNodeSrc<'a> {
@ -753,6 +754,13 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
// macro calls are parsed as expression statements */
}
enum FieldDefList {
RecordFieldDefList,
TupleFieldDefList,
}
},
token_enums: &ast_enums! {
enum LeftDelimiter { LParen, LBrack, LCurly }
enum RightDelimiter { RParen, RBrack, RCurly }
enum RangeSeparator { Dotdot, Dotdotdot, Dotdoteq}
@ -817,10 +825,5 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
Ident,
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 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";
pub const AST: &str = "crates/ra_syntax/src/ast/generated.rs";
const SYNTAX_KINDS: &str = "crates/ra_parser/src/syntax_kind/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_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
//! wrappers around `SyntaxNode` which implement `ra_syntax::AstNode`.
use std::{
borrow::Cow,
collections::{BTreeSet, HashSet},
};
use proc_macro2::{Punct, Spacing};
use quote::{format_ident, quote};
use std::borrow::Cow;
use std::collections::{BTreeSet, HashMap, HashSet};
use crate::{
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)?;
update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
let ast_file = project_root().join(codegen::AST);
let ast = generate_ast(KINDS_SRC, AST_SRC)?;
update(ast_file.as_path(), &ast, mode)?;
let ast_nodes_file = project_root().join(codegen::AST_NODES);
let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
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(())
}
@ -33,7 +40,7 @@ struct ElementKinds {
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
.punct
.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()))
.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 kind_str = &**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 {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#kind => true,
_ => false,
}
}
fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
fn cast(syntax: SyntaxToken) -> Option<Self> {
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 name = format_ident!("{}", node.name);
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 => {
let is_token = element_kinds_map[&ty.to_string()].has_tokens;
let is_token = token_kinds.contains(&ty.to_string());
if is_token {
quote! {
pub fn #method_name(&self) -> Option<#ty> {
@ -175,18 +230,9 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
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 {
fn can_cast(kind: SyntaxKind) -> bool {
match kind {
#kind => true,
_ => false,
}
kind == #kind
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
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 {})
});
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! {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum #name {
@ -270,18 +274,50 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
}
)*
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 {
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,
)*
}
}
}
#specific_ast_trait
#(#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 {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
}
}
}
});
let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect();
for node in kinds
@ -294,15 +330,16 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
}
let ast = quote! {
#[allow(unused_imports)]
use crate::{
SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *},
ast::{self, AstNode, AstToken, AstChildren, support},
SyntaxNode, SyntaxKind::{self, *},
ast::{self, AstNode, AstChildren, support},
};
#(#tokens)*
use super::tokens::*;
#(#nodes)*
#(#enums)*
#(#displays)*
};
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")
.args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"])
.arg(project_root().join("rustfmt.toml"))
.args(&["--config", "fn_single_line=true"])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;