1use super::super::pair_span;
14use crate::ast::operators::{FuzzyOp, FuzzyTolerance};
15use crate::ast::{AssignExpr, BinaryOp, Expr, IfExpr, RangeKind, Span, UnaryOp};
16use crate::error::{Result, ShapeError};
17use crate::parser::{Rule, pair_location};
18use pest::iterators::Pair;
19
20pub fn parse_pipe_expr(pair: Pair<Rule>) -> Result<Expr> {
23 let span = pair_span(&pair);
24 let pair_loc = pair_location(&pair);
25 let mut inner = pair.into_inner();
26 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
27 message: "expected expression in pipe".to_string(),
28 location: Some(pair_loc),
29 })?;
30 let mut left = parse_ternary_expr(first)?;
31
32 for ternary_pair in inner {
34 let right = parse_ternary_expr(ternary_pair)?;
35 left = Expr::BinaryOp {
36 left: Box::new(left),
37 op: BinaryOp::Pipe,
38 right: Box::new(right),
39 span,
40 };
41 }
42
43 Ok(left)
44}
45
46pub fn parse_ternary_expr(pair: Pair<Rule>) -> Result<Expr> {
48 let span = pair_span(&pair);
49 let pair_loc = pair_location(&pair);
50 let mut inner = pair.into_inner();
51 let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
52 message: "expected condition expression in ternary".to_string(),
53 location: Some(pair_loc.clone()),
54 })?;
55 let condition_expr = parse_null_coalesce_expr(condition_pair)?;
56
57 if let Some(then_pair) = inner.next() {
59 let then_expr = parse_ternary_branch(then_pair)?;
61 let else_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
62 message: "expected else expression after ':' in ternary".to_string(),
63 location: Some(pair_loc),
64 })?;
65 let else_expr = parse_ternary_branch(else_pair)?;
66
67 Ok(Expr::If(
68 Box::new(IfExpr {
69 condition: Box::new(condition_expr),
70 then_branch: Box::new(then_expr),
71 else_branch: Some(Box::new(else_expr)),
72 }),
73 span,
74 ))
75 } else {
76 Ok(condition_expr)
78 }
79}
80
81fn parse_ternary_branch(pair: Pair<Rule>) -> Result<Expr> {
82 let pair_loc = pair_location(&pair);
83 match pair.as_rule() {
84 Rule::ternary_branch => {
85 let inner = pair
86 .into_inner()
87 .next()
88 .ok_or_else(|| ShapeError::ParseError {
89 message: "expected expression in ternary branch".to_string(),
90 location: Some(pair_loc),
91 })?;
92 parse_assignment_expr_no_range(inner)
93 }
94 Rule::assignment_expr_no_range => parse_assignment_expr_no_range(pair),
95 _ => super::primary::parse_expression(pair),
96 }
97}
98
99fn compound_op_to_binary(op_str: &str) -> Option<BinaryOp> {
101 match op_str {
102 "+=" => Some(BinaryOp::Add),
103 "-=" => Some(BinaryOp::Sub),
104 "*=" => Some(BinaryOp::Mul),
105 "/=" => Some(BinaryOp::Div),
106 "%=" => Some(BinaryOp::Mod),
107 "**=" => Some(BinaryOp::Pow),
108 "^=" => Some(BinaryOp::BitXor),
109 "&=" => Some(BinaryOp::BitAnd),
110 "|=" => Some(BinaryOp::BitOr),
111 "<<=" => Some(BinaryOp::BitShl),
112 ">>=" => Some(BinaryOp::BitShr),
113 _ => None,
114 }
115}
116
117pub fn parse_assignment_expr(pair: Pair<Rule>) -> Result<Expr> {
119 let span = pair_span(&pair);
120 let pair_loc = pair_location(&pair);
121 let mut inner = pair.into_inner();
122 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
123 message: "expected expression".to_string(),
124 location: Some(pair_loc.clone()),
125 })?;
126
127 if let Some(second) = inner.next() {
128 if second.as_rule() == Rule::compound_assign_op {
130 let target = super::primary::parse_postfix_expr(first)?;
131 if !matches!(
132 target,
133 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
134 ) {
135 return Err(ShapeError::ParseError {
136 message: "invalid assignment target".to_string(),
137 location: Some(pair_loc),
138 });
139 }
140 let bin_op =
141 compound_op_to_binary(second.as_str()).ok_or_else(|| ShapeError::ParseError {
142 message: format!("Unknown compound operator: {}", second.as_str()),
143 location: None,
144 })?;
145 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
146 message: "expected value after compound assignment".to_string(),
147 location: None,
148 })?;
149 let value = parse_assignment_expr(value_pair)?;
150 let desugared = Expr::BinaryOp {
152 left: Box::new(target.clone()),
153 op: bin_op,
154 right: Box::new(value),
155 span,
156 };
157 Ok(Expr::Assign(
158 Box::new(AssignExpr {
159 target: Box::new(target),
160 value: Box::new(desugared),
161 }),
162 span,
163 ))
164 } else if second.as_rule() == Rule::assign_op {
165 let target = super::primary::parse_postfix_expr(first)?;
167 if !matches!(
168 target,
169 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
170 ) {
171 return Err(ShapeError::ParseError {
172 message: "invalid assignment target".to_string(),
173 location: Some(pair_loc),
174 });
175 }
176 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
177 message: "expected value after assignment".to_string(),
178 location: None,
179 })?;
180 let value = parse_assignment_expr(value_pair)?;
181 Ok(Expr::Assign(
182 Box::new(AssignExpr {
183 target: Box::new(target),
184 value: Box::new(value),
185 }),
186 span,
187 ))
188 } else {
189 match first.as_rule() {
191 Rule::pipe_expr => parse_pipe_expr(first),
192 Rule::ternary_expr => parse_ternary_expr(first),
193 _ => parse_pipe_expr(first),
194 }
195 }
196 } else {
197 match first.as_rule() {
199 Rule::pipe_expr => parse_pipe_expr(first),
200 Rule::ternary_expr => parse_ternary_expr(first),
201 _ => parse_pipe_expr(first),
202 }
203 }
204}
205
206fn parse_assignment_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
207 let span = pair_span(&pair);
208 let pair_loc = pair_location(&pair);
209 let mut inner = pair.into_inner();
210 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
211 message: "expected expression".to_string(),
212 location: Some(pair_loc.clone()),
213 })?;
214
215 if let Some(second) = inner.next() {
216 if second.as_rule() == Rule::compound_assign_op {
217 let target = super::primary::parse_postfix_expr(first)?;
218 if !matches!(
219 target,
220 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
221 ) {
222 return Err(ShapeError::ParseError {
223 message: "invalid assignment target".to_string(),
224 location: Some(pair_loc),
225 });
226 }
227 let bin_op =
228 compound_op_to_binary(second.as_str()).ok_or_else(|| ShapeError::ParseError {
229 message: format!("Unknown compound operator: {}", second.as_str()),
230 location: None,
231 })?;
232 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
233 message: "expected value after compound assignment".to_string(),
234 location: None,
235 })?;
236 let value = parse_assignment_expr_no_range(value_pair)?;
237 let desugared = Expr::BinaryOp {
238 left: Box::new(target.clone()),
239 op: bin_op,
240 right: Box::new(value),
241 span,
242 };
243 Ok(Expr::Assign(
244 Box::new(AssignExpr {
245 target: Box::new(target),
246 value: Box::new(desugared),
247 }),
248 span,
249 ))
250 } else if second.as_rule() == Rule::assign_op {
251 let target = super::primary::parse_postfix_expr(first)?;
253 if !matches!(
254 target,
255 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
256 ) {
257 return Err(ShapeError::ParseError {
258 message: "invalid assignment target".to_string(),
259 location: Some(pair_loc),
260 });
261 }
262 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
263 message: "expected value after assignment".to_string(),
264 location: None,
265 })?;
266 let value = parse_assignment_expr_no_range(value_pair)?;
267 Ok(Expr::Assign(
268 Box::new(AssignExpr {
269 target: Box::new(target),
270 value: Box::new(value),
271 }),
272 span,
273 ))
274 } else {
275 parse_null_coalesce_expr_no_range(first)
277 }
278 } else {
279 parse_null_coalesce_expr_no_range(first)
280 }
281}
282
283pub fn parse_null_coalesce_expr(pair: Pair<Rule>) -> Result<Expr> {
285 let span = pair_span(&pair);
286 let pair_loc = pair_location(&pair);
287 let mut inner = pair.into_inner();
288 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
289 message: "expected expression in null coalesce".to_string(),
290 location: Some(pair_loc),
291 })?;
292 let mut left = parse_context_expr(first)?;
293
294 for context_expr in inner {
295 let right = parse_context_expr(context_expr)?;
296 left = Expr::BinaryOp {
297 left: Box::new(left),
298 op: BinaryOp::NullCoalesce,
299 right: Box::new(right),
300 span,
301 };
302 }
303
304 Ok(left)
305}
306
307fn parse_null_coalesce_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
308 let span = pair_span(&pair);
309 let pair_loc = pair_location(&pair);
310 let mut inner = pair.into_inner();
311 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
312 message: "expected expression".to_string(),
313 location: Some(pair_loc),
314 })?;
315 let mut left = parse_context_expr_no_range(first)?;
316
317 for context_expr in inner {
318 let right = parse_context_expr_no_range(context_expr)?;
319 left = Expr::BinaryOp {
320 left: Box::new(left),
321 op: BinaryOp::NullCoalesce,
322 right: Box::new(right),
323 span,
324 };
325 }
326
327 Ok(left)
328}
329
330pub fn parse_context_expr(pair: Pair<Rule>) -> Result<Expr> {
332 let span = pair_span(&pair);
333 let pair_loc = pair_location(&pair);
334 let mut inner = pair.into_inner();
335 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
336 message: "expected expression in error context".to_string(),
337 location: Some(pair_loc),
338 })?;
339 let mut left = parse_or_expr(first)?;
340
341 for or_expr in inner {
342 let rhs_source = or_expr.as_str().trim().to_string();
343 let right = parse_or_expr(or_expr)?;
344 let is_grouped_rhs = rhs_source.starts_with('(') && rhs_source.ends_with(')');
345
346 match right {
347 Expr::TryOperator(inner_try, try_span) if !is_grouped_rhs => {
348 let context_expr = Expr::BinaryOp {
351 left: Box::new(left),
352 op: BinaryOp::ErrorContext,
353 right: inner_try,
354 span,
355 };
356 left = Expr::TryOperator(Box::new(context_expr), try_span);
357 }
358 right => {
359 left = Expr::BinaryOp {
360 left: Box::new(left),
361 op: BinaryOp::ErrorContext,
362 right: Box::new(right),
363 span,
364 };
365 }
366 }
367 }
368
369 Ok(left)
370}
371
372fn parse_context_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
373 let span = pair_span(&pair);
374 let pair_loc = pair_location(&pair);
375 let mut inner = pair.into_inner();
376 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
377 message: "expected expression".to_string(),
378 location: Some(pair_loc),
379 })?;
380 let mut left = parse_or_expr_no_range(first)?;
381
382 for or_expr in inner {
383 let rhs_source = or_expr.as_str().trim().to_string();
384 let right = parse_or_expr_no_range(or_expr)?;
385 let is_grouped_rhs = rhs_source.starts_with('(') && rhs_source.ends_with(')');
386
387 match right {
388 Expr::TryOperator(inner_try, try_span) if !is_grouped_rhs => {
389 let context_expr = Expr::BinaryOp {
391 left: Box::new(left),
392 op: BinaryOp::ErrorContext,
393 right: inner_try,
394 span,
395 };
396 left = Expr::TryOperator(Box::new(context_expr), try_span);
397 }
398 right => {
399 left = Expr::BinaryOp {
400 left: Box::new(left),
401 op: BinaryOp::ErrorContext,
402 right: Box::new(right),
403 span,
404 };
405 }
406 }
407 }
408
409 Ok(left)
410}
411
412pub fn parse_or_expr(pair: Pair<Rule>) -> Result<Expr> {
414 let span = pair_span(&pair);
415 let pair_loc = pair_location(&pair);
416 let mut inner = pair.into_inner();
417 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
418 message: "expected expression in logical OR".to_string(),
419 location: Some(pair_loc),
420 })?;
421 let mut left = parse_and_expr(first)?;
422
423 for and_expr in inner {
424 let right = parse_and_expr(and_expr)?;
425 left = Expr::BinaryOp {
426 left: Box::new(left),
427 op: BinaryOp::Or,
428 right: Box::new(right),
429 span,
430 };
431 }
432
433 Ok(left)
434}
435
436fn parse_or_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
437 let span = pair_span(&pair);
438 let pair_loc = pair_location(&pair);
439 let mut inner = pair.into_inner();
440 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
441 message: "expected expression".to_string(),
442 location: Some(pair_loc),
443 })?;
444 let mut left = parse_and_expr_no_range(first)?;
445
446 for and_expr in inner {
447 let right = parse_and_expr_no_range(and_expr)?;
448 left = Expr::BinaryOp {
449 left: Box::new(left),
450 op: BinaryOp::Or,
451 right: Box::new(right),
452 span,
453 };
454 }
455
456 Ok(left)
457}
458
459pub fn parse_and_expr(pair: Pair<Rule>) -> Result<Expr> {
461 let span = pair_span(&pair);
462 let pair_loc = pair_location(&pair);
463 let mut inner = pair.into_inner();
464 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
465 message: "expected expression in logical AND".to_string(),
466 location: Some(pair_loc),
467 })?;
468 let mut left = parse_bitwise_or_expr(first)?;
469
470 for expr in inner {
471 let right = parse_bitwise_or_expr(expr)?;
472 left = Expr::BinaryOp {
473 left: Box::new(left),
474 op: BinaryOp::And,
475 right: Box::new(right),
476 span,
477 };
478 }
479
480 Ok(left)
481}
482
483fn parse_and_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
484 let span = pair_span(&pair);
485 let pair_loc = pair_location(&pair);
486 let mut inner = pair.into_inner();
487 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
488 message: "expected expression".to_string(),
489 location: Some(pair_loc),
490 })?;
491 let mut left = parse_bitwise_or_expr_no_range(first)?;
492
493 for expr in inner {
494 let right = parse_bitwise_or_expr_no_range(expr)?;
495 left = Expr::BinaryOp {
496 left: Box::new(left),
497 op: BinaryOp::And,
498 right: Box::new(right),
499 span,
500 };
501 }
502
503 Ok(left)
504}
505
506fn parse_bitwise_or_expr(pair: Pair<Rule>) -> Result<Expr> {
508 let span = pair_span(&pair);
509 let pair_loc = pair_location(&pair);
510 let mut inner = pair.into_inner();
511 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
512 message: "expected expression in bitwise OR".to_string(),
513 location: Some(pair_loc),
514 })?;
515 let mut left = parse_bitwise_xor_expr(first)?;
516
517 for expr in inner {
518 let right = parse_bitwise_xor_expr(expr)?;
519 left = Expr::BinaryOp {
520 left: Box::new(left),
521 op: BinaryOp::BitOr,
522 right: Box::new(right),
523 span,
524 };
525 }
526
527 Ok(left)
528}
529
530fn parse_bitwise_or_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
531 let span = pair_span(&pair);
532 let pair_loc = pair_location(&pair);
533 let mut inner = pair.into_inner();
534 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
535 message: "expected expression".to_string(),
536 location: Some(pair_loc),
537 })?;
538 let mut left = parse_bitwise_xor_expr_no_range(first)?;
539
540 for expr in inner {
541 let right = parse_bitwise_xor_expr_no_range(expr)?;
542 left = Expr::BinaryOp {
543 left: Box::new(left),
544 op: BinaryOp::BitOr,
545 right: Box::new(right),
546 span,
547 };
548 }
549
550 Ok(left)
551}
552
553fn parse_bitwise_xor_expr(pair: Pair<Rule>) -> Result<Expr> {
555 let span = pair_span(&pair);
556 let pair_loc = pair_location(&pair);
557 let mut inner = pair.into_inner();
558 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
559 message: "expected expression in bitwise XOR".to_string(),
560 location: Some(pair_loc),
561 })?;
562 let mut left = parse_bitwise_and_expr(first)?;
563
564 for expr in inner {
565 let right = parse_bitwise_and_expr(expr)?;
566 left = Expr::BinaryOp {
567 left: Box::new(left),
568 op: BinaryOp::BitXor,
569 right: Box::new(right),
570 span,
571 };
572 }
573
574 Ok(left)
575}
576
577fn parse_bitwise_xor_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
578 let span = pair_span(&pair);
579 let pair_loc = pair_location(&pair);
580 let mut inner = pair.into_inner();
581 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
582 message: "expected expression".to_string(),
583 location: Some(pair_loc),
584 })?;
585 let mut left = parse_bitwise_and_expr_no_range(first)?;
586
587 for expr in inner {
588 let right = parse_bitwise_and_expr_no_range(expr)?;
589 left = Expr::BinaryOp {
590 left: Box::new(left),
591 op: BinaryOp::BitXor,
592 right: Box::new(right),
593 span,
594 };
595 }
596
597 Ok(left)
598}
599
600fn parse_bitwise_and_expr(pair: Pair<Rule>) -> Result<Expr> {
602 let span = pair_span(&pair);
603 let pair_loc = pair_location(&pair);
604 let mut inner = pair.into_inner();
605 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
606 message: "expected expression in bitwise AND".to_string(),
607 location: Some(pair_loc),
608 })?;
609 let mut left = parse_comparison_expr(first)?;
610
611 for expr in inner {
612 let right = parse_comparison_expr(expr)?;
613 left = Expr::BinaryOp {
614 left: Box::new(left),
615 op: BinaryOp::BitAnd,
616 right: Box::new(right),
617 span,
618 };
619 }
620
621 Ok(left)
622}
623
624fn parse_bitwise_and_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
625 let span = pair_span(&pair);
626 let pair_loc = pair_location(&pair);
627 let mut inner = pair.into_inner();
628 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
629 message: "expected expression".to_string(),
630 location: Some(pair_loc),
631 })?;
632 let mut left = parse_comparison_expr_no_range(first)?;
633
634 for expr in inner {
635 let right = parse_comparison_expr_no_range(expr)?;
636 left = Expr::BinaryOp {
637 left: Box::new(left),
638 op: BinaryOp::BitAnd,
639 right: Box::new(right),
640 span,
641 };
642 }
643
644 Ok(left)
645}
646
647pub fn parse_comparison_expr(pair: Pair<Rule>) -> Result<Expr> {
649 let span = pair_span(&pair);
650 let pair_loc = pair_location(&pair);
651 let mut inner = pair.into_inner();
652 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
653 message: "expected expression in comparison".to_string(),
654 location: Some(pair_loc),
655 })?;
656 let mut left = parse_range_expr(first)?;
657
658 for tail in inner {
659 left = apply_comparison_tail(left, tail, span, parse_range_expr)?;
660 }
661
662 Ok(left)
663}
664
665fn parse_comparison_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
666 let span = pair_span(&pair);
667 let pair_loc = pair_location(&pair);
668 let mut inner = pair.into_inner();
669 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
670 message: "expected expression".to_string(),
671 location: Some(pair_loc),
672 })?;
673 let mut left = parse_additive_expr(first)?;
674
675 for tail in inner {
676 left = apply_comparison_tail(left, tail, span, parse_additive_expr)?;
677 }
678
679 Ok(left)
680}
681
682fn apply_comparison_tail<F>(left: Expr, tail: Pair<Rule>, span: Span, parse_rhs: F) -> Result<Expr>
683where
684 F: Fn(Pair<Rule>) -> Result<Expr>,
685{
686 let mut tail_inner = tail.into_inner();
687 let first = tail_inner.next().ok_or_else(|| ShapeError::ParseError {
688 message: "Empty comparison tail".to_string(),
689 location: None,
690 })?;
691
692 match first.as_rule() {
693 Rule::fuzzy_comparison_tail | Rule::fuzzy_comparison_tail_no_range => {
694 let mut fuzzy_inner = first.into_inner();
696
697 let fuzzy_op_pair = fuzzy_inner.next().ok_or_else(|| ShapeError::ParseError {
698 message: "Fuzzy comparison missing operator".to_string(),
699 location: None,
700 })?;
701 let op = parse_fuzzy_op(fuzzy_op_pair)?;
702
703 let rhs_pair = fuzzy_inner.next().ok_or_else(|| ShapeError::ParseError {
704 message: "Fuzzy comparison missing right-hand side".to_string(),
705 location: None,
706 })?;
707 let right = parse_rhs(rhs_pair)?;
708
709 let tolerance = if let Some(within_clause) = fuzzy_inner.next() {
711 parse_within_clause(within_clause)?
712 } else {
713 FuzzyTolerance::Percentage(0.02)
715 };
716
717 Ok(Expr::FuzzyComparison {
718 left: Box::new(left),
719 op,
720 right: Box::new(right),
721 tolerance,
722 span,
723 })
724 }
725 Rule::comparison_op => {
726 let op = parse_comparison_op(first)?;
727 let rhs_pair = tail_inner.next().ok_or_else(|| ShapeError::ParseError {
728 message: "Comparison operator missing right-hand side".to_string(),
729 location: None,
730 })?;
731 let right = parse_rhs(rhs_pair)?;
732 Ok(Expr::BinaryOp {
733 left: Box::new(left),
734 op,
735 right: Box::new(right),
736 span,
737 })
738 }
739 Rule::type_annotation => {
740 let type_annotation = crate::parser::parse_type_annotation(first)?;
741 Ok(Expr::InstanceOf {
742 expr: Box::new(left),
743 type_annotation,
744 span,
745 })
746 }
747 _ => Err(ShapeError::ParseError {
748 message: format!("Unexpected comparison tail: {:?}", first.as_rule()),
749 location: None,
750 }),
751 }
752}
753
754fn parse_fuzzy_op(pair: Pair<Rule>) -> Result<FuzzyOp> {
756 match pair.as_str() {
757 "~=" => Ok(FuzzyOp::Equal),
758 "~>" => Ok(FuzzyOp::Greater),
759 "~<" => Ok(FuzzyOp::Less),
760 _ => Err(ShapeError::ParseError {
761 message: format!("Unknown fuzzy operator: {}", pair.as_str()),
762 location: None,
763 }),
764 }
765}
766
767fn parse_within_clause(pair: Pair<Rule>) -> Result<FuzzyTolerance> {
769 let mut inner = pair.into_inner();
770 let tolerance_spec = inner.next().ok_or_else(|| ShapeError::ParseError {
771 message: "Within clause missing tolerance value".to_string(),
772 location: None,
773 })?;
774 parse_tolerance_spec(tolerance_spec)
775}
776
777fn parse_tolerance_spec(pair: Pair<Rule>) -> Result<FuzzyTolerance> {
779 let text = pair.as_str().trim();
780
781 if text.ends_with('%') {
782 let num_str = text.trim_end_matches('%');
784 let value: f64 = num_str.parse().map_err(|_| ShapeError::ParseError {
785 message: format!("Invalid tolerance percentage: {}", text),
786 location: None,
787 })?;
788 Ok(FuzzyTolerance::Percentage(value / 100.0))
790 } else {
791 let value: f64 = text.parse().map_err(|_| ShapeError::ParseError {
793 message: format!("Invalid tolerance value: {}", text),
794 location: None,
795 })?;
796 Ok(FuzzyTolerance::Absolute(value))
797 }
798}
799
800pub fn parse_range_expr(pair: Pair<Rule>) -> Result<Expr> {
804 let span = pair_span(&pair);
805 let pair_loc = pair_location(&pair);
806 let mut inner = pair.into_inner().peekable();
807
808 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
810 message: "expected expression in range".to_string(),
811 location: Some(pair_loc.clone()),
812 })?;
813
814 match first.as_rule() {
815 Rule::range_op => {
816 let kind = parse_range_op(&first);
818 if let Some(end_pair) = inner.next() {
819 let end = parse_additive_expr(end_pair)?;
821 Ok(Expr::Range {
822 start: None,
823 end: Some(Box::new(end)),
824 kind,
825 span,
826 })
827 } else {
828 Ok(Expr::Range {
830 start: None,
831 end: None,
832 kind,
833 span,
834 })
835 }
836 }
837 Rule::additive_expr => {
838 let start = parse_additive_expr(first)?;
840
841 if let Some(next) = inner.next() {
842 match next.as_rule() {
843 Rule::range_op => {
844 let kind = parse_range_op(&next);
846 if let Some(end_pair) = inner.next() {
847 let end = parse_additive_expr(end_pair)?;
849 Ok(Expr::Range {
850 start: Some(Box::new(start)),
851 end: Some(Box::new(end)),
852 kind,
853 span,
854 })
855 } else {
856 Ok(Expr::Range {
858 start: Some(Box::new(start)),
859 end: None,
860 kind,
861 span,
862 })
863 }
864 }
865 _ => {
866 Err(ShapeError::ParseError {
868 message: format!(
869 "unexpected token in range expression: {:?}",
870 next.as_rule()
871 ),
872 location: Some(pair_loc),
873 })
874 }
875 }
876 } else {
877 Ok(start)
879 }
880 }
881 _ => {
882 parse_additive_expr(first)
884 }
885 }
886}
887
888fn parse_range_op(pair: &Pair<Rule>) -> RangeKind {
890 if pair.as_str() == "..=" {
891 RangeKind::Inclusive
892 } else {
893 RangeKind::Exclusive
894 }
895}
896
897pub fn parse_comparison_op(pair: Pair<Rule>) -> Result<BinaryOp> {
899 match pair.as_str() {
900 ">" => Ok(BinaryOp::Greater),
901 "<" => Ok(BinaryOp::Less),
902 ">=" => Ok(BinaryOp::GreaterEq),
903 "<=" => Ok(BinaryOp::LessEq),
904 "==" => Ok(BinaryOp::Equal),
905 "!=" => Ok(BinaryOp::NotEqual),
906 "~=" => Ok(BinaryOp::FuzzyEqual),
907 "~>" => Ok(BinaryOp::FuzzyGreater),
908 "~<" => Ok(BinaryOp::FuzzyLess),
909 _ => Err(ShapeError::ParseError {
910 message: format!("Unknown comparison operator: {}", pair.as_str()),
911 location: None,
912 }),
913 }
914}
915
916pub fn parse_additive_expr(pair: Pair<Rule>) -> Result<Expr> {
918 let span = pair_span(&pair);
921 let expr_str = pair.as_str();
922 let inner_pairs: Vec<_> = pair.into_inner().collect();
923
924 if inner_pairs.is_empty() {
925 return Err(ShapeError::ParseError {
926 message: "Empty additive expression".to_string(),
927 location: None,
928 });
929 }
930
931 let mut left = parse_shift_expr(inner_pairs[0].clone())?;
933
934 if inner_pairs.len() == 1 {
936 return Ok(left);
937 }
938
939 let mut current_pos = inner_pairs[0].as_str().len();
942
943 for i in 1..inner_pairs.len() {
944 let expr_start = expr_str[current_pos..]
946 .find(inner_pairs[i].as_str())
947 .ok_or_else(|| ShapeError::ParseError {
948 message: "Cannot find expression in string".to_string(),
949 location: None,
950 })?;
951 let op_str = expr_str[current_pos..current_pos + expr_start].trim();
952
953 let right = parse_shift_expr(inner_pairs[i].clone())?;
954
955 left = Expr::BinaryOp {
956 left: Box::new(left),
957 op: match op_str {
958 "+" => BinaryOp::Add,
959 "-" => BinaryOp::Sub,
960 _ => {
961 return Err(ShapeError::ParseError {
962 message: format!("Unknown additive operator: '{}'", op_str),
963 location: None,
964 });
965 }
966 },
967 right: Box::new(right),
968 span,
969 };
970
971 current_pos += expr_start + inner_pairs[i].as_str().len();
972 }
973
974 Ok(left)
975}
976
977pub fn parse_shift_expr(pair: Pair<Rule>) -> Result<Expr> {
979 let span = pair_span(&pair);
980 let expr_str = pair.as_str();
981 let inner_pairs: Vec<_> = pair.into_inner().collect();
982
983 if inner_pairs.is_empty() {
984 return Err(ShapeError::ParseError {
985 message: "Empty shift expression".to_string(),
986 location: None,
987 });
988 }
989
990 let mut left = parse_multiplicative_expr(inner_pairs[0].clone())?;
991
992 if inner_pairs.len() == 1 {
993 return Ok(left);
994 }
995
996 let mut current_pos = inner_pairs[0].as_str().len();
997
998 for i in 1..inner_pairs.len() {
999 let expr_start = expr_str[current_pos..]
1000 .find(inner_pairs[i].as_str())
1001 .ok_or_else(|| ShapeError::ParseError {
1002 message: "Cannot find expression in string".to_string(),
1003 location: None,
1004 })?;
1005 let op_str = expr_str[current_pos..current_pos + expr_start].trim();
1006
1007 let right = parse_multiplicative_expr(inner_pairs[i].clone())?;
1008
1009 left = Expr::BinaryOp {
1010 left: Box::new(left),
1011 op: match op_str {
1012 "<<" => BinaryOp::BitShl,
1013 ">>" => BinaryOp::BitShr,
1014 _ => {
1015 return Err(ShapeError::ParseError {
1016 message: format!("Unknown shift operator: '{}'", op_str),
1017 location: None,
1018 });
1019 }
1020 },
1021 right: Box::new(right),
1022 span,
1023 };
1024
1025 current_pos += expr_start + inner_pairs[i].as_str().len();
1026 }
1027
1028 Ok(left)
1029}
1030
1031pub fn parse_multiplicative_expr(pair: Pair<Rule>) -> Result<Expr> {
1033 let span = pair_span(&pair);
1035 let expr_str = pair.as_str();
1036 let inner_pairs: Vec<_> = pair.into_inner().collect();
1037
1038 if inner_pairs.is_empty() {
1039 return Err(ShapeError::ParseError {
1040 message: "Empty multiplicative expression".to_string(),
1041 location: None,
1042 });
1043 }
1044
1045 let mut left = parse_exponential_expr(inner_pairs[0].clone())?;
1047
1048 if inner_pairs.len() == 1 {
1050 return Ok(left);
1051 }
1052
1053 let mut current_pos = inner_pairs[0].as_str().len();
1056
1057 for i in 1..inner_pairs.len() {
1058 let expr_start = expr_str[current_pos..]
1060 .find(inner_pairs[i].as_str())
1061 .ok_or_else(|| ShapeError::ParseError {
1062 message: "Cannot find expression in string".to_string(),
1063 location: None,
1064 })?;
1065 let op_str = expr_str[current_pos..current_pos + expr_start].trim();
1066
1067 let right = parse_exponential_expr(inner_pairs[i].clone())?;
1068
1069 left = Expr::BinaryOp {
1070 left: Box::new(left),
1071 op: match op_str {
1072 "*" => BinaryOp::Mul,
1073 "/" => BinaryOp::Div,
1074 "%" => BinaryOp::Mod,
1075 _ => {
1076 return Err(ShapeError::ParseError {
1077 message: format!("Unknown multiplicative operator: '{}'", op_str),
1078 location: None,
1079 });
1080 }
1081 },
1082 right: Box::new(right),
1083 span,
1084 };
1085
1086 current_pos += expr_start + inner_pairs[i].as_str().len();
1087 }
1088
1089 Ok(left)
1090}
1091
1092pub fn parse_exponential_expr(pair: Pair<Rule>) -> Result<Expr> {
1094 let span = pair_span(&pair);
1096 let inner_pairs: Vec<_> = pair.into_inner().collect();
1097
1098 if inner_pairs.is_empty() {
1099 return Err(ShapeError::ParseError {
1100 message: "Empty exponential expression".to_string(),
1101 location: None,
1102 });
1103 }
1104
1105 let mut exprs: Vec<Expr> = Vec::new();
1107 for p in inner_pairs {
1108 exprs.push(parse_unary_expr(p)?);
1109 }
1110
1111 if exprs.len() == 1 {
1113 return Ok(exprs.into_iter().next().unwrap());
1114 }
1115
1116 let mut result = exprs.pop().unwrap(); while let Some(left_expr) = exprs.pop() {
1121 result = Expr::BinaryOp {
1122 left: Box::new(left_expr),
1123 op: BinaryOp::Pow,
1124 right: Box::new(result),
1125 span,
1126 };
1127 }
1128
1129 Ok(result)
1130}
1131
1132pub fn parse_unary_expr(pair: Pair<Rule>) -> Result<Expr> {
1134 let span = pair_span(&pair);
1135 let pair_str = pair.as_str();
1136 let pair_loc = pair_location(&pair);
1137 let mut inner = pair.into_inner();
1138 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
1139 message: "expected expression in unary operation".to_string(),
1140 location: Some(pair_loc.clone()),
1141 })?;
1142
1143 if first.as_rule() == Rule::ref_expr {
1145 let ref_span = pair_span(&first);
1146 let ref_inner = first.into_inner();
1147 let mut is_mutable = false;
1148 let mut expr_pair = None;
1149 for child in ref_inner {
1150 match child.as_rule() {
1151 Rule::ref_mut_keyword => {
1152 is_mutable = true;
1153 }
1154 _ => {
1155 expr_pair = Some(child);
1157 }
1158 }
1159 }
1160 let inner_expr = expr_pair.ok_or_else(|| ShapeError::ParseError {
1161 message: "expected expression after &".to_string(),
1162 location: Some(pair_loc),
1163 })?;
1164 let operand = super::primary::parse_postfix_expr(inner_expr)?;
1165 return Ok(Expr::Reference {
1166 expr: Box::new(operand),
1167 is_mutable,
1168 span: ref_span,
1169 });
1170 }
1171
1172 if pair_str.starts_with('!') {
1174 Ok(Expr::UnaryOp {
1175 op: UnaryOp::Not,
1176 operand: Box::new(parse_unary_expr(first)?),
1177 span,
1178 })
1179 } else if pair_str.starts_with('~') {
1180 Ok(Expr::UnaryOp {
1181 op: UnaryOp::BitNot,
1182 operand: Box::new(parse_unary_expr(first)?),
1183 span,
1184 })
1185 } else if pair_str.starts_with('-') {
1186 Ok(Expr::UnaryOp {
1187 op: UnaryOp::Neg,
1188 operand: Box::new(parse_unary_expr(first)?),
1189 span,
1190 })
1191 } else {
1192 super::primary::parse_postfix_expr(first)
1194 }
1195}