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.value_text().is_some())
103 || self
104 .0
105 .children()
106 .any(|child| child.kind() != SyntaxKind::ROXYGEN_TAG)
107 }
108}
109
110impl RoxygenTag {
111 pub fn at(&self) -> Option<SyntaxToken<RLanguage>> {
113 first_child_token(&self.0, SyntaxKind::ROXYGEN_AT)
114 }
115
116 pub fn name(&self) -> Option<SmolStr> {
118 first_child_token(&self.0, SyntaxKind::ROXYGEN_TAG_NAME).map(|t| SmolStr::new(t.text()))
119 }
120
121 pub fn arg(&self) -> Option<SyntaxToken<RLanguage>> {
123 first_child_token(&self.0, SyntaxKind::ROXYGEN_TAG_ARG)
124 }
125
126 pub fn text(&self) -> Option<SyntaxToken<RLanguage>> {
128 first_child_token(&self.0, SyntaxKind::ROXYGEN_TEXT)
129 }
130
131 pub fn value_text(&self) -> Option<String> {
142 let head_end = self.arg().map(|arg| arg.text_range().end()).or_else(|| {
143 first_child_token(&self.0, SyntaxKind::ROXYGEN_TAG_NAME)
144 .map(|name| name.text_range().end())
145 })?;
146 let value: String = self
147 .0
148 .descendants_with_tokens()
149 .filter_map(|element| element.into_token())
150 .filter(|token| {
151 token.text_range().start() >= head_end && token.kind() != SyntaxKind::ROXYGEN_MARKER
152 })
153 .map(|token| token.text().to_string())
154 .collect();
155 let trimmed = value.trim();
156 (!trimmed.is_empty()).then(|| trimmed.to_string())
157 }
158
159 pub fn is_examples(&self) -> bool {
161 matches!(self.name().as_deref(), Some("examples" | "examplesIf"))
162 }
163
164 pub fn arg_names(&self) -> Vec<(SmolStr, TextRange)> {
168 let Some(arg) = self.arg() else {
169 return Vec::new();
170 };
171 let arg_start = arg.text_range().start();
172 let mut names = Vec::new();
173 let mut offset = 0usize;
174 for piece in arg.text().split(',') {
175 let trimmed = piece.trim();
176 if !trimmed.is_empty() {
177 let lead = piece.len() - piece.trim_start().len();
178 let start = arg_start + TextSize::from((offset + lead) as u32);
179 names.push((
180 SmolStr::new(trimmed),
181 TextRange::at(start, TextSize::of(trimmed)),
182 ));
183 }
184 offset += piece.len() + 1;
185 }
186 names
187 }
188}
189
190#[derive(Debug, Clone, PartialEq, Eq)]
191pub struct ForExprParts {
192 pub leading_comments: Vec<SyntaxToken<RLanguage>>,
193 pub variable_elements: Vec<SyntaxElement<RLanguage>>,
194 pub sequence_elements: Vec<SyntaxElement<RLanguage>>,
195 pub post_clause_comments: Vec<SyntaxToken<RLanguage>>,
196 pub body: Option<SyntaxElement<RLanguage>>,
197}
198
199#[derive(Debug, Clone, PartialEq, Eq)]
200pub struct WhileExprParts {
201 pub leading_comments: Vec<SyntaxToken<RLanguage>>,
202 pub condition_elements: Vec<SyntaxElement<RLanguage>>,
203 pub post_clause_comments: Vec<SyntaxToken<RLanguage>>,
204 pub body: Option<SyntaxElement<RLanguage>>,
205}
206
207impl Root {
208 pub fn expressions(&self) -> impl Iterator<Item = SyntaxNode> {
209 self.syntax().children()
210 }
211}
212
213impl AssignmentExpr {
214 pub fn op_kind(&self) -> Option<SyntaxKind> {
218 self.syntax()
219 .children_with_tokens()
220 .find_map(|element| match element {
221 SyntaxElement::Token(token) if is_assignment_op(token.kind()) => Some(token.kind()),
222 _ => None,
223 })
224 }
225
226 pub fn op_token(&self) -> Option<SyntaxToken<RLanguage>> {
228 self.syntax()
229 .children_with_tokens()
230 .find_map(|element| match element {
231 SyntaxElement::Token(token) if is_assignment_op(token.kind()) => Some(token),
232 _ => None,
233 })
234 }
235
236 pub fn target_element(&self) -> Option<SyntaxElement<RLanguage>> {
240 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
241 let op_idx = assignment_op_index(&elements)?;
242 let kind = element_kind(&elements[op_idx])?;
243 let (start, end) = if is_right_assign(kind) {
244 (op_idx + 1, elements.len())
245 } else {
246 (0, op_idx)
247 };
248 elements[start..end]
249 .iter()
250 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
251 .cloned()
252 }
253
254 pub fn value_element(&self) -> Option<SyntaxElement<RLanguage>> {
256 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
257 let op_idx = assignment_op_index(&elements)?;
258 let kind = element_kind(&elements[op_idx])?;
259 let (start, end) = if is_right_assign(kind) {
260 (0, op_idx)
261 } else {
262 (op_idx + 1, elements.len())
263 };
264 elements[start..end]
265 .iter()
266 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
267 .cloned()
268 }
269
270 pub fn target_name(&self) -> Option<SmolStr> {
274 match self.target_element()? {
275 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IDENT => {
276 Some(SmolStr::new(token.text()))
277 }
278 SyntaxElement::Token(token) if token.kind() == SyntaxKind::STRING => {
279 StringLit::cast(token).and_then(|s| s.unquote().map(SmolStr::new))
280 }
281 _ => None,
282 }
283 }
284
285 pub fn target_name_token(&self) -> Option<SyntaxToken<RLanguage>> {
287 match self.target_element()? {
288 SyntaxElement::Token(token)
289 if token.kind() == SyntaxKind::IDENT || token.kind() == SyntaxKind::STRING =>
290 {
291 Some(token)
292 }
293 _ => None,
294 }
295 }
296}
297
298impl FunctionExpr {
299 pub fn lparen_index(&self) -> Option<usize> {
300 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
301 elements.iter().position(|e| e.kind() == SyntaxKind::LPAREN)
302 }
303
304 pub fn rparen_index(&self) -> Option<usize> {
305 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
306 let lparen_idx = self.lparen_index()?;
307 let mut depth = 0usize;
308 elements
309 .iter()
310 .enumerate()
311 .skip(lparen_idx)
312 .find_map(|(i, el)| match el.kind() {
313 SyntaxKind::LPAREN => {
314 depth += 1;
315 None
316 }
317 SyntaxKind::RPAREN => {
318 depth = depth.saturating_sub(1);
319 if depth == 0 { Some(i) } else { None }
320 }
321 _ => None,
322 })
323 }
324
325 pub fn formals(&self) -> Vec<Formal> {
328 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
329 let Some(lparen_idx) = self.lparen_index() else {
330 return Vec::new();
331 };
332 let Some(rparen_idx) = self.rparen_index() else {
333 return Vec::new();
334 };
335
336 split_function_formals(&elements[lparen_idx + 1..rparen_idx])
337 .into_iter()
338 .filter_map(formal_from_elements)
339 .collect()
340 }
341
342 pub fn params(&self) -> Vec<Param> {
346 self.formals()
347 .into_iter()
348 .map(|formal| Param {
349 name: formal.name,
350 name_token: formal.name_token,
351 })
352 .collect()
353 }
354
355 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
360 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
361 let rparen_idx = self.rparen_index()?;
362 elements[rparen_idx + 1..]
363 .iter()
364 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
365 .cloned()
366 }
367}
368
369#[derive(Debug, Clone, PartialEq, Eq, Hash)]
372pub struct Formal {
373 name: SmolStr,
374 name_token: SyntaxToken<RLanguage>,
375 range: TextRange,
376 default: Option<SyntaxElement<RLanguage>>,
377}
378
379impl Formal {
380 pub fn name(&self) -> SmolStr {
383 self.name.clone()
384 }
385
386 pub fn name_token(&self) -> SyntaxToken<RLanguage> {
388 self.name_token.clone()
389 }
390
391 pub fn text_range(&self) -> TextRange {
393 self.range
394 }
395
396 pub fn default(&self) -> Option<SyntaxElement<RLanguage>> {
398 self.default.clone()
399 }
400
401 pub fn default_range(&self) -> Option<TextRange> {
403 self.default.as_ref().map(SyntaxElement::text_range)
404 }
405}
406
407fn split_function_formals(
408 elements: &[SyntaxElement<RLanguage>],
409) -> Vec<&[SyntaxElement<RLanguage>]> {
410 let mut formals = Vec::new();
411 let mut start = 0usize;
412 let mut depth = 0usize;
413
414 for (index, element) in elements.iter().enumerate() {
415 match element.kind() {
416 SyntaxKind::LPAREN | SyntaxKind::LBRACK | SyntaxKind::LBRACK2 | SyntaxKind::LBRACE => {
417 depth += 1
418 }
419 SyntaxKind::RPAREN | SyntaxKind::RBRACK | SyntaxKind::RBRACK2 | SyntaxKind::RBRACE => {
420 depth = depth.saturating_sub(1)
421 }
422 SyntaxKind::COMMA if depth == 0 => {
423 formals.push(&elements[start..index]);
424 start = index + 1;
425 }
426 _ => {}
427 }
428 }
429 formals.push(&elements[start..]);
430 formals
431}
432
433fn formal_from_elements(elements: &[SyntaxElement<RLanguage>]) -> Option<Formal> {
434 let name_index = elements
435 .iter()
436 .position(|element| !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT)?;
437 let SyntaxElement::Token(name_token) = &elements[name_index] else {
438 return None;
439 };
440 if name_token.kind() != SyntaxKind::IDENT {
441 return None;
442 }
443
444 let eq_index = elements[name_index + 1..]
445 .iter()
446 .position(|element| element.kind() == SyntaxKind::ASSIGN_EQ)
447 .map(|index| name_index + 1 + index);
448 let default = eq_index.and_then(|index| {
449 elements[index + 1..]
450 .iter()
451 .find(|element| !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT)
452 .filter(|element| crate::ast::Expr::cast((*element).clone()).is_some())
453 .cloned()
454 });
455 let end = default
456 .as_ref()
457 .map(SyntaxElement::text_range)
458 .map(TextRange::end)
459 .or_else(|| eq_index.map(|index| elements[index].text_range().end()))
460 .unwrap_or_else(|| name_token.text_range().end());
461
462 Some(Formal {
463 name: SmolStr::new(name_token.text()),
464 name_token: name_token.clone(),
465 range: TextRange::new(name_token.text_range().start(), end),
466 default,
467 })
468}
469
470#[derive(Debug, Clone)]
471pub struct Param {
472 pub name: SmolStr,
473 pub name_token: SyntaxToken<RLanguage>,
474}
475
476fn is_assignment_op(kind: SyntaxKind) -> bool {
477 matches!(
478 kind,
479 SyntaxKind::ASSIGN_LEFT
480 | SyntaxKind::ASSIGN_RIGHT
481 | SyntaxKind::SUPER_ASSIGN
482 | SyntaxKind::SUPER_ASSIGN_RIGHT
483 | SyntaxKind::ASSIGN_EQ
484 | SyntaxKind::WALRUS
485 )
486}
487
488fn is_right_assign(kind: SyntaxKind) -> bool {
489 matches!(
490 kind,
491 SyntaxKind::ASSIGN_RIGHT | SyntaxKind::SUPER_ASSIGN_RIGHT
492 )
493}
494
495fn assignment_op_index(elements: &[SyntaxElement<RLanguage>]) -> Option<usize> {
496 elements
497 .iter()
498 .position(|e| matches!(e, SyntaxElement::Token(t) if is_assignment_op(t.kind())))
499}
500
501fn element_kind(element: &SyntaxElement<RLanguage>) -> Option<SyntaxKind> {
502 Some(element.kind())
503}
504
505fn namespace_member_token(node: &SyntaxNode) -> Option<SyntaxToken<RLanguage>> {
509 let mut seen_ns_op = false;
510 for element in node.children_with_tokens() {
511 match element {
512 SyntaxElement::Token(t)
513 if matches!(t.kind(), SyntaxKind::COLON2 | SyntaxKind::COLON3) =>
514 {
515 seen_ns_op = true;
516 }
517 SyntaxElement::Token(t) if seen_ns_op && t.kind() == SyntaxKind::IDENT => {
518 return Some(t);
519 }
520 _ => {}
521 }
522 }
523 None
524}
525
526impl CallExpr {
527 pub fn arg_list(&self) -> Option<ArgList> {
528 support::child(self.syntax())
529 }
530
531 pub fn callee_token(&self) -> Option<SyntaxToken<RLanguage>> {
537 for element in self.syntax().children_with_tokens() {
538 match element {
539 SyntaxElement::Token(token)
540 if is_trivia(token.kind()) || token.kind() == SyntaxKind::COMMENT =>
541 {
542 continue;
543 }
544 SyntaxElement::Token(token)
545 if matches!(token.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
546 {
547 return Some(token);
548 }
549 SyntaxElement::Node(node) if node.kind() == SyntaxKind::BINARY_EXPR => {
556 return namespace_member_token(&node);
557 }
558 _ => return None,
559 }
560 }
561 None
562 }
563
564 pub fn callee_name(&self) -> Option<SmolStr> {
567 self.callee_token().as_ref().map(token_name)
568 }
569
570 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
574 last_element_before(self.syntax(), SyntaxKind::LPAREN)
575 }
576}
577
578impl SubsetExpr {
579 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
581 last_element_before(self.syntax(), SyntaxKind::LBRACK)
582 }
583
584 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
585 first_child_token(self.syntax(), SyntaxKind::LBRACK)
586 }
587
588 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
589 first_child_token(self.syntax(), SyntaxKind::RBRACK)
590 }
591
592 pub fn arg_list(&self) -> Option<ArgList> {
593 support::child(self.syntax())
594 }
595
596 pub fn args(&self) -> impl Iterator<Item = Arg> {
597 self.arg_list()
598 .map(|list| list.args().collect::<Vec<_>>())
599 .unwrap_or_default()
600 .into_iter()
601 }
602}
603
604impl Subset2Expr {
605 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
607 last_element_before(self.syntax(), SyntaxKind::LBRACK2)
608 }
609
610 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
611 first_child_token(self.syntax(), SyntaxKind::LBRACK2)
612 }
613
614 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
615 first_child_token(self.syntax(), SyntaxKind::RBRACK2)
616 }
617
618 pub fn arg_list(&self) -> Option<ArgList> {
619 support::child(self.syntax())
620 }
621
622 pub fn args(&self) -> impl Iterator<Item = Arg> {
623 self.arg_list()
624 .map(|list| list.args().collect::<Vec<_>>())
625 .unwrap_or_default()
626 .into_iter()
627 }
628}
629
630fn last_element_before(
633 node: &SyntaxNode,
634 boundary: SyntaxKind,
635) -> Option<SyntaxElement<RLanguage>> {
636 let elements: Vec<_> = node.children_with_tokens().collect();
637 let idx = elements.iter().position(|e| e.kind() == boundary)?;
638 elements[..idx]
639 .iter()
640 .rev()
641 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
642 .cloned()
643}
644
645#[derive(Debug, Clone, PartialEq, Eq)]
648pub struct NamespaceAccess {
649 pub package: SmolStr,
650 pub package_token: SyntaxToken<RLanguage>,
651 pub internal: bool,
653 pub name: SmolStr,
654 pub name_token: SyntaxToken<RLanguage>,
655}
656
657impl BinaryExpr {
658 pub fn namespace_access(&self) -> Option<NamespaceAccess> {
663 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
664 let (op_idx, internal) = elements
665 .iter()
666 .enumerate()
667 .find_map(|(i, e)| match e.kind() {
668 SyntaxKind::COLON2 => Some((i, false)),
669 SyntaxKind::COLON3 => Some((i, true)),
670 _ => None,
671 })?;
672 let package_token = elements[..op_idx].iter().rev().find_map(|e| match e {
674 SyntaxElement::Token(t)
675 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
676 {
677 Some(t.clone())
678 }
679 _ => None,
680 })?;
681 let rhs = elements[op_idx + 1..]
684 .iter()
685 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?;
686 let name_token = match rhs {
687 SyntaxElement::Token(t)
688 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
689 {
690 t.clone()
691 }
692 SyntaxElement::Node(n) if n.kind() == SyntaxKind::CALL_EXPR => {
693 CallExpr::cast(n.clone())?.callee_token()?
694 }
695 _ => return None,
696 };
697 Some(NamespaceAccess {
698 package: token_name(&package_token),
699 package_token,
700 internal,
701 name: token_name(&name_token),
702 name_token,
703 })
704 }
705}
706
707impl ArgList {
708 pub fn args(&self) -> impl Iterator<Item = Arg> {
709 support::children(self.syntax())
710 }
711}
712
713impl IfExpr {
714 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
715 self.syntax().children_with_tokens().collect()
716 }
717
718 pub fn if_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
719 self.elements()
720 .into_iter()
721 .find_map(|element| match element {
722 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IF_KW => Some(token),
723 _ => None,
724 })
725 }
726
727 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
728 let elements = self.elements();
729 let lparen_idx = self.lparen_index()?;
730 let rparen_idx = self.rparen_index()?;
731 Some(elements[lparen_idx + 1..rparen_idx].to_vec())
732 }
733
734 pub fn then_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
735 let elements = self.elements();
736 let rparen_idx = self.rparen_index()?;
737 let else_idx = find_token_after_index(&elements, rparen_idx, SyntaxKind::ELSE_KW);
738 let then_end = else_idx.unwrap_or(elements.len());
739 Some(elements[rparen_idx + 1..then_end].to_vec())
740 }
741
742 pub fn else_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
743 self.elements()
744 .into_iter()
745 .find_map(|element| match element {
746 SyntaxElement::Token(token) if token.kind() == SyntaxKind::ELSE_KW => Some(token),
747 _ => None,
748 })
749 }
750
751 pub fn else_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
752 let elements = self.elements();
753 let else_idx = find_token_index(&elements, SyntaxKind::ELSE_KW)?;
754 Some(elements[else_idx + 1..].to_vec())
755 }
756
757 pub fn lparen_index(&self) -> Option<usize> {
758 find_token_index(&self.elements(), SyntaxKind::LPAREN)
759 }
760
761 pub fn rparen_index(&self) -> Option<usize> {
762 let elements = self.elements();
763 let lparen_idx = self.lparen_index()?;
764 find_token_after_index(&elements, lparen_idx, SyntaxKind::RPAREN)
765 }
766}
767
768impl ForExpr {
769 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
770 self.syntax().children_with_tokens().collect()
771 }
772
773 pub fn for_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
774 self.elements()
775 .into_iter()
776 .find_map(|element| match element {
777 SyntaxElement::Token(token) if token.kind() == SyntaxKind::FOR_KW => Some(token),
778 _ => None,
779 })
780 }
781
782 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
783 let elements = self.elements();
784 let lparen_idx = self.lparen_index()?;
785
786 let mut depth = 0usize;
787 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
788 |(idx, element)| match element {
789 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
790 depth += 1;
791 None
792 }
793 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
794 depth = depth.saturating_sub(1);
795 if depth == 0 { Some(idx) } else { None }
796 }
797 _ => None,
798 },
799 )?;
800
801 Some((lparen_idx, rparen_idx))
802 }
803
804 pub fn lparen_index(&self) -> Option<usize> {
805 let elements = self.elements();
806 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
807 find_token_after_index(&elements, for_idx, SyntaxKind::LPAREN)
808 }
809
810 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
811 let elements = self.elements();
812 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
813 let (_, rparen_idx) = self.clause_bounds()?;
814 Some(
815 elements[for_idx + 1..rparen_idx]
816 .iter()
817 .filter_map(|element| match element {
818 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
819 Some(token.clone())
820 }
821 _ => None,
822 })
823 .collect(),
824 )
825 }
826
827 pub fn clause_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
828 let elements = self.elements();
829 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
830 Some(
831 elements[lparen_idx + 1..rparen_idx]
832 .iter()
833 .filter(|element| {
834 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
835 })
836 .cloned()
837 .collect(),
838 )
839 }
840
841 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
842 let elements = self.elements();
843 let (_, rparen_idx) = self.clause_bounds()?;
844 let mut comments = Vec::new();
845 for element in &elements[rparen_idx + 1..] {
846 if is_trivia(element.kind()) {
847 continue;
848 }
849 if let SyntaxElement::Token(token) = element
850 && token.kind() == SyntaxKind::COMMENT
851 {
852 comments.push(token.clone());
853 continue;
854 }
855 break;
856 }
857 Some(comments)
858 }
859
860 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
861 let elements = self.elements();
862 let (_, rparen_idx) = self.clause_bounds()?;
863 for element in &elements[rparen_idx + 1..] {
864 if is_trivia(element.kind()) {
865 continue;
866 }
867 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
868 {
869 continue;
870 }
871 return Some(element.clone());
872 }
873 None
874 }
875
876 pub fn parts(&self) -> Option<ForExprParts> {
877 self.for_keyword()?;
878 self.lparen_index()?;
879 self.clause_bounds()?;
880
881 let clause_elements = self.clause_elements()?;
882 let in_idx = clause_elements.iter().position(
883 |el| matches!(el, SyntaxElement::Token(tok) if tok.kind() == SyntaxKind::IN_KW),
884 )?;
885
886 Some(ForExprParts {
887 leading_comments: self.leading_comments()?,
888 variable_elements: clause_elements[..in_idx].to_vec(),
889 sequence_elements: clause_elements[in_idx + 1..].to_vec(),
890 post_clause_comments: self.post_clause_comments()?,
891 body: self.body_element(),
892 })
893 }
894}
895
896impl WhileExpr {
897 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
898 self.syntax().children_with_tokens().collect()
899 }
900
901 pub fn while_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
902 self.elements()
903 .into_iter()
904 .find_map(|element| match element {
905 SyntaxElement::Token(token) if token.kind() == SyntaxKind::WHILE_KW => Some(token),
906 _ => None,
907 })
908 }
909
910 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
911 let elements = self.elements();
912 let lparen_idx = self.lparen_index()?;
913
914 let mut depth = 0usize;
915 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
916 |(idx, element)| match element {
917 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
918 depth += 1;
919 None
920 }
921 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
922 depth = depth.saturating_sub(1);
923 if depth == 0 { Some(idx) } else { None }
924 }
925 _ => None,
926 },
927 )?;
928
929 Some((lparen_idx, rparen_idx))
930 }
931
932 pub fn lparen_index(&self) -> Option<usize> {
933 let elements = self.elements();
934 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
935 find_token_after_index(&elements, while_idx, SyntaxKind::LPAREN)
936 }
937
938 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
939 let elements = self.elements();
940 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
941 let (_, rparen_idx) = self.clause_bounds()?;
942 Some(
943 elements[while_idx + 1..rparen_idx]
944 .iter()
945 .filter_map(|element| match element {
946 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
947 Some(token.clone())
948 }
949 _ => None,
950 })
951 .collect(),
952 )
953 }
954
955 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
956 let elements = self.elements();
957 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
958 Some(
959 elements[lparen_idx + 1..rparen_idx]
960 .iter()
961 .filter(|element| {
962 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
963 })
964 .cloned()
965 .collect(),
966 )
967 }
968
969 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
970 let elements = self.elements();
971 let (_, rparen_idx) = self.clause_bounds()?;
972 let mut comments = Vec::new();
973 for element in &elements[rparen_idx + 1..] {
974 if is_trivia(element.kind()) {
975 continue;
976 }
977 if let SyntaxElement::Token(token) = element
978 && token.kind() == SyntaxKind::COMMENT
979 {
980 comments.push(token.clone());
981 continue;
982 }
983 break;
984 }
985 Some(comments)
986 }
987
988 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
989 let elements = self.elements();
990 let (_, rparen_idx) = self.clause_bounds()?;
991 for element in &elements[rparen_idx + 1..] {
992 if is_trivia(element.kind()) {
993 continue;
994 }
995 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
996 {
997 continue;
998 }
999 return Some(element.clone());
1000 }
1001 None
1002 }
1003
1004 pub fn parts(&self) -> Option<WhileExprParts> {
1005 self.while_keyword()?;
1006 self.lparen_index()?;
1007 self.clause_bounds()?;
1008
1009 Some(WhileExprParts {
1010 leading_comments: self.leading_comments()?,
1011 condition_elements: self.condition_elements()?,
1012 post_clause_comments: self.post_clause_comments()?,
1013 body: self.body_element(),
1014 })
1015 }
1016}
1017
1018impl BinaryExpr {
1019 pub fn lhs(&self) -> Option<SyntaxElement<RLanguage>> {
1022 self.parts().map(|(lhs, _, _)| lhs)
1023 }
1024
1025 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
1027 self.parts().map(|(_, op, _)| op)
1028 }
1029
1030 pub fn op_kind(&self) -> Option<SyntaxKind> {
1031 self.op().map(|op| op.kind())
1032 }
1033
1034 pub fn rhs(&self) -> Option<SyntaxElement<RLanguage>> {
1036 self.parts().map(|(_, _, rhs)| rhs)
1037 }
1038
1039 pub fn parts(
1041 &self,
1042 ) -> Option<(
1043 SyntaxElement<RLanguage>,
1044 SyntaxToken<RLanguage>,
1045 SyntaxElement<RLanguage>,
1046 )> {
1047 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1048 let op_idx = elements
1049 .iter()
1050 .position(|e| matches!(e, SyntaxElement::Token(t) if is_binary_operator(t.kind())))?;
1051 let op = elements[op_idx].as_token()?.clone();
1052 let lhs = elements[..op_idx]
1053 .iter()
1054 .rev()
1055 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
1056 .clone();
1057 let rhs = elements[op_idx + 1..]
1058 .iter()
1059 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
1060 .clone();
1061 Some((lhs, op, rhs))
1062 }
1063}
1064
1065impl UnaryExpr {
1066 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
1068 self.syntax().children_with_tokens().find_map(|e| match e {
1069 SyntaxElement::Token(t) if is_unary_operator(t.kind()) => Some(t),
1070 _ => None,
1071 })
1072 }
1073
1074 pub fn op_kind(&self) -> Option<SyntaxKind> {
1075 self.op().map(|op| op.kind())
1076 }
1077
1078 pub fn operand(&self) -> Option<SyntaxElement<RLanguage>> {
1080 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1081 let op_idx = elements
1082 .iter()
1083 .position(|e| matches!(e, SyntaxElement::Token(t) if is_unary_operator(t.kind())))?;
1084 elements[op_idx + 1..]
1085 .iter()
1086 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1087 .cloned()
1088 }
1089}
1090
1091impl ParenExpr {
1092 pub fn lparen(&self) -> Option<SyntaxToken<RLanguage>> {
1093 first_child_token(self.syntax(), SyntaxKind::LPAREN)
1094 }
1095
1096 pub fn rparen(&self) -> Option<SyntaxToken<RLanguage>> {
1097 first_child_token(self.syntax(), SyntaxKind::RPAREN)
1098 }
1099
1100 pub fn inner(&self) -> Option<SyntaxElement<RLanguage>> {
1102 self.syntax().children_with_tokens().find(|e| {
1103 !is_trivia(e.kind())
1104 && !matches!(
1105 e.kind(),
1106 SyntaxKind::COMMENT | SyntaxKind::LPAREN | SyntaxKind::RPAREN
1107 )
1108 })
1109 }
1110}
1111
1112impl BlockExpr {
1113 pub fn lbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1114 first_child_token(self.syntax(), SyntaxKind::LBRACE)
1115 }
1116
1117 pub fn rbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1118 first_child_token(self.syntax(), SyntaxKind::RBRACE)
1119 }
1120
1121 pub fn statements(&self) -> impl Iterator<Item = SyntaxElement<RLanguage>> + '_ {
1125 self.syntax().children_with_tokens().filter(|e| {
1126 !is_trivia(e.kind())
1127 && !matches!(
1128 e.kind(),
1129 SyntaxKind::COMMENT
1130 | SyntaxKind::LBRACE
1131 | SyntaxKind::RBRACE
1132 | SyntaxKind::SEMICOLON
1133 )
1134 })
1135 }
1136}
1137
1138impl Arg {
1139 pub fn eq_token(&self) -> Option<SyntaxToken<RLanguage>> {
1141 first_child_token(self.syntax(), SyntaxKind::ASSIGN_EQ)
1142 }
1143
1144 pub fn name_token(&self) -> Option<SyntaxToken<RLanguage>> {
1147 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1148 let eq = elements
1149 .iter()
1150 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)?;
1151 elements[..eq].iter().rev().find_map(|e| match e {
1152 SyntaxElement::Token(t)
1153 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
1154 {
1155 Some(t.clone())
1156 }
1157 _ => None,
1158 })
1159 }
1160
1161 pub fn name(&self) -> Option<SmolStr> {
1163 self.name_token().as_ref().map(token_name)
1164 }
1165
1166 pub fn is_named(&self) -> bool {
1167 self.name_token().is_some()
1168 }
1169
1170 pub fn value(&self) -> Option<SyntaxElement<RLanguage>> {
1173 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1174 let start = match elements
1175 .iter()
1176 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)
1177 {
1178 Some(eq) => eq + 1,
1179 None => 0,
1180 };
1181 elements[start..]
1182 .iter()
1183 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1184 .cloned()
1185 }
1186}
1187
1188impl RepeatExpr {
1189 pub fn repeat_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
1190 first_child_token(self.syntax(), SyntaxKind::REPEAT_KW)
1191 }
1192
1193 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
1195 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1196 let kw_idx = elements
1197 .iter()
1198 .position(|e| e.kind() == SyntaxKind::REPEAT_KW)?;
1199 elements[kw_idx + 1..]
1200 .iter()
1201 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1202 .cloned()
1203 }
1204}
1205
1206fn find_token_index(elements: &[SyntaxElement<RLanguage>], kind: SyntaxKind) -> Option<usize> {
1207 elements
1208 .iter()
1209 .position(|element| matches!(element, SyntaxElement::Token(token) if token.kind() == kind))
1210}
1211
1212fn find_token_after_index(
1213 elements: &[SyntaxElement<RLanguage>],
1214 start_idx: usize,
1215 kind: SyntaxKind,
1216) -> Option<usize> {
1217 elements
1218 .iter()
1219 .enumerate()
1220 .skip(start_idx + 1)
1221 .find_map(|(idx, element)| match element {
1222 SyntaxElement::Token(token) if token.kind() == kind => Some(idx),
1223 _ => None,
1224 })
1225}