diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/lib.rs | 35 | ||||
-rw-r--r-- | crates/ra_syntax/src/parsing.rs | 32 | ||||
-rw-r--r-- | crates/ra_syntax/src/tests.rs | 66 |
3 files changed, 132 insertions, 1 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index a33a35cc1..9b7664576 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs | |||
@@ -168,6 +168,41 @@ impl SourceFile { | |||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | impl ast::Path { | ||
172 | /// Returns `text`, parsed as a path, but only if it has no errors. | ||
173 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
174 | parsing::parse_text_fragment(text, ra_parser::FragmentKind::Path) | ||
175 | } | ||
176 | } | ||
177 | |||
178 | impl ast::Pat { | ||
179 | /// Returns `text`, parsed as a pattern, but only if it has no errors. | ||
180 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
181 | parsing::parse_text_fragment(text, ra_parser::FragmentKind::Pattern) | ||
182 | } | ||
183 | } | ||
184 | |||
185 | impl ast::Expr { | ||
186 | /// Returns `text`, parsed as an expression, but only if it has no errors. | ||
187 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
188 | parsing::parse_text_fragment(text, ra_parser::FragmentKind::Expr) | ||
189 | } | ||
190 | } | ||
191 | |||
192 | impl ast::ModuleItem { | ||
193 | /// Returns `text`, parsed as an item, but only if it has no errors. | ||
194 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
195 | parsing::parse_text_fragment(text, ra_parser::FragmentKind::Item) | ||
196 | } | ||
197 | } | ||
198 | |||
199 | impl ast::TypeRef { | ||
200 | /// Returns `text`, parsed as an type reference, but only if it has no errors. | ||
201 | pub fn parse(text: &str) -> Result<Self, ()> { | ||
202 | parsing::parse_text_fragment(text, ra_parser::FragmentKind::Type) | ||
203 | } | ||
204 | } | ||
205 | |||
171 | /// Matches a `SyntaxNode` against an `ast` type. | 206 | /// Matches a `SyntaxNode` against an `ast` type. |
172 | /// | 207 | /// |
173 | /// # Example: | 208 | /// # Example: |
diff --git a/crates/ra_syntax/src/parsing.rs b/crates/ra_syntax/src/parsing.rs index e5eb80850..0ed3c20ef 100644 --- a/crates/ra_syntax/src/parsing.rs +++ b/crates/ra_syntax/src/parsing.rs | |||
@@ -6,13 +6,14 @@ mod text_token_source; | |||
6 | mod text_tree_sink; | 6 | mod text_tree_sink; |
7 | mod reparsing; | 7 | mod reparsing; |
8 | 8 | ||
9 | use crate::{syntax_node::GreenNode, SyntaxError}; | 9 | use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode}; |
10 | use text_token_source::TextTokenSource; | 10 | use text_token_source::TextTokenSource; |
11 | use text_tree_sink::TextTreeSink; | 11 | use text_tree_sink::TextTreeSink; |
12 | 12 | ||
13 | pub use lexer::*; | 13 | pub use lexer::*; |
14 | 14 | ||
15 | pub(crate) use self::reparsing::incremental_reparse; | 15 | pub(crate) use self::reparsing::incremental_reparse; |
16 | use ra_parser::SyntaxKind; | ||
16 | 17 | ||
17 | pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) { | 18 | pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) { |
18 | let (tokens, lexer_errors) = tokenize(&text); | 19 | let (tokens, lexer_errors) = tokenize(&text); |
@@ -27,3 +28,32 @@ pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) { | |||
27 | 28 | ||
28 | (tree, parser_errors) | 29 | (tree, parser_errors) |
29 | } | 30 | } |
31 | |||
32 | /// Returns `text` parsed as a `T` provided there are no parse errors. | ||
33 | pub(crate) fn parse_text_fragment<T: AstNode>( | ||
34 | text: &str, | ||
35 | fragment_kind: ra_parser::FragmentKind, | ||
36 | ) -> Result<T, ()> { | ||
37 | let (tokens, lexer_errors) = tokenize(&text); | ||
38 | if !lexer_errors.is_empty() { | ||
39 | return Err(()); | ||
40 | } | ||
41 | |||
42 | let mut token_source = TextTokenSource::new(text, &tokens); | ||
43 | let mut tree_sink = TextTreeSink::new(text, &tokens); | ||
44 | |||
45 | // TextTreeSink assumes that there's at least some root node to which it can attach errors and | ||
46 | // tokens. We arbitrarily give it a SourceFile. | ||
47 | use ra_parser::TreeSink; | ||
48 | tree_sink.start_node(SyntaxKind::SOURCE_FILE); | ||
49 | ra_parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind); | ||
50 | tree_sink.finish_node(); | ||
51 | |||
52 | let (tree, parser_errors) = tree_sink.finish(); | ||
53 | use ra_parser::TokenSource; | ||
54 | if !parser_errors.is_empty() || token_source.current().kind != SyntaxKind::EOF { | ||
55 | return Err(()); | ||
56 | } | ||
57 | |||
58 | SyntaxNode::new_root(tree).first_child().and_then(T::cast).ok_or(()) | ||
59 | } | ||
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs index aee57db62..959967b79 100644 --- a/crates/ra_syntax/src/tests.rs +++ b/crates/ra_syntax/src/tests.rs | |||
@@ -55,6 +55,51 @@ fn parser_tests() { | |||
55 | } | 55 | } |
56 | 56 | ||
57 | #[test] | 57 | #[test] |
58 | fn expr_parser_tests() { | ||
59 | fragment_parser_dir_test( | ||
60 | &["parser/fragments/expr/ok"], | ||
61 | &["parser/fragments/expr/err"], | ||
62 | crate::ast::Expr::parse, | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn path_parser_tests() { | ||
68 | fragment_parser_dir_test( | ||
69 | &["parser/fragments/path/ok"], | ||
70 | &["parser/fragments/path/err"], | ||
71 | crate::ast::Path::parse, | ||
72 | ); | ||
73 | } | ||
74 | |||
75 | #[test] | ||
76 | fn pattern_parser_tests() { | ||
77 | fragment_parser_dir_test( | ||
78 | &["parser/fragments/pattern/ok"], | ||
79 | &["parser/fragments/pattern/err"], | ||
80 | crate::ast::Pat::parse, | ||
81 | ); | ||
82 | } | ||
83 | |||
84 | #[test] | ||
85 | fn item_parser_tests() { | ||
86 | fragment_parser_dir_test( | ||
87 | &["parser/fragments/item/ok"], | ||
88 | &["parser/fragments/item/err"], | ||
89 | crate::ast::ModuleItem::parse, | ||
90 | ); | ||
91 | } | ||
92 | |||
93 | #[test] | ||
94 | fn type_parser_tests() { | ||
95 | fragment_parser_dir_test( | ||
96 | &["parser/fragments/type/ok"], | ||
97 | &["parser/fragments/type/err"], | ||
98 | crate::ast::TypeRef::parse, | ||
99 | ); | ||
100 | } | ||
101 | |||
102 | #[test] | ||
58 | fn parser_fuzz_tests() { | 103 | fn parser_fuzz_tests() { |
59 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { | 104 | for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) { |
60 | fuzz::check_parser(&text) | 105 | fuzz::check_parser(&text) |
@@ -134,3 +179,24 @@ fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) | |||
134 | } | 179 | } |
135 | acc | 180 | acc |
136 | } | 181 | } |
182 | |||
183 | fn fragment_parser_dir_test<T, F>(ok_paths: &[&str], err_paths: &[&str], f: F) | ||
184 | where | ||
185 | T: crate::AstNode, | ||
186 | F: Fn(&str) -> Result<T, ()>, | ||
187 | { | ||
188 | dir_tests(&test_data_dir(), ok_paths, "rast", |text, path| { | ||
189 | if let Ok(node) = f(text) { | ||
190 | format!("{:#?}", crate::ast::AstNode::syntax(&node)) | ||
191 | } else { | ||
192 | panic!("Failed to parse '{:?}'", path); | ||
193 | } | ||
194 | }); | ||
195 | dir_tests(&test_data_dir(), err_paths, "rast", |text, path| { | ||
196 | if let Ok(_) = f(text) { | ||
197 | panic!("'{:?}' successfully parsed when it should have errored", path); | ||
198 | } else { | ||
199 | "ERROR\n".to_owned() | ||
200 | } | ||
201 | }); | ||
202 | } | ||