From c9cfd57eeaa53657c0af7b9c4ba74d6b7b9889ed Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 20 Jul 2019 20:04:34 +0300 Subject: switch to upstream rowan's API --- crates/ra_syntax/src/algo.rs | 117 ++++++- crates/ra_syntax/src/ast/expr_extensions.rs | 13 +- crates/ra_syntax/src/ast/extensions.rs | 5 +- crates/ra_syntax/src/lib.rs | 16 +- crates/ra_syntax/src/parsing/reparsing.rs | 13 +- crates/ra_syntax/src/syntax_node.rs | 483 ++-------------------------- crates/ra_syntax/src/syntax_text.rs | 178 ---------- 7 files changed, 146 insertions(+), 679 deletions(-) delete mode 100644 crates/ra_syntax/src/syntax_text.rs (limited to 'crates/ra_syntax/src') diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index f47e11e66..6bb46b021 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -1,17 +1,18 @@ pub mod visit; +use std::ops::RangeInclusive; + use itertools::Itertools; -use crate::{AstNode, Direction, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit}; +use crate::{ + AstNode, Direction, InsertPosition, NodeOrToken, SourceFile, SyntaxElement, SyntaxNode, + SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, +}; pub use rowan::TokenAtOffset; 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(SyntaxToken(n)), - TokenAtOffset::Between(l, r) => TokenAtOffset::Between(SyntaxToken(l), SyntaxToken(r)), - } + node.token_at_offset(offset) } /// Returns ancestors of the node at the offset, sorted by length. This should @@ -44,20 +45,110 @@ pub fn find_node_at_offset(syntax: &SyntaxNode, offset: TextUnit) -> /// Finds the first sibling in the given direction which is not `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) - } + NodeOrToken::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), + NodeOrToken::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(), + NodeOrToken::Node(_) => true, + NodeOrToken::Token(token) => !token.kind().is_trivia(), } } } pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { - SyntaxElement::new(root.0.covering_node(range)) + root.covering_element(range) +} + +/// Adds specified children (tokens or nodes) to the current node at the +/// specific position. +/// +/// This is a type-unsafe low-level editing API, if you need to use it, +/// prefer to create a type-safe abstraction on top of it instead. +pub fn insert_children( + parent: &SyntaxNode, + position: InsertPosition, + to_insert: impl Iterator, +) -> SyntaxNode { + let mut delta = TextUnit::default(); + let to_insert = to_insert.map(|element| { + delta += element.text_range().len(); + to_green_element(element) + }); + + let old_children = parent.green().children(); + + let new_children = match &position { + InsertPosition::First => { + to_insert.chain(old_children.iter().cloned()).collect::>() + } + InsertPosition::Last => old_children.iter().cloned().chain(to_insert).collect::>(), + InsertPosition::Before(anchor) | InsertPosition::After(anchor) => { + let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 }; + let split_at = position_of_child(parent, anchor.clone()) + take_anchor; + let (before, after) = old_children.split_at(split_at); + before + .iter() + .cloned() + .chain(to_insert) + .chain(after.iter().cloned()) + .collect::>() + } + }; + + with_children(parent, new_children) +} + +/// Replaces all nodes in `to_delete` with nodes from `to_insert` +/// +/// This is a type-unsafe low-level editing API, if you need to use it, +/// prefer to create a type-safe abstraction on top of it instead. +pub fn replace_children( + parent: &SyntaxNode, + to_delete: RangeInclusive, + to_insert: impl Iterator, +) -> SyntaxNode { + let start = position_of_child(parent, to_delete.start().clone()); + let end = position_of_child(parent, to_delete.end().clone()); + let old_children = parent.green().children(); + + let new_children = old_children[..start] + .iter() + .cloned() + .chain(to_insert.map(to_green_element)) + .chain(old_children[end + 1..].iter().cloned()) + .collect::>(); + with_children(parent, new_children) +} + +fn with_children( + parent: &SyntaxNode, + new_children: Box<[NodeOrToken]>, +) -> SyntaxNode { + let len = new_children.iter().map(|it| it.text_len()).sum::(); + let new_node = + rowan::GreenNode::new(rowan::cursor::SyntaxKind(parent.kind() as u16), new_children); + let new_file_node = parent.replace_with(new_node); + let file = SourceFile::new(new_file_node); + + // FIXME: use a more elegant way to re-fetch the node (#1185), make + // `range` private afterwards + let mut ptr = SyntaxNodePtr::new(parent); + ptr.range = TextRange::offset_len(ptr.range().start(), len); + ptr.to_node(file.syntax()).to_owned() +} + +fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize { + parent + .children_with_tokens() + .position(|it| it == child) + .expect("element is not a child of current element") +} + +fn to_green_element(element: SyntaxElement) -> NodeOrToken { + match element { + NodeOrToken::Node(it) => it.green().clone().into(), + NodeOrToken::Token(it) => it.green().clone().into(), + } } diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 139bd3ec0..f9190d877 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs @@ -2,7 +2,7 @@ use crate::{ ast::{self, child_opt, children, AstChildren, AstNode}, - SmolStr, SyntaxElement, + SmolStr, SyntaxKind::*, SyntaxToken, T, }; @@ -229,14 +229,11 @@ pub enum LiteralKind { impl ast::Literal { pub fn token(&self) -> SyntaxToken { - let elem = self - .syntax() + self.syntax() .children_with_tokens() - .find(|e| e.kind() != ATTR && !e.kind().is_trivia()); - match elem { - Some(SyntaxElement::Token(token)) => token, - _ => unreachable!(), - } + .find(|e| e.kind() != ATTR && !e.kind().is_trivia()) + .and_then(|e| e.into_token()) + .unwrap() } pub fn kind(&self) -> LiteralKind { diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index 753fc42c6..d4873b39a 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs @@ -24,10 +24,7 @@ impl ast::NameRef { } fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { - match node.0.green().children().first() { - Some(rowan::GreenElement::Token(it)) => it.text(), - _ => panic!(), - } + node.green().children().first().and_then(|it| it.as_token()).unwrap().text() } impl ast::Attr { diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 8af04c136..21c07d69a 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -20,7 +20,6 @@ //! [Swift]: mod syntax_node; -mod syntax_text; mod syntax_error; mod parsing; mod validation; @@ -43,14 +42,13 @@ pub use crate::{ ptr::{AstPtr, SyntaxNodePtr}, syntax_error::{Location, SyntaxError, SyntaxErrorKind}, syntax_node::{ - Direction, InsertPosition, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, - WalkEvent, + Direction, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, + SyntaxTreeBuilder, WalkEvent, }, - syntax_text::SyntaxText, }; pub use ra_parser::SyntaxKind; pub use ra_parser::T; -pub use rowan::{SmolStr, TextRange, TextUnit}; +pub use rowan::{SmolStr, SyntaxText, TextRange, TextUnit}; /// `Parse` is the result of the parsing: a syntax tree and a collection of /// errors. @@ -76,7 +74,7 @@ impl Parse { } pub fn syntax_node(&self) -> SyntaxNode { - SyntaxNode::new(self.green.clone()) + SyntaxNode::new_root(self.green.clone()) } } @@ -147,7 +145,7 @@ pub use crate::ast::SourceFile; impl SourceFile { fn new(green: GreenNode) -> SourceFile { - let root = SyntaxNode::new(green); + let root = SyntaxNode::new_root(green); if cfg!(debug_assertions) { validation::validate_block_structure(&root); } @@ -267,8 +265,8 @@ fn api_walkthrough() { match event { WalkEvent::Enter(node) => { let text = match &node { - SyntaxElement::Node(it) => it.text().to_string(), - SyntaxElement::Token(it) => it.text().to_string(), + NodeOrToken::Node(it) => it.text().to_string(), + NodeOrToken::Token(it) => it.text().to_string(), }; buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent); indent += 2; diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs index 2f388bdfe..65b8aa10d 100644 --- a/crates/ra_syntax/src/parsing/reparsing.rs +++ b/crates/ra_syntax/src/parsing/reparsing.rs @@ -16,7 +16,7 @@ use crate::{ text_token_source::TextTokenSource, text_tree_sink::TextTreeSink, }, - syntax_node::{GreenNode, GreenToken, SyntaxElement, SyntaxNode}, + syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode}, SyntaxError, SyntaxKind::*, TextRange, TextUnit, T, @@ -70,7 +70,8 @@ fn reparse_token<'node>( } } - let new_token = GreenToken::new(rowan::SyntaxKind(token.kind().into()), text.into()); + let new_token = + GreenToken::new(rowan::cursor::SyntaxKind(token.kind().into()), text.into()); Some((token.replace_with(new_token), token.text_range())) } _ => None, @@ -98,8 +99,8 @@ fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { let edit = AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone()); let text = match element { - SyntaxElement::Token(token) => token.text().to_string(), - SyntaxElement::Node(node) => node.text().to_string(), + NodeOrToken::Token(token) => token.text().to_string(), + NodeOrToken::Node(node) => node.text().to_string(), }; edit.apply(text) } @@ -114,8 +115,8 @@ fn is_contextual_kw(text: &str) -> bool { fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { let node = algo::find_covering_element(node, range); let mut ancestors = match node { - SyntaxElement::Token(it) => it.parent().ancestors(), - SyntaxElement::Node(it) => it.ancestors(), + NodeOrToken::Token(it) => it.parent().ancestors(), + NodeOrToken::Node(it) => it.ancestors(), }; ancestors.find_map(|node| { let first_child = node.first_child_or_token().map(|it| it.kind()); diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index c42045d77..689dbefde 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs @@ -6,15 +6,12 @@ //! The *real* implementation is in the (language-agnostic) `rowan` crate, this //! modules just wraps its API. -use std::{fmt, iter::successors, ops::RangeInclusive}; - use ra_parser::ParseError; -use rowan::GreenNodeBuilder; +use rowan::{GreenNodeBuilder, Language}; use crate::{ syntax_error::{SyntaxError, SyntaxErrorKind}, - AstNode, Parse, SmolStr, SourceFile, SyntaxKind, SyntaxNodePtr, SyntaxText, TextRange, - TextUnit, + Parse, SmolStr, SyntaxKind, TextUnit, }; pub use rowan::WalkEvent; @@ -28,465 +25,27 @@ pub enum InsertPosition { After(T), } -#[derive(PartialEq, Eq, Hash, Clone)] -pub struct SyntaxNode(pub(crate) rowan::cursor::SyntaxNode); - -impl fmt::Debug for SyntaxNode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if f.alternate() { - let mut level = 0; - for event in self.preorder_with_tokens() { - match event { - WalkEvent::Enter(element) => { - for _ in 0..level { - write!(f, " ")?; - } - match element { - SyntaxElement::Node(node) => writeln!(f, "{:?}", node)?, - SyntaxElement::Token(token) => writeln!(f, "{:?}", token)?, - } - level += 1; - } - WalkEvent::Leave(_) => level -= 1, - } - } - assert_eq!(level, 0); - Ok(()) - } else { - write!(f, "{:?}@{:?}", self.kind(), self.text_range()) - } - } -} - -impl fmt::Display for SyntaxNode { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.text(), fmt) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Direction { - Next, - Prev, -} - -impl SyntaxNode { - pub(crate) fn new(green: GreenNode) -> SyntaxNode { - let inner = rowan::cursor::SyntaxNode::new_root(green); - SyntaxNode(inner) - } - - pub fn kind(&self) -> SyntaxKind { - self.0.kind().0.into() - } - - pub fn text_range(&self) -> TextRange { - self.0.text_range() - } - - pub fn text(&self) -> SyntaxText { - SyntaxText::new(self.clone()) - } - - pub fn parent(&self) -> Option { - self.0.parent().map(SyntaxNode) - } - - pub fn first_child(&self) -> Option { - self.0.first_child().map(SyntaxNode) - } - - pub fn first_child_or_token(&self) -> Option { - self.0.first_child_or_token().map(SyntaxElement::new) - } - - pub fn last_child(&self) -> Option { - self.0.last_child().map(SyntaxNode) - } - - pub fn last_child_or_token(&self) -> Option { - self.0.last_child_or_token().map(SyntaxElement::new) - } - - pub fn next_sibling(&self) -> Option { - self.0.next_sibling().map(SyntaxNode) - } - - pub fn next_sibling_or_token(&self) -> Option { - self.0.next_sibling_or_token().map(SyntaxElement::new) - } - - pub fn prev_sibling(&self) -> Option { - self.0.prev_sibling().map(SyntaxNode) - } - - pub fn prev_sibling_or_token(&self) -> Option { - self.0.prev_sibling_or_token().map(SyntaxElement::new) - } - - 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) - } - - pub fn last_token(&self) -> Option { - self.0.last_token().map(SyntaxToken) - } - - pub fn ancestors(&self) -> impl Iterator { - successors(Some(self.clone()), |node| node.parent()) - } - - pub fn descendants(&self) -> impl Iterator { - self.preorder().filter_map(|event| match event { - WalkEvent::Enter(node) => Some(node), - WalkEvent::Leave(_) => None, - }) - } - - 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 { - successors(Some(self.clone()), move |node| match direction { - Direction::Next => node.next_sibling(), - Direction::Prev => node.prev_sibling(), - }) - } - - pub fn siblings_with_tokens( - &self, - direction: Direction, - ) -> impl Iterator { - let me: SyntaxElement = self.clone().into(); - successors(Some(me), move |el| match direction { - Direction::Next => el.next_sibling_or_token(), - Direction::Prev => el.prev_sibling_or_token(), - }) - } +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum RustLanguage {} +impl Language for RustLanguage { + type Kind = SyntaxKind; - pub fn preorder(&self) -> impl Iterator> { - self.0.preorder().map(|event| match event { - WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode(n)), - WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxNode(n)), - }) + fn kind_from_raw(raw: rowan::cursor::SyntaxKind) -> SyntaxKind { + SyntaxKind::from(raw.0) } - pub fn preorder_with_tokens(&self) -> impl Iterator> { - self.0.preorder_with_tokens().map(|event| match event { - WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxElement::new(n)), - WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxElement::new(n)), - }) - } - - pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode { - self.0.replace_with(replacement) - } - - /// Adds specified children (tokens or nodes) to the current node at the - /// specific position. - /// - /// This is a type-unsafe low-level editing API, if you need to use it, - /// prefer to create a type-safe abstraction on top of it instead. - pub fn insert_children( - &self, - position: InsertPosition, - to_insert: impl Iterator, - ) -> SyntaxNode { - let mut delta = TextUnit::default(); - let to_insert = to_insert.map(|element| { - delta += element.text_len(); - to_green_element(element) - }); - - let old_children = self.0.green().children(); - - let new_children = match &position { - InsertPosition::First => { - to_insert.chain(old_children.iter().cloned()).collect::>() - } - InsertPosition::Last => { - old_children.iter().cloned().chain(to_insert).collect::>() - } - InsertPosition::Before(anchor) | InsertPosition::After(anchor) => { - let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 }; - let split_at = self.position_of_child(anchor.clone()) + take_anchor; - let (before, after) = old_children.split_at(split_at); - before - .iter() - .cloned() - .chain(to_insert) - .chain(after.iter().cloned()) - .collect::>() - } - }; - - self.with_children(new_children) - } - - /// Replaces all nodes in `to_delete` with nodes from `to_insert` - /// - /// This is a type-unsafe low-level editing API, if you need to use it, - /// prefer to create a type-safe abstraction on top of it instead. - pub fn replace_children( - &self, - to_delete: RangeInclusive, - to_insert: impl Iterator, - ) -> SyntaxNode { - let start = self.position_of_child(to_delete.start().clone()); - let end = self.position_of_child(to_delete.end().clone()); - let old_children = self.0.green().children(); - - let new_children = old_children[..start] - .iter() - .cloned() - .chain(to_insert.map(to_green_element)) - .chain(old_children[end + 1..].iter().cloned()) - .collect::>(); - self.with_children(new_children) - } - - fn with_children(&self, new_children: Box<[rowan::GreenElement]>) -> SyntaxNode { - let len = new_children.iter().map(|it| it.text_len()).sum::(); - let new_node = GreenNode::new(rowan::SyntaxKind(self.kind() as u16), new_children); - let new_file_node = self.replace_with(new_node); - let file = SourceFile::new(new_file_node); - - // FIXME: use a more elegant way to re-fetch the node (#1185), make - // `range` private afterwards - let mut ptr = SyntaxNodePtr::new(self); - ptr.range = TextRange::offset_len(ptr.range().start(), len); - ptr.to_node(file.syntax()).to_owned() - } - - fn position_of_child(&self, child: SyntaxElement) -> usize { - self.children_with_tokens() - .position(|it| it == child) - .expect("element is not a child of current element") + fn kind_to_raw(kind: SyntaxKind) -> rowan::cursor::SyntaxKind { + rowan::cursor::SyntaxKind(kind.into()) } } -fn to_green_element(element: SyntaxElement) -> rowan::GreenElement { - match element { - SyntaxElement::Node(node) => node.0.green().clone().into(), - SyntaxElement::Token(tok) => { - GreenToken::new(rowan::SyntaxKind(tok.kind() as u16), tok.text().clone()).into() - } - } -} - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct SyntaxToken(pub(crate) rowan::cursor::SyntaxToken); - -impl fmt::Debug for SyntaxToken { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}@{:?}", self.kind(), self.text_range())?; - if self.text().len() < 25 { - return write!(fmt, " {:?}", self.text()); - } - let text = self.text().as_str(); - for idx in 21..25 { - if text.is_char_boundary(idx) { - let text = format!("{} ...", &text[..idx]); - return write!(fmt, " {:?}", text); - } - } - unreachable!() - } -} +pub type SyntaxNode = rowan::SyntaxNode; +pub type SyntaxToken = rowan::SyntaxToken; +pub type SyntaxElement = rowan::NodeOrToken; +pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren; +pub type SyntaxElementChildren = rowan::SyntaxElementChildren; -impl fmt::Display for SyntaxToken { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.text(), fmt) - } -} - -impl SyntaxToken { - pub fn kind(&self) -> SyntaxKind { - self.0.kind().0.into() - } - - pub fn text(&self) -> &SmolStr { - self.0.text() - } - - pub fn text_range(&self) -> TextRange { - self.0.text_range() - } - - pub fn parent(&self) -> SyntaxNode { - SyntaxNode(self.0.parent()) - } - - pub fn next_sibling_or_token(&self) -> Option { - self.0.next_sibling_or_token().map(SyntaxElement::new) - } - - pub fn prev_sibling_or_token(&self) -> Option { - self.0.prev_sibling_or_token().map(SyntaxElement::new) - } - - pub fn siblings_with_tokens( - &self, - direction: Direction, - ) -> impl Iterator { - let me: SyntaxElement = self.clone().into(); - successors(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) - } - - pub fn prev_token(&self) -> Option { - self.0.prev_token().map(SyntaxToken) - } - - pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode { - self.0.replace_with(new_token) - } -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum SyntaxElement { - Node(SyntaxNode), - Token(SyntaxToken), -} - -impl From for SyntaxElement { - fn from(node: SyntaxNode) -> Self { - SyntaxElement::Node(node) - } -} - -impl From for SyntaxElement { - fn from(token: SyntaxToken) -> Self { - SyntaxElement::Token(token) - } -} - -impl fmt::Display for SyntaxElement { - 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 SyntaxElement { - pub(crate) fn new(el: rowan::cursor::SyntaxElement) -> Self { - match el { - rowan::cursor::SyntaxElement::Node(it) => SyntaxElement::Node(SyntaxNode(it)), - rowan::cursor::SyntaxElement::Token(it) => SyntaxElement::Token(SyntaxToken(it)), - } - } - - pub fn kind(&self) -> SyntaxKind { - match self { - SyntaxElement::Node(it) => it.kind(), - SyntaxElement::Token(it) => it.kind(), - } - } - - pub fn as_node(&self) -> Option<&SyntaxNode> { - match self { - SyntaxElement::Node(node) => Some(node), - SyntaxElement::Token(_) => None, - } - } - - pub fn into_node(self) -> Option { - match self { - SyntaxElement::Node(node) => Some(node), - SyntaxElement::Token(_) => None, - } - } - - pub fn as_token(&self) -> Option<&SyntaxToken> { - match self { - SyntaxElement::Node(_) => None, - SyntaxElement::Token(token) => Some(token), - } - } - - pub fn into_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.clone(), - SyntaxElement::Token(it) => it.parent(), - } - .ancestors() - } - - pub fn text_range(&self) -> TextRange { - match self { - SyntaxElement::Node(it) => it.text_range(), - SyntaxElement::Token(it) => it.text_range(), - } - } - - fn text_len(&self) -> TextUnit { - match self { - SyntaxElement::Node(node) => node.0.green().text_len(), - SyntaxElement::Token(token) => TextUnit::of_str(token.0.text()), - } - } -} - -#[derive(Clone, Debug)] -pub struct SyntaxNodeChildren(rowan::cursor::SyntaxNodeChildren); - -impl Iterator for SyntaxNodeChildren { - type Item = SyntaxNode; - fn next(&mut self) -> Option { - self.0.next().map(SyntaxNode) - } -} - -#[derive(Clone, Debug)] -pub struct SyntaxElementChildren(rowan::cursor::SyntaxElementChildren); - -impl Iterator for SyntaxElementChildren { - type Item = SyntaxElement; - fn next(&mut self) -> Option { - self.0.next().map(SyntaxElement::new) - } -} +pub use rowan::{Direction, NodeOrToken}; pub struct SyntaxTreeBuilder { errors: Vec, @@ -507,19 +66,21 @@ impl SyntaxTreeBuilder { pub fn finish(self) -> Parse { let (green, errors) = self.finish_raw(); - let node = SyntaxNode::new(green); + let node = SyntaxNode::new_root(green); if cfg!(debug_assertions) { crate::validation::validate_block_structure(&node); } - Parse::new(node.0.green().clone(), errors) + Parse::new(node.green().clone(), errors) } pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { - self.inner.token(rowan::SyntaxKind(kind.into()), text) + let kind = RustLanguage::kind_to_raw(kind); + self.inner.token(kind, text) } pub fn start_node(&mut self, kind: SyntaxKind) { - self.inner.start_node(rowan::SyntaxKind(kind.into())) + let kind = RustLanguage::kind_to_raw(kind); + self.inner.start_node(kind) } pub fn finish_node(&mut self) { diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs deleted file mode 100644 index 652cb7a1e..000000000 --- a/crates/ra_syntax/src/syntax_text.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::{ - fmt, - ops::{self, Bound}, -}; - -use crate::{SmolStr, SyntaxElement, SyntaxNode, TextRange, TextUnit}; - -#[derive(Clone)] -pub struct SyntaxText { - node: SyntaxNode, - range: TextRange, -} - -impl SyntaxText { - pub(crate) fn new(node: SyntaxNode) -> SyntaxText { - let range = node.text_range(); - SyntaxText { node, range } - } - - pub fn try_fold_chunks(&self, init: T, mut f: F) -> Result - where - F: FnMut(T, &str) -> Result, - { - self.node.descendants_with_tokens().try_fold(init, move |acc, element| { - let res = match element { - SyntaxElement::Token(token) => { - let range = match self.range.intersection(&token.text_range()) { - None => return Ok(acc), - Some(it) => it, - }; - let slice = if range == token.text_range() { - token.text() - } else { - let range = range - token.text_range().start(); - &token.text()[range] - }; - f(acc, slice)? - } - SyntaxElement::Node(_) => acc, - }; - Ok(res) - }) - } - - pub fn try_for_each_chunk Result<(), E>, E>( - &self, - mut f: F, - ) -> Result<(), E> { - self.try_fold_chunks((), move |(), chunk| f(chunk)) - } - - pub fn for_each_chunk(&self, mut f: F) { - enum Void {} - match self.try_for_each_chunk(|chunk| Ok::<(), Void>(f(chunk))) { - Ok(()) => (), - Err(void) => match void {}, - } - } - - pub fn to_smol_string(&self) -> SmolStr { - self.to_string().into() - } - - pub fn contains_char(&self, c: char) -> bool { - self.try_for_each_chunk(|chunk| if chunk.contains(c) { Err(()) } else { Ok(()) }).is_err() - } - - pub fn find_char(&self, c: char) -> Option { - let mut acc: TextUnit = 0.into(); - let res = self.try_for_each_chunk(|chunk| { - if let Some(pos) = chunk.find(c) { - let pos: TextUnit = (pos as u32).into(); - return Err(acc + pos); - } - acc += TextUnit::of_str(chunk); - Ok(()) - }); - found(res) - } - - pub fn len(&self) -> TextUnit { - self.range.len() - } - - pub fn is_empty(&self) -> bool { - self.range.is_empty() - } - - pub fn slice(&self, range: impl ops::RangeBounds) -> SyntaxText { - let start = match range.start_bound() { - Bound::Included(&b) => b, - Bound::Excluded(_) => panic!("utf-aware slicing can't work this way"), - Bound::Unbounded => 0.into(), - }; - let end = match range.end_bound() { - Bound::Included(_) => panic!("utf-aware slicing can't work this way"), - Bound::Excluded(&b) => b, - Bound::Unbounded => self.len(), - }; - assert!(start <= end); - let len = end - start; - let start = self.range.start() + start; - let end = start + len; - assert!( - start <= end, - "invalid slice, range: {:?}, slice: {:?}", - self.range, - (range.start_bound(), range.end_bound()), - ); - let range = TextRange::from_to(start, end); - assert!( - range.is_subrange(&self.range), - "invalid slice, range: {:?}, slice: {:?}", - self.range, - range, - ); - SyntaxText { node: self.node.clone(), range } - } - - pub fn char_at(&self, offset: impl Into) -> Option { - let offset = offset.into(); - let mut start: TextUnit = 0.into(); - let res = self.try_for_each_chunk(|chunk| { - let end = start + TextUnit::of_str(chunk); - if start <= offset && offset < end { - let off: usize = u32::from(offset - start) as usize; - return Err(chunk[off..].chars().next().unwrap()); - } - start = end; - Ok(()) - }); - found(res) - } -} - -fn found(res: Result<(), T>) -> Option { - match res { - Ok(()) => None, - Err(it) => Some(it), - } -} - -impl fmt::Debug for SyntaxText { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.to_string(), f) - } -} - -impl fmt::Display for SyntaxText { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.try_for_each_chunk(|chunk| fmt::Display::fmt(chunk, f)) - } -} - -impl From for String { - fn from(text: SyntaxText) -> String { - text.to_string() - } -} - -impl PartialEq for SyntaxText { - fn eq(&self, mut rhs: &str) -> bool { - self.try_for_each_chunk(|chunk| { - if !rhs.starts_with(chunk) { - return Err(()); - } - rhs = &rhs[chunk.len()..]; - Ok(()) - }) - .is_ok() - } -} - -impl PartialEq<&'_ str> for SyntaxText { - fn eq(&self, rhs: &&str) -> bool { - self == *rhs - } -} -- cgit v1.2.3 From 62be91b82d6368a20a40893b199bc4f7a35a2223 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 21 Jul 2019 13:08:32 +0300 Subject: minor, move type --- crates/ra_syntax/src/algo.rs | 12 ++++++++++-- crates/ra_syntax/src/lib.rs | 5 +++-- crates/ra_syntax/src/syntax_node.rs | 8 -------- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'crates/ra_syntax/src') diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index 6bb46b021..ecd42c133 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -5,8 +5,8 @@ use std::ops::RangeInclusive; use itertools::Itertools; use crate::{ - AstNode, Direction, InsertPosition, NodeOrToken, SourceFile, SyntaxElement, SyntaxNode, - SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, + AstNode, Direction, NodeOrToken, SourceFile, SyntaxElement, SyntaxNode, SyntaxNodePtr, + SyntaxToken, TextRange, TextUnit, }; pub use rowan::TokenAtOffset; @@ -61,6 +61,14 @@ pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxEleme root.covering_element(range) } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum InsertPosition { + First, + Last, + Before(T), + After(T), +} + /// Adds specified children (tokens or nodes) to the current node at the /// specific position. /// diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 21c07d69a..7b778f38c 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -37,13 +37,14 @@ use ra_text_edit::AtomTextEdit; use crate::syntax_node::GreenNode; pub use crate::{ + algo::InsertPosition, ast::{AstNode, AstToken}, parsing::{classify_literal, tokenize, Token}, ptr::{AstPtr, SyntaxNodePtr}, syntax_error::{Location, SyntaxError, SyntaxErrorKind}, syntax_node::{ - Direction, InsertPosition, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, - SyntaxTreeBuilder, WalkEvent, + Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, + WalkEvent, }, }; pub use ra_parser::SyntaxKind; diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index 689dbefde..95795a27a 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs @@ -17,14 +17,6 @@ use crate::{ pub use rowan::WalkEvent; pub(crate) use rowan::{GreenNode, GreenToken}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum InsertPosition { - First, - Last, - Before(T), - After(T), -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum RustLanguage {} impl Language for RustLanguage { -- cgit v1.2.3 From d52ee59a712932bc381d8c690dc2f681598760fe Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 21 Jul 2019 13:28:58 +0300 Subject: streamline API --- crates/ra_syntax/src/algo.rs | 17 +++++------------ crates/ra_syntax/src/lib.rs | 6 ++---- crates/ra_syntax/src/syntax_node.rs | 1 - 3 files changed, 7 insertions(+), 17 deletions(-) (limited to 'crates/ra_syntax/src') diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index ecd42c133..45f624810 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -5,16 +5,9 @@ use std::ops::RangeInclusive; use itertools::Itertools; use crate::{ - AstNode, Direction, NodeOrToken, SourceFile, SyntaxElement, SyntaxNode, SyntaxNodePtr, - SyntaxToken, TextRange, TextUnit, + AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, }; -pub use rowan::TokenAtOffset; - -pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset { - node.token_at_offset(offset) -} - /// Returns ancestors of the node at the offset, sorted by length. This should /// do the right thing at an edge, e.g. when searching for expressions at `{ /// <|>foo }` we will get the name reference instead of the whole block, which @@ -24,7 +17,7 @@ pub fn ancestors_at_offset( node: &SyntaxNode, offset: TextUnit, ) -> impl Iterator { - find_token_at_offset(node, offset) + node.token_at_offset(offset) .map(|token| token.parent().ancestors()) .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) } @@ -137,14 +130,14 @@ fn with_children( let len = new_children.iter().map(|it| it.text_len()).sum::(); let new_node = rowan::GreenNode::new(rowan::cursor::SyntaxKind(parent.kind() as u16), new_children); - let new_file_node = parent.replace_with(new_node); - let file = SourceFile::new(new_file_node); + let new_root_node = parent.replace_with(new_node); + let new_root_node = SyntaxNode::new_root(new_root_node); // FIXME: use a more elegant way to re-fetch the node (#1185), make // `range` private afterwards let mut ptr = SyntaxNodePtr::new(parent); ptr.range = TextRange::offset_len(ptr.range().start(), len); - ptr.to_node(file.syntax()).to_owned() + ptr.to_node(&new_root_node) } fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize { diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index 7b778f38c..d02078256 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -44,12 +44,10 @@ pub use crate::{ syntax_error::{Location, SyntaxError, SyntaxErrorKind}, syntax_node::{ Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, - WalkEvent, }, }; -pub use ra_parser::SyntaxKind; -pub use ra_parser::T; -pub use rowan::{SmolStr, SyntaxText, TextRange, TextUnit}; +pub use ra_parser::{SyntaxKind, T}; +pub use rowan::{SmolStr, SyntaxText, TextRange, TextUnit, TokenAtOffset, WalkEvent}; /// `Parse` is the result of the parsing: a syntax tree and a collection of /// errors. diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs index 95795a27a..b2f5b8c64 100644 --- a/crates/ra_syntax/src/syntax_node.rs +++ b/crates/ra_syntax/src/syntax_node.rs @@ -14,7 +14,6 @@ use crate::{ Parse, SmolStr, SyntaxKind, TextUnit, }; -pub use rowan::WalkEvent; pub(crate) use rowan::{GreenNode, GreenToken}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -- cgit v1.2.3 From 773ad2edb3b84bf20378a577bc4cd808384de078 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 21 Jul 2019 13:34:15 +0300 Subject: simiplify --- crates/ra_syntax/src/lib.rs | 15 +++++++-------- crates/ra_syntax/src/validation.rs | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'crates/ra_syntax/src') diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index d02078256..7f69b86e1 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -143,18 +143,17 @@ impl Parse { pub use crate::ast::SourceFile; impl SourceFile { - fn new(green: GreenNode) -> SourceFile { - let root = SyntaxNode::new_root(green); + pub fn parse(text: &str) -> Parse { + let (green, mut errors) = parsing::parse_text(text); + let root = SyntaxNode::new_root(green.clone()); + if cfg!(debug_assertions) { validation::validate_block_structure(&root); } - assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); - SourceFile::cast(root).unwrap() - } - pub fn parse(text: &str) -> Parse { - let (green, mut errors) = parsing::parse_text(text); - errors.extend(validation::validate(&SourceFile::new(green.clone()))); + errors.extend(validation::validate(&root)); + + assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE); Parse { green, errors: Arc::new(errors), _ty: PhantomData } } } diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 19bdafef2..e03c02d1b 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs @@ -5,16 +5,16 @@ mod field_expr; use crate::{ algo::visit::{visitor_ctx, VisitorCtx}, - ast, AstNode, SourceFile, SyntaxError, + ast, SyntaxError, SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING}, SyntaxNode, TextUnit, T, }; pub(crate) use unescape::EscapeError; -pub(crate) fn validate(file: &SourceFile) -> Vec { +pub(crate) fn validate(root: &SyntaxNode) -> Vec { let mut errors = Vec::new(); - for node in file.syntax().descendants() { + for node in root.descendants() { let _ = visitor_ctx(&mut errors) .visit::(validate_literal) .visit::(block::validate_block_node) -- cgit v1.2.3