aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen/gen_syntax.rs
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-08-24 10:19:53 +0100
committerZac Pullar-Strecker <[email protected]>2020-08-24 10:20:13 +0100
commit7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch)
treebdb47765991cb973b2cd5481a088fac636bd326c /xtask/src/codegen/gen_syntax.rs
parentca464650eeaca6195891199a93f4f76cf3e7e697 (diff)
parente65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'xtask/src/codegen/gen_syntax.rs')
-rw-r--r--xtask/src/codegen/gen_syntax.rs104
1 files changed, 66 insertions, 38 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 45b788bdb..200e8aa50 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -1,7 +1,7 @@
1//! This module generates AST datatype used by rust-analyzer. 1//! This module generates AST datatype used by rust-analyzer.
2//! 2//!
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 `syntax::AstNode`.
5 5
6use std::{ 6use std::{
7 collections::{BTreeSet, HashSet}, 7 collections::{BTreeSet, HashSet},
@@ -10,29 +10,27 @@ use std::{
10 10
11use proc_macro2::{Punct, Spacing}; 11use proc_macro2::{Punct, Spacing};
12use quote::{format_ident, quote}; 12use quote::{format_ident, quote};
13use ungrammar::{Grammar, Rule}; 13use ungrammar::{rust_grammar, Grammar, Rule};
14 14
15use crate::{ 15use crate::{
16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC}, 16 ast_src::{AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC},
17 codegen::{self, update, Mode}, 17 codegen::{reformat, update, Mode},
18 project_root, Result, 18 project_root, Result,
19}; 19};
20 20
21pub fn generate_syntax(mode: Mode) -> Result<()> { 21pub fn generate_syntax(mode: Mode) -> Result<()> {
22 let grammar = include_str!("rust.ungram") 22 let grammar = rust_grammar();
23 .parse::<Grammar>()
24 .unwrap_or_else(|err| panic!("\n \x1b[91merror\x1b[0m: {}\n", err));
25 let ast = lower(&grammar); 23 let ast = lower(&grammar);
26 24
27 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); 25 let syntax_kinds_file = project_root().join("crates/parser/src/syntax_kind/generated.rs");
28 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 26 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
29 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 27 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
30 28
31 let ast_tokens_file = project_root().join(codegen::AST_TOKENS); 29 let ast_tokens_file = project_root().join("crates/syntax/src/ast/generated/tokens.rs");
32 let contents = generate_tokens(&ast)?; 30 let contents = generate_tokens(&ast)?;
33 update(ast_tokens_file.as_path(), &contents, mode)?; 31 update(ast_tokens_file.as_path(), &contents, mode)?;
34 32
35 let ast_nodes_file = project_root().join(codegen::AST_NODES); 33 let ast_nodes_file = project_root().join("crates/syntax/src/ast/generated/nodes.rs");
36 let contents = generate_nodes(KINDS_SRC, &ast)?; 34 let contents = generate_nodes(KINDS_SRC, &ast)?;
37 update(ast_nodes_file.as_path(), &contents, mode)?; 35 update(ast_nodes_file.as_path(), &contents, mode)?;
38 36
@@ -63,7 +61,7 @@ fn generate_tokens(grammar: &AstSrc) -> Result<String> {
63 } 61 }
64 }); 62 });
65 63
66 let pretty = crate::reformat(quote! { 64 let pretty = reformat(quote! {
67 use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken}; 65 use crate::{SyntaxKind::{self, *}, SyntaxToken, ast::AstToken};
68 #(#tokens)* 66 #(#tokens)*
69 })? 67 })?
@@ -153,25 +151,10 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
153 quote!(impl ast::#trait_name for #name {}) 151 quote!(impl ast::#trait_name for #name {})
154 }); 152 });
155 153
156 ( 154 let ast_node = if en.name == "Stmt" {
155 quote! {}
156 } else {
157 quote! { 157 quote! {
158 #[pretty_doc_comment_placeholder_workaround]
159 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
160 pub enum #name {
161 #(#variants(#variants),)*
162 }
163
164 #(#traits)*
165 },
166 quote! {
167 #(
168 impl From<#variants> for #name {
169 fn from(node: #variants) -> #name {
170 #name::#variants(node)
171 }
172 }
173 )*
174
175 impl AstNode for #name { 158 impl AstNode for #name {
176 fn can_cast(kind: SyntaxKind) -> bool { 159 fn can_cast(kind: SyntaxKind) -> bool {
177 match kind { 160 match kind {
@@ -196,6 +179,28 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
196 } 179 }
197 } 180 }
198 } 181 }
182 }
183 };
184
185 (
186 quote! {
187 #[pretty_doc_comment_placeholder_workaround]
188 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
189 pub enum #name {
190 #(#variants(#variants),)*
191 }
192
193 #(#traits)*
194 },
195 quote! {
196 #(
197 impl From<#variants> for #name {
198 fn from(node: #variants) -> #name {
199 #name::#variants(node)
200 }
201 }
202 )*
203 #ast_node
199 }, 204 },
200 ) 205 )
201 }) 206 })
@@ -256,7 +261,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> Result<String> {
256 } 261 }
257 } 262 }
258 263
259 let pretty = crate::reformat(res)?; 264 let pretty = reformat(res)?;
260 Ok(pretty) 265 Ok(pretty)
261} 266}
262 267
@@ -378,7 +383,7 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
378 } 383 }
379 }; 384 };
380 385
381 crate::reformat(ast) 386 reformat(ast)
382} 387}
383 388
384fn to_upper_snake_case(s: &str) -> String { 389fn to_upper_snake_case(s: &str) -> String {
@@ -472,11 +477,18 @@ impl Field {
472 "#" => "pound", 477 "#" => "pound",
473 "?" => "question_mark", 478 "?" => "question_mark",
474 "," => "comma", 479 "," => "comma",
480 "|" => "pipe",
475 _ => name, 481 _ => name,
476 }; 482 };
477 format_ident!("{}_token", name) 483 format_ident!("{}_token", name)
478 } 484 }
479 Field::Node { name, .. } => format_ident!("{}", name), 485 Field::Node { name, .. } => {
486 if name == "type" {
487 format_ident!("ty")
488 } else {
489 format_ident!("{}", name)
490 }
491 }
480 } 492 }
481 } 493 }
482 fn ty(&self) -> proc_macro2::Ident { 494 fn ty(&self) -> proc_macro2::Ident {
@@ -491,13 +503,7 @@ fn lower(grammar: &Grammar) -> AstSrc {
491 let mut res = AstSrc::default(); 503 let mut res = AstSrc::default();
492 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()]; 504 res.tokens = vec!["Whitespace".into(), "Comment".into(), "String".into(), "RawString".into()];
493 505
494 let nodes = grammar 506 let nodes = grammar.iter().collect::<Vec<_>>();
495 .iter()
496 .filter(|&node| match grammar[node].rule {
497 Rule::Node(it) if it == node => false,
498 _ => true,
499 })
500 .collect::<Vec<_>>();
501 507
502 for &node in &nodes { 508 for &node in &nodes {
503 let name = grammar[node].name.clone(); 509 let name = grammar[node].name.clone();
@@ -531,6 +537,7 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
531 for alternative in alternatives { 537 for alternative in alternatives {
532 match alternative { 538 match alternative {
533 Rule::Node(it) => variants.push(grammar[*it].name.clone()), 539 Rule::Node(it) => variants.push(grammar[*it].name.clone()),
540 Rule::Token(it) if grammar[*it].name == ";" => (),
534 _ => return None, 541 _ => return None,
535 } 542 }
536 } 543 }
@@ -572,6 +579,24 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
572 } 579 }
573 Rule::Labeled { label: l, rule } => { 580 Rule::Labeled { label: l, rule } => {
574 assert!(label.is_none()); 581 assert!(label.is_none());
582 let manually_implemented = matches!(
583 l.as_str(),
584 "lhs"
585 | "rhs"
586 | "then_branch"
587 | "else_branch"
588 | "start"
589 | "end"
590 | "op"
591 | "index"
592 | "base"
593 | "value"
594 | "trait"
595 | "self_ty"
596 );
597 if manually_implemented {
598 return;
599 }
575 lower_rule(acc, grammar, Some(l), rule); 600 lower_rule(acc, grammar, Some(l), rule);
576 } 601 }
577 Rule::Seq(rules) | Rule::Alt(rules) => { 602 Rule::Seq(rules) | Rule::Alt(rules) => {
@@ -687,6 +712,9 @@ fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str
687 712
688fn extract_enum_traits(ast: &mut AstSrc) { 713fn extract_enum_traits(ast: &mut AstSrc) {
689 for enm in &mut ast.enums { 714 for enm in &mut ast.enums {
715 if enm.name == "Stmt" {
716 continue;
717 }
690 let nodes = &ast.nodes; 718 let nodes = &ast.nodes;
691 let mut variant_traits = enm 719 let mut variant_traits = enm
692 .variants 720 .variants