diff options
author | Aleksey Kladov <[email protected]> | 2018-08-09 15:43:39 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-09 15:43:39 +0100 |
commit | d8b2a5efc0e5de3b0d72f29ccc86185f0827c9d3 (patch) | |
tree | 46f8e8feb046ece8511ac1981f53bfa1762d3af3 /src/ast | |
parent | 36bd28633baf6015b767e9e70d2d53185271db50 (diff) |
Generate AST
Diffstat (limited to 'src/ast')
-rw-r--r-- | src/ast/generated.rs | 54 | ||||
-rw-r--r-- | src/ast/generated.rs.tera | 22 | ||||
-rw-r--r-- | src/ast/mod.rs | 70 |
3 files changed, 146 insertions, 0 deletions
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/mod.rs b/src/ast/mod.rs new file mode 100644 index 000000000..dc7e006c9 --- /dev/null +++ b/src/ast/mod.rs | |||
@@ -0,0 +1,70 @@ | |||
1 | mod generated; | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | use { | ||
5 | SyntaxNode, SyntaxRoot, TreeRoot, | ||
6 | SyntaxKind::*, | ||
7 | }; | ||
8 | pub use self::generated::*; | ||
9 | |||
10 | pub trait AstNode<R: TreeRoot>: Sized { | ||
11 | fn cast(syntax: SyntaxNode<R>) -> Option<Self>; | ||
12 | fn syntax(&self) -> &SyntaxNode<R>; | ||
13 | } | ||
14 | |||
15 | impl File<Arc<SyntaxRoot>> { | ||
16 | pub fn parse(text: &str) -> Self { | ||
17 | File::cast(::parse(text)).unwrap() | ||
18 | } | ||
19 | } | ||
20 | |||
21 | impl<R: TreeRoot> File<R> { | ||
22 | pub fn functions<'a>(&'a self) -> impl Iterator<Item = FnItem<R>> + 'a { | ||
23 | self.syntax() | ||
24 | .children() | ||
25 | .filter_map(FnItem::cast) | ||
26 | } | ||
27 | } | ||
28 | |||
29 | impl<R: TreeRoot> FnItem<R> { | ||
30 | pub fn name(&self) -> Option<Name<R>> { | ||
31 | self.syntax() | ||
32 | .children() | ||
33 | .filter_map(Name::cast) | ||
34 | .next() | ||
35 | } | ||
36 | |||
37 | pub fn has_atom_attr(&self, atom: &str) -> bool { | ||
38 | self.syntax() | ||
39 | .children() | ||
40 | .filter(|node| node.kind() == ATTR) | ||
41 | .any(|attr| { | ||
42 | let mut metas = attr.children().filter(|node| node.kind() == META_ITEM); | ||
43 | let meta = match metas.next() { | ||
44 | None => return false, | ||
45 | Some(meta) => { | ||
46 | if metas.next().is_some() { | ||
47 | return false; | ||
48 | } | ||
49 | meta | ||
50 | } | ||
51 | }; | ||
52 | let mut children = meta.children(); | ||
53 | match children.next() { | ||
54 | None => false, | ||
55 | Some(child) => { | ||
56 | if children.next().is_some() { | ||
57 | return false; | ||
58 | } | ||
59 | child.kind() == IDENT && child.text() == atom | ||
60 | } | ||
61 | } | ||
62 | }) | ||
63 | } | ||
64 | } | ||
65 | |||
66 | impl<R: TreeRoot> Name<R> { | ||
67 | pub fn text(&self) -> String { | ||
68 | self.syntax().text() | ||
69 | } | ||
70 | } | ||