diff options
-rw-r--r-- | libeditor/src/lib.rs | 2 | ||||
-rw-r--r-- | src/ast/generated.rs | 54 | ||||
-rw-r--r-- | src/ast/generated.rs.tera | 22 | ||||
-rw-r--r-- | src/ast/mod.rs (renamed from src/ast.rs) | 54 | ||||
-rw-r--r-- | src/grammar.ron | 11 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | tools/src/main.rs | 41 |
7 files changed, 134 insertions, 52 deletions
diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index 387859d4a..e7cc6a696 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs | |||
@@ -3,7 +3,7 @@ extern crate libsyntax2; | |||
3 | mod extend_selection; | 3 | mod extend_selection; |
4 | 4 | ||
5 | use libsyntax2::{ | 5 | use libsyntax2::{ |
6 | SyntaxNodeRef, | 6 | SyntaxNodeRef, AstNode, |
7 | algo::walk, | 7 | algo::walk, |
8 | SyntaxKind::*, | 8 | SyntaxKind::*, |
9 | }; | 9 | }; |
diff --git a/src/ast/generated.rs b/src/ast/generated.rs new file mode 100644 index 000000000..612b04f86 --- /dev/null +++ b/src/ast/generated.rs | |||
@@ -0,0 +1,54 @@ | |||
1 | use std::sync::Arc; | ||
2 | use { | ||
3 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, | ||
4 | SyntaxKind::*, | ||
5 | }; | ||
6 | |||
7 | |||
8 | #[derive(Debug)] | ||
9 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { | ||
10 | syntax: SyntaxNode<R>, | ||
11 | } | ||
12 | |||
13 | impl<R: TreeRoot> AstNode<R> for File<R> { | ||
14 | fn cast(syntax: SyntaxNode<R>) -> Option<Self> { | ||
15 | match syntax.kind() { | ||
16 | FILE => Some(File { syntax }), | ||
17 | _ => None, | ||
18 | } | ||
19 | } | ||
20 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | ||
21 | } | ||
22 | |||
23 | |||
24 | #[derive(Debug)] | ||
25 | pub struct FnItem<R: TreeRoot = Arc<SyntaxRoot>> { | ||
26 | syntax: SyntaxNode<R>, | ||
27 | } | ||
28 | |||
29 | impl<R: TreeRoot> AstNode<R> for FnItem<R> { | ||
30 | fn cast(syntax: SyntaxNode<R>) -> Option<Self> { | ||
31 | match syntax.kind() { | ||
32 | FN_ITEM => Some(FnItem { syntax }), | ||
33 | _ => None, | ||
34 | } | ||
35 | } | ||
36 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | ||
37 | } | ||
38 | |||
39 | |||
40 | #[derive(Debug)] | ||
41 | pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> { | ||
42 | syntax: SyntaxNode<R>, | ||
43 | } | ||
44 | |||
45 | impl<R: TreeRoot> AstNode<R> for Name<R> { | ||
46 | fn cast(syntax: SyntaxNode<R>) -> Option<Self> { | ||
47 | match syntax.kind() { | ||
48 | NAME => Some(Name { syntax }), | ||
49 | _ => None, | ||
50 | } | ||
51 | } | ||
52 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | ||
53 | } | ||
54 | |||
diff --git a/src/ast/generated.rs.tera b/src/ast/generated.rs.tera new file mode 100644 index 000000000..f2559383a --- /dev/null +++ b/src/ast/generated.rs.tera | |||
@@ -0,0 +1,22 @@ | |||
1 | use std::sync::Arc; | ||
2 | use { | ||
3 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, | ||
4 | SyntaxKind::*, | ||
5 | }; | ||
6 | {% for node in ast %} | ||
7 | {% set Name = node.kind | camel %} | ||
8 | #[derive(Debug)] | ||
9 | pub struct {{ Name }}<R: TreeRoot = Arc<SyntaxRoot>> { | ||
10 | syntax: SyntaxNode<R>, | ||
11 | } | ||
12 | |||
13 | impl<R: TreeRoot> AstNode<R> for {{ Name }}<R> { | ||
14 | fn cast(syntax: SyntaxNode<R>) -> Option<Self> { | ||
15 | match syntax.kind() { | ||
16 | {{ node.kind }} => Some({{ Name }} { syntax }), | ||
17 | _ => None, | ||
18 | } | ||
19 | } | ||
20 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | ||
21 | } | ||
22 | {% endfor %} | ||
diff --git a/src/ast.rs b/src/ast/mod.rs index a595b9324..dc7e006c9 100644 --- a/src/ast.rs +++ b/src/ast/mod.rs | |||
@@ -1,57 +1,41 @@ | |||
1 | mod generated; | ||
2 | |||
1 | use std::sync::Arc; | 3 | use std::sync::Arc; |
2 | use { | 4 | use { |
3 | SyntaxNode, SyntaxRoot, TreeRoot, | 5 | SyntaxNode, SyntaxRoot, TreeRoot, |
4 | SyntaxKind::*, | 6 | SyntaxKind::*, |
5 | }; | 7 | }; |
8 | pub use self::generated::*; | ||
6 | 9 | ||
7 | #[derive(Debug)] | 10 | pub trait AstNode<R: TreeRoot>: Sized { |
8 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { | 11 | fn cast(syntax: SyntaxNode<R>) -> Option<Self>; |
9 | syntax: SyntaxNode<R>, | 12 | fn syntax(&self) -> &SyntaxNode<R>; |
10 | } | ||
11 | |||
12 | #[derive(Debug)] | ||
13 | pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> { | ||
14 | syntax: SyntaxNode<R>, | ||
15 | } | 13 | } |
16 | 14 | ||
17 | #[derive(Debug)] | ||
18 | pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> { | ||
19 | syntax: SyntaxNode<R>, | ||
20 | } | ||
21 | |||
22 | |||
23 | impl File<Arc<SyntaxRoot>> { | 15 | impl File<Arc<SyntaxRoot>> { |
24 | pub fn parse(text: &str) -> Self { | 16 | pub fn parse(text: &str) -> Self { |
25 | File { | 17 | File::cast(::parse(text)).unwrap() |
26 | syntax: ::parse(text), | ||
27 | } | ||
28 | } | 18 | } |
29 | } | 19 | } |
30 | 20 | ||
31 | impl<R: TreeRoot> File<R> { | 21 | impl<R: TreeRoot> File<R> { |
32 | pub fn functions<'a>(&'a self) -> impl Iterator<Item = Function<R>> + 'a { | 22 | pub fn functions<'a>(&'a self) -> impl Iterator<Item = FnItem<R>> + 'a { |
33 | self.syntax | 23 | self.syntax() |
34 | .children() | 24 | .children() |
35 | .filter(|node| node.kind() == FN_ITEM) | 25 | .filter_map(FnItem::cast) |
36 | .map(|node| Function { syntax: node }) | ||
37 | } | 26 | } |
38 | } | 27 | } |
39 | 28 | ||
40 | impl<R: TreeRoot> Function<R> { | 29 | impl<R: TreeRoot> FnItem<R> { |
41 | pub fn syntax(&self) -> SyntaxNode<R> { | ||
42 | self.syntax.clone() | ||
43 | } | ||
44 | |||
45 | pub fn name(&self) -> Option<Name<R>> { | 30 | pub fn name(&self) -> Option<Name<R>> { |
46 | self.syntax | 31 | self.syntax() |
47 | .children() | 32 | .children() |
48 | .filter(|node| node.kind() == NAME) | 33 | .filter_map(Name::cast) |
49 | .map(|node| Name { syntax: node }) | ||
50 | .next() | 34 | .next() |
51 | } | 35 | } |
52 | 36 | ||
53 | pub fn has_atom_attr(&self, atom: &str) -> bool { | 37 | pub fn has_atom_attr(&self, atom: &str) -> bool { |
54 | self.syntax | 38 | self.syntax() |
55 | .children() | 39 | .children() |
56 | .filter(|node| node.kind() == ATTR) | 40 | .filter(|node| node.kind() == ATTR) |
57 | .any(|attr| { | 41 | .any(|attr| { |
@@ -81,14 +65,6 @@ impl<R: TreeRoot> Function<R> { | |||
81 | 65 | ||
82 | impl<R: TreeRoot> Name<R> { | 66 | impl<R: TreeRoot> Name<R> { |
83 | pub fn text(&self) -> String { | 67 | pub fn text(&self) -> String { |
84 | self.syntax.text() | 68 | self.syntax().text() |
85 | } | ||
86 | } | ||
87 | |||
88 | |||
89 | |||
90 | impl<R: TreeRoot> File<R> { | ||
91 | pub fn syntax(&self) -> SyntaxNode<R> { | ||
92 | self.syntax.clone() | ||
93 | } | 69 | } |
94 | } | 70 | } |
diff --git a/src/grammar.ron b/src/grammar.ron index 0443dd798..b6a870d84 100644 --- a/src/grammar.ron +++ b/src/grammar.ron | |||
@@ -212,5 +212,16 @@ Grammar( | |||
212 | "PARAM", | 212 | "PARAM", |
213 | "SELF_PARAM", | 213 | "SELF_PARAM", |
214 | "ARG_LIST", | 214 | "ARG_LIST", |
215 | ], | ||
216 | ast: [ | ||
217 | ( | ||
218 | kind: "FILE" | ||
219 | ), | ||
220 | ( | ||
221 | kind: "FN_ITEM" | ||
222 | ), | ||
223 | ( | ||
224 | kind: "NAME" | ||
225 | ), | ||
215 | ] | 226 | ] |
216 | ) | 227 | ) |
diff --git a/src/lib.rs b/src/lib.rs index 91b0c9c55..d1e690bb2 100644 --- a/src/lib.rs +++ b/src/lib.rs | |||
@@ -41,7 +41,7 @@ mod yellow; | |||
41 | pub mod utils; | 41 | pub mod utils; |
42 | 42 | ||
43 | pub use { | 43 | pub use { |
44 | ast::File, | 44 | ast::{AstNode, File}, |
45 | lexer::{tokenize, Token}, | 45 | lexer::{tokenize, Token}, |
46 | syntax_kinds::SyntaxKind, | 46 | syntax_kinds::SyntaxKind, |
47 | text_unit::{TextRange, TextUnit}, | 47 | text_unit::{TextRange, TextUnit}, |
diff --git a/tools/src/main.rs b/tools/src/main.rs index 714158f55..b5c966f74 100644 --- a/tools/src/main.rs +++ b/tools/src/main.rs | |||
@@ -23,6 +23,8 @@ const INLINE_TESTS_DIR: &str = "tests/data/parser/inline"; | |||
23 | const GRAMMAR: &str = "./src/grammar.ron"; | 23 | const GRAMMAR: &str = "./src/grammar.ron"; |
24 | const SYNTAX_KINDS: &str = "./src/syntax_kinds/generated.rs"; | 24 | const SYNTAX_KINDS: &str = "./src/syntax_kinds/generated.rs"; |
25 | const SYNTAX_KINDS_TEMPLATE: &str = "./src/syntax_kinds/generated.rs.tera"; | 25 | const SYNTAX_KINDS_TEMPLATE: &str = "./src/syntax_kinds/generated.rs.tera"; |
26 | const AST: &str = "./src/ast/generated.rs"; | ||
27 | const AST_TEMPLATE: &str = "./src/ast/generated.rs.tera"; | ||
26 | 28 | ||
27 | fn main() -> Result<()> { | 29 | fn main() -> Result<()> { |
28 | let matches = App::new("tasks") | 30 | let matches = App::new("tasks") |
@@ -47,10 +49,16 @@ fn main() -> Result<()> { | |||
47 | 49 | ||
48 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { | 50 | fn run_gen_command(name: &str, verify: bool) -> Result<()> { |
49 | match name { | 51 | match name { |
50 | "gen-kinds" => update(Path::new(SYNTAX_KINDS), &get_kinds()?, verify), | 52 | "gen-kinds" => { |
51 | "gen-tests" => gen_tests(verify), | 53 | update(Path::new(SYNTAX_KINDS), &render_template(SYNTAX_KINDS_TEMPLATE)?, verify)?; |
54 | update(Path::new(AST), &render_template(AST_TEMPLATE)?, verify)?; | ||
55 | }, | ||
56 | "gen-tests" => { | ||
57 | gen_tests(verify)? | ||
58 | }, | ||
52 | _ => unreachable!(), | 59 | _ => unreachable!(), |
53 | } | 60 | } |
61 | Ok(()) | ||
54 | } | 62 | } |
55 | 63 | ||
56 | fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { | 64 | fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { |
@@ -68,13 +76,30 @@ fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { | |||
68 | Ok(()) | 76 | Ok(()) |
69 | } | 77 | } |
70 | 78 | ||
71 | fn get_kinds() -> Result<String> { | 79 | fn render_template(template: &str) -> Result<String> { |
72 | let grammar = grammar()?; | 80 | let grammar: ron::value::Value = { |
73 | let template = fs::read_to_string(SYNTAX_KINDS_TEMPLATE)?; | 81 | let text = fs::read_to_string(GRAMMAR)?; |
82 | ron::de::from_str(&text)? | ||
83 | }; | ||
84 | let template = fs::read_to_string(template)?; | ||
74 | let mut tera = tera::Tera::default(); | 85 | let mut tera = tera::Tera::default(); |
75 | tera.add_raw_template("grammar", &template) | 86 | tera.add_raw_template("grammar", &template) |
76 | .map_err(|e| format_err!("template error: {:?}", e))?; | 87 | .map_err(|e| format_err!("template error: {:?}", e))?; |
77 | tera.register_global_function("concat", Box::new(concat)); | 88 | tera.register_global_function("concat", Box::new(concat)); |
89 | tera.register_filter("camel", |arg, _| { | ||
90 | Ok(arg.as_str().unwrap() | ||
91 | .split("_") | ||
92 | .flat_map(|word| { | ||
93 | word.chars() | ||
94 | .next().unwrap() | ||
95 | .to_uppercase() | ||
96 | .chain( | ||
97 | word.chars().skip(1).flat_map(|c| c.to_lowercase()) | ||
98 | ) | ||
99 | }) | ||
100 | .collect::<String>() | ||
101 | .into()) | ||
102 | }); | ||
78 | let ret = tera | 103 | let ret = tera |
79 | .render("grammar", &grammar) | 104 | .render("grammar", &grammar) |
80 | .map_err(|e| format_err!("template error: {:?}", e))?; | 105 | .map_err(|e| format_err!("template error: {:?}", e))?; |
@@ -94,12 +119,6 @@ fn get_kinds() -> Result<String> { | |||
94 | } | 119 | } |
95 | } | 120 | } |
96 | 121 | ||
97 | fn grammar() -> Result<ron::value::Value> { | ||
98 | let text = fs::read_to_string(GRAMMAR)?; | ||
99 | let ret = ron::de::from_str(&text)?; | ||
100 | Ok(ret) | ||
101 | } | ||
102 | |||
103 | fn gen_tests(verify: bool) -> Result<()> { | 122 | fn gen_tests(verify: bool) -> Result<()> { |
104 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; | 123 | let tests = tests_from_dir(Path::new(GRAMMAR_DIR))?; |
105 | 124 | ||