1use nom::{
15 branch::alt,
16 bytes::complete::{tag, tag_no_case, take_while1},
17 character::complete::{alpha1, char, multispace0},
18 combinator::{map, opt, recognize, value},
19 multi::{many0, separated_list0},
20 sequence::{delimited, pair, preceded, terminated},
21 IResult,
22};
23
24use super::ast::{BinaryOperator, CellReference, Expr, UnaryOperator};
25use crate::error::{Error, Result};
26
27pub fn parse_formula(input: &str) -> Result<Expr> {
35 let trimmed = input.trim();
36 if trimmed.is_empty() {
37 return Err(Error::Internal("empty formula".to_string()));
38 }
39 match parse_expr(trimmed) {
40 Ok(("", expr)) => Ok(expr),
41 Ok((remaining, _)) => Err(Error::Internal(format!(
42 "unexpected trailing input: {remaining}"
43 ))),
44 Err(e) => Err(Error::Internal(format!("formula parse error: {e}"))),
45 }
46}
47
48fn ws<'a, F, O>(inner: F) -> impl FnMut(&'a str) -> IResult<&'a str, O>
50where
51 F: FnMut(&'a str) -> IResult<&'a str, O>,
52{
53 delimited(multispace0, inner, multispace0)
54}
55
56fn parse_expr(input: &str) -> IResult<&str, Expr> {
58 let (input, left) = parse_concat_expr(input)?;
59 let (input, rest) = many0(pair(ws(parse_comparison_op), parse_concat_expr))(input)?;
60 Ok((input, fold_binary(left, rest)))
61}
62
63fn parse_comparison_op(input: &str) -> IResult<&str, BinaryOperator> {
64 alt((
65 value(BinaryOperator::Le, tag("<=")),
66 value(BinaryOperator::Ge, tag(">=")),
67 value(BinaryOperator::Ne, tag("<>")),
68 value(BinaryOperator::Lt, tag("<")),
69 value(BinaryOperator::Gt, tag(">")),
70 value(BinaryOperator::Eq, tag("=")),
71 ))(input)
72}
73
74fn parse_concat_expr(input: &str) -> IResult<&str, Expr> {
76 let (input, left) = parse_additive(input)?;
77 let (input, rest) = many0(pair(
78 ws(value(BinaryOperator::Concat, tag("&"))),
79 parse_additive,
80 ))(input)?;
81 Ok((input, fold_binary(left, rest)))
82}
83
84fn parse_additive(input: &str) -> IResult<&str, Expr> {
86 let (input, left) = parse_multiplicative(input)?;
87 let (input, rest) = many0(pair(ws(parse_add_sub_op), parse_multiplicative))(input)?;
88 Ok((input, fold_binary(left, rest)))
89}
90
91fn parse_add_sub_op(input: &str) -> IResult<&str, BinaryOperator> {
92 alt((
93 value(BinaryOperator::Add, tag("+")),
94 value(BinaryOperator::Sub, tag("-")),
95 ))(input)
96}
97
98fn parse_multiplicative(input: &str) -> IResult<&str, Expr> {
100 let (input, left) = parse_power(input)?;
101 let (input, rest) = many0(pair(ws(parse_mul_div_op), parse_power))(input)?;
102 Ok((input, fold_binary(left, rest)))
103}
104
105fn parse_mul_div_op(input: &str) -> IResult<&str, BinaryOperator> {
106 alt((
107 value(BinaryOperator::Mul, tag("*")),
108 value(BinaryOperator::Div, tag("/")),
109 ))(input)
110}
111
112fn parse_power(input: &str) -> IResult<&str, Expr> {
114 let (input, left) = parse_unary(input)?;
115 let (input, rest) = many0(pair(ws(value(BinaryOperator::Pow, tag("^"))), parse_unary))(input)?;
116 Ok((input, fold_binary(left, rest)))
117}
118
119fn parse_unary(input: &str) -> IResult<&str, Expr> {
121 let input = input.trim_start();
122 if let Ok((rest, _)) = tag::<&str, &str, nom::error::Error<&str>>("-")(input) {
124 let (rest, operand) = parse_unary(rest)?;
125 return Ok((
126 rest,
127 Expr::UnaryOp {
128 op: UnaryOperator::Neg,
129 operand: Box::new(operand),
130 },
131 ));
132 }
133 if let Ok((rest, _)) = tag::<&str, &str, nom::error::Error<&str>>("+")(input) {
135 let (rest, operand) = parse_unary(rest)?;
136 return Ok((
137 rest,
138 Expr::UnaryOp {
139 op: UnaryOperator::Pos,
140 operand: Box::new(operand),
141 },
142 ));
143 }
144 let (input, expr) = parse_primary(input)?;
146 let (input, pcts) = many0(ws(value(UnaryOperator::Percent, tag("%"))))(input)?;
147 let result = pcts.into_iter().fold(expr, |acc, op| Expr::UnaryOp {
148 op,
149 operand: Box::new(acc),
150 });
151 Ok((input, result))
152}
153
154fn parse_primary(input: &str) -> IResult<&str, Expr> {
156 let input = input.trim_start();
157 alt((
158 parse_paren_expr,
159 parse_string_literal,
160 parse_error_literal,
161 parse_bool_literal,
162 parse_function_call,
163 parse_cell_ref_or_range,
164 parse_number_literal,
165 ))(input)
166}
167
168fn parse_number_literal(input: &str) -> IResult<&str, Expr> {
170 let (input, num_str) = recognize(pair(
171 take_while1(|c: char| c.is_ascii_digit()),
172 opt(pair(tag("."), take_while1(|c: char| c.is_ascii_digit()))),
173 ))(input)?;
174 let n: f64 = num_str.parse().map_err(|_| {
175 nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Float))
176 })?;
177 Ok((input, Expr::Number(n)))
178}
179
180fn parse_string_literal(input: &str) -> IResult<&str, Expr> {
182 let (input, _) = tag("\"")(input)?;
183 let mut result = String::new();
184 let mut remaining = input;
185 loop {
186 if remaining.is_empty() {
187 return Err(nom::Err::Error(nom::error::Error::new(
188 remaining,
189 nom::error::ErrorKind::Tag,
190 )));
191 }
192 if remaining.starts_with("\"\"") {
193 result.push('"');
194 remaining = &remaining[2..];
195 } else if remaining.starts_with('"') {
196 remaining = &remaining[1..];
197 break;
198 } else {
199 let c = remaining.chars().next().unwrap();
200 result.push(c);
201 remaining = &remaining[c.len_utf8()..];
202 }
203 }
204 Ok((remaining, Expr::String(result)))
205}
206
207fn parse_bool_literal(input: &str) -> IResult<&str, Expr> {
209 let (input, val) = alt((
210 value(
211 true,
212 terminated(tag_no_case("TRUE"), not_alnum_or_underscore),
213 ),
214 value(
215 false,
216 terminated(tag_no_case("FALSE"), not_alnum_or_underscore),
217 ),
218 ))(input)?;
219 Ok((input, Expr::Bool(val)))
220}
221
222fn not_alnum_or_underscore(input: &str) -> IResult<&str, ()> {
225 if input.is_empty() {
226 return Ok((input, ()));
227 }
228 let c = input.chars().next().unwrap();
229 if c.is_alphanumeric() || c == '_' {
230 Err(nom::Err::Error(nom::error::Error::new(
231 input,
232 nom::error::ErrorKind::Alpha,
233 )))
234 } else {
235 Ok((input, ()))
236 }
237}
238
239fn parse_error_literal(input: &str) -> IResult<&str, Expr> {
241 let (input, err) = alt((
242 tag("#DIV/0!"),
243 tag("#VALUE!"),
244 tag("#REF!"),
245 tag("#NAME?"),
246 tag("#NUM!"),
247 tag("#NULL!"),
248 tag("#N/A"),
249 ))(input)?;
250 Ok((input, Expr::Error(err.to_string())))
251}
252
253fn parse_cell_ref_or_range(input: &str) -> IResult<&str, Expr> {
255 let (input, first) = parse_single_cell_ref(input)?;
256 if let Ok((input, _)) = tag::<&str, &str, nom::error::Error<&str>>(":")(input) {
258 let (input, second) = parse_single_cell_ref(input)?;
259 Ok((
260 input,
261 Expr::Range {
262 start: first,
263 end: second,
264 },
265 ))
266 } else {
267 Ok((input, Expr::CellRef(first)))
268 }
269}
270
271fn parse_single_cell_ref(input: &str) -> IResult<&str, CellReference> {
273 let (input, sheet) = opt(parse_sheet_prefix)(input)?;
275 let (input, abs_col) = map(opt(tag("$")), |o| o.is_some())(input)?;
277 let (input, col) = alpha1(input)?;
279 let col_upper = col.to_uppercase();
281 if !col_upper.chars().all(|c| c.is_ascii_uppercase()) {
282 return Err(nom::Err::Error(nom::error::Error::new(
283 input,
284 nom::error::ErrorKind::Alpha,
285 )));
286 }
287 let (input, abs_row) = map(opt(tag("$")), |o| o.is_some())(input)?;
289 let (input, row_str) = take_while1(|c: char| c.is_ascii_digit())(input)?;
291 let row: u32 = row_str.parse().map_err(|_| {
292 nom::Err::Error(nom::error::Error::new(input, nom::error::ErrorKind::Digit))
293 })?;
294 Ok((
295 input,
296 CellReference {
297 col: col_upper,
298 row,
299 abs_col,
300 abs_row,
301 sheet,
302 },
303 ))
304}
305
306fn parse_sheet_prefix(input: &str) -> IResult<&str, String> {
308 alt((parse_quoted_sheet_prefix, parse_unquoted_sheet_prefix))(input)
309}
310
311fn parse_unquoted_sheet_prefix(input: &str) -> IResult<&str, String> {
313 let (input, name) = terminated(
314 recognize(pair(
315 take_while1(|c: char| c.is_alphanumeric() || c == '_'),
316 many0(take_while1(|c: char| c.is_alphanumeric() || c == '_')),
317 )),
318 tag("!"),
319 )(input)?;
320 Ok((input, name.to_string()))
321}
322
323fn parse_quoted_sheet_prefix(input: &str) -> IResult<&str, String> {
325 let (input, _) = tag("'")(input)?;
326 let mut result = String::new();
327 let mut remaining = input;
328 loop {
329 if remaining.is_empty() {
330 return Err(nom::Err::Error(nom::error::Error::new(
331 remaining,
332 nom::error::ErrorKind::Tag,
333 )));
334 }
335 if remaining.starts_with("''") {
336 result.push('\'');
337 remaining = &remaining[2..];
338 } else if remaining.starts_with('\'') {
339 remaining = &remaining[1..];
340 break;
341 } else {
342 let c = remaining.chars().next().unwrap();
343 result.push(c);
344 remaining = &remaining[c.len_utf8()..];
345 }
346 }
347 let (remaining, _) = tag("!")(remaining)?;
348 Ok((remaining, result))
349}
350
351fn parse_function_call(input: &str) -> IResult<&str, Expr> {
353 let (input, name) = recognize(pair(
355 alt((alpha1, tag("_"))),
356 many0(alt((
357 take_while1(|c: char| c.is_alphanumeric() || c == '_'),
358 tag("."),
359 ))),
360 ))(input)?;
361 let (input, _) = preceded(multispace0, char('('))(input)?;
363 let (input, _) = multispace0(input)?;
364 let (input, args) = separated_list0(ws(char(',')), parse_expr)(input)?;
366 let (input, _) = preceded(multispace0, char(')'))(input)?;
367 Ok((
368 input,
369 Expr::Function {
370 name: name.to_uppercase(),
371 args,
372 },
373 ))
374}
375
376fn parse_paren_expr(input: &str) -> IResult<&str, Expr> {
378 let (input, _) = char('(')(input)?;
379 let (input, _) = multispace0(input)?;
380 let (input, expr) = parse_expr(input)?;
381 let (input, _) = preceded(multispace0, char(')'))(input)?;
382 Ok((input, Expr::Paren(Box::new(expr))))
383}
384
385fn fold_binary(first: Expr, rest: Vec<(BinaryOperator, Expr)>) -> Expr {
387 rest.into_iter()
388 .fold(first, |left, (op, right)| Expr::BinaryOp {
389 op,
390 left: Box::new(left),
391 right: Box::new(right),
392 })
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use crate::formula::ast::{BinaryOperator, CellReference, Expr, UnaryOperator};
399
400 #[test]
401 fn test_parse_integer() {
402 let result = parse_formula("42").unwrap();
403 assert_eq!(result, Expr::Number(42.0));
404 }
405
406 #[test]
407 fn test_parse_decimal() {
408 let result = parse_formula("3.15").unwrap();
409 assert_eq!(result, Expr::Number(3.15));
410 }
411
412 #[test]
413 fn test_parse_negative_number() {
414 let result = parse_formula("-5").unwrap();
415 assert_eq!(
416 result,
417 Expr::UnaryOp {
418 op: UnaryOperator::Neg,
419 operand: Box::new(Expr::Number(5.0)),
420 }
421 );
422 }
423
424 #[test]
425 fn test_parse_string() {
426 let result = parse_formula("\"hello\"").unwrap();
427 assert_eq!(result, Expr::String("hello".to_string()));
428 }
429
430 #[test]
431 fn test_parse_empty_string() {
432 let result = parse_formula("\"\"").unwrap();
433 assert_eq!(result, Expr::String(String::new()));
434 }
435
436 #[test]
437 fn test_parse_true() {
438 let result = parse_formula("TRUE").unwrap();
439 assert_eq!(result, Expr::Bool(true));
440 }
441
442 #[test]
443 fn test_parse_false() {
444 let result = parse_formula("FALSE").unwrap();
445 assert_eq!(result, Expr::Bool(false));
446 }
447
448 #[test]
449 fn test_parse_error_div0() {
450 let result = parse_formula("#DIV/0!").unwrap();
451 assert_eq!(result, Expr::Error("#DIV/0!".to_string()));
452 }
453
454 #[test]
455 fn test_parse_error_na() {
456 let result = parse_formula("#N/A").unwrap();
457 assert_eq!(result, Expr::Error("#N/A".to_string()));
458 }
459
460 #[test]
461 fn test_parse_cell_ref() {
462 let result = parse_formula("A1").unwrap();
463 assert_eq!(
464 result,
465 Expr::CellRef(CellReference {
466 col: "A".to_string(),
467 row: 1,
468 abs_col: false,
469 abs_row: false,
470 sheet: None,
471 })
472 );
473 }
474
475 #[test]
476 fn test_parse_abs_cell_ref() {
477 let result = parse_formula("$A$1").unwrap();
478 assert_eq!(
479 result,
480 Expr::CellRef(CellReference {
481 col: "A".to_string(),
482 row: 1,
483 abs_col: true,
484 abs_row: true,
485 sheet: None,
486 })
487 );
488 }
489
490 #[test]
491 fn test_parse_mixed_cell_ref() {
492 let result = parse_formula("$A1").unwrap();
493 assert_eq!(
494 result,
495 Expr::CellRef(CellReference {
496 col: "A".to_string(),
497 row: 1,
498 abs_col: true,
499 abs_row: false,
500 sheet: None,
501 })
502 );
503 }
504
505 #[test]
506 fn test_parse_range() {
507 let result = parse_formula("A1:B10").unwrap();
508 assert_eq!(
509 result,
510 Expr::Range {
511 start: CellReference {
512 col: "A".to_string(),
513 row: 1,
514 abs_col: false,
515 abs_row: false,
516 sheet: None,
517 },
518 end: CellReference {
519 col: "B".to_string(),
520 row: 10,
521 abs_col: false,
522 abs_row: false,
523 sheet: None,
524 },
525 }
526 );
527 }
528
529 #[test]
530 fn test_parse_addition() {
531 let result = parse_formula("1+2").unwrap();
532 assert_eq!(
533 result,
534 Expr::BinaryOp {
535 op: BinaryOperator::Add,
536 left: Box::new(Expr::Number(1.0)),
537 right: Box::new(Expr::Number(2.0)),
538 }
539 );
540 }
541
542 #[test]
543 fn test_parse_subtraction() {
544 let result = parse_formula("5-3").unwrap();
545 assert_eq!(
546 result,
547 Expr::BinaryOp {
548 op: BinaryOperator::Sub,
549 left: Box::new(Expr::Number(5.0)),
550 right: Box::new(Expr::Number(3.0)),
551 }
552 );
553 }
554
555 #[test]
556 fn test_parse_multiplication() {
557 let result = parse_formula("2*3").unwrap();
558 assert_eq!(
559 result,
560 Expr::BinaryOp {
561 op: BinaryOperator::Mul,
562 left: Box::new(Expr::Number(2.0)),
563 right: Box::new(Expr::Number(3.0)),
564 }
565 );
566 }
567
568 #[test]
569 fn test_parse_division() {
570 let result = parse_formula("10/2").unwrap();
571 assert_eq!(
572 result,
573 Expr::BinaryOp {
574 op: BinaryOperator::Div,
575 left: Box::new(Expr::Number(10.0)),
576 right: Box::new(Expr::Number(2.0)),
577 }
578 );
579 }
580
581 #[test]
582 fn test_precedence_mul_over_add() {
583 let result = parse_formula("1+2*3").unwrap();
585 assert_eq!(
586 result,
587 Expr::BinaryOp {
588 op: BinaryOperator::Add,
589 left: Box::new(Expr::Number(1.0)),
590 right: Box::new(Expr::BinaryOp {
591 op: BinaryOperator::Mul,
592 left: Box::new(Expr::Number(2.0)),
593 right: Box::new(Expr::Number(3.0)),
594 }),
595 }
596 );
597 }
598
599 #[test]
600 fn test_precedence_parens() {
601 let result = parse_formula("(1+2)*3").unwrap();
603 assert_eq!(
604 result,
605 Expr::BinaryOp {
606 op: BinaryOperator::Mul,
607 left: Box::new(Expr::Paren(Box::new(Expr::BinaryOp {
608 op: BinaryOperator::Add,
609 left: Box::new(Expr::Number(1.0)),
610 right: Box::new(Expr::Number(2.0)),
611 }))),
612 right: Box::new(Expr::Number(3.0)),
613 }
614 );
615 }
616
617 #[test]
618 fn test_parse_function_no_args() {
619 let result = parse_formula("NOW()").unwrap();
620 assert_eq!(
621 result,
622 Expr::Function {
623 name: "NOW".to_string(),
624 args: vec![],
625 }
626 );
627 }
628
629 #[test]
630 fn test_parse_function_one_arg() {
631 let result = parse_formula("ABS(-5)").unwrap();
632 assert_eq!(
633 result,
634 Expr::Function {
635 name: "ABS".to_string(),
636 args: vec![Expr::UnaryOp {
637 op: UnaryOperator::Neg,
638 operand: Box::new(Expr::Number(5.0)),
639 }],
640 }
641 );
642 }
643
644 #[test]
645 fn test_parse_function_multi_args() {
646 let result = parse_formula("SUM(1,2,3)").unwrap();
647 assert_eq!(
648 result,
649 Expr::Function {
650 name: "SUM".to_string(),
651 args: vec![Expr::Number(1.0), Expr::Number(2.0), Expr::Number(3.0),],
652 }
653 );
654 }
655
656 #[test]
657 fn test_parse_nested_function() {
658 let result = parse_formula("SUM(A1:A10,MAX(B1:B10))").unwrap();
659 assert_eq!(
660 result,
661 Expr::Function {
662 name: "SUM".to_string(),
663 args: vec![
664 Expr::Range {
665 start: CellReference {
666 col: "A".to_string(),
667 row: 1,
668 abs_col: false,
669 abs_row: false,
670 sheet: None,
671 },
672 end: CellReference {
673 col: "A".to_string(),
674 row: 10,
675 abs_col: false,
676 abs_row: false,
677 sheet: None,
678 },
679 },
680 Expr::Function {
681 name: "MAX".to_string(),
682 args: vec![Expr::Range {
683 start: CellReference {
684 col: "B".to_string(),
685 row: 1,
686 abs_col: false,
687 abs_row: false,
688 sheet: None,
689 },
690 end: CellReference {
691 col: "B".to_string(),
692 row: 10,
693 abs_col: false,
694 abs_row: false,
695 sheet: None,
696 },
697 }],
698 },
699 ],
700 }
701 );
702 }
703
704 #[test]
705 fn test_parse_equal() {
706 let result = parse_formula("A1=B1").unwrap();
707 assert_eq!(
708 result,
709 Expr::BinaryOp {
710 op: BinaryOperator::Eq,
711 left: Box::new(Expr::CellRef(CellReference {
712 col: "A".to_string(),
713 row: 1,
714 abs_col: false,
715 abs_row: false,
716 sheet: None,
717 })),
718 right: Box::new(Expr::CellRef(CellReference {
719 col: "B".to_string(),
720 row: 1,
721 abs_col: false,
722 abs_row: false,
723 sheet: None,
724 })),
725 }
726 );
727 }
728
729 #[test]
730 fn test_parse_not_equal() {
731 let result = parse_formula("A1<>B1").unwrap();
732 assert_eq!(
733 result,
734 Expr::BinaryOp {
735 op: BinaryOperator::Ne,
736 left: Box::new(Expr::CellRef(CellReference {
737 col: "A".to_string(),
738 row: 1,
739 abs_col: false,
740 abs_row: false,
741 sheet: None,
742 })),
743 right: Box::new(Expr::CellRef(CellReference {
744 col: "B".to_string(),
745 row: 1,
746 abs_col: false,
747 abs_row: false,
748 sheet: None,
749 })),
750 }
751 );
752 }
753
754 #[test]
755 fn test_parse_less_than() {
756 let result = parse_formula("A1<B1").unwrap();
757 assert_eq!(
758 result,
759 Expr::BinaryOp {
760 op: BinaryOperator::Lt,
761 left: Box::new(Expr::CellRef(CellReference {
762 col: "A".to_string(),
763 row: 1,
764 abs_col: false,
765 abs_row: false,
766 sheet: None,
767 })),
768 right: Box::new(Expr::CellRef(CellReference {
769 col: "B".to_string(),
770 row: 1,
771 abs_col: false,
772 abs_row: false,
773 sheet: None,
774 })),
775 }
776 );
777 }
778
779 #[test]
780 fn test_parse_concat() {
781 let result = parse_formula("A1&B1").unwrap();
782 assert_eq!(
783 result,
784 Expr::BinaryOp {
785 op: BinaryOperator::Concat,
786 left: Box::new(Expr::CellRef(CellReference {
787 col: "A".to_string(),
788 row: 1,
789 abs_col: false,
790 abs_row: false,
791 sheet: None,
792 })),
793 right: Box::new(Expr::CellRef(CellReference {
794 col: "B".to_string(),
795 row: 1,
796 abs_col: false,
797 abs_row: false,
798 sheet: None,
799 })),
800 }
801 );
802 }
803
804 #[test]
805 fn test_parse_complex_formula() {
806 let result = parse_formula("SUM(A1:A10)+AVERAGE(B1:B10)*2").unwrap();
808 assert_eq!(
809 result,
810 Expr::BinaryOp {
811 op: BinaryOperator::Add,
812 left: Box::new(Expr::Function {
813 name: "SUM".to_string(),
814 args: vec![Expr::Range {
815 start: CellReference {
816 col: "A".to_string(),
817 row: 1,
818 abs_col: false,
819 abs_row: false,
820 sheet: None,
821 },
822 end: CellReference {
823 col: "A".to_string(),
824 row: 10,
825 abs_col: false,
826 abs_row: false,
827 sheet: None,
828 },
829 }],
830 }),
831 right: Box::new(Expr::BinaryOp {
832 op: BinaryOperator::Mul,
833 left: Box::new(Expr::Function {
834 name: "AVERAGE".to_string(),
835 args: vec![Expr::Range {
836 start: CellReference {
837 col: "B".to_string(),
838 row: 1,
839 abs_col: false,
840 abs_row: false,
841 sheet: None,
842 },
843 end: CellReference {
844 col: "B".to_string(),
845 row: 10,
846 abs_col: false,
847 abs_row: false,
848 sheet: None,
849 },
850 }],
851 }),
852 right: Box::new(Expr::Number(2.0)),
853 }),
854 }
855 );
856 }
857
858 #[test]
859 fn test_parse_sheet_ref() {
860 let result = parse_formula("Sheet1!A1").unwrap();
861 assert_eq!(
862 result,
863 Expr::CellRef(CellReference {
864 col: "A".to_string(),
865 row: 1,
866 abs_col: false,
867 abs_row: false,
868 sheet: Some("Sheet1".to_string()),
869 })
870 );
871 }
872}