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