1use crate::parser::context::{
2 ParserCtx, StatementTracker, push_token_diagnostic_ctx as push_token_diagnostic,
3};
4use crate::parser::diagnostics::ParseDiagnostic;
5use crate::parser::events::{Event, ExprParse};
6use crate::parser::lexer::{TokKind, Token};
7use crate::parser::recovery::error_expr_to_line_end;
8use crate::parser::structural::{
9 parse_for_expr, parse_function_expr, parse_if_expr, parse_repeat_expr, parse_while_expr,
10};
11use crate::syntax::SyntaxKind;
12
13fn is_assignment_operator(kind: &TokKind) -> bool {
14 matches!(
15 kind,
16 TokKind::AssignLeft
17 | TokKind::SuperAssign
18 | TokKind::AssignRight
19 | TokKind::SuperAssignRight
20 | TokKind::AssignEq
21 | TokKind::Walrus
22 )
23}
24
25fn is_infix_operator(kind: &TokKind) -> bool {
26 infix_binding_power(kind).is_some()
27}
28
29fn next_operator<'a>(
30 ctx: &ParserCtx<'a>,
31 start: usize,
32 inside_brackets: bool,
33) -> Option<(usize, &'a Token)> {
34 let op_idx = ctx.skip_ws(start);
35 let op = ctx.token(op_idx)?;
36 if matches!(op.kind, TokKind::Newline | TokKind::Comment) {
37 if !inside_brackets {
48 return None;
49 }
50 let next_idx = ctx.skip_ws_newlines_comments(start);
51 let next = ctx.token(next_idx)?;
52 if is_assignment_operator(&next.kind) || is_infix_operator(&next.kind) {
53 return Some((next_idx, next));
54 }
55 return None;
56 }
57 if is_assignment_operator(&op.kind) || is_infix_operator(&op.kind) {
58 return Some((op_idx, op));
59 }
60 None
61}
62
63pub(crate) fn parse_expr(
64 tokens: &[Token],
65 start: usize,
66 min_bp: u8,
67 diagnostics: &mut Vec<ParseDiagnostic>,
68) -> Option<ExprParse> {
69 parse_expr_with_mode(tokens, start, min_bp, diagnostics, false, false)
70}
71
72pub(crate) fn parse_expr_in_brackets(
73 tokens: &[Token],
74 start: usize,
75 min_bp: u8,
76 diagnostics: &mut Vec<ParseDiagnostic>,
77) -> Option<ExprParse> {
78 parse_expr_with_mode(tokens, start, min_bp, diagnostics, true, true)
79}
80
81fn parse_expr_with_mode(
82 tokens: &[Token],
83 start: usize,
84 min_bp: u8,
85 diagnostics: &mut Vec<ParseDiagnostic>,
86 allow_newline_prefix: bool,
87 inside_brackets: bool,
88) -> Option<ExprParse> {
89 let ctx = ParserCtx::new(tokens);
90 let start_non_ws = if allow_newline_prefix {
91 ctx.skip_ws_and_newlines(start)
92 } else {
93 ctx.skip_ws(start)
94 };
95 if matches!(
96 tokens.get(start_non_ws).map(|t| &t.kind),
97 Some(TokKind::IfKw)
98 ) {
99 return parse_if_expr(tokens, start_non_ws, diagnostics);
100 }
101 if matches!(
102 tokens.get(start_non_ws).map(|t| &t.kind),
103 Some(TokKind::ForKw)
104 ) {
105 return parse_for_expr(tokens, start_non_ws, diagnostics);
106 }
107 if matches!(
108 tokens.get(start_non_ws).map(|t| &t.kind),
109 Some(TokKind::WhileKw)
110 ) {
111 return parse_while_expr(tokens, start_non_ws, diagnostics);
112 }
113 if matches!(
114 tokens.get(start_non_ws).map(|t| &t.kind),
115 Some(TokKind::RepeatKw)
116 ) {
117 return parse_repeat_expr(tokens, start_non_ws, diagnostics);
118 }
119 if matches!(
120 tokens.get(start_non_ws).map(|t| &t.kind),
121 Some(TokKind::FunctionKw)
122 ) {
123 return parse_function_expr(tokens, start_non_ws, inside_brackets, diagnostics);
124 }
125 if matches!(
126 tokens.get(start_non_ws).map(|t| &t.kind),
127 Some(TokKind::LambdaFn)
128 ) {
129 return parse_function_expr(tokens, start_non_ws, inside_brackets, diagnostics);
130 }
131
132 let mut lhs = parse_prefix(
133 &ctx,
134 start,
135 diagnostics,
136 allow_newline_prefix,
137 inside_brackets,
138 )?;
139
140 if lhs.end == lhs.start + 1 && tokens[lhs.start].kind.is_comment_like() {
147 return Some(lhs);
148 }
149
150 loop {
151 lhs = parse_postfix_chain(&ctx, lhs, inside_brackets, diagnostics);
152
153 let Some((op_idx, op)) = next_operator(&ctx, lhs.end, inside_brackets) else {
154 break;
155 };
156
157 if is_assignment_operator(&op.kind) {
158 let (l_bp, r_bp) = (1, 1);
159 if l_bp < min_bp {
160 break;
161 }
162
163 let rhs_start = op_idx + 1;
164 let rhs_operand = ctx.skip_ws_newlines_comments(rhs_start);
170 let Some(rhs) = parse_expr_with_mode(
171 tokens,
172 rhs_operand,
173 r_bp,
174 diagnostics,
175 true,
176 inside_brackets,
177 ) else {
178 push_token_diagnostic(diagnostics, "expected assignment right-hand side", op);
179 return Some(error_expr_to_line_end(tokens, lhs.start, rhs_start));
180 };
181
182 lhs = build_assignment_expr(lhs, op_idx, rhs);
183 continue;
184 }
185
186 let Some((l_bp, r_bp)) = infix_binding_power(&op.kind) else {
187 break;
188 };
189 if l_bp < min_bp {
190 break;
191 }
192
193 let rhs_start = op_idx + 1;
194 let rhs_operand = ctx.skip_ws_newlines_comments(rhs_start);
199 let rhs = if is_extract_operator(&op.kind) {
208 parse_prefix(&ctx, rhs_operand, diagnostics, true, inside_brackets)
209 } else {
210 parse_expr_with_mode(
211 tokens,
212 rhs_operand,
213 r_bp,
214 diagnostics,
215 true,
216 inside_brackets,
217 )
218 };
219 let Some(rhs) = rhs else {
220 push_token_diagnostic(
221 diagnostics,
222 "expected right-hand side for binary operator",
223 op,
224 );
225 return Some(error_expr_to_line_end(tokens, lhs.start, rhs_start));
226 };
227
228 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
229 && lhs
230 .events
231 .iter()
232 .any(|event| matches!(event, Event::Start(SyntaxKind::CALL_EXPR)))
233 {
234 push_token_diagnostic(
235 diagnostics,
236 "namespace operator requires a package name on the left-hand side",
237 op,
238 );
239 }
240
241 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
242 && matches!(expr_root_kind(&rhs), Some(SyntaxKind::BLOCK_EXPR))
243 {
244 push_token_diagnostic(
245 diagnostics,
246 "namespace operator requires an identifier on the right-hand side",
247 op,
248 );
249 }
250
251 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
252 && matches!(
253 expr_root_kind(&rhs),
254 Some(SyntaxKind::INT | SyntaxKind::FLOAT | SyntaxKind::COMPLEX)
255 )
256 {
257 push_token_diagnostic(
258 diagnostics,
259 "namespace operator requires an identifier on the right-hand side",
260 op,
261 );
262 }
263
264 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
265 && matches!(expr_root_kind(&rhs), Some(SyntaxKind::IDENT))
266 {
267 let rhs_tok_idx = ctx.skip_ws(rhs.start);
268 if let Some(tok) = tokens.get(rhs_tok_idx)
269 && ident_is_special_constant(tok.text.as_str())
270 {
271 push_token_diagnostic(
272 diagnostics,
273 "namespace operator requires an identifier on the right-hand side",
274 op,
275 );
276 }
277 }
278
279 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
280 && matches!(expr_root_kind(&lhs), Some(SyntaxKind::BINARY_EXPR))
281 && lhs
282 .events
283 .iter()
284 .any(|event| matches!(event, Event::Tok(idx) if matches!(tokens[*idx].kind, TokKind::Colon2 | TokKind::Colon3)))
285 {
286 push_token_diagnostic(diagnostics, "namespace operator chaining is not allowed", op);
287 }
288
289 lhs = build_binary_expr(lhs, op_idx, rhs);
290 }
291
292 Some(lhs)
293}
294
295fn parse_prefix(
296 ctx: &ParserCtx<'_>,
297 start: usize,
298 diagnostics: &mut Vec<ParseDiagnostic>,
299 allow_newline_prefix: bool,
300 inside_brackets: bool,
301) -> Option<ExprParse> {
302 let tokens = ctx.tokens();
303 let i = if allow_newline_prefix {
304 ctx.skip_ws_and_newlines(start)
305 } else {
306 ctx.skip_ws(start)
307 };
308 let tok = tokens.get(i)?;
309
310 match tok.kind {
311 TokKind::Plus | TokKind::Minus | TokKind::Bang | TokKind::Tilde | TokKind::Question => {
312 let rbp = match tok.kind {
327 TokKind::Tilde => 41,
328 TokKind::Question => 1,
329 TokKind::Bang => 70,
330 _ => 130,
331 };
332 let operand_start = i + 1;
333 let Some(operand) = parse_expr_with_mode(
334 tokens,
335 operand_start,
336 rbp,
337 diagnostics,
338 true,
339 inside_brackets,
340 ) else {
341 push_token_diagnostic(diagnostics, "expected operand for unary operator", tok);
342 return Some(error_expr_to_line_end(tokens, i, operand_start));
343 };
344 let mut events = Vec::new();
345 events.push(Event::Start(SyntaxKind::UNARY_EXPR));
346 events.push(Event::Tok(i));
347 for idx in (i + 1)..operand.start {
348 events.push(Event::Tok(idx));
349 }
350 events.extend(operand.events);
351 events.push(Event::Finish);
352 Some(ExprParse {
353 start: i,
354 end: operand.end,
355 events,
356 })
357 }
358 TokKind::Ident
359 | TokKind::Int
360 | TokKind::Float
361 | TokKind::Complex
362 | TokKind::String
363 | TokKind::Comment
364 | TokKind::UserOp => Some(ExprParse {
365 start: i,
366 end: i + 1,
367 events: vec![Event::Tok(i)],
368 }),
369 TokKind::LParen => {
370 let inner_start = i + 1;
371 let mut expr_start = inner_start;
372 while matches!(
373 tokens.get(expr_start).map(|t| &t.kind),
374 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
375 ) {
376 expr_start += 1;
377 }
378 let Some(inner) = parse_expr_with_mode(tokens, expr_start, 0, diagnostics, true, true)
379 else {
380 push_token_diagnostic(diagnostics, "expected expression after '('", tok);
381 return Some(error_expr_to_line_end(tokens, i, inner_start));
382 };
383 let mut close_idx = inner.end;
384 while matches!(
385 tokens.get(close_idx).map(|t| &t.kind),
386 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
387 ) {
388 close_idx += 1;
389 }
390 if !matches!(
391 tokens.get(close_idx).map(|t| &t.kind),
392 Some(TokKind::RParen)
393 ) {
394 push_token_diagnostic(diagnostics, "expected ')'", tok);
395 let mut events = Vec::new();
396 events.push(Event::Start(SyntaxKind::PAREN_EXPR));
397 events.push(Event::Tok(i));
398 for idx in inner_start..inner.start {
399 events.push(Event::Tok(idx));
400 }
401 events.extend(inner.events);
402 for idx in inner.end..close_idx {
403 events.push(Event::Tok(idx));
404 }
405 events.push(Event::Finish);
406 return Some(ExprParse {
407 start: i,
408 end: close_idx,
409 events,
410 });
411 }
412
413 let mut events = Vec::new();
414 events.push(Event::Start(SyntaxKind::PAREN_EXPR));
415 events.push(Event::Tok(i));
416 for idx in inner_start..inner.start {
417 events.push(Event::Tok(idx));
418 }
419 events.extend(inner.events);
420 for idx in inner.end..close_idx {
421 events.push(Event::Tok(idx));
422 }
423 events.push(Event::Tok(close_idx));
424 events.push(Event::Finish);
425
426 Some(ExprParse {
427 start: i,
428 end: close_idx + 1,
429 events,
430 })
431 }
432 TokKind::LBrace => parse_block_expr(ctx, i, diagnostics),
433 TokKind::Star
434 | TokKind::Slash
435 | TokKind::Caret
436 | TokKind::AssignLeft
437 | TokKind::SuperAssign
438 | TokKind::AssignRight
439 | TokKind::SuperAssignRight
440 | TokKind::AssignEq
441 | TokKind::Walrus
442 | TokKind::Colon
443 | TokKind::Or
444 | TokKind::Or2
445 | TokKind::And
446 | TokKind::And2
447 | TokKind::Equal2
448 | TokKind::NotEqual
449 | TokKind::LessThan
450 | TokKind::LessThanOrEqual
451 | TokKind::GreaterThan
452 | TokKind::GreaterThanOrEqual
453 | TokKind::Colon2
454 | TokKind::Colon3
455 | TokKind::Dollar
456 | TokKind::At
457 | TokKind::Semicolon
458 | TokKind::Comma
459 | TokKind::Pipe => {
460 push_token_diagnostic(diagnostics, "unexpected operator at expression start", tok);
461 Some(error_expr_to_line_end(tokens, i, i + 1))
462 }
463 TokKind::Whitespace
464 | TokKind::Newline
465 | TokKind::RParen
466 | TokKind::RBrack
467 | TokKind::RBrack2
468 | TokKind::RBrace
469 | TokKind::IfKw
470 | TokKind::ElseKw
471 | TokKind::ForKw
472 | TokKind::WhileKw
473 | TokKind::RepeatKw
474 | TokKind::FunctionKw
475 | TokKind::LambdaFn
476 | TokKind::InKw
477 | TokKind::LBrack
478 | TokKind::LBrack2
479 | TokKind::RoxygenMarker
480 | TokKind::RoxygenAt
481 | TokKind::RoxygenTagName
482 | TokKind::RoxygenTagArg
483 | TokKind::RoxygenText
484 | TokKind::RoxygenCode
485 | TokKind::RoxygenRdMacro
486 | TokKind::RoxygenMdLink
487 | TokKind::RoxygenMdBracket
488 | TokKind::RoxygenMdImage
489 | TokKind::RoxygenMdDelim
490 | TokKind::RoxygenMdCode
491 | TokKind::RoxygenMdListMarker
492 | TokKind::RoxygenMdFence
493 | TokKind::RoxygenMdHtml
494 | TokKind::RoxygenMdHtmlBlock
495 | TokKind::RoxygenMdTableDelim
496 | TokKind::RoxygenMdHeading
497 | TokKind::RoxygenMdSetextUnderline
498 | TokKind::RoxygenMdBlockQuote
499 | TokKind::RoxygenMdThematicBreak
500 | TokKind::Unknown => None,
501 }
502}
503
504fn parse_block_expr(
505 ctx: &ParserCtx<'_>,
506 start: usize,
507 diagnostics: &mut Vec<ParseDiagnostic>,
508) -> Option<ExprParse> {
509 let tokens = ctx.tokens();
510 let mut i = start + 1;
511 let mut events = vec![Event::Start(SyntaxKind::BLOCK_EXPR), Event::Tok(start)];
512 let mut statements = StatementTracker::default();
513
514 loop {
515 let next = ctx.skip_ws(i);
516 let Some(tok) = tokens.get(next) else {
517 push_token_diagnostic(diagnostics, "expected '}' to close block", &tokens[start]);
518 for idx in i..tokens.len() {
519 events.push(Event::Tok(idx));
520 }
521 events.push(Event::Finish);
522 return Some(ExprParse {
523 start,
524 end: tokens.len(),
525 events,
526 });
527 };
528
529 if tok.kind == TokKind::RBrace {
530 for idx in i..next {
531 events.push(Event::Tok(idx));
532 }
533 events.push(Event::Tok(next));
534 events.push(Event::Finish);
535 return Some(ExprParse {
536 start,
537 end: next + 1,
538 events,
539 });
540 }
541
542 if matches!(tok.kind, TokKind::Newline | TokKind::Semicolon) {
544 for idx in i..=next {
545 events.push(Event::Tok(idx));
546 }
547 i = next + 1;
548 continue;
549 }
550
551 if tok.kind == TokKind::RoxygenMarker {
552 for idx in i..next {
554 events.push(Event::Tok(idx));
555 }
556 i = crate::parser::roxygen::emit_roxygen_block(tokens, next, &mut events);
557 continue;
558 }
559
560 let before = diagnostics.len();
561 if let Some(expr) = parse_expr(tokens, i, 0, diagnostics) {
562 if !tokens[expr.start].kind.is_comment_like() {
564 let recovered = diagnostics.len() > before;
565 statements.record(tokens, expr.start, expr.end, recovered, diagnostics);
566 }
567 for idx in i..expr.start {
568 events.push(Event::Tok(idx));
569 }
570 events.extend(expr.events);
571 i = expr.end;
572 } else {
573 events.push(Event::Tok(i));
574 i += 1;
575 statements.record_recovery(i);
576 }
577 }
578}
579
580fn parse_postfix_chain(
581 ctx: &ParserCtx<'_>,
582 mut lhs: ExprParse,
583 inside_brackets: bool,
584 diagnostics: &mut Vec<ParseDiagnostic>,
585) -> ExprParse {
586 let tokens = ctx.tokens();
587 loop {
588 let after_lhs = if inside_brackets {
593 ctx.skip_ws_and_newlines(lhs.end)
594 } else {
595 ctx.skip_ws(lhs.end)
596 };
597 if matches!(
598 tokens.get(after_lhs).map(|t| &t.kind),
599 Some(TokKind::LParen)
600 ) {
601 lhs = parse_call_expr(ctx, lhs, after_lhs, diagnostics);
602 continue;
603 }
604 if matches!(
605 tokens.get(after_lhs).map(|t| &t.kind),
606 Some(TokKind::LBrack)
607 ) {
608 lhs = parse_subset_expr(ctx, lhs, after_lhs, diagnostics);
609 continue;
610 }
611 if matches!(
612 tokens.get(after_lhs).map(|t| &t.kind),
613 Some(TokKind::LBrack2)
614 ) {
615 lhs = parse_subset2_expr(ctx, lhs, after_lhs, diagnostics);
616 continue;
617 }
618 break;
619 }
620 lhs
621}
622
623fn build_binary_like_expr(
624 kind: SyntaxKind,
625 lhs: ExprParse,
626 op_idx: usize,
627 rhs: ExprParse,
628) -> ExprParse {
629 let mut events = Vec::new();
630 events.push(Event::Start(kind));
631 events.extend(lhs.events);
632 for idx in lhs.end..op_idx {
633 events.push(Event::Tok(idx));
634 }
635 events.push(Event::Tok(op_idx));
636 for idx in (op_idx + 1)..rhs.start {
637 events.push(Event::Tok(idx));
638 }
639 events.extend(rhs.events);
640 events.push(Event::Finish);
641
642 ExprParse {
643 start: lhs.start,
644 end: rhs.end,
645 events,
646 }
647}
648
649fn build_binary_expr(lhs: ExprParse, op_idx: usize, rhs: ExprParse) -> ExprParse {
650 build_binary_like_expr(SyntaxKind::BINARY_EXPR, lhs, op_idx, rhs)
651}
652
653fn build_assignment_expr(lhs: ExprParse, op_idx: usize, rhs: ExprParse) -> ExprParse {
654 build_binary_like_expr(SyntaxKind::ASSIGNMENT_EXPR, lhs, op_idx, rhs)
655}
656
657fn is_named_arg(ctx: &ParserCtx<'_>, i: usize) -> bool {
662 let tokens = ctx.tokens();
663 if !matches!(
664 tokens.get(i).map(|t| &t.kind),
665 Some(TokKind::Ident | TokKind::String)
666 ) {
667 return false;
668 }
669 let mut next = i + 1;
670 while matches!(
671 tokens.get(next).map(|t| &t.kind),
672 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
673 ) {
674 next += 1;
675 }
676 matches!(tokens.get(next).map(|t| &t.kind), Some(TokKind::AssignEq))
677}
678
679fn has_newline(tokens: &[Token], start: usize, end: usize) -> bool {
680 tokens[start..end]
681 .iter()
682 .any(|t| t.kind == TokKind::Newline)
683}
684
685fn expr_root_kind(expr: &ExprParse) -> Option<SyntaxKind> {
686 expr.events.iter().find_map(|event| match event {
687 Event::Start(kind) => Some(*kind),
688 _ => None,
689 })
690}
691
692pub fn ident_is_special_constant(text: &str) -> bool {
693 matches!(
694 text,
695 "NA" | "NULL"
696 | "TRUE"
697 | "FALSE"
698 | "Inf"
699 | "NaN"
700 | "NA_integer_"
701 | "NA_real_"
702 | "NA_complex_"
703 | "NA_character_"
704 )
705}
706
707fn parse_call_expr(
708 ctx: &ParserCtx<'_>,
709 callee: ExprParse,
710 lparen_idx: usize,
711 diagnostics: &mut Vec<ParseDiagnostic>,
712) -> ExprParse {
713 let tokens = ctx.tokens();
714 let mut events = vec![Event::Start(SyntaxKind::CALL_EXPR)];
715 events.extend(callee.events);
716 for idx in callee.end..lparen_idx {
718 events.push(Event::Tok(idx));
719 }
720 events.push(Event::Tok(lparen_idx)); events.push(Event::Start(SyntaxKind::ARG_LIST));
723 let mut i = lparen_idx + 1;
724
725 let mut expect_delimiter = false;
726 let mut last_arg_was_comment_only = false;
727 loop {
728 let next_i = ctx.skip_ws_and_newlines(i);
730 let had_newline_gap = has_newline(tokens, i, next_i);
731 for idx in i..next_i {
732 events.push(Event::Tok(idx));
733 }
734 i = next_i;
735
736 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RParen) | None) {
738 break;
739 }
740
741 if expect_delimiter
742 && !had_newline_gap
743 && let Some(tok) = tokens.get(i)
744 {
745 let current_is_comment = tok.kind == TokKind::Comment;
746 if !current_is_comment && !last_arg_was_comment_only {
747 push_token_diagnostic(diagnostics, "expected ',' between arguments", tok);
748 }
749 }
750
751 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
753 events.push(Event::Start(SyntaxKind::ARG));
754 events.push(Event::Finish);
755 events.push(Event::Tok(i)); i += 1;
757 expect_delimiter = false;
758 last_arg_was_comment_only = false;
759 continue;
760 }
761
762 events.push(Event::Start(SyntaxKind::ARG));
763 last_arg_was_comment_only = false;
764
765 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RoxygenMarker)) {
766 i = crate::parser::roxygen::emit_roxygen_block(tokens, i, &mut events);
772 last_arg_was_comment_only = true;
773 } else if is_named_arg(ctx, i) {
774 events.push(Event::Tok(i)); let mut eq_idx = i + 1;
777 while matches!(
778 tokens.get(eq_idx).map(|t| &t.kind),
779 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
780 ) {
781 eq_idx += 1;
782 }
783 for idx in (i + 1)..eq_idx {
784 events.push(Event::Tok(idx));
785 }
786 if !matches!(tokens.get(eq_idx).map(|t| &t.kind), Some(TokKind::AssignEq)) {
787 events.push(Event::Finish); expect_delimiter = true;
789 i = eq_idx;
790 continue;
791 }
792 events.push(Event::Tok(eq_idx)); let val_start = eq_idx + 1;
794 let mut value_idx = val_start;
795 while matches!(
796 tokens.get(value_idx).map(|t| &t.kind),
797 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
798 ) {
799 value_idx += 1;
800 }
801 if matches!(
802 tokens.get(value_idx).map(|t| &t.kind),
803 Some(TokKind::Comma | TokKind::RParen) | None
804 ) {
805 for idx in val_start..value_idx {
806 events.push(Event::Tok(idx));
807 }
808 i = value_idx;
809 } else if let Some(val) = parse_expr_in_brackets(tokens, value_idx, 0, diagnostics) {
810 for idx in val_start..val.start {
811 events.push(Event::Tok(idx));
812 }
813 events.extend(val.events);
814 i = val.end;
815 } else {
816 i = val_start;
817 }
818 } else {
819 if let Some(arg) = parse_expr_in_brackets(tokens, i, 0, diagnostics) {
821 last_arg_was_comment_only = arg.end == arg.start + 1
822 && matches!(
823 tokens.get(arg.start).map(|t| &t.kind),
824 Some(TokKind::Comment)
825 );
826 for idx in i..arg.start {
827 events.push(Event::Tok(idx));
828 }
829 events.extend(arg.events);
830 i = arg.end;
831 } else {
832 last_arg_was_comment_only = false;
833 events.push(Event::Tok(i));
834 i += 1;
835 }
836 }
837
838 events.push(Event::Finish); expect_delimiter = true;
840
841 let next_i = ctx.skip_ws_and_newlines(i);
843 for idx in i..next_i {
844 events.push(Event::Tok(idx));
845 }
846 i = next_i;
847
848 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
849 events.push(Event::Tok(i)); i += 1;
851 expect_delimiter = false;
852 last_arg_was_comment_only = false;
853 }
854 }
855
856 events.push(Event::Finish); let next_i = ctx.skip_ws_and_newlines(i);
860 for idx in i..next_i {
861 events.push(Event::Tok(idx));
862 }
863 i = next_i;
864
865 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RParen)) {
866 events.push(Event::Tok(i));
867 i += 1;
868 } else if let Some(tok) = tokens.get(lparen_idx) {
869 push_token_diagnostic(diagnostics, "expected ')' to close function call", tok);
870 }
871
872 events.push(Event::Finish); ExprParse {
875 start: callee.start,
876 end: i,
877 events,
878 }
879}
880
881fn parse_subset_expr(
882 ctx: &ParserCtx<'_>,
883 target: ExprParse,
884 lbrack_idx: usize,
885 diagnostics: &mut Vec<ParseDiagnostic>,
886) -> ExprParse {
887 parse_bracket_expr(
888 ctx,
889 target,
890 lbrack_idx,
891 SyntaxKind::SUBSET_EXPR,
892 diagnostics,
893 )
894}
895
896fn parse_subset2_expr(
897 ctx: &ParserCtx<'_>,
898 target: ExprParse,
899 lbrack2_idx: usize,
900 diagnostics: &mut Vec<ParseDiagnostic>,
901) -> ExprParse {
902 parse_bracket_expr(
903 ctx,
904 target,
905 lbrack2_idx,
906 SyntaxKind::SUBSET2_EXPR,
907 diagnostics,
908 )
909}
910
911fn parse_bracket_expr(
912 ctx: &ParserCtx<'_>,
913 target: ExprParse,
914 open_idx: usize,
915 node_kind: SyntaxKind,
916 diagnostics: &mut Vec<ParseDiagnostic>,
917) -> ExprParse {
918 let tokens = ctx.tokens();
919 let mut events = vec![Event::Start(node_kind)];
920 events.extend(target.events);
921 for idx in target.end..open_idx {
922 events.push(Event::Tok(idx));
923 }
924 events.push(Event::Tok(open_idx));
925
926 events.push(Event::Start(SyntaxKind::ARG_LIST));
927 let mut i = open_idx + 1;
928
929 let mut expect_delimiter = false;
930 let mut last_arg_was_comment_only = false;
931 loop {
932 let next_i = ctx.skip_ws_and_newlines(i);
933 let had_newline_gap = has_newline(tokens, i, next_i);
934 for idx in i..next_i {
935 events.push(Event::Tok(idx));
936 }
937 i = next_i;
938
939 if is_matching_subset_close(tokens, i, node_kind) || tokens.get(i).is_none() {
940 break;
941 }
942
943 if expect_delimiter
944 && !had_newline_gap
945 && let Some(tok) = tokens.get(i)
946 {
947 let current_is_comment = tok.kind == TokKind::Comment;
948 if !current_is_comment && !last_arg_was_comment_only {
949 push_token_diagnostic(diagnostics, "expected ',' between subset arguments", tok);
950 }
951 }
952
953 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
954 events.push(Event::Start(SyntaxKind::ARG));
955 events.push(Event::Finish);
956 events.push(Event::Tok(i));
957 i += 1;
958 expect_delimiter = false;
959 last_arg_was_comment_only = false;
960 continue;
961 }
962
963 events.push(Event::Start(SyntaxKind::ARG));
964 last_arg_was_comment_only = false;
965
966 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RoxygenMarker)) {
967 i = crate::parser::roxygen::emit_roxygen_block(tokens, i, &mut events);
970 last_arg_was_comment_only = true;
971 } else if is_named_arg(ctx, i) {
972 events.push(Event::Tok(i)); let mut eq_idx = i + 1;
978 while matches!(
979 tokens.get(eq_idx).map(|t| &t.kind),
980 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
981 ) {
982 eq_idx += 1;
983 }
984 for idx in (i + 1)..eq_idx {
985 events.push(Event::Tok(idx));
986 }
987 events.push(Event::Tok(eq_idx)); let val_start = eq_idx + 1;
990 let mut value_idx = val_start;
991 while matches!(
992 tokens.get(value_idx).map(|t| &t.kind),
993 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
994 ) {
995 value_idx += 1;
996 }
997 if matches!(
998 tokens.get(value_idx).map(|t| &t.kind),
999 Some(TokKind::Comma) | None
1000 ) || is_matching_subset_close(tokens, value_idx, node_kind)
1001 {
1002 for idx in val_start..value_idx {
1004 events.push(Event::Tok(idx));
1005 }
1006 i = value_idx;
1007 } else if let Some(val) = parse_expr_in_brackets(tokens, value_idx, 0, diagnostics) {
1008 for idx in val_start..val.start {
1009 events.push(Event::Tok(idx));
1010 }
1011 events.extend(val.events);
1012 i = val.end;
1013 } else {
1014 i = val_start;
1015 }
1016 } else if let Some(arg) = parse_expr_in_brackets(tokens, i, 0, diagnostics) {
1017 last_arg_was_comment_only = arg.end == arg.start + 1
1018 && matches!(
1019 tokens.get(arg.start).map(|t| &t.kind),
1020 Some(TokKind::Comment)
1021 );
1022 for idx in i..arg.start {
1023 events.push(Event::Tok(idx));
1024 }
1025 events.extend(arg.events);
1026 i = arg.end;
1027 } else {
1028 last_arg_was_comment_only = false;
1029 events.push(Event::Tok(i));
1030 i += 1;
1031 }
1032 events.push(Event::Finish);
1033 expect_delimiter = true;
1034
1035 let next_i = ctx.skip_ws_and_newlines(i);
1036 for idx in i..next_i {
1037 events.push(Event::Tok(idx));
1038 }
1039 i = next_i;
1040 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
1041 events.push(Event::Tok(i));
1042 i += 1;
1043 expect_delimiter = false;
1044 last_arg_was_comment_only = false;
1045 }
1046 }
1047
1048 events.push(Event::Finish); let next_i = ctx.skip_ws_and_newlines(i);
1050 for idx in i..next_i {
1051 events.push(Event::Tok(idx));
1052 }
1053 i = next_i;
1054
1055 if is_matching_subset_close(tokens, i, node_kind) {
1056 match node_kind {
1057 SyntaxKind::SUBSET_EXPR => {
1058 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RBrack2)) {
1059 events.push(Event::Tok(i)); i += 1;
1061 } else {
1062 events.push(Event::Tok(i));
1063 i += 1;
1064 }
1065 }
1066 SyntaxKind::SUBSET2_EXPR => {
1067 events.push(Event::Tok(i));
1068 i += 1;
1069 }
1070 _ => {}
1071 }
1072 } else if node_kind == SyntaxKind::SUBSET_EXPR
1073 && matches!(previous_non_trivia_kind(tokens, i), Some(TokKind::RBrack2))
1074 {
1075 } else if let Some(tok) = tokens.get(open_idx) {
1078 push_token_diagnostic(
1079 diagnostics,
1080 "expected closing bracket in subset expression",
1081 tok,
1082 );
1083 }
1084
1085 events.push(Event::Finish);
1086 ExprParse {
1087 start: target.start,
1088 end: i,
1089 events,
1090 }
1091}
1092
1093fn is_matching_subset_close(tokens: &[Token], idx: usize, node_kind: SyntaxKind) -> bool {
1094 match node_kind {
1095 SyntaxKind::SUBSET_EXPR => matches!(
1096 tokens.get(idx).map(|t| &t.kind),
1097 Some(TokKind::RBrack | TokKind::RBrack2)
1098 ),
1099 SyntaxKind::SUBSET2_EXPR => {
1100 matches!(tokens.get(idx).map(|t| &t.kind), Some(TokKind::RBrack2))
1101 }
1102 _ => false,
1103 }
1104}
1105
1106fn previous_non_trivia_kind(tokens: &[Token], mut idx: usize) -> Option<TokKind> {
1107 if idx == 0 {
1108 return None;
1109 }
1110 idx -= 1;
1111 loop {
1112 let tok = tokens.get(idx)?;
1113 if !matches!(tok.kind, TokKind::Whitespace | TokKind::Newline) {
1114 return Some(tok.kind.clone());
1115 }
1116 if idx == 0 {
1117 return None;
1118 }
1119 idx -= 1;
1120 }
1121}
1122
1123fn is_extract_operator(kind: &TokKind) -> bool {
1128 matches!(
1129 kind,
1130 TokKind::Dollar | TokKind::At | TokKind::Colon2 | TokKind::Colon3
1131 )
1132}
1133
1134fn infix_binding_power(kind: &TokKind) -> Option<(u8, u8)> {
1135 match kind {
1142 TokKind::Question => Some((0, 1)),
1143 TokKind::Or | TokKind::Or2 => Some((50, 51)),
1144 TokKind::And | TokKind::And2 => Some((60, 61)),
1145 TokKind::Equal2
1146 | TokKind::NotEqual
1147 | TokKind::LessThan
1148 | TokKind::LessThanOrEqual
1149 | TokKind::GreaterThan
1150 | TokKind::GreaterThanOrEqual => Some((80, 81)),
1151 TokKind::Plus | TokKind::Minus => Some((90, 91)),
1152 TokKind::Star | TokKind::Slash => Some((100, 101)),
1153 TokKind::Pipe | TokKind::UserOp => Some((110, 111)),
1154 TokKind::Colon => Some((120, 121)),
1155 TokKind::Tilde => Some((40, 41)),
1156 TokKind::Caret => Some((140, 140)),
1157 TokKind::Colon2 | TokKind::Colon3 | TokKind::Dollar | TokKind::At => Some((150, 151)),
1158 _ => None,
1159 }
1160}