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<'a>)> {
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 {
38 return None;
39 }
40 let next_idx = ctx.skip_ws_newlines_comments(start);
41 let next = ctx.token(next_idx)?;
42 if is_assignment_operator(&next.kind) || is_infix_operator(&next.kind) {
43 return Some((next_idx, next));
44 }
45 return None;
46 }
47 if is_assignment_operator(&op.kind) || is_infix_operator(&op.kind) {
48 return Some((op_idx, op));
49 }
50 None
51}
52
53pub(crate) fn parse_expr(
54 tokens: &[Token],
55 start: usize,
56 min_bp: u8,
57 diagnostics: &mut Vec<ParseDiagnostic>,
58 md_default: bool,
59) -> Option<ExprParse> {
60 parse_expr_with_mode(tokens, start, min_bp, diagnostics, false, false, md_default)
61}
62
63pub(crate) fn parse_expr_in_brackets(
64 tokens: &[Token],
65 start: usize,
66 min_bp: u8,
67 diagnostics: &mut Vec<ParseDiagnostic>,
68 md_default: bool,
69) -> Option<ExprParse> {
70 parse_expr_with_mode(tokens, start, min_bp, diagnostics, true, true, md_default)
71}
72
73fn parse_expr_with_mode(
74 tokens: &[Token],
75 start: usize,
76 min_bp: u8,
77 diagnostics: &mut Vec<ParseDiagnostic>,
78 allow_newline_prefix: bool,
79 inside_brackets: bool,
80 md_default: bool,
81) -> Option<ExprParse> {
82 let ctx = ParserCtx::new(tokens, md_default);
83 let start_non_ws = if allow_newline_prefix {
84 ctx.skip_ws_and_newlines(start)
85 } else {
86 ctx.skip_ws(start)
87 };
88 if matches!(
89 tokens.get(start_non_ws).map(|t| &t.kind),
90 Some(TokKind::IfKw)
91 ) {
92 return parse_if_expr(tokens, start_non_ws, diagnostics, md_default);
93 }
94 if matches!(
95 tokens.get(start_non_ws).map(|t| &t.kind),
96 Some(TokKind::ForKw)
97 ) {
98 return parse_for_expr(tokens, start_non_ws, diagnostics, md_default);
99 }
100 if matches!(
101 tokens.get(start_non_ws).map(|t| &t.kind),
102 Some(TokKind::WhileKw)
103 ) {
104 return parse_while_expr(tokens, start_non_ws, diagnostics, md_default);
105 }
106 if matches!(
107 tokens.get(start_non_ws).map(|t| &t.kind),
108 Some(TokKind::RepeatKw)
109 ) {
110 return parse_repeat_expr(tokens, start_non_ws, diagnostics, md_default);
111 }
112 if matches!(
113 tokens.get(start_non_ws).map(|t| &t.kind),
114 Some(TokKind::FunctionKw)
115 ) {
116 return parse_function_expr(
117 tokens,
118 start_non_ws,
119 inside_brackets,
120 diagnostics,
121 md_default,
122 );
123 }
124 if matches!(
125 tokens.get(start_non_ws).map(|t| &t.kind),
126 Some(TokKind::LambdaFn)
127 ) {
128 return parse_function_expr(
129 tokens,
130 start_non_ws,
131 inside_brackets,
132 diagnostics,
133 md_default,
134 );
135 }
136
137 let mut lhs = parse_prefix(
138 &ctx,
139 start,
140 diagnostics,
141 allow_newline_prefix,
142 inside_brackets,
143 )?;
144
145 if lhs.end == lhs.start + 1 && tokens[lhs.start].kind.is_comment_like() {
152 return Some(lhs);
153 }
154
155 loop {
156 lhs = parse_postfix_chain(&ctx, lhs, inside_brackets, diagnostics);
157
158 let Some((op_idx, op)) = next_operator(&ctx, lhs.end, inside_brackets) else {
159 break;
160 };
161
162 if is_assignment_operator(&op.kind) {
163 let (l_bp, r_bp) = (1, 1);
164 if l_bp < min_bp {
165 break;
166 }
167
168 let rhs_start = op_idx + 1;
169 let rhs_operand = ctx.skip_ws_newlines_comments(rhs_start);
175 let Some(rhs) = parse_expr_with_mode(
176 tokens,
177 rhs_operand,
178 r_bp,
179 diagnostics,
180 true,
181 inside_brackets,
182 ctx.md_default(),
183 ) else {
184 push_token_diagnostic(diagnostics, "expected assignment right-hand side", op);
185 return Some(error_expr_to_line_end(tokens, lhs.start, rhs_start));
186 };
187
188 lhs = build_assignment_expr(lhs, op_idx, rhs);
189 continue;
190 }
191
192 let Some((l_bp, r_bp)) = infix_binding_power(&op.kind) else {
193 break;
194 };
195 if l_bp < min_bp {
196 break;
197 }
198
199 let rhs_start = op_idx + 1;
200 let rhs_operand = ctx.skip_ws_newlines_comments(rhs_start);
205 let rhs = if is_extract_operator(&op.kind) {
214 parse_prefix(&ctx, rhs_operand, diagnostics, true, inside_brackets)
215 } else {
216 parse_expr_with_mode(
217 tokens,
218 rhs_operand,
219 r_bp,
220 diagnostics,
221 true,
222 inside_brackets,
223 ctx.md_default(),
224 )
225 };
226 let Some(rhs) = rhs else {
227 push_token_diagnostic(
228 diagnostics,
229 "expected right-hand side for binary operator",
230 op,
231 );
232 return Some(error_expr_to_line_end(tokens, lhs.start, rhs_start));
233 };
234
235 if op.kind == TokKind::Pipe
236 && let Some(callee_idx) = direct_call_callee(&rhs)
237 && let Some(callee) = tokens.get(callee_idx)
238 && callee.kind == TokKind::Ident
239 && ident_denotes_return(callee.text)
240 {
241 push_token_diagnostic(
242 diagnostics,
243 "function 'return' not supported in RHS call of a pipe",
244 callee,
245 );
246 }
247
248 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
249 && lhs
250 .events
251 .iter()
252 .any(|event| matches!(event, Event::Start(SyntaxKind::CALL_EXPR)))
253 {
254 push_token_diagnostic(
255 diagnostics,
256 "namespace operator requires a package name on the left-hand side",
257 op,
258 );
259 }
260
261 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
262 && matches!(expr_root_kind(&rhs), Some(SyntaxKind::BLOCK_EXPR))
263 {
264 push_token_diagnostic(
265 diagnostics,
266 "namespace operator requires an identifier on the right-hand side",
267 op,
268 );
269 }
270
271 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
272 && matches!(
273 expr_root_kind(&rhs),
274 Some(SyntaxKind::INT | SyntaxKind::FLOAT | SyntaxKind::COMPLEX)
275 )
276 {
277 push_token_diagnostic(
278 diagnostics,
279 "namespace operator requires an identifier on the right-hand side",
280 op,
281 );
282 }
283
284 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
285 && matches!(expr_root_kind(&rhs), Some(SyntaxKind::IDENT))
286 {
287 let rhs_tok_idx = ctx.skip_ws(rhs.start);
288 if let Some(tok) = tokens.get(rhs_tok_idx)
289 && ident_is_special_constant(tok.text)
290 {
291 push_token_diagnostic(
292 diagnostics,
293 "namespace operator requires an identifier on the right-hand side",
294 op,
295 );
296 }
297 }
298
299 if matches!(op.kind, TokKind::Colon2 | TokKind::Colon3)
300 && matches!(expr_root_kind(&lhs), Some(SyntaxKind::BINARY_EXPR))
301 && lhs
302 .events
303 .iter()
304 .any(|event| matches!(event, Event::Tok(idx) if matches!(tokens[*idx].kind, TokKind::Colon2 | TokKind::Colon3)))
305 {
306 push_token_diagnostic(diagnostics, "namespace operator chaining is not allowed", op);
307 }
308
309 lhs = build_binary_expr(lhs, op_idx, rhs);
310 }
311
312 Some(lhs)
313}
314
315fn parse_prefix(
316 ctx: &ParserCtx<'_>,
317 start: usize,
318 diagnostics: &mut Vec<ParseDiagnostic>,
319 allow_newline_prefix: bool,
320 inside_brackets: bool,
321) -> Option<ExprParse> {
322 let tokens = ctx.tokens();
323 let i = if allow_newline_prefix {
324 ctx.skip_ws_and_newlines(start)
325 } else {
326 ctx.skip_ws(start)
327 };
328 let tok = tokens.get(i)?;
329
330 match tok.kind {
331 TokKind::Plus | TokKind::Minus | TokKind::Bang | TokKind::Tilde | TokKind::Question => {
332 let rbp = match tok.kind {
333 TokKind::Tilde => 41,
334 TokKind::Question => 1,
335 TokKind::Bang => 70,
336 _ => 130,
337 };
338 let operand_start = i + 1;
339 let Some(operand) = parse_expr_with_mode(
340 tokens,
341 operand_start,
342 rbp,
343 diagnostics,
344 true,
345 inside_brackets,
346 ctx.md_default(),
347 ) else {
348 push_token_diagnostic(diagnostics, "expected operand for unary operator", tok);
349 return Some(error_expr_to_line_end(tokens, i, operand_start));
350 };
351 let mut events = Vec::new();
352 events.push(Event::Start(SyntaxKind::UNARY_EXPR));
353 events.push(Event::Tok(i));
354 for idx in (i + 1)..operand.start {
355 events.push(Event::Tok(idx));
356 }
357 events.extend(operand.events);
358 events.push(Event::Finish);
359 Some(ExprParse {
360 start: i,
361 end: operand.end,
362 events,
363 })
364 }
365 TokKind::Ident
366 | TokKind::Int
367 | TokKind::Float
368 | TokKind::Complex
369 | TokKind::String
370 | TokKind::Comment
371 | TokKind::UserOp => Some(ExprParse {
372 start: i,
373 end: i + 1,
374 events: vec![Event::Tok(i)],
375 }),
376 TokKind::LParen => {
377 let inner_start = i + 1;
378 let mut expr_start = inner_start;
379 while matches!(
380 tokens.get(expr_start).map(|t| &t.kind),
381 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
382 ) {
383 expr_start += 1;
384 }
385 let Some(inner) = parse_expr_with_mode(
386 tokens,
387 expr_start,
388 0,
389 diagnostics,
390 true,
391 true,
392 ctx.md_default(),
393 ) else {
394 push_token_diagnostic(diagnostics, "expected expression after '('", tok);
395 return Some(error_expr_to_line_end(tokens, i, inner_start));
396 };
397 let mut close_idx = inner.end;
398 while matches!(
399 tokens.get(close_idx).map(|t| &t.kind),
400 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
401 ) {
402 close_idx += 1;
403 }
404 if !matches!(
405 tokens.get(close_idx).map(|t| &t.kind),
406 Some(TokKind::RParen)
407 ) {
408 push_token_diagnostic(diagnostics, "expected ')'", tok);
409 let mut events = Vec::new();
410 events.push(Event::Start(SyntaxKind::PAREN_EXPR));
411 events.push(Event::Tok(i));
412 for idx in inner_start..inner.start {
413 events.push(Event::Tok(idx));
414 }
415 events.extend(inner.events);
416 for idx in inner.end..close_idx {
417 events.push(Event::Tok(idx));
418 }
419 events.push(Event::Finish);
420 return Some(ExprParse {
421 start: i,
422 end: close_idx,
423 events,
424 });
425 }
426
427 let mut events = Vec::new();
428 events.push(Event::Start(SyntaxKind::PAREN_EXPR));
429 events.push(Event::Tok(i));
430 for idx in inner_start..inner.start {
431 events.push(Event::Tok(idx));
432 }
433 events.extend(inner.events);
434 for idx in inner.end..close_idx {
435 events.push(Event::Tok(idx));
436 }
437 events.push(Event::Tok(close_idx));
438 events.push(Event::Finish);
439
440 Some(ExprParse {
441 start: i,
442 end: close_idx + 1,
443 events,
444 })
445 }
446 TokKind::LBrace => parse_block_expr(ctx, i, diagnostics),
447 TokKind::Star
448 | TokKind::Slash
449 | TokKind::Caret
450 | TokKind::AssignLeft
451 | TokKind::SuperAssign
452 | TokKind::AssignRight
453 | TokKind::SuperAssignRight
454 | TokKind::AssignEq
455 | TokKind::Walrus
456 | TokKind::Colon
457 | TokKind::Or
458 | TokKind::Or2
459 | TokKind::And
460 | TokKind::And2
461 | TokKind::Equal2
462 | TokKind::NotEqual
463 | TokKind::LessThan
464 | TokKind::LessThanOrEqual
465 | TokKind::GreaterThan
466 | TokKind::GreaterThanOrEqual
467 | TokKind::Colon2
468 | TokKind::Colon3
469 | TokKind::Dollar
470 | TokKind::At
471 | TokKind::Semicolon
472 | TokKind::Comma
473 | TokKind::Pipe => {
474 push_token_diagnostic(diagnostics, "unexpected operator at expression start", tok);
475 Some(error_expr_to_line_end(tokens, i, i + 1))
476 }
477 TokKind::Whitespace
478 | TokKind::Newline
479 | TokKind::RParen
480 | TokKind::RBrack
481 | TokKind::RBrack2
482 | TokKind::RBrace
483 | TokKind::IfKw
484 | TokKind::ElseKw
485 | TokKind::ForKw
486 | TokKind::WhileKw
487 | TokKind::RepeatKw
488 | TokKind::FunctionKw
489 | TokKind::LambdaFn
490 | TokKind::InKw
491 | TokKind::LBrack
492 | TokKind::LBrack2
493 | TokKind::RoxygenMarker
494 | TokKind::RoxygenAt
495 | TokKind::RoxygenTagName
496 | TokKind::RoxygenTagArg
497 | TokKind::RoxygenText
498 | TokKind::RoxygenCode
499 | TokKind::RoxygenRdMacro
500 | TokKind::RoxygenMdLink
501 | TokKind::RoxygenMdBracket
502 | TokKind::RoxygenMdImage
503 | TokKind::RoxygenMdDelim
504 | TokKind::RoxygenMdCode
505 | TokKind::RoxygenMdListMarker
506 | TokKind::RoxygenMdFence
507 | TokKind::RoxygenMdHtml
508 | TokKind::RoxygenMdHtmlBlock
509 | TokKind::RoxygenMdTableDelim
510 | TokKind::RoxygenMdHeading
511 | TokKind::RoxygenMdSetextUnderline
512 | TokKind::RoxygenMdBlockQuote
513 | TokKind::RoxygenMdThematicBreak
514 | TokKind::Unknown => None,
515 }
516}
517
518fn parse_block_expr(
519 ctx: &ParserCtx<'_>,
520 start: usize,
521 diagnostics: &mut Vec<ParseDiagnostic>,
522) -> Option<ExprParse> {
523 let tokens = ctx.tokens();
524 let mut i = start + 1;
525 let mut events = vec![Event::Start(SyntaxKind::BLOCK_EXPR), Event::Tok(start)];
526 let mut statements = StatementTracker::default();
527
528 loop {
529 let next = ctx.skip_ws(i);
530 let Some(tok) = tokens.get(next) else {
531 push_token_diagnostic(diagnostics, "expected '}' to close block", &tokens[start]);
532 for idx in i..tokens.len() {
533 events.push(Event::Tok(idx));
534 }
535 events.push(Event::Finish);
536 return Some(ExprParse {
537 start,
538 end: tokens.len(),
539 events,
540 });
541 };
542
543 if tok.kind == TokKind::RBrace {
544 for idx in i..next {
545 events.push(Event::Tok(idx));
546 }
547 events.push(Event::Tok(next));
548 events.push(Event::Finish);
549 return Some(ExprParse {
550 start,
551 end: next + 1,
552 events,
553 });
554 }
555
556 if matches!(tok.kind, TokKind::Newline | TokKind::Semicolon) {
558 for idx in i..=next {
559 events.push(Event::Tok(idx));
560 }
561 i = next + 1;
562 continue;
563 }
564
565 if tok.kind == TokKind::RoxygenMarker {
566 for idx in i..next {
568 events.push(Event::Tok(idx));
569 }
570 i = crate::parser::roxygen::emit_roxygen_block(
571 tokens,
572 next,
573 &mut events,
574 ctx.md_default(),
575 );
576 continue;
577 }
578
579 let before = diagnostics.len();
580 if let Some(expr) = parse_expr(tokens, i, 0, diagnostics, ctx.md_default()) {
581 if !tokens[expr.start].kind.is_comment_like() {
583 let recovered = diagnostics.len() > before;
584 statements.record(tokens, expr.start, expr.end, recovered, diagnostics);
585 }
586 for idx in i..expr.start {
587 events.push(Event::Tok(idx));
588 }
589 events.extend(expr.events);
590 i = expr.end;
591 } else {
592 events.push(Event::Tok(i));
593 i += 1;
594 statements.record_recovery(i);
595 }
596 }
597}
598
599fn parse_postfix_chain(
600 ctx: &ParserCtx<'_>,
601 mut lhs: ExprParse,
602 inside_brackets: bool,
603 diagnostics: &mut Vec<ParseDiagnostic>,
604) -> ExprParse {
605 let tokens = ctx.tokens();
606 loop {
607 let after_lhs = if inside_brackets {
612 ctx.skip_ws_and_newlines(lhs.end)
613 } else {
614 ctx.skip_ws(lhs.end)
615 };
616 if matches!(
617 tokens.get(after_lhs).map(|t| &t.kind),
618 Some(TokKind::LParen)
619 ) {
620 lhs = parse_call_expr(ctx, lhs, after_lhs, diagnostics);
621 continue;
622 }
623 if matches!(
624 tokens.get(after_lhs).map(|t| &t.kind),
625 Some(TokKind::LBrack)
626 ) {
627 lhs = parse_subset_expr(ctx, lhs, after_lhs, diagnostics);
628 continue;
629 }
630 if matches!(
631 tokens.get(after_lhs).map(|t| &t.kind),
632 Some(TokKind::LBrack2)
633 ) {
634 lhs = parse_subset2_expr(ctx, lhs, after_lhs, diagnostics);
635 continue;
636 }
637 break;
638 }
639 lhs
640}
641
642fn build_binary_like_expr(
643 kind: SyntaxKind,
644 lhs: ExprParse,
645 op_idx: usize,
646 rhs: ExprParse,
647) -> ExprParse {
648 let mut events = Vec::new();
649 events.push(Event::Start(kind));
650 events.extend(lhs.events);
651 for idx in lhs.end..op_idx {
652 events.push(Event::Tok(idx));
653 }
654 events.push(Event::Tok(op_idx));
655 for idx in (op_idx + 1)..rhs.start {
656 events.push(Event::Tok(idx));
657 }
658 events.extend(rhs.events);
659 events.push(Event::Finish);
660
661 ExprParse {
662 start: lhs.start,
663 end: rhs.end,
664 events,
665 }
666}
667
668fn build_binary_expr(lhs: ExprParse, op_idx: usize, rhs: ExprParse) -> ExprParse {
669 build_binary_like_expr(SyntaxKind::BINARY_EXPR, lhs, op_idx, rhs)
670}
671
672fn build_assignment_expr(lhs: ExprParse, op_idx: usize, rhs: ExprParse) -> ExprParse {
673 build_binary_like_expr(SyntaxKind::ASSIGNMENT_EXPR, lhs, op_idx, rhs)
674}
675
676fn is_named_arg(ctx: &ParserCtx<'_>, i: usize) -> bool {
681 let tokens = ctx.tokens();
682 if !matches!(
683 tokens.get(i).map(|t| &t.kind),
684 Some(TokKind::Ident | TokKind::String)
685 ) {
686 return false;
687 }
688 let mut next = i + 1;
689 while matches!(
690 tokens.get(next).map(|t| &t.kind),
691 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
692 ) {
693 next += 1;
694 }
695 matches!(tokens.get(next).map(|t| &t.kind), Some(TokKind::AssignEq))
696}
697
698fn has_newline(tokens: &[Token], start: usize, end: usize) -> bool {
699 tokens[start..end]
700 .iter()
701 .any(|t| t.kind == TokKind::Newline)
702}
703
704fn expr_root_kind(expr: &ExprParse) -> Option<SyntaxKind> {
705 expr.events.iter().find_map(|event| match event {
706 Event::Start(kind) => Some(*kind),
707 _ => None,
708 })
709}
710
711fn direct_call_callee(expr: &ExprParse) -> Option<usize> {
717 let mut events = expr.events.iter();
718 if !matches!(events.next(), Some(Event::Start(SyntaxKind::CALL_EXPR))) {
719 return None;
720 }
721 match events.next()? {
722 Event::Tok(idx) => Some(*idx),
723 Event::Start(_) | Event::Leaf(_, _) | Event::Finish => None,
724 }
725}
726
727fn ident_denotes_return(text: &str) -> bool {
733 if text == "return" {
734 return true;
735 }
736 let Some(body) = text
737 .strip_prefix('`')
738 .and_then(|body| body.strip_suffix('`'))
739 else {
740 return false;
741 };
742
743 let expected = b"return";
744 let bytes = body.as_bytes();
745 let mut input = 0;
746 let mut output = 0;
747 while input < bytes.len() {
748 let decoded = if bytes[input] != b'\\' {
749 let byte = bytes[input];
750 input += 1;
751 byte
752 } else {
753 input += 1;
754 let Some(&escape) = bytes.get(input) else {
755 return false;
756 };
757 if escape == b'x' {
758 input += 1;
759 let Some((byte, end)) = decode_ascii_escape(bytes, input, 16, 2) else {
760 return false;
761 };
762 input = end;
763 byte
764 } else if matches!(escape, b'0'..=b'7') {
765 let Some((byte, end)) = decode_ascii_escape(bytes, input, 8, 3) else {
766 return false;
767 };
768 input = end;
769 byte
770 } else {
771 return false;
772 }
773 };
774
775 if expected.get(output) != Some(&decoded) {
776 return false;
777 }
778 output += 1;
779 }
780 output == expected.len()
781}
782
783fn decode_ascii_escape(
784 bytes: &[u8],
785 start: usize,
786 radix: u32,
787 max_digits: usize,
788) -> Option<(u8, usize)> {
789 let mut value = 0_u8;
790 let mut end = start;
791 while end < bytes.len() && end - start < max_digits {
792 let Some(digit) = (bytes[end] as char).to_digit(radix) else {
793 break;
794 };
795 value = value.checked_mul(radix as u8)?.checked_add(digit as u8)?;
796 end += 1;
797 }
798 (end > start).then_some((value, end))
799}
800
801pub fn ident_is_special_constant(text: &str) -> bool {
802 matches!(
803 text,
804 "NA" | "NULL"
805 | "TRUE"
806 | "FALSE"
807 | "Inf"
808 | "NaN"
809 | "NA_integer_"
810 | "NA_real_"
811 | "NA_complex_"
812 | "NA_character_"
813 )
814}
815
816fn parse_call_expr(
817 ctx: &ParserCtx<'_>,
818 callee: ExprParse,
819 lparen_idx: usize,
820 diagnostics: &mut Vec<ParseDiagnostic>,
821) -> ExprParse {
822 let tokens = ctx.tokens();
823 let mut events = vec![Event::Start(SyntaxKind::CALL_EXPR)];
824 events.extend(callee.events);
825 for idx in callee.end..lparen_idx {
827 events.push(Event::Tok(idx));
828 }
829 events.push(Event::Tok(lparen_idx)); events.push(Event::Start(SyntaxKind::ARG_LIST));
832 let mut i = lparen_idx + 1;
833
834 let mut expect_delimiter = false;
835 let mut last_arg_was_comment_only = false;
836 loop {
837 let next_i = ctx.skip_ws_and_newlines(i);
839 let had_newline_gap = has_newline(tokens, i, next_i);
840 for idx in i..next_i {
841 events.push(Event::Tok(idx));
842 }
843 i = next_i;
844
845 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RParen) | None) {
847 break;
848 }
849
850 if expect_delimiter
851 && !had_newline_gap
852 && let Some(tok) = tokens.get(i)
853 {
854 let current_is_comment = tok.kind == TokKind::Comment;
855 if !current_is_comment && !last_arg_was_comment_only {
856 push_token_diagnostic(diagnostics, "expected ',' between arguments", tok);
857 }
858 }
859
860 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
862 events.push(Event::Start(SyntaxKind::ARG));
863 events.push(Event::Finish);
864 events.push(Event::Tok(i)); i += 1;
866 expect_delimiter = false;
867 last_arg_was_comment_only = false;
868 continue;
869 }
870
871 events.push(Event::Start(SyntaxKind::ARG));
872 last_arg_was_comment_only = false;
873
874 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RoxygenMarker)) {
875 i = crate::parser::roxygen::emit_roxygen_block(
881 tokens,
882 i,
883 &mut events,
884 ctx.md_default(),
885 );
886 last_arg_was_comment_only = true;
887 } else if is_named_arg(ctx, i) {
888 events.push(Event::Tok(i)); let mut eq_idx = i + 1;
891 while matches!(
892 tokens.get(eq_idx).map(|t| &t.kind),
893 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
894 ) {
895 eq_idx += 1;
896 }
897 for idx in (i + 1)..eq_idx {
898 events.push(Event::Tok(idx));
899 }
900 if !matches!(tokens.get(eq_idx).map(|t| &t.kind), Some(TokKind::AssignEq)) {
901 events.push(Event::Finish); expect_delimiter = true;
903 i = eq_idx;
904 continue;
905 }
906 events.push(Event::Tok(eq_idx)); let val_start = eq_idx + 1;
908 let mut value_idx = val_start;
909 while matches!(
910 tokens.get(value_idx).map(|t| &t.kind),
911 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
912 ) {
913 value_idx += 1;
914 }
915 if matches!(
916 tokens.get(value_idx).map(|t| &t.kind),
917 Some(TokKind::Comma | TokKind::RParen) | None
918 ) {
919 for idx in val_start..value_idx {
920 events.push(Event::Tok(idx));
921 }
922 i = value_idx;
923 } else if let Some(val) =
924 parse_expr_in_brackets(tokens, value_idx, 0, diagnostics, ctx.md_default())
925 {
926 for idx in val_start..val.start {
927 events.push(Event::Tok(idx));
928 }
929 events.extend(val.events);
930 i = val.end;
931 } else {
932 i = val_start;
933 }
934 } else {
935 if let Some(arg) = parse_expr_in_brackets(tokens, i, 0, diagnostics, ctx.md_default()) {
937 last_arg_was_comment_only = arg.end == arg.start + 1
938 && matches!(
939 tokens.get(arg.start).map(|t| &t.kind),
940 Some(TokKind::Comment)
941 );
942 for idx in i..arg.start {
943 events.push(Event::Tok(idx));
944 }
945 events.extend(arg.events);
946 i = arg.end;
947 } else {
948 last_arg_was_comment_only = false;
949 events.push(Event::Tok(i));
950 i += 1;
951 }
952 }
953
954 events.push(Event::Finish); expect_delimiter = true;
956
957 let next_i = ctx.skip_ws_and_newlines(i);
959 for idx in i..next_i {
960 events.push(Event::Tok(idx));
961 }
962 i = next_i;
963
964 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
965 events.push(Event::Tok(i)); i += 1;
967 expect_delimiter = false;
968 last_arg_was_comment_only = false;
969 }
970 }
971
972 events.push(Event::Finish); let next_i = ctx.skip_ws_and_newlines(i);
976 for idx in i..next_i {
977 events.push(Event::Tok(idx));
978 }
979 i = next_i;
980
981 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RParen)) {
982 events.push(Event::Tok(i));
983 i += 1;
984 } else if let Some(tok) = tokens.get(lparen_idx) {
985 push_token_diagnostic(diagnostics, "expected ')' to close function call", tok);
986 }
987
988 events.push(Event::Finish); ExprParse {
991 start: callee.start,
992 end: i,
993 events,
994 }
995}
996
997fn parse_subset_expr(
998 ctx: &ParserCtx<'_>,
999 target: ExprParse,
1000 lbrack_idx: usize,
1001 diagnostics: &mut Vec<ParseDiagnostic>,
1002) -> ExprParse {
1003 parse_bracket_expr(
1004 ctx,
1005 target,
1006 lbrack_idx,
1007 SyntaxKind::SUBSET_EXPR,
1008 diagnostics,
1009 )
1010}
1011
1012fn parse_subset2_expr(
1013 ctx: &ParserCtx<'_>,
1014 target: ExprParse,
1015 lbrack2_idx: usize,
1016 diagnostics: &mut Vec<ParseDiagnostic>,
1017) -> ExprParse {
1018 parse_bracket_expr(
1019 ctx,
1020 target,
1021 lbrack2_idx,
1022 SyntaxKind::SUBSET2_EXPR,
1023 diagnostics,
1024 )
1025}
1026
1027fn parse_bracket_expr(
1028 ctx: &ParserCtx<'_>,
1029 target: ExprParse,
1030 open_idx: usize,
1031 node_kind: SyntaxKind,
1032 diagnostics: &mut Vec<ParseDiagnostic>,
1033) -> ExprParse {
1034 let tokens = ctx.tokens();
1035 let mut events = vec![Event::Start(node_kind)];
1036 events.extend(target.events);
1037 for idx in target.end..open_idx {
1038 events.push(Event::Tok(idx));
1039 }
1040 events.push(Event::Tok(open_idx));
1041
1042 events.push(Event::Start(SyntaxKind::ARG_LIST));
1043 let mut i = open_idx + 1;
1044
1045 let mut expect_delimiter = false;
1046 let mut last_arg_was_comment_only = false;
1047 loop {
1048 let next_i = ctx.skip_ws_and_newlines(i);
1049 let had_newline_gap = has_newline(tokens, i, next_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) || tokens.get(i).is_none() {
1056 break;
1057 }
1058
1059 if expect_delimiter
1060 && !had_newline_gap
1061 && let Some(tok) = tokens.get(i)
1062 {
1063 let current_is_comment = tok.kind == TokKind::Comment;
1064 if !current_is_comment && !last_arg_was_comment_only {
1065 push_token_diagnostic(diagnostics, "expected ',' between subset arguments", tok);
1066 }
1067 }
1068
1069 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
1070 events.push(Event::Start(SyntaxKind::ARG));
1071 events.push(Event::Finish);
1072 events.push(Event::Tok(i));
1073 i += 1;
1074 expect_delimiter = false;
1075 last_arg_was_comment_only = false;
1076 continue;
1077 }
1078
1079 events.push(Event::Start(SyntaxKind::ARG));
1080 last_arg_was_comment_only = false;
1081
1082 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RoxygenMarker)) {
1083 i = crate::parser::roxygen::emit_roxygen_block(
1086 tokens,
1087 i,
1088 &mut events,
1089 ctx.md_default(),
1090 );
1091 last_arg_was_comment_only = true;
1092 } else if is_named_arg(ctx, i) {
1093 events.push(Event::Tok(i)); let mut eq_idx = i + 1;
1099 while matches!(
1100 tokens.get(eq_idx).map(|t| &t.kind),
1101 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
1102 ) {
1103 eq_idx += 1;
1104 }
1105 for idx in (i + 1)..eq_idx {
1106 events.push(Event::Tok(idx));
1107 }
1108 events.push(Event::Tok(eq_idx)); let val_start = eq_idx + 1;
1111 let mut value_idx = val_start;
1112 while matches!(
1113 tokens.get(value_idx).map(|t| &t.kind),
1114 Some(TokKind::Whitespace | TokKind::Newline | TokKind::Comment)
1115 ) {
1116 value_idx += 1;
1117 }
1118 if matches!(
1119 tokens.get(value_idx).map(|t| &t.kind),
1120 Some(TokKind::Comma) | None
1121 ) || is_matching_subset_close(tokens, value_idx, node_kind)
1122 {
1123 for idx in val_start..value_idx {
1125 events.push(Event::Tok(idx));
1126 }
1127 i = value_idx;
1128 } else if let Some(val) =
1129 parse_expr_in_brackets(tokens, value_idx, 0, diagnostics, ctx.md_default())
1130 {
1131 for idx in val_start..val.start {
1132 events.push(Event::Tok(idx));
1133 }
1134 events.extend(val.events);
1135 i = val.end;
1136 } else {
1137 i = val_start;
1138 }
1139 } else if let Some(arg) =
1140 parse_expr_in_brackets(tokens, i, 0, diagnostics, ctx.md_default())
1141 {
1142 last_arg_was_comment_only = arg.end == arg.start + 1
1143 && matches!(
1144 tokens.get(arg.start).map(|t| &t.kind),
1145 Some(TokKind::Comment)
1146 );
1147 for idx in i..arg.start {
1148 events.push(Event::Tok(idx));
1149 }
1150 events.extend(arg.events);
1151 i = arg.end;
1152 } else {
1153 last_arg_was_comment_only = false;
1154 events.push(Event::Tok(i));
1155 i += 1;
1156 }
1157 events.push(Event::Finish);
1158 expect_delimiter = true;
1159
1160 let next_i = ctx.skip_ws_and_newlines(i);
1161 for idx in i..next_i {
1162 events.push(Event::Tok(idx));
1163 }
1164 i = next_i;
1165 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::Comma)) {
1166 events.push(Event::Tok(i));
1167 i += 1;
1168 expect_delimiter = false;
1169 last_arg_was_comment_only = false;
1170 }
1171 }
1172
1173 events.push(Event::Finish); let next_i = ctx.skip_ws_and_newlines(i);
1175 for idx in i..next_i {
1176 events.push(Event::Tok(idx));
1177 }
1178 i = next_i;
1179
1180 if is_matching_subset_close(tokens, i, node_kind) {
1181 match node_kind {
1182 SyntaxKind::SUBSET_EXPR => {
1183 if matches!(tokens.get(i).map(|t| &t.kind), Some(TokKind::RBrack2)) {
1184 events.push(Event::Tok(i)); i += 1;
1186 } else {
1187 events.push(Event::Tok(i));
1188 i += 1;
1189 }
1190 }
1191 SyntaxKind::SUBSET2_EXPR => {
1192 events.push(Event::Tok(i));
1193 i += 1;
1194 }
1195 _ => {}
1196 }
1197 } else if node_kind == SyntaxKind::SUBSET_EXPR
1198 && matches!(previous_non_trivia_kind(tokens, i), Some(TokKind::RBrack2))
1199 {
1200 } else if let Some(tok) = tokens.get(open_idx) {
1203 push_token_diagnostic(
1204 diagnostics,
1205 "expected closing bracket in subset expression",
1206 tok,
1207 );
1208 }
1209
1210 events.push(Event::Finish);
1211 ExprParse {
1212 start: target.start,
1213 end: i,
1214 events,
1215 }
1216}
1217
1218fn is_matching_subset_close(tokens: &[Token], idx: usize, node_kind: SyntaxKind) -> bool {
1219 match node_kind {
1220 SyntaxKind::SUBSET_EXPR => matches!(
1221 tokens.get(idx).map(|t| &t.kind),
1222 Some(TokKind::RBrack | TokKind::RBrack2)
1223 ),
1224 SyntaxKind::SUBSET2_EXPR => {
1225 matches!(tokens.get(idx).map(|t| &t.kind), Some(TokKind::RBrack2))
1226 }
1227 _ => false,
1228 }
1229}
1230
1231fn previous_non_trivia_kind(tokens: &[Token], mut idx: usize) -> Option<TokKind> {
1232 if idx == 0 {
1233 return None;
1234 }
1235 idx -= 1;
1236 loop {
1237 let tok = tokens.get(idx)?;
1238 if !matches!(tok.kind, TokKind::Whitespace | TokKind::Newline) {
1239 return Some(tok.kind.clone());
1240 }
1241 if idx == 0 {
1242 return None;
1243 }
1244 idx -= 1;
1245 }
1246}
1247
1248fn is_extract_operator(kind: &TokKind) -> bool {
1253 matches!(
1254 kind,
1255 TokKind::Dollar | TokKind::At | TokKind::Colon2 | TokKind::Colon3
1256 )
1257}
1258
1259fn infix_binding_power(kind: &TokKind) -> Option<(u8, u8)> {
1260 match kind {
1261 TokKind::Question => Some((0, 1)),
1262 TokKind::Or | TokKind::Or2 => Some((50, 51)),
1263 TokKind::And | TokKind::And2 => Some((60, 61)),
1264 TokKind::Equal2
1265 | TokKind::NotEqual
1266 | TokKind::LessThan
1267 | TokKind::LessThanOrEqual
1268 | TokKind::GreaterThan
1269 | TokKind::GreaterThanOrEqual => Some((80, 81)),
1270 TokKind::Plus | TokKind::Minus => Some((90, 91)),
1271 TokKind::Star | TokKind::Slash => Some((100, 101)),
1272 TokKind::Pipe | TokKind::UserOp => Some((110, 111)),
1273 TokKind::Colon => Some((120, 121)),
1274 TokKind::Tilde => Some((40, 41)),
1275 TokKind::Caret => Some((140, 140)),
1276 TokKind::Colon2 | TokKind::Colon3 | TokKind::Dollar | TokKind::At => Some((150, 151)),
1277 _ => None,
1278 }
1279}