aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/lib.rs')
-rw-r--r--crates/ra_syntax/src/lib.rs94
1 files changed, 64 insertions, 30 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 0ceabc203..930a643b7 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -31,6 +31,12 @@ pub mod ast;
31#[doc(hidden)] 31#[doc(hidden)]
32pub mod fuzz; 32pub mod fuzz;
33 33
34use std::{sync::Arc, fmt::Write};
35
36use ra_text_edit::AtomTextEdit;
37
38use crate::syntax_node::GreenNode;
39
34pub use rowan::{SmolStr, TextRange, TextUnit}; 40pub use rowan::{SmolStr, TextRange, TextUnit};
35pub use ra_parser::SyntaxKind; 41pub use ra_parser::SyntaxKind;
36pub use ra_parser::T; 42pub use ra_parser::T;
@@ -43,45 +49,72 @@ pub use crate::{
43 parsing::{tokenize, classify_literal, Token}, 49 parsing::{tokenize, classify_literal, Token},
44}; 50};
45 51
46use ra_text_edit::AtomTextEdit; 52/// `Parse` is the result of the parsing: a syntax tree and a collection of
47use crate::syntax_node::GreenNode; 53/// errors.
48 54///
49/// `SourceFile` represents a parse tree for a single Rust file. 55/// Note that we always produce a syntax tree, even for completely invalid
50pub use crate::ast::SourceFile; 56/// files.
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct Parse {
59 pub tree: TreeArc<SourceFile>,
60 pub errors: Arc<Vec<SyntaxError>>,
61}
51 62
52impl SourceFile { 63impl Parse {
53 fn new(green: GreenNode, errors: Vec<SyntaxError>) -> TreeArc<SourceFile> { 64 pub fn ok(self) -> Result<TreeArc<SourceFile>, Arc<Vec<SyntaxError>>> {
54 let root = SyntaxNode::new(green, errors); 65 if self.errors.is_empty() {
55 if cfg!(debug_assertions) { 66 Ok(self.tree)
56 validation::validate_block_structure(&root); 67 } else {
68 Err(self.errors)
57 } 69 }
58 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
59 TreeArc::cast(root)
60 } 70 }
61 71
62 pub fn parse(text: &str) -> TreeArc<SourceFile> { 72 pub fn reparse(&self, edit: &AtomTextEdit) -> Parse {
63 let (green, errors) = parsing::parse_text(text); 73 self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
64 SourceFile::new(green, errors)
65 } 74 }
66 75
67 pub fn reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { 76 pub fn debug_dump(&self) -> String {
68 self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) 77 let mut buf = self.tree.syntax().debug_dump();
78 for err in self.errors.iter() {
79 writeln!(buf, "err: `{}`", err).unwrap();
80 }
81 buf
69 } 82 }
70 83
71 pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<TreeArc<SourceFile>> { 84 fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<Parse> {
72 parsing::incremental_reparse(self.syntax(), edit, self.errors()) 85 // FIXME: validation errors are not handled here
73 .map(|(green_node, errors, _reparsed_range)| SourceFile::new(green_node, errors)) 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 )
74 } 92 }
75 93
76 fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc<SourceFile> { 94 fn full_reparse(&self, edit: &AtomTextEdit) -> Parse {
77 let text = edit.apply(self.syntax().text().to_string()); 95 let text = edit.apply(self.tree.syntax().text().to_string());
78 SourceFile::parse(&text) 96 SourceFile::parse(&text)
79 } 97 }
98}
99
100/// `SourceFile` represents a parse tree for a single Rust file.
101pub use crate::ast::SourceFile;
102
103impl SourceFile {
104 fn new(green: GreenNode) -> TreeArc<SourceFile> {
105 let root = SyntaxNode::new(green);
106 if cfg!(debug_assertions) {
107 validation::validate_block_structure(&root);
108 }
109 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
110 TreeArc::cast(root)
111 }
80 112
81 pub fn errors(&self) -> Vec<SyntaxError> { 113 pub fn parse(text: &str) -> Parse {
82 let mut errors = self.syntax.root_data().to_vec(); 114 let (green, mut errors) = parsing::parse_text(text);
83 errors.extend(validation::validate(self)); 115 let tree = SourceFile::new(green);
84 errors 116 errors.extend(validation::validate(&tree));
117 Parse { tree, errors: Arc::new(errors) }
85 } 118 }
86} 119}
87 120
@@ -98,14 +131,15 @@ fn api_walkthrough() {
98 "; 131 ";
99 // `SourceFile` is the main entry point. 132 // `SourceFile` is the main entry point.
100 // 133 //
101 // 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
102 // source code might be parsed. 135 // of errors. That is, syntax tree is constructed even in presence of errors.
103 let file = SourceFile::parse(source_code); 136 let parse = SourceFile::parse(source_code);
137 assert!(parse.errors.is_empty());
104 138
105 // 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
106 // 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
107 // points to the whole file instead of an individual node. 141 // points to the whole file instead of an individual node.
108 let file: TreeArc<SourceFile> = file; 142 let file: TreeArc<SourceFile> = parse.tree;
109 143
110 // `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:
111 let mut func = None; 145 let mut func = None;