aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-09 17:37:34 +0100
committerBenjamin Coenen <[email protected]>2020-04-09 18:12:50 +0100
commitc1317d692321ba5ba8f138067ebefbb9559d098d (patch)
treee29a44577e4d2cf55b6f53e3428abea43bbd33d7 /xtask/src/codegen
parentfc70cf9458c5234decafdd52b9aced790ac43d7a (diff)
parent30f0ad159a0f260f54356385de63c171722adb72 (diff)
feat: add support for feature attributes in struct literal
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_syntax.rs218
1 files changed, 142 insertions, 76 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 2dfb68371..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()));
@@ -146,14 +201,23 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
146 FieldSrc::Many(_) => { 201 FieldSrc::Many(_) => {
147 quote! { 202 quote! {
148 pub fn #method_name(&self) -> AstChildren<#ty> { 203 pub fn #method_name(&self) -> AstChildren<#ty> {
149 AstChildren::new(&self.syntax) 204 support::children(&self.syntax)
150 } 205 }
151 } 206 }
152 } 207 }
153 FieldSrc::Optional(_) | FieldSrc::Shorthand => { 208 FieldSrc::Optional(_) | FieldSrc::Shorthand => {
154 quote! { 209 let is_token = token_kinds.contains(&ty.to_string());
155 pub fn #method_name(&self) -> Option<#ty> { 210 if is_token {
156 AstChildren::new(&self.syntax).next() 211 quote! {
212 pub fn #method_name(&self) -> Option<#ty> {
213 support::token(&self.syntax)
214 }
215 }
216 } else {
217 quote! {
218 pub fn #method_name(&self) -> Option<#ty> {
219 support::child(&self.syntax)
220 }
157 } 221 }
158 } 222 }
159 } 223 }
@@ -166,18 +230,9 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
166 pub(crate) syntax: SyntaxNode, 230 pub(crate) syntax: SyntaxNode,
167 } 231 }
168 232
169 impl std::fmt::Display for #name {
170 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
171 std::fmt::Display::fmt(self.syntax(), f)
172 }
173 }
174
175 impl AstNode for #name { 233 impl AstNode for #name {
176 fn can_cast(kind: SyntaxKind) -> bool { 234 fn can_cast(kind: SyntaxKind) -> bool {
177 match kind { 235 kind == #kind
178 #kind => true,
179 _ => false,
180 }
181 } 236 }
182 fn cast(syntax: SyntaxNode) -> Option<Self> { 237 fn cast(syntax: SyntaxNode) -> Option<Self> {
183 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } 238 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
@@ -219,12 +274,6 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
219 } 274 }
220 )* 275 )*
221 276
222 impl std::fmt::Display for #name {
223 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
224 std::fmt::Display::fmt(self.syntax(), f)
225 }
226 }
227
228 impl AstNode for #name { 277 impl AstNode for #name {
229 fn can_cast(kind: SyntaxKind) -> bool { 278 fn can_cast(kind: SyntaxKind) -> bool {
230 match kind { 279 match kind {
@@ -249,10 +298,26 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
249 } 298 }
250 } 299 }
251 } 300 }
301
252 #(#traits)* 302 #(#traits)*
253 } 303 }
254 }); 304 });
255 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
256 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();
257 322
258 for node in kinds 323 for node in kinds
@@ -265,15 +330,16 @@ fn generate_ast(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> {
265 } 330 }
266 331
267 let ast = quote! { 332 let ast = quote! {
268 #[allow(unused_imports)]
269 use crate::{ 333 use crate::{
270 SyntaxNode, SyntaxToken, SyntaxElement, NodeOrToken, SyntaxKind::{self, *}, 334 SyntaxNode, SyntaxKind::{self, *},
271 ast::{self, AstNode, AstToken, AstChildren}, 335 ast::{self, AstNode, AstChildren, support},
272 }; 336 };
273 337
274 #(#tokens)* 338 use super::tokens::*;
339
275 #(#nodes)* 340 #(#nodes)*
276 #(#enums)* 341 #(#enums)*
342 #(#displays)*
277 }; 343 };
278 344
279 let pretty = crate::reformat(ast)?; 345 let pretty = crate::reformat(ast)?;