diff options
-rw-r--r-- | crates/libsyntax2/src/grammar/mod.rs | 6 | ||||
-rw-r--r-- | crates/libsyntax2/src/lib.rs | 41 | ||||
-rw-r--r-- | crates/libsyntax2/src/parser_impl/mod.rs | 9 | ||||
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax.rs | 23 | ||||
-rw-r--r-- | crates/libsyntax2/tests/test/main.rs | 38 |
5 files changed, 104 insertions, 13 deletions
diff --git a/crates/libsyntax2/src/grammar/mod.rs b/crates/libsyntax2/src/grammar/mod.rs index 46ba8a89a..496d28349 100644 --- a/crates/libsyntax2/src/grammar/mod.rs +++ b/crates/libsyntax2/src/grammar/mod.rs | |||
@@ -40,11 +40,11 @@ pub(crate) use self::{ | |||
40 | items::named_field_def_list, | 40 | items::named_field_def_list, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | pub(crate) fn file(p: &mut Parser) { | 43 | pub(crate) fn root(p: &mut Parser) { |
44 | let file = p.start(); | 44 | let m = p.start(); |
45 | p.eat(SHEBANG); | 45 | p.eat(SHEBANG); |
46 | items::mod_contents(p, false); | 46 | items::mod_contents(p, false); |
47 | file.complete(p, ROOT); | 47 | m.complete(p, ROOT); |
48 | } | 48 | } |
49 | 49 | ||
50 | 50 | ||
diff --git a/crates/libsyntax2/src/lib.rs b/crates/libsyntax2/src/lib.rs index bb060cbae..d43d26c4c 100644 --- a/crates/libsyntax2/src/lib.rs +++ b/crates/libsyntax2/src/lib.rs | |||
@@ -70,13 +70,15 @@ impl File { | |||
70 | } | 70 | } |
71 | pub fn parse(text: &str) -> File { | 71 | pub fn parse(text: &str) -> File { |
72 | let tokens = tokenize(&text); | 72 | let tokens = tokenize(&text); |
73 | let (green, errors) = parser_impl::parse::<yellow::GreenBuilder>(text, &tokens); | 73 | let (green, errors) = parser_impl::parse_with::<yellow::GreenBuilder>( |
74 | text, &tokens, grammar::root, | ||
75 | ); | ||
74 | File::new(green, errors) | 76 | File::new(green, errors) |
75 | } | 77 | } |
76 | pub fn reparse(&self, edit: &AtomEdit) -> File { | 78 | pub fn reparse(&self, edit: &AtomEdit) -> File { |
77 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) | 79 | self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit)) |
78 | } | 80 | } |
79 | fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { | 81 | pub fn incremental_reparse(&self, edit: &AtomEdit) -> Option<File> { |
80 | let (node, reparser) = find_reparsable_node(self.syntax(), edit.delete)?; | 82 | let (node, reparser) = find_reparsable_node(self.syntax(), edit.delete)?; |
81 | let text = replace_range( | 83 | let text = replace_range( |
82 | node.text(), | 84 | node.text(), |
@@ -87,7 +89,12 @@ impl File { | |||
87 | if !is_balanced(&tokens) { | 89 | if !is_balanced(&tokens) { |
88 | return None; | 90 | return None; |
89 | } | 91 | } |
90 | None | 92 | let (green, new_errors) = parser_impl::parse_with::<yellow::GreenBuilder>( |
93 | &text, &tokens, reparser, | ||
94 | ); | ||
95 | let green_root = node.replace_with(green); | ||
96 | let errors = merge_errors(self.errors(), new_errors, edit, node.range().start()); | ||
97 | Some(File::new(green_root, errors)) | ||
91 | } | 98 | } |
92 | fn full_reparse(&self, edit: &AtomEdit) -> File { | 99 | fn full_reparse(&self, edit: &AtomEdit) -> File { |
93 | let text = replace_range(self.syntax().text(), edit.delete, &edit.insert); | 100 | let text = replace_range(self.syntax().text(), edit.delete, &edit.insert); |
@@ -173,7 +180,7 @@ fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(Syntax | |||
173 | } | 180 | } |
174 | } | 181 | } |
175 | 182 | ||
176 | fn replace_range(mut text: String, range: TextRange, replace_with: &str) -> String { | 183 | pub /*(meh)*/ fn replace_range(mut text: String, range: TextRange, replace_with: &str) -> String { |
177 | let start = u32::from(range.start()) as usize; | 184 | let start = u32::from(range.start()) as usize; |
178 | let end = u32::from(range.end()) as usize; | 185 | let end = u32::from(range.end()) as usize; |
179 | text.replace_range(start..end, replace_with); | 186 | text.replace_range(start..end, replace_with); |
@@ -199,3 +206,29 @@ fn is_balanced(tokens: &[Token]) -> bool { | |||
199 | } | 206 | } |
200 | balance == 0 | 207 | balance == 0 |
201 | } | 208 | } |
209 | |||
210 | fn merge_errors( | ||
211 | old_errors: Vec<SyntaxError>, | ||
212 | new_errors: Vec<SyntaxError>, | ||
213 | edit: &AtomEdit, | ||
214 | node_offset: TextUnit, | ||
215 | ) -> Vec<SyntaxError> { | ||
216 | let mut res = Vec::new(); | ||
217 | for e in old_errors { | ||
218 | if e.offset < edit.delete.start() { | ||
219 | res.push(e) | ||
220 | } else if e.offset > edit.delete.end() { | ||
221 | res.push(SyntaxError { | ||
222 | msg: e.msg, | ||
223 | offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(), | ||
224 | }) | ||
225 | } | ||
226 | } | ||
227 | for e in new_errors { | ||
228 | res.push(SyntaxError { | ||
229 | msg: e.msg, | ||
230 | offset: e.offset + node_offset, | ||
231 | }) | ||
232 | } | ||
233 | res | ||
234 | } | ||
diff --git a/crates/libsyntax2/src/parser_impl/mod.rs b/crates/libsyntax2/src/parser_impl/mod.rs index 14cceced5..f60ef80f0 100644 --- a/crates/libsyntax2/src/parser_impl/mod.rs +++ b/crates/libsyntax2/src/parser_impl/mod.rs | |||
@@ -2,7 +2,6 @@ mod event; | |||
2 | mod input; | 2 | mod input; |
3 | 3 | ||
4 | use { | 4 | use { |
5 | grammar, | ||
6 | lexer::Token, | 5 | lexer::Token, |
7 | parser_api::Parser, | 6 | parser_api::Parser, |
8 | parser_impl::{ | 7 | parser_impl::{ |
@@ -27,12 +26,16 @@ pub(crate) trait Sink<'a> { | |||
27 | } | 26 | } |
28 | 27 | ||
29 | /// Parse a sequence of tokens into the representative node tree | 28 | /// Parse a sequence of tokens into the representative node tree |
30 | pub(crate) fn parse<'a, S: Sink<'a>>(text: &'a str, tokens: &[Token]) -> S::Tree { | 29 | pub(crate) fn parse_with<'a, S: Sink<'a>>( |
30 | text: &'a str, | ||
31 | tokens: &[Token], | ||
32 | parser: fn(&mut Parser), | ||
33 | ) -> S::Tree { | ||
31 | let events = { | 34 | let events = { |
32 | let input = input::ParserInput::new(text, tokens); | 35 | let input = input::ParserInput::new(text, tokens); |
33 | let parser_impl = ParserImpl::new(&input); | 36 | let parser_impl = ParserImpl::new(&input); |
34 | let mut parser_api = Parser(parser_impl); | 37 | let mut parser_api = Parser(parser_impl); |
35 | grammar::file(&mut parser_api); | 38 | parser(&mut parser_api); |
36 | parser_api.0.into_events() | 39 | parser_api.0.into_events() |
37 | }; | 40 | }; |
38 | let mut sink = S::new(text); | 41 | let mut sink = S::new(text); |
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs index 8f1b1d79a..0045598d4 100644 --- a/crates/libsyntax2/src/yellow/syntax.rs +++ b/crates/libsyntax2/src/yellow/syntax.rs | |||
@@ -3,7 +3,7 @@ use std::{fmt, sync::Arc}; | |||
3 | use smol_str::SmolStr; | 3 | use smol_str::SmolStr; |
4 | 4 | ||
5 | use { | 5 | use { |
6 | yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot}, | 6 | yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot}, |
7 | SyntaxKind::{self, *}, | 7 | SyntaxKind::{self, *}, |
8 | TextRange, TextUnit, | 8 | TextRange, TextUnit, |
9 | }; | 9 | }; |
@@ -141,6 +141,27 @@ impl<R: TreeRoot> SyntaxNode<R> { | |||
141 | self.red().green().leaf_text() | 141 | self.red().green().leaf_text() |
142 | } | 142 | } |
143 | 143 | ||
144 | pub(crate) fn replace_with(&self, green: GreenNode) -> GreenNode { | ||
145 | assert_eq!(self.kind(), green.kind()); | ||
146 | match self.parent() { | ||
147 | None => green, | ||
148 | Some(parent) => { | ||
149 | let children: Vec<_> = parent.children().map(|child| { | ||
150 | if child == *self { | ||
151 | green.clone() | ||
152 | } else { | ||
153 | child.red().green().clone() | ||
154 | } | ||
155 | }).collect(); | ||
156 | let new_parent = GreenNode::new_branch( | ||
157 | parent.kind(), | ||
158 | children.into_boxed_slice(), | ||
159 | ); | ||
160 | parent.replace_with(new_parent) | ||
161 | }, | ||
162 | } | ||
163 | } | ||
164 | |||
144 | fn red(&self) -> &RedNode { | 165 | fn red(&self) -> &RedNode { |
145 | unsafe { self.red.get(&self.root) } | 166 | unsafe { self.red.get(&self.root) } |
146 | } | 167 | } |
diff --git a/crates/libsyntax2/tests/test/main.rs b/crates/libsyntax2/tests/test/main.rs index cb8a52c98..e7ae4d601 100644 --- a/crates/libsyntax2/tests/test/main.rs +++ b/crates/libsyntax2/tests/test/main.rs | |||
@@ -9,7 +9,11 @@ use std::{ | |||
9 | fmt::Write, | 9 | fmt::Write, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use libsyntax2::File; | 12 | use test_utils::extract_range; |
13 | use libsyntax2::{ | ||
14 | File, AtomEdit, | ||
15 | utils::dump_tree, | ||
16 | }; | ||
13 | 17 | ||
14 | #[test] | 18 | #[test] |
15 | fn lexer_tests() { | 19 | fn lexer_tests() { |
@@ -23,10 +27,40 @@ fn lexer_tests() { | |||
23 | fn parser_tests() { | 27 | fn parser_tests() { |
24 | dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| { | 28 | dir_tests(&["parser/inline", "parser/ok", "parser/err"], |text| { |
25 | let file = File::parse(text); | 29 | let file = File::parse(text); |
26 | libsyntax2::utils::dump_tree(file.syntax()) | 30 | dump_tree(file.syntax()) |
27 | }) | 31 | }) |
28 | } | 32 | } |
29 | 33 | ||
34 | #[test] | ||
35 | fn reparse_test() { | ||
36 | fn do_check(before: &str, replace_with: &str) { | ||
37 | let (range, before) = extract_range(before); | ||
38 | let after = libsyntax2::replace_range(before.clone(), range, replace_with); | ||
39 | |||
40 | let fully_reparsed = File::parse(&after); | ||
41 | let incrementally_reparsed = { | ||
42 | let f = File::parse(&before); | ||
43 | let edit = AtomEdit { delete: range, insert: replace_with.to_string() }; | ||
44 | f.incremental_reparse(&edit).unwrap() | ||
45 | }; | ||
46 | assert_eq_text!( | ||
47 | &dump_tree(fully_reparsed.syntax()), | ||
48 | &dump_tree(incrementally_reparsed.syntax()), | ||
49 | ) | ||
50 | } | ||
51 | |||
52 | do_check(r" | ||
53 | fn foo() { | ||
54 | let x = foo + <|>bar<|> | ||
55 | } | ||
56 | ", "baz"); | ||
57 | do_check(r" | ||
58 | struct Foo { | ||
59 | f: foo<|><|> | ||
60 | } | ||
61 | ", ",\n g: (),"); | ||
62 | } | ||
63 | |||
30 | 64 | ||
31 | /// Read file and normalize newlines. | 65 | /// Read file and normalize newlines. |
32 | /// | 66 | /// |