From dccaa5e45e9baaa2d286353a7499a89af1669e42 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Oct 2018 17:50:56 +0300 Subject: [PATCH 1/3] use aliases --- crates/ra_syntax/src/yellow/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs index c621b1d6a3..2c57d8b418 100644 --- a/crates/ra_syntax/src/yellow/mod.rs +++ b/crates/ra_syntax/src/yellow/mod.rs @@ -53,12 +53,12 @@ impl> Hash for SyntaxNode { } } -impl SyntaxNode { +impl SyntaxNode { pub(crate) fn new(green: GreenNode, errors: Vec) -> SyntaxNode { SyntaxNode(::rowan::SyntaxNode::new(green, errors)) } } -impl<'a> SyntaxNode> { +impl<'a> SyntaxNodeRef<'a> { pub fn leaf_text(self) -> Option<&'a SmolStr> { self.0.leaf_text() } From d323c81d5cc6a198239285abcede2166181d8f39 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Oct 2018 18:02:57 +0300 Subject: [PATCH 2/3] make ancestors and descendants inherent --- crates/ra_editor/src/code_actions.rs | 5 ++--- crates/ra_editor/src/completion.rs | 13 ++++++------- crates/ra_editor/src/extend_selection.rs | 4 ++-- crates/ra_editor/src/folding_ranges.rs | 8 +++----- crates/ra_editor/src/lib.rs | 10 +++++----- crates/ra_editor/src/scope/fn_scope.rs | 6 +++--- crates/ra_editor/src/symbols.rs | 4 ++-- crates/ra_editor/src/typing.rs | 3 +-- crates/ra_syntax/src/algo/mod.rs | 8 ++------ crates/ra_syntax/src/algo/walk.rs | 6 ------ crates/ra_syntax/src/reparsing.rs | 2 +- crates/ra_syntax/src/utils.rs | 4 ++-- crates/ra_syntax/src/yellow/mod.rs | 9 +++++++++ crates/ra_syntax/src/yellow/syntax_text.rs | 4 ++-- 14 files changed, 40 insertions(+), 46 deletions(-) diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs index 83f7956d29..b0f0d8f1d0 100644 --- a/crates/ra_editor/src/code_actions.rs +++ b/crates/ra_editor/src/code_actions.rs @@ -9,7 +9,6 @@ use ra_syntax::{ Direction, siblings, find_leaf_at_offset, find_covering_node, - ancestors, }, }; @@ -101,8 +100,8 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option LocalEdit + 'a> { let node = find_covering_node(file.syntax(), range); - let expr = ancestors(node).filter_map(ast::Expr::cast).next()?; - let anchor_stmt = ancestors(expr.syntax()).filter_map(ast::Stmt::cast).next()?; + let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; + let anchor_stmt = expr.syntax().ancestors().filter_map(ast::Stmt::cast).next()?; let indent = anchor_stmt.syntax().prev_sibling()?; if indent.kind() != WHITESPACE { return None; diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs index ff9de20d38..62a63fb044 100644 --- a/crates/ra_editor/src/completion.rs +++ b/crates/ra_editor/src/completion.rs @@ -4,7 +4,6 @@ use ra_syntax::{ File, TextUnit, AstNode, SyntaxNodeRef, SyntaxKind::*, ast::{self, LoopBodyOwner, ModuleItemOwner}, algo::{ - ancestors, visit::{visitor, Visitor, visitor_ctx, VisitorCtx}, }, text_utils::is_subrange, @@ -59,7 +58,7 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec(|it| Some(it.items())) .visit::(|it| Some(it.item_list()?.items())) @@ -92,7 +91,7 @@ fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec) { let mut params = HashMap::new(); - for node in ancestors(ctx) { + for node in ctx.ancestors() { let _ = visitor_ctx(&mut params) .visit::(process) .visit::(process) @@ -123,7 +122,7 @@ fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec) { } fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool { - match ancestors(node).filter_map(N::cast).next() { + match node.ancestors().filter_map(N::cast).next() { None => false, Some(n) => n.syntax().range() == node.range(), } @@ -152,7 +151,7 @@ fn complete_expr_keywords(file: &File, fn_def: ast::FnDef, name_ref: ast::NameRe } fn is_in_loop_body(name_ref: ast::NameRef) -> bool { - for node in ancestors(name_ref.syntax()) { + for node in name_ref.syntax().ancestors() { if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { break; } @@ -171,7 +170,7 @@ fn is_in_loop_body(name_ref: ast::NameRef) -> bool { } fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option { - // let is_last_in_block = ancestors(name_ref.syntax()).filter_map(ast::Expr::cast) + // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast) // .next() // .and_then(|it| it.syntax().parent()) // .and_then(ast::Block::cast) @@ -181,7 +180,7 @@ fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option false, Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range() }; diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs index dc914a26ad..2f8a04b2b3 100644 --- a/crates/ra_editor/src/extend_selection.rs +++ b/crates/ra_editor/src/extend_selection.rs @@ -1,7 +1,7 @@ use ra_syntax::{ File, TextRange, SyntaxNodeRef, TextUnit, SyntaxKind::*, - algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node, ancestors, Direction, siblings}, + algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node, Direction, siblings}, }; pub fn extend_selection(file: &File, range: TextRange) -> Option { @@ -30,7 +30,7 @@ pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option } } - match ancestors(node).skip_while(|n| n.range() == range).next() { + match node.ancestors().skip_while(|n| n.range() == range).next() { None => None, Some(parent) => Some(parent.range()), } diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs index 817da28d1a..892aaf97be 100644 --- a/crates/ra_editor/src/folding_ranges.rs +++ b/crates/ra_editor/src/folding_ranges.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use ra_syntax::{ File, TextRange, SyntaxNodeRef, SyntaxKind, - algo::{walk, Direction, siblings}, + algo::{Direction, siblings}, }; #[derive(Debug, PartialEq, Eq)] @@ -19,12 +19,10 @@ pub struct Fold { } pub fn folding_ranges(file: &File) -> Vec { - let syntax = file.syntax(); - let mut res = vec![]; let mut visited = HashSet::new(); - for node in walk::preorder(syntax) { + for node in file.syntax().descendants() { if visited.contains(&node) { continue; } @@ -139,4 +137,4 @@ fn main() { } -} \ No newline at end of file +} diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index de929d73a6..a93924e005 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs @@ -21,7 +21,7 @@ mod test_utils; use ra_syntax::{ File, TextUnit, TextRange, SyntaxNodeRef, ast::{self, AstNode, NameOwner}, - algo::{walk, find_leaf_at_offset, ancestors}, + algo::find_leaf_at_offset, SyntaxKind::{self, *}, }; pub use ra_syntax::AtomEdit; @@ -86,7 +86,7 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option { pub fn highlight(file: &File) -> Vec { let mut res = Vec::new(); - for node in walk::preorder(file.syntax()) { + for node in file.syntax().descendants() { let tag = match node.kind() { ERROR => "error", COMMENT | DOC_COMMENT => "comment", @@ -110,7 +110,7 @@ pub fn highlight(file: &File) -> Vec { pub fn diagnostics(file: &File) -> Vec { let mut res = Vec::new(); - for node in walk::preorder(file.syntax()) { + for node in file.syntax().descendants() { if node.kind() == ERROR { res.push(Diagnostic { range: node.range(), @@ -130,7 +130,7 @@ pub fn syntax_tree(file: &File) -> String { } pub fn runnables(file: &File) -> Vec { - walk::preorder(file.syntax()) + file.syntax().descendants() .filter_map(ast::FnDef::cast) .filter_map(|f| { let name = f.name()?.text(); @@ -159,7 +159,7 @@ pub fn find_node_at_offset<'a, N: AstNode<'a>>( let leaf = leaves.clone() .find(|leaf| !leaf.kind().is_trivia()) .or_else(|| leaves.right_biased())?; - ancestors(leaf) + leaf.ancestors() .filter_map(N::cast) .next() } diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs index 3ae5276a22..eddd874956 100644 --- a/crates/ra_editor/src/scope/fn_scope.rs +++ b/crates/ra_editor/src/scope/fn_scope.rs @@ -6,7 +6,7 @@ use std::{ use ra_syntax::{ SyntaxNodeRef, SyntaxNode, SmolStr, AstNode, ast::{self, NameOwner, LoopBodyOwner, ArgListOwner}, - algo::{ancestors, generate, walk::preorder} + algo::{generate} }; type ScopeId = usize; @@ -51,7 +51,7 @@ impl FnScopes { res } fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) { - let entries = preorder(pat.syntax()) + let entries = pat.syntax().descendants() .filter_map(ast::BindPat::cast) .filter_map(ScopeEntry::new); self.scopes[scope].entries.extend(entries); @@ -66,7 +66,7 @@ impl FnScopes { self.scope_for.insert(node.owned(), scope); } fn scope_for(&self, node: SyntaxNodeRef) -> Option { - ancestors(node) + node.ancestors() .filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope)) .next() } diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs index 9179841772..e5cc5ca284 100644 --- a/crates/ra_editor/src/symbols.rs +++ b/crates/ra_editor/src/symbols.rs @@ -3,7 +3,7 @@ use ra_syntax::{ ast::{self, NameOwner}, algo::{ visit::{visitor, Visitor}, - walk::{walk, WalkEvent, preorder}, + walk::{walk, WalkEvent}, }, }; use TextRange; @@ -25,7 +25,7 @@ pub struct FileSymbol { } pub fn file_symbols(file: &File) -> Vec { - preorder(file.syntax()) + file.syntax().descendants() .filter_map(to_symbol) .collect() } diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index 0f4e7e0d02..5120769418 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs @@ -4,7 +4,6 @@ use ra_syntax::{ TextUnit, TextRange, SyntaxNodeRef, File, AstNode, SyntaxKind, ast, algo::{ - walk::preorder, find_covering_node, }, text_utils::{intersect, contains_offset_nonstrict}, @@ -33,7 +32,7 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { }; let node = find_covering_node(file.syntax(), range); let mut edit = EditBuilder::new(); - for node in preorder(node) { + for node in node.descendants() { let text = match node.leaf_text() { Some(text) => text, None => continue, diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs index 8de44c5861..3716a6000f 100644 --- a/crates/ra_syntax/src/algo/mod.rs +++ b/crates/ra_syntax/src/algo/mod.rs @@ -94,10 +94,6 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe common_ancestor(left, right) } -pub fn ancestors<'a>(node: SyntaxNodeRef<'a>) -> impl Iterator> { - generate(Some(node), |&node| node.parent()) -} - #[derive(Debug)] pub enum Direction { Forward, @@ -115,8 +111,8 @@ pub fn siblings<'a>( } fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> { - for p in ancestors(n1) { - if ancestors(n2).any(|a| a == p) { + for p in n1.ancestors() { + if n2.ancestors().any(|a| a == p) { return p; } } diff --git a/crates/ra_syntax/src/algo/walk.rs b/crates/ra_syntax/src/algo/walk.rs index 536ee705fb..8e294d965b 100644 --- a/crates/ra_syntax/src/algo/walk.rs +++ b/crates/ra_syntax/src/algo/walk.rs @@ -3,12 +3,6 @@ use { algo::generate, }; -pub fn preorder<'a>(root: SyntaxNodeRef<'a>) -> impl Iterator> { - walk(root).filter_map(|event| match event { - WalkEvent::Enter(node) => Some(node), - WalkEvent::Exit(_) => None, - }) -} #[derive(Debug, Copy, Clone)] pub enum WalkEvent<'a> { diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs index e3c200d1e1..dcafd2c407 100644 --- a/crates/ra_syntax/src/reparsing.rs +++ b/crates/ra_syntax/src/reparsing.rs @@ -112,7 +112,7 @@ fn find_reparsable_node<'node>( range: TextRange, ) -> Option<(SyntaxNodeRef<'node>, fn(&mut Parser))> { let node = algo::find_covering_node(node, range); - return algo::ancestors(node) + return node.ancestors() .filter_map(|node| reparser(node).map(|r| (node, r))) .next(); diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs index 8bc5f0e24c..e274f7471f 100644 --- a/crates/ra_syntax/src/utils.rs +++ b/crates/ra_syntax/src/utils.rs @@ -1,6 +1,6 @@ use std::fmt::Write; use { - algo::walk::{preorder, walk, WalkEvent}, + algo::walk::{walk, WalkEvent}, SyntaxKind, File, SyntaxNodeRef }; @@ -56,7 +56,7 @@ pub fn check_fuzz_invariants(text: &str) { pub(crate) fn validate_block_structure(root: SyntaxNodeRef) { let mut stack = Vec::new(); - for node in preorder(root) { + for node in root.descendants() { match node.kind() { SyntaxKind::L_CURLY => { stack.push(node) diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs index 2c57d8b418..95d277a2fc 100644 --- a/crates/ra_syntax/src/yellow/mod.rs +++ b/crates/ra_syntax/src/yellow/mod.rs @@ -62,6 +62,15 @@ impl<'a> SyntaxNodeRef<'a> { pub fn leaf_text(self) -> Option<&'a SmolStr> { self.0.leaf_text() } + pub fn ancestors(self) -> impl Iterator> { + ::algo::generate(Some(self), |&node| node.parent()) + } + pub fn descendants(self) -> impl Iterator> { + ::algo::walk::walk(self).filter_map(|event| match event { + ::algo::walk::WalkEvent::Enter(node) => Some(node), + ::algo::walk::WalkEvent::Exit(_) => None, + }) + } } impl> SyntaxNode { diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs index affd7f9c7d..0db1049de9 100644 --- a/crates/ra_syntax/src/yellow/syntax_text.rs +++ b/crates/ra_syntax/src/yellow/syntax_text.rs @@ -4,7 +4,6 @@ use std::{ use { SyntaxNodeRef, TextRange, TextUnit, - algo::walk::preorder, text_utils::{intersect, contains_offset_nonstrict}, }; @@ -23,7 +22,8 @@ impl<'a> SyntaxText<'a> { } pub fn chunks(&self) -> impl Iterator { let range = self.range; - preorder(self.node) + self.node + .descendants() .filter_map(move |node| { let text = node.leaf_text()?; let range = intersect(range, node.range())?; From 1a2a8dec14ec04ea8eeccae99fd885e7a280e45b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 2 Oct 2018 18:14:33 +0300 Subject: [PATCH 3/3] Make siblings an inherent method --- crates/ra_editor/src/code_actions.rs | 13 ++++++------- crates/ra_editor/src/extend_selection.rs | 16 ++++++++-------- crates/ra_editor/src/folding_ranges.rs | 4 ++-- crates/ra_syntax/src/algo/mod.rs | 16 ---------------- crates/ra_syntax/src/lib.rs | 2 +- crates/ra_syntax/src/yellow/mod.rs | 13 +++++++++++++ 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs index b0f0d8f1d0..216d592ff4 100644 --- a/crates/ra_editor/src/code_actions.rs +++ b/crates/ra_editor/src/code_actions.rs @@ -1,12 +1,11 @@ use join_to_string::join; use ra_syntax::{ - File, TextUnit, TextRange, + File, TextUnit, TextRange, Direction, ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, SyntaxKind::{COMMA, WHITESPACE}, SyntaxNodeRef, algo::{ - Direction, siblings, find_leaf_at_offset, find_covering_node, }, @@ -24,12 +23,12 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option(file: &'a File, range: TextRange) -> Option Option { - siblings(node, direction) + node.siblings(direction) .skip(1) .find(|node| !node.kind().is_trivia()) } diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs index 2f8a04b2b3..b00a457b90 100644 --- a/crates/ra_editor/src/extend_selection.rs +++ b/crates/ra_editor/src/extend_selection.rs @@ -1,7 +1,7 @@ use ra_syntax::{ - File, TextRange, SyntaxNodeRef, TextUnit, + File, TextRange, SyntaxNodeRef, TextUnit, Direction, SyntaxKind::*, - algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node, Direction, siblings}, + algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node}, }; pub fn extend_selection(file: &File, range: TextRange) -> Option { @@ -71,12 +71,12 @@ fn pick_best<'a>(l: SyntaxNodeRef<'a>, r: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a } fn extend_comments(node: SyntaxNodeRef) -> Option { - let left = adj_comments(node, Direction::Backward); - let right = adj_comments(node, Direction::Forward); - if left != right { + let prev = adj_comments(node, Direction::Prev); + let next = adj_comments(node, Direction::Next); + if prev != next { Some(TextRange::from_to( - left.range().start(), - right.range().end(), + prev.range().start(), + next.range().end(), )) } else { None @@ -85,7 +85,7 @@ fn extend_comments(node: SyntaxNodeRef) -> Option { fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef { let mut res = node; - for node in siblings(node, dir) { + for node in node.siblings(dir) { match node.kind() { COMMENT => res = node, WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs index 892aaf97be..733512368e 100644 --- a/crates/ra_editor/src/folding_ranges.rs +++ b/crates/ra_editor/src/folding_ranges.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use ra_syntax::{ File, TextRange, SyntaxNodeRef, SyntaxKind, - algo::{Direction, siblings}, + Direction, }; #[derive(Debug, PartialEq, Eq)] @@ -62,7 +62,7 @@ fn contiguous_range_for<'a>( let left = node; let mut right = node; - for node in siblings(node, Direction::Forward) { + for node in node.siblings(Direction::Next) { visited.insert(node); match node.kind() { SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), diff --git a/crates/ra_syntax/src/algo/mod.rs b/crates/ra_syntax/src/algo/mod.rs index 3716a6000f..a6678093d9 100644 --- a/crates/ra_syntax/src/algo/mod.rs +++ b/crates/ra_syntax/src/algo/mod.rs @@ -94,22 +94,6 @@ pub fn find_covering_node(root: SyntaxNodeRef, range: TextRange) -> SyntaxNodeRe common_ancestor(left, right) } -#[derive(Debug)] -pub enum Direction { - Forward, - Backward, -} - -pub fn siblings<'a>( - node: SyntaxNodeRef<'a>, - direction: Direction -) -> impl Iterator> { - generate(Some(node), move |&node| match direction { - Direction::Forward => node.next_sibling(), - Direction::Backward => node.prev_sibling(), - }) -} - fn common_ancestor<'a>(n1: SyntaxNodeRef<'a>, n2: SyntaxNodeRef<'a>) -> SyntaxNodeRef<'a> { for p in n1.ancestors() { if n2.ancestors().any(|a| a == p) { diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs index c7eda45636..738664afd0 100644 --- a/crates/ra_syntax/src/lib.rs +++ b/crates/ra_syntax/src/lib.rs @@ -51,7 +51,7 @@ pub use { ast::AstNode, lexer::{tokenize, Token}, syntax_kinds::SyntaxKind, - yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError}, + yellow::{SyntaxNode, SyntaxNodeRef, OwnedRoot, RefRoot, TreeRoot, SyntaxError, Direction}, reparsing::AtomEdit, }; diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs index 95d277a2fc..710320f47c 100644 --- a/crates/ra_syntax/src/yellow/mod.rs +++ b/crates/ra_syntax/src/yellow/mod.rs @@ -58,6 +58,13 @@ impl SyntaxNode { SyntaxNode(::rowan::SyntaxNode::new(green, errors)) } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { + Next, + Prev, +} + impl<'a> SyntaxNodeRef<'a> { pub fn leaf_text(self) -> Option<&'a SmolStr> { self.0.leaf_text() @@ -71,6 +78,12 @@ impl<'a> SyntaxNodeRef<'a> { ::algo::walk::WalkEvent::Exit(_) => None, }) } + pub fn siblings(self, direction: Direction) -> impl Iterator> { + ::algo::generate(Some(self), move |&node| match direction { + Direction::Next => node.next_sibling(), + Direction::Prev => node.prev_sibling(), + }) + } } impl> SyntaxNode {