diff options
Diffstat (limited to 'xtask/src')
-rw-r--r-- | xtask/src/codegen.rs | 12 | ||||
-rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 250 | ||||
-rw-r--r-- | xtask/src/install.rs | 2 |
3 files changed, 137 insertions, 127 deletions
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs index 678b40133..0e4dcb95a 100644 --- a/xtask/src/codegen.rs +++ b/xtask/src/codegen.rs | |||
@@ -9,9 +9,9 @@ mod gen_syntax; | |||
9 | mod gen_parser_tests; | 9 | mod gen_parser_tests; |
10 | mod gen_assists_docs; | 10 | mod gen_assists_docs; |
11 | 11 | ||
12 | use std::{fs, mem, path::Path}; | 12 | use std::{mem, path::Path}; |
13 | 13 | ||
14 | use crate::Result; | 14 | use crate::{not_bash::fs2, Result}; |
15 | 15 | ||
16 | pub use self::{ | 16 | pub use self::{ |
17 | gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, | 17 | gen_assists_docs::generate_assists_docs, gen_parser_tests::generate_parser_tests, |
@@ -39,7 +39,7 @@ pub enum Mode { | |||
39 | /// A helper to update file on disk if it has changed. | 39 | /// A helper to update file on disk if it has changed. |
40 | /// With verify = false, | 40 | /// With verify = false, |
41 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | 41 | fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { |
42 | match fs::read_to_string(path) { | 42 | match fs2::read_to_string(path) { |
43 | Ok(ref old_contents) if normalize(old_contents) == normalize(contents) => { | 43 | Ok(ref old_contents) if normalize(old_contents) == normalize(contents) => { |
44 | return Ok(()); | 44 | return Ok(()); |
45 | } | 45 | } |
@@ -49,7 +49,7 @@ fn update(path: &Path, contents: &str, mode: Mode) -> Result<()> { | |||
49 | anyhow::bail!("`{}` is not up-to-date", path.display()); | 49 | anyhow::bail!("`{}` is not up-to-date", path.display()); |
50 | } | 50 | } |
51 | eprintln!("updating {}", path.display()); | 51 | eprintln!("updating {}", path.display()); |
52 | fs::write(path, contents)?; | 52 | fs2::write(path, contents)?; |
53 | return Ok(()); | 53 | return Ok(()); |
54 | 54 | ||
55 | fn normalize(s: &str) -> String { | 55 | fn normalize(s: &str) -> String { |
@@ -65,7 +65,7 @@ fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> { | |||
65 | do_extract_comment_blocks(text, true) | 65 | do_extract_comment_blocks(text, true) |
66 | } | 66 | } |
67 | 67 | ||
68 | fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> Vec<Vec<String>> { | 68 | fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) -> Vec<Vec<String>> { |
69 | let mut res = Vec::new(); | 69 | let mut res = Vec::new(); |
70 | 70 | ||
71 | let prefix = "// "; | 71 | let prefix = "// "; |
@@ -73,7 +73,7 @@ fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> | |||
73 | 73 | ||
74 | let mut block = vec![]; | 74 | let mut block = vec![]; |
75 | for line in lines { | 75 | for line in lines { |
76 | if line == "//" && allow_blocks_with_empty_lins { | 76 | if line == "//" && allow_blocks_with_empty_lines { |
77 | block.push(String::new()); | 77 | block.push(String::new()); |
78 | continue; | 78 | continue; |
79 | } | 79 | } |
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index ec1f6ad8a..e9dc09552 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
@@ -63,126 +63,138 @@ fn generate_tokens(grammar: AstSrc<'_>) -> Result<String> { | |||
63 | } | 63 | } |
64 | 64 | ||
65 | fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | 65 | fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { |
66 | let nodes = grammar.nodes.iter().map(|node| { | 66 | let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar |
67 | let name = format_ident!("{}", node.name); | 67 | .nodes |
68 | let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); | 68 | .iter() |
69 | let traits = node.traits.iter().map(|trait_name| { | 69 | .map(|node| { |
70 | let trait_name = format_ident!("{}", trait_name); | 70 | let name = format_ident!("{}", node.name); |
71 | quote!(impl ast::#trait_name for #name {}) | 71 | let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); |
72 | }); | 72 | let traits = node.traits.iter().map(|trait_name| { |
73 | 73 | let trait_name = format_ident!("{}", trait_name); | |
74 | let methods = node.fields.iter().map(|field| { | 74 | quote!(impl ast::#trait_name for #name {}) |
75 | let method_name = field.method_name(); | 75 | }); |
76 | let ty = field.ty(); | 76 | |
77 | 77 | let methods = node.fields.iter().map(|field| { | |
78 | if field.is_many() { | 78 | let method_name = field.method_name(); |
79 | quote! { | 79 | let ty = field.ty(); |
80 | pub fn #method_name(&self) -> AstChildren<#ty> { | 80 | |
81 | support::children(&self.syntax) | 81 | if field.is_many() { |
82 | } | ||
83 | } | ||
84 | } else { | ||
85 | if let Some(token_kind) = field.token_kind() { | ||
86 | quote! { | 82 | quote! { |
87 | pub fn #method_name(&self) -> Option<#ty> { | 83 | pub fn #method_name(&self) -> AstChildren<#ty> { |
88 | support::token(&self.syntax, #token_kind) | 84 | support::children(&self.syntax) |
89 | } | 85 | } |
90 | } | 86 | } |
91 | } else { | 87 | } else { |
92 | quote! { | 88 | if let Some(token_kind) = field.token_kind() { |
93 | pub fn #method_name(&self) -> Option<#ty> { | 89 | quote! { |
94 | support::child(&self.syntax) | 90 | pub fn #method_name(&self) -> Option<#ty> { |
91 | support::token(&self.syntax, #token_kind) | ||
92 | } | ||
93 | } | ||
94 | } else { | ||
95 | quote! { | ||
96 | pub fn #method_name(&self) -> Option<#ty> { | ||
97 | support::child(&self.syntax) | ||
98 | } | ||
95 | } | 99 | } |
96 | } | 100 | } |
97 | } | 101 | } |
98 | } | 102 | }); |
99 | }); | 103 | ( |
100 | 104 | quote! { | |
101 | quote! { | 105 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
102 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 106 | pub struct #name { |
103 | pub struct #name { | 107 | pub(crate) syntax: SyntaxNode, |
104 | pub(crate) syntax: SyntaxNode, | 108 | } |
105 | } | ||
106 | |||
107 | impl AstNode for #name { | ||
108 | fn can_cast(kind: SyntaxKind) -> bool { | ||
109 | kind == #kind | ||
110 | } | ||
111 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
112 | if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } | ||
113 | } | ||
114 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
115 | } | ||
116 | |||
117 | #(#traits)* | ||
118 | |||
119 | impl #name { | ||
120 | #(#methods)* | ||
121 | } | ||
122 | } | ||
123 | }); | ||
124 | 109 | ||
125 | let enums = grammar.enums.iter().map(|en| { | 110 | #(#traits)* |
126 | let variants = en.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>(); | ||
127 | let name = format_ident!("{}", en.name); | ||
128 | let kinds = variants | ||
129 | .iter() | ||
130 | .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string()))) | ||
131 | .collect::<Vec<_>>(); | ||
132 | let traits = en.traits.iter().map(|trait_name| { | ||
133 | let trait_name = format_ident!("{}", trait_name); | ||
134 | quote!(impl ast::#trait_name for #name {}) | ||
135 | }); | ||
136 | 111 | ||
137 | quote! { | 112 | impl #name { |
138 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 113 | #(#methods)* |
139 | pub enum #name { | 114 | } |
140 | #(#variants(#variants),)* | 115 | }, |
141 | } | 116 | quote! { |
117 | impl AstNode for #name { | ||
118 | fn can_cast(kind: SyntaxKind) -> bool { | ||
119 | kind == #kind | ||
120 | } | ||
121 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
122 | if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } | ||
123 | } | ||
124 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
125 | } | ||
126 | }, | ||
127 | ) | ||
128 | }) | ||
129 | .unzip(); | ||
142 | 130 | ||
143 | #( | 131 | let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar |
144 | impl From<#variants> for #name { | 132 | .enums |
145 | fn from(node: #variants) -> #name { | 133 | .iter() |
146 | #name::#variants(node) | 134 | .map(|en| { |
147 | } | 135 | let variants: Vec<_> = en.variants.iter().map(|var| format_ident!("{}", var)).collect(); |
148 | } | 136 | let name = format_ident!("{}", en.name); |
149 | )* | 137 | let kinds: Vec<_> = variants |
138 | .iter() | ||
139 | .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string()))) | ||
140 | .collect(); | ||
141 | let traits = en.traits.iter().map(|trait_name| { | ||
142 | let trait_name = format_ident!("{}", trait_name); | ||
143 | quote!(impl ast::#trait_name for #name {}) | ||
144 | }); | ||
145 | |||
146 | ( | ||
147 | quote! { | ||
148 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
149 | pub enum #name { | ||
150 | #(#variants(#variants),)* | ||
151 | } | ||
150 | 152 | ||
151 | impl AstNode for #name { | 153 | #(#traits)* |
152 | fn can_cast(kind: SyntaxKind) -> bool { | 154 | }, |
153 | match kind { | 155 | quote! { |
154 | #(#kinds)|* => true, | 156 | #( |
155 | _ => false, | 157 | impl From<#variants> for #name { |
158 | fn from(node: #variants) -> #name { | ||
159 | #name::#variants(node) | ||
160 | } | ||
156 | } | 161 | } |
157 | } | 162 | )* |
158 | fn cast(syntax: SyntaxNode) -> Option<Self> { | 163 | |
159 | let res = match syntax.kind() { | 164 | impl AstNode for #name { |
160 | #( | 165 | fn can_cast(kind: SyntaxKind) -> bool { |
161 | #kinds => #name::#variants(#variants { syntax }), | 166 | match kind { |
162 | )* | 167 | #(#kinds)|* => true, |
163 | _ => return None, | 168 | _ => false, |
164 | }; | 169 | } |
165 | Some(res) | 170 | } |
166 | } | 171 | fn cast(syntax: SyntaxNode) -> Option<Self> { |
167 | fn syntax(&self) -> &SyntaxNode { | 172 | let res = match syntax.kind() { |
168 | match self { | 173 | #( |
169 | #( | 174 | #kinds => #name::#variants(#variants { syntax }), |
170 | #name::#variants(it) => &it.syntax, | 175 | )* |
171 | )* | 176 | _ => return None, |
177 | }; | ||
178 | Some(res) | ||
179 | } | ||
180 | fn syntax(&self) -> &SyntaxNode { | ||
181 | match self { | ||
182 | #( | ||
183 | #name::#variants(it) => &it.syntax, | ||
184 | )* | ||
185 | } | ||
186 | } | ||
172 | } | 187 | } |
173 | } | 188 | }, |
174 | } | 189 | ) |
190 | }) | ||
191 | .unzip(); | ||
175 | 192 | ||
176 | #(#traits)* | 193 | let enum_names = grammar.enums.iter().map(|it| it.name); |
177 | } | 194 | let node_names = grammar.nodes.iter().map(|it| it.name); |
178 | }); | ||
179 | 195 | ||
180 | let displays = grammar | 196 | let display_impls = |
181 | .enums | 197 | enum_names.chain(node_names.clone()).map(|it| format_ident!("{}", it)).map(|name| { |
182 | .iter() | ||
183 | .map(|it| format_ident!("{}", it.name)) | ||
184 | .chain(grammar.nodes.iter().map(|it| format_ident!("{}", it.name))) | ||
185 | .map(|name| { | ||
186 | quote! { | 198 | quote! { |
187 | impl std::fmt::Display for #name { | 199 | impl std::fmt::Display for #name { |
188 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | 200 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { |
@@ -192,13 +204,13 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
192 | } | 204 | } |
193 | }); | 205 | }); |
194 | 206 | ||
195 | let defined_nodes: HashSet<_> = grammar.nodes.iter().map(|node| node.name).collect(); | 207 | let defined_nodes: HashSet<_> = node_names.collect(); |
196 | 208 | ||
197 | for node in kinds | 209 | for node in kinds |
198 | .nodes | 210 | .nodes |
199 | .iter() | 211 | .iter() |
200 | .map(|kind| to_pascal_case(*kind)) | 212 | .map(|kind| to_pascal_case(kind)) |
201 | .filter(|name| !defined_nodes.contains(&**name)) | 213 | .filter(|name| !defined_nodes.contains(name.as_str())) |
202 | { | 214 | { |
203 | eprintln!("Warning: node {} not defined in ast source", node); | 215 | eprintln!("Warning: node {} not defined in ast source", node); |
204 | } | 216 | } |
@@ -210,9 +222,11 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { | |||
210 | T, | 222 | T, |
211 | }; | 223 | }; |
212 | 224 | ||
213 | #(#nodes)* | 225 | #(#node_defs)* |
214 | #(#enums)* | 226 | #(#enum_defs)* |
215 | #(#displays)* | 227 | #(#node_boilerplate_impls)* |
228 | #(#enum_boilerplate_impls)* | ||
229 | #(#display_impls)* | ||
216 | }; | 230 | }; |
217 | 231 | ||
218 | let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])"); | 232 | let ast = ast.to_string().replace("T ! [ ", "T![").replace(" ] )", "])"); |
@@ -380,20 +394,16 @@ fn to_pascal_case(s: &str) -> String { | |||
380 | 394 | ||
381 | impl Field<'_> { | 395 | impl Field<'_> { |
382 | fn is_many(&self) -> bool { | 396 | fn is_many(&self) -> bool { |
383 | match self { | 397 | matches!(self, Field::Node { src: FieldSrc::Many(_), .. }) |
384 | Field::Node { src: FieldSrc::Many(_), .. } => true, | ||
385 | _ => false, | ||
386 | } | ||
387 | } | 398 | } |
388 | fn token_kind(&self) -> Option<proc_macro2::TokenStream> { | 399 | fn token_kind(&self) -> Option<proc_macro2::TokenStream> { |
389 | let res = match self { | 400 | match self { |
390 | Field::Token(token) => { | 401 | Field::Token(token) => { |
391 | let token: proc_macro2::TokenStream = token.parse().unwrap(); | 402 | let token: proc_macro2::TokenStream = token.parse().unwrap(); |
392 | quote! { T![#token] } | 403 | Some(quote! { T![#token] }) |
393 | } | 404 | } |
394 | _ => return None, | 405 | _ => None, |
395 | }; | 406 | } |
396 | Some(res) | ||
397 | } | 407 | } |
398 | fn method_name(&self) -> proc_macro2::Ident { | 408 | fn method_name(&self) -> proc_macro2::Ident { |
399 | match self { | 409 | match self { |
diff --git a/xtask/src/install.rs b/xtask/src/install.rs index bc32a04b3..9ba77a3aa 100644 --- a/xtask/src/install.rs +++ b/xtask/src/install.rs | |||
@@ -7,7 +7,7 @@ use anyhow::{bail, format_err, Context, Result}; | |||
7 | use crate::not_bash::{pushd, run}; | 7 | use crate::not_bash::{pushd, run}; |
8 | 8 | ||
9 | // Latest stable, feel free to send a PR if this lags behind. | 9 | // Latest stable, feel free to send a PR if this lags behind. |
10 | const REQUIRED_RUST_VERSION: u32 = 41; | 10 | const REQUIRED_RUST_VERSION: u32 = 43; |
11 | 11 | ||
12 | pub struct InstallCmd { | 12 | pub struct InstallCmd { |
13 | pub client: Option<ClientOpt>, | 13 | pub client: Option<ClientOpt>, |