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.rs257
1 files changed, 226 insertions, 31 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 32afd47bc..b5594e3a9 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,6 +3,11 @@
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};
8 13
@@ -17,14 +22,161 @@ pub fn generate_syntax(mode: Mode) -> Result<()> {
17 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?; 22 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
18 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 23 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
19 24
20 let ast_file = project_root().join(codegen::AST); 25 let ast_nodes_file = project_root().join(codegen::AST_NODES);
21 let ast = generate_ast(AST_SRC)?; 26 let contents = generate_nodes(KINDS_SRC, AST_SRC)?;
22 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)?;
23 32
24 Ok(()) 33 Ok(())
25} 34}
26 35
27fn generate_ast(grammar: AstSrc<'_>) -> Result<String> { 36#[derive(Debug, Default, Clone)]
37struct ElementKinds {
38 kinds: BTreeSet<proc_macro2::Ident>,
39 has_nodes: bool,
40 has_tokens: bool,
41}
42
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().map(|kind_str| {
62 let kind_str = &**kind_str;
63 let kind = format_ident!("{}", kind_str);
64 let name = format_ident!("{}", to_pascal_case(kind_str));
65 quote! {
66 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
67 pub struct #name {
68 pub(crate) syntax: SyntaxToken,
69 }
70
71 impl std::fmt::Display for #name {
72 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
73 std::fmt::Display::fmt(&self.syntax, f)
74 }
75 }
76
77 impl AstToken for #name {
78 fn can_cast(kind: SyntaxKind) -> bool { kind == #kind }
79 fn cast(syntax: SyntaxToken) -> Option<Self> {
80 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
81 }
82 fn syntax(&self) -> &SyntaxToken { &self.syntax }
83 }
84 }
85 });
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
28 let nodes = grammar.nodes.iter().map(|node| { 180 let nodes = grammar.nodes.iter().map(|node| {
29 let name = format_ident!("{}", node.name); 181 let name = format_ident!("{}", node.name);
30 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); 182 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
@@ -42,20 +194,31 @@ fn generate_ast(grammar: AstSrc<'_>) -> Result<String> {
42 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => ty, 194 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => ty,
43 FieldSrc::Shorthand => name, 195 FieldSrc::Shorthand => name,
44 }; 196 };
197
45 let ty = format_ident!("{}", ty); 198 let ty = format_ident!("{}", ty);
46 199
47 match field { 200 match field {
48 FieldSrc::Many(_) => { 201 FieldSrc::Many(_) => {
49 quote! { 202 quote! {
50 pub fn #method_name(&self) -> AstChildren<#ty> { 203 pub fn #method_name(&self) -> AstChildren<#ty> {
51 AstChildren::new(&self.syntax) 204 support::children(&self.syntax)
52 } 205 }
53 } 206 }
54 } 207 }
55 FieldSrc::Optional(_) | FieldSrc::Shorthand => { 208 FieldSrc::Optional(_) | FieldSrc::Shorthand => {
56 quote! { 209 let is_token = token_kinds.contains(&ty.to_string());
57 pub fn #method_name(&self) -> Option<#ty> { 210 if is_token {
58 AstChildren::new(&self.syntax).next() 211 let method_name = format_ident!("{}_token", method_name);
212 quote! {
213 pub fn #method_name(&self) -> Option<#ty> {
214 support::token(&self.syntax)
215 }
216 }
217 } else {
218 quote! {
219 pub fn #method_name(&self) -> Option<#ty> {
220 support::child(&self.syntax)
221 }
59 } 222 }
60 } 223 }
61 } 224 }
@@ -68,24 +231,16 @@ fn generate_ast(grammar: AstSrc<'_>) -> Result<String> {
68 pub(crate) syntax: SyntaxNode, 231 pub(crate) syntax: SyntaxNode,
69 } 232 }
70 233
71 impl std::fmt::Display for #name {
72 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
73 std::fmt::Display::fmt(self.syntax(), f)
74 }
75 }
76
77 impl AstNode for #name { 234 impl AstNode for #name {
78 fn can_cast(kind: SyntaxKind) -> bool { 235 fn can_cast(kind: SyntaxKind) -> bool {
79 match kind { 236 kind == #kind
80 #kind => true,
81 _ => false,
82 }
83 } 237 }
84 fn cast(syntax: SyntaxNode) -> Option<Self> { 238 fn cast(syntax: SyntaxNode) -> Option<Self> {
85 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } 239 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
86 } 240 }
87 fn syntax(&self) -> &SyntaxNode { &self.syntax } 241 fn syntax(&self) -> &SyntaxNode { &self.syntax }
88 } 242 }
243
89 #(#traits)* 244 #(#traits)*
90 245
91 impl #name { 246 impl #name {
@@ -120,12 +275,6 @@ fn generate_ast(grammar: AstSrc<'_>) -> Result<String> {
120 } 275 }
121 )* 276 )*
122 277
123 impl std::fmt::Display for #name {
124 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
125 std::fmt::Display::fmt(self.syntax(), f)
126 }
127 }
128
129 impl AstNode for #name { 278 impl AstNode for #name {
130 fn can_cast(kind: SyntaxKind) -> bool { 279 fn can_cast(kind: SyntaxKind) -> bool {
131 match kind { 280 match kind {
@@ -150,18 +299,48 @@ fn generate_ast(grammar: AstSrc<'_>) -> Result<String> {
150 } 299 }
151 } 300 }
152 } 301 }
302
153 #(#traits)* 303 #(#traits)*
154 } 304 }
155 }); 305 });
156 306
307 let displays = grammar
308 .enums
309 .iter()
310 .map(|it| format_ident!("{}", it.name))
311 .chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name)))
312 .map(|name| {
313 quote! {
314 impl std::fmt::Display for #name {
315 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
316 std::fmt::Display::fmt(self.syntax(), f)
317 }
318 }
319 }
320 });
321
322 let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect();
323
324 for node in kinds
325 .nodes
326 .iter()
327 .map(|kind| to_pascal_case(*kind))
328 .filter(|name| !defined_nodes.contains(&**name))
329 {
330 eprintln!("Warning: node {} not defined in ast source", node);
331 }
332
157 let ast = quote! { 333 let ast = quote! {
158 use crate::{ 334 use crate::{
159 SyntaxNode, SyntaxKind::{self, *}, 335 SyntaxNode, SyntaxKind::{self, *},
160 ast::{self, AstNode, AstChildren}, 336 ast::{self, AstNode, AstChildren, support},
161 }; 337 };
162 338
339 use super::tokens::*;
340
163 #(#nodes)* 341 #(#nodes)*
164 #(#enums)* 342 #(#enums)*
343 #(#displays)*
165 }; 344 };
166 345
167 let pretty = crate::reformat(ast)?; 346 let pretty = crate::reformat(ast)?;
@@ -282,12 +461,12 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
282 461
283fn to_upper_snake_case(s: &str) -> String { 462fn to_upper_snake_case(s: &str) -> String {
284 let mut buf = String::with_capacity(s.len()); 463 let mut buf = String::with_capacity(s.len());
285 let mut prev_is_upper = None; 464 let mut prev = false;
286 for c in s.chars() { 465 for c in s.chars() {
287 if c.is_ascii_uppercase() && prev_is_upper == Some(false) { 466 if c.is_ascii_uppercase() && prev {
288 buf.push('_') 467 buf.push('_')
289 } 468 }
290 prev_is_upper = Some(c.is_ascii_uppercase()); 469 prev = true;
291 470
292 buf.push(c.to_ascii_uppercase()); 471 buf.push(c.to_ascii_uppercase());
293 } 472 }
@@ -296,14 +475,30 @@ fn to_upper_snake_case(s: &str) -> String {
296 475
297fn to_lower_snake_case(s: &str) -> String { 476fn to_lower_snake_case(s: &str) -> String {
298 let mut buf = String::with_capacity(s.len()); 477 let mut buf = String::with_capacity(s.len());
299 let mut prev_is_upper = None; 478 let mut prev = false;
300 for c in s.chars() { 479 for c in s.chars() {
301 if c.is_ascii_uppercase() && prev_is_upper == Some(false) { 480 if c.is_ascii_uppercase() && prev {
302 buf.push('_') 481 buf.push('_')
303 } 482 }
304 prev_is_upper = Some(c.is_ascii_uppercase()); 483 prev = true;
305 484
306 buf.push(c.to_ascii_lowercase()); 485 buf.push(c.to_ascii_lowercase());
307 } 486 }
308 buf 487 buf
309} 488}
489
490fn to_pascal_case(s: &str) -> String {
491 let mut buf = String::with_capacity(s.len());
492 let mut prev_is_underscore = true;
493 for c in s.chars() {
494 if c == '_' {
495 prev_is_underscore = true;
496 } else if prev_is_underscore {
497 buf.push(c.to_ascii_uppercase());
498 prev_is_underscore = false;
499 } else {
500 buf.push(c.to_ascii_lowercase());
501 }
502 }
503 buf
504}