aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
authorveetaha <[email protected]>2020-04-18 21:51:13 +0100
committerveetaha <[email protected]>2020-04-18 21:51:13 +0100
commit972d3b2ba30ec40bebe85452117e669536faa167 (patch)
treef1e2763392c045324f1963e355378de4acf9eb57 /xtask/src/codegen
parentb949500126f6bd3723d22541adb2f7c8aae206a4 (diff)
Group generated ast boilerplate apart from the interesting part
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_syntax.rs250
1 files changed, 130 insertions, 120 deletions
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
65fn generate_nodes(kinds: KindsSrc<'_>, grammar: AstSrc<'_>) -> Result<String> { 65fn 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
381impl Field<'_> { 395impl 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 {