aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_syntax.rs182
1 files changed, 19 insertions, 163 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 4c9e447a3..ce18f2b8f 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,10 +3,7 @@
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
6use std::{ 6use std::collections::{BTreeSet, HashSet};
7 borrow::Cow,
8 collections::{BTreeSet, HashSet},
9};
10 7
11use proc_macro2::{Punct, Spacing}; 8use proc_macro2::{Punct, Spacing};
12use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
@@ -26,10 +23,6 @@ pub fn generate_syntax(mode: Mode) -> Result<()> {
26 let contents = generate_nodes(KINDS_SRC, AST_SRC)?; 23 let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
27 update(ast_nodes_file.as_path(), &contents, mode)?; 24 update(ast_nodes_file.as_path(), &contents, mode)?;
28 25
29 let ast_tokens_file = project_root().join(codegen::AST_TOKENS);
30 let contents = generate_tokens(KINDS_SRC, AST_SRC)?;
31 update(ast_tokens_file.as_path(), &contents, mode)?;
32
33 Ok(()) 26 Ok(())
34} 27}
35 28
@@ -40,147 +33,7 @@ struct ElementKinds {
40 has_tokens: bool, 33 has_tokens: bool,
41} 34}
42 35
43fn generate_tokens(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
44 let all_token_kinds: Vec<_> = kinds
45 .punct
46 .into_iter()
47 .map(|(_, kind)| kind)
48 .copied()
49 .map(|x| x.into())
50 .chain(
51 kinds
52 .keywords
53 .into_iter()
54 .chain(kinds.contextual_keywords.into_iter())
55 .map(|name| Cow::Owned(format!("{}_KW", to_upper_snake_case(&name)))),
56 )
57 .chain(kinds.literals.into_iter().copied().map(|x| x.into()))
58 .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
59 .collect();
60
61 let tokens = all_token_kinds.iter().filter_map(|kind_str| {
62 if kind_str.ends_with("_KW") {
63 return None;
64 }
65 let kind_str = &**kind_str;
66 let kind = format_ident!("{}", kind_str);
67 let name = format_ident!("{}", to_pascal_case(kind_str));
68 let res = quote! {
69 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
70 pub struct #name {
71 pub(crate) syntax: SyntaxToken,
72 }
73
74 impl std::fmt::Display for #name {
75 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76 std::fmt::Display::fmt(&self.syntax, f)
77 }
78 }
79
80 impl AstToken for #name {
81 fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
82 fn cast(syntax: SyntaxToken) -> Option<Self> {
83 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
84 }
85 fn syntax(&self) -> &SyntaxToken { &self.syntax }
86 }
87 };
88 Some(res)
89 });
90
91 let enums = grammar.token_enums.iter().map(|en| {
92 let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>();
93 let name = format_ident!("{}", en.name);
94 let kinds = variants
95 .iter()
96 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
97 .collect::<Vec<_>>();
98 assert!(en.traits.is_empty());
99
100 quote! {
101 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
102 pub enum #name {
103 #(#variants(#variants),)*
104 }
105
106 #(
107 impl From<#variants> for #name {
108 fn from(node: #variants) -> #name {
109 #name::#variants(node)
110 }
111 }
112 )*
113
114 impl std::fmt::Display for #name {
115 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
116 std::fmt::Display::fmt(self.syntax(), f)
117 }
118 }
119
120 impl AstToken for #name {
121 fn can_cast(kind: SyntaxKind) -> bool {
122 match kind {
123 #(#kinds)|* => true,
124 _ => false,
125 }
126 }
127 fn cast(syntax: SyntaxToken) -> Option<Self> {
128 let res = match syntax.kind() {
129 #(
130 #kinds => #name::#variants(#variants { syntax }),
131 )*
132 _ => return None,
133 };
134 Some(res)
135 }
136 fn syntax(&self) -> &SyntaxToken {
137 match self {
138 #(
139 #name::#variants(it) => &it.syntax,
140 )*
141 }
142 }
143 }
144 }
145 });
146
147 crate::reformat(quote! {
148 use crate::{SyntaxToken, SyntaxKind::{self, *}, ast::AstToken};
149
150 #(#tokens)*
151 #(#enums)*
152 })
153}
154
155fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 36fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
156 let all_token_kinds: Vec<_> = kinds
157 .punct
158 .into_iter()
159 .map(|(_, kind)| kind)
160 .copied()
161 .map(|x| x.into())
162 .chain(
163 kinds
164 .keywords
165 .into_iter()
166 .chain(kinds.contextual_keywords.into_iter())
167 .map(|name| Cow::Owned(format!("{}_KW", to_upper_snake_case(&name)))),
168 )
169 .chain(kinds.literals.into_iter().copied().map(|x| x.into()))
170 .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
171 .collect();
172
173 let mut token_kinds = HashSet::new();
174 for kind in &all_token_kinds {
175 let kind = &**kind;
176 let name = to_pascal_case(kind);
177 token_kinds.insert(name);
178 }
179
180 for en in grammar.token_enums {
181 token_kinds.insert(en.name.to_string());
182 }
183
184 let nodes = grammar.nodes.iter().map(|node| { 37 let nodes = grammar.nodes.iter().map(|node| {
185 let name = format_ident!("{}", node.name); 38 let name = format_ident!("{}", node.name);
186 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); 39 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
@@ -207,19 +60,9 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
207 } 60 }
208 } 61 }
209 } else { 62 } else {
210 let is_token = token_kinds.contains(&ty.to_string()); 63 quote! {
211 if is_token { 64 pub fn #method_name(&self) -> Option<#ty> {
212 let method_name = format_ident!("{}_token", method_name); 65 support::child(&self.syntax)
213 quote! {
214 pub fn #method_name(&self) -> Option<#ty> {
215 support::token(&self.syntax)
216 }
217 }
218 } else {
219 quote! {
220 pub fn #method_name(&self) -> Option<#ty> {
221 support::child(&self.syntax)
222 }
223 } 66 }
224 } 67 }
225 } 68 }
@@ -338,8 +181,6 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
338 T, 181 T,
339 }; 182 };
340 183
341 use super::tokens::*;
342
343 #(#nodes)* 184 #(#nodes)*
344 #(#enums)* 185 #(#enums)*
345 #(#displays)* 186 #(#displays)*
@@ -456,6 +297,8 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
456 macro_rules! T { 297 macro_rules! T {
457 #((#punctuation_values) => { $crate::SyntaxKind::#punctuation };)* 298 #((#punctuation_values) => { $crate::SyntaxKind::#punctuation };)*
458 #((#all_keywords_idents) => { $crate::SyntaxKind::#all_keywords };)* 299 #((#all_keywords_idents) => { $crate::SyntaxKind::#all_keywords };)*
300 (lifetime) => { $crate::SyntaxKind::LIFETIME };
301 (ident) => { $crate::SyntaxKind::IDENT };
459 } 302 }
460 }; 303 };
461 304
@@ -535,8 +378,21 @@ impl Field<'_> {
535 "')'" => "r_paren", 378 "')'" => "r_paren",
536 "'['" => "l_brack", 379 "'['" => "l_brack",
537 "']'" => "r_brack", 380 "']'" => "r_brack",
381 "<" => "l_angle",
382 ">" => "r_angle",
538 "=" => "eq", 383 "=" => "eq",
539 "!" => "excl", 384 "!" => "excl",
385 "*" => "star",
386 "&" => "amp",
387 "_" => "underscore",
388 "." => "dot",
389 ".." => "dotdot",
390 "..." => "dotdotdot",
391 "=>" => "fat_arrow",
392 "@" => "at",
393 ":" => "colon",
394 "::" => "coloncolon",
395 "#" => "pound",
540 _ => name, 396 _ => name,
541 }; 397 };
542 format_ident!("{}_token", name) 398 format_ident!("{}_token", name)