From 9e213385c9d06db3c8ca20812779e2b8f8ad2c71 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 30 Mar 2019 13:25:53 +0300 Subject: switch to new rowan --- crates/ra_syntax/Cargo.toml | 2 +- crates/ra_syntax/src/algo.rs | 41 +- crates/ra_syntax/src/ast.rs | 246 ++++++++---- crates/ra_syntax/src/ast/generated.rs | 527 +------------------------ crates/ra_syntax/src/grammar.ron | 35 +- crates/ra_syntax/src/lib.rs | 34 +- crates/ra_syntax/src/parsing/reparsing.rs | 142 ++++--- crates/ra_syntax/src/parsing/text_tree_sink.rs | 28 +- crates/ra_syntax/src/syntax_node.rs | 287 ++++++++++++-- crates/ra_syntax/src/syntax_text.rs | 15 +- crates/ra_syntax/src/validation.rs | 18 +- crates/ra_syntax/src/validation/byte.rs | 6 +- crates/ra_syntax/src/validation/byte_string.rs | 6 +- crates/ra_syntax/src/validation/char.rs | 6 +- crates/ra_syntax/src/validation/string.rs | 6 +- 15 files changed, 599 insertions(+), 800 deletions(-) (limited to 'crates/ra_syntax') diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 7e70dad3f..1a763fb47 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml @@ -13,7 +13,7 @@ unicode-xid = "0.1.0" itertools = "0.8.0" drop_bomb = "0.1.4" parking_lot = "0.7.0" -rowan = "0.3.3" +rowan = "0.4.0" # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here # to reduce number of compilations diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index e2b4f0388..06b45135c 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -1,18 +1,14 @@ pub mod visit; -use rowan::TransparentNewType; +use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction, SyntaxToken, SyntaxElement}; -use crate::{SyntaxNode, TextRange, TextUnit, AstNode, Direction}; +pub use rowan::TokenAtOffset; -pub use rowan::LeafAtOffset; - -pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset<&SyntaxNode> { - match node.0.leaf_at_offset(offset) { - LeafAtOffset::None => LeafAtOffset::None, - LeafAtOffset::Single(n) => LeafAtOffset::Single(SyntaxNode::from_repr(n)), - LeafAtOffset::Between(l, r) => { - LeafAtOffset::Between(SyntaxNode::from_repr(l), SyntaxNode::from_repr(r)) - } +pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset { + match node.0.token_at_offset(offset) { + TokenAtOffset::None => TokenAtOffset::None, + TokenAtOffset::Single(n) => TokenAtOffset::Single(n.into()), + TokenAtOffset::Between(l, r) => TokenAtOffset::Between(l.into(), r.into()), } } @@ -26,16 +22,29 @@ pub fn find_leaf_at_offset(node: &SyntaxNode, offset: TextUnit) -> LeafAtOffset< /// /// then the left node will be silently preferred. pub fn find_node_at_offset(syntax: &SyntaxNode, offset: TextUnit) -> Option<&N> { - find_leaf_at_offset(syntax, offset).find_map(|leaf| leaf.ancestors().find_map(N::cast)) + find_token_at_offset(syntax, offset) + .find_map(|leaf| leaf.parent().ancestors().find_map(N::cast)) } /// Finds the first sibling in the given direction which is not `trivia` -pub fn non_trivia_sibling(node: &SyntaxNode, direction: Direction) -> Option<&SyntaxNode> { - node.siblings(direction).skip(1).find(|node| !node.kind().is_trivia()) +pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option { + return match element { + SyntaxElement::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), + SyntaxElement::Token(token) => { + token.siblings_with_tokens(direction).skip(1).find(not_trivia) + } + }; + + fn not_trivia(element: &SyntaxElement) -> bool { + match element { + SyntaxElement::Node(_) => true, + SyntaxElement::Token(token) => !token.kind().is_trivia(), + } + } } -pub fn find_covering_node(root: &SyntaxNode, range: TextRange) -> &SyntaxNode { - SyntaxNode::from_repr(root.0.covering_node(range)) +pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { + root.0.covering_node(range).into() } // Replace with `std::iter::successors` in `1.34.0` diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index fd7e63f84..9a44afc67 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -7,7 +7,7 @@ use itertools::Itertools; pub use self::generated::*; use crate::{ - syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, + syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren}, SmolStr, SyntaxKind::*, }; @@ -27,7 +27,8 @@ pub trait AstNode: pub trait AstToken: AstNode { fn text(&self) -> &SmolStr { - self.syntax().leaf_text().unwrap() + // self.syntax().leaf_text().unwrap() + unimplemented!() } } @@ -126,8 +127,8 @@ pub trait AttrsOwner: AstNode { } pub trait DocCommentsOwner: AstNode { - fn doc_comments(&self) -> AstChildren { - children(self) + fn doc_comments(&self) -> CommentIter { + CommentIter { iter: self.syntax().children_with_tokens() } } /// Returns the textual content of a doc comment block as a single string. @@ -179,9 +180,9 @@ impl Attr { pub fn as_atom(&self) -> Option { let tt = self.value()?; - let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; + let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; if attr.kind() == IDENT { - Some(attr.leaf_text().unwrap().clone()) + Some(attr.as_token()?.text().clone()) } else { None } @@ -189,10 +190,10 @@ impl Attr { pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { let tt = self.value()?; - let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; - let args = TokenTree::cast(args)?; + let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; + let args = TokenTree::cast(args.as_node()?)?; if attr.kind() == IDENT { - Some((attr.leaf_text().unwrap().clone(), args)) + Some((attr.as_token()?.text().clone(), args)) } else { None } @@ -200,16 +201,35 @@ impl Attr { pub fn as_named(&self) -> Option { let tt = self.value()?; - let attr = tt.syntax().children().nth(1)?; + let attr = tt.syntax().children_with_tokens().nth(1)?; if attr.kind() == IDENT { - Some(attr.leaf_text().unwrap().clone()) + Some(attr.as_token()?.text().clone()) } else { None } } } -impl Comment { +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Comment<'a>(SyntaxToken<'a>); + +impl<'a> Comment<'a> { + pub fn cast(token: SyntaxToken<'a>) -> Option { + if token.kind() == COMMENT { + Some(Comment(token)) + } else { + None + } + } + + pub fn syntax(&self) -> SyntaxToken<'a> { + self.0 + } + + pub fn text(&self) -> &'a SmolStr { + self.0.text() + } + pub fn flavor(&self) -> CommentFlavor { let text = self.text(); if text.starts_with("///") { @@ -230,13 +250,16 @@ impl Comment { pub fn prefix(&self) -> &'static str { self.flavor().prefix() } +} - pub fn count_newlines_lazy(&self) -> impl Iterator { - self.text().chars().filter(|&c| c == '\n').map(|_| &()) - } +pub struct CommentIter<'a> { + iter: SyntaxElementChildren<'a>, +} - pub fn has_newlines(&self) -> bool { - self.count_newlines_lazy().count() > 0 +impl<'a> Iterator for CommentIter<'a> { + type Item = Comment<'a>; + fn next(&mut self) -> Option> { + self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast)) } } @@ -267,27 +290,42 @@ impl CommentFlavor { } } -impl Whitespace { - pub fn count_newlines_lazy(&self) -> impl Iterator { - self.text().chars().filter(|&c| c == '\n').map(|_| &()) +pub struct Whitespace<'a>(SyntaxToken<'a>); + +impl<'a> Whitespace<'a> { + pub fn cast(token: SyntaxToken<'a>) -> Option { + if token.kind() == WHITESPACE { + Some(Whitespace(token)) + } else { + None + } + } + + pub fn syntax(&self) -> SyntaxToken<'a> { + self.0 } - pub fn has_newlines(&self) -> bool { - self.text().contains('\n') + pub fn text(&self) -> &'a SmolStr { + self.0.text() + } + + pub fn spans_multiple_lines(&self) -> bool { + let text = self.text(); + text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n')) } } impl Name { pub fn text(&self) -> &SmolStr { - let ident = self.syntax().first_child().unwrap(); - ident.leaf_text().unwrap() + let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); + ident.text() } } impl NameRef { pub fn text(&self) -> &SmolStr { - let ident = self.syntax().first_child().unwrap(); - ident.leaf_text().unwrap() + let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); + ident.text() } } @@ -316,7 +354,7 @@ impl ImplBlock { impl Module { pub fn has_semi(&self) -> bool { - match self.syntax().last_child() { + match self.syntax().last_child_or_token() { None => false, Some(node) => node.kind() == SEMI, } @@ -325,7 +363,7 @@ impl Module { impl LetStmt { pub fn has_semi(&self) -> bool { - match self.syntax().last_child() { + match self.syntax().last_child_or_token() { None => false, Some(node) => node.kind() == SEMI, } @@ -360,7 +398,7 @@ impl IfExpr { impl ExprStmt { pub fn has_semi(&self) -> bool { - match self.syntax().last_child() { + match self.syntax().last_child_or_token() { None => false, Some(node) => node.kind() == SEMI, } @@ -384,7 +422,7 @@ impl PathSegment { let res = if let Some(name_ref) = self.name_ref() { PathSegmentKind::Name(name_ref) } else { - match self.syntax().first_child()?.kind() { + match self.syntax().first_child_or_token()?.kind() { SELF_KW => PathSegmentKind::SelfKw, SUPER_KW => PathSegmentKind::SuperKw, CRATE_KW => PathSegmentKind::CrateKw, @@ -395,7 +433,7 @@ impl PathSegment { } pub fn has_colon_colon(&self) -> bool { - match self.syntax.first_child().map(|s| s.kind()) { + match self.syntax.first_child_or_token().map(|s| s.kind()) { Some(COLONCOLON) => true, _ => false, } @@ -410,7 +448,7 @@ impl Path { impl UseTree { pub fn has_star(&self) -> bool { - self.syntax().children().any(|it| it.kind() == STAR) + self.syntax().children_with_tokens().any(|it| it.kind() == STAR) } } @@ -425,7 +463,7 @@ impl UseTreeList { impl RefPat { pub fn is_mut(&self) -> bool { - self.syntax().children().any(|n| n.kind() == MUT_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) } } @@ -500,19 +538,19 @@ impl EnumVariant { impl PointerType { pub fn is_mut(&self) -> bool { - self.syntax().children().any(|n| n.kind() == MUT_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) } } impl ReferenceType { pub fn is_mut(&self) -> bool { - self.syntax().children().any(|n| n.kind() == MUT_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) } } impl RefExpr { pub fn is_mut(&self) -> bool { - self.syntax().children().any(|n| n.kind() == MUT_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) } } @@ -528,7 +566,7 @@ pub enum PrefixOp { impl PrefixExpr { pub fn op_kind(&self) -> Option { - match self.syntax().first_child()?.kind() { + match self.op_token()?.kind() { STAR => Some(PrefixOp::Deref), EXCL => Some(PrefixOp::Not), MINUS => Some(PrefixOp::Neg), @@ -536,8 +574,8 @@ impl PrefixExpr { } } - pub fn op(&self) -> Option<&SyntaxNode> { - self.syntax().first_child() + pub fn op_token(&self) -> Option { + self.syntax().first_child_or_token()?.as_token() } } @@ -608,40 +646,42 @@ pub enum BinOp { } impl BinExpr { - fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> { - self.syntax().children().find_map(|c| match c.kind() { - PIPEPIPE => Some((c, BinOp::BooleanOr)), - AMPAMP => Some((c, BinOp::BooleanAnd)), - EQEQ => Some((c, BinOp::EqualityTest)), - NEQ => Some((c, BinOp::NegatedEqualityTest)), - LTEQ => Some((c, BinOp::LesserEqualTest)), - GTEQ => Some((c, BinOp::GreaterEqualTest)), - L_ANGLE => Some((c, BinOp::LesserTest)), - R_ANGLE => Some((c, BinOp::GreaterTest)), - PLUS => Some((c, BinOp::Addition)), - STAR => Some((c, BinOp::Multiplication)), - MINUS => Some((c, BinOp::Subtraction)), - SLASH => Some((c, BinOp::Division)), - PERCENT => Some((c, BinOp::Remainder)), - SHL => Some((c, BinOp::LeftShift)), - SHR => Some((c, BinOp::RightShift)), - CARET => Some((c, BinOp::BitwiseXor)), - PIPE => Some((c, BinOp::BitwiseOr)), - AMP => Some((c, BinOp::BitwiseAnd)), - DOTDOT => Some((c, BinOp::RangeRightOpen)), - DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), - EQ => Some((c, BinOp::Assignment)), - PLUSEQ => Some((c, BinOp::AddAssign)), - SLASHEQ => Some((c, BinOp::DivAssign)), - STAREQ => Some((c, BinOp::MulAssign)), - PERCENTEQ => Some((c, BinOp::RemAssign)), - SHREQ => Some((c, BinOp::ShrAssign)), - SHLEQ => Some((c, BinOp::ShlAssign)), - MINUSEQ => Some((c, BinOp::SubAssign)), - PIPEEQ => Some((c, BinOp::BitOrAssign)), - AMPEQ => Some((c, BinOp::BitAndAssign)), - CARETEQ => Some((c, BinOp::BitXorAssign)), - _ => None, + fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { + self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { + match c.kind() { + PIPEPIPE => Some((c, BinOp::BooleanOr)), + AMPAMP => Some((c, BinOp::BooleanAnd)), + EQEQ => Some((c, BinOp::EqualityTest)), + NEQ => Some((c, BinOp::NegatedEqualityTest)), + LTEQ => Some((c, BinOp::LesserEqualTest)), + GTEQ => Some((c, BinOp::GreaterEqualTest)), + L_ANGLE => Some((c, BinOp::LesserTest)), + R_ANGLE => Some((c, BinOp::GreaterTest)), + PLUS => Some((c, BinOp::Addition)), + STAR => Some((c, BinOp::Multiplication)), + MINUS => Some((c, BinOp::Subtraction)), + SLASH => Some((c, BinOp::Division)), + PERCENT => Some((c, BinOp::Remainder)), + SHL => Some((c, BinOp::LeftShift)), + SHR => Some((c, BinOp::RightShift)), + CARET => Some((c, BinOp::BitwiseXor)), + PIPE => Some((c, BinOp::BitwiseOr)), + AMP => Some((c, BinOp::BitwiseAnd)), + DOTDOT => Some((c, BinOp::RangeRightOpen)), + DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), + EQ => Some((c, BinOp::Assignment)), + PLUSEQ => Some((c, BinOp::AddAssign)), + SLASHEQ => Some((c, BinOp::DivAssign)), + STAREQ => Some((c, BinOp::MulAssign)), + PERCENTEQ => Some((c, BinOp::RemAssign)), + SHREQ => Some((c, BinOp::ShrAssign)), + SHLEQ => Some((c, BinOp::ShlAssign)), + MINUSEQ => Some((c, BinOp::SubAssign)), + PIPEEQ => Some((c, BinOp::BitOrAssign)), + AMPEQ => Some((c, BinOp::BitAndAssign)), + CARETEQ => Some((c, BinOp::BitXorAssign)), + _ => None, + } }) } @@ -649,7 +689,7 @@ impl BinExpr { self.op_details().map(|t| t.1) } - pub fn op(&self) -> Option<&SyntaxNode> { + pub fn op_token(&self) -> Option { self.op_details().map(|t| t.0) } @@ -680,11 +720,23 @@ pub enum SelfParamFlavor { } impl SelfParam { + pub fn self_kw_token(&self) -> SyntaxToken { + self.syntax() + .children_with_tokens() + .filter_map(|it| it.as_token()) + .find(|it| it.kind() == SELF_KW) + .expect("invalid tree: self param must have self") + } + pub fn flavor(&self) -> SelfParamFlavor { - let borrowed = self.syntax().children().any(|n| n.kind() == AMP); + let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP); if borrowed { // check for a `mut` coming after the & -- `mut &self` != `&mut self` - if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW) + if self + .syntax() + .children_with_tokens() + .skip_while(|n| n.kind() != AMP) + .any(|n| n.kind() == MUT_KW) { SelfParamFlavor::MutRef } else { @@ -707,25 +759,31 @@ pub enum LiteralFlavor { Bool, } -impl LiteralExpr { +impl Literal { + pub fn token(&self) -> SyntaxToken { + match self.syntax().first_child_or_token().unwrap() { + SyntaxElement::Token(token) => token, + _ => unreachable!(), + } + } + pub fn flavor(&self) -> LiteralFlavor { - let syntax = self.syntax(); - match syntax.kind() { + match self.token().kind() { INT_NUMBER => { let allowed_suffix_list = [ "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", "u16", "u8", ]; - let text = syntax.text().to_string(); + let text = self.token().text().to_string(); let suffix = allowed_suffix_list .iter() .find(|&s| text.ends_with(s)) .map(|&suf| SmolStr::new(suf)); - LiteralFlavor::IntNumber { suffix: suffix } + LiteralFlavor::IntNumber { suffix } } FLOAT_NUMBER => { let allowed_suffix_list = ["f64", "f32"]; - let text = syntax.text().to_string(); + let text = self.token().text().to_string(); let suffix = allowed_suffix_list .iter() .find(|&s| text.ends_with(s)) @@ -750,11 +808,29 @@ impl NamedField { impl BindPat { pub fn is_mutable(&self) -> bool { - self.syntax().children().any(|n| n.kind() == MUT_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) } pub fn is_ref(&self) -> bool { - self.syntax().children().any(|n| n.kind() == REF_KW) + self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW) + } +} + +impl LifetimeParam { + pub fn lifetime_token(&self) -> Option { + self.syntax() + .children_with_tokens() + .filter_map(|it| it.as_token()) + .find(|it| it.kind() == LIFETIME) + } +} + +impl WherePred { + pub fn lifetime_token(&self) -> Option { + self.syntax() + .children_with_tokens() + .filter_map(|it| it.as_token()) + .find(|it| it.kind() == LIFETIME) } } @@ -835,7 +911,7 @@ where let pred = predicates.next().unwrap(); let mut bounds = pred.type_bound_list().unwrap().bounds(); - assert_eq!("'a", pred.lifetime().unwrap().syntax().text().to_string()); + assert_eq!("'a", pred.lifetime_token().unwrap().text()); assert_bound("'b", bounds.next()); assert_bound("'c", bounds.next()); diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index c51b4caa4..4afe1a146 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -376,64 +376,6 @@ impl BreakExpr { } } -// Byte -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct Byte { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for Byte { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for Byte { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - BYTE => Some(Byte::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for Byte { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for Byte {} -impl Byte {} - -// ByteString -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct ByteString { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for ByteString { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for ByteString { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - BYTE_STRING => Some(ByteString::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for ByteString { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for ByteString {} -impl ByteString {} - // CallExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -503,64 +445,6 @@ impl CastExpr { } } -// Char -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct Char { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for Char { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for Char { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - CHAR => Some(Char::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for Char { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for Char {} -impl Char {} - -// Comment -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct Comment { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for Comment { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for Comment { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - COMMENT => Some(Comment::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for Comment { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for Comment {} -impl Comment {} - // Condition #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1115,35 +999,6 @@ impl ExternCrateItem { } } -// FalseKw -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct FalseKw { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for FalseKw { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for FalseKw { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - FALSE_KW => Some(FalseKw::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for FalseKw { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for FalseKw {} -impl FalseKw {} - // FieldExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1249,35 +1104,6 @@ impl FieldPatList { } } -// FloatNumber -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct FloatNumber { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for FloatNumber { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for FloatNumber { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - FLOAT_NUMBER => Some(FloatNumber::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for FloatNumber { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for FloatNumber {} -impl FloatNumber {} - // FnDef #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1613,35 +1439,6 @@ impl ToOwned for IndexExpr { impl IndexExpr {} -// IntNumber -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct IntNumber { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for IntNumber { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for IntNumber { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - INT_NUMBER => Some(IntNumber::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for IntNumber { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for IntNumber {} -impl IntNumber {} - // ItemList #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1777,35 +1574,6 @@ impl LetStmt { } } -// Lifetime -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct Lifetime { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for Lifetime { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for Lifetime { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - LIFETIME => Some(Lifetime::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for Lifetime { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for Lifetime {} -impl Lifetime {} - // LifetimeArg #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -1832,11 +1600,7 @@ impl ToOwned for LifetimeArg { } -impl LifetimeArg { - pub fn lifetime(&self) -> Option<&Lifetime> { - super::child_opt(self) - } -} +impl LifetimeArg {} // LifetimeParam #[derive(Debug, PartialEq, Eq, Hash)] @@ -1865,11 +1629,7 @@ impl ToOwned for LifetimeParam { impl ast::AttrsOwner for LifetimeParam {} -impl LifetimeParam { - pub fn lifetime(&self) -> Option<&Lifetime> { - super::child_opt(self) - } -} +impl LifetimeParam {} // Literal #[derive(Debug, PartialEq, Eq, Hash)] @@ -1897,130 +1657,7 @@ impl ToOwned for Literal { } -impl Literal { - pub fn literal_expr(&self) -> Option<&LiteralExpr> { - super::child_opt(self) - } -} - -// LiteralExpr -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct LiteralExpr { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for LiteralExpr { - type Repr = rowan::SyntaxNode; -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LiteralExprKind<'a> { - String(&'a String), - ByteString(&'a ByteString), - RawString(&'a RawString), - RawByteString(&'a RawByteString), - Char(&'a Char), - Byte(&'a Byte), - IntNumber(&'a IntNumber), - FloatNumber(&'a FloatNumber), - TrueKw(&'a TrueKw), - FalseKw(&'a FalseKw), -} -impl<'a> From<&'a String> for &'a LiteralExpr { - fn from(n: &'a String) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a ByteString> for &'a LiteralExpr { - fn from(n: &'a ByteString) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a RawString> for &'a LiteralExpr { - fn from(n: &'a RawString) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a RawByteString> for &'a LiteralExpr { - fn from(n: &'a RawByteString) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a Char> for &'a LiteralExpr { - fn from(n: &'a Char) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a Byte> for &'a LiteralExpr { - fn from(n: &'a Byte) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a IntNumber> for &'a LiteralExpr { - fn from(n: &'a IntNumber) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a FloatNumber> for &'a LiteralExpr { - fn from(n: &'a FloatNumber) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a TrueKw> for &'a LiteralExpr { - fn from(n: &'a TrueKw) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} -impl<'a> From<&'a FalseKw> for &'a LiteralExpr { - fn from(n: &'a FalseKw) -> &'a LiteralExpr { - LiteralExpr::cast(&n.syntax).unwrap() - } -} - - -impl AstNode for LiteralExpr { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - | STRING - | BYTE_STRING - | RAW_STRING - | RAW_BYTE_STRING - | CHAR - | BYTE - | INT_NUMBER - | FLOAT_NUMBER - | TRUE_KW - | FALSE_KW => Some(LiteralExpr::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for LiteralExpr { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - -impl LiteralExpr { - pub fn kind(&self) -> LiteralExprKind { - match self.syntax.kind() { - STRING => LiteralExprKind::String(String::cast(&self.syntax).unwrap()), - BYTE_STRING => LiteralExprKind::ByteString(ByteString::cast(&self.syntax).unwrap()), - RAW_STRING => LiteralExprKind::RawString(RawString::cast(&self.syntax).unwrap()), - RAW_BYTE_STRING => LiteralExprKind::RawByteString(RawByteString::cast(&self.syntax).unwrap()), - CHAR => LiteralExprKind::Char(Char::cast(&self.syntax).unwrap()), - BYTE => LiteralExprKind::Byte(Byte::cast(&self.syntax).unwrap()), - INT_NUMBER => LiteralExprKind::IntNumber(IntNumber::cast(&self.syntax).unwrap()), - FLOAT_NUMBER => LiteralExprKind::FloatNumber(FloatNumber::cast(&self.syntax).unwrap()), - TRUE_KW => LiteralExprKind::TrueKw(TrueKw::cast(&self.syntax).unwrap()), - FALSE_KW => LiteralExprKind::FalseKw(FalseKw::cast(&self.syntax).unwrap()), - _ => unreachable!(), - } - } -} - -impl LiteralExpr {} +impl Literal {} // LiteralPat #[derive(Debug, PartialEq, Eq, Hash)] @@ -3404,64 +3041,6 @@ impl ToOwned for RangePat { impl RangePat {} -// RawByteString -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct RawByteString { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for RawByteString { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for RawByteString { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - RAW_BYTE_STRING => Some(RawByteString::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for RawByteString { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for RawByteString {} -impl RawByteString {} - -// RawString -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct RawString { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for RawString { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for RawString { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - RAW_STRING => Some(RawString::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for RawString { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for RawString {} -impl RawString {} - // RefExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -3622,34 +3201,6 @@ impl ReturnExpr { } } -// SelfKw -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct SelfKw { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for SelfKw { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for SelfKw { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - SELF_KW => Some(SelfKw::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for SelfKw { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl SelfKw {} - // SelfParam #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -3677,11 +3228,7 @@ impl ToOwned for SelfParam { impl ast::TypeAscriptionOwner for SelfParam {} -impl SelfParam { - pub fn self_kw(&self) -> Option<&SelfKw> { - super::child_opt(self) - } -} +impl SelfParam {} // SlicePat #[derive(Debug, PartialEq, Eq, Hash)] @@ -3866,35 +3413,6 @@ impl Stmt { impl Stmt {} -// String -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct String { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for String { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for String { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - STRING => Some(String::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for String { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for String {} -impl String {} - // StructDef #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -4070,35 +3588,6 @@ impl TraitDef { } } -// TrueKw -#[derive(Debug, PartialEq, Eq, Hash)] -#[repr(transparent)] -pub struct TrueKw { - pub(crate) syntax: SyntaxNode, -} -unsafe impl TransparentNewType for TrueKw { - type Repr = rowan::SyntaxNode; -} - -impl AstNode for TrueKw { - fn cast(syntax: &SyntaxNode) -> Option<&Self> { - match syntax.kind() { - TRUE_KW => Some(TrueKw::from_repr(syntax.into_repr())), - _ => None, - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} - -impl ToOwned for TrueKw { - type Owned = TreeArc; - fn to_owned(&self) -> TreeArc { TreeArc::cast(self.syntax.to_owned()) } -} - - -impl ast::AstToken for TrueKw {} -impl TrueKw {} - // TryExpr #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] @@ -4403,10 +3892,6 @@ impl TypeBound { pub fn type_ref(&self) -> Option<&TypeRef> { super::child_opt(self) } - - pub fn lifetime(&self) -> Option<&Lifetime> { - super::child_opt(self) - } } // TypeBoundList @@ -4847,10 +4332,6 @@ impl WherePred { pub fn type_ref(&self) -> Option<&TypeRef> { super::child_opt(self) } - - pub fn lifetime(&self) -> Option<&Lifetime> { - super::child_opt(self) - } } // WhileExpr diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 1123c2e95..6d7a5a1cb 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -463,31 +463,7 @@ Grammar( "RangeExpr": (), "BinExpr": (), - "IntNumber": ( traits: ["AstToken"] ), - "FloatNumber": ( traits: ["AstToken"] ), - "String": ( traits: ["AstToken"] ), - "RawString": ( traits: ["AstToken"] ), - "Byte": ( traits: ["AstToken"] ), - "RawByteString": ( traits: ["AstToken"] ), - "ByteString": ( traits: ["AstToken"] ), - "Char": ( traits: ["AstToken"] ), - "TrueKw": ( traits: ["AstToken"] ), - "FalseKw": ( traits: ["AstToken"] ), - "LiteralExpr": ( - enum: [ - "String", - "ByteString", - "RawString", - "RawByteString", - "Char", - "Byte", - "IntNumber", - "FloatNumber", - "TrueKw", - "FalseKw", - ] - ), - "Literal": (options: ["LiteralExpr"]), + "Literal": (), "Expr": ( enum: [ @@ -580,14 +556,11 @@ Grammar( ), "TypeParam": ( traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"] ), "LifetimeParam": ( - options: [ "Lifetime"], traits: ["AttrsOwner"], ), - "Lifetime": ( traits: ["AstToken"] ), "TypeBound": ( options: [ "TypeRef", - "Lifetime", ] ), "TypeBoundList": ( @@ -598,7 +571,6 @@ Grammar( "WherePred": ( options: [ "TypeRef", - "Lifetime", ], traits: [ "TypeBoundsOwner", @@ -643,12 +615,10 @@ Grammar( ] ), "SelfParam": ( - options: ["SelfKw"], traits: [ "TypeAscriptionOwner", ] ), - "SelfKw": (), "Param": ( options: [ "Pat" ], traits: [ @@ -692,8 +662,7 @@ Grammar( ]), "TypeArg": (options: ["TypeRef"]), "AssocTypeArg": (options: ["NameRef", "TypeRef"]), - "LifetimeArg": (options: ["Lifetime"]), - "Comment": ( traits: ["AstToken"] ), + "LifetimeArg": (), "Whitespace": ( traits: ["AstToken"] ), }, ) diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 4f3020440..e1088e296 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -38,7 +38,7 @@ pub use crate::{ ast::AstNode, syntax_error::{SyntaxError, SyntaxErrorKind, Location}, syntax_text::SyntaxText, - syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder}, + syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder, SyntaxElement, SyntaxToken}, ptr::{SyntaxNodePtr, AstPtr}, parsing::{tokenize, Token}, }; @@ -70,7 +70,7 @@ impl SourceFile { pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option> { parsing::incremental_reparse(self.syntax(), edit, self.errors()) - .map(|(green_node, errors)| SourceFile::new(green_node, errors)) + .map(|(green_node, errors, _reparsed_range)| SourceFile::new(green_node, errors)) } fn full_reparse(&self, edit: &AtomTextEdit) -> TreeArc { @@ -179,15 +179,23 @@ fn api_walkthrough() { // There's a bunch of traversal methods on `SyntaxNode`: assert_eq!(expr_syntax.parent(), Some(block.syntax())); - assert_eq!(block.syntax().first_child().map(|it| it.kind()), Some(SyntaxKind::L_CURLY)); - assert_eq!(expr_syntax.next_sibling().map(|it| it.kind()), Some(SyntaxKind::WHITESPACE)); + assert_eq!( + block.syntax().first_child_or_token().map(|it| it.kind()), + Some(SyntaxKind::L_CURLY) + ); + assert_eq!( + expr_syntax.next_sibling_or_token().map(|it| it.kind()), + Some(SyntaxKind::WHITESPACE) + ); // As well as some iterator helpers: let f = expr_syntax.ancestors().find_map(ast::FnDef::cast); assert_eq!(f, Some(&*func)); - assert!(expr_syntax.siblings(Direction::Next).any(|it| it.kind() == SyntaxKind::R_CURLY)); + assert!(expr_syntax + .siblings_with_tokens(Direction::Next) + .any(|it| it.kind() == SyntaxKind::R_CURLY)); assert_eq!( - expr_syntax.descendants().count(), + expr_syntax.descendants_with_tokens().count(), 8, // 5 tokens `1`, ` `, `+`, ` `, `!` // 2 child literal expressions: `1`, `1` // 1 the node itself: `1 + 1` @@ -196,16 +204,14 @@ fn api_walkthrough() { // There's also a `preorder` method with a more fine-grained iteration control: let mut buf = String::new(); let mut indent = 0; - for event in expr_syntax.preorder() { + for event in expr_syntax.preorder_with_tokens() { match event { WalkEvent::Enter(node) => { - buf += &format!( - "{:indent$}{:?} {:?}\n", - " ", - node.text(), - node.kind(), - indent = indent - ); + let text = match node { + SyntaxElement::Node(it) => it.text().to_string(), + SyntaxElement::Token(it) => it.text().to_string(), + }; + buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent); indent += 2; } WalkEvent::Leave(_) => indent -= 2, diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index 7e7f914f5..69887f500 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs @@ -12,7 +12,7 @@ use ra_parser::Reparser; use crate::{ SyntaxKind::*, TextRange, TextUnit, SyntaxError, algo, - syntax_node::{GreenNode, SyntaxNode}, + syntax_node::{GreenNode, SyntaxNode, GreenToken, SyntaxElement}, parsing::{ text_token_source::TextTokenSource, text_tree_sink::TextTreeSink, @@ -24,60 +24,62 @@ pub(crate) fn incremental_reparse( node: &SyntaxNode, edit: &AtomTextEdit, errors: Vec, -) -> Option<(GreenNode, Vec)> { - let (node, green, new_errors) = - reparse_leaf(node, &edit).or_else(|| reparse_block(node, &edit))?; - let green_root = node.replace_with(green); - let errors = merge_errors(errors, new_errors, node, edit); - Some((green_root, errors)) +) -> Option<(GreenNode, Vec, TextRange)> { + if let Some((green, old_range)) = reparse_token(node, &edit) { + return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range)); + } + + if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) { + return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range)); + } + None } -fn reparse_leaf<'node>( +fn reparse_token<'node>( root: &'node SyntaxNode, edit: &AtomTextEdit, -) -> Option<(&'node SyntaxNode, GreenNode, Vec)> { - let node = algo::find_covering_node(root, edit.delete); - match node.kind() { +) -> Option<(GreenNode, TextRange)> { + let token = algo::find_covering_element(root, edit.delete).as_token()?; + match token.kind() { WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { - if node.kind() == WHITESPACE || node.kind() == COMMENT { + if token.kind() == WHITESPACE || token.kind() == COMMENT { // removing a new line may extends previous token - if node.text().to_string()[edit.delete - node.range().start()].contains('\n') { + if token.text().to_string()[edit.delete - token.range().start()].contains('\n') { return None; } } - let text = get_text_after_edit(node, &edit); - let tokens = tokenize(&text); - let token = match tokens[..] { - [token] if token.kind == node.kind() => token, + let text = get_text_after_edit(token.into(), &edit); + let lex_tokens = tokenize(&text); + let lex_token = match lex_tokens[..] { + [lex_token] if lex_token.kind == token.kind() => lex_token, _ => return None, }; - if token.kind == IDENT && is_contextual_kw(&text) { + if lex_token.kind == IDENT && is_contextual_kw(&text) { return None; } - if let Some(next_char) = root.text().char_at(node.range().end()) { + if let Some(next_char) = root.text().char_at(token.range().end()) { let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); if tokens_with_next_char.len() == 1 { return None; } } - let green = GreenNode::new_leaf(node.kind(), text.into()); - let new_errors = vec![]; - Some((node, green, new_errors)) + let new_token = GreenToken::new(token.kind(), text.into()); + Some((token.replace_with(new_token), token.range())) } _ => None, } } fn reparse_block<'node>( - node: &'node SyntaxNode, + root: &'node SyntaxNode, edit: &AtomTextEdit, -) -> Option<(&'node SyntaxNode, GreenNode, Vec)> { - let (node, reparser) = find_reparsable_node(node, edit.delete)?; - let text = get_text_after_edit(node, &edit); +) -> Option<(GreenNode, Vec, TextRange)> { + let (node, reparser) = find_reparsable_node(root, edit.delete)?; + let text = get_text_after_edit(node.into(), &edit); let tokens = tokenize(&text); if !is_balanced(&tokens) { return None; @@ -86,12 +88,16 @@ fn reparse_block<'node>( let mut tree_sink = TextTreeSink::new(&text, &tokens); reparser.parse(&token_source, &mut tree_sink); let (green, new_errors) = tree_sink.finish(); - Some((node, green, new_errors)) + Some((node.replace_with(green), new_errors, node.range())) } -fn get_text_after_edit(node: &SyntaxNode, edit: &AtomTextEdit) -> String { - let edit = AtomTextEdit::replace(edit.delete - node.range().start(), edit.insert.clone()); - edit.apply(node.text().to_string()) +fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { + let edit = AtomTextEdit::replace(edit.delete - element.range().start(), edit.insert.clone()); + let text = match element { + SyntaxElement::Token(token) => token.text().to_string(), + SyntaxElement::Node(node) => node.text().to_string(), + }; + edit.apply(text) } fn is_contextual_kw(text: &str) -> bool { @@ -102,9 +108,13 @@ fn is_contextual_kw(text: &str) -> bool { } fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(&SyntaxNode, Reparser)> { - let node = algo::find_covering_node(node, range); - node.ancestors().find_map(|node| { - let first_child = node.first_child().map(|it| it.kind()); + let node = algo::find_covering_element(node, range); + let mut ancestors = match node { + SyntaxElement::Token(it) => it.parent().ancestors(), + SyntaxElement::Node(it) => it.ancestors(), + }; + ancestors.find_map(|node| { + let first_child = node.first_child_or_token().map(|it| it.kind()); let parent = node.parent().map(|it| it.kind()); Reparser::for_node(node.kind(), first_child, parent).map(|r| (node, r)) }) @@ -136,19 +146,19 @@ fn is_balanced(tokens: &[Token]) -> bool { fn merge_errors( old_errors: Vec, new_errors: Vec, - old_node: &SyntaxNode, + old_range: TextRange, edit: &AtomTextEdit, ) -> Vec { let mut res = Vec::new(); for e in old_errors { - if e.offset() <= old_node.range().start() { + if e.offset() <= old_range.start() { res.push(e) - } else if e.offset() >= old_node.range().end() { + } else if e.offset() >= old_range.end() { res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); } } for e in new_errors { - res.push(e.add_offset(old_node.range().start(), 0.into())); + res.push(e.add_offset(old_range.start(), 0.into())); } res } @@ -160,13 +170,7 @@ mod tests { use crate::{SourceFile, AstNode}; use super::*; - fn do_check(before: &str, replace_with: &str, reparser: F) - where - for<'a> F: Fn( - &'a SyntaxNode, - &AtomTextEdit, - ) -> Option<(&'a SyntaxNode, GreenNode, Vec)>, - { + fn do_check(before: &str, replace_with: &str, reparsed_len: u32) { let (range, before) = extract_range(before); let edit = AtomTextEdit::replace(range, replace_with.to_owned()); let after = edit.apply(before.clone()); @@ -175,23 +179,20 @@ mod tests { let incrementally_reparsed = { let f = SourceFile::parse(&before); let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() }; - let (node, green, new_errors) = - reparser(f.syntax(), &edit).expect("cannot incrementally reparse"); - let green_root = node.replace_with(green); - let errors = super::merge_errors(f.errors(), new_errors, node, &edit); - SourceFile::new(green_root, errors) + let (green, new_errors, range) = + incremental_reparse(f.syntax(), &edit, f.errors()).unwrap(); + assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); + SourceFile::new(green, new_errors) }; assert_eq_text!( &fully_reparsed.syntax().debug_dump(), &incrementally_reparsed.syntax().debug_dump(), - ) + ); } - #[test] + #[test] // FIXME: some test here actually test token reparsing fn reparse_block_tests() { - let do_check = |before, replace_to| do_check(before, replace_to, reparse_block); - do_check( r" fn foo() { @@ -199,6 +200,7 @@ fn foo() { } ", "baz", + 3, ); do_check( r" @@ -207,6 +209,7 @@ fn foo() { } ", "baz", + 25, ); do_check( r" @@ -215,6 +218,7 @@ struct Foo { } ", ",\n g: (),", + 14, ); do_check( r" @@ -225,6 +229,7 @@ fn foo { } ", "62", + 31, // FIXME: reparse only int literal here ); do_check( r" @@ -233,7 +238,9 @@ mod foo { } ", "bar", + 11, ); + do_check( r" trait Foo { @@ -241,6 +248,7 @@ trait Foo { } ", "Output", + 3, ); do_check( r" @@ -249,13 +257,9 @@ impl IntoIterator for Foo { } ", "n next(", + 9, ); - do_check( - r" -use a::b::{foo,<|>,bar<|>}; - ", - "baz", - ); + do_check(r"use a::b::{foo,<|>,bar<|>};", "baz", 10); do_check( r" pub enum A { @@ -263,12 +267,14 @@ pub enum A { } ", "\nBar;\n", + 11, ); do_check( r" foo!{a, b<|><|> d} ", ", c[3]", + 8, ); do_check( r" @@ -277,6 +283,7 @@ fn foo() { } ", "123", + 14, ); do_check( r" @@ -285,54 +292,60 @@ extern { } ", " exit(code: c_int)", + 11, ); } #[test] - fn reparse_leaf_tests() { - let do_check = |before, replace_to| do_check(before, replace_to, reparse_leaf); - + fn reparse_token_tests() { do_check( r"<|><|> fn foo() -> i32 { 1 } ", "\n\n\n \n", + 1, ); do_check( r" fn foo() -> <|><|> {} ", " \n", + 2, ); do_check( r" fn <|>foo<|>() -> i32 { 1 } ", "bar", + 3, ); do_check( r" fn foo<|><|>foo() { } ", "bar", + 6, ); do_check( r" fn foo /* <|><|> */ () {} ", "some comment", + 6, ); do_check( r" fn baz <|><|> () {} ", " \t\t\n\n", + 2, ); do_check( r" fn baz <|><|> () {} ", " \t\t\n\n", + 2, ); do_check( r" @@ -340,24 +353,28 @@ fn baz <|><|> () {} mod { } ", "c", + 14, ); do_check( r#" fn -> &str { "Hello<|><|>" } "#, ", world", + 7, ); do_check( r#" fn -> &str { // "Hello<|><|>" "#, ", world", + 10, ); do_check( r##" fn -> &str { r#"Hello<|><|>"# "##, ", world", + 10, ); do_check( r" @@ -367,6 +384,7 @@ enum Foo { } ", "Clone", + 4, ); } } diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs index b17d06c61..71fc515f2 100644 --- a/crates/ra_syntax/src/parsing/text_tree_sink.rs +++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs @@ -28,10 +28,10 @@ enum State { } impl<'a> TreeSink for TextTreeSink<'a> { - fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) { + fn token(&mut self, kind: SyntaxKind, n_tokens: u8) { match mem::replace(&mut self.state, State::Normal) { State::PendingStart => unreachable!(), - State::PendingFinish => self.inner.finish_branch(), + State::PendingFinish => self.inner.finish_node(), State::Normal => (), } self.eat_trivias(); @@ -40,18 +40,18 @@ impl<'a> TreeSink for TextTreeSink<'a> { .iter() .map(|it| it.len) .sum::(); - self.do_leaf(kind, len, n_tokens); + self.do_token(kind, len, n_tokens); } - fn start_branch(&mut self, kind: SyntaxKind) { + fn start_node(&mut self, kind: SyntaxKind) { match mem::replace(&mut self.state, State::Normal) { State::PendingStart => { - self.inner.start_branch(kind); + self.inner.start_node(kind); // No need to attach trivias to previous node: there is no // previous node. return; } - State::PendingFinish => self.inner.finish_branch(), + State::PendingFinish => self.inner.finish_node(), State::Normal => (), } @@ -71,14 +71,14 @@ impl<'a> TreeSink for TextTreeSink<'a> { n_attached_trivias(kind, leading_trivias) }; self.eat_n_trivias(n_trivias - n_attached_trivias); - self.inner.start_branch(kind); + self.inner.start_node(kind); self.eat_n_trivias(n_attached_trivias); } - fn finish_branch(&mut self) { + fn finish_node(&mut self) { match mem::replace(&mut self.state, State::PendingFinish) { State::PendingStart => unreachable!(), - State::PendingFinish => self.inner.finish_branch(), + State::PendingFinish => self.inner.finish_node(), State::Normal => (), } } @@ -104,7 +104,7 @@ impl<'a> TextTreeSink<'a> { match mem::replace(&mut self.state, State::Normal) { State::PendingFinish => { self.eat_trivias(); - self.inner.finish_branch() + self.inner.finish_node() } State::PendingStart | State::Normal => unreachable!(), } @@ -117,7 +117,7 @@ impl<'a> TextTreeSink<'a> { if !token.kind.is_trivia() { break; } - self.do_leaf(token.kind, token.len, 1); + self.do_token(token.kind, token.len, 1); } } @@ -125,16 +125,16 @@ impl<'a> TextTreeSink<'a> { for _ in 0..n { let token = self.tokens[self.token_pos]; assert!(token.kind.is_trivia()); - self.do_leaf(token.kind, token.len, 1); + self.do_token(token.kind, token.len, 1); } } - fn do_leaf(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { + fn do_token(&mut self, kind: SyntaxKind, len: TextUnit, n_tokens: usize) { let range = TextRange::offset_len(self.text_pos, len); let text: SmolStr = self.text[range].into(); self.text_pos += len; self.token_pos += n_tokens; - self.inner.leaf(kind, text); + self.inner.token(kind, text); } } diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index e5b4cdb11..be181d0ae 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs @@ -29,6 +29,9 @@ impl Types for RaTypes { } pub(crate) type GreenNode = rowan::GreenNode; +pub(crate) type GreenToken = rowan::GreenToken; +#[allow(unused)] +pub(crate) type GreenElement = rowan::GreenElement; /// Marker trait for CST and AST nodes pub trait SyntaxNodeWrapper: TransparentNewType> {} @@ -113,11 +116,13 @@ impl ToOwned for SyntaxNode { impl fmt::Debug for SyntaxNode { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; - if has_short_text(self.kind()) { - write!(fmt, " \"{}\"", self.text())?; - } - Ok(()) + write!(fmt, "{:?}@{:?}", self.kind(), self.range()) + } +} + +impl fmt::Display for SyntaxNode { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.text(), fmt) } } @@ -145,14 +150,6 @@ impl SyntaxNode { SyntaxText::new(self) } - pub fn is_leaf(&self) -> bool { - self.0.is_leaf() - } - - pub fn leaf_text(&self) -> Option<&SmolStr> { - self.0.leaf_text() - } - pub fn parent(&self) -> Option<&SyntaxNode> { self.0.parent().map(SyntaxNode::from_repr) } @@ -161,22 +158,50 @@ impl SyntaxNode { self.0.first_child().map(SyntaxNode::from_repr) } + pub fn first_child_or_token(&self) -> Option { + self.0.first_child_or_token().map(SyntaxElement::from) + } + pub fn last_child(&self) -> Option<&SyntaxNode> { self.0.last_child().map(SyntaxNode::from_repr) } + pub fn last_child_or_token(&self) -> Option { + self.0.last_child_or_token().map(SyntaxElement::from) + } + pub fn next_sibling(&self) -> Option<&SyntaxNode> { self.0.next_sibling().map(SyntaxNode::from_repr) } + pub fn next_sibling_or_token(&self) -> Option { + self.0.next_sibling_or_token().map(SyntaxElement::from) + } + pub fn prev_sibling(&self) -> Option<&SyntaxNode> { self.0.prev_sibling().map(SyntaxNode::from_repr) } + pub fn prev_sibling_or_token(&self) -> Option { + self.0.prev_sibling_or_token().map(SyntaxElement::from) + } + pub fn children(&self) -> SyntaxNodeChildren { SyntaxNodeChildren(self.0.children()) } + pub fn children_with_tokens(&self) -> SyntaxElementChildren { + SyntaxElementChildren(self.0.children_with_tokens()) + } + + pub fn first_token(&self) -> Option { + self.0.first_token().map(SyntaxToken::from) + } + + pub fn last_token(&self) -> Option { + self.0.last_token().map(SyntaxToken::from) + } + pub fn ancestors(&self) -> impl Iterator { crate::algo::generate(Some(self), |&node| node.parent()) } @@ -188,6 +213,13 @@ impl SyntaxNode { }) } + pub fn descendants_with_tokens(&self) -> impl Iterator { + self.preorder_with_tokens().filter_map(|event| match event { + WalkEvent::Enter(it) => Some(it), + WalkEvent::Leave(_) => None, + }) + } + pub fn siblings(&self, direction: Direction) -> impl Iterator { crate::algo::generate(Some(self), move |&node| match direction { Direction::Next => node.next_sibling(), @@ -195,6 +227,17 @@ impl SyntaxNode { }) } + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator { + let me: SyntaxElement = self.into(); + crate::algo::generate(Some(me), move |el| match direction { + Direction::Next => el.next_sibling_or_token(), + Direction::Prev => el.prev_sibling_or_token(), + }) + } + pub fn preorder(&self) -> impl Iterator> { self.0.preorder().map(|event| match event { WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode::from_repr(n)), @@ -202,6 +245,13 @@ impl SyntaxNode { }) } + pub fn preorder_with_tokens(&self) -> impl Iterator> { + self.0.preorder_with_tokens().map(|event| match event { + WalkEvent::Enter(n) => WalkEvent::Enter(n.into()), + WalkEvent::Leave(n) => WalkEvent::Leave(n.into()), + }) + } + pub fn memory_size_of_subtree(&self) -> usize { self.0.memory_size_of_subtree() } @@ -223,17 +273,20 @@ impl SyntaxNode { }; } - for event in self.preorder() { + for event in self.preorder_with_tokens() { match event { - WalkEvent::Enter(node) => { + WalkEvent::Enter(element) => { indent!(); - writeln!(buf, "{:?}", node).unwrap(); - if node.first_child().is_none() { - let off = node.range().end(); - while err_pos < errors.len() && errors[err_pos].offset() <= off { - indent!(); - writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); - err_pos += 1; + match element { + SyntaxElement::Node(node) => writeln!(buf, "{:?}", node).unwrap(), + SyntaxElement::Token(token) => { + writeln!(buf, "{:?}", token).unwrap(); + let off = token.range().end(); + while err_pos < errors.len() && errors[err_pos].offset() <= off { + indent!(); + writeln!(buf, "err: `{}`", errors[err_pos]).unwrap(); + err_pos += 1; + } } } level += 1; @@ -255,7 +308,172 @@ impl SyntaxNode { } pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { - self.0.replace_self(replacement) + self.0.replace_with(replacement) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct SyntaxToken<'a>(pub(crate) rowan::SyntaxToken<'a, RaTypes>); + +//FIXME: always output text +impl<'a> fmt::Debug for SyntaxToken<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; + if has_short_text(self.kind()) { + write!(fmt, " \"{}\"", self.text())?; + } + Ok(()) + } +} + +impl<'a> fmt::Display for SyntaxToken<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.text(), fmt) + } +} + +impl<'a> From> for SyntaxToken<'a> { + fn from(t: rowan::SyntaxToken<'a, RaTypes>) -> Self { + SyntaxToken(t) + } +} + +impl<'a> SyntaxToken<'a> { + pub fn kind(&self) -> SyntaxKind { + self.0.kind() + } + + pub fn text(&self) -> &'a SmolStr { + self.0.text() + } + + pub fn range(&self) -> TextRange { + self.0.range() + } + + pub fn parent(&self) -> &'a SyntaxNode { + SyntaxNode::from_repr(self.0.parent()) + } + + pub fn next_sibling_or_token(&self) -> Option> { + self.0.next_sibling_or_token().map(SyntaxElement::from) + } + + pub fn prev_sibling_or_token(&self) -> Option> { + self.0.prev_sibling_or_token().map(SyntaxElement::from) + } + + pub fn siblings_with_tokens( + &self, + direction: Direction, + ) -> impl Iterator> { + let me: SyntaxElement = (*self).into(); + crate::algo::generate(Some(me), move |el| match direction { + Direction::Next => el.next_sibling_or_token(), + Direction::Prev => el.prev_sibling_or_token(), + }) + } + + pub fn next_token(&self) -> Option> { + self.0.next_token().map(SyntaxToken::from) + } + + pub fn prev_token(&self) -> Option> { + self.0.prev_token().map(SyntaxToken::from) + } + + pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode { + self.0.replace_with(new_token) + } +} + +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +pub enum SyntaxElement<'a> { + Node(&'a SyntaxNode), + Token(SyntaxToken<'a>), +} + +impl<'a> fmt::Display for SyntaxElement<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self { + SyntaxElement::Node(it) => fmt::Display::fmt(it, fmt), + SyntaxElement::Token(it) => fmt::Display::fmt(it, fmt), + } + } +} + +impl<'a> SyntaxElement<'a> { + pub fn kind(&self) -> SyntaxKind { + match self { + SyntaxElement::Node(it) => it.kind(), + SyntaxElement::Token(it) => it.kind(), + } + } + + pub fn as_node(&self) -> Option<&'a SyntaxNode> { + match self { + SyntaxElement::Node(node) => Some(*node), + SyntaxElement::Token(_) => None, + } + } + + pub fn as_token(&self) -> Option> { + match self { + SyntaxElement::Node(_) => None, + SyntaxElement::Token(token) => Some(*token), + } + } + + pub fn next_sibling_or_token(&self) -> Option> { + match self { + SyntaxElement::Node(it) => it.next_sibling_or_token(), + SyntaxElement::Token(it) => it.next_sibling_or_token(), + } + } + + pub fn prev_sibling_or_token(&self) -> Option> { + match self { + SyntaxElement::Node(it) => it.prev_sibling_or_token(), + SyntaxElement::Token(it) => it.prev_sibling_or_token(), + } + } + + pub fn ancestors(&self) -> impl Iterator { + match self { + SyntaxElement::Node(it) => it, + SyntaxElement::Token(it) => it.parent(), + } + .ancestors() + } +} + +impl<'a> From> for SyntaxElement<'a> { + fn from(el: rowan::SyntaxElement<'a, RaTypes>) -> Self { + match el { + rowan::SyntaxElement::Node(n) => SyntaxElement::Node(SyntaxNode::from_repr(n)), + rowan::SyntaxElement::Token(t) => SyntaxElement::Token(t.into()), + } + } +} + +impl<'a> From<&'a SyntaxNode> for SyntaxElement<'a> { + fn from(node: &'a SyntaxNode) -> SyntaxElement<'a> { + SyntaxElement::Node(node) + } +} + +impl<'a> From> for SyntaxElement<'a> { + fn from(token: SyntaxToken<'a>) -> SyntaxElement<'a> { + SyntaxElement::Token(token) + } +} + +impl<'a> SyntaxElement<'a> { + pub fn range(&self) -> TextRange { + match self { + SyntaxElement::Node(it) => it.range(), + SyntaxElement::Token(it) => it.range(), + } } } @@ -270,6 +488,17 @@ impl<'a> Iterator for SyntaxNodeChildren<'a> { } } +#[derive(Debug)] +pub struct SyntaxElementChildren<'a>(rowan::SyntaxElementChildren<'a, RaTypes>); + +impl<'a> Iterator for SyntaxElementChildren<'a> { + type Item = SyntaxElement<'a>; + + fn next(&mut self) -> Option> { + self.0.next().map(SyntaxElement::from) + } +} + fn has_short_text(kind: SyntaxKind) -> bool { use crate::SyntaxKind::*; match kind { @@ -304,16 +533,16 @@ impl SyntaxTreeBuilder { node } - pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) { - self.inner.leaf(kind, text) + pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { + self.inner.token(kind, text) } - pub fn start_branch(&mut self, kind: SyntaxKind) { - self.inner.start_internal(kind) + pub fn start_node(&mut self, kind: SyntaxKind) { + self.inner.start_node(kind) } - pub fn finish_branch(&mut self) { - self.inner.finish_internal() + pub fn finish_node(&mut self) { + self.inner.finish_node() } pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs index 84e5b231a..6bb2ff461 100644 --- a/crates/ra_syntax/src/syntax_text.rs +++ b/crates/ra_syntax/src/syntax_text.rs @@ -1,6 +1,6 @@ use std::{fmt, ops}; -use crate::{SyntaxNode, TextRange, TextUnit}; +use crate::{SyntaxNode, TextRange, TextUnit, SyntaxElement}; #[derive(Clone)] pub struct SyntaxText<'a> { @@ -15,11 +15,14 @@ impl<'a> SyntaxText<'a> { pub fn chunks(&self) -> impl Iterator { let range = self.range; - self.node.descendants().filter_map(move |node| { - let text = node.leaf_text()?; - let range = range.intersection(&node.range())?; - let range = range - node.range().start(); - Some(&text[range]) + self.node.descendants_with_tokens().filter_map(move |el| match el { + SyntaxElement::Token(t) => { + let text = t.text(); + let range = range.intersection(&t.range())?; + let range = range - t.range().start(); + Some(&text[range]) + } + SyntaxElement::Node(_) => None, }) } diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 69f344d65..fc534df83 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs @@ -6,7 +6,7 @@ mod block; use crate::{ SourceFile, SyntaxError, AstNode, SyntaxNode, - SyntaxKind::{L_CURLY, R_CURLY}, + SyntaxKind::{L_CURLY, R_CURLY, BYTE, BYTE_STRING, STRING, CHAR}, ast, algo::visit::{visitor_ctx, VisitorCtx}, }; @@ -15,16 +15,24 @@ pub(crate) fn validate(file: &SourceFile) -> Vec { let mut errors = Vec::new(); for node in file.syntax().descendants() { let _ = visitor_ctx(&mut errors) - .visit::(byte::validate_byte_node) - .visit::(byte_string::validate_byte_string_node) - .visit::(char::validate_char_node) - .visit::(string::validate_string_node) + .visit::(validate_literal) .visit::(block::validate_block_node) .accept(node); } errors } +// FIXME: kill duplication +fn validate_literal(literal: &ast::Literal, acc: &mut Vec) { + match literal.token().kind() { + BYTE => byte::validate_byte_node(literal.token(), acc), + BYTE_STRING => byte_string::validate_byte_string_node(literal.token(), acc), + STRING => string::validate_string_node(literal.token(), acc), + CHAR => char::validate_char_node(literal.token(), acc), + _ => (), + } +} + pub(crate) fn validate_block_structure(root: &SyntaxNode) { let mut stack = Vec::new(); for node in root.descendants() { diff --git a/crates/ra_syntax/src/validation/byte.rs b/crates/ra_syntax/src/validation/byte.rs index 838e7a65f..290f80fc6 100644 --- a/crates/ra_syntax/src/validation/byte.rs +++ b/crates/ra_syntax/src/validation/byte.rs @@ -1,17 +1,17 @@ //! Validation of byte literals use crate::{ - ast::{self, AstNode, AstToken}, string_lexing::{self, StringComponentKind}, TextRange, validation::char, SyntaxError, SyntaxErrorKind::*, + SyntaxToken, }; -pub(super) fn validate_byte_node(node: &ast::Byte, errors: &mut Vec) { +pub(super) fn validate_byte_node(node: SyntaxToken, errors: &mut Vec) { let literal_text = node.text(); - let literal_range = node.syntax().range(); + let literal_range = node.range(); let mut components = string_lexing::parse_byte_literal(literal_text); let mut len = 0; for component in &mut components { diff --git a/crates/ra_syntax/src/validation/byte_string.rs b/crates/ra_syntax/src/validation/byte_string.rs index 64c7054a1..eae395e9d 100644 --- a/crates/ra_syntax/src/validation/byte_string.rs +++ b/crates/ra_syntax/src/validation/byte_string.rs @@ -1,15 +1,15 @@ use crate::{ - ast::{self, AstNode, AstToken}, string_lexing::{self, StringComponentKind}, SyntaxError, SyntaxErrorKind::*, + SyntaxToken, }; use super::byte; -pub(crate) fn validate_byte_string_node(node: &ast::ByteString, errors: &mut Vec) { +pub(crate) fn validate_byte_string_node(node: SyntaxToken, errors: &mut Vec) { let literal_text = node.text(); - let literal_range = node.syntax().range(); + let literal_range = node.range(); let mut components = string_lexing::parse_byte_string_literal(literal_text); for component in &mut components { let range = component.range + literal_range.start(); diff --git a/crates/ra_syntax/src/validation/char.rs b/crates/ra_syntax/src/validation/char.rs index c874e5d08..a385accdd 100644 --- a/crates/ra_syntax/src/validation/char.rs +++ b/crates/ra_syntax/src/validation/char.rs @@ -5,16 +5,16 @@ use std::u32; use arrayvec::ArrayString; use crate::{ - ast::{self, AstNode, AstToken}, string_lexing::{self, StringComponentKind}, TextRange, SyntaxError, SyntaxErrorKind::*, + SyntaxToken, }; -pub(super) fn validate_char_node(node: &ast::Char, errors: &mut Vec) { +pub(super) fn validate_char_node(node: SyntaxToken, errors: &mut Vec) { let literal_text = node.text(); - let literal_range = node.syntax().range(); + let literal_range = node.range(); let mut components = string_lexing::parse_char_literal(literal_text); let mut len = 0; for component in &mut components { diff --git a/crates/ra_syntax/src/validation/string.rs b/crates/ra_syntax/src/validation/string.rs index d857d088c..f7f5c02c0 100644 --- a/crates/ra_syntax/src/validation/string.rs +++ b/crates/ra_syntax/src/validation/string.rs @@ -1,15 +1,15 @@ use crate::{ - ast::{self, AstNode, AstToken}, string_lexing, SyntaxError, SyntaxErrorKind::*, + SyntaxToken, }; use super::char; -pub(crate) fn validate_string_node(node: &ast::String, errors: &mut Vec) { +pub(crate) fn validate_string_node(node: SyntaxToken, errors: &mut Vec) { let literal_text = node.text(); - let literal_range = node.syntax().range(); + let literal_range = node.range(); let mut components = string_lexing::parse_string_literal(literal_text); for component in &mut components { let range = component.range + literal_range.start(); -- cgit v1.2.3