From d7e169fe55a15dd684e7a93dd111c66ed49ed949 Mon Sep 17 00:00:00 2001 From: Dawer <7803845+iDawer@users.noreply.github.com> Date: Thu, 6 May 2021 10:07:06 +0500 Subject: [PATCH] Borrow text from nodes of immutable syntax trees --- crates/syntax/src/ast/node_ext.rs | 36 +++++++++++++++++++++-------- crates/syntax/src/token_text.rs | 38 ++++++++++++++++++------------- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 492fbc4a0fb..8e6d7b092f1 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -1,10 +1,11 @@ //! Various extension methods to ast Nodes, which are hard to code-generate. //! Extensions for various expressions live in a sibling `expr_extensions` module. -use std::{fmt, iter::successors}; +use std::{borrow::Cow, fmt, iter::successors}; use itertools::Itertools; use parser::SyntaxKind; +use rowan::{GreenNodeData, GreenTokenData, NodeOrToken}; use crate::{ ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, @@ -12,19 +13,19 @@ }; impl ast::Lifetime { - pub fn text(&self) -> TokenText { + pub fn text(&self) -> TokenText<'_> { text_of_first_token(self.syntax()) } } impl ast::Name { - pub fn text(&self) -> TokenText { + pub fn text(&self) -> TokenText<'_> { text_of_first_token(self.syntax()) } } impl ast::NameRef { - pub fn text(&self) -> TokenText { + pub fn text(&self) -> TokenText<'_> { text_of_first_token(self.syntax()) } @@ -33,11 +34,28 @@ pub fn as_tuple_field(&self) -> Option { } } -fn text_of_first_token(node: &SyntaxNode) -> TokenText { - let first_token = - node.green().children().next().and_then(|it| it.into_token()).unwrap().to_owned(); +fn _text_of_first_token(node: &SyntaxNode) -> Cow<'_, str> { + fn cow_map &str>(green: Cow, f: F) -> Cow { + match green { + Cow::Borrowed(green_ref) => Cow::Borrowed(f(green_ref)), + Cow::Owned(green) => Cow::Owned(f(&green).to_owned()), + } + } + + cow_map(node.green(), |green_ref| { + green_ref.children().next().and_then(NodeOrToken::into_token).unwrap().text() + }) +} - TokenText(first_token) +fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> { + fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData { + green_ref.children().next().and_then(NodeOrToken::into_token).unwrap() + } + + match node.green() { + Cow::Borrowed(green_ref) => TokenText::Borrowed(first_token(green_ref).text()), + Cow::Owned(green) => TokenText::Owned(first_token(&green).to_owned()), + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -412,7 +430,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } impl NameOrNameRef { - pub fn text(&self) -> TokenText { + pub fn text(&self) -> TokenText<'_> { match self { NameOrNameRef::Name(name) => name.text(), NameOrNameRef::NameRef(name_ref) => name_ref.text(), diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs index d2ed0a12a46..e29f4eea402 100644 --- a/crates/syntax/src/token_text.rs +++ b/crates/syntax/src/token_text.rs @@ -2,75 +2,81 @@ use std::{cmp::Ordering, fmt, ops}; -pub struct TokenText(pub(crate) rowan::GreenToken); +pub enum TokenText<'a> { + Borrowed(&'a str), + Owned(rowan::GreenToken), +} -impl TokenText { +impl TokenText<'_> { pub fn as_str(&self) -> &str { - self.0.text() + match self { + TokenText::Borrowed(it) => *it, + TokenText::Owned(green) => green.text(), + } } } -impl ops::Deref for TokenText { +impl ops::Deref for TokenText<'_> { type Target = str; fn deref(&self) -> &str { self.as_str() } } -impl AsRef for TokenText { +impl AsRef for TokenText<'_> { fn as_ref(&self) -> &str { self.as_str() } } -impl From for String { +impl From> for String { fn from(token_text: TokenText) -> Self { token_text.as_str().into() } } -impl PartialEq<&'_ str> for TokenText { +impl PartialEq<&'_ str> for TokenText<'_> { fn eq(&self, other: &&str) -> bool { self.as_str() == *other } } -impl PartialEq for &'_ str { +impl PartialEq> for &'_ str { fn eq(&self, other: &TokenText) -> bool { other == self } } -impl PartialEq for TokenText { +impl PartialEq for TokenText<'_> { fn eq(&self, other: &String) -> bool { self.as_str() == other.as_str() } } -impl PartialEq for String { +impl PartialEq> for String { fn eq(&self, other: &TokenText) -> bool { other == self } } -impl PartialEq for TokenText { +impl PartialEq for TokenText<'_> { fn eq(&self, other: &TokenText) -> bool { self.as_str() == other.as_str() } } -impl Eq for TokenText {} -impl Ord for TokenText { +impl Eq for TokenText<'_> {} +impl Ord for TokenText<'_> { fn cmp(&self, other: &Self) -> Ordering { self.as_str().cmp(other.as_str()) } } -impl PartialOrd for TokenText { +impl PartialOrd for TokenText<'_> { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl fmt::Display for TokenText { +impl fmt::Display for TokenText<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self.as_str(), f) } } -impl fmt::Debug for TokenText { +impl fmt::Debug for TokenText<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.as_str(), f) } -- 2.44.0