diff options
Diffstat (limited to 'crates/ra_syntax')
10 files changed, 149 insertions, 13 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index 9f5c41b0c..c2ab19d97 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -17,8 +17,8 @@ pub use self::{ | |||
17 | generated::*, | 17 | generated::*, |
18 | traits::*, | 18 | traits::*, |
19 | tokens::*, | 19 | tokens::*, |
20 | extensions::{PathSegmentKind, StructKind, SelfParamKind}, | 20 | extensions::{PathSegmentKind, StructKind,FieldKind, SelfParamKind}, |
21 | expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind}, | 21 | expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind,ArrayExprKind}, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The | 24 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 1d8313810..9484c3b9b 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -193,6 +193,28 @@ impl ast::BinExpr { | |||
193 | } | 193 | } |
194 | } | 194 | } |
195 | 195 | ||
196 | pub enum ArrayExprKind<'a> { | ||
197 | Repeat { initializer: Option<&'a ast::Expr>, repeat: Option<&'a ast::Expr> }, | ||
198 | ElementList(AstChildren<'a, ast::Expr>), | ||
199 | } | ||
200 | |||
201 | impl ast::ArrayExpr { | ||
202 | pub fn kind(&self) -> ArrayExprKind { | ||
203 | if self.is_repeat() { | ||
204 | ArrayExprKind::Repeat { | ||
205 | initializer: children(self).nth(0), | ||
206 | repeat: children(self).nth(1), | ||
207 | } | ||
208 | } else { | ||
209 | ArrayExprKind::ElementList(children(self)) | ||
210 | } | ||
211 | } | ||
212 | |||
213 | fn is_repeat(&self) -> bool { | ||
214 | self.syntax().children_with_tokens().any(|it| it.kind() == SEMI) | ||
215 | } | ||
216 | } | ||
217 | |||
196 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 218 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
197 | pub enum LiteralKind { | 219 | pub enum LiteralKind { |
198 | String, | 220 | String, |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index aec57c380..ca33b43e7 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -3,11 +3,8 @@ | |||
3 | 3 | ||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{SmolStr, SyntaxToken, ast::{self, AstNode, children, child_opt}, SyntaxKind::*, SyntaxElement}; |
7 | SmolStr, SyntaxToken, | 7 | use ra_parser::SyntaxKind; |
8 | ast::{self, AstNode, children, child_opt}, | ||
9 | SyntaxKind::*, | ||
10 | }; | ||
11 | 8 | ||
12 | impl ast::Name { | 9 | impl ast::Name { |
13 | pub fn text(&self) -> &SmolStr { | 10 | pub fn text(&self) -> &SmolStr { |
@@ -217,6 +214,33 @@ impl ast::ExprStmt { | |||
217 | } | 214 | } |
218 | } | 215 | } |
219 | 216 | ||
217 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
218 | pub enum FieldKind<'a> { | ||
219 | Name(&'a ast::NameRef), | ||
220 | Index(SyntaxToken<'a>), | ||
221 | } | ||
222 | |||
223 | impl ast::FieldExpr { | ||
224 | pub fn index_token(&self) -> Option<SyntaxToken> { | ||
225 | self.syntax | ||
226 | .children_with_tokens() | ||
227 | // FIXME: Accepting floats here to reject them in validation later | ||
228 | .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER) | ||
229 | .as_ref() | ||
230 | .and_then(SyntaxElement::as_token) | ||
231 | } | ||
232 | |||
233 | pub fn field_access(&self) -> Option<FieldKind> { | ||
234 | if let Some(nr) = self.name_ref() { | ||
235 | Some(FieldKind::Name(nr)) | ||
236 | } else if let Some(tok) = self.index_token() { | ||
237 | Some(FieldKind::Index(tok)) | ||
238 | } else { | ||
239 | None | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
220 | impl ast::RefPat { | 244 | impl ast::RefPat { |
221 | pub fn is_mut(&self) -> bool { | 245 | pub fn is_mut(&self) -> bool { |
222 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | 246 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) |
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs index 4b8c22a57..4198eefdb 100644 --- a/crates/ra_syntax/src/syntax_error.rs +++ b/crates/ra_syntax/src/syntax_error.rs | |||
@@ -95,6 +95,7 @@ pub enum SyntaxErrorKind { | |||
95 | InvalidSuffix, | 95 | InvalidSuffix, |
96 | InvalidBlockAttr, | 96 | InvalidBlockAttr, |
97 | InvalidMatchInnerAttr, | 97 | InvalidMatchInnerAttr, |
98 | InvalidTupleIndexFormat, | ||
98 | } | 99 | } |
99 | 100 | ||
100 | impl fmt::Display for SyntaxErrorKind { | 101 | impl fmt::Display for SyntaxErrorKind { |
@@ -139,6 +140,9 @@ impl fmt::Display for SyntaxErrorKind { | |||
139 | InvalidMatchInnerAttr => { | 140 | InvalidMatchInnerAttr => { |
140 | write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression") | 141 | write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression") |
141 | } | 142 | } |
143 | InvalidTupleIndexFormat => { | ||
144 | write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix") | ||
145 | } | ||
142 | ParseError(msg) => write!(f, "{}", msg.0), | 146 | ParseError(msg) => write!(f, "{}", msg.0), |
143 | } | 147 | } |
144 | } | 148 | } |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index fc534df83..c2f545173 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -3,6 +3,7 @@ mod byte_string; | |||
3 | mod char; | 3 | mod char; |
4 | mod string; | 4 | mod string; |
5 | mod block; | 5 | mod block; |
6 | mod field_expr; | ||
6 | 7 | ||
7 | use crate::{ | 8 | use crate::{ |
8 | SourceFile, SyntaxError, AstNode, SyntaxNode, | 9 | SourceFile, SyntaxError, AstNode, SyntaxNode, |
@@ -17,6 +18,7 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> { | |||
17 | let _ = visitor_ctx(&mut errors) | 18 | let _ = visitor_ctx(&mut errors) |
18 | .visit::<ast::Literal, _>(validate_literal) | 19 | .visit::<ast::Literal, _>(validate_literal) |
19 | .visit::<ast::Block, _>(block::validate_block_node) | 20 | .visit::<ast::Block, _>(block::validate_block_node) |
21 | .visit::<ast::FieldExpr, _>(field_expr::validate_field_expr_node) | ||
20 | .accept(node); | 22 | .accept(node); |
21 | } | 23 | } |
22 | errors | 24 | errors |
diff --git a/crates/ra_syntax/src/validation/field_expr.rs b/crates/ra_syntax/src/validation/field_expr.rs new file mode 100644 index 000000000..2b405062e --- /dev/null +++ b/crates/ra_syntax/src/validation/field_expr.rs | |||
@@ -0,0 +1,12 @@ | |||
1 | use crate::{ast::{self, FieldKind}, | ||
2 | SyntaxError, | ||
3 | SyntaxErrorKind::*, | ||
4 | }; | ||
5 | |||
6 | pub(crate) fn validate_field_expr_node(node: &ast::FieldExpr, errors: &mut Vec<SyntaxError>) { | ||
7 | if let Some(FieldKind::Index(idx)) = node.field_access() { | ||
8 | if idx.text().chars().any(|c| c < '0' || c > '9') { | ||
9 | errors.push(SyntaxError::new(InvalidTupleIndexFormat, idx.range())); | ||
10 | } | ||
11 | } | ||
12 | } | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.rs b/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.rs new file mode 100644 index 000000000..30cc49138 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.rs | |||
@@ -0,0 +1,5 @@ | |||
1 | fn foo() { | ||
2 | x.0.; | ||
3 | x.1i32; | ||
4 | x.0x01; | ||
5 | } | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.txt b/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.txt new file mode 100644 index 000000000..c111f60ea --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0010_bad_tuple_index_expr.txt | |||
@@ -0,0 +1,51 @@ | |||
1 | SOURCE_FILE@[0; 47) | ||
2 | FN_DEF@[0; 46) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) "(" | ||
9 | R_PAREN@[7; 8) ")" | ||
10 | WHITESPACE@[8; 9) " " | ||
11 | BLOCK@[9; 46) | ||
12 | L_CURLY@[9; 10) "{" | ||
13 | WHITESPACE@[10; 15) "\n " | ||
14 | EXPR_STMT@[15; 20) | ||
15 | FIELD_EXPR@[15; 19) | ||
16 | PATH_EXPR@[15; 16) | ||
17 | PATH@[15; 16) | ||
18 | PATH_SEGMENT@[15; 16) | ||
19 | NAME_REF@[15; 16) | ||
20 | IDENT@[15; 16) "x" | ||
21 | DOT@[16; 17) "." | ||
22 | err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix` | ||
23 | FLOAT_NUMBER@[17; 19) "0." | ||
24 | SEMI@[19; 20) ";" | ||
25 | WHITESPACE@[20; 25) "\n " | ||
26 | EXPR_STMT@[25; 32) | ||
27 | FIELD_EXPR@[25; 31) | ||
28 | PATH_EXPR@[25; 26) | ||
29 | PATH@[25; 26) | ||
30 | PATH_SEGMENT@[25; 26) | ||
31 | NAME_REF@[25; 26) | ||
32 | IDENT@[25; 26) "x" | ||
33 | DOT@[26; 27) "." | ||
34 | err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix` | ||
35 | INT_NUMBER@[27; 31) "1i32" | ||
36 | SEMI@[31; 32) ";" | ||
37 | WHITESPACE@[32; 37) "\n " | ||
38 | EXPR_STMT@[37; 44) | ||
39 | FIELD_EXPR@[37; 43) | ||
40 | PATH_EXPR@[37; 38) | ||
41 | PATH@[37; 38) | ||
42 | PATH_SEGMENT@[37; 38) | ||
43 | NAME_REF@[37; 38) | ||
44 | IDENT@[37; 38) "x" | ||
45 | DOT@[38; 39) "." | ||
46 | err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix` | ||
47 | INT_NUMBER@[39; 43) "0x01" | ||
48 | SEMI@[43; 44) ";" | ||
49 | WHITESPACE@[44; 45) "\n" | ||
50 | R_CURLY@[45; 46) "}" | ||
51 | WHITESPACE@[46; 47) "\n" | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.rs index 3e69538e5..b8da2ddc3 100644 --- a/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.rs +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | fn foo() { | 1 | fn foo() { |
2 | x.foo; | 2 | x.foo; |
3 | x.0.bar; | 3 | x.0.bar; |
4 | x.0(); | ||
4 | } | 5 | } |
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.txt index a86702843..78054ec5a 100644 --- a/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.txt +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.txt | |||
@@ -1,5 +1,5 @@ | |||
1 | SOURCE_FILE@[0; 37) | 1 | SOURCE_FILE@[0; 48) |
2 | FN_DEF@[0; 36) | 2 | FN_DEF@[0; 47) |
3 | FN_KW@[0; 2) "fn" | 3 | FN_KW@[0; 2) "fn" |
4 | WHITESPACE@[2; 3) " " | 4 | WHITESPACE@[2; 3) " " |
5 | NAME@[3; 6) | 5 | NAME@[3; 6) |
@@ -8,7 +8,7 @@ SOURCE_FILE@[0; 37) | |||
8 | L_PAREN@[6; 7) "(" | 8 | L_PAREN@[6; 7) "(" |
9 | R_PAREN@[7; 8) ")" | 9 | R_PAREN@[7; 8) ")" |
10 | WHITESPACE@[8; 9) " " | 10 | WHITESPACE@[8; 9) " " |
11 | BLOCK@[9; 36) | 11 | BLOCK@[9; 47) |
12 | L_CURLY@[9; 10) "{" | 12 | L_CURLY@[9; 10) "{" |
13 | WHITESPACE@[10; 15) "\n " | 13 | WHITESPACE@[10; 15) "\n " |
14 | EXPR_STMT@[15; 21) | 14 | EXPR_STMT@[15; 21) |
@@ -37,6 +37,21 @@ SOURCE_FILE@[0; 37) | |||
37 | NAME_REF@[30; 33) | 37 | NAME_REF@[30; 33) |
38 | IDENT@[30; 33) "bar" | 38 | IDENT@[30; 33) "bar" |
39 | SEMI@[33; 34) ";" | 39 | SEMI@[33; 34) ";" |
40 | WHITESPACE@[34; 35) "\n" | 40 | WHITESPACE@[34; 39) "\n " |
41 | R_CURLY@[35; 36) "}" | 41 | EXPR_STMT@[39; 45) |
42 | WHITESPACE@[36; 37) "\n" | 42 | CALL_EXPR@[39; 44) |
43 | FIELD_EXPR@[39; 42) | ||
44 | PATH_EXPR@[39; 40) | ||
45 | PATH@[39; 40) | ||
46 | PATH_SEGMENT@[39; 40) | ||
47 | NAME_REF@[39; 40) | ||
48 | IDENT@[39; 40) "x" | ||
49 | DOT@[40; 41) "." | ||
50 | INT_NUMBER@[41; 42) "0" | ||
51 | ARG_LIST@[42; 44) | ||
52 | L_PAREN@[42; 43) "(" | ||
53 | R_PAREN@[43; 44) ")" | ||
54 | SEMI@[44; 45) ";" | ||
55 | WHITESPACE@[45; 46) "\n" | ||
56 | R_CURLY@[46; 47) "}" | ||
57 | WHITESPACE@[47; 48) "\n" | ||