aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libeditor/src/lib.rs2
-rw-r--r--src/ast/generated.rs54
-rw-r--r--src/ast/generated.rs.tera22
-rw-r--r--src/ast/mod.rs (renamed from src/ast.rs)54
-rw-r--r--src/grammar.ron11
-rw-r--r--src/lib.rs2
-rw-r--r--tools/src/main.rs41
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;
3mod extend_selection; 3mod extend_selection;
4 4
5use libsyntax2::{ 5use 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 @@
1use std::sync::Arc;
2use {
3 SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
4 SyntaxKind::*,
5};
6
7
8#[derive(Debug)]
9pub struct File<R: TreeRoot = Arc<SyntaxRoot>> {
10 syntax: SyntaxNode<R>,
11}
12
13impl<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)]
25pub struct FnItem<R: TreeRoot = Arc<SyntaxRoot>> {
26 syntax: SyntaxNode<R>,
27}
28
29impl<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)]
41pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> {
42 syntax: SyntaxNode<R>,
43}
44
45impl<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 @@
1use std::sync::Arc;
2use {
3 SyntaxNode, SyntaxRoot, TreeRoot, AstNode,
4 SyntaxKind::*,
5};
6{% for node in ast %}
7{% set Name = node.kind | camel %}
8#[derive(Debug)]
9pub struct {{ Name }}<R: TreeRoot = Arc<SyntaxRoot>> {
10 syntax: SyntaxNode<R>,
11}
12
13impl<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 @@
1mod generated;
2
1use std::sync::Arc; 3use std::sync::Arc;
2use { 4use {
3 SyntaxNode, SyntaxRoot, TreeRoot, 5 SyntaxNode, SyntaxRoot, TreeRoot,
4 SyntaxKind::*, 6 SyntaxKind::*,
5}; 7};
8pub use self::generated::*;
6 9
7#[derive(Debug)] 10pub trait AstNode<R: TreeRoot>: Sized {
8pub 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)]
13pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> {
14 syntax: SyntaxNode<R>,
15} 13}
16 14
17#[derive(Debug)]
18pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> {
19 syntax: SyntaxNode<R>,
20}
21
22
23impl File<Arc<SyntaxRoot>> { 15impl 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
31impl<R: TreeRoot> File<R> { 21impl<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
40impl<R: TreeRoot> Function<R> { 29impl<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
82impl<R: TreeRoot> Name<R> { 66impl<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
90impl<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;
41pub mod utils; 41pub mod utils;
42 42
43pub use { 43pub 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";
23const GRAMMAR: &str = "./src/grammar.ron"; 23const GRAMMAR: &str = "./src/grammar.ron";
24const SYNTAX_KINDS: &str = "./src/syntax_kinds/generated.rs"; 24const SYNTAX_KINDS: &str = "./src/syntax_kinds/generated.rs";
25const SYNTAX_KINDS_TEMPLATE: &str = "./src/syntax_kinds/generated.rs.tera"; 25const SYNTAX_KINDS_TEMPLATE: &str = "./src/syntax_kinds/generated.rs.tera";
26const AST: &str = "./src/ast/generated.rs";
27const AST_TEMPLATE: &str = "./src/ast/generated.rs.tera";
26 28
27fn main() -> Result<()> { 29fn main() -> Result<()> {
28 let matches = App::new("tasks") 30 let matches = App::new("tasks")
@@ -47,10 +49,16 @@ fn main() -> Result<()> {
47 49
48fn run_gen_command(name: &str, verify: bool) -> Result<()> { 50fn 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
56fn update(path: &Path, contents: &str, verify: bool) -> Result<()> { 64fn 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
71fn get_kinds() -> Result<String> { 79fn 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
97fn 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
103fn gen_tests(verify: bool) -> Result<()> { 122fn 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