aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/codegen
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-01-03 19:37:02 +0000
committerAleksey Kladov <[email protected]>2020-01-03 20:54:10 +0000
commit084bd304f304e674fc3d5b132daf8a9f975064c9 (patch)
tree1715adcc8ef9cb9bc48e73e6708f9452854c947f /xtask/src/codegen
parent67922a029a42e11a76711f9a2c71ca542973042c (diff)
Switch ast declaration from ron to a macro
Diffstat (limited to 'xtask/src/codegen')
-rw-r--r--xtask/src/codegen/gen_syntax.rs234
1 files changed, 98 insertions, 136 deletions
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 88f2ac0e3..0f50ca569 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -3,149 +3,142 @@
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::{collections::BTreeMap, fs};
7
8use proc_macro2::{Punct, Spacing}; 6use proc_macro2::{Punct, Spacing};
9use quote::{format_ident, quote}; 7use quote::{format_ident, quote};
10use ron;
11use serde::Deserialize;
12 8
13use crate::{ 9use crate::{
10 ast_src::{AstSrc, FieldSrc, KindsSrc, AST_SRC, KINDS_SRC},
14 codegen::{self, update, Mode}, 11 codegen::{self, update, Mode},
15 project_root, Result, 12 project_root, Result,
16}; 13};
17 14
18pub fn generate_syntax(mode: Mode) -> Result<()> { 15pub fn generate_syntax(mode: Mode) -> Result<()> {
19 let grammar = project_root().join(codegen::GRAMMAR);
20 let grammar: Grammar = {
21 let text = fs::read_to_string(grammar)?;
22 ron::de::from_str(&text)?
23 };
24
25 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS); 16 let syntax_kinds_file = project_root().join(codegen::SYNTAX_KINDS);
26 let syntax_kinds = generate_syntax_kinds(&grammar)?; 17 let syntax_kinds = generate_syntax_kinds(KINDS_SRC)?;
27 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?; 18 update(syntax_kinds_file.as_path(), &syntax_kinds, mode)?;
28 19
29 let ast_file = project_root().join(codegen::AST); 20 let ast_file = project_root().join(codegen::AST);
30 let ast = generate_ast(&grammar)?; 21 let ast = generate_ast(AST_SRC)?;
31 update(ast_file.as_path(), &ast, mode)?; 22 update(ast_file.as_path(), &ast, mode)?;
32 23
33 Ok(()) 24 Ok(())
34} 25}
35 26
36fn generate_ast(grammar: &Grammar) -> Result<String> { 27fn generate_ast(grammar: AstSrc<'_>) -> Result<String> {
37 let nodes = grammar.ast.iter().map(|(name, ast_node)| { 28 let nodes = grammar.nodes.iter().map(|node| {
38 let variants = 29 let name = format_ident!("{}", node.name);
39 ast_node.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>(); 30 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string()));
40 let name = format_ident!("{}", name); 31 let traits = node.traits.iter().map(|trait_name| {
41 32 let trait_name = format_ident!("{}", trait_name);
42 let adt = if variants.is_empty() { 33 quote!(impl ast::#trait_name for #name {})
43 let kind = format_ident!("{}", to_upper_snake_case(&name.to_string())); 34 });
44 quote! {
45 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
46 pub struct #name {
47 pub(crate) syntax: SyntaxNode,
48 }
49 35
50 impl AstNode for #name { 36 let methods = node.fields.iter().map(|(name, field)| {
51 fn can_cast(kind: SyntaxKind) -> bool { 37 let method_name = match field {
52 match kind { 38 FieldSrc::Shorthand => format_ident!("{}", to_lower_snake_case(&name)),
53 #kind => true, 39 _ => format_ident!("{}", name),
54 _ => false, 40 };
41 let ty = match field {
42 FieldSrc::Optional(ty) | FieldSrc::Many(ty) => ty,
43 FieldSrc::Shorthand => name,
44 };
45 let ty = format_ident!("{}", ty);
46
47 match field {
48 FieldSrc::Many(_) => {
49 quote! {
50 pub fn #method_name(&self) -> AstChildren<#ty> {
51 AstChildren::new(&self.syntax)
55 } 52 }
56 } 53 }
57 fn cast(syntax: SyntaxNode) -> Option<Self> { 54 }
58 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } 55 FieldSrc::Optional(_) | FieldSrc::Shorthand => {
56 quote! {
57 pub fn #method_name(&self) -> Option<#ty> {
58 AstChildren::new(&self.syntax).next()
59 }
59 } 60 }
60 fn syntax(&self) -> &SyntaxNode { &self.syntax }
61 } 61 }
62 } 62 }
63 } else { 63 });
64 let kinds = variants
65 .iter()
66 .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
67 .collect::<Vec<_>>();
68
69 quote! {
70 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
71 pub enum #name {
72 #(#variants(#variants),)*
73 }
74 64
75 #( 65 quote! {
76 impl From<#variants> for #name { 66 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
77 fn from(node: #variants) -> #name { 67 pub struct #name {
78 #name::#variants(node) 68 pub(crate) syntax: SyntaxNode,
79 } 69 }
80 }
81 )*
82 70
83 impl AstNode for #name { 71 impl AstNode for #name {
84 fn can_cast(kind: SyntaxKind) -> bool { 72 fn can_cast(kind: SyntaxKind) -> bool {
85 match kind { 73 match kind {
86 #(#kinds)|* => true, 74 #kind => true,
87 _ => false, 75 _ => false,
88 }
89 }
90 fn cast(syntax: SyntaxNode) -> Option<Self> {
91 let res = match syntax.kind() {
92 #(
93 #kinds => #name::#variants(#variants { syntax }),
94 )*
95 _ => return None,
96 };
97 Some(res)
98 }
99 fn syntax(&self) -> &SyntaxNode {
100 match self {
101 #(
102 #name::#variants(it) => &it.syntax,
103 )*
104 }
105 } 76 }
106 } 77 }
78 fn cast(syntax: SyntaxNode) -> Option<Self> {
79 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
80 }
81 fn syntax(&self) -> &SyntaxNode { &self.syntax }
107 } 82 }
108 }; 83 #(#traits)*
84
85 impl #name {
86 #(#methods)*
87 }
88 }
89 });
109 90
110 let traits = ast_node.traits.iter().map(|trait_name| { 91 let enums = grammar.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 let traits = en.traits.iter().map(|trait_name| {
111 let trait_name = format_ident!("{}", trait_name); 99 let trait_name = format_ident!("{}", trait_name);
112 quote!(impl ast::#trait_name for #name {}) 100 quote!(impl ast::#trait_name for #name {})
113 }); 101 });
114 102
115 let collections = ast_node.collections.iter().map(|(name, kind)| { 103 quote! {
116 let method_name = format_ident!("{}", name); 104 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
117 let kind = format_ident!("{}", kind); 105 pub enum #name {
118 quote! { 106 #(#variants(#variants),)*
119 pub fn #method_name(&self) -> AstChildren<#kind> {
120 AstChildren::new(&self.syntax)
121 }
122 } 107 }
123 });
124 108
125 let options = ast_node.options.iter().map(|attr| { 109 #(
126 let method_name = match attr { 110 impl From<#variants> for #name {
127 Attr::Type(t) => format_ident!("{}", to_lower_snake_case(&t)), 111 fn from(node: #variants) -> #name {
128 Attr::NameType(n, _) => format_ident!("{}", n), 112 #name::#variants(node)
129 };
130 let ty = match attr {
131 Attr::Type(t) | Attr::NameType(_, t) => format_ident!("{}", t),
132 };
133 quote! {
134 pub fn #method_name(&self) -> Option<#ty> {
135 AstChildren::new(&self.syntax).next()
136 } 113 }
137 } 114 }
138 }); 115 )*
139
140 quote! {
141 #adt
142
143 #(#traits)*
144 116
145 impl #name { 117 impl AstNode for #name {
146 #(#collections)* 118 fn can_cast(kind: SyntaxKind) -> bool {
147 #(#options)* 119 match kind {
120 #(#kinds)|* => true,
121 _ => false,
122 }
123 }
124 fn cast(syntax: SyntaxNode) -> Option<Self> {
125 let res = match syntax.kind() {
126 #(
127 #kinds => #name::#variants(#variants { syntax }),
128 )*
129 _ => return None,
130 };
131 Some(res)
132 }
133 fn syntax(&self) -> &SyntaxNode {
134 match self {
135 #(
136 #name::#variants(it) => &it.syntax,
137 )*
138 }
139 }
148 } 140 }
141 #(#traits)*
149 } 142 }
150 }); 143 });
151 144
@@ -156,13 +149,14 @@ fn generate_ast(grammar: &Grammar) -> Result<String> {
156 }; 149 };
157 150
158 #(#nodes)* 151 #(#nodes)*
152 #(#enums)*
159 }; 153 };
160 154
161 let pretty = codegen::reformat(ast)?; 155 let pretty = codegen::reformat(ast)?;
162 Ok(pretty) 156 Ok(pretty)
163} 157}
164 158
165fn generate_syntax_kinds(grammar: &Grammar) -> Result<String> { 159fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> Result<String> {
166 let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar 160 let (single_byte_tokens_values, single_byte_tokens): (Vec<_>, Vec<_>) = grammar
167 .punct 161 .punct
168 .iter() 162 .iter()
@@ -274,38 +268,6 @@ fn generate_syntax_kinds(grammar: &Grammar) -> Result<String> {
274 codegen::reformat(ast) 268 codegen::reformat(ast)
275} 269}
276 270
277#[derive(Deserialize, Debug)]
278struct Grammar {
279 punct: Vec<(String, String)>,
280 keywords: Vec<String>,
281 contextual_keywords: Vec<String>,
282 literals: Vec<String>,
283 tokens: Vec<String>,
284 nodes: Vec<String>,
285 ast: BTreeMap<String, AstNode>,
286}
287
288#[derive(Deserialize, Debug)]
289struct AstNode {
290 #[serde(default)]
291 #[serde(rename = "enum")]
292 variants: Vec<String>,
293
294 #[serde(default)]
295 traits: Vec<String>,
296 #[serde(default)]
297 collections: Vec<(String, String)>,
298 #[serde(default)]
299 options: Vec<Attr>,
300}
301
302#[derive(Deserialize, Debug)]
303#[serde(untagged)]
304enum Attr {
305 Type(String),
306 NameType(String, String),
307}
308
309fn to_upper_snake_case(s: &str) -> String { 271fn to_upper_snake_case(s: &str) -> String {
310 let mut buf = String::with_capacity(s.len()); 272 let mut buf = String::with_capacity(s.len());
311 let mut prev_is_upper = None; 273 let mut prev_is_upper = None;