aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen/gen_syntax.rs
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/codegen/gen_syntax.rs')
-rw-r--r--xtask/src/codegen/gen_syntax.rs265
1 files changed, 151 insertions, 114 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 6dae93aa2..6657c9fc5 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,10 +3,13 @@
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::{
7 borrow::Cow,
8 collections::{BTreeSet, HashSet},
9};
10
6use proc_macro2::{Punct, Spacing}; 11use proc_macro2::{Punct, Spacing};
7use quote::{format_ident, quote}; 12use quote::{format_ident, quote};
8use std::borrow::Cow;
9use std::collections::{BTreeSet, HashMap, HashSet};
10 13
11use crate::{ 14use crate::{
12 ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC}, 15 ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC},
@@ -19,9 +22,13 @@ pub fn generate_syntax(mode: Mode) -> Result<()> {
19 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 22 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
20 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 23 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
21 24
22 let ast_file = project_root().join(codegen::AST); 25 let ast_nodes_file = project_root().join(codegen::AST_NODES);
23 let ast = generate_ast(KINDS_SRC, AST_SRC)?; 26 let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
24 update(ast_file.as_path(), &ast, mode)?; 27 update(ast_nodes_file.as_path(), &contents, mode)?;
28
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)?;
25 32
26 Ok(()) 33 Ok(())
27} 34}
@@ -33,7 +40,7 @@ struct ElementKinds {
33 has_tokens: bool, 40 has_tokens: bool,
34} 41}
35 42
36fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 43fn generate_tokens(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
37 let all_token_kinds: Vec<_> = kinds 44 let all_token_kinds: Vec<_> = kinds
38 .punct 45 .punct
39 .into_iter() 46 .into_iter()
@@ -51,46 +58,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
51 .chain(kinds.tokens.into_iter().copied().map(|x| x.into())) 58 .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
52 .collect(); 59 .collect();
53 60
54 let mut element_kinds_map = HashMap::new();
55 for kind in &all_token_kinds {
56 let kind = &**kind;
57 let name = to_pascal_case(kind);
58 element_kinds_map.insert(
59 name,
60 ElementKinds {
61 kinds: Some(format_ident!("{}", kind)).into_iter().collect(),
62 has_nodes: false,
63 has_tokens: true,
64 },
65 );
66 }
67
68 for kind in kinds.nodes {
69 let name = to_pascal_case(kind);
70 element_kinds_map.insert(
71 name,
72 ElementKinds {
73 kinds: Some(format_ident!("{}", *kind)).into_iter().collect(),
74 has_nodes: true,
75 has_tokens: false,
76 },
77 );
78 }
79
80 for en in grammar.enums {
81 let mut element_kinds: ElementKinds = Default::default();
82 for variant in en.variants {
83 if let Some(variant_element_kinds) = element_kinds_map.get(*variant) {
84 element_kinds.kinds.extend(variant_element_kinds.kinds.iter().cloned());
85 element_kinds.has_tokens |= variant_element_kinds.has_tokens;
86 element_kinds.has_nodes |= variant_element_kinds.has_nodes;
87 } else {
88 panic!("Enum variant has type that does not exist or was not declared before the enum: {}", *variant);
89 }
90 }
91 element_kinds_map.insert(en.name.to_string(), element_kinds);
92 }
93
94 let tokens = all_token_kinds.iter().map(|kind_str| { 61 let tokens = all_token_kinds.iter().map(|kind_str| {
95 let kind_str = &**kind_str; 62 let kind_str = &**kind_str;
96 let kind = format_ident!("{}", kind_str); 63 let kind = format_ident!("{}", kind_str);
@@ -108,12 +75,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
108 } 75 }
109 76
110 impl AstToken for #name { 77 impl AstToken for #name {
111 fn can_cast(kind: SyntaxKind) -> bool { 78 fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
112 match kind {
113 #kind => true,
114 _ => false,
115 }
116 }
117 fn cast(syntax: SyntaxToken) -> Option<Self> { 79 fn cast(syntax: SyntaxToken) -> Option<Self> {
118 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } 80 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
119 } 81 }
@@ -122,6 +84,99 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
122 } 84 }
123 }); 85 });
124 86
87 let enums = grammar.token_enums.iter().map(|en| {
88 let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>();
89 let name = format_ident!("{}", en.name);
90 let kinds = variants
91 .iter()
92 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
93 .collect::<Vec<_>>();
94 assert!(en.traits.is_empty());
95
96 quote! {
97 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
98 pub enum #name {
99 #(#variants(#variants),)*
100 }
101
102 #(
103 impl From<#variants> for #name {
104 fn from(node: #variants) -> #name {
105 #name::#variants(node)
106 }
107 }
108 )*
109
110 impl std::fmt::Display for #name {
111 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112 std::fmt::Display::fmt(self.syntax(), f)
113 }
114 }
115
116 impl AstToken for #name {
117 fn can_cast(kind: SyntaxKind) -> bool {
118 match kind {
119 #(#kinds)|* => true,
120 _ => false,
121 }
122 }
123 fn cast(syntax: SyntaxToken) -> Option<Self> {
124 let res = match syntax.kind() {
125 #(
126 #kinds => #name::#variants(#variants { syntax }),
127 )*
128 _ => return None,
129 };
130 Some(res)
131 }
132 fn syntax(&self) -> &SyntaxToken {
133 match self {
134 #(
135 #name::#variants(it) => &it.syntax,
136 )*
137 }
138 }
139 }
140 }
141 });
142
143 crate::reformat(quote! {
144 use crate::{SyntaxToken, SyntaxKind::{self, *}, ast::AstToken};
145
146 #(#tokens)*
147 #(#enums)*
148 })
149}
150
151fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
152 let all_token_kinds: Vec<_> = kinds
153 .punct
154 .into_iter()
155 .map(|(_, kind)| kind)
156 .copied()
157 .map(|x| x.into())
158 .chain(
159 kinds
160 .keywords
161 .into_iter()
162 .chain(kinds.contextual_keywords.into_iter())
163 .map(|name| Cow::Owned(format!("{}_KW", to_upper_snake_case(&name)))),
164 )
165 .chain(kinds.literals.into_iter().copied().map(|x| x.into()))
166 .chain(kinds.tokens.into_iter().copied().map(|x| x.into()))
167 .collect();
168
169 let mut token_kinds = HashSet::new();
170 for kind in &all_token_kinds {
171 let kind = &**kind;
172 let name = to_pascal_case(kind);
173 token_kinds.insert(name);
174 }
175
176 for en in grammar.token_enums {
177 token_kinds.insert(en.name.to_string());
178 }
179
125 let nodes = grammar.nodes.iter().map(|node| { 180 let nodes = grammar.nodes.iter().map(|node| {
126 let name = format_ident!("{}", node.name); 181 let name = format_ident!("{}", node.name);
127 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); 182 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
@@ -151,7 +206,7 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
151 } 206 }
152 } 207 }
153 FieldSrc::Optional(_) | FieldSrc::Shorthand => { 208 FieldSrc::Optional(_) | FieldSrc::Shorthand => {
154 let is_token = element_kinds_map[&ty.to_string()].has_tokens; 209 let is_token = token_kinds.contains(&ty.to_string());
155 if is_token { 210 if is_token {
156 quote! { 211 quote! {
157 pub fn #method_name(&self) -> Option<#ty> { 212 pub fn #method_name(&self) -> Option<#ty> {
@@ -175,18 +230,9 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
175 pub(crate) syntax: SyntaxNode, 230 pub(crate) syntax: SyntaxNode,
176 } 231 }
177 232
178 impl std::fmt::Display for #name {
179 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
180 std::fmt::Display::fmt(self.syntax(), f)
181 }
182 }
183
184 impl AstNode for #name { 233 impl AstNode for #name {
185 fn can_cast(kind: SyntaxKind) -> bool { 234 fn can_cast(kind: SyntaxKind) -> bool {
186 match kind { 235 kind == #kind
187 #kind => true,
188 _ => false,
189 }
190 } 236 }
191 fn cast(syntax: SyntaxNode) -> Option<Self> { 237 fn cast(syntax: SyntaxNode) -> Option<Self> {
192 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } 238 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
@@ -214,48 +260,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
214 quote!(impl ast::#trait_name for #name {}) 260 quote!(impl ast::#trait_name for #name {})
215 }); 261 });
216 262
217 let element_kinds = &element_kinds_map[&en.name.to_string()];
218 assert!(
219 element_kinds.has_nodes ^ element_kinds.has_tokens,
220 "{}: {:#?}",
221 name,
222 element_kinds
223 );
224 let specific_ast_trait = {
225 let (ast_trait, syntax_type) = if element_kinds.has_tokens {
226 (quote!(AstToken), quote!(SyntaxToken))
227 } else {
228 (quote!(AstNode), quote!(SyntaxNode))
229 };
230
231 quote! {
232 impl #ast_trait for #name {
233 fn can_cast(kind: SyntaxKind) -> bool {
234 match kind {
235 #(#kinds)|* => true,
236 _ => false,
237 }
238 }
239 fn cast(syntax: #syntax_type) -> Option<Self> {
240 let res = match syntax.kind() {
241 #(
242 #kinds => #name::#variants(#variants { syntax }),
243 )*
244 _ => return None,
245 };
246 Some(res)
247 }
248 fn syntax(&self) -> &#syntax_type {
249 match self {
250 #(
251 #name::#variants(it) => &it.syntax,
252 )*
253 }
254 }
255 }
256 }
257 };
258
259 quote! { 263 quote! {
260 #[derive(Debug, Clone, PartialEq, Eq, Hash)] 264 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
261 pub enum #name { 265 pub enum #name {
@@ -270,18 +274,50 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
270 } 274 }
271 )* 275 )*
272 276
273 impl std::fmt::Display for #name { 277 impl AstNode for #name {
274 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 278 fn can_cast(kind: SyntaxKind) -> bool {
275 std::fmt::Display::fmt(self.syntax(), f) 279 match kind {
280 #(#kinds)|* => true,
281 _ => false,
282 }
283 }
284 fn cast(syntax: SyntaxNode) -> Option<Self> {
285 let res = match syntax.kind() {
286 #(
287 #kinds => #name::#variants(#variants { syntax }),
288 )*
289 _ => return None,
290 };
291 Some(res)
292 }
293 fn syntax(&self) -> &SyntaxNode {
294 match self {
295 #(
296 #name::#variants(it) => &it.syntax,
297 )*
298 }
276 } 299 }
277 } 300 }
278 301
279 #specific_ast_trait
280
281 #(#traits)* 302 #(#traits)*
282 } 303 }
283 }); 304 });
284 305
306 let displays = grammar
307 .enums
308 .iter()
309 .map(|it| format_ident!("{}", it.name))
310 .chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name)))
311 .map(|name| {
312 quote! {
313 impl std::fmt::Display for #name {
314 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
315 std::fmt::Display::fmt(self.syntax(), f)
316 }
317 }
318 }
319 });
320
285 let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect(); 321 let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect();
286 322
287 for node in kinds 323 for node in kinds
@@ -294,15 +330,16 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
294 } 330 }
295 331
296 let ast = quote! { 332 let ast = quote! {
297 #[allow(unused_imports)]
298 use crate::{ 333 use crate::{
299 SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *}, 334 SyntaxNode, SyntaxKind::{self, *},
300 ast::{self, AstNode, AstToken, AstChildren, support}, 335 ast::{self, AstNode, AstChildren, support},
301 }; 336 };
302 337
303 #(#tokens)* 338 use super::tokens::*;
339
304 #(#nodes)* 340 #(#nodes)*
305 #(#enums)* 341 #(#enums)*
342 #(#displays)*
306 }; 343 };
307 344
308 let pretty = crate::reformat(ast)?; 345 let pretty = crate::reformat(ast)?;