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