diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 54 | ||||
-rw-r--r-- | crates/ra_tools/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_tools/src/codegen.rs | 165 |
3 files changed, 180 insertions, 40 deletions
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index a18810253..26efeeba9 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -263,7 +263,7 @@ Grammar( | |||
263 | "SourceFile": ( | 263 | "SourceFile": ( |
264 | traits: [ "ModuleItemOwner", "FnDefOwner" ], | 264 | traits: [ "ModuleItemOwner", "FnDefOwner" ], |
265 | collections: [ | 265 | collections: [ |
266 | ["modules", "Module"], | 266 | ("modules", "Module"), |
267 | ] | 267 | ] |
268 | ), | 268 | ), |
269 | "FnDef": ( | 269 | "FnDef": ( |
@@ -286,7 +286,7 @@ Grammar( | |||
286 | "DocCommentsOwner" | 286 | "DocCommentsOwner" |
287 | ] | 287 | ] |
288 | ), | 288 | ), |
289 | "NamedFieldDefList": (collections: [["fields", "NamedFieldDef"]]), | 289 | "NamedFieldDefList": (collections: [("fields", "NamedFieldDef")]), |
290 | "NamedFieldDef": ( | 290 | "NamedFieldDef": ( |
291 | traits: [ | 291 | traits: [ |
292 | "VisibilityOwner", | 292 | "VisibilityOwner", |
@@ -296,7 +296,7 @@ Grammar( | |||
296 | "TypeAscriptionOwner" | 296 | "TypeAscriptionOwner" |
297 | ] | 297 | ] |
298 | ), | 298 | ), |
299 | "PosFieldDefList": (collections: [["fields", "PosFieldDef"]]), | 299 | "PosFieldDefList": (collections: [("fields", "PosFieldDef")]), |
300 | "PosFieldDef": ( traits: ["VisibilityOwner", "AttrsOwner"], options: ["TypeRef"]), | 300 | "PosFieldDef": ( traits: ["VisibilityOwner", "AttrsOwner"], options: ["TypeRef"]), |
301 | "EnumDef": ( traits: [ | 301 | "EnumDef": ( traits: [ |
302 | "VisibilityOwner", | 302 | "VisibilityOwner", |
@@ -305,7 +305,7 @@ Grammar( | |||
305 | "AttrsOwner", | 305 | "AttrsOwner", |
306 | "DocCommentsOwner" | 306 | "DocCommentsOwner" |
307 | ], options: [["variant_list", "EnumVariantList"]] ), | 307 | ], options: [["variant_list", "EnumVariantList"]] ), |
308 | "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), | 308 | "EnumVariantList": ( collections: [("variants", "EnumVariant")] ), |
309 | "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), | 309 | "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner", "AttrsOwner"], options: ["Expr"] ), |
310 | "TraitDef": ( | 310 | "TraitDef": ( |
311 | traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner", "TypeBoundsOwner"], | 311 | traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner", "TypeBoundsOwner"], |
@@ -316,7 +316,7 @@ Grammar( | |||
316 | options: [ "ItemList" ] | 316 | options: [ "ItemList" ] |
317 | ), | 317 | ), |
318 | "ItemList": ( | 318 | "ItemList": ( |
319 | collections: [["impl_items", "ImplItem"]], | 319 | collections: [("impl_items", "ImplItem")], |
320 | traits: [ "FnDefOwner", "ModuleItemOwner" ], | 320 | traits: [ "FnDefOwner", "ModuleItemOwner" ], |
321 | ), | 321 | ), |
322 | "ConstDef": ( | 322 | "ConstDef": ( |
@@ -355,7 +355,7 @@ Grammar( | |||
355 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner", "AttrsOwner"]), | 355 | "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner", "AttrsOwner"]), |
356 | 356 | ||
357 | "ParenType": (options: ["TypeRef"]), | 357 | "ParenType": (options: ["TypeRef"]), |
358 | "TupleType": ( collections: [["fields", "TypeRef"]] ), | 358 | "TupleType": ( collections: [("fields", "TypeRef")] ), |
359 | "NeverType": (), | 359 | "NeverType": (), |
360 | "PathType": (options: ["Path"]), | 360 | "PathType": (options: ["Path"]), |
361 | "PointerType": (options: ["TypeRef"]), | 361 | "PointerType": (options: ["TypeRef"]), |
@@ -405,10 +405,10 @@ Grammar( | |||
405 | ), | 405 | ), |
406 | 406 | ||
407 | "TupleExpr": ( | 407 | "TupleExpr": ( |
408 | collections: [["exprs", "Expr"]] | 408 | collections: [("exprs", "Expr")] |
409 | ), | 409 | ), |
410 | "ArrayExpr": ( | 410 | "ArrayExpr": ( |
411 | collections: [["exprs", "Expr"]] | 411 | collections: [("exprs", "Expr")] |
412 | ), | 412 | ), |
413 | "ParenExpr": (options: ["Expr"]), | 413 | "ParenExpr": (options: ["Expr"]), |
414 | "PathExpr": (options: ["Path"]), | 414 | "PathExpr": (options: ["Path"]), |
@@ -449,7 +449,7 @@ Grammar( | |||
449 | options: [ "Expr", "MatchArmList" ], | 449 | options: [ "Expr", "MatchArmList" ], |
450 | ), | 450 | ), |
451 | "MatchArmList": ( | 451 | "MatchArmList": ( |
452 | collections: [ ["arms", "MatchArm"] ], | 452 | collections: [ ("arms", "MatchArm") ], |
453 | traits: [ "AttrsOwner" ] | 453 | traits: [ "AttrsOwner" ] |
454 | ), | 454 | ), |
455 | "MatchArm": ( | 455 | "MatchArm": ( |
@@ -457,13 +457,13 @@ Grammar( | |||
457 | [ "guard", "MatchGuard" ], | 457 | [ "guard", "MatchGuard" ], |
458 | "Expr", | 458 | "Expr", |
459 | ], | 459 | ], |
460 | collections: [ [ "pats", "Pat" ] ], | 460 | collections: [ ("pats", "Pat") ], |
461 | traits: [ "AttrsOwner" ] | 461 | traits: [ "AttrsOwner" ] |
462 | ), | 462 | ), |
463 | "MatchGuard": (options: ["Expr"]), | 463 | "MatchGuard": (options: ["Expr"]), |
464 | "StructLit": (options: ["Path", "NamedFieldList"]), | 464 | "StructLit": (options: ["Path", "NamedFieldList"]), |
465 | "NamedFieldList": ( | 465 | "NamedFieldList": ( |
466 | collections: [ ["fields", "NamedField"] ], | 466 | collections: [ ("fields", "NamedField") ], |
467 | options: [["spread", "Expr"]] | 467 | options: [["spread", "Expr"]] |
468 | ), | 468 | ), |
469 | "NamedField": (options: ["NameRef", "Expr"]), | 469 | "NamedField": (options: ["NameRef", "Expr"]), |
@@ -532,8 +532,8 @@ Grammar( | |||
532 | "StructPat": ( options: ["FieldPatList", "Path"] ), | 532 | "StructPat": ( options: ["FieldPatList", "Path"] ), |
533 | "FieldPatList": ( | 533 | "FieldPatList": ( |
534 | collections: [ | 534 | collections: [ |
535 | ["field_pats", "FieldPat"], | 535 | ("field_pats", "FieldPat"), |
536 | ["bind_pats", "BindPat"], | 536 | ("bind_pats", "BindPat"), |
537 | ] | 537 | ] |
538 | ), | 538 | ), |
539 | "FieldPat": ( | 539 | "FieldPat": ( |
@@ -542,9 +542,9 @@ Grammar( | |||
542 | ), | 542 | ), |
543 | "TupleStructPat": ( | 543 | "TupleStructPat": ( |
544 | options: ["Path"], | 544 | options: ["Path"], |
545 | collections: [["args", "Pat"]], | 545 | collections: [("args", "Pat")], |
546 | ), | 546 | ), |
547 | "TuplePat": ( collections: [["args", "Pat"]] ), | 547 | "TuplePat": ( collections: [("args", "Pat")] ), |
548 | "SlicePat": (), | 548 | "SlicePat": (), |
549 | "RangePat": (), | 549 | "RangePat": (), |
550 | "LiteralPat": (options: ["Literal"]), | 550 | "LiteralPat": (options: ["Literal"]), |
@@ -575,8 +575,8 @@ Grammar( | |||
575 | "TokenTree": (), | 575 | "TokenTree": (), |
576 | "TypeParamList": ( | 576 | "TypeParamList": ( |
577 | collections: [ | 577 | collections: [ |
578 | ["type_params", "TypeParam" ], | 578 | ("type_params", "TypeParam" ), |
579 | ["lifetime_params", "LifetimeParam" ], | 579 | ("lifetime_params", "LifetimeParam" ), |
580 | ] | 580 | ] |
581 | ), | 581 | ), |
582 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner", "DefaultTypeParamOwner"] ), | 582 | "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner", "DefaultTypeParamOwner"] ), |
@@ -590,7 +590,7 @@ Grammar( | |||
590 | ), | 590 | ), |
591 | "TypeBoundList": ( | 591 | "TypeBoundList": ( |
592 | collections: [ | 592 | collections: [ |
593 | ["bounds", "TypeBound"], | 593 | ("bounds", "TypeBound"), |
594 | ] | 594 | ] |
595 | ), | 595 | ), |
596 | "WherePred": ( | 596 | "WherePred": ( |
@@ -603,7 +603,7 @@ Grammar( | |||
603 | ), | 603 | ), |
604 | "WhereClause": ( | 604 | "WhereClause": ( |
605 | collections: [ | 605 | collections: [ |
606 | ["predicates", "WherePred"], | 606 | ("predicates", "WherePred"), |
607 | ], | 607 | ], |
608 | ), | 608 | ), |
609 | "ExprStmt": ( | 609 | "ExprStmt": ( |
@@ -627,7 +627,7 @@ Grammar( | |||
627 | "Block": ( | 627 | "Block": ( |
628 | options: [ "Expr" ], | 628 | options: [ "Expr" ], |
629 | collections: [ | 629 | collections: [ |
630 | ["statements", "Stmt"], | 630 | ("statements", "Stmt"), |
631 | ], | 631 | ], |
632 | traits: [ | 632 | traits: [ |
633 | "AttrsOwner", | 633 | "AttrsOwner", |
@@ -636,7 +636,7 @@ Grammar( | |||
636 | "ParamList": ( | 636 | "ParamList": ( |
637 | options: [ "SelfParam" ], | 637 | options: [ "SelfParam" ], |
638 | collections: [ | 638 | collections: [ |
639 | ["params", "Param"] | 639 | ("params", "Param"), |
640 | ] | 640 | ] |
641 | ), | 641 | ), |
642 | "SelfParam": ( | 642 | "SelfParam": ( |
@@ -663,14 +663,14 @@ Grammar( | |||
663 | traits: ["NameOwner"], | 663 | traits: ["NameOwner"], |
664 | ), | 664 | ), |
665 | "UseTreeList": ( | 665 | "UseTreeList": ( |
666 | collections: [["use_trees", "UseTree"]] | 666 | collections: [("use_trees", "UseTree")] |
667 | ), | 667 | ), |
668 | "ExternCrateItem": ( | 668 | "ExternCrateItem": ( |
669 | options: ["NameRef", "Alias"], | 669 | options: ["NameRef", "Alias"], |
670 | ), | 670 | ), |
671 | "ArgList": ( | 671 | "ArgList": ( |
672 | collections: [ | 672 | collections: [ |
673 | ["args", "Expr"] | 673 | ("args", "Expr"), |
674 | ] | 674 | ] |
675 | ), | 675 | ), |
676 | "Path": ( | 676 | "Path": ( |
@@ -683,9 +683,9 @@ Grammar( | |||
683 | options: [ "NameRef", "TypeArgList" ] | 683 | options: [ "NameRef", "TypeArgList" ] |
684 | ), | 684 | ), |
685 | "TypeArgList": (collections: [ | 685 | "TypeArgList": (collections: [ |
686 | ["type_args", "TypeArg"], | 686 | ("type_args", "TypeArg"), |
687 | ["lifetime_args", "LifetimeArg"], | 687 | ("lifetime_args", "LifetimeArg"), |
688 | ["assoc_type_args", "AssocTypeArg"], | 688 | ("assoc_type_args", "AssocTypeArg"), |
689 | ]), | 689 | ]), |
690 | "TypeArg": (options: ["TypeRef"]), | 690 | "TypeArg": (options: ["TypeRef"]), |
691 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), | 691 | "AssocTypeArg": (options: ["NameRef", "TypeRef"]), |
@@ -698,7 +698,7 @@ Grammar( | |||
698 | "MacroStmts" : ( | 698 | "MacroStmts" : ( |
699 | options: [ "Expr" ], | 699 | options: [ "Expr" ], |
700 | collections: [ | 700 | collections: [ |
701 | ["statements", "Stmt"], | 701 | ("statements", "Stmt"), |
702 | ], | 702 | ], |
703 | ) | 703 | ) |
704 | }, | 704 | }, |
diff --git a/crates/ra_tools/Cargo.toml b/crates/ra_tools/Cargo.toml index ab9fa5d86..1bb6fb71c 100644 --- a/crates/ra_tools/Cargo.toml +++ b/crates/ra_tools/Cargo.toml | |||
@@ -12,4 +12,5 @@ itertools = "0.8.0" | |||
12 | clap = "2.32.0" | 12 | clap = "2.32.0" |
13 | quote = "1.0.2" | 13 | quote = "1.0.2" |
14 | ron = "0.5.1" | 14 | ron = "0.5.1" |
15 | heck = "0.3.0" | ||
15 | serde = { version = "1.0.0", features = ["derive"] } | 16 | serde = { version = "1.0.0", features = ["derive"] } |
diff --git a/crates/ra_tools/src/codegen.rs b/crates/ra_tools/src/codegen.rs index f0a54808a..e14092704 100644 --- a/crates/ra_tools/src/codegen.rs +++ b/crates/ra_tools/src/codegen.rs | |||
@@ -1,27 +1,162 @@ | |||
1 | use std::{collections::BTreeMap, fs, path::Path}; | 1 | use std::{ |
2 | collections::BTreeMap, | ||
3 | fs, | ||
4 | io::Write, | ||
5 | path::Path, | ||
6 | process::{Command, Stdio}, | ||
7 | }; | ||
2 | 8 | ||
3 | use quote::quote; | 9 | use heck::{ShoutySnakeCase, SnakeCase}; |
10 | use quote::{format_ident, quote}; | ||
4 | use ron; | 11 | use ron; |
5 | use serde::Deserialize; | 12 | use serde::Deserialize; |
6 | 13 | ||
7 | use crate::{project_root, Mode, Result, AST, GRAMMAR}; | 14 | use crate::{project_root, Mode, Result, AST, GRAMMAR, SYNTAX_KINDS}; |
8 | 15 | ||
9 | pub fn generate(mode: Mode) -> Result<()> { | 16 | pub fn generate(mode: Mode) -> Result<()> { |
10 | let grammar = project_root().join(GRAMMAR); | 17 | let grammar = project_root().join(GRAMMAR); |
11 | // let syntax_kinds = project_root().join(SYNTAX_KINDS); | 18 | let grammar: Grammar = { |
12 | let ast = project_root().join(AST); | 19 | let text = fs::read_to_string(grammar)?; |
13 | generate_ast(&grammar, &ast, mode) | ||
14 | } | ||
15 | |||
16 | fn generate_ast(grammar_src: &Path, dst: &Path, mode: Mode) -> Result<()> { | ||
17 | let src: Grammar = { | ||
18 | let text = fs::read_to_string(grammar_src)?; | ||
19 | ron::de::from_str(&text)? | 20 | ron::de::from_str(&text)? |
20 | }; | 21 | }; |
21 | eprintln!("{:#?}", src); | 22 | |
23 | let _syntax_kinds = project_root().join(SYNTAX_KINDS); | ||
24 | let _ast = project_root().join(AST); | ||
25 | |||
26 | let ast = generate_ast(&grammar)?; | ||
27 | println!("{}", ast); | ||
22 | Ok(()) | 28 | Ok(()) |
23 | } | 29 | } |
24 | 30 | ||
31 | fn generate_ast(grammar: &Grammar) -> Result<String> { | ||
32 | let nodes = grammar.ast.iter().map(|(name, ast_node)| { | ||
33 | let variants = | ||
34 | ast_node.variants.iter().map(|var| format_ident!("{}", var)).collect::<Vec<_>>(); | ||
35 | let name = format_ident!("{}", name); | ||
36 | |||
37 | let kinds = if variants.is_empty() { vec![name.clone()] } else { variants.clone() } | ||
38 | .into_iter() | ||
39 | .map(|name| format_ident!("{}", name.to_string().to_shouty_snake_case())) | ||
40 | .collect::<Vec<_>>(); | ||
41 | |||
42 | let variants = if variants.is_empty() { | ||
43 | None | ||
44 | } else { | ||
45 | let kind_enum = format_ident!("{}Kind", name); | ||
46 | Some(quote!( | ||
47 | pub enum #kind_enum { | ||
48 | #(#variants(#variants),)* | ||
49 | } | ||
50 | |||
51 | #( | ||
52 | impl From<#variants> for #name { | ||
53 | fn from(node: #variants) -> #name { | ||
54 | #name { syntax: node.syntax } | ||
55 | } | ||
56 | } | ||
57 | )* | ||
58 | |||
59 | impl #name { | ||
60 | pub fn kind(&self) -> #kind_enum { | ||
61 | let syntax = self.syntax.clone(); | ||
62 | match syntax.kind() { | ||
63 | #( | ||
64 | #kinds => | ||
65 | #kind_enum::#variants(#variants { syntax }), | ||
66 | )* | ||
67 | _ => unreachable!(), | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | )) | ||
72 | }; | ||
73 | |||
74 | let traits = ast_node.traits.iter().map(|trait_name| { | ||
75 | let trait_name = format_ident!("{}", trait_name); | ||
76 | quote!(impl ast::#trait_name for #name {}) | ||
77 | }); | ||
78 | |||
79 | let collections = ast_node.collections.iter().map(|(name, kind)| { | ||
80 | let method_name = format_ident!("{}", name); | ||
81 | let kind = format_ident!("{}", kind); | ||
82 | quote! { | ||
83 | pub fn #method_name(&self) -> AstChildren<#kind> { | ||
84 | AstChildren::new(&self.syntax) | ||
85 | } | ||
86 | } | ||
87 | }); | ||
88 | |||
89 | let options = ast_node.options.iter().map(|attr| { | ||
90 | let method_name = match attr { | ||
91 | Attr::Type(t) => format_ident!("{}", t.to_snake_case()), | ||
92 | Attr::NameType(n, _) => format_ident!("{}", n), | ||
93 | }; | ||
94 | let ty = match attr { | ||
95 | Attr::Type(t) | Attr::NameType(_, t) => format_ident!("{}", t), | ||
96 | }; | ||
97 | quote! { | ||
98 | pub fn #method_name(&self) -> Option<#ty> { | ||
99 | AstChildren::new(&self.syntax).next() | ||
100 | } | ||
101 | } | ||
102 | }); | ||
103 | |||
104 | quote! { | ||
105 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
106 | pub struct #name { | ||
107 | pub(crate) syntax: SyntaxNode, | ||
108 | } | ||
109 | |||
110 | impl AstNode for #name { | ||
111 | fn can_cast(kind: SyntaxKind) -> bool { | ||
112 | match kind { | ||
113 | #(#kinds)|* => true, | ||
114 | _ => false, | ||
115 | } | ||
116 | } | ||
117 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
118 | if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } | ||
119 | } | ||
120 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
121 | } | ||
122 | |||
123 | #variants | ||
124 | |||
125 | #(#traits)* | ||
126 | |||
127 | impl #name { | ||
128 | #(#collections)* | ||
129 | #(#options)* | ||
130 | } | ||
131 | } | ||
132 | }); | ||
133 | |||
134 | let ast = quote! { | ||
135 | use crate::{ | ||
136 | SyntaxNode, SyntaxKind::{self, *}, | ||
137 | ast::{self, AstNode, AstChildren}, | ||
138 | }; | ||
139 | |||
140 | #(#nodes)* | ||
141 | }; | ||
142 | |||
143 | let pretty = reformat(ast)?; | ||
144 | Ok(pretty) | ||
145 | } | ||
146 | |||
147 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | ||
148 | let mut rustfmt = Command::new("rustfmt") | ||
149 | .arg("--config-path") | ||
150 | .arg(project_root().join("rustfmt.toml")) | ||
151 | .stdin(Stdio::piped()) | ||
152 | .stdout(Stdio::piped()) | ||
153 | .spawn()?; | ||
154 | write!(rustfmt.stdin.take().unwrap(), "{}", text)?; | ||
155 | let output = rustfmt.wait_with_output()?; | ||
156 | let stdout = String::from_utf8(output.stdout)?; | ||
157 | Ok(stdout) | ||
158 | } | ||
159 | |||
25 | #[derive(Deserialize, Debug)] | 160 | #[derive(Deserialize, Debug)] |
26 | struct Grammar { | 161 | struct Grammar { |
27 | single_byte_tokens: Vec<(String, String)>, | 162 | single_byte_tokens: Vec<(String, String)>, |
@@ -36,9 +171,13 @@ struct Grammar { | |||
36 | #[derive(Deserialize, Debug)] | 171 | #[derive(Deserialize, Debug)] |
37 | struct AstNode { | 172 | struct AstNode { |
38 | #[serde(default)] | 173 | #[serde(default)] |
174 | #[serde(rename = "enum")] | ||
175 | variants: Vec<String>, | ||
176 | |||
177 | #[serde(default)] | ||
39 | traits: Vec<String>, | 178 | traits: Vec<String>, |
40 | #[serde(default)] | 179 | #[serde(default)] |
41 | collections: Vec<Attr>, | 180 | collections: Vec<(String, String)>, |
42 | #[serde(default)] | 181 | #[serde(default)] |
43 | options: Vec<Attr>, | 182 | options: Vec<Attr>, |
44 | } | 183 | } |