aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/ast.rs16
-rw-r--r--crates/ra_syntax/src/fuzz.rs21
-rw-r--r--crates/ra_syntax/src/lib.rs55
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs4
-rw-r--r--crates/ra_syntax/src/ptr.rs2
-rw-r--r--crates/ra_syntax/src/syntax_node.rs10
-rw-r--r--crates/ra_syntax/tests/test.rs8
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};
5fn check_file_invariants(file: &SourceFile) { 5fn 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
11pub fn check_parser(text: &str) { 10pub 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 {
76fn test_local_syntax_ptr() { 76fn 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]
22fn parser_tests() { 22fn 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,