aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax')
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/algo.rs124
-rw-r--r--crates/syntax/src/ast/edit.rs12
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs19
-rw-r--r--crates/syntax/src/ast/make.rs128
-rw-r--r--crates/syntax/src/ast/node_ext.rs25
-rw-r--r--crates/syntax/src/ted.rs5
-rw-r--r--crates/syntax/src/token_text.rs50
8 files changed, 152 insertions, 213 deletions
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 556f80882..c0bc59918 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "=0.13.0-pre.3" 16rowan = "=0.13.0-pre.5"
17rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.7" 19arrayvec = "0.7"
diff --git a/crates/syntax/src/algo.rs b/crates/syntax/src/algo.rs
index c9229c4e0..3f9b84ab9 100644
--- a/crates/syntax/src/algo.rs
+++ b/crates/syntax/src/algo.rs
@@ -1,10 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{fmt, hash::BuildHasherDefault, ops::RangeInclusive};
4 fmt,
5 hash::BuildHasherDefault,
6 ops::{self, RangeInclusive},
7};
8 4
9use indexmap::IndexMap; 5use indexmap::IndexMap;
10use itertools::Itertools; 6use itertools::Itertools;
@@ -358,107 +354,11 @@ impl fmt::Debug for SyntaxRewriter<'_> {
358} 354}
359 355
360impl SyntaxRewriter<'_> { 356impl SyntaxRewriter<'_> {
361 pub fn delete<T: Clone + Into<SyntaxElement>>(&mut self, what: &T) {
362 let what = what.clone().into();
363 let replacement = Replacement::Delete;
364 self.replacements.insert(what, replacement);
365 }
366 pub fn insert_before<T: Clone + Into<SyntaxElement>, U: Clone + Into<SyntaxElement>>(
367 &mut self,
368 before: &T,
369 what: &U,
370 ) {
371 let before = before.clone().into();
372 let pos = match before.prev_sibling_or_token() {
373 Some(sibling) => InsertPos::After(sibling),
374 None => match before.parent() {
375 Some(parent) => InsertPos::FirstChildOf(parent),
376 None => return,
377 },
378 };
379 self.insertions.entry(pos).or_insert_with(Vec::new).push(what.clone().into());
380 }
381 pub fn insert_after<T: Clone + Into<SyntaxElement>, U: Clone + Into<SyntaxElement>>(
382 &mut self,
383 after: &T,
384 what: &U,
385 ) {
386 self.insertions
387 .entry(InsertPos::After(after.clone().into()))
388 .or_insert_with(Vec::new)
389 .push(what.clone().into());
390 }
391 pub fn insert_as_first_child<T: Clone + Into<SyntaxNode>, U: Clone + Into<SyntaxElement>>(
392 &mut self,
393 parent: &T,
394 what: &U,
395 ) {
396 self.insertions
397 .entry(InsertPos::FirstChildOf(parent.clone().into()))
398 .or_insert_with(Vec::new)
399 .push(what.clone().into());
400 }
401 pub fn insert_many_before<
402 T: Clone + Into<SyntaxElement>,
403 U: IntoIterator<Item = SyntaxElement>,
404 >(
405 &mut self,
406 before: &T,
407 what: U,
408 ) {
409 let before = before.clone().into();
410 let pos = match before.prev_sibling_or_token() {
411 Some(sibling) => InsertPos::After(sibling),
412 None => match before.parent() {
413 Some(parent) => InsertPos::FirstChildOf(parent),
414 None => return,
415 },
416 };
417 self.insertions.entry(pos).or_insert_with(Vec::new).extend(what);
418 }
419 pub fn insert_many_after<
420 T: Clone + Into<SyntaxElement>,
421 U: IntoIterator<Item = SyntaxElement>,
422 >(
423 &mut self,
424 after: &T,
425 what: U,
426 ) {
427 self.insertions
428 .entry(InsertPos::After(after.clone().into()))
429 .or_insert_with(Vec::new)
430 .extend(what);
431 }
432 pub fn insert_many_as_first_children<
433 T: Clone + Into<SyntaxNode>,
434 U: IntoIterator<Item = SyntaxElement>,
435 >(
436 &mut self,
437 parent: &T,
438 what: U,
439 ) {
440 self.insertions
441 .entry(InsertPos::FirstChildOf(parent.clone().into()))
442 .or_insert_with(Vec::new)
443 .extend(what)
444 }
445 pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) { 357 pub fn replace<T: Clone + Into<SyntaxElement>>(&mut self, what: &T, with: &T) {
446 let what = what.clone().into(); 358 let what = what.clone().into();
447 let replacement = Replacement::Single(with.clone().into()); 359 let replacement = Replacement::Single(with.clone().into());
448 self.replacements.insert(what, replacement); 360 self.replacements.insert(what, replacement);
449 } 361 }
450 pub fn replace_with_many<T: Clone + Into<SyntaxElement>>(
451 &mut self,
452 what: &T,
453 with: Vec<SyntaxElement>,
454 ) {
455 let what = what.clone().into();
456 let replacement = Replacement::Many(with);
457 self.replacements.insert(what, replacement);
458 }
459 pub fn replace_ast<T: AstNode>(&mut self, what: &T, with: &T) {
460 self.replace(what.syntax(), with.syntax())
461 }
462 362
463 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode { 363 pub fn rewrite(&self, node: &SyntaxNode) -> SyntaxNode {
464 let _p = profile::span("rewrite"); 364 let _p = profile::span("rewrite");
@@ -534,10 +434,6 @@ impl SyntaxRewriter<'_> {
534 if let Some(replacement) = self.replacement(&element) { 434 if let Some(replacement) = self.replacement(&element) {
535 match replacement { 435 match replacement {
536 Replacement::Single(element) => acc.push(element_to_green(element)), 436 Replacement::Single(element) => acc.push(element_to_green(element)),
537 Replacement::Many(replacements) => {
538 acc.extend(replacements.into_iter().map(element_to_green))
539 }
540 Replacement::Delete => (),
541 }; 437 };
542 } else { 438 } else {
543 match element { 439 match element {
@@ -555,30 +451,14 @@ impl SyntaxRewriter<'_> {
555 451
556fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> { 452fn element_to_green(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> {
557 match element { 453 match element {
558 NodeOrToken::Node(it) => NodeOrToken::Node(it.green()), 454 NodeOrToken::Node(it) => NodeOrToken::Node(it.green().into_owned()),
559 NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()), 455 NodeOrToken::Token(it) => NodeOrToken::Token(it.green().to_owned()),
560 } 456 }
561} 457}
562 458
563impl ops::AddAssign for SyntaxRewriter<'_> {
564 fn add_assign(&mut self, rhs: SyntaxRewriter) {
565 self.replacements.extend(rhs.replacements);
566 for (pos, insertions) in rhs.insertions.into_iter() {
567 match self.insertions.entry(pos) {
568 indexmap::map::Entry::Occupied(mut occupied) => {
569 occupied.get_mut().extend(insertions)
570 }
571 indexmap::map::Entry::Vacant(vacant) => drop(vacant.insert(insertions)),
572 }
573 }
574 }
575}
576
577#[derive(Clone, Debug)] 459#[derive(Clone, Debug)]
578enum Replacement { 460enum Replacement {
579 Delete,
580 Single(SyntaxElement), 461 Single(SyntaxElement),
581 Many(Vec<SyntaxElement>),
582} 462}
583 463
584fn with_children( 464fn with_children(
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs
index 8c60927e4..cbc75f922 100644
--- a/crates/syntax/src/ast/edit.rs
+++ b/crates/syntax/src/ast/edit.rs
@@ -665,18 +665,8 @@ pub trait AstNodeEdit: AstNode + Clone + Sized {
665 665
666 #[must_use] 666 #[must_use]
667 fn replace_descendant<D: AstNode>(&self, old: D, new: D) -> Self { 667 fn replace_descendant<D: AstNode>(&self, old: D, new: D) -> Self {
668 self.replace_descendants(iter::once((old, new)))
669 }
670
671 #[must_use]
672 fn replace_descendants<D: AstNode>(
673 &self,
674 replacement_map: impl IntoIterator<Item = (D, D)>,
675 ) -> Self {
676 let mut rewriter = SyntaxRewriter::default(); 668 let mut rewriter = SyntaxRewriter::default();
677 for (from, to) in replacement_map { 669 rewriter.replace(old.syntax(), new.syntax());
678 rewriter.replace(from.syntax(), to.syntax())
679 }
680 rewriter.rewrite_ast(self) 670 rewriter.rewrite_ast(self)
681 } 671 }
682 fn indent_level(&self) -> IndentLevel { 672 fn indent_level(&self) -> IndentLevel {
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 04f97f368..168355555 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -195,18 +195,13 @@ impl ast::GenericParamList {
195 pub fn add_generic_param(&self, generic_param: ast::GenericParam) { 195 pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
196 match self.generic_params().last() { 196 match self.generic_params().last() {
197 Some(last_param) => { 197 Some(last_param) => {
198 let mut elems = Vec::new(); 198 let position = Position::after(last_param.syntax());
199 if !last_param 199 let elements = vec![
200 .syntax() 200 make::token(T![,]).into(),
201 .siblings_with_tokens(Direction::Next) 201 make::tokens::single_space().into(),
202 .any(|it| it.kind() == T![,]) 202 generic_param.syntax().clone().into(),
203 { 203 ];
204 elems.push(make::token(T![,]).into()); 204 ted::insert_all(position, elements);
205 elems.push(make::tokens::single_space().into());
206 };
207 elems.push(generic_param.syntax().clone().into());
208 let after_last_param = Position::after(last_param.syntax());
209 ted::insert_all(after_last_param, elems);
210 } 205 }
211 None => { 206 None => {
212 let after_l_angle = Position::after(self.l_angle_token().unwrap()); 207 let after_l_angle = Position::after(self.l_angle_token().unwrap());
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 42da09606..1998ad1f6 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -3,31 +3,81 @@
3//! 3//!
4//! Note that all functions here intended to be stupid constructors, which just 4//! Note that all functions here intended to be stupid constructors, which just
5//! assemble a finish node from immediate children. If you want to do something 5//! assemble a finish node from immediate children. If you want to do something
6//! smarter than that, it probably doesn't belong in this module. 6//! smarter than that, it belongs to the `ext` submodule.
7//! 7//!
8//! Keep in mind that `from_text` functions should be kept private. The public 8//! Keep in mind that `from_text` functions should be kept private. The public
9//! API should require to assemble every node piecewise. The trick of 9//! API should require to assemble every node piecewise. The trick of
10//! `parse(format!())` we use internally is an implementation detail -- long 10//! `parse(format!())` we use internally is an implementation detail -- long
11//! term, it will be replaced with direct tree manipulation. 11//! term, it will be replaced with direct tree manipulation.
12use itertools::Itertools; 12use itertools::Itertools;
13use stdx::format_to; 13use stdx::{format_to, never};
14 14
15use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken}; 15use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};
16 16
17pub fn name(text: &str) -> ast::Name { 17/// While the parent module defines basic atomic "constructors", the `ext`
18 ast_from_text(&format!("mod {};", text)) 18/// module defines shortcuts for common things.
19///
20/// It's named `ext` rather than `shortcuts` just to keep it short.
21pub mod ext {
22 use super::*;
23
24 pub fn ident_path(ident: &str) -> ast::Path {
25 path_unqualified(path_segment(name_ref(ident)))
26 }
27
28 pub fn expr_unreachable() -> ast::Expr {
29 expr_from_text("unreachable!()")
30 }
31 pub fn expr_todo() -> ast::Expr {
32 expr_from_text("todo!()")
33 }
34 pub fn empty_block_expr() -> ast::BlockExpr {
35 block_expr(None, None)
36 }
37
38 pub fn ty_bool() -> ast::Type {
39 ty_path(ident_path("bool"))
40 }
41 pub fn ty_option(t: ast::Type) -> ast::Type {
42 ty_from_text(&format!("Option<{}>", t))
43 }
44 pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type {
45 ty_from_text(&format!("Result<{}, {}>", t, e))
46 }
19} 47}
20 48
49pub fn name(text: &str) -> ast::Name {
50 ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text))
51}
21pub fn name_ref(text: &str) -> ast::NameRef { 52pub fn name_ref(text: &str) -> ast::NameRef {
22 ast_from_text(&format!("fn f() {{ {}; }}", text)) 53 ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text))
23} 54}
55fn raw_ident_esc(ident: &str) -> &'static str {
56 let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some();
57 if is_keyword && !matches!(ident, "self" | "crate" | "super" | "Self") {
58 "r#"
59 } else {
60 ""
61 }
62}
63
64pub fn lifetime(text: &str) -> ast::Lifetime {
65 let mut text = text;
66 let tmp;
67 if never!(!text.starts_with('\'')) {
68 tmp = format!("'{}", text);
69 text = &tmp;
70 }
71 ast_from_text(&format!("fn f<{}>() {{ }}", text))
72}
73
24// FIXME: replace stringly-typed constructor with a family of typed ctors, a-la 74// FIXME: replace stringly-typed constructor with a family of typed ctors, a-la
25// `expr_xxx`. 75// `expr_xxx`.
26pub fn ty(text: &str) -> ast::Type { 76pub fn ty(text: &str) -> ast::Type {
27 ast_from_text(&format!("fn f() -> {} {{}}", text)) 77 ty_from_text(text)
28} 78}
29pub fn ty_unit() -> ast::Type { 79pub fn ty_unit() -> ast::Type {
30 ty("()") 80 ty_from_text("()")
31} 81}
32pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { 82pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
33 let mut count: usize = 0; 83 let mut count: usize = 0;
@@ -36,15 +86,16 @@ pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
36 contents.push(','); 86 contents.push(',');
37 } 87 }
38 88
39 ty(&format!("({})", contents)) 89 ty_from_text(&format!("({})", contents))
40}
41// FIXME: handle path to type
42pub fn ty_generic(name: ast::NameRef, types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
43 let contents = types.into_iter().join(", ");
44 ty(&format!("{}<{}>", name, contents))
45} 90}
46pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { 91pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type {
47 ty(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) 92 ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) })
93}
94pub fn ty_path(path: ast::Path) -> ast::Type {
95 ty_from_text(&path.to_string())
96}
97fn ty_from_text(text: &str) -> ast::Type {
98 ast_from_text(&format!("type _T = {};", text))
48} 99}
49 100
50pub fn assoc_item_list() -> ast::AssocItemList { 101pub fn assoc_item_list() -> ast::AssocItemList {
@@ -78,7 +129,7 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
78pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { 129pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
79 ast_from_text(&format!("{}::{}", qual, segment)) 130 ast_from_text(&format!("{}::{}", qual, segment))
80} 131}
81 132// FIXME: path concatenation operation doesn't make sense as AST op.
82pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { 133pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path {
83 ast_from_text(&format!("{}::{}", first, second)) 134 ast_from_text(&format!("{}::{}", first, second))
84} 135}
@@ -94,15 +145,14 @@ pub fn path_from_segments(
94 format!("use {};", segments) 145 format!("use {};", segments)
95 }) 146 })
96} 147}
97 148// FIXME: should not be pub
98pub fn path_from_text(text: &str) -> ast::Path { 149pub fn path_from_text(text: &str) -> ast::Path {
99 ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) 150 ast_from_text(&format!("fn main() {{ let test = {}; }}", text))
100} 151}
101 152
102pub fn glob_use_tree() -> ast::UseTree { 153pub fn use_tree_glob() -> ast::UseTree {
103 ast_from_text("use *;") 154 ast_from_text("use *;")
104} 155}
105
106pub fn use_tree( 156pub fn use_tree(
107 path: ast::Path, 157 path: ast::Path,
108 use_tree_list: Option<ast::UseTreeList>, 158 use_tree_list: Option<ast::UseTreeList>,
@@ -197,15 +247,6 @@ pub fn expr_literal(text: &str) -> ast::Literal {
197pub fn expr_empty_block() -> ast::Expr { 247pub fn expr_empty_block() -> ast::Expr {
198 expr_from_text("{}") 248 expr_from_text("{}")
199} 249}
200pub fn expr_unimplemented() -> ast::Expr {
201 expr_from_text("unimplemented!()")
202}
203pub fn expr_unreachable() -> ast::Expr {
204 expr_from_text("unreachable!()")
205}
206pub fn expr_todo() -> ast::Expr {
207 expr_from_text("todo!()")
208}
209pub fn expr_path(path: ast::Path) -> ast::Expr { 250pub fn expr_path(path: ast::Path) -> ast::Expr {
210 expr_from_text(&path.to_string()) 251 expr_from_text(&path.to_string())
211} 252}
@@ -265,6 +306,9 @@ pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
265 let expr = elements.into_iter().format(", "); 306 let expr = elements.into_iter().format(", ");
266 expr_from_text(&format!("({})", expr)) 307 expr_from_text(&format!("({})", expr))
267} 308}
309pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
310 expr_from_text(&format!("{} = {}", lhs, rhs))
311}
268fn expr_from_text(text: &str) -> ast::Expr { 312fn expr_from_text(text: &str) -> ast::Expr {
269 ast_from_text(&format!("const C: () = {};", text)) 313 ast_from_text(&format!("const C: () = {};", text))
270} 314}
@@ -431,17 +475,6 @@ pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
431 ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) 475 ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi))
432} 476}
433 477
434pub fn token(kind: SyntaxKind) -> SyntaxToken {
435 tokens::SOURCE_FILE
436 .tree()
437 .syntax()
438 .clone_for_update()
439 .descendants_with_tokens()
440 .filter_map(|it| it.into_token())
441 .find(|it| it.kind() == kind)
442 .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
443}
444
445pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { 478pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param {
446 ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) 479 ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty))
447} 480}
@@ -463,7 +496,7 @@ pub fn param_list(
463 ast_from_text(&list) 496 ast_from_text(&list)
464} 497}
465 498
466pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::GenericParam { 499pub fn type_param(name: ast::Name, ty: Option<ast::TypeBoundList>) -> ast::TypeParam {
467 let bound = match ty { 500 let bound = match ty {
468 Some(it) => format!(": {}", it), 501 Some(it) => format!(": {}", it),
469 None => String::new(), 502 None => String::new(),
@@ -471,6 +504,10 @@ pub fn generic_param(name: String, ty: Option<ast::TypeBoundList>) -> ast::Gener
471 ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) 504 ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound))
472} 505}
473 506
507pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam {
508 ast_from_text(&format!("fn f<{}>() {{ }}", lifetime))
509}
510
474pub fn generic_param_list( 511pub fn generic_param_list(
475 pats: impl IntoIterator<Item = ast::GenericParam>, 512 pats: impl IntoIterator<Item = ast::GenericParam>,
476) -> ast::GenericParamList { 513) -> ast::GenericParamList {
@@ -572,7 +609,18 @@ fn ast_from_text<N: AstNode>(text: &str) -> N {
572} 609}
573 610
574fn unroot(n: SyntaxNode) -> SyntaxNode { 611fn unroot(n: SyntaxNode) -> SyntaxNode {
575 SyntaxNode::new_root(n.green()) 612 SyntaxNode::new_root(n.green().into())
613}
614
615pub fn token(kind: SyntaxKind) -> SyntaxToken {
616 tokens::SOURCE_FILE
617 .tree()
618 .syntax()
619 .clone_for_update()
620 .descendants_with_tokens()
621 .filter_map(|it| it.into_token())
622 .find(|it| it.kind() == kind)
623 .unwrap_or_else(|| panic!("unhandled token: {:?}", kind))
576} 624}
577 625
578pub mod tokens { 626pub mod tokens {
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 492fbc4a0..bef49238f 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -1,30 +1,31 @@
1//! Various extension methods to ast Nodes, which are hard to code-generate. 1//! Various extension methods to ast Nodes, which are hard to code-generate.
2//! Extensions for various expressions live in a sibling `expr_extensions` module. 2//! Extensions for various expressions live in a sibling `expr_extensions` module.
3 3
4use std::{fmt, iter::successors}; 4use std::{borrow::Cow, fmt, iter::successors};
5 5
6use itertools::Itertools; 6use itertools::Itertools;
7use parser::SyntaxKind; 7use parser::SyntaxKind;
8use rowan::{GreenNodeData, GreenTokenData};
8 9
9use crate::{ 10use crate::{
10 ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode}, 11 ast::{self, support, AstNode, AstToken, AttrsOwner, NameOwner, SyntaxNode},
11 SmolStr, SyntaxElement, SyntaxToken, TokenText, T, 12 NodeOrToken, SmolStr, SyntaxElement, SyntaxToken, TokenText, T,
12}; 13};
13 14
14impl ast::Lifetime { 15impl ast::Lifetime {
15 pub fn text(&self) -> TokenText { 16 pub fn text(&self) -> TokenText<'_> {
16 text_of_first_token(self.syntax()) 17 text_of_first_token(self.syntax())
17 } 18 }
18} 19}
19 20
20impl ast::Name { 21impl ast::Name {
21 pub fn text(&self) -> TokenText { 22 pub fn text(&self) -> TokenText<'_> {
22 text_of_first_token(self.syntax()) 23 text_of_first_token(self.syntax())
23 } 24 }
24} 25}
25 26
26impl ast::NameRef { 27impl ast::NameRef {
27 pub fn text(&self) -> TokenText { 28 pub fn text(&self) -> TokenText<'_> {
28 text_of_first_token(self.syntax()) 29 text_of_first_token(self.syntax())
29 } 30 }
30 31
@@ -33,11 +34,15 @@ impl ast::NameRef {
33 } 34 }
34} 35}
35 36
36fn text_of_first_token(node: &SyntaxNode) -> TokenText { 37fn text_of_first_token(node: &SyntaxNode) -> TokenText<'_> {
37 let first_token = 38 fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
38 node.green().children().next().and_then(|it| it.into_token()).unwrap().to_owned(); 39 green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
40 }
39 41
40 TokenText(first_token) 42 match node.green() {
43 Cow::Borrowed(green_ref) => TokenText::borrowed(first_token(green_ref).text()),
44 Cow::Owned(green) => TokenText::owned(first_token(&green).to_owned()),
45 }
41} 46}
42 47
43#[derive(Debug, PartialEq, Eq, Clone)] 48#[derive(Debug, PartialEq, Eq, Clone)]
@@ -412,7 +417,7 @@ impl fmt::Display for NameOrNameRef {
412} 417}
413 418
414impl NameOrNameRef { 419impl NameOrNameRef {
415 pub fn text(&self) -> TokenText { 420 pub fn text(&self) -> TokenText<'_> {
416 match self { 421 match self {
417 NameOrNameRef::Name(name) => name.text(), 422 NameOrNameRef::Name(name) => name.text(),
418 NameOrNameRef::NameRef(name_ref) => name_ref.text(), 423 NameOrNameRef::NameRef(name_ref) => name_ref.text(),
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index 91a06101f..a50c0dbca 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -125,8 +125,11 @@ pub fn remove_all_iter(range: impl IntoIterator<Item = SyntaxElement>) {
125} 125}
126 126
127pub fn replace(old: impl Element, new: impl Element) { 127pub fn replace(old: impl Element, new: impl Element) {
128 replace_with_many(old, vec![new.syntax_element()])
129}
130pub fn replace_with_many(old: impl Element, new: Vec<SyntaxElement>) {
128 let old = old.syntax_element(); 131 let old = old.syntax_element();
129 replace_all(old.clone()..=old, vec![new.syntax_element()]) 132 replace_all(old.clone()..=old, new)
130} 133}
131pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) { 134pub fn replace_all(range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
132 let start = range.start().index(); 135 let start = range.start().index();
diff --git a/crates/syntax/src/token_text.rs b/crates/syntax/src/token_text.rs
index d2ed0a12a..f3e8b321a 100644
--- a/crates/syntax/src/token_text.rs
+++ b/crates/syntax/src/token_text.rs
@@ -2,75 +2,93 @@
2 2
3use std::{cmp::Ordering, fmt, ops}; 3use std::{cmp::Ordering, fmt, ops};
4 4
5pub struct TokenText(pub(crate) rowan::GreenToken); 5use rowan::GreenToken;
6
7pub struct TokenText<'a>(pub(crate) Repr<'a>);
8
9pub(crate) enum Repr<'a> {
10 Borrowed(&'a str),
11 Owned(GreenToken),
12}
13
14impl<'a> TokenText<'a> {
15 pub(crate) fn borrowed(text: &'a str) -> Self {
16 TokenText(Repr::Borrowed(text))
17 }
18
19 pub(crate) fn owned(green: GreenToken) -> Self {
20 TokenText(Repr::Owned(green))
21 }
6 22
7impl TokenText {
8 pub fn as_str(&self) -> &str { 23 pub fn as_str(&self) -> &str {
9 self.0.text() 24 match self.0 {
25 Repr::Borrowed(it) => it,
26 Repr::Owned(ref green) => green.text(),
27 }
10 } 28 }
11} 29}
12 30
13impl ops::Deref for TokenText { 31impl ops::Deref for TokenText<'_> {
14 type Target = str; 32 type Target = str;
15 33
16 fn deref(&self) -> &str { 34 fn deref(&self) -> &str {
17 self.as_str() 35 self.as_str()
18 } 36 }
19} 37}
20impl AsRef<str> for TokenText { 38impl AsRef<str> for TokenText<'_> {
21 fn as_ref(&self) -> &str { 39 fn as_ref(&self) -> &str {
22 self.as_str() 40 self.as_str()
23 } 41 }
24} 42}
25 43
26impl From<TokenText> for String { 44impl From<TokenText<'_>> for String {
27 fn from(token_text: TokenText) -> Self { 45 fn from(token_text: TokenText) -> Self {
28 token_text.as_str().into() 46 token_text.as_str().into()
29 } 47 }
30} 48}
31 49
32impl PartialEq<&'_ str> for TokenText { 50impl PartialEq<&'_ str> for TokenText<'_> {
33 fn eq(&self, other: &&str) -> bool { 51 fn eq(&self, other: &&str) -> bool {
34 self.as_str() == *other 52 self.as_str() == *other
35 } 53 }
36} 54}
37impl PartialEq<TokenText> for &'_ str { 55impl PartialEq<TokenText<'_>> for &'_ str {
38 fn eq(&self, other: &TokenText) -> bool { 56 fn eq(&self, other: &TokenText) -> bool {
39 other == self 57 other == self
40 } 58 }
41} 59}
42impl PartialEq<String> for TokenText { 60impl PartialEq<String> for TokenText<'_> {
43 fn eq(&self, other: &String) -> bool { 61 fn eq(&self, other: &String) -> bool {
44 self.as_str() == other.as_str() 62 self.as_str() == other.as_str()
45 } 63 }
46} 64}
47impl PartialEq<TokenText> for String { 65impl PartialEq<TokenText<'_>> for String {
48 fn eq(&self, other: &TokenText) -> bool { 66 fn eq(&self, other: &TokenText) -> bool {
49 other == self 67 other == self
50 } 68 }
51} 69}
52impl PartialEq for TokenText { 70impl PartialEq for TokenText<'_> {
53 fn eq(&self, other: &TokenText) -> bool { 71 fn eq(&self, other: &TokenText) -> bool {
54 self.as_str() == other.as_str() 72 self.as_str() == other.as_str()
55 } 73 }
56} 74}
57impl Eq for TokenText {} 75impl Eq for TokenText<'_> {}
58impl Ord for TokenText { 76impl Ord for TokenText<'_> {
59 fn cmp(&self, other: &Self) -> Ordering { 77 fn cmp(&self, other: &Self) -> Ordering {
60 self.as_str().cmp(other.as_str()) 78 self.as_str().cmp(other.as_str())
61 } 79 }
62} 80}
63impl PartialOrd for TokenText { 81impl PartialOrd for TokenText<'_> {
64 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 82 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
65 Some(self.cmp(other)) 83 Some(self.cmp(other))
66 } 84 }
67} 85}
68impl fmt::Display for TokenText { 86impl fmt::Display for TokenText<'_> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 fmt::Display::fmt(self.as_str(), f) 88 fmt::Display::fmt(self.as_str(), f)
71 } 89 }
72} 90}
73impl fmt::Debug for TokenText { 91impl fmt::Debug for TokenText<'_> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt::Debug::fmt(self.as_str(), f) 93 fmt::Debug::fmt(self.as_str(), f)
76 } 94 }