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 self.operand(false)
241 }
242
243 pub fn value_element(&self) -> Option<SyntaxElement<RLanguage>> {
245 self.operand(true)
246 }
247
248 fn operand(&self, value_side: bool) -> Option<SyntaxElement<RLanguage>> {
249 let is_operand =
250 |e: &SyntaxElement<RLanguage>| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT;
251 let mut elements = self.syntax().children_with_tokens();
252 let mut before = None;
253 while let Some(element) = elements.next() {
254 if matches!(&element, SyntaxElement::Token(t) if is_assignment_op(t.kind())) {
255 return if is_right_assign(element.kind()) == value_side {
256 before
257 } else {
258 elements.find(is_operand)
259 };
260 }
261 if before.is_none() && is_operand(&element) {
262 before = Some(element);
263 }
264 }
265 None
266 }
267
268 pub fn target_name(&self) -> Option<SmolStr> {
272 match self.target_element()? {
273 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IDENT => {
274 Some(SmolStr::new(token.text()))
275 }
276 SyntaxElement::Token(token) if token.kind() == SyntaxKind::STRING => {
277 StringLit::cast(token).and_then(|s| s.unquote().map(SmolStr::new))
278 }
279 _ => None,
280 }
281 }
282
283 pub fn target_name_token(&self) -> Option<SyntaxToken<RLanguage>> {
285 match self.target_element()? {
286 SyntaxElement::Token(token)
287 if token.kind() == SyntaxKind::IDENT || token.kind() == SyntaxKind::STRING =>
288 {
289 Some(token)
290 }
291 _ => None,
292 }
293 }
294}
295
296impl FunctionExpr {
297 pub fn lparen_index(&self) -> Option<usize> {
298 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
299 elements.iter().position(|e| e.kind() == SyntaxKind::LPAREN)
300 }
301
302 pub fn rparen_index(&self) -> Option<usize> {
303 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
304 let lparen_idx = self.lparen_index()?;
305 let mut depth = 0usize;
306 elements
307 .iter()
308 .enumerate()
309 .skip(lparen_idx)
310 .find_map(|(i, el)| match el.kind() {
311 SyntaxKind::LPAREN => {
312 depth += 1;
313 None
314 }
315 SyntaxKind::RPAREN => {
316 depth = depth.saturating_sub(1);
317 if depth == 0 { Some(i) } else { None }
318 }
319 _ => None,
320 })
321 }
322
323 pub fn formals(&self) -> Vec<Formal> {
326 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
327 let Some(lparen_idx) = self.lparen_index() else {
328 return Vec::new();
329 };
330 let Some(rparen_idx) = self.rparen_index() else {
331 return Vec::new();
332 };
333
334 split_function_formals(&elements[lparen_idx + 1..rparen_idx])
335 .into_iter()
336 .filter_map(formal_from_elements)
337 .collect()
338 }
339
340 pub fn params(&self) -> Vec<Param> {
344 self.formals()
345 .into_iter()
346 .map(|formal| Param {
347 name: formal.name,
348 name_token: formal.name_token,
349 })
350 .collect()
351 }
352
353 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
358 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
359 let rparen_idx = self.rparen_index()?;
360 elements[rparen_idx + 1..]
361 .iter()
362 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
363 .cloned()
364 }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
370pub struct Formal {
371 name: SmolStr,
372 name_token: SyntaxToken<RLanguage>,
373 range: TextRange,
374 default: Option<SyntaxElement<RLanguage>>,
375}
376
377impl Formal {
378 pub fn name(&self) -> SmolStr {
381 self.name.clone()
382 }
383
384 pub fn name_token(&self) -> SyntaxToken<RLanguage> {
386 self.name_token.clone()
387 }
388
389 pub fn text_range(&self) -> TextRange {
391 self.range
392 }
393
394 pub fn default(&self) -> Option<SyntaxElement<RLanguage>> {
396 self.default.clone()
397 }
398
399 pub fn default_range(&self) -> Option<TextRange> {
401 self.default.as_ref().map(SyntaxElement::text_range)
402 }
403}
404
405fn split_function_formals(
406 elements: &[SyntaxElement<RLanguage>],
407) -> Vec<&[SyntaxElement<RLanguage>]> {
408 let mut formals = Vec::new();
409 let mut start = 0usize;
410 let mut depth = 0usize;
411
412 for (index, element) in elements.iter().enumerate() {
413 match element.kind() {
414 SyntaxKind::LPAREN | SyntaxKind::LBRACK | SyntaxKind::LBRACK2 | SyntaxKind::LBRACE => {
415 depth += 1
416 }
417 SyntaxKind::RPAREN | SyntaxKind::RBRACK | SyntaxKind::RBRACK2 | SyntaxKind::RBRACE => {
418 depth = depth.saturating_sub(1)
419 }
420 SyntaxKind::COMMA if depth == 0 => {
421 formals.push(&elements[start..index]);
422 start = index + 1;
423 }
424 _ => {}
425 }
426 }
427 formals.push(&elements[start..]);
428 formals
429}
430
431fn formal_from_elements(elements: &[SyntaxElement<RLanguage>]) -> Option<Formal> {
432 let name_index = elements
433 .iter()
434 .position(|element| !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT)?;
435 let SyntaxElement::Token(name_token) = &elements[name_index] else {
436 return None;
437 };
438 if name_token.kind() != SyntaxKind::IDENT {
439 return None;
440 }
441
442 let eq_index = elements[name_index + 1..]
443 .iter()
444 .position(|element| element.kind() == SyntaxKind::ASSIGN_EQ)
445 .map(|index| name_index + 1 + index);
446 let default = eq_index.and_then(|index| {
447 elements[index + 1..]
448 .iter()
449 .find(|element| !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT)
450 .filter(|element| crate::ast::Expr::cast((*element).clone()).is_some())
451 .cloned()
452 });
453 let end = default
454 .as_ref()
455 .map(SyntaxElement::text_range)
456 .map(TextRange::end)
457 .or_else(|| eq_index.map(|index| elements[index].text_range().end()))
458 .unwrap_or_else(|| name_token.text_range().end());
459
460 Some(Formal {
461 name: SmolStr::new(name_token.text()),
462 name_token: name_token.clone(),
463 range: TextRange::new(name_token.text_range().start(), end),
464 default,
465 })
466}
467
468#[derive(Debug, Clone)]
469pub struct Param {
470 pub name: SmolStr,
471 pub name_token: SyntaxToken<RLanguage>,
472}
473
474fn is_assignment_op(kind: SyntaxKind) -> bool {
475 matches!(
476 kind,
477 SyntaxKind::ASSIGN_LEFT
478 | SyntaxKind::ASSIGN_RIGHT
479 | SyntaxKind::SUPER_ASSIGN
480 | SyntaxKind::SUPER_ASSIGN_RIGHT
481 | SyntaxKind::ASSIGN_EQ
482 | SyntaxKind::WALRUS
483 )
484}
485
486fn is_right_assign(kind: SyntaxKind) -> bool {
487 matches!(
488 kind,
489 SyntaxKind::ASSIGN_RIGHT | SyntaxKind::SUPER_ASSIGN_RIGHT
490 )
491}
492
493fn namespace_member_token(node: &SyntaxNode) -> Option<SyntaxToken<RLanguage>> {
497 let mut seen_ns_op = false;
498 for element in node.children_with_tokens() {
499 match element {
500 SyntaxElement::Token(t)
501 if matches!(t.kind(), SyntaxKind::COLON2 | SyntaxKind::COLON3) =>
502 {
503 seen_ns_op = true;
504 }
505 SyntaxElement::Token(t) if seen_ns_op && t.kind() == SyntaxKind::IDENT => {
506 return Some(t);
507 }
508 _ => {}
509 }
510 }
511 None
512}
513
514impl CallExpr {
515 pub fn arg_list(&self) -> Option<ArgList> {
516 support::child(self.syntax())
517 }
518
519 pub fn callee_token(&self) -> Option<SyntaxToken<RLanguage>> {
525 for element in self.syntax().children_with_tokens() {
526 match element {
527 SyntaxElement::Token(token)
528 if is_trivia(token.kind()) || token.kind() == SyntaxKind::COMMENT =>
529 {
530 continue;
531 }
532 SyntaxElement::Token(token)
533 if matches!(token.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
534 {
535 return Some(token);
536 }
537 SyntaxElement::Node(node) if node.kind() == SyntaxKind::BINARY_EXPR => {
544 return namespace_member_token(&node);
545 }
546 _ => return None,
547 }
548 }
549 None
550 }
551
552 pub fn callee_name(&self) -> Option<SmolStr> {
555 self.callee_token().as_ref().map(token_name)
556 }
557
558 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
562 last_element_before(self.syntax(), SyntaxKind::LPAREN)
563 }
564}
565
566impl SubsetExpr {
567 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
569 last_element_before(self.syntax(), SyntaxKind::LBRACK)
570 }
571
572 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
573 first_child_token(self.syntax(), SyntaxKind::LBRACK)
574 }
575
576 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
577 first_child_token(self.syntax(), SyntaxKind::RBRACK)
578 }
579
580 pub fn arg_list(&self) -> Option<ArgList> {
581 support::child(self.syntax())
582 }
583
584 pub fn args(&self) -> impl Iterator<Item = Arg> {
585 self.arg_list()
586 .map(|list| list.args().collect::<Vec<_>>())
587 .unwrap_or_default()
588 .into_iter()
589 }
590}
591
592impl Subset2Expr {
593 pub fn base(&self) -> Option<SyntaxElement<RLanguage>> {
595 last_element_before(self.syntax(), SyntaxKind::LBRACK2)
596 }
597
598 pub fn open_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
599 first_child_token(self.syntax(), SyntaxKind::LBRACK2)
600 }
601
602 pub fn close_bracket(&self) -> Option<SyntaxToken<RLanguage>> {
603 first_child_token(self.syntax(), SyntaxKind::RBRACK2)
604 }
605
606 pub fn arg_list(&self) -> Option<ArgList> {
607 support::child(self.syntax())
608 }
609
610 pub fn args(&self) -> impl Iterator<Item = Arg> {
611 self.arg_list()
612 .map(|list| list.args().collect::<Vec<_>>())
613 .unwrap_or_default()
614 .into_iter()
615 }
616}
617
618fn last_element_before(
621 node: &SyntaxNode,
622 boundary: SyntaxKind,
623) -> Option<SyntaxElement<RLanguage>> {
624 let elements: Vec<_> = node.children_with_tokens().collect();
625 let idx = elements.iter().position(|e| e.kind() == boundary)?;
626 elements[..idx]
627 .iter()
628 .rev()
629 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
630 .cloned()
631}
632
633#[derive(Debug, Clone, PartialEq, Eq)]
636pub struct NamespaceAccess {
637 pub package: SmolStr,
638 pub package_token: SyntaxToken<RLanguage>,
639 pub internal: bool,
641 pub name: SmolStr,
642 pub name_token: SyntaxToken<RLanguage>,
643}
644
645impl BinaryExpr {
646 pub fn namespace_access(&self) -> Option<NamespaceAccess> {
651 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
652 let (op_idx, internal) = elements
653 .iter()
654 .enumerate()
655 .find_map(|(i, e)| match e.kind() {
656 SyntaxKind::COLON2 => Some((i, false)),
657 SyntaxKind::COLON3 => Some((i, true)),
658 _ => None,
659 })?;
660 let package_token = elements[..op_idx].iter().rev().find_map(|e| match e {
662 SyntaxElement::Token(t)
663 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
664 {
665 Some(t.clone())
666 }
667 _ => None,
668 })?;
669 let rhs = elements[op_idx + 1..]
672 .iter()
673 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?;
674 let name_token = match rhs {
675 SyntaxElement::Token(t)
676 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
677 {
678 t.clone()
679 }
680 SyntaxElement::Node(n) if n.kind() == SyntaxKind::CALL_EXPR => {
681 CallExpr::cast(n.clone())?.callee_token()?
682 }
683 _ => return None,
684 };
685 Some(NamespaceAccess {
686 package: token_name(&package_token),
687 package_token,
688 internal,
689 name: token_name(&name_token),
690 name_token,
691 })
692 }
693}
694
695impl ArgList {
696 pub fn args(&self) -> impl Iterator<Item = Arg> {
697 support::children(self.syntax())
698 }
699}
700
701impl IfExpr {
702 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
703 self.syntax().children_with_tokens().collect()
704 }
705
706 pub fn if_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
707 self.elements()
708 .into_iter()
709 .find_map(|element| match element {
710 SyntaxElement::Token(token) if token.kind() == SyntaxKind::IF_KW => Some(token),
711 _ => None,
712 })
713 }
714
715 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
716 let elements = self.elements();
717 let lparen_idx = self.lparen_index()?;
718 let rparen_idx = self.rparen_index()?;
719 Some(elements[lparen_idx + 1..rparen_idx].to_vec())
720 }
721
722 pub fn then_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
723 let elements = self.elements();
724 let rparen_idx = self.rparen_index()?;
725 let else_idx = find_token_after_index(&elements, rparen_idx, SyntaxKind::ELSE_KW);
726 let then_end = else_idx.unwrap_or(elements.len());
727 Some(elements[rparen_idx + 1..then_end].to_vec())
728 }
729
730 pub fn else_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
731 self.elements()
732 .into_iter()
733 .find_map(|element| match element {
734 SyntaxElement::Token(token) if token.kind() == SyntaxKind::ELSE_KW => Some(token),
735 _ => None,
736 })
737 }
738
739 pub fn else_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
740 let elements = self.elements();
741 let else_idx = find_token_index(&elements, SyntaxKind::ELSE_KW)?;
742 Some(elements[else_idx + 1..].to_vec())
743 }
744
745 pub fn lparen_index(&self) -> Option<usize> {
746 find_token_index(&self.elements(), SyntaxKind::LPAREN)
747 }
748
749 pub fn rparen_index(&self) -> Option<usize> {
750 let elements = self.elements();
751 let lparen_idx = self.lparen_index()?;
752 find_token_after_index(&elements, lparen_idx, SyntaxKind::RPAREN)
753 }
754}
755
756impl ForExpr {
757 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
758 self.syntax().children_with_tokens().collect()
759 }
760
761 pub fn for_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
762 self.elements()
763 .into_iter()
764 .find_map(|element| match element {
765 SyntaxElement::Token(token) if token.kind() == SyntaxKind::FOR_KW => Some(token),
766 _ => None,
767 })
768 }
769
770 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
771 let elements = self.elements();
772 let lparen_idx = self.lparen_index()?;
773
774 let mut depth = 0usize;
775 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
776 |(idx, element)| match element {
777 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
778 depth += 1;
779 None
780 }
781 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
782 depth = depth.saturating_sub(1);
783 if depth == 0 { Some(idx) } else { None }
784 }
785 _ => None,
786 },
787 )?;
788
789 Some((lparen_idx, rparen_idx))
790 }
791
792 pub fn lparen_index(&self) -> Option<usize> {
793 let elements = self.elements();
794 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
795 find_token_after_index(&elements, for_idx, SyntaxKind::LPAREN)
796 }
797
798 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
799 let elements = self.elements();
800 let for_idx = find_token_index(&elements, SyntaxKind::FOR_KW)?;
801 let (_, rparen_idx) = self.clause_bounds()?;
802 Some(
803 elements[for_idx + 1..rparen_idx]
804 .iter()
805 .filter_map(|element| match element {
806 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
807 Some(token.clone())
808 }
809 _ => None,
810 })
811 .collect(),
812 )
813 }
814
815 pub fn clause_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
816 let elements = self.elements();
817 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
818 Some(
819 elements[lparen_idx + 1..rparen_idx]
820 .iter()
821 .filter(|element| {
822 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
823 })
824 .cloned()
825 .collect(),
826 )
827 }
828
829 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
830 let elements = self.elements();
831 let (_, rparen_idx) = self.clause_bounds()?;
832 let mut comments = Vec::new();
833 for element in &elements[rparen_idx + 1..] {
834 if is_trivia(element.kind()) {
835 continue;
836 }
837 if let SyntaxElement::Token(token) = element
838 && token.kind() == SyntaxKind::COMMENT
839 {
840 comments.push(token.clone());
841 continue;
842 }
843 break;
844 }
845 Some(comments)
846 }
847
848 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
849 let elements = self.elements();
850 let (_, rparen_idx) = self.clause_bounds()?;
851 for element in &elements[rparen_idx + 1..] {
852 if is_trivia(element.kind()) {
853 continue;
854 }
855 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
856 {
857 continue;
858 }
859 return Some(element.clone());
860 }
861 None
862 }
863
864 pub fn parts(&self) -> Option<ForExprParts> {
865 self.for_keyword()?;
866 self.lparen_index()?;
867 self.clause_bounds()?;
868
869 let clause_elements = self.clause_elements()?;
870 let in_idx = clause_elements.iter().position(
871 |el| matches!(el, SyntaxElement::Token(tok) if tok.kind() == SyntaxKind::IN_KW),
872 )?;
873
874 Some(ForExprParts {
875 leading_comments: self.leading_comments()?,
876 variable_elements: clause_elements[..in_idx].to_vec(),
877 sequence_elements: clause_elements[in_idx + 1..].to_vec(),
878 post_clause_comments: self.post_clause_comments()?,
879 body: self.body_element(),
880 })
881 }
882}
883
884impl WhileExpr {
885 pub fn elements(&self) -> Vec<SyntaxElement<RLanguage>> {
886 self.syntax().children_with_tokens().collect()
887 }
888
889 pub fn while_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
890 self.elements()
891 .into_iter()
892 .find_map(|element| match element {
893 SyntaxElement::Token(token) if token.kind() == SyntaxKind::WHILE_KW => Some(token),
894 _ => None,
895 })
896 }
897
898 pub fn clause_bounds(&self) -> Option<(usize, usize)> {
899 let elements = self.elements();
900 let lparen_idx = self.lparen_index()?;
901
902 let mut depth = 0usize;
903 let rparen_idx = elements.iter().enumerate().skip(lparen_idx).find_map(
904 |(idx, element)| match element {
905 SyntaxElement::Token(token) if token.kind() == SyntaxKind::LPAREN => {
906 depth += 1;
907 None
908 }
909 SyntaxElement::Token(token) if token.kind() == SyntaxKind::RPAREN => {
910 depth = depth.saturating_sub(1);
911 if depth == 0 { Some(idx) } else { None }
912 }
913 _ => None,
914 },
915 )?;
916
917 Some((lparen_idx, rparen_idx))
918 }
919
920 pub fn lparen_index(&self) -> Option<usize> {
921 let elements = self.elements();
922 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
923 find_token_after_index(&elements, while_idx, SyntaxKind::LPAREN)
924 }
925
926 pub fn leading_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
927 let elements = self.elements();
928 let while_idx = find_token_index(&elements, SyntaxKind::WHILE_KW)?;
929 let (_, rparen_idx) = self.clause_bounds()?;
930 Some(
931 elements[while_idx + 1..rparen_idx]
932 .iter()
933 .filter_map(|element| match element {
934 SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT => {
935 Some(token.clone())
936 }
937 _ => None,
938 })
939 .collect(),
940 )
941 }
942
943 pub fn condition_elements(&self) -> Option<Vec<SyntaxElement<RLanguage>>> {
944 let elements = self.elements();
945 let (lparen_idx, rparen_idx) = self.clause_bounds()?;
946 Some(
947 elements[lparen_idx + 1..rparen_idx]
948 .iter()
949 .filter(|element| {
950 !is_trivia(element.kind()) && element.kind() != SyntaxKind::COMMENT
951 })
952 .cloned()
953 .collect(),
954 )
955 }
956
957 pub fn post_clause_comments(&self) -> Option<Vec<SyntaxToken<RLanguage>>> {
958 let elements = self.elements();
959 let (_, rparen_idx) = self.clause_bounds()?;
960 let mut comments = Vec::new();
961 for element in &elements[rparen_idx + 1..] {
962 if is_trivia(element.kind()) {
963 continue;
964 }
965 if let SyntaxElement::Token(token) = element
966 && token.kind() == SyntaxKind::COMMENT
967 {
968 comments.push(token.clone());
969 continue;
970 }
971 break;
972 }
973 Some(comments)
974 }
975
976 pub fn body_element(&self) -> Option<SyntaxElement<RLanguage>> {
977 let elements = self.elements();
978 let (_, rparen_idx) = self.clause_bounds()?;
979 for element in &elements[rparen_idx + 1..] {
980 if is_trivia(element.kind()) {
981 continue;
982 }
983 if matches!(element, SyntaxElement::Token(token) if token.kind() == SyntaxKind::COMMENT)
984 {
985 continue;
986 }
987 return Some(element.clone());
988 }
989 None
990 }
991
992 pub fn parts(&self) -> Option<WhileExprParts> {
993 self.while_keyword()?;
994 self.lparen_index()?;
995 self.clause_bounds()?;
996
997 Some(WhileExprParts {
998 leading_comments: self.leading_comments()?,
999 condition_elements: self.condition_elements()?,
1000 post_clause_comments: self.post_clause_comments()?,
1001 body: self.body_element(),
1002 })
1003 }
1004}
1005
1006impl BinaryExpr {
1007 pub fn lhs(&self) -> Option<SyntaxElement<RLanguage>> {
1010 self.parts().map(|(lhs, _, _)| lhs)
1011 }
1012
1013 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
1015 self.parts().map(|(_, op, _)| op)
1016 }
1017
1018 pub fn op_kind(&self) -> Option<SyntaxKind> {
1019 self.op().map(|op| op.kind())
1020 }
1021
1022 pub fn rhs(&self) -> Option<SyntaxElement<RLanguage>> {
1024 self.parts().map(|(_, _, rhs)| rhs)
1025 }
1026
1027 pub fn parts(
1029 &self,
1030 ) -> Option<(
1031 SyntaxElement<RLanguage>,
1032 SyntaxToken<RLanguage>,
1033 SyntaxElement<RLanguage>,
1034 )> {
1035 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1036 let op_idx = elements
1037 .iter()
1038 .position(|e| matches!(e, SyntaxElement::Token(t) if is_binary_operator(t.kind())))?;
1039 let op = elements[op_idx].as_token()?.clone();
1040 let lhs = elements[..op_idx]
1041 .iter()
1042 .rev()
1043 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
1044 .clone();
1045 let rhs = elements[op_idx + 1..]
1046 .iter()
1047 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)?
1048 .clone();
1049 Some((lhs, op, rhs))
1050 }
1051}
1052
1053impl UnaryExpr {
1054 pub fn op(&self) -> Option<SyntaxToken<RLanguage>> {
1056 self.syntax().children_with_tokens().find_map(|e| match e {
1057 SyntaxElement::Token(t) if is_unary_operator(t.kind()) => Some(t),
1058 _ => None,
1059 })
1060 }
1061
1062 pub fn op_kind(&self) -> Option<SyntaxKind> {
1063 self.op().map(|op| op.kind())
1064 }
1065
1066 pub fn operand(&self) -> Option<SyntaxElement<RLanguage>> {
1068 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1069 let op_idx = elements
1070 .iter()
1071 .position(|e| matches!(e, SyntaxElement::Token(t) if is_unary_operator(t.kind())))?;
1072 elements[op_idx + 1..]
1073 .iter()
1074 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1075 .cloned()
1076 }
1077}
1078
1079impl ParenExpr {
1080 pub fn lparen(&self) -> Option<SyntaxToken<RLanguage>> {
1081 first_child_token(self.syntax(), SyntaxKind::LPAREN)
1082 }
1083
1084 pub fn rparen(&self) -> Option<SyntaxToken<RLanguage>> {
1085 first_child_token(self.syntax(), SyntaxKind::RPAREN)
1086 }
1087
1088 pub fn inner(&self) -> Option<SyntaxElement<RLanguage>> {
1090 self.syntax().children_with_tokens().find(|e| {
1091 !is_trivia(e.kind())
1092 && !matches!(
1093 e.kind(),
1094 SyntaxKind::COMMENT | SyntaxKind::LPAREN | SyntaxKind::RPAREN
1095 )
1096 })
1097 }
1098}
1099
1100impl BlockExpr {
1101 pub fn lbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1102 first_child_token(self.syntax(), SyntaxKind::LBRACE)
1103 }
1104
1105 pub fn rbrace(&self) -> Option<SyntaxToken<RLanguage>> {
1106 first_child_token(self.syntax(), SyntaxKind::RBRACE)
1107 }
1108
1109 pub fn statements(&self) -> impl Iterator<Item = SyntaxElement<RLanguage>> + '_ {
1113 self.syntax().children_with_tokens().filter(|e| {
1114 !is_trivia(e.kind())
1115 && !matches!(
1116 e.kind(),
1117 SyntaxKind::COMMENT
1118 | SyntaxKind::LBRACE
1119 | SyntaxKind::RBRACE
1120 | SyntaxKind::SEMICOLON
1121 )
1122 })
1123 }
1124}
1125
1126impl Arg {
1127 pub fn eq_token(&self) -> Option<SyntaxToken<RLanguage>> {
1129 first_child_token(self.syntax(), SyntaxKind::ASSIGN_EQ)
1130 }
1131
1132 pub fn name_token(&self) -> Option<SyntaxToken<RLanguage>> {
1135 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1136 let eq = elements
1137 .iter()
1138 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)?;
1139 elements[..eq].iter().rev().find_map(|e| match e {
1140 SyntaxElement::Token(t)
1141 if matches!(t.kind(), SyntaxKind::IDENT | SyntaxKind::STRING) =>
1142 {
1143 Some(t.clone())
1144 }
1145 _ => None,
1146 })
1147 }
1148
1149 pub fn name(&self) -> Option<SmolStr> {
1151 self.name_token().as_ref().map(token_name)
1152 }
1153
1154 pub fn is_named(&self) -> bool {
1155 self.name_token().is_some()
1156 }
1157
1158 pub fn value(&self) -> Option<SyntaxElement<RLanguage>> {
1161 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1162 let start = match elements
1163 .iter()
1164 .position(|e| e.kind() == SyntaxKind::ASSIGN_EQ)
1165 {
1166 Some(eq) => eq + 1,
1167 None => 0,
1168 };
1169 elements[start..]
1170 .iter()
1171 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1172 .cloned()
1173 }
1174}
1175
1176impl RepeatExpr {
1177 pub fn repeat_keyword(&self) -> Option<SyntaxToken<RLanguage>> {
1178 first_child_token(self.syntax(), SyntaxKind::REPEAT_KW)
1179 }
1180
1181 pub fn body(&self) -> Option<SyntaxElement<RLanguage>> {
1183 let elements: Vec<_> = self.syntax().children_with_tokens().collect();
1184 let kw_idx = elements
1185 .iter()
1186 .position(|e| e.kind() == SyntaxKind::REPEAT_KW)?;
1187 elements[kw_idx + 1..]
1188 .iter()
1189 .find(|e| !is_trivia(e.kind()) && e.kind() != SyntaxKind::COMMENT)
1190 .cloned()
1191 }
1192}
1193
1194fn find_token_index(elements: &[SyntaxElement<RLanguage>], kind: SyntaxKind) -> Option<usize> {
1195 elements
1196 .iter()
1197 .position(|element| matches!(element, SyntaxElement::Token(token) if token.kind() == kind))
1198}
1199
1200fn find_token_after_index(
1201 elements: &[SyntaxElement<RLanguage>],
1202 start_idx: usize,
1203 kind: SyntaxKind,
1204) -> Option<usize> {
1205 elements
1206 .iter()
1207 .enumerate()
1208 .skip(start_idx + 1)
1209 .find_map(|(idx, element)| match element {
1210 SyntaxElement::Token(token) if token.kind() == kind => Some(idx),
1211 _ => None,
1212 })
1213}