aboutsummaryrefslogtreecommitdiff
path: root/crates/syntax/src/ast
diff options
context:
space:
mode:
Diffstat (limited to 'crates/syntax/src/ast')
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs105
-rw-r--r--crates/syntax/src/ast/make.rs14
-rw-r--r--crates/syntax/src/ast/node_ext.rs4
3 files changed, 120 insertions, 3 deletions
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
new file mode 100644
index 000000000..06cde591d
--- /dev/null
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -0,0 +1,105 @@
1//! Structural editing for ast.
2
3use std::iter::empty;
4
5use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause};
6use parser::T;
7
8use crate::{
9 ast,
10 ted::{self, Position},
11 AstNode, Direction, SyntaxKind,
12};
13
14use super::NameOwner;
15
16pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit {
17 fn get_or_create_where_clause(&self) -> ast::WhereClause;
18}
19
20impl GenericParamsOwnerEdit for ast::Fn {
21 fn get_or_create_where_clause(&self) -> WhereClause {
22 if self.where_clause().is_none() {
23 let position = if let Some(ty) = self.ret_type() {
24 Position::after(ty.syntax().clone())
25 } else if let Some(param_list) = self.param_list() {
26 Position::after(param_list.syntax().clone())
27 } else {
28 Position::last_child_of(self.syntax().clone())
29 };
30 create_where_clause(position)
31 }
32 self.where_clause().unwrap()
33 }
34}
35
36impl GenericParamsOwnerEdit for ast::Impl {
37 fn get_or_create_where_clause(&self) -> WhereClause {
38 if self.where_clause().is_none() {
39 let position = if let Some(ty) = self.self_ty() {
40 Position::after(ty.syntax().clone())
41 } else {
42 Position::last_child_of(self.syntax().clone())
43 };
44 create_where_clause(position)
45 }
46 self.where_clause().unwrap()
47 }
48}
49impl GenericParamsOwnerEdit for ast::Struct {
50 fn get_or_create_where_clause(&self) -> WhereClause {
51 if self.where_clause().is_none() {
52 let tfl = self.field_list().and_then(|fl| match fl {
53 ast::FieldList::RecordFieldList(_) => None,
54 ast::FieldList::TupleFieldList(it) => Some(it),
55 });
56 let position = if let Some(tfl) = tfl {
57 Position::after(tfl.syntax().clone())
58 } else if let Some(gpl) = self.generic_param_list() {
59 Position::after(gpl.syntax().clone())
60 } else if let Some(name) = self.name() {
61 Position::after(name.syntax().clone())
62 } else {
63 Position::last_child_of(self.syntax().clone())
64 };
65 create_where_clause(position)
66 }
67 self.where_clause().unwrap()
68 }
69}
70
71fn create_where_clause(position: Position) {
72 let elements = vec![
73 make::tokens::single_space().into(),
74 make::where_clause(empty()).clone_for_update().syntax().clone().into(),
75 ];
76 ted::insert_all(position, elements);
77}
78
79impl ast::WhereClause {
80 pub fn add_predicate(&self, predicate: ast::WherePred) {
81 if let Some(pred) = self.predicates().last() {
82 if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) {
83 ted::append_child(self.syntax().clone(), make::token(T![,]));
84 }
85 }
86 if self.syntax().children_with_tokens().last().map(|it| it.kind())
87 != Some(SyntaxKind::WHITESPACE)
88 {
89 ted::append_child(self.syntax().clone(), make::tokens::single_space());
90 }
91 ted::append_child(self.syntax().clone(), predicate.syntax().clone())
92 }
93}
94
95impl ast::TypeBoundList {
96 pub fn remove(&self) {
97 if let Some(colon) =
98 self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:])
99 {
100 ted::remove_all(colon..=self.syntax().clone().into())
101 } else {
102 ted::remove(self.syntax().clone())
103 }
104 }
105}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 05a6b0b25..810c8d4c8 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -174,6 +174,11 @@ pub fn block_expr(
174pub fn expr_unit() -> ast::Expr { 174pub fn expr_unit() -> ast::Expr {
175 expr_from_text("()") 175 expr_from_text("()")
176} 176}
177pub fn expr_literal(text: &str) -> ast::Literal {
178 assert_eq!(text.trim(), text);
179 ast_from_text(&format!("fn f() {{ let _ = {}; }}", text))
180}
181
177pub fn expr_empty_block() -> ast::Expr { 182pub fn expr_empty_block() -> ast::Expr {
178 expr_from_text("{}") 183 expr_from_text("{}")
179} 184}
@@ -390,6 +395,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
390 tokens::SOURCE_FILE 395 tokens::SOURCE_FILE
391 .tree() 396 .tree()
392 .syntax() 397 .syntax()
398 .clone_for_update()
393 .descendants_with_tokens() 399 .descendants_with_tokens()
394 .filter_map(|it| it.into_token()) 400 .filter_map(|it| it.into_token())
395 .find(|it| it.kind() == kind) 401 .find(|it| it.kind() == kind)
@@ -544,6 +550,7 @@ pub mod tokens {
544 SOURCE_FILE 550 SOURCE_FILE
545 .tree() 551 .tree()
546 .syntax() 552 .syntax()
553 .clone_for_update()
547 .descendants_with_tokens() 554 .descendants_with_tokens()
548 .filter_map(|it| it.into_token()) 555 .filter_map(|it| it.into_token())
549 .find(|it| it.kind() == WHITESPACE && it.text() == " ") 556 .find(|it| it.kind() == WHITESPACE && it.text() == " ")
@@ -569,13 +576,16 @@ pub mod tokens {
569 } 576 }
570 577
571 pub fn single_newline() -> SyntaxToken { 578 pub fn single_newline() -> SyntaxToken {
572 SOURCE_FILE 579 let res = SOURCE_FILE
573 .tree() 580 .tree()
574 .syntax() 581 .syntax()
582 .clone_for_update()
575 .descendants_with_tokens() 583 .descendants_with_tokens()
576 .filter_map(|it| it.into_token()) 584 .filter_map(|it| it.into_token())
577 .find(|it| it.kind() == WHITESPACE && it.text() == "\n") 585 .find(|it| it.kind() == WHITESPACE && it.text() == "\n")
578 .unwrap() 586 .unwrap();
587 res.detach();
588 res
579 } 589 }
580 590
581 pub fn blank_line() -> SyntaxToken { 591 pub fn blank_line() -> SyntaxToken {
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 52ac97c84..0b0d39a75 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -34,7 +34,9 @@ impl ast::NameRef {
34} 34}
35 35
36fn text_of_first_token(node: &SyntaxNode) -> &str { 36fn text_of_first_token(node: &SyntaxNode) -> &str {
37 node.green().children().next().and_then(|it| it.into_token()).unwrap().text() 37 let t =
38 node.green().children().next().and_then(|it| it.into_token()).unwrap().text().to_string();
39 Box::leak(Box::new(t))
38} 40}
39 41
40pub enum Macro { 42pub enum Macro {