aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-08-18 21:11:08 +0100
committerAleksey Kladov <[email protected]>2019-08-18 21:11:08 +0100
commit8cefdb5527d011d7d5ca2902791b7c3da0276fec (patch)
treeb40d906a23b8ffa37b40edd4916a13fd9e6f4ab0 /crates
parentd545a5c75cb181758dd745b031eacfd7fc8a6929 (diff)
use quote! macro to generate grammar
We already use syn&quote elsewhere (transitively), so it make sense to cut down on the number of technologies and get rid of tera
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_syntax/src/grammar.ron54
-rw-r--r--crates/ra_tools/Cargo.toml1
-rw-r--r--crates/ra_tools/src/codegen.rs165
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"
12clap = "2.32.0" 12clap = "2.32.0"
13quote = "1.0.2" 13quote = "1.0.2"
14ron = "0.5.1" 14ron = "0.5.1"
15heck = "0.3.0"
15serde = { version = "1.0.0", features = ["derive"] } 16serde = { 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 @@
1use std::{collections::BTreeMap, fs, path::Path}; 1use std::{
2 collections::BTreeMap,
3 fs,
4 io::Write,
5 path::Path,
6 process::{Command, Stdio},
7};
2 8
3use quote::quote; 9use heck::{ShoutySnakeCase, SnakeCase};
10use quote::{format_ident, quote};
4use ron; 11use ron;
5use serde::Deserialize; 12use serde::Deserialize;
6 13
7use crate::{project_root, Mode, Result, AST, GRAMMAR}; 14use crate::{project_root, Mode, Result, AST, GRAMMAR, SYNTAX_KINDS};
8 15
9pub fn generate(mode: Mode) -> Result<()> { 16pub 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
16fn 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
31fn 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
147fn 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)]
26struct Grammar { 161struct 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)]
37struct AstNode { 172struct 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}