1use super::super::pair_span;
14use crate::ast::operators::{FuzzyOp, FuzzyTolerance};
15use crate::ast::{AssignExpr, BinaryOp, Expr, IfExpr, Literal, RangeKind, Span, UnaryOp};
16use crate::error::{Result, ShapeError};
17use crate::parser::{Rule, pair_location};
18use pest::iterators::Pair;
19
20fn parse_binary_chain(
30 pair: Pair<Rule>,
31 error_ctx: &str,
32 op: BinaryOp,
33 parse_child: fn(Pair<Rule>) -> Result<Expr>,
34) -> Result<Expr> {
35 let span = pair_span(&pair);
36 let pair_loc = pair_location(&pair);
37 let mut inner = pair.into_inner();
38 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
39 message: format!("expected expression in {}", error_ctx),
40 location: Some(pair_loc),
41 })?;
42 let mut left = parse_child(first)?;
43
44 for child in inner {
45 let right = parse_child(child)?;
46 left = Expr::BinaryOp {
47 left: Box::new(left),
48 op,
49 right: Box::new(right),
50 span,
51 };
52 }
53
54 Ok(left)
55}
56
57fn parse_positional_op_chain(
64 pair: Pair<Rule>,
65 error_ctx: &str,
66 parse_child: fn(Pair<Rule>) -> Result<Expr>,
67 resolve_op: fn(&str) -> Result<BinaryOp>,
68) -> Result<Expr> {
69 let span = pair_span(&pair);
70 let expr_str = pair.as_str();
71 let inner_pairs: Vec<_> = pair.into_inner().collect();
72
73 if inner_pairs.is_empty() {
74 return Err(ShapeError::ParseError {
75 message: format!("Empty {} expression", error_ctx),
76 location: None,
77 });
78 }
79
80 let mut left = parse_child(inner_pairs[0].clone())?;
81
82 if inner_pairs.len() == 1 {
83 return Ok(left);
84 }
85
86 let mut current_pos = inner_pairs[0].as_str().len();
87
88 for i in 1..inner_pairs.len() {
89 let expr_start = expr_str[current_pos..]
90 .find(inner_pairs[i].as_str())
91 .ok_or_else(|| ShapeError::ParseError {
92 message: "Cannot find expression in string".to_string(),
93 location: None,
94 })?;
95 let op_str = expr_str[current_pos..current_pos + expr_start].trim();
96 let op = resolve_op(op_str)?;
97 let right = parse_child(inner_pairs[i].clone())?;
98
99 left = Expr::BinaryOp {
100 left: Box::new(left),
101 op,
102 right: Box::new(right),
103 span,
104 };
105
106 current_pos += expr_start + inner_pairs[i].as_str().len();
107 }
108
109 Ok(left)
110}
111
112fn select_null_coalesce(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
128 if allow_range { parse_null_coalesce_expr } else { parse_null_coalesce_expr_no_range }
129}
130fn child_of_null_coalesce(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
131 if allow_range { parse_context_expr } else { parse_context_expr_no_range }
132}
133fn child_of_context(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
134 if allow_range { parse_or_expr } else { parse_or_expr_no_range }
135}
136fn child_of_or(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
137 if allow_range { parse_and_expr } else { parse_and_expr_no_range }
138}
139fn child_of_and(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
140 if allow_range { parse_bitwise_or_expr } else { parse_bitwise_or_expr_no_range }
141}
142fn child_of_bitwise_or(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
143 if allow_range { parse_bitwise_xor_expr } else { parse_bitwise_xor_expr_no_range }
144}
145fn child_of_bitwise_xor(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
146 if allow_range { parse_bitwise_and_expr } else { parse_bitwise_and_expr_no_range }
147}
148fn child_of_bitwise_and(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
149 if allow_range { parse_comparison_expr } else { parse_comparison_expr_no_range }
150}
151fn child_of_comparison(allow_range: bool) -> fn(Pair<Rule>) -> Result<Expr> {
152 if allow_range { parse_range_expr } else { parse_additive_expr }
153}
154
155pub fn parse_pipe_expr(pair: Pair<Rule>) -> Result<Expr> {
162 parse_binary_chain(pair, "pipe", BinaryOp::Pipe, parse_ternary_expr)
163}
164
165pub fn parse_ternary_expr(pair: Pair<Rule>) -> Result<Expr> {
171 parse_ternary_impl(pair, true)
172}
173
174fn parse_ternary_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
175 parse_ternary_impl(pair, false)
176}
177
178fn parse_ternary_impl(pair: Pair<Rule>, allow_range: bool) -> Result<Expr> {
179 let span = pair_span(&pair);
180 let pair_loc = pair_location(&pair);
181 let mut inner = pair.into_inner();
182 let condition_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
183 message: "expected condition expression in ternary".to_string(),
184 location: Some(pair_loc.clone()),
185 })?;
186 let condition_expr = (select_null_coalesce(allow_range))(condition_pair)?;
187
188 if let Some(then_pair) = inner.next() {
189 let then_expr = parse_ternary_branch(then_pair)?;
190 let else_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
191 message: "expected else expression after ':' in ternary".to_string(),
192 location: Some(pair_loc),
193 })?;
194 let else_expr = parse_ternary_branch(else_pair)?;
195
196 Ok(Expr::If(
197 Box::new(IfExpr {
198 condition: Box::new(condition_expr),
199 then_branch: Box::new(then_expr),
200 else_branch: Some(Box::new(else_expr)),
201 }),
202 span,
203 ))
204 } else {
205 Ok(condition_expr)
206 }
207}
208
209fn parse_ternary_branch(pair: Pair<Rule>) -> Result<Expr> {
210 let pair_loc = pair_location(&pair);
211 match pair.as_rule() {
212 Rule::ternary_branch => {
213 let inner = pair
214 .into_inner()
215 .next()
216 .ok_or_else(|| ShapeError::ParseError {
217 message: "expected expression in ternary branch".to_string(),
218 location: Some(pair_loc),
219 })?;
220 parse_ternary_expr_no_range(inner)
221 }
222 Rule::ternary_expr_no_range => parse_ternary_expr_no_range(pair),
223 Rule::assignment_expr_no_range => parse_assignment_expr_no_range(pair),
224 _ => super::primary::parse_expression(pair),
225 }
226}
227
228fn compound_op_to_binary(op_str: &str) -> Option<BinaryOp> {
233 match op_str {
234 "+=" => Some(BinaryOp::Add),
235 "-=" => Some(BinaryOp::Sub),
236 "*=" => Some(BinaryOp::Mul),
237 "/=" => Some(BinaryOp::Div),
238 "%=" => Some(BinaryOp::Mod),
239 "**=" => Some(BinaryOp::Pow),
240 "^=" => Some(BinaryOp::BitXor),
241 "&=" => Some(BinaryOp::BitAnd),
242 "|=" => Some(BinaryOp::BitOr),
243 "<<=" => Some(BinaryOp::BitShl),
244 ">>=" => Some(BinaryOp::BitShr),
245 _ => None,
246 }
247}
248
249pub fn parse_assignment_expr(pair: Pair<Rule>) -> Result<Expr> {
251 parse_assignment_impl(pair, true)
252}
253
254fn parse_assignment_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
255 parse_assignment_impl(pair, false)
256}
257
258fn parse_assignment_impl(pair: Pair<Rule>, allow_range: bool) -> Result<Expr> {
259 let span = pair_span(&pair);
260 let pair_loc = pair_location(&pair);
261 let mut inner = pair.into_inner();
262 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
263 message: "expected expression".to_string(),
264 location: Some(pair_loc.clone()),
265 })?;
266
267 let recurse: fn(Pair<Rule>) -> Result<Expr> = if allow_range {
268 parse_assignment_expr
269 } else {
270 parse_assignment_expr_no_range
271 };
272
273 if let Some(second) = inner.next() {
274 if second.as_rule() == Rule::compound_assign_op {
275 let target = super::primary::parse_postfix_expr(first)?;
276 if !matches!(
277 target,
278 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
279 ) {
280 return Err(ShapeError::ParseError {
281 message: "invalid assignment target".to_string(),
282 location: Some(pair_loc),
283 });
284 }
285 let bin_op =
286 compound_op_to_binary(second.as_str()).ok_or_else(|| ShapeError::ParseError {
287 message: format!("Unknown compound operator: {}", second.as_str()),
288 location: None,
289 })?;
290 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
291 message: "expected value after compound assignment".to_string(),
292 location: None,
293 })?;
294 let value = recurse(value_pair)?;
295 let desugared = Expr::BinaryOp {
296 left: Box::new(target.clone()),
297 op: bin_op,
298 right: Box::new(value),
299 span,
300 };
301 Ok(Expr::Assign(
302 Box::new(AssignExpr {
303 target: Box::new(target),
304 value: Box::new(desugared),
305 }),
306 span,
307 ))
308 } else if second.as_rule() == Rule::assign_op {
309 let target = super::primary::parse_postfix_expr(first)?;
310 if !matches!(
311 target,
312 Expr::Identifier(_, _) | Expr::PropertyAccess { .. } | Expr::IndexAccess { .. }
313 ) {
314 return Err(ShapeError::ParseError {
315 message: "invalid assignment target".to_string(),
316 location: Some(pair_loc),
317 });
318 }
319 let value_pair = inner.next().ok_or_else(|| ShapeError::ParseError {
320 message: "expected value after assignment".to_string(),
321 location: None,
322 })?;
323 let value = recurse(value_pair)?;
324 Ok(Expr::Assign(
325 Box::new(AssignExpr {
326 target: Box::new(target),
327 value: Box::new(value),
328 }),
329 span,
330 ))
331 } else if allow_range {
332 match first.as_rule() {
333 Rule::pipe_expr => parse_pipe_expr(first),
334 Rule::ternary_expr => parse_ternary_expr(first),
335 _ => parse_pipe_expr(first),
336 }
337 } else {
338 (select_null_coalesce(false))(first)
339 }
340 } else if allow_range {
341 match first.as_rule() {
342 Rule::pipe_expr => parse_pipe_expr(first),
343 Rule::ternary_expr => parse_ternary_expr(first),
344 _ => parse_pipe_expr(first),
345 }
346 } else {
347 (select_null_coalesce(false))(first)
348 }
349}
350
351pub fn parse_null_coalesce_expr(pair: Pair<Rule>) -> Result<Expr> {
357 parse_binary_chain(pair, "null coalesce", BinaryOp::NullCoalesce, child_of_null_coalesce(true))
358}
359
360fn parse_null_coalesce_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
361 parse_binary_chain(pair, "null coalesce", BinaryOp::NullCoalesce, child_of_null_coalesce(false))
362}
363
364pub fn parse_context_expr(pair: Pair<Rule>) -> Result<Expr> {
370 parse_context_impl(pair, true)
371}
372
373fn parse_context_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
374 parse_context_impl(pair, false)
375}
376
377fn parse_context_impl(pair: Pair<Rule>, allow_range: bool) -> Result<Expr> {
378 let span = pair_span(&pair);
379 let pair_loc = pair_location(&pair);
380 let parse_child = child_of_context(allow_range);
381 let mut inner = pair.into_inner();
382 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
383 message: "expected expression in error context".to_string(),
384 location: Some(pair_loc),
385 })?;
386 let mut left = parse_child(first)?;
387
388 for or_expr in inner {
389 let rhs_source = or_expr.as_str().trim().to_string();
390 let right = parse_child(or_expr)?;
391 let is_grouped_rhs = rhs_source.starts_with('(') && rhs_source.ends_with(')');
392
393 match right {
394 Expr::TryOperator(inner_try, try_span) if !is_grouped_rhs => {
395 let context_expr = Expr::BinaryOp {
396 left: Box::new(left),
397 op: BinaryOp::ErrorContext,
398 right: inner_try,
399 span,
400 };
401 left = Expr::TryOperator(Box::new(context_expr), try_span);
402 }
403 right => {
404 left = Expr::BinaryOp {
405 left: Box::new(left),
406 op: BinaryOp::ErrorContext,
407 right: Box::new(right),
408 span,
409 };
410 }
411 }
412 }
413
414 Ok(left)
415}
416
417pub fn parse_or_expr(pair: Pair<Rule>) -> Result<Expr> {
423 parse_binary_chain(pair, "logical OR", BinaryOp::Or, child_of_or(true))
424}
425fn parse_or_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
426 parse_binary_chain(pair, "logical OR", BinaryOp::Or, child_of_or(false))
427}
428
429pub fn parse_and_expr(pair: Pair<Rule>) -> Result<Expr> {
431 parse_binary_chain(pair, "logical AND", BinaryOp::And, child_of_and(true))
432}
433fn parse_and_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
434 parse_binary_chain(pair, "logical AND", BinaryOp::And, child_of_and(false))
435}
436
437fn parse_bitwise_or_expr(pair: Pair<Rule>) -> Result<Expr> {
439 parse_binary_chain(pair, "bitwise OR", BinaryOp::BitOr, child_of_bitwise_or(true))
440}
441fn parse_bitwise_or_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
442 parse_binary_chain(pair, "bitwise OR", BinaryOp::BitOr, child_of_bitwise_or(false))
443}
444
445fn parse_bitwise_xor_expr(pair: Pair<Rule>) -> Result<Expr> {
447 parse_binary_chain(pair, "bitwise XOR", BinaryOp::BitXor, child_of_bitwise_xor(true))
448}
449fn parse_bitwise_xor_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
450 parse_binary_chain(pair, "bitwise XOR", BinaryOp::BitXor, child_of_bitwise_xor(false))
451}
452
453fn parse_bitwise_and_expr(pair: Pair<Rule>) -> Result<Expr> {
455 parse_binary_chain(pair, "bitwise AND", BinaryOp::BitAnd, child_of_bitwise_and(true))
456}
457fn parse_bitwise_and_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
458 parse_binary_chain(pair, "bitwise AND", BinaryOp::BitAnd, child_of_bitwise_and(false))
459}
460
461pub fn parse_comparison_expr(pair: Pair<Rule>) -> Result<Expr> {
467 parse_comparison_impl(pair, true)
468}
469
470fn parse_comparison_expr_no_range(pair: Pair<Rule>) -> Result<Expr> {
471 parse_comparison_impl(pair, false)
472}
473
474fn parse_comparison_impl(pair: Pair<Rule>, allow_range: bool) -> Result<Expr> {
475 let span = pair_span(&pair);
476 let pair_loc = pair_location(&pair);
477 let parse_child = child_of_comparison(allow_range);
478 let mut inner = pair.into_inner();
479 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
480 message: "expected expression in comparison".to_string(),
481 location: Some(pair_loc),
482 })?;
483 let mut left = parse_child(first)?;
484
485 for tail in inner {
486 left = apply_comparison_tail(left, tail, span, parse_child)?;
487 }
488
489 Ok(left)
490}
491
492fn apply_comparison_tail(
493 left: Expr,
494 tail: Pair<Rule>,
495 span: Span,
496 parse_rhs: fn(Pair<Rule>) -> Result<Expr>,
497) -> Result<Expr> {
498 let mut tail_inner = tail.into_inner();
499 let first = tail_inner.next().ok_or_else(|| ShapeError::ParseError {
500 message: "Empty comparison tail".to_string(),
501 location: None,
502 })?;
503
504 match first.as_rule() {
505 Rule::fuzzy_comparison_tail | Rule::fuzzy_comparison_tail_no_range => {
506 let mut fuzzy_inner = first.into_inner();
507
508 let fuzzy_op_pair = fuzzy_inner.next().ok_or_else(|| ShapeError::ParseError {
509 message: "Fuzzy comparison missing operator".to_string(),
510 location: None,
511 })?;
512 let op = parse_fuzzy_op(fuzzy_op_pair)?;
513
514 let rhs_pair = fuzzy_inner.next().ok_or_else(|| ShapeError::ParseError {
515 message: "Fuzzy comparison missing right-hand side".to_string(),
516 location: None,
517 })?;
518 let right = parse_rhs(rhs_pair)?;
519
520 let tolerance = if let Some(within_clause) = fuzzy_inner.next() {
521 parse_within_clause(within_clause)?
522 } else {
523 FuzzyTolerance::Percentage(0.02)
524 };
525
526 Ok(Expr::FuzzyComparison {
527 left: Box::new(left),
528 op,
529 right: Box::new(right),
530 tolerance,
531 span,
532 })
533 }
534 Rule::comparison_op => {
535 let op = parse_comparison_op(first)?;
536 let rhs_pair = tail_inner.next().ok_or_else(|| ShapeError::ParseError {
537 message: "Comparison operator missing right-hand side".to_string(),
538 location: None,
539 })?;
540 let right = parse_rhs(rhs_pair)?;
541 Ok(Expr::BinaryOp {
542 left: Box::new(left),
543 op,
544 right: Box::new(right),
545 span,
546 })
547 }
548 Rule::type_annotation => {
549 let type_annotation = crate::parser::parse_type_annotation(first)?;
550 Ok(Expr::InstanceOf {
551 expr: Box::new(left),
552 type_annotation,
553 span,
554 })
555 }
556 _ => Err(ShapeError::ParseError {
557 message: format!("Unexpected comparison tail: {:?}", first.as_rule()),
558 location: None,
559 }),
560 }
561}
562
563fn parse_fuzzy_op(pair: Pair<Rule>) -> Result<FuzzyOp> {
565 match pair.as_str() {
566 "~=" => Ok(FuzzyOp::Equal),
567 "~>" => Ok(FuzzyOp::Greater),
568 "~<" => Ok(FuzzyOp::Less),
569 _ => Err(ShapeError::ParseError {
570 message: format!("Unknown fuzzy operator: {}", pair.as_str()),
571 location: None,
572 }),
573 }
574}
575
576fn parse_within_clause(pair: Pair<Rule>) -> Result<FuzzyTolerance> {
578 let mut inner = pair.into_inner();
579 let tolerance_spec = inner.next().ok_or_else(|| ShapeError::ParseError {
580 message: "Within clause missing tolerance value".to_string(),
581 location: None,
582 })?;
583 parse_tolerance_spec(tolerance_spec)
584}
585
586fn parse_tolerance_spec(pair: Pair<Rule>) -> Result<FuzzyTolerance> {
588 let text = pair.as_str().trim();
589
590 if text.ends_with('%') {
591 let num_str = text.trim_end_matches('%');
592 let value: f64 = num_str.parse().map_err(|_| ShapeError::ParseError {
593 message: format!("Invalid tolerance percentage: {}", text),
594 location: None,
595 })?;
596 Ok(FuzzyTolerance::Percentage(value / 100.0))
597 } else {
598 let value: f64 = text.parse().map_err(|_| ShapeError::ParseError {
599 message: format!("Invalid tolerance value: {}", text),
600 location: None,
601 })?;
602 Ok(FuzzyTolerance::Absolute(value))
603 }
604}
605
606pub fn parse_comparison_op(pair: Pair<Rule>) -> Result<BinaryOp> {
608 match pair.as_str() {
609 ">" => Ok(BinaryOp::Greater),
610 "<" => Ok(BinaryOp::Less),
611 ">=" => Ok(BinaryOp::GreaterEq),
612 "<=" => Ok(BinaryOp::LessEq),
613 "==" => Ok(BinaryOp::Equal),
614 "!=" => Ok(BinaryOp::NotEqual),
615 "~=" => Ok(BinaryOp::FuzzyEqual),
616 "~>" => Ok(BinaryOp::FuzzyGreater),
617 "~<" => Ok(BinaryOp::FuzzyLess),
618 _ => Err(ShapeError::ParseError {
619 message: format!("Unknown comparison operator: {}", pair.as_str()),
620 location: None,
621 }),
622 }
623}
624
625pub fn parse_range_expr(pair: Pair<Rule>) -> Result<Expr> {
632 let span = pair_span(&pair);
633 let pair_loc = pair_location(&pair);
634 let mut inner = pair.into_inner().peekable();
635
636 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
637 message: "expected expression in range".to_string(),
638 location: Some(pair_loc.clone()),
639 })?;
640
641 match first.as_rule() {
642 Rule::range_op => {
643 let kind = parse_range_op(&first);
644 if let Some(end_pair) = inner.next() {
645 let end = parse_additive_expr(end_pair)?;
646 Ok(Expr::Range { start: None, end: Some(Box::new(end)), kind, span })
647 } else {
648 Ok(Expr::Range { start: None, end: None, kind, span })
649 }
650 }
651 Rule::additive_expr => {
652 let start = parse_additive_expr(first)?;
653 if let Some(next) = inner.next() {
654 match next.as_rule() {
655 Rule::range_op => {
656 let kind = parse_range_op(&next);
657 if let Some(end_pair) = inner.next() {
658 let end = parse_additive_expr(end_pair)?;
659 Ok(Expr::Range {
660 start: Some(Box::new(start)),
661 end: Some(Box::new(end)),
662 kind,
663 span,
664 })
665 } else {
666 Ok(Expr::Range {
667 start: Some(Box::new(start)),
668 end: None,
669 kind,
670 span,
671 })
672 }
673 }
674 _ => Err(ShapeError::ParseError {
675 message: format!(
676 "unexpected token in range expression: {:?}",
677 next.as_rule()
678 ),
679 location: Some(pair_loc),
680 }),
681 }
682 } else {
683 Ok(start)
684 }
685 }
686 _ => parse_additive_expr(first),
687 }
688}
689
690fn parse_range_op(pair: &Pair<Rule>) -> RangeKind {
691 if pair.as_str() == "..=" { RangeKind::Inclusive } else { RangeKind::Exclusive }
692}
693
694fn resolve_additive_op(op_str: &str) -> Result<BinaryOp> {
699 match op_str {
700 "+" => Ok(BinaryOp::Add),
701 "-" => Ok(BinaryOp::Sub),
702 _ => Err(ShapeError::ParseError {
703 message: format!("Unknown additive operator: '{}'", op_str),
704 location: None,
705 }),
706 }
707}
708
709fn resolve_shift_op(op_str: &str) -> Result<BinaryOp> {
710 match op_str {
711 "<<" => Ok(BinaryOp::BitShl),
712 ">>" => Ok(BinaryOp::BitShr),
713 _ => Err(ShapeError::ParseError {
714 message: format!("Unknown shift operator: '{}'", op_str),
715 location: None,
716 }),
717 }
718}
719
720fn resolve_multiplicative_op(op_str: &str) -> Result<BinaryOp> {
721 match op_str {
722 "*" => Ok(BinaryOp::Mul),
723 "/" => Ok(BinaryOp::Div),
724 "%" => Ok(BinaryOp::Mod),
725 _ => Err(ShapeError::ParseError {
726 message: format!("Unknown multiplicative operator: '{}'", op_str),
727 location: None,
728 }),
729 }
730}
731
732pub fn parse_additive_expr(pair: Pair<Rule>) -> Result<Expr> {
734 parse_positional_op_chain(pair, "additive", parse_shift_expr, resolve_additive_op)
735}
736
737pub fn parse_shift_expr(pair: Pair<Rule>) -> Result<Expr> {
739 parse_positional_op_chain(pair, "shift", parse_multiplicative_expr, resolve_shift_op)
740}
741
742pub fn parse_multiplicative_expr(pair: Pair<Rule>) -> Result<Expr> {
744 parse_positional_op_chain(pair, "multiplicative", parse_exponential_expr, resolve_multiplicative_op)
745}
746
747pub fn parse_exponential_expr(pair: Pair<Rule>) -> Result<Expr> {
753 let span = pair_span(&pair);
754 let inner_pairs: Vec<_> = pair.into_inner().collect();
755
756 if inner_pairs.is_empty() {
757 return Err(ShapeError::ParseError {
758 message: "Empty exponential expression".to_string(),
759 location: None,
760 });
761 }
762
763 let mut exprs: Vec<Expr> = Vec::new();
764 for p in inner_pairs {
765 exprs.push(parse_unary_expr(p)?);
766 }
767
768 if exprs.len() == 1 {
769 return Ok(exprs.into_iter().next().unwrap());
770 }
771
772 let mut result = exprs.pop().unwrap();
774 while let Some(left_expr) = exprs.pop() {
775 result = Expr::BinaryOp {
776 left: Box::new(left_expr),
777 op: BinaryOp::Pow,
778 right: Box::new(result),
779 span,
780 };
781 }
782
783 Ok(result)
784}
785
786pub fn parse_unary_expr(pair: Pair<Rule>) -> Result<Expr> {
792 let span = pair_span(&pair);
793 let pair_str = pair.as_str();
794 let pair_loc = pair_location(&pair);
795 let mut inner = pair.into_inner();
796 let first = inner.next().ok_or_else(|| ShapeError::ParseError {
797 message: "expected expression in unary operation".to_string(),
798 location: Some(pair_loc.clone()),
799 })?;
800
801 if first.as_rule() == Rule::ref_expr {
803 let ref_span = pair_span(&first);
804 let ref_inner = first.into_inner();
805 let mut is_mutable = false;
806 let mut expr_pair = None;
807 for child in ref_inner {
808 match child.as_rule() {
809 Rule::ref_mut_keyword => {
810 is_mutable = true;
811 }
812 _ => {
813 expr_pair = Some(child);
814 }
815 }
816 }
817 let inner_expr = expr_pair.ok_or_else(|| ShapeError::ParseError {
818 message: "expected expression after &".to_string(),
819 location: Some(pair_loc),
820 })?;
821 let operand = super::primary::parse_postfix_expr(inner_expr)?;
822 return Ok(Expr::Reference {
823 expr: Box::new(operand),
824 is_mutable,
825 span: ref_span,
826 });
827 }
828
829 if pair_str.starts_with('!') {
830 Ok(Expr::UnaryOp {
831 op: UnaryOp::Not,
832 operand: Box::new(parse_unary_expr(first)?),
833 span,
834 })
835 } else if pair_str.starts_with('~') {
836 Ok(Expr::UnaryOp {
837 op: UnaryOp::BitNot,
838 operand: Box::new(parse_unary_expr(first)?),
839 span,
840 })
841 } else if pair_str.starts_with('-') {
842 let operand = parse_unary_expr(first)?;
843 match &operand {
846 Expr::Literal(Literal::TypedInt(value, width), lit_span) => {
847 let neg = value.wrapping_neg();
848 if width.in_range_i64(neg) {
849 return Ok(Expr::Literal(Literal::TypedInt(neg, *width), *lit_span));
850 }
851 }
852 Expr::Literal(Literal::Int(value), lit_span) => {
853 return Ok(Expr::Literal(Literal::Int(-value), *lit_span));
854 }
855 Expr::Literal(Literal::Number(value), lit_span) => {
856 return Ok(Expr::Literal(Literal::Number(-value), *lit_span));
857 }
858 _ => {}
859 }
860 Ok(Expr::UnaryOp {
861 op: UnaryOp::Neg,
862 operand: Box::new(operand),
863 span,
864 })
865 } else {
866 super::primary::parse_postfix_expr(first)
867 }
868}