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 params(&self) -> Vec<Param> {
329 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
330 let Some(lparen_idx) = self.lparen_index() else {
331 return Vec::new();
332 };
333 let Some(rparen_idx) = self.rparen_index() else {
334 return Vec::new();
335 };
336 let mut params = Vec::new();
337 let mut depth = 0usize;
338 let mut at_param_start = true;
339 let mut i = lparen_idx + 1;
340 while i < rparen_idx {
341 let element = &elements[i];
342 match element.kind() {
343 SyntaxKind::LPAREN
344 | SyntaxKind::LBRACK
345 | SyntaxKind::LBRACK2
346 | SyntaxKind::LBRACE => {
347 depth += 1;
348 at_param_start = false;
349 }
350 SyntaxKind::RPAREN
351 | SyntaxKind::RBRACK
352 | SyntaxKind::RBRACK2
353 | SyntaxKind::RBRACE => {
354 depth = depth.saturating_sub(1);
355 at_param_start = false;
356 }
357 SyntaxKind::COMMA if depth == 0 => {
358 at_param_start = true;
359 }
360 SyntaxKind::IDENT if depth == 0 && at_param_start => {
361 if let SyntaxElement::Token(token) = element {
362 params.push(Param {
363 name: SmolStr::new(token.text()),
364 name_token: token.clone(),
365 });
366 }
367 at_param_start = false;
368 }
369 SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE | SyntaxKind::COMMENT => {}
370 _ => {
371 at_param_start = false;
372 }
373 }
374 i += 1;
375 }
376 params
377 }
378
379 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
384 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
385 let rparen_idx = self.rparen_index()?;
386 elements[rparen_idx + 1..]
387 .iter()
388 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
389 .cloned()
390 }
391}
392
393#[derive(Debug, Clone)]
394pub struct Param {
395 pub name: SmolStr,
396 pub name_token: SyntaxToken<RLanguage>,
397}
398
399fn is_assignment_op(kind: SyntaxKind) -> bool {
400 matches!(
401 kind,
402 SyntaxKind::ASSIGN_LEFT
403 | SyntaxKind::ASSIGN_RIGHT
404 | SyntaxKind::SUPER_ASSIGN
405 | SyntaxKind::SUPER_ASSIGN_RIGHT
406 | SyntaxKind::ASSIGN_EQ
407 | SyntaxKind::WALRUS
408 )
409}
410
411fn is_right_assign(kind: SyntaxKind) -> bool {
412 matches!(
413 kind,
414 SyntaxKind::ASSIGN_RIGHT | SyntaxKind::SUPER_ASSIGN_RIGHT
415 )
416}
417
418fn assignment_op_index(elements: &[SyntaxElement<RLanguage>]) -> Option<usize> {
419 elements
420 .iter()
421 .position(|e| matches!(e, SyntaxElement::Token(t) if is_assignment_op(t.kind())))
422}
423
424fn element_kind(element: &SyntaxElement<RLanguage>) -> Option<SyntaxKind> {
425 Some(element.kind())
426}
427
428fn namespace_member_token(node: &SyntaxNode) -> Option<SyntaxToken<RLanguage>> {
432 let mut seen_ns_op = false;
433 for element in node.children_with_tokens() {
434 match element {
435 SyntaxElement::Token(t)
436 if matches!(t.kind(), SyntaxKind::COLON2 | SyntaxKind::COLON3) =>
437 {
438 seen_ns_op = true;
439 }
440 SyntaxElement::Token(t) if seen_ns_op && t.kind() == SyntaxKind::IDENT => {
441 return Some(t);
442 }
443 _ => {}
444 }
445 }
446 None
447}
448
449impl CallExpr {
450 pub fn arg_list(&self) -> Option<ArgList> {
451 support::child(self.syntax())
452 }
453
454 pub fn callee_token(&self) -> Option<SyntaxToken<RLanguage>> {
460 for element in self.syntax().children_with_tokens() {
461 match element {
462 SyntaxElement::Token(token)
463 if is_trivia(token.kind()) || token.kind() == SyntaxKind::COMMENT =>
464 {
465 continue;
466 }
467 SyntaxElement::Token(token)
468 if matches!(token.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
469 {
470 return Some(token);
471 }
472 SyntaxElement::Node(node) if node.kind() == SyntaxKind::BINARY_EXPR => {
479 return namespace_member_token(&node);
480 }
481 _ => return None,
482 }
483 }
484 None
485 }
486
487 pub fn callee_name(&self) -> Option<SmolStr> {
490 self.callee_token().as_ref().map(token_name)
491 }
492
493 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
497 last_element_before(self.syntax(), SyntaxKind::LPAREN)
498 }
499}
500
501impl SubsetExpr {
502 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
504 last_element_before(self.syntax(), SyntaxKind::LBRACK)
505 }
506
507 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
508 first_child_token(self.syntax(), SyntaxKind::LBRACK)
509 }
510
511 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
512 first_child_token(self.syntax(), SyntaxKind::RBRACK)
513 }
514
515 pub fn arg_list(&self) -> Option<ArgList> {
516 support::child(self.syntax())
517 }
518
519 pub fn args(&self) -> impl Iterator<Item = Arg> {
520 self.arg_list()
521 .map(|list| list.args().collect::<Vec<_>>())
522 .unwrap_or_default()
523 .into_iter()
524 }
525}
526
527impl Subset2Expr {
528 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
530 last_element_before(self.syntax(), SyntaxKind::LBRACK2)
531 }
532
533 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
534 first_child_token(self.syntax(), SyntaxKind::LBRACK2)
535 }
536
537 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
538 first_child_token(self.syntax(), SyntaxKind::RBRACK2)
539 }
540
541 pub fn arg_list(&self) -> Option<ArgList> {
542 support::child(self.syntax())
543 }
544
545 pub fn args(&self) -> impl Iterator<Item = Arg> {
546 self.arg_list()
547 .map(|list| list.args().collect::<Vec<_>>())
548 .unwrap_or_default()
549 .into_iter()
550 }
551}
552
553fn last_element_before(
556 node: &SyntaxNode,
557 boundary: SyntaxKind,
558) -> Option<SyntaxElement<RLanguage>> {
559 let elements: Vec<_> = node.children_with_tokens().collect();
560 let idx = elements.iter().position(|e| e.kind() == boundary)?;
561 elements[..idx]
562 .iter()
563 .rev()
564 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
565 .cloned()
566}
567
568#[derive(Debug, Clone, PartialEq, Eq)]
571pub struct NamespaceAccess {
572 pub package: SmolStr,
573 pub package_token: SyntaxToken<RLanguage>,
574 pub internal: bool,
576 pub name: SmolStr,
577 pub name_token: SyntaxToken<RLanguage>,
578}
579
580impl BinaryExpr {
581 pub fn namespace_access(&self) -> Option<NamespaceAccess> {
586 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
587 let (op_idx, internal) = elements
588 .iter()
589 .enumerate()
590 .find_map(|(i, e)| match e.kind() {
591 SyntaxKind::COLON2 => Some((i, false)),
592 SyntaxKind::COLON3 => Some((i, true)),
593 _ => None,
594 })?;
595 let package_token = elements[..op_idx].iter().rev().find_map(|e| match e {
597 SyntaxElement::Token(t)
598 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
599 {
600 Some(t.clone())
601 }
602 _ => None,
603 })?;
604 let rhs = elements[op_idx + 1..]
607 .iter()
608 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?;
609 let name_token = match rhs {
610 SyntaxElement::Token(t)
611 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
612 {
613 t.clone()
614 }
615 SyntaxElement::Node(n) if n.kind() == SyntaxKind::CALL_EXPR => {
616 CallExpr::cast(n.clone())?.callee_token()?
617 }
618 _ => return None,
619 };
620 Some(NamespaceAccess {
621 package: token_name(&package_token),
622 package_token,
623 internal,
624 name: token_name(&name_token),
625 name_token,
626 })
627 }
628}
629
630impl ArgList {
631 pub fn args(&self) -> impl Iterator<Item = Arg> {
632 support::children(self.syntax())
633 }
634}
635
636impl IfExpr {
637 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
638 self.syntax().children_with_tokens().collect()
639 }
640
641 pub fn if_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
642 self.elements()
643 .into_iter()
644 .find_map(|element| match element {
645 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IF_KW => Some(token),
646 _ => None,
647 })
648 }
649
650 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
651 let elements = self.elements();
652 let lparen_idx = self.lparen_index()?;
653 let rparen_idx = self.rparen_index()?;
654 Some(elements[lparen_idx + 1..rparen_idx].to_vec())
655 }
656
657 pub fn then_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
658 let elements = self.elements();
659 let rparen_idx = self.rparen_index()?;
660 let else_idx = find_token_after_index(&elements, rparen_idx, SyntaxKind::ELSE_KW);
661 let then_end = else_idx.unwrap_or(elements.len());
662 Some(elements[rparen_idx + 1..then_end].to_vec())
663 }
664
665 pub fn else_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
666 self.elements()
667 .into_iter()
668 .find_map(|element| match element {
669 SyntaxElement::Token(token) if token.kind() == SyntaxKind::ELSE_KW => Some(token),
670 _ => None,
671 })
672 }
673
674 pub fn else_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
675 let elements = self.elements();
676 let else_idx = find_token_index(&elements, SyntaxKind::ELSE_KW)?;
677 Some(elements[else_idx + 1..].to_vec())
678 }
679
680 pub fn lparen_index(&self) -> Option<usize> {
681 find_token_index(&self.elements(), SyntaxKind::LPAREN)
682 }
683
684 pub fn rparen_index(&self) -> Option<usize> {
685 let elements = self.elements();
686 let lparen_idx = self.lparen_index()?;
687 find_token_after_index(&elements, lparen_idx, SyntaxKind::RPAREN)
688 }
689}
690
691impl ForExpr {
692 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
693 self.syntax().children_with_tokens().collect()
694 }
695
696 pub fn for_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
697 self.elements()
698 .into_iter()
699 .find_map(|element| match element {
700 SyntaxElement::Token(token) if token.kind() == SyntaxKind::FOR_KW => Some(token),
701 _ => None,
702 })
703 }
704
705 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
706 let elements = self.elements();
707 let lparen_idx = self.lparen_index()?;
708
709 let mut depth = 0usize;
710 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
711 |(idx, element)| match element {
712 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
713 depth += 1;
714 None
715 }
716 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
717 depth = depth.saturating_sub(1);
718 if depth == 0 { Some(idx) } else { None }
719 }
720 _ => None,
721 },
722 )?;
723
724 Some((lparen_idx, rparen_idx))
725 }
726
727 pub fn lparen_index(&self) -> Option<usize> {
728 let elements = self.elements();
729 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
730 find_token_after_index(&elements, for_idx, SyntaxKind::LPAREN)
731 }
732
733 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
734 let elements = self.elements();
735 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
736 let (_, rparen_idx) = self.clause_bounds()?;
737 Some(
738 elements[for_idx + 1..rparen_idx]
739 .iter()
740 .filter_map(|element| match element {
741 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
742 Some(token.clone())
743 }
744 _ => None,
745 })
746 .collect(),
747 )
748 }
749
750 pub fn clause_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
751 let elements = self.elements();
752 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
753 Some(
754 elements[lparen_idx + 1..rparen_idx]
755 .iter()
756 .filter(|element| {
757 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
758 })
759 .cloned()
760 .collect(),
761 )
762 }
763
764 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
765 let elements = self.elements();
766 let (_, rparen_idx) = self.clause_bounds()?;
767 let mut comments = Vec::new();
768 for element in &elements[rparen_idx + 1..] {
769 if is_trivia(element.kind()) {
770 continue;
771 }
772 if let SyntaxElement::Token(token) = element
773 && token.kind() == SyntaxKind::COMMENT
774 {
775 comments.push(token.clone());
776 continue;
777 }
778 break;
779 }
780 Some(comments)
781 }
782
783 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
784 let elements = self.elements();
785 let (_, rparen_idx) = self.clause_bounds()?;
786 for element in &elements[rparen_idx + 1..] {
787 if is_trivia(element.kind()) {
788 continue;
789 }
790 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
791 {
792 continue;
793 }
794 return Some(element.clone());
795 }
796 None
797 }
798
799 pub fn parts(&self) -> Option<ForExprParts> {
800 self.for_keyword()?;
801 self.lparen_index()?;
802 self.clause_bounds()?;
803
804 let clause_elements = self.clause_elements()?;
805 let in_idx = clause_elements.iter().position(
806 |el| matches!(el, SyntaxElement::Token(tok) if tok.kind() == SyntaxKind::IN_KW),
807 )?;
808
809 Some(ForExprParts {
810 leading_comments: self.leading_comments()?,
811 variable_elements: clause_elements[..in_idx].to_vec(),
812 sequence_elements: clause_elements[in_idx + 1..].to_vec(),
813 post_clause_comments: self.post_clause_comments()?,
814 body: self.body_element(),
815 })
816 }
817}
818
819impl WhileExpr {
820 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
821 self.syntax().children_with_tokens().collect()
822 }
823
824 pub fn while_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
825 self.elements()
826 .into_iter()
827 .find_map(|element| match element {
828 SyntaxElement::Token(token) if token.kind() == SyntaxKind::WHILE_KW => Some(token),
829 _ => None,
830 })
831 }
832
833 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
834 let elements = self.elements();
835 let lparen_idx = self.lparen_index()?;
836
837 let mut depth = 0usize;
838 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
839 |(idx, element)| match element {
840 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
841 depth += 1;
842 None
843 }
844 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
845 depth = depth.saturating_sub(1);
846 if depth == 0 { Some(idx) } else { None }
847 }
848 _ => None,
849 },
850 )?;
851
852 Some((lparen_idx, rparen_idx))
853 }
854
855 pub fn lparen_index(&self) -> Option<usize> {
856 let elements = self.elements();
857 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
858 find_token_after_index(&elements, while_idx, SyntaxKind::LPAREN)
859 }
860
861 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
862 let elements = self.elements();
863 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
864 let (_, rparen_idx) = self.clause_bounds()?;
865 Some(
866 elements[while_idx + 1..rparen_idx]
867 .iter()
868 .filter_map(|element| match element {
869 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
870 Some(token.clone())
871 }
872 _ => None,
873 })
874 .collect(),
875 )
876 }
877
878 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
879 let elements = self.elements();
880 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
881 Some(
882 elements[lparen_idx + 1..rparen_idx]
883 .iter()
884 .filter(|element| {
885 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
886 })
887 .cloned()
888 .collect(),
889 )
890 }
891
892 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
893 let elements = self.elements();
894 let (_, rparen_idx) = self.clause_bounds()?;
895 let mut comments = Vec::new();
896 for element in &elements[rparen_idx + 1..] {
897 if is_trivia(element.kind()) {
898 continue;
899 }
900 if let SyntaxElement::Token(token) = element
901 && token.kind() == SyntaxKind::COMMENT
902 {
903 comments.push(token.clone());
904 continue;
905 }
906 break;
907 }
908 Some(comments)
909 }
910
911 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
912 let elements = self.elements();
913 let (_, rparen_idx) = self.clause_bounds()?;
914 for element in &elements[rparen_idx + 1..] {
915 if is_trivia(element.kind()) {
916 continue;
917 }
918 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
919 {
920 continue;
921 }
922 return Some(element.clone());
923 }
924 None
925 }
926
927 pub fn parts(&self) -> Option<WhileExprParts> {
928 self.while_keyword()?;
929 self.lparen_index()?;
930 self.clause_bounds()?;
931
932 Some(WhileExprParts {
933 leading_comments: self.leading_comments()?,
934 condition_elements: self.condition_elements()?,
935 post_clause_comments: self.post_clause_comments()?,
936 body: self.body_element(),
937 })
938 }
939}
940
941impl BinaryExpr {
942 pub fn lhs(&self) -> Option<SyntaxElement<RLanguage>> {
945 self.parts().map(|(lhs, _, _)| lhs)
946 }
947
948 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
950 self.parts().map(|(_, op, _)| op)
951 }
952
953 pub fn op_kind(&self) -> Option<SyntaxKind> {
954 self.op().map(|op| op.kind())
955 }
956
957 pub fn rhs(&self) -> Option<SyntaxElement<RLanguage>> {
959 self.parts().map(|(_, _, rhs)| rhs)
960 }
961
962 pub fn parts(
964 &self,
965 ) -> Option<(
966 SyntaxElement<RLanguage>,
967 SyntaxToken<RLanguage>,
968 SyntaxElement<RLanguage>,
969 )> {
970 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
971 let op_idx = elements
972 .iter()
973 .position(|e| matches!(e, SyntaxElement::Token(t) if is_binary_operator(t.kind())))?;
974 let op = elements[op_idx].as_token()?.clone();
975 let lhs = elements[..op_idx]
976 .iter()
977 .rev()
978 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
979 .clone();
980 let rhs = elements[op_idx + 1..]
981 .iter()
982 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
983 .clone();
984 Some((lhs, op, rhs))
985 }
986}
987
988impl UnaryExpr {
989 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
991 self.syntax().children_with_tokens().find_map(|e| match e {
992 SyntaxElement::Token(t) if is_unary_operator(t.kind()) => Some(t),
993 _ => None,
994 })
995 }
996
997 pub fn op_kind(&self) -> Option<SyntaxKind> {
998 self.op().map(|op| op.kind())
999 }
1000
1001 pub fn operand(&self) -> Option<SyntaxElement<RLanguage>> {
1003 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1004 let op_idx = elements
1005 .iter()
1006 .position(|e| matches!(e, SyntaxElement::Token(t) if is_unary_operator(t.kind())))?;
1007 elements[op_idx + 1..]
1008 .iter()
1009 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1010 .cloned()
1011 }
1012}
1013
1014impl ParenExpr {
1015 pub fn lparen(&self) -> Option<SyntaxToken<RLanguage>> {
1016 first_child_token(self.syntax(), SyntaxKind::LPAREN)
1017 }
1018
1019 pub fn rparen(&self) -> Option<SyntaxToken<RLanguage>> {
1020 first_child_token(self.syntax(), SyntaxKind::RPAREN)
1021 }
1022
1023 pub fn inner(&self) -> Option<SyntaxElement<RLanguage>> {
1025 self.syntax().children_with_tokens().find(|e| {
1026 !is_trivia(e.kind())
1027 && !matches!(
1028 e.kind(),
1029 SyntaxKind::COMMENT | SyntaxKind::LPAREN | SyntaxKind::RPAREN
1030 )
1031 })
1032 }
1033}
1034
1035impl BlockExpr {
1036 pub fn lbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1037 first_child_token(self.syntax(), SyntaxKind::LBRACE)
1038 }
1039
1040 pub fn rbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1041 first_child_token(self.syntax(), SyntaxKind::RBRACE)
1042 }
1043
1044 pub fn statements(&self) -> impl Iterator<Item = SyntaxElement<RLanguage>> + '_ {
1048 self.syntax().children_with_tokens().filter(|e| {
1049 !is_trivia(e.kind())
1050 && !matches!(
1051 e.kind(),
1052 SyntaxKind::COMMENT
1053 | SyntaxKind::LBRACE
1054 | SyntaxKind::RBRACE
1055 | SyntaxKind::SEMICOLON
1056 )
1057 })
1058 }
1059}
1060
1061impl Arg {
1062 pub fn eq_token(&self) -> Option<SyntaxToken<RLanguage>> {
1064 first_child_token(self.syntax(), SyntaxKind::ASSIGN_EQ)
1065 }
1066
1067 pub fn name_token(&self) -> Option<SyntaxToken<RLanguage>> {
1070 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1071 let eq = elements
1072 .iter()
1073 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)?;
1074 elements[..eq].iter().rev().find_map(|e| match e {
1075 SyntaxElement::Token(t)
1076 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
1077 {
1078 Some(t.clone())
1079 }
1080 _ => None,
1081 })
1082 }
1083
1084 pub fn name(&self) -> Option<SmolStr> {
1086 self.name_token().as_ref().map(token_name)
1087 }
1088
1089 pub fn is_named(&self) -> bool {
1090 self.name_token().is_some()
1091 }
1092
1093 pub fn value(&self) -> Option<SyntaxElement<RLanguage>> {
1096 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1097 let start = match elements
1098 .iter()
1099 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)
1100 {
1101 Some(eq) => eq + 1,
1102 None => 0,
1103 };
1104 elements[start..]
1105 .iter()
1106 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1107 .cloned()
1108 }
1109}
1110
1111impl RepeatExpr {
1112 pub fn repeat_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
1113 first_child_token(self.syntax(), SyntaxKind::REPEAT_KW)
1114 }
1115
1116 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
1118 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1119 let kw_idx = elements
1120 .iter()
1121 .position(|e| e.kind() == SyntaxKind::REPEAT_KW)?;
1122 elements[kw_idx + 1..]
1123 .iter()
1124 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1125 .cloned()
1126 }
1127}
1128
1129fn find_token_index(elements: &[SyntaxElement<RLanguage>], kind: SyntaxKind) -> Option<usize> {
1130 elements
1131 .iter()
1132 .position(|element| matches!(element, SyntaxElement::Token(token) if token.kind() == kind))
1133}
1134
1135fn find_token_after_index(
1136 elements: &[SyntaxElement<RLanguage>],
1137 start_idx: usize,
1138 kind: SyntaxKind,
1139) -> Option<usize> {
1140 elements
1141 .iter()
1142 .enumerate()
1143 .skip(start_idx + 1)
1144 .find_map(|(idx, element)| match element {
1145 SyntaxElement::Token(token) if token.kind() == kind => Some(idx),
1146 _ => None,
1147 })
1148}