From f5a81ec4683613bd62624811733345d627f2127b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 30 Jan 2021 18:19:21 +0300 Subject: Upgrade rowan Notably, new rowan comes with support for mutable syntax trees. --- crates/syntax/src/ast/edit_in_place.rs | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 crates/syntax/src/ast/edit_in_place.rs (limited to 'crates/syntax/src/ast/edit_in_place.rs') 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 @@ +//! Structural editing for ast. + +use std::iter::empty; + +use ast::{edit::AstNodeEdit, make, GenericParamsOwner, WhereClause}; +use parser::T; + +use crate::{ + ast, + ted::{self, Position}, + AstNode, Direction, SyntaxKind, +}; + +use super::NameOwner; + +pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit { + fn get_or_create_where_clause(&self) -> ast::WhereClause; +} + +impl GenericParamsOwnerEdit for ast::Fn { + fn get_or_create_where_clause(&self) -> WhereClause { + if self.where_clause().is_none() { + let position = if let Some(ty) = self.ret_type() { + Position::after(ty.syntax().clone()) + } else if let Some(param_list) = self.param_list() { + Position::after(param_list.syntax().clone()) + } else { + Position::last_child_of(self.syntax().clone()) + }; + create_where_clause(position) + } + self.where_clause().unwrap() + } +} + +impl GenericParamsOwnerEdit for ast::Impl { + fn get_or_create_where_clause(&self) -> WhereClause { + if self.where_clause().is_none() { + let position = if let Some(ty) = self.self_ty() { + Position::after(ty.syntax().clone()) + } else { + Position::last_child_of(self.syntax().clone()) + }; + create_where_clause(position) + } + self.where_clause().unwrap() + } +} +impl GenericParamsOwnerEdit for ast::Struct { + fn get_or_create_where_clause(&self) -> WhereClause { + if self.where_clause().is_none() { + let tfl = self.field_list().and_then(|fl| match fl { + ast::FieldList::RecordFieldList(_) => None, + ast::FieldList::TupleFieldList(it) => Some(it), + }); + let position = if let Some(tfl) = tfl { + Position::after(tfl.syntax().clone()) + } else if let Some(gpl) = self.generic_param_list() { + Position::after(gpl.syntax().clone()) + } else if let Some(name) = self.name() { + Position::after(name.syntax().clone()) + } else { + Position::last_child_of(self.syntax().clone()) + }; + create_where_clause(position) + } + self.where_clause().unwrap() + } +} + +fn create_where_clause(position: Position) { + let elements = vec![ + make::tokens::single_space().into(), + make::where_clause(empty()).clone_for_update().syntax().clone().into(), + ]; + ted::insert_all(position, elements); +} + +impl ast::WhereClause { + pub fn add_predicate(&self, predicate: ast::WherePred) { + if let Some(pred) = self.predicates().last() { + if !pred.syntax().siblings_with_tokens(Direction::Next).any(|it| it.kind() == T![,]) { + ted::append_child(self.syntax().clone(), make::token(T![,])); + } + } + if self.syntax().children_with_tokens().last().map(|it| it.kind()) + != Some(SyntaxKind::WHITESPACE) + { + ted::append_child(self.syntax().clone(), make::tokens::single_space()); + } + ted::append_child(self.syntax().clone(), predicate.syntax().clone()) + } +} + +impl ast::TypeBoundList { + pub fn remove(&self) { + if let Some(colon) = + self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) + { + ted::remove_all(colon..=self.syntax().clone().into()) + } else { + ted::remove(self.syntax().clone()) + } + } +} -- cgit v1.2.3