1use rowan::ast::support;
2use rowan::{SyntaxElement, SyntaxToken, TextRange, TextSize};
3use smol_str::SmolStr;
4
5use crate::ast::AstNode;
6use crate::ast::kinds::{is_binary_operator, is_trivia, is_unary_operator};
7use crate::ast::tokens::{AstToken, StringLit, token_name};
8use crate::syntax::{RLanguage, SyntaxKind, SyntaxNode};
9
10macro_rules! ast_node {
11 ($name:ident, $kind:expr) => {
12 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
13 pub struct $name(SyntaxNode);
14
15 impl AstNode for $name {
16 type Language = RLanguage;
17
18 fn can_cast(kind: SyntaxKind) -> bool {
19 kind == $kind
20 }
21
22 fn cast(syntax: SyntaxNode) -> Option<Self> {
23 Self::can_cast(syntax.kind()).then(|| Self(syntax))
24 }
25
26 fn syntax(&self) -> &SyntaxNode {
27 &self.0
28 }
29 }
30 };
31}
32
33ast_node!(Root, SyntaxKind::ROOT);
34ast_node!(AssignmentExpr, SyntaxKind::ASSIGNMENT_EXPR);
35ast_node!(BinaryExpr, SyntaxKind::BINARY_EXPR);
36ast_node!(UnaryExpr, SyntaxKind::UNARY_EXPR);
37ast_node!(ParenExpr, SyntaxKind::PAREN_EXPR);
38ast_node!(CallExpr, SyntaxKind::CALL_EXPR);
39ast_node!(SubsetExpr, SyntaxKind::SUBSET_EXPR);
40ast_node!(Subset2Expr, SyntaxKind::SUBSET2_EXPR);
41ast_node!(ArgList, SyntaxKind::ARG_LIST);
42ast_node!(Arg, SyntaxKind::ARG);
43ast_node!(IfExpr, SyntaxKind::IF_EXPR);
44ast_node!(ForExpr, SyntaxKind::FOR_EXPR);
45ast_node!(WhileExpr, SyntaxKind::WHILE_EXPR);
46ast_node!(RepeatExpr, SyntaxKind::REPEAT_EXPR);
47ast_node!(FunctionExpr, SyntaxKind::FUNCTION_EXPR);
48ast_node!(BlockExpr, SyntaxKind::BLOCK_EXPR);
49ast_node!(RoxygenBlock, SyntaxKind::ROXYGEN_BLOCK);
50ast_node!(RoxygenSection, SyntaxKind::ROXYGEN_SECTION);
51ast_node!(RoxygenParagraph, SyntaxKind::ROXYGEN_PARAGRAPH);
52ast_node!(RoxygenTag, SyntaxKind::ROXYGEN_TAG);
53
54fn first_child_token(node: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken<RLanguage>> {
56 node.children_with_tokens()
57 .find_map(|element| match element {
58 SyntaxElement::Token(token) if token.kind() == kind => Some(token),
59 _ => None,
60 })
61}
62
63impl RoxygenBlock {
64 pub fn sections(&self) -> impl Iterator<Item = RoxygenSection> + '_ {
67 self.0.children().filter_map(RoxygenSection::cast)
68 }
69
70 pub fn tags(&self) -> impl Iterator<Item = RoxygenTag> + '_ {
72 self.sections().filter_map(|section| section.tag())
73 }
74
75 pub fn has_tag(&self, name: &str) -> bool {
77 self.tags().any(|tag| tag.name().as_deref() == Some(name))
78 }
79
80 pub fn intro(&self) -> Option<RoxygenSection> {
83 self.sections().find(|section| section.tag().is_none())
84 }
85}
86
87impl RoxygenSection {
88 pub fn tag(&self) -> Option<RoxygenTag> {
91 self.0.children().find_map(RoxygenTag::cast)
92 }
93
94 pub fn paragraphs(&self) -> impl Iterator<Item = RoxygenParagraph> + '_ {
96 self.0.children().filter_map(RoxygenParagraph::cast)
97 }
98
99 pub fn has_prose(&self) -> bool {
102 self.tag().is_some_and(|tag| tag.text().is_some()) || self.paragraphs().next().is_some()
103 }
104}
105
106impl RoxygenTag {
107 pub fn at(&self) -> Option<SyntaxToken<RLanguage>> {
109 first_child_token(&self.0, SyntaxKind::ROXYGEN_AT)
110 }
111
112 pub fn name(&self) -> Option<SmolStr> {
114 first_child_token(&self.0, SyntaxKind::ROXYGEN_TAG_NAME).map(|t| SmolStr::new(t.text()))
115 }
116
117 pub fn arg(&self) -> Option<SyntaxToken<RLanguage>> {
119 first_child_token(&self.0, SyntaxKind::ROXYGEN_TAG_ARG)
120 }
121
122 pub fn text(&self) -> Option<SyntaxToken<RLanguage>> {
124 first_child_token(&self.0, SyntaxKind::ROXYGEN_TEXT)
125 }
126
127 pub fn is_examples(&self) -> bool {
129 matches!(self.name().as_deref(), Some("examples" | "examplesIf"))
130 }
131
132 pub fn arg_names(&self) -> Vec<(SmolStr, TextRange)> {
136 let Some(arg) = self.arg() else {
137 return Vec::new();
138 };
139 let arg_start = arg.text_range().start();
140 let mut names = Vec::new();
141 let mut offset = 0usize;
142 for piece in arg.text().split(',') {
143 let trimmed = piece.trim();
144 if !trimmed.is_empty() {
145 let lead = piece.len() - piece.trim_start().len();
146 let start = arg_start + TextSize::from((offset + lead) as u32);
147 names.push((
148 SmolStr::new(trimmed),
149 TextRange::at(start, TextSize::of(trimmed)),
150 ));
151 }
152 offset += piece.len() + 1;
153 }
154 names
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct ForExprParts {
160 pub leading_comments: Vec<SyntaxToken<RLanguage>>,
161 pub variable_elements: Vec<SyntaxElement<RLanguage>>,
162 pub sequence_elements: Vec<SyntaxElement<RLanguage>>,
163 pub post_clause_comments: Vec<SyntaxToken<RLanguage>>,
164 pub body: Option<SyntaxElement<RLanguage>>,
165}
166
167#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct WhileExprParts {
169 pub leading_comments: Vec<SyntaxToken<RLanguage>>,
170 pub condition_elements: Vec<SyntaxElement<RLanguage>>,
171 pub post_clause_comments: Vec<SyntaxToken<RLanguage>>,
172 pub body: Option<SyntaxElement<RLanguage>>,
173}
174
175impl Root {
176 pub fn expressions(&self) -> impl Iterator<Item = SyntaxNode> {
177 self.syntax().children()
178 }
179}
180
181impl AssignmentExpr {
182 pub fn op_kind(&self) -> Option<SyntaxKind> {
186 self.syntax()
187 .children_with_tokens()
188 .find_map(|element| match element {
189 SyntaxElement::Token(token) if is_assignment_op(token.kind()) => Some(token.kind()),
190 _ => None,
191 })
192 }
193
194 pub fn op_token(&self) -> Option<SyntaxToken<RLanguage>> {
196 self.syntax()
197 .children_with_tokens()
198 .find_map(|element| match element {
199 SyntaxElement::Token(token) if is_assignment_op(token.kind()) => Some(token),
200 _ => None,
201 })
202 }
203
204 pub fn target_element(&self) -> Option<SyntaxElement<RLanguage>> {
208 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
209 let op_idx = assignment_op_index(&elements)?;
210 let kind = element_kind(&elements[op_idx])?;
211 let (start, end) = if is_right_assign(kind) {
212 (op_idx + 1, elements.len())
213 } else {
214 (0, op_idx)
215 };
216 elements[start..end]
217 .iter()
218 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
219 .cloned()
220 }
221
222 pub fn value_element(&self) -> Option<SyntaxElement<RLanguage>> {
224 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
225 let op_idx = assignment_op_index(&elements)?;
226 let kind = element_kind(&elements[op_idx])?;
227 let (start, end) = if is_right_assign(kind) {
228 (0, op_idx)
229 } else {
230 (op_idx + 1, elements.len())
231 };
232 elements[start..end]
233 .iter()
234 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
235 .cloned()
236 }
237
238 pub fn target_name(&self) -> Option<SmolStr> {
242 match self.target_element()? {
243 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IDENT => {
244 Some(SmolStr::new(token.text()))
245 }
246 SyntaxElement::Token(token) if token.kind() == SyntaxKind::STRING => {
247 StringLit::cast(token).and_then(|s| s.unquote().map(SmolStr::new))
248 }
249 _ => None,
250 }
251 }
252
253 pub fn target_name_token(&self) -> Option<SyntaxToken<RLanguage>> {
255 match self.target_element()? {
256 SyntaxElement::Token(token)
257 if token.kind() == SyntaxKind::IDENT || token.kind() == SyntaxKind::STRING =>
258 {
259 Some(token)
260 }
261 _ => None,
262 }
263 }
264}
265
266impl FunctionExpr {
267 pub fn lparen_index(&self) -> Option<usize> {
268 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
269 elements.iter().position(|e| e.kind() == SyntaxKind::LPAREN)
270 }
271
272 pub fn rparen_index(&self) -> Option<usize> {
273 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
274 let lparen_idx = self.lparen_index()?;
275 let mut depth = 0usize;
276 elements
277 .iter()
278 .enumerate()
279 .skip(lparen_idx)
280 .find_map(|(i, el)| match el.kind() {
281 SyntaxKind::LPAREN => {
282 depth += 1;
283 None
284 }
285 SyntaxKind::RPAREN => {
286 depth = depth.saturating_sub(1);
287 if depth == 0 { Some(i) } else { None }
288 }
289 _ => None,
290 })
291 }
292
293 pub fn params(&self) -> Vec<Param> {
297 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
298 let Some(lparen_idx) = self.lparen_index() else {
299 return Vec::new();
300 };
301 let Some(rparen_idx) = self.rparen_index() else {
302 return Vec::new();
303 };
304 let mut params = Vec::new();
305 let mut depth = 0usize;
306 let mut at_param_start = true;
307 let mut i = lparen_idx + 1;
308 while i < rparen_idx {
309 let element = &elements[i];
310 match element.kind() {
311 SyntaxKind::LPAREN
312 | SyntaxKind::LBRACK
313 | SyntaxKind::LBRACK2
314 | SyntaxKind::LBRACE => {
315 depth += 1;
316 at_param_start = false;
317 }
318 SyntaxKind::RPAREN
319 | SyntaxKind::RBRACK
320 | SyntaxKind::RBRACK2
321 | SyntaxKind::RBRACE => {
322 depth = depth.saturating_sub(1);
323 at_param_start = false;
324 }
325 SyntaxKind::COMMA if depth == 0 => {
326 at_param_start = true;
327 }
328 SyntaxKind::IDENT if depth == 0 && at_param_start => {
329 if let SyntaxElement::Token(token) = element {
330 params.push(Param {
331 name: SmolStr::new(token.text()),
332 name_token: token.clone(),
333 });
334 }
335 at_param_start = false;
336 }
337 SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE | SyntaxKind::COMMENT => {}
338 _ => {
339 at_param_start = false;
340 }
341 }
342 i += 1;
343 }
344 params
345 }
346
347 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
352 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
353 let rparen_idx = self.rparen_index()?;
354 elements[rparen_idx + 1..]
355 .iter()
356 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
357 .cloned()
358 }
359}
360
361#[derive(Debug, Clone)]
362pub struct Param {
363 pub name: SmolStr,
364 pub name_token: SyntaxToken<RLanguage>,
365}
366
367fn is_assignment_op(kind: SyntaxKind) -> bool {
368 matches!(
369 kind,
370 SyntaxKind::ASSIGN_LEFT
371 | SyntaxKind::ASSIGN_RIGHT
372 | SyntaxKind::SUPER_ASSIGN
373 | SyntaxKind::SUPER_ASSIGN_RIGHT
374 | SyntaxKind::ASSIGN_EQ
375 | SyntaxKind::WALRUS
376 )
377}
378
379fn is_right_assign(kind: SyntaxKind) -> bool {
380 matches!(
381 kind,
382 SyntaxKind::ASSIGN_RIGHT | SyntaxKind::SUPER_ASSIGN_RIGHT
383 )
384}
385
386fn assignment_op_index(elements: &[SyntaxElement<RLanguage>]) -> Option<usize> {
387 elements
388 .iter()
389 .position(|e| matches!(e, SyntaxElement::Token(t) if is_assignment_op(t.kind())))
390}
391
392fn element_kind(element: &SyntaxElement<RLanguage>) -> Option<SyntaxKind> {
393 Some(element.kind())
394}
395
396fn namespace_member_token(node: &SyntaxNode) -> Option<SyntaxToken<RLanguage>> {
400 let mut seen_ns_op = false;
401 for element in node.children_with_tokens() {
402 match element {
403 SyntaxElement::Token(t)
404 if matches!(t.kind(), SyntaxKind::COLON2 | SyntaxKind::COLON3) =>
405 {
406 seen_ns_op = true;
407 }
408 SyntaxElement::Token(t) if seen_ns_op && t.kind() == SyntaxKind::IDENT => {
409 return Some(t);
410 }
411 _ => {}
412 }
413 }
414 None
415}
416
417impl CallExpr {
418 pub fn arg_list(&self) -> Option<ArgList> {
419 support::child(self.syntax())
420 }
421
422 pub fn callee_token(&self) -> Option<SyntaxToken<RLanguage>> {
428 for element in self.syntax().children_with_tokens() {
429 match element {
430 SyntaxElement::Token(token)
431 if is_trivia(token.kind()) || token.kind() == SyntaxKind::COMMENT =>
432 {
433 continue;
434 }
435 SyntaxElement::Token(token)
436 if matches!(token.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
437 {
438 return Some(token);
439 }
440 SyntaxElement::Node(node) if node.kind() == SyntaxKind::BINARY_EXPR => {
447 return namespace_member_token(&node);
448 }
449 _ => return None,
450 }
451 }
452 None
453 }
454
455 pub fn callee_name(&self) -> Option<SmolStr> {
458 self.callee_token().as_ref().map(token_name)
459 }
460
461 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
465 last_element_before(self.syntax(), SyntaxKind::LPAREN)
466 }
467}
468
469impl SubsetExpr {
470 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
472 last_element_before(self.syntax(), SyntaxKind::LBRACK)
473 }
474
475 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
476 first_child_token(self.syntax(), SyntaxKind::LBRACK)
477 }
478
479 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
480 first_child_token(self.syntax(), SyntaxKind::RBRACK)
481 }
482
483 pub fn arg_list(&self) -> Option<ArgList> {
484 support::child(self.syntax())
485 }
486
487 pub fn args(&self) -> impl Iterator<Item = Arg> {
488 self.arg_list()
489 .map(|list| list.args().collect::<Vec<_>>())
490 .unwrap_or_default()
491 .into_iter()
492 }
493}
494
495impl Subset2Expr {
496 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
498 last_element_before(self.syntax(), SyntaxKind::LBRACK2)
499 }
500
501 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
502 first_child_token(self.syntax(), SyntaxKind::LBRACK2)
503 }
504
505 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
506 first_child_token(self.syntax(), SyntaxKind::RBRACK2)
507 }
508
509 pub fn arg_list(&self) -> Option<ArgList> {
510 support::child(self.syntax())
511 }
512
513 pub fn args(&self) -> impl Iterator<Item = Arg> {
514 self.arg_list()
515 .map(|list| list.args().collect::<Vec<_>>())
516 .unwrap_or_default()
517 .into_iter()
518 }
519}
520
521fn last_element_before(
524 node: &SyntaxNode,
525 boundary: SyntaxKind,
526) -> Option<SyntaxElement<RLanguage>> {
527 let elements: Vec<_> = node.children_with_tokens().collect();
528 let idx = elements.iter().position(|e| e.kind() == boundary)?;
529 elements[..idx]
530 .iter()
531 .rev()
532 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
533 .cloned()
534}
535
536#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct NamespaceAccess {
540 pub package: SmolStr,
541 pub package_token: SyntaxToken<RLanguage>,
542 pub internal: bool,
544 pub name: SmolStr,
545 pub name_token: SyntaxToken<RLanguage>,
546}
547
548impl BinaryExpr {
549 pub fn namespace_access(&self) -> Option<NamespaceAccess> {
554 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
555 let (op_idx, internal) = elements
556 .iter()
557 .enumerate()
558 .find_map(|(i, e)| match e.kind() {
559 SyntaxKind::COLON2 => Some((i, false)),
560 SyntaxKind::COLON3 => Some((i, true)),
561 _ => None,
562 })?;
563 let package_token = elements[..op_idx].iter().rev().find_map(|e| match e {
565 SyntaxElement::Token(t)
566 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
567 {
568 Some(t.clone())
569 }
570 _ => None,
571 })?;
572 let rhs = elements[op_idx + 1..]
575 .iter()
576 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?;
577 let name_token = match rhs {
578 SyntaxElement::Token(t)
579 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
580 {
581 t.clone()
582 }
583 SyntaxElement::Node(n) if n.kind() == SyntaxKind::CALL_EXPR => {
584 CallExpr::cast(n.clone())?.callee_token()?
585 }
586 _ => return None,
587 };
588 Some(NamespaceAccess {
589 package: token_name(&package_token),
590 package_token,
591 internal,
592 name: token_name(&name_token),
593 name_token,
594 })
595 }
596}
597
598impl ArgList {
599 pub fn args(&self) -> impl Iterator<Item = Arg> {
600 support::children(self.syntax())
601 }
602}
603
604impl IfExpr {
605 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
606 self.syntax().children_with_tokens().collect()
607 }
608
609 pub fn if_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
610 self.elements()
611 .into_iter()
612 .find_map(|element| match element {
613 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IF_KW => Some(token),
614 _ => None,
615 })
616 }
617
618 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
619 let elements = self.elements();
620 let lparen_idx = self.lparen_index()?;
621 let rparen_idx = self.rparen_index()?;
622 Some(elements[lparen_idx + 1..rparen_idx].to_vec())
623 }
624
625 pub fn then_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
626 let elements = self.elements();
627 let rparen_idx = self.rparen_index()?;
628 let else_idx = find_token_after_index(&elements, rparen_idx, SyntaxKind::ELSE_KW);
629 let then_end = else_idx.unwrap_or(elements.len());
630 Some(elements[rparen_idx + 1..then_end].to_vec())
631 }
632
633 pub fn else_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
634 self.elements()
635 .into_iter()
636 .find_map(|element| match element {
637 SyntaxElement::Token(token) if token.kind() == SyntaxKind::ELSE_KW => Some(token),
638 _ => None,
639 })
640 }
641
642 pub fn else_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
643 let elements = self.elements();
644 let else_idx = find_token_index(&elements, SyntaxKind::ELSE_KW)?;
645 Some(elements[else_idx + 1..].to_vec())
646 }
647
648 pub fn lparen_index(&self) -> Option<usize> {
649 find_token_index(&self.elements(), SyntaxKind::LPAREN)
650 }
651
652 pub fn rparen_index(&self) -> Option<usize> {
653 let elements = self.elements();
654 let lparen_idx = self.lparen_index()?;
655 find_token_after_index(&elements, lparen_idx, SyntaxKind::RPAREN)
656 }
657}
658
659impl ForExpr {
660 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
661 self.syntax().children_with_tokens().collect()
662 }
663
664 pub fn for_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
665 self.elements()
666 .into_iter()
667 .find_map(|element| match element {
668 SyntaxElement::Token(token) if token.kind() == SyntaxKind::FOR_KW => Some(token),
669 _ => None,
670 })
671 }
672
673 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
674 let elements = self.elements();
675 let lparen_idx = self.lparen_index()?;
676
677 let mut depth = 0usize;
678 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
679 |(idx, element)| match element {
680 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
681 depth += 1;
682 None
683 }
684 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
685 depth = depth.saturating_sub(1);
686 if depth == 0 { Some(idx) } else { None }
687 }
688 _ => None,
689 },
690 )?;
691
692 Some((lparen_idx, rparen_idx))
693 }
694
695 pub fn lparen_index(&self) -> Option<usize> {
696 let elements = self.elements();
697 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
698 find_token_after_index(&elements, for_idx, SyntaxKind::LPAREN)
699 }
700
701 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
702 let elements = self.elements();
703 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
704 let (_, rparen_idx) = self.clause_bounds()?;
705 Some(
706 elements[for_idx + 1..rparen_idx]
707 .iter()
708 .filter_map(|element| match element {
709 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
710 Some(token.clone())
711 }
712 _ => None,
713 })
714 .collect(),
715 )
716 }
717
718 pub fn clause_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
719 let elements = self.elements();
720 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
721 Some(
722 elements[lparen_idx + 1..rparen_idx]
723 .iter()
724 .filter(|element| {
725 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
726 })
727 .cloned()
728 .collect(),
729 )
730 }
731
732 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
733 let elements = self.elements();
734 let (_, rparen_idx) = self.clause_bounds()?;
735 let mut comments = Vec::new();
736 for element in &elements[rparen_idx + 1..] {
737 if is_trivia(element.kind()) {
738 continue;
739 }
740 if let SyntaxElement::Token(token) = element
741 && token.kind() == SyntaxKind::COMMENT
742 {
743 comments.push(token.clone());
744 continue;
745 }
746 break;
747 }
748 Some(comments)
749 }
750
751 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
752 let elements = self.elements();
753 let (_, rparen_idx) = self.clause_bounds()?;
754 for element in &elements[rparen_idx + 1..] {
755 if is_trivia(element.kind()) {
756 continue;
757 }
758 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
759 {
760 continue;
761 }
762 return Some(element.clone());
763 }
764 None
765 }
766
767 pub fn parts(&self) -> Option<ForExprParts> {
768 self.for_keyword()?;
769 self.lparen_index()?;
770 self.clause_bounds()?;
771
772 let clause_elements = self.clause_elements()?;
773 let in_idx = clause_elements.iter().position(
774 |el| matches!(el, SyntaxElement::Token(tok) if tok.kind() == SyntaxKind::IN_KW),
775 )?;
776
777 Some(ForExprParts {
778 leading_comments: self.leading_comments()?,
779 variable_elements: clause_elements[..in_idx].to_vec(),
780 sequence_elements: clause_elements[in_idx + 1..].to_vec(),
781 post_clause_comments: self.post_clause_comments()?,
782 body: self.body_element(),
783 })
784 }
785}
786
787impl WhileExpr {
788 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
789 self.syntax().children_with_tokens().collect()
790 }
791
792 pub fn while_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
793 self.elements()
794 .into_iter()
795 .find_map(|element| match element {
796 SyntaxElement::Token(token) if token.kind() == SyntaxKind::WHILE_KW => Some(token),
797 _ => None,
798 })
799 }
800
801 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
802 let elements = self.elements();
803 let lparen_idx = self.lparen_index()?;
804
805 let mut depth = 0usize;
806 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
807 |(idx, element)| match element {
808 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
809 depth += 1;
810 None
811 }
812 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
813 depth = depth.saturating_sub(1);
814 if depth == 0 { Some(idx) } else { None }
815 }
816 _ => None,
817 },
818 )?;
819
820 Some((lparen_idx, rparen_idx))
821 }
822
823 pub fn lparen_index(&self) -> Option<usize> {
824 let elements = self.elements();
825 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
826 find_token_after_index(&elements, while_idx, SyntaxKind::LPAREN)
827 }
828
829 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
830 let elements = self.elements();
831 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
832 let (_, rparen_idx) = self.clause_bounds()?;
833 Some(
834 elements[while_idx + 1..rparen_idx]
835 .iter()
836 .filter_map(|element| match element {
837 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
838 Some(token.clone())
839 }
840 _ => None,
841 })
842 .collect(),
843 )
844 }
845
846 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
847 let elements = self.elements();
848 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
849 Some(
850 elements[lparen_idx + 1..rparen_idx]
851 .iter()
852 .filter(|element| {
853 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
854 })
855 .cloned()
856 .collect(),
857 )
858 }
859
860 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
861 let elements = self.elements();
862 let (_, rparen_idx) = self.clause_bounds()?;
863 let mut comments = Vec::new();
864 for element in &elements[rparen_idx + 1..] {
865 if is_trivia(element.kind()) {
866 continue;
867 }
868 if let SyntaxElement::Token(token) = element
869 && token.kind() == SyntaxKind::COMMENT
870 {
871 comments.push(token.clone());
872 continue;
873 }
874 break;
875 }
876 Some(comments)
877 }
878
879 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
880 let elements = self.elements();
881 let (_, rparen_idx) = self.clause_bounds()?;
882 for element in &elements[rparen_idx + 1..] {
883 if is_trivia(element.kind()) {
884 continue;
885 }
886 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
887 {
888 continue;
889 }
890 return Some(element.clone());
891 }
892 None
893 }
894
895 pub fn parts(&self) -> Option<WhileExprParts> {
896 self.while_keyword()?;
897 self.lparen_index()?;
898 self.clause_bounds()?;
899
900 Some(WhileExprParts {
901 leading_comments: self.leading_comments()?,
902 condition_elements: self.condition_elements()?,
903 post_clause_comments: self.post_clause_comments()?,
904 body: self.body_element(),
905 })
906 }
907}
908
909impl BinaryExpr {
910 pub fn lhs(&self) -> Option<SyntaxElement<RLanguage>> {
913 self.parts().map(|(lhs, _, _)| lhs)
914 }
915
916 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
918 self.parts().map(|(_, op, _)| op)
919 }
920
921 pub fn op_kind(&self) -> Option<SyntaxKind> {
922 self.op().map(|op| op.kind())
923 }
924
925 pub fn rhs(&self) -> Option<SyntaxElement<RLanguage>> {
927 self.parts().map(|(_, _, rhs)| rhs)
928 }
929
930 pub fn parts(
932 &self,
933 ) -> Option<(
934 SyntaxElement<RLanguage>,
935 SyntaxToken<RLanguage>,
936 SyntaxElement<RLanguage>,
937 )> {
938 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
939 let op_idx = elements
940 .iter()
941 .position(|e| matches!(e, SyntaxElement::Token(t) if is_binary_operator(t.kind())))?;
942 let op = elements[op_idx].as_token()?.clone();
943 let lhs = elements[..op_idx]
944 .iter()
945 .rev()
946 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
947 .clone();
948 let rhs = elements[op_idx + 1..]
949 .iter()
950 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
951 .clone();
952 Some((lhs, op, rhs))
953 }
954}
955
956impl UnaryExpr {
957 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
959 self.syntax().children_with_tokens().find_map(|e| match e {
960 SyntaxElement::Token(t) if is_unary_operator(t.kind()) => Some(t),
961 _ => None,
962 })
963 }
964
965 pub fn op_kind(&self) -> Option<SyntaxKind> {
966 self.op().map(|op| op.kind())
967 }
968
969 pub fn operand(&self) -> Option<SyntaxElement<RLanguage>> {
971 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
972 let op_idx = elements
973 .iter()
974 .position(|e| matches!(e, SyntaxElement::Token(t) if is_unary_operator(t.kind())))?;
975 elements[op_idx + 1..]
976 .iter()
977 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
978 .cloned()
979 }
980}
981
982impl ParenExpr {
983 pub fn lparen(&self) -> Option<SyntaxToken<RLanguage>> {
984 first_child_token(self.syntax(), SyntaxKind::LPAREN)
985 }
986
987 pub fn rparen(&self) -> Option<SyntaxToken<RLanguage>> {
988 first_child_token(self.syntax(), SyntaxKind::RPAREN)
989 }
990
991 pub fn inner(&self) -> Option<SyntaxElement<RLanguage>> {
993 self.syntax().children_with_tokens().find(|e| {
994 !is_trivia(e.kind())
995 && !matches!(
996 e.kind(),
997 SyntaxKind::COMMENT | SyntaxKind::LPAREN | SyntaxKind::RPAREN
998 )
999 })
1000 }
1001}
1002
1003impl BlockExpr {
1004 pub fn lbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1005 first_child_token(self.syntax(), SyntaxKind::LBRACE)
1006 }
1007
1008 pub fn rbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1009 first_child_token(self.syntax(), SyntaxKind::RBRACE)
1010 }
1011
1012 pub fn statements(&self) -> impl Iterator<Item = SyntaxElement<RLanguage>> + '_ {
1016 self.syntax().children_with_tokens().filter(|e| {
1017 !is_trivia(e.kind())
1018 && !matches!(
1019 e.kind(),
1020 SyntaxKind::COMMENT
1021 | SyntaxKind::LBRACE
1022 | SyntaxKind::RBRACE
1023 | SyntaxKind::SEMICOLON
1024 )
1025 })
1026 }
1027}
1028
1029impl Arg {
1030 pub fn eq_token(&self) -> Option<SyntaxToken<RLanguage>> {
1032 first_child_token(self.syntax(), SyntaxKind::ASSIGN_EQ)
1033 }
1034
1035 pub fn name_token(&self) -> Option<SyntaxToken<RLanguage>> {
1038 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1039 let eq = elements
1040 .iter()
1041 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)?;
1042 elements[..eq].iter().rev().find_map(|e| match e {
1043 SyntaxElement::Token(t)
1044 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
1045 {
1046 Some(t.clone())
1047 }
1048 _ => None,
1049 })
1050 }
1051
1052 pub fn name(&self) -> Option<SmolStr> {
1054 self.name_token().as_ref().map(token_name)
1055 }
1056
1057 pub fn is_named(&self) -> bool {
1058 self.name_token().is_some()
1059 }
1060
1061 pub fn value(&self) -> Option<SyntaxElement<RLanguage>> {
1064 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1065 let start = match elements
1066 .iter()
1067 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)
1068 {
1069 Some(eq) => eq + 1,
1070 None => 0,
1071 };
1072 elements[start..]
1073 .iter()
1074 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1075 .cloned()
1076 }
1077}
1078
1079impl RepeatExpr {
1080 pub fn repeat_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
1081 first_child_token(self.syntax(), SyntaxKind::REPEAT_KW)
1082 }
1083
1084 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
1086 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1087 let kw_idx = elements
1088 .iter()
1089 .position(|e| e.kind() == SyntaxKind::REPEAT_KW)?;
1090 elements[kw_idx + 1..]
1091 .iter()
1092 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1093 .cloned()
1094 }
1095}
1096
1097fn find_token_index(elements: &[SyntaxElement<RLanguage>], kind: SyntaxKind) -> Option<usize> {
1098 elements
1099 .iter()
1100 .position(|element| matches!(element, SyntaxElement::Token(token) if token.kind() == kind))
1101}
1102
1103fn find_token_after_index(
1104 elements: &[SyntaxElement<RLanguage>],
1105 start_idx: usize,
1106 kind: SyntaxKind,
1107) -> Option<usize> {
1108 elements
1109 .iter()
1110 .enumerate()
1111 .skip(start_idx + 1)
1112 .find_map(|(idx, element)| match element {
1113 SyntaxElement::Token(token) if token.kind() == kind => Some(idx),
1114 _ => None,
1115 })
1116}