diff options
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 16 | ||||
-rw-r--r-- | crates/ra_syntax/src/fuzz.rs | 21 | ||||
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 55 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing/reparsing.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/ptr.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/syntax_node.rs | 10 | ||||
-rw-r--r-- | crates/ra_syntax/tests/test.rs | 8 |
7 files changed, 54 insertions, 62 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index f7e33366e..319110b6a 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -80,7 +80,9 @@ fn test_doc_comment_none() { | |||
80 | // non-doc | 80 | // non-doc |
81 | mod foo {} | 81 | mod foo {} |
82 | "#, | 82 | "#, |
83 | ); | 83 | ) |
84 | .ok() | ||
85 | .unwrap(); | ||
84 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 86 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
85 | assert!(module.doc_comment_text().is_none()); | 87 | assert!(module.doc_comment_text().is_none()); |
86 | } | 88 | } |
@@ -93,7 +95,9 @@ fn test_doc_comment_of_items() { | |||
93 | // non-doc | 95 | // non-doc |
94 | mod foo {} | 96 | mod foo {} |
95 | "#, | 97 | "#, |
96 | ); | 98 | ) |
99 | .ok() | ||
100 | .unwrap(); | ||
97 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 101 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
98 | assert_eq!("doc", module.doc_comment_text().unwrap()); | 102 | assert_eq!("doc", module.doc_comment_text().unwrap()); |
99 | } | 103 | } |
@@ -110,7 +114,9 @@ fn test_doc_comment_preserves_indents() { | |||
110 | /// ``` | 114 | /// ``` |
111 | mod foo {} | 115 | mod foo {} |
112 | "#, | 116 | "#, |
113 | ); | 117 | ) |
118 | .ok() | ||
119 | .unwrap(); | ||
114 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | 120 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); |
115 | assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); | 121 | assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); |
116 | } | 122 | } |
@@ -133,7 +139,9 @@ where | |||
133 | for<'a> F: Fn(&'a str) | 139 | for<'a> F: Fn(&'a str) |
134 | {} | 140 | {} |
135 | "#, | 141 | "#, |
136 | ); | 142 | ) |
143 | .ok() | ||
144 | .unwrap(); | ||
137 | let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap(); | 145 | let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap(); |
138 | 146 | ||
139 | let mut predicates = where_clause.predicates(); | 147 | let mut predicates = where_clause.predicates(); |
diff --git a/crates/ra_syntax/src/fuzz.rs b/crates/ra_syntax/src/fuzz.rs index af11b2e1a..6a9905bd1 100644 --- a/crates/ra_syntax/src/fuzz.rs +++ b/crates/ra_syntax/src/fuzz.rs | |||
@@ -5,12 +5,11 @@ use std::str::{self, FromStr}; | |||
5 | fn check_file_invariants(file: &SourceFile) { | 5 | fn check_file_invariants(file: &SourceFile) { |
6 | let root = file.syntax(); | 6 | let root = file.syntax(); |
7 | validation::validate_block_structure(root); | 7 | validation::validate_block_structure(root); |
8 | let _ = file.errors(); | ||
9 | } | 8 | } |
10 | 9 | ||
11 | pub fn check_parser(text: &str) { | 10 | pub fn check_parser(text: &str) { |
12 | let file = SourceFile::parse(text); | 11 | let file = SourceFile::parse(text); |
13 | check_file_invariants(&file); | 12 | check_file_invariants(&file.tree); |
14 | } | 13 | } |
15 | 14 | ||
16 | #[derive(Debug, Clone)] | 15 | #[derive(Debug, Clone)] |
@@ -44,16 +43,18 @@ impl CheckReparse { | |||
44 | } | 43 | } |
45 | 44 | ||
46 | pub fn run(&self) { | 45 | pub fn run(&self) { |
47 | let file = SourceFile::parse(&self.text); | 46 | let parse = SourceFile::parse(&self.text); |
48 | let new_file = file.reparse(&self.edit); | 47 | let new_parse = parse.reparse(&self.edit); |
49 | check_file_invariants(&new_file); | 48 | check_file_invariants(&new_parse.tree); |
50 | assert_eq!(&new_file.syntax().text().to_string(), &self.edited_text); | 49 | assert_eq!(&new_parse.tree.syntax().text().to_string(), &self.edited_text); |
51 | let full_reparse = SourceFile::parse(&self.edited_text); | 50 | let full_reparse = SourceFile::parse(&self.edited_text); |
52 | for (a, b) in new_file.syntax().descendants().zip(full_reparse.syntax().descendants()) { | 51 | for (a, b) in |
52 | new_parse.tree.syntax().descendants().zip(full_reparse.tree.syntax().descendants()) | ||
53 | { | ||
53 | if (a.kind(), a.range()) != (b.kind(), b.range()) { | 54 | if (a.kind(), a.range()) != (b.kind(), b.range()) { |
54 | eprint!("original:\n{}", file.syntax().debug_dump()); | 55 | eprint!("original:\n{}", parse.tree.syntax().debug_dump()); |
55 | eprint!("reparsed:\n{}", new_file.syntax().debug_dump()); | 56 | eprint!("reparsed:\n{}", new_parse.tree.syntax().debug_dump()); |
56 | eprint!("full reparse:\n{}", full_reparse.syntax().debug_dump()); | 57 | eprint!("full reparse:\n{}", full_reparse.tree.syntax().debug_dump()); |
57 | assert_eq!( | 58 | assert_eq!( |
58 | format!("{:?}", a), | 59 | format!("{:?}", a), |
59 | format!("{:?}", b), | 60 | format!("{:?}", b), |
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 6574eeed1..930a643b7 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -69,6 +69,10 @@ impl Parse { | |||
69 | } | 69 | } |
70 | } | 70 | } |
71 | 71 | ||
72 | pub fn reparse(&self, edit: &AtomTextEdit) -> Parse { | ||
73 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | ||
74 | } | ||
75 | |||
72 | pub fn debug_dump(&self) -> String { | 76 | pub fn debug_dump(&self) -> String { |
73 | let mut buf = self.tree.syntax().debug_dump(); | 77 | let mut buf = self.tree.syntax().debug_dump(); |
74 | for err in self.errors.iter() { | 78 | for err in self.errors.iter() { |
@@ -76,6 +80,21 @@ impl Parse { | |||
76 | } | 80 | } |
77 | buf | 81 | buf |
78 | } | 82 | } |
83 | |||
84 | fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse> { | ||
85 | // FIXME: validation errors are not handled here | ||
86 | parsing::incremental_reparse(self.tree.syntax(), edit, self.errors.to_vec()).map( | ||
87 | |(green_node, errors, _reparsed_range)| Parse { | ||
88 | tree: SourceFile::new(green_node), | ||
89 | errors: Arc::new(errors), | ||
90 | }, | ||
91 | ) | ||
92 | } | ||
93 | |||
94 | fn full_reparse(&self, edit: &AtomTextEdit) -> Parse { | ||
95 | let text = edit.apply(self.tree.syntax().text().to_string()); | ||
96 | SourceFile::parse(&text) | ||
97 | } | ||
79 | } | 98 | } |
80 | 99 | ||
81 | /// `SourceFile` represents a parse tree for a single Rust file. | 100 | /// `SourceFile` represents a parse tree for a single Rust file. |
@@ -91,37 +110,12 @@ impl SourceFile { | |||
91 | TreeArc::cast(root) | 110 | TreeArc::cast(root) |
92 | } | 111 | } |
93 | 112 | ||
94 | pub fn parse2(text: &str) -> Parse { | 113 | pub fn parse(text: &str) -> Parse { |
95 | let (green, mut errors) = parsing::parse_text(text); | 114 | let (green, mut errors) = parsing::parse_text(text); |
96 | let tree = SourceFile::new(green); | 115 | let tree = SourceFile::new(green); |
97 | errors.extend(validation::validate(&tree)); | 116 | errors.extend(validation::validate(&tree)); |
98 | Parse { tree, errors: Arc::new(errors) } | 117 | Parse { tree, errors: Arc::new(errors) } |
99 | } | 118 | } |
100 | |||
101 | pub fn parse(text: &str) -> TreeArc<SourceFile> { | ||
102 | let (green, _errors) = parsing::parse_text(text); | ||
103 | SourceFile::new(green) | ||
104 | } | ||
105 | |||
106 | pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { | ||
107 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | ||
108 | } | ||
109 | |||
110 | pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { | ||
111 | parsing::incremental_reparse(self.syntax(), edit, self.errors()) | ||
112 | .map(|(green_node, _errors, _reparsed_range)| SourceFile::new(green_node)) | ||
113 | } | ||
114 | |||
115 | fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { | ||
116 | let text = edit.apply(self.syntax().text().to_string()); | ||
117 | SourceFile::parse(&text) | ||
118 | } | ||
119 | |||
120 | pub fn errors(&self) -> Vec<SyntaxError> { | ||
121 | let mut errors = self.syntax.root_data().to_vec(); | ||
122 | errors.extend(validation::validate(self)); | ||
123 | errors | ||
124 | } | ||
125 | } | 119 | } |
126 | 120 | ||
127 | /// This test does not assert anything and instead just shows off the crate's | 121 | /// This test does not assert anything and instead just shows off the crate's |
@@ -137,14 +131,15 @@ fn api_walkthrough() { | |||
137 | "; | 131 | "; |
138 | // `SourceFile` is the main entry point. | 132 | // `SourceFile` is the main entry point. |
139 | // | 133 | // |
140 | // Note how `parse` does not return a `Result`: even completely invalid | 134 | // The `parse` method returns a `Parse` -- a pair of syntax tree and a list |
141 | // source code might be parsed. | 135 | // of errors. That is, syntax tree is constructed even in presence of errors. |
142 | let file = SourceFile::parse(source_code); | 136 | let parse = SourceFile::parse(source_code); |
137 | assert!(parse.errors.is_empty()); | ||
143 | 138 | ||
144 | // Due to the way ownership is set up, owned syntax Nodes always live behind | 139 | // Due to the way ownership is set up, owned syntax Nodes always live behind |
145 | // a `TreeArc` smart pointer. `TreeArc` is roughly an `std::sync::Arc` which | 140 | // a `TreeArc` smart pointer. `TreeArc` is roughly an `std::sync::Arc` which |
146 | // points to the whole file instead of an individual node. | 141 | // points to the whole file instead of an individual node. |
147 | let file: TreeArc<SourceFile> = file; | 142 | let file: TreeArc<SourceFile> = parse.tree; |
148 | 143 | ||
149 | // `SourceFile` is the root of the syntax tree. We can iterate file's items: | 144 | // `SourceFile` is the root of the syntax tree. We can iterate file's items: |
150 | let mut func = None; | 145 | let mut func = None; |
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index dc913cf2b..cf27a3393 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs | |||
@@ -178,12 +178,12 @@ mod tests { | |||
178 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); | 178 | let edit = AtomTextEdit::replace(range, replace_with.to_owned()); |
179 | let after = edit.apply(before.clone()); | 179 | let after = edit.apply(before.clone()); |
180 | 180 | ||
181 | let fully_reparsed = SourceFile::parse2(&after); | 181 | let fully_reparsed = SourceFile::parse(&after); |
182 | let incrementally_reparsed = { | 182 | let incrementally_reparsed = { |
183 | let f = SourceFile::parse(&before); | 183 | let f = SourceFile::parse(&before); |
184 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; | 184 | let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; |
185 | let (green, new_errors, range) = | 185 | let (green, new_errors, range) = |
186 | incremental_reparse(f.syntax(), &edit, f.errors()).unwrap(); | 186 | incremental_reparse(f.tree.syntax(), &edit, f.errors.to_vec()).unwrap(); |
187 | assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); | 187 | assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); |
188 | Parse { tree: SourceFile::new(green), errors: Arc::new(new_errors) } | 188 | Parse { tree: SourceFile::new(green), errors: Arc::new(new_errors) } |
189 | }; | 189 | }; |
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs index cee9503ca..10cddb852 100644 --- a/crates/ra_syntax/src/ptr.rs +++ b/crates/ra_syntax/src/ptr.rs | |||
@@ -76,7 +76,7 @@ impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr { | |||
76 | fn test_local_syntax_ptr() { | 76 | fn test_local_syntax_ptr() { |
77 | use crate::{ast, AstNode, SourceFile}; | 77 | use crate::{ast, AstNode, SourceFile}; |
78 | 78 | ||
79 | let file = SourceFile::parse("struct Foo { f: u32, }"); | 79 | let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap(); |
80 | let field = file.syntax().descendants().find_map(ast::NamedFieldDef::cast).unwrap(); | 80 | let field = file.syntax().descendants().find_map(ast::NamedFieldDef::cast).unwrap(); |
81 | let ptr = SyntaxNodePtr::new(field.syntax()); | 81 | let ptr = SyntaxNodePtr::new(field.syntax()); |
82 | let field_syntax = ptr.to_node(file.syntax()); | 82 | let field_syntax = ptr.to_node(file.syntax()); |
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index 769125d11..4105b5220 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs | |||
@@ -280,16 +280,6 @@ impl SyntaxNode { | |||
280 | buf | 280 | buf |
281 | } | 281 | } |
282 | 282 | ||
283 | pub(crate) fn root_data(&self) -> &[SyntaxError] { | ||
284 | match self.0.root_data() { | ||
285 | None => &[], | ||
286 | Some(data) => { | ||
287 | let data: &Vec<SyntaxError> = std::any::Any::downcast_ref(data).unwrap(); | ||
288 | data.as_slice() | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { | 283 | pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { |
294 | self.0.replace_with(replacement) | 284 | self.0.replace_with(replacement) |
295 | } | 285 | } |
diff --git a/crates/ra_syntax/tests/test.rs b/crates/ra_syntax/tests/test.rs index 4b711f271..f31e12588 100644 --- a/crates/ra_syntax/tests/test.rs +++ b/crates/ra_syntax/tests/test.rs | |||
@@ -21,7 +21,7 @@ fn lexer_tests() { | |||
21 | #[test] | 21 | #[test] |
22 | fn parser_tests() { | 22 | fn parser_tests() { |
23 | dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { | 23 | dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { |
24 | let parse = SourceFile::parse2(text); | 24 | let parse = SourceFile::parse(text); |
25 | let errors = parse.errors.as_slice(); | 25 | let errors = parse.errors.as_slice(); |
26 | assert_eq!( | 26 | assert_eq!( |
27 | errors, | 27 | errors, |
@@ -32,7 +32,7 @@ fn parser_tests() { | |||
32 | parse.debug_dump() | 32 | parse.debug_dump() |
33 | }); | 33 | }); |
34 | dir_tests(&test_data_dir(), &["parser/err", "parser/inline/err"], |text, path| { | 34 | dir_tests(&test_data_dir(), &["parser/err", "parser/inline/err"], |text, path| { |
35 | let parse = SourceFile::parse2(text); | 35 | let parse = SourceFile::parse(text); |
36 | let errors = parse.errors.as_slice(); | 36 | let errors = parse.errors.as_slice(); |
37 | assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display()); | 37 | assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display()); |
38 | parse.debug_dump() | 38 | parse.debug_dump() |
@@ -78,9 +78,7 @@ fn self_hosting_parsing() { | |||
78 | { | 78 | { |
79 | count += 1; | 79 | count += 1; |
80 | let text = read_text(entry.path()); | 80 | let text = read_text(entry.path()); |
81 | let node = SourceFile::parse(&text); | 81 | SourceFile::parse(&text).ok().expect("There should be no errors in the file"); |
82 | let errors = node.errors(); | ||
83 | assert_eq!(&*errors, &[], "There should be no errors in the file {:?}", entry); | ||
84 | } | 82 | } |
85 | assert!( | 83 | assert!( |
86 | count > 30, | 84 | count > 30, |