diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 22 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 34 | ||||
-rw-r--r-- | crates/ra_syntax/src/syntax_error.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/validation/field_expr.rs | 12 |
6 files changed, 71 insertions, 7 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 | } | ||