diff options
Diffstat (limited to 'crates/syntax/src')
-rw-r--r-- | crates/syntax/src/parsing/lexer.rs | 23 | ||||
-rw-r--r-- | crates/syntax/src/ptr.rs | 2 | ||||
-rw-r--r-- | crates/syntax/src/validation.rs | 45 |
3 files changed, 59 insertions, 11 deletions
diff --git a/crates/syntax/src/parsing/lexer.rs b/crates/syntax/src/parsing/lexer.rs index f1202113b..7e38c32cc 100644 --- a/crates/syntax/src/parsing/lexer.rs +++ b/crates/syntax/src/parsing/lexer.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | //! Lexer analyzes raw input string and produces lexemes (tokens). | 1 | //! Lexer analyzes raw input string and produces lexemes (tokens). |
2 | //! It is just a bridge to `rustc_lexer`. | 2 | //! It is just a bridge to `rustc_lexer`. |
3 | 3 | ||
4 | use rustc_lexer::{LiteralKind as LK, RawStrError}; | ||
5 | |||
6 | use std::convert::TryInto; | 4 | use std::convert::TryInto; |
7 | 5 | ||
6 | use rustc_lexer::{LiteralKind as LK, RawStrError}; | ||
7 | |||
8 | use crate::{ | 8 | use crate::{ |
9 | SyntaxError, | 9 | SyntaxError, |
10 | SyntaxKind::{self, *}, | 10 | SyntaxKind::{self, *}, |
@@ -61,17 +61,18 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) { | |||
61 | (tokens, errors) | 61 | (tokens, errors) |
62 | } | 62 | } |
63 | 63 | ||
64 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token | 64 | /// Returns `SyntaxKind` and `Option<SyntaxError>` if `text` parses as a single token. |
65 | /// encountered at the beginning of the string. | ||
66 | /// | 65 | /// |
67 | /// Returns `None` if the string contains zero *or two or more* tokens. | 66 | /// Returns `None` if the string contains zero *or two or more* tokens. |
68 | /// The token is malformed if the returned error is not `None`. | 67 | /// The token is malformed if the returned error is not `None`. |
69 | /// | 68 | /// |
70 | /// Beware that unescape errors are not checked at tokenization time. | 69 | /// Beware that unescape errors are not checked at tokenization time. |
71 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { | 70 | pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> { |
72 | lex_first_token(text) | 71 | let (first_token, err) = lex_first_token(text)?; |
73 | .filter(|(token, _)| token.len == TextSize::of(text)) | 72 | if first_token.len != TextSize::of(text) { |
74 | .map(|(token, error)| (token.kind, error)) | 73 | return None; |
74 | } | ||
75 | Some((first_token.kind, err)) | ||
75 | } | 76 | } |
76 | 77 | ||
77 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and | 78 | /// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and |
@@ -79,9 +80,11 @@ pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxEr | |||
79 | /// | 80 | /// |
80 | /// Beware that unescape errors are not checked at tokenization time. | 81 | /// Beware that unescape errors are not checked at tokenization time. |
81 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { | 82 | pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> { |
82 | lex_first_token(text) | 83 | let (single_token, err) = lex_single_syntax_kind(text)?; |
83 | .filter(|(token, error)| !error.is_some() && token.len == TextSize::of(text)) | 84 | if err.is_some() { |
84 | .map(|(token, _error)| token.kind) | 85 | return None; |
86 | } | ||
87 | Some(single_token) | ||
85 | } | 88 | } |
86 | 89 | ||
87 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token | 90 | /// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token |
diff --git a/crates/syntax/src/ptr.rs b/crates/syntax/src/ptr.rs index ca7957747..d3fb7a5d9 100644 --- a/crates/syntax/src/ptr.rs +++ b/crates/syntax/src/ptr.rs | |||
@@ -12,6 +12,8 @@ use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; | |||
12 | /// specific node across reparses of the same file. | 12 | /// specific node across reparses of the same file. |
13 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 13 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
14 | pub struct SyntaxNodePtr { | 14 | pub struct SyntaxNodePtr { |
15 | // Don't expose this field further. At some point, we might want to replace | ||
16 | // range with node id. | ||
15 | pub(crate) range: TextRange, | 17 | pub(crate) range: TextRange, |
16 | kind: SyntaxKind, | 18 | kind: SyntaxKind, |
17 | } | 19 | } |
diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 2dddaf09a..0f9a5e8ae 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs | |||
@@ -3,10 +3,11 @@ | |||
3 | mod block; | 3 | mod block; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | ast, match_ast, AstNode, SyntaxError, | 6 | algo, ast, match_ast, AstNode, SyntaxError, |
7 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS}, | 7 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST, FN, INT_NUMBER, STRING, TYPE_ALIAS}, |
8 | SyntaxNode, SyntaxToken, TextSize, T, | 8 | SyntaxNode, SyntaxToken, TextSize, T, |
9 | }; | 9 | }; |
10 | use rowan::Direction; | ||
10 | use rustc_lexer::unescape::{ | 11 | use rustc_lexer::unescape::{ |
11 | self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, | 12 | self, unescape_byte, unescape_byte_literal, unescape_char, unescape_literal, Mode, |
12 | }; | 13 | }; |
@@ -95,6 +96,9 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
95 | ast::Visibility(it) => validate_visibility(it, &mut errors), | 96 | ast::Visibility(it) => validate_visibility(it, &mut errors), |
96 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), | 97 | ast::RangeExpr(it) => validate_range_expr(it, &mut errors), |
97 | ast::PathSegment(it) => validate_path_keywords(it, &mut errors), | 98 | ast::PathSegment(it) => validate_path_keywords(it, &mut errors), |
99 | ast::RefType(it) => validate_trait_object_ref_ty(it, &mut errors), | ||
100 | ast::PtrType(it) => validate_trait_object_ptr_ty(it, &mut errors), | ||
101 | ast::FnPtrType(it) => validate_trait_object_fn_ptr_ret_ty(it, &mut errors), | ||
98 | _ => (), | 102 | _ => (), |
99 | } | 103 | } |
100 | } | 104 | } |
@@ -301,3 +305,42 @@ fn validate_path_keywords(segment: ast::PathSegment, errors: &mut Vec<SyntaxErro | |||
301 | return true; | 305 | return true; |
302 | } | 306 | } |
303 | } | 307 | } |
308 | |||
309 | fn validate_trait_object_ref_ty(ty: ast::RefType, errors: &mut Vec<SyntaxError>) { | ||
310 | if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { | ||
311 | if let Some(err) = validate_trait_object_ty(ty) { | ||
312 | errors.push(err); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | fn validate_trait_object_ptr_ty(ty: ast::PtrType, errors: &mut Vec<SyntaxError>) { | ||
318 | if let Some(ast::Type::DynTraitType(ty)) = ty.ty() { | ||
319 | if let Some(err) = validate_trait_object_ty(ty) { | ||
320 | errors.push(err); | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | |||
325 | fn validate_trait_object_fn_ptr_ret_ty(ty: ast::FnPtrType, errors: &mut Vec<SyntaxError>) { | ||
326 | if let Some(ast::Type::DynTraitType(ty)) = ty.ret_type().and_then(|ty| ty.ty()) { | ||
327 | if let Some(err) = validate_trait_object_ty(ty) { | ||
328 | errors.push(err); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | |||
333 | fn validate_trait_object_ty(ty: ast::DynTraitType) -> Option<SyntaxError> { | ||
334 | let tbl = ty.type_bound_list()?; | ||
335 | |||
336 | if tbl.bounds().count() > 1 { | ||
337 | let dyn_token = ty.dyn_token()?; | ||
338 | let potential_parentheses = | ||
339 | algo::skip_trivia_token(dyn_token.prev_token()?, Direction::Prev)?; | ||
340 | let kind = potential_parentheses.kind(); | ||
341 | if !matches!(kind, T!['('] | T![<] | T![=]) { | ||
342 | return Some(SyntaxError::new("ambiguous `+` in a type", ty.syntax().text_range())); | ||
343 | } | ||
344 | } | ||
345 | None | ||
346 | } | ||