Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'xtask/src/codegen/grammar.rs')
-rw-r--r--xtask/src/codegen/grammar.rs71
1 files changed, 45 insertions, 26 deletions
diff --git a/xtask/src/codegen/grammar.rs b/xtask/src/codegen/grammar.rs
index 45fa2d37c8..0352539754 100644
--- a/xtask/src/codegen/grammar.rs
+++ b/xtask/src/codegen/grammar.rs
@@ -17,15 +17,22 @@ use quote::{format_ident, quote};
use ungrammar::{Grammar, Rule};
use crate::{
- codegen::{add_preamble, ensure_file_contents, reformat},
+ codegen::{add_preamble, ensure_file_contents, grammar::ast_src::generate_kind_src, reformat},
project_root,
};
mod ast_src;
-use self::ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC};
+use self::ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc};
pub(crate) fn generate(check: bool) {
- let syntax_kinds = generate_syntax_kinds(KINDS_SRC);
+ let grammar = fs::read_to_string(project_root().join("crates/syntax/rust.ungram"))
+ .unwrap()
+ .parse()
+ .unwrap();
+ let ast = lower(&grammar);
+ let kinds_src = generate_kind_src(&ast.nodes, &ast.enums, &grammar);
+
+ let syntax_kinds = generate_syntax_kinds(kinds_src);
let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
ensure_file_contents(
crate::flags::CodegenType::Grammar,
@@ -34,12 +41,6 @@ pub(crate) fn generate(check: bool) {
check,
);
- let grammar = fs::read_to_string(project_root().join("crates/syntax/rust.ungram"))
- .unwrap()
- .parse()
- .unwrap();
- let ast = lower(&grammar);
-
let ast_tokens = generate_tokens(&ast);
let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
ensure_file_contents(
@@ -49,7 +50,7 @@ pub(crate) fn generate(check: bool) {
check,
);
- let ast_nodes = generate_nodes(KINDS_SRC, &ast);
+ let ast_nodes = generate_nodes(kinds_src, &ast);
let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
ensure_file_contents(
crate::flags::CodegenType::Grammar,
@@ -96,7 +97,7 @@ fn generate_tokens(grammar: &AstSrc) -> String {
.replace("#[derive", "\n#[derive")
}
-fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
+fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String {
let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
.nodes
.iter()
@@ -117,7 +118,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
});
let methods = node.fields.iter().map(|field| {
- let method_name = field.method_name();
+ let method_name = format_ident!("{}", field.method_name());
let ty = field.ty();
if field.is_many() {
@@ -260,7 +261,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
.iter()
.map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
.collect();
-
+ let nodes = nodes.iter().map(|node| format_ident!("{}", node.name));
(
quote! {
#[pretty_doc_comment_placeholder_workaround]
@@ -293,6 +294,15 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
&self.syntax
}
}
+
+ #(
+ impl From<#nodes> for #name {
+ #[inline]
+ fn from(node: #nodes) -> #name {
+ #name { syntax: node.syntax }
+ }
+ }
+ )*
},
)
})
@@ -366,7 +376,7 @@ fn write_doc_comment(contents: &[String], dest: &mut String) {
}
}
-fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
+fn generate_syntax_kinds(grammar: KindsSrc) -> String {
let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
.punct
.iter()
@@ -481,7 +491,9 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
#([#punctuation_values] => { $crate::SyntaxKind::#punctuation };)*
#([#all_keywords_idents] => { $crate::SyntaxKind::#all_keywords };)*
[lifetime_ident] => { $crate::SyntaxKind::LIFETIME_IDENT };
+ [int_number] => { $crate::SyntaxKind::INT_NUMBER };
[ident] => { $crate::SyntaxKind::IDENT };
+ [string] => { $crate::SyntaxKind::STRING };
[shebang] => { $crate::SyntaxKind::SHEBANG };
}
};
@@ -550,7 +562,7 @@ impl Field {
_ => None,
}
}
- fn method_name(&self) -> proc_macro2::Ident {
+ fn method_name(&self) -> String {
match self {
Field::Token(name) => {
let name = match name.as_str() {
@@ -585,13 +597,13 @@ impl Field {
"~" => "tilde",
_ => name,
};
- format_ident!("{}_token", name)
+ format!("{name}_token",)
}
Field::Node { name, .. } => {
if name == "type" {
- format_ident!("ty")
+ String::from("ty")
} else {
- format_ident!("{}", name)
+ name.to_owned()
}
}
}
@@ -604,6 +616,15 @@ impl Field {
}
}
+fn clean_token_name(name: &str) -> String {
+ let cleaned = name.trim_start_matches(['@', '#', '?']);
+ if cleaned.is_empty() {
+ name.to_owned()
+ } else {
+ cleaned.to_owned()
+ }
+}
+
fn lower(grammar: &Grammar) -> AstSrc {
let mut res = AstSrc {
tokens:
@@ -683,14 +704,12 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
}
Rule::Token(token) => {
assert!(label.is_none());
- let mut name = grammar[*token].name.clone();
- if name != "int_number" && name != "string" {
- if "[]{}()".contains(&name) {
- name = format!("'{name}'");
- }
- let field = Field::Token(name);
- acc.push(field);
+ let mut name = clean_token_name(&grammar[*token].name);
+ if "[]{}()".contains(&name) {
+ name = format!("'{name}'");
}
+ let field = Field::Token(name);
+ acc.push(field);
}
Rule::Rep(inner) => {
if let Rule::Node(node) = &**inner {
@@ -863,7 +882,7 @@ fn extract_struct_traits(ast: &mut AstSrc) {
fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str]) {
let mut to_remove = Vec::new();
for (i, field) in node.fields.iter().enumerate() {
- let method_name = field.method_name().to_string();
+ let method_name = field.method_name();
if methods.iter().any(|&it| it == method_name) {
to_remove.push(i);
}