Parse and infer tuple indices

This commit is contained in:
robojumper 2019-04-05 22:34:45 +02:00
parent 0372eca5b2
commit ca40ca93a5
13 changed files with 210 additions and 14 deletions

View file

@ -17,7 +17,7 @@ pub use self::{
generated::*,
traits::*,
tokens::*,
extensions::{PathSegmentKind, StructKind, SelfParamKind},
extensions::{PathSegmentKind, StructKind, FieldKind, SelfParamKind},
expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralKind},
};

View file

@ -3,11 +3,8 @@
use itertools::Itertools;
use crate::{
SmolStr, SyntaxToken,
ast::{self, AstNode, children, child_opt},
SyntaxKind::*,
};
use crate::{SmolStr, SyntaxToken, ast::{self, AstNode, children, child_opt}, SyntaxKind::*, SyntaxElement};
use ra_parser::SyntaxKind;
impl ast::Name {
pub fn text(&self) -> &SmolStr {
@ -217,6 +214,33 @@ impl ast::ExprStmt {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FieldKind<'a> {
Name(&'a ast::NameRef),
Index(SyntaxToken<'a>),
}
impl ast::FieldExpr {
pub fn index_token(&self) -> Option<SyntaxToken> {
self.syntax
.children_with_tokens()
// FIXME: Accepting floats here to reject them in validation later
.find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
.as_ref()
.and_then(SyntaxElement::as_token)
}
pub fn field_access(&self) -> Option<FieldKind> {
if let Some(nr) = self.name_ref() {
Some(FieldKind::Name(nr))
} else if let Some(tok) = self.index_token() {
Some(FieldKind::Index(tok))
} else {
None
}
}
}
impl ast::RefPat {
pub fn is_mut(&self) -> bool {
self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)

View file

@ -95,6 +95,7 @@ pub enum SyntaxErrorKind {
InvalidSuffix,
InvalidBlockAttr,
InvalidMatchInnerAttr,
InvalidTupleIndexFormat,
}
impl fmt::Display for SyntaxErrorKind {
@ -139,6 +140,9 @@ impl fmt::Display for SyntaxErrorKind {
InvalidMatchInnerAttr => {
write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
}
InvalidTupleIndexFormat => {
write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix")
}
ParseError(msg) => write!(f, "{}", msg.0),
}
}

View file

@ -3,6 +3,7 @@ mod byte_string;
mod char;
mod string;
mod block;
mod field_expr;
use crate::{
SourceFile, SyntaxError, AstNode, SyntaxNode,
@ -17,6 +18,7 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> {
let _ = visitor_ctx(&mut errors)
.visit::<ast::Literal, _>(validate_literal)
.visit::<ast::Block, _>(block::validate_block_node)
.visit::<ast::FieldExpr, _>(field_expr::validate_field_expr_node)
.accept(node);
}
errors

View file

@ -0,0 +1,12 @@
use crate::{ast::{self, FieldKind},
SyntaxError,
SyntaxErrorKind::*,
};
pub(crate) fn validate_field_expr_node(node: &ast::FieldExpr, errors: &mut Vec<SyntaxError>) {
if let Some(FieldKind::Index(idx)) = node.field_access() {
if idx.text().chars().any(|c| c < '0' || c > '9') {
errors.push(SyntaxError::new(InvalidTupleIndexFormat, idx.range()));
}
}
}

View file

@ -0,0 +1,5 @@
fn foo() {
x.0.;
x.1i32;
x.0x01;
}

View file

@ -0,0 +1,51 @@
SOURCE_FILE@[0; 47)
FN_DEF@[0; 46)
FN_KW@[0; 2) "fn"
WHITESPACE@[2; 3) " "
NAME@[3; 6)
IDENT@[3; 6) "foo"
PARAM_LIST@[6; 8)
L_PAREN@[6; 7) "("
R_PAREN@[7; 8) ")"
WHITESPACE@[8; 9) " "
BLOCK@[9; 46)
L_CURLY@[9; 10) "{"
WHITESPACE@[10; 15) "\n "
EXPR_STMT@[15; 20)
FIELD_EXPR@[15; 19)
PATH_EXPR@[15; 16)
PATH@[15; 16)
PATH_SEGMENT@[15; 16)
NAME_REF@[15; 16)
IDENT@[15; 16) "x"
DOT@[16; 17) "."
err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix`
FLOAT_NUMBER@[17; 19) "0."
SEMI@[19; 20) ";"
WHITESPACE@[20; 25) "\n "
EXPR_STMT@[25; 32)
FIELD_EXPR@[25; 31)
PATH_EXPR@[25; 26)
PATH@[25; 26)
PATH_SEGMENT@[25; 26)
NAME_REF@[25; 26)
IDENT@[25; 26) "x"
DOT@[26; 27) "."
err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix`
INT_NUMBER@[27; 31) "1i32"
SEMI@[31; 32) ";"
WHITESPACE@[32; 37) "\n "
EXPR_STMT@[37; 44)
FIELD_EXPR@[37; 43)
PATH_EXPR@[37; 38)
PATH@[37; 38)
PATH_SEGMENT@[37; 38)
NAME_REF@[37; 38)
IDENT@[37; 38) "x"
DOT@[38; 39) "."
err: `Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix`
INT_NUMBER@[39; 43) "0x01"
SEMI@[43; 44) ";"
WHITESPACE@[44; 45) "\n"
R_CURLY@[45; 46) "}"
WHITESPACE@[46; 47) "\n"

View file

@ -1,4 +1,5 @@
fn foo() {
x.foo;
x.0.bar;
x.0();
}

View file

@ -1,5 +1,5 @@
SOURCE_FILE@[0; 37)
FN_DEF@[0; 36)
SOURCE_FILE@[0; 48)
FN_DEF@[0; 47)
FN_KW@[0; 2) "fn"
WHITESPACE@[2; 3) " "
NAME@[3; 6)
@ -8,7 +8,7 @@ SOURCE_FILE@[0; 37)
L_PAREN@[6; 7) "("
R_PAREN@[7; 8) ")"
WHITESPACE@[8; 9) " "
BLOCK@[9; 36)
BLOCK@[9; 47)
L_CURLY@[9; 10) "{"
WHITESPACE@[10; 15) "\n "
EXPR_STMT@[15; 21)
@ -37,6 +37,21 @@ SOURCE_FILE@[0; 37)
NAME_REF@[30; 33)
IDENT@[30; 33) "bar"
SEMI@[33; 34) ";"
WHITESPACE@[34; 35) "\n"
R_CURLY@[35; 36) "}"
WHITESPACE@[36; 37) "\n"
WHITESPACE@[34; 39) "\n "
EXPR_STMT@[39; 45)
CALL_EXPR@[39; 44)
FIELD_EXPR@[39; 42)
PATH_EXPR@[39; 40)
PATH@[39; 40)
PATH_SEGMENT@[39; 40)
NAME_REF@[39; 40)
IDENT@[39; 40) "x"
DOT@[40; 41) "."
INT_NUMBER@[41; 42) "0"
ARG_LIST@[42; 44)
L_PAREN@[42; 43) "("
R_PAREN@[43; 44) ")"
SEMI@[44; 45) ";"
WHITESPACE@[45; 46) "\n"
R_CURLY@[46; 47) "}"
WHITESPACE@[47; 48) "\n"