diff options
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 182 |
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 | ||
6 | use std::{ | 6 | use std::collections::{BTreeSet, HashSet}; |
7 | borrow::Cow, | ||
8 | collections::{BTreeSet, HashSet}, | ||
9 | }; | ||
10 | 7 | ||
11 | use proc_macro2::{Punct, Spacing}; | 8 | use proc_macro2::{Punct, Spacing}; |
12 | use quote::{format_ident, quote}; | 9 | use 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 | ||
43 | fn 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 | |||
155 | fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | 36 | fn 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) |