1use pest::iterators::Pair;
22use pest::Parser as PestParser;
23use pest_derive::Parser;
24use std::fmt;
25
26use super::ast::*;
27
28#[derive(Parser)]
29#[grammar = "grammar.pest"]
30pub struct V2Parser;
31
32#[derive(Debug)]
35pub struct ParseError(pub String);
36
37impl fmt::Display for ParseError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "parse error: {}", self.0)
40 }
41}
42
43impl std::error::Error for ParseError {}
44
45impl From<pest::error::Error<Rule>> for ParseError {
46 fn from(e: pest::error::Error<Rule>) -> Self {
47 ParseError(e.to_string())
48 }
49}
50
51pub fn parse(input: &str) -> Result<Expr, ParseError> {
54 let mut pairs = V2Parser::parse(Rule::program, input)?;
55 let program = pairs.next().unwrap();
56 let expr_pair = program.into_inner().next().unwrap();
57 Ok(parse_expr(expr_pair))
58}
59
60fn is_kw(rule: Rule) -> bool {
63 matches!(
64 rule,
65 Rule::kw_and | Rule::kw_or | Rule::kw_not | Rule::kw_for
66 | Rule::kw_in | Rule::kw_if | Rule::kw_else | Rule::kw_let | Rule::kw_lambda | Rule::kw_kind
67 | Rule::kw_is | Rule::kw_as
68 )
69}
70
71fn parse_expr(pair: Pair<Rule>) -> Expr {
74 match pair.as_rule() {
75 Rule::expr => parse_expr(pair.into_inner().next().unwrap()),
76 Rule::cond_expr => parse_cond(pair),
77 Rule::pipe_expr => parse_pipeline(pair),
78 Rule::coalesce_expr => parse_coalesce(pair),
79 Rule::or_expr => parse_or(pair),
80 Rule::and_expr => parse_and(pair),
81 Rule::not_expr => parse_not(pair),
82 Rule::kind_expr => parse_kind(pair),
83 Rule::cmp_expr => parse_cmp(pair),
84 Rule::add_expr => parse_add(pair),
85 Rule::mul_expr => parse_mul(pair),
86 Rule::cast_expr => parse_cast(pair),
87 Rule::unary_expr => parse_unary(pair),
88 Rule::postfix_expr => parse_postfix_expr(pair),
89 Rule::primary => parse_primary(pair),
90 r => panic!("unexpected rule in parse_expr: {:?}", r),
91 }
92}
93
94fn parse_cond(pair: Pair<Rule>) -> Expr {
101 let mut inner = pair.into_inner().filter(|p| !is_kw(p.as_rule()));
102 let then_ = parse_expr(inner.next().unwrap());
103 let cond = match inner.next() {
104 Some(p) => parse_expr(p),
105 None => return then_,
106 };
107 let else_ = parse_expr(inner.next().unwrap());
108 Expr::IfElse {
109 cond: Box::new(cond),
110 then_: Box::new(then_),
111 else_: Box::new(else_),
112 }
113}
114
115fn parse_pipeline(pair: Pair<Rule>) -> Expr {
118 let mut inner = pair.into_inner();
119 let base = parse_expr(inner.next().unwrap()); let mut steps: Vec<PipeStep> = Vec::new();
121 for step_pair in inner {
122 let inner_step = step_pair.into_inner().next().unwrap();
124 match inner_step.as_rule() {
125 Rule::pipe_forward => {
126 let inner_pair = inner_step.into_inner().next().unwrap();
127 let expr = if inner_pair.as_rule() == Rule::pipe_method_call {
128 let mut mi = inner_pair.into_inner();
129 let name = mi.next().unwrap().as_str().to_string();
130 let args = mi.next().map(parse_arg_list).unwrap_or_default();
131 Expr::Chain(Box::new(Expr::Current), vec![Step::Method(name, args)])
132 } else {
133 parse_expr(inner_pair)
134 };
135 steps.push(PipeStep::Forward(expr));
136 }
137 Rule::pipe_bind => {
138 let target = parse_bind_target(inner_step.into_inner().next().unwrap());
139 steps.push(PipeStep::Bind(target));
140 }
141 r => panic!("unexpected pipe_step inner: {:?}", r),
142 }
143 }
144 if steps.is_empty() { base } else { Expr::Pipeline { base: Box::new(base), steps } }
145}
146
147fn parse_bind_target(pair: Pair<Rule>) -> BindTarget {
148 let inner = pair.into_inner().next().unwrap();
150 match inner.as_rule() {
151 Rule::ident => BindTarget::Name(inner.as_str().to_string()),
152 Rule::bind_obj => {
153 let mut fields = Vec::new();
154 let mut rest = None;
155 for p in inner.into_inner() {
156 match p.as_rule() {
157 Rule::ident => fields.push(p.as_str().to_string()),
158 Rule::bind_rest => {
159 rest = Some(
160 p.into_inner()
161 .find(|x| x.as_rule() == Rule::ident)
162 .unwrap()
163 .as_str()
164 .to_string()
165 );
166 }
167 _ => {}
168 }
169 }
170 BindTarget::Obj { fields, rest }
171 }
172 Rule::bind_arr => {
173 let fields: Vec<String> = inner.into_inner()
174 .filter(|p| p.as_rule() == Rule::ident)
175 .map(|p| p.as_str().to_string())
176 .collect();
177 BindTarget::Arr(fields)
178 }
179 r => panic!("unexpected bind_target inner: {:?}", r),
180 }
181}
182
183fn parse_coalesce(pair: Pair<Rule>) -> Expr {
186 let mut inner = pair.into_inner();
187 let first = parse_expr(inner.next().unwrap());
188 inner.fold(first, |acc, rhs| {
189 Expr::Coalesce(Box::new(acc), Box::new(parse_expr(rhs)))
190 })
191}
192
193fn parse_or(pair: Pair<Rule>) -> Expr {
196 let mut inner = pair.into_inner().filter(|p| !is_kw(p.as_rule()));
197 let first = parse_expr(inner.next().unwrap());
198 inner.fold(first, |acc, rhs| {
199 Expr::BinOp(Box::new(acc), BinOp::Or, Box::new(parse_expr(rhs)))
200 })
201}
202
203fn parse_and(pair: Pair<Rule>) -> Expr {
204 let mut inner = pair.into_inner().filter(|p| !is_kw(p.as_rule()));
205 let first = parse_expr(inner.next().unwrap());
206 inner.fold(first, |acc, rhs| {
207 Expr::BinOp(Box::new(acc), BinOp::And, Box::new(parse_expr(rhs)))
208 })
209}
210
211fn parse_not(pair: Pair<Rule>) -> Expr {
212 let mut inner = pair.into_inner();
213 let first = inner.next().unwrap();
214 if first.as_rule() == Rule::kw_not {
215 let operand = inner.next().unwrap();
216 Expr::Not(Box::new(parse_expr(operand)))
217 } else {
218 parse_expr(first)
219 }
220}
221
222fn parse_kind(pair: Pair<Rule>) -> Expr {
225 let mut inner = pair.into_inner();
226 let cmp = parse_expr(inner.next().unwrap());
227 match inner.next() {
228 None => cmp,
229 Some(p) if matches!(p.as_rule(), Rule::kw_kind | Rule::kw_is) => {
230 let next = inner.next().unwrap();
231 let (negate, kind_type_str) = if next.as_rule() == Rule::kw_not {
232 (true, inner.next().unwrap().as_str())
233 } else {
234 (false, next.as_str())
235 };
236 let ty = match kind_type_str {
237 "null" => KindType::Null,
238 "bool" => KindType::Bool,
239 "number" => KindType::Number,
240 "string" => KindType::Str,
241 "array" => KindType::Array,
242 "object" => KindType::Object,
243 other => panic!("unknown kind type: {}", other),
244 };
245 Expr::Kind { expr: Box::new(cmp), ty, negate }
246 }
247 _ => cmp,
248 }
249}
250
251fn parse_cmp(pair: Pair<Rule>) -> Expr {
254 let mut inner = pair.into_inner();
255 let lhs = parse_expr(inner.next().unwrap());
256 if let Some(op_pair) = inner.next() {
257 let op = match op_pair.as_str() {
258 "==" => BinOp::Eq, "!=" => BinOp::Neq,
259 "<" => BinOp::Lt, "<=" => BinOp::Lte,
260 ">" => BinOp::Gt, ">=" => BinOp::Gte,
261 "~=" => BinOp::Fuzzy,
262 o => panic!("unknown cmp op: {}", o),
263 };
264 let rhs = parse_expr(inner.next().unwrap());
265 Expr::BinOp(Box::new(lhs), op, Box::new(rhs))
266 } else {
267 lhs
268 }
269}
270
271fn parse_add(pair: Pair<Rule>) -> Expr {
274 parse_left_assoc(pair, |s| match s {
275 "+" => Some(BinOp::Add), "-" => Some(BinOp::Sub), _ => None,
276 })
277}
278
279fn parse_mul(pair: Pair<Rule>) -> Expr {
280 parse_left_assoc(pair, |s| match s {
281 "*" => Some(BinOp::Mul), "/" => Some(BinOp::Div), "%" => Some(BinOp::Mod), _ => None,
282 })
283}
284
285fn parse_left_assoc<F>(pair: Pair<Rule>, op_fn: F) -> Expr
286where
287 F: Fn(&str) -> Option<BinOp>,
288{
289 let mut inner = pair.into_inner().peekable();
290 let first = parse_expr(inner.next().unwrap());
291 let mut acc = first;
292 while inner.peek().is_some() {
293 let op_pair = inner.next().unwrap();
294 let op = op_fn(op_pair.as_str()).unwrap();
295 let rhs = parse_expr(inner.next().unwrap());
296 acc = Expr::BinOp(Box::new(acc), op, Box::new(rhs));
297 }
298 acc
299}
300
301fn parse_cast(pair: Pair<Rule>) -> Expr {
304 let mut inner = pair.into_inner().peekable();
306 let mut acc = parse_expr(inner.next().unwrap());
307 while inner.peek().is_some() {
308 let kw = inner.next().unwrap();
310 debug_assert_eq!(kw.as_rule(), Rule::kw_as);
311 let ty_pair = inner.next().unwrap();
312 let ty = match ty_pair.as_str() {
313 "int" => CastType::Int,
314 "float" => CastType::Float,
315 "number" => CastType::Number,
316 "string" => CastType::Str,
317 "bool" => CastType::Bool,
318 "array" => CastType::Array,
319 "object" => CastType::Object,
320 "null" => CastType::Null,
321 o => panic!("unknown cast type: {}", o),
322 };
323 acc = Expr::Cast { expr: Box::new(acc), ty };
324 }
325 acc
326}
327
328fn parse_unary(pair: Pair<Rule>) -> Expr {
331 let mut inner = pair.into_inner();
332 let first = inner.next().unwrap();
333 match first.as_rule() {
334 Rule::unary_neg => {
335 let operand = parse_expr(inner.next().unwrap());
336 Expr::UnaryNeg(Box::new(operand))
337 }
338 _ => parse_expr(first),
339 }
340}
341
342fn parse_postfix_expr(pair: Pair<Rule>) -> Expr {
345 let mut inner = pair.into_inner();
346 let base = parse_primary(inner.next().unwrap());
347 let raw_steps: Vec<Step> = inner.flat_map(parse_postfix_step).collect();
348 let mut steps: Vec<Step> = Vec::with_capacity(raw_steps.len());
360 for s in raw_steps {
361 match s {
362 Step::Quantifier(QuantifierKind::First) => {
363 match steps.last() {
364 Some(Step::Field(_)) => {
365 if let Some(Step::Field(k)) = steps.pop() {
366 steps.push(Step::OptField(k));
367 }
368 }
369 Some(Step::Method(_, _)) => {
370 if let Some(Step::Method(n, a)) = steps.pop() {
371 steps.push(Step::OptMethod(n, a));
372 }
373 }
374 _ => {
375 }
378 }
379 }
380 other => steps.push(other),
381 }
382 }
383 if let Some(rewritten) = classify_chain_write(&base, &steps) {
384 return rewritten;
385 }
386 base.maybe_chain(steps)
387}
388
389fn classify_chain_write(base: &Expr, steps: &[Step]) -> Option<Expr> {
398 if !matches!(base, Expr::Root) { return None; }
399 let last = steps.last()?;
400 let (name, args) = match last { Step::Method(n, a) => (n.as_str(), a), _ => return None };
401 if !is_terminal_write(name) { return None; }
402
403 let prefix = &steps[..steps.len() - 1];
404 let path = match steps_to_path(prefix) {
405 Ok(p) => p,
406 Err(_) => return None, };
408
409 let op = build_write_op(name, args, path)?;
410 Some(Expr::Patch { root: Box::new(Expr::Root), ops: vec![op] })
411}
412
413fn is_terminal_write(name: &str) -> bool {
414 matches!(name, "set" | "modify" | "delete" | "unset" | "merge" | "deep_merge" | "deepMerge")
418}
419
420fn steps_to_path(steps: &[Step]) -> Result<Vec<PathStep>, String> {
421 let mut out = Vec::with_capacity(steps.len());
422 for s in steps {
423 match s {
424 Step::Field(f) => out.push(PathStep::Field(f.clone())),
425 Step::Index(i) => out.push(PathStep::Index(*i)),
426 Step::OptField(f) => out.push(PathStep::Field(f.clone())),
427 Step::Descendant(f) => out.push(PathStep::Descendant(f.clone())),
428 Step::DynIndex(e) => {
429 out.push(PathStep::DynIndex((**e).clone()));
432 }
433 _ => return Err("chain-write: unsupported step in path".into()),
434 }
435 }
436 Ok(out)
437}
438
439fn build_write_op(name: &str, args: &[Arg], path: Vec<PathStep>) -> Option<PatchOp> {
440 match name {
441 "set" => {
442 let v = arg_expr(args.first()?).clone();
443 Some(PatchOp { path, val: v, cond: None })
444 }
445 "modify" => {
450 let v = match arg_expr(args.first()?).clone() {
451 Expr::Lambda { params, body } => {
452 if let Some(p) = params.into_iter().next() {
453 Expr::Let { name: p, init: Box::new(Expr::Current), body }
454 } else {
455 *body
456 }
457 }
458 other => other,
459 };
460 Some(PatchOp { path, val: v, cond: None })
461 }
462 "delete" => {
463 if !args.is_empty() { return None; }
464 Some(PatchOp { path, val: Expr::DeleteMark, cond: None })
465 }
466 "merge" | "deep_merge" | "deepMerge" => {
469 let arg = arg_expr(args.first()?).clone();
470 let method = if name == "merge" { "merge".to_string() } else { "deep_merge".to_string() };
471 let v = Expr::Chain(
472 Box::new(Expr::Current),
473 vec![Step::Method(method, vec![Arg::Pos(arg)])],
474 );
475 Some(PatchOp { path, val: v, cond: None })
476 }
477 "unset" => {
479 let key = match arg_expr(args.first()?) {
480 Expr::Str(s) => s.clone(),
481 Expr::Ident(s) => s.clone(),
482 _ => return None,
483 };
484 let mut p = path;
485 p.push(PathStep::Field(key));
486 Some(PatchOp { path: p, val: Expr::DeleteMark, cond: None })
487 }
488 _ => None,
489 }
490}
491
492fn arg_expr(a: &Arg) -> &Expr {
493 match a { Arg::Pos(e) | Arg::Named(_, e) => e }
494}
495
496fn parse_postfix_step(pair: Pair<Rule>) -> Vec<Step> {
497 let inner_pair = pair.into_inner().next().unwrap();
498 match inner_pair.as_rule() {
499 Rule::field_access => {
500 let name = inner_pair.into_inner().next().unwrap().as_str().to_string();
501 vec![Step::Field(name)]
502 }
503 Rule::descendant => {
504 let mut di = inner_pair.into_inner();
505 match di.next() {
506 Some(p) => vec![Step::Descendant(p.as_str().to_string())],
507 None => vec![Step::DescendAll],
508 }
509 }
510 Rule::deep_method => {
511 let mut mi = inner_pair.into_inner();
513 let name = mi.next().unwrap().as_str().to_string();
514 let args = mi.next().map(parse_arg_list).unwrap_or_default();
515 let mapped = match name.as_str() {
516 "find" | "find_all" | "findAll" => "deep_find".to_string(),
517 "shape" => "deep_shape".to_string(),
518 "like" => "deep_like".to_string(),
519 other => format!("deep_{}", other),
520 };
521 vec![Step::Method(mapped, args)]
522 }
523 Rule::inline_filter => {
524 let expr = parse_expr(inner_pair.into_inner().next().unwrap());
525 vec![Step::InlineFilter(Box::new(expr))]
526 }
527 Rule::quantifier => {
528 let s = inner_pair.as_str();
529 if s.starts_with('!') { vec![Step::Quantifier(QuantifierKind::One)] }
530 else { vec![Step::Quantifier(QuantifierKind::First)] }
531 }
532 Rule::method_call => {
533 let mut mi = inner_pair.into_inner();
534 let name = mi.next().unwrap().as_str().to_string();
535 let args = mi.next().map(parse_arg_list).unwrap_or_default();
536 vec![Step::Method(name, args)]
537 }
538 Rule::index_access => {
539 let bi = inner_pair.into_inner().next().unwrap();
540 vec![parse_bracket(bi)]
541 }
542 Rule::dyn_field => {
543 let expr = parse_expr(inner_pair.into_inner().next().unwrap());
544 vec![Step::DynIndex(Box::new(expr))]
545 }
546 Rule::map_into_shape => {
547 let mut guard: Option<Expr> = None;
551 let mut body: Option<Expr> = None;
552 let mut saw_if = false;
553 for p in inner_pair.into_inner() {
554 match p.as_rule() {
555 Rule::kw_if => saw_if = true,
556 Rule::expr => {
557 if saw_if && guard.is_none() { guard = Some(parse_expr(p)); }
558 else { body = Some(parse_expr(p)); }
559 }
560 _ => {}
561 }
562 }
563 let body = body.expect("map_into_shape requires body");
564 let mut steps = Vec::new();
565 if let Some(g) = guard {
566 steps.push(Step::Method("filter".into(), vec![Arg::Pos(g)]));
567 }
568 steps.push(Step::Method("map".into(), vec![Arg::Pos(body)]));
569 steps
570 }
571 r => panic!("unexpected postfix rule: {:?}", r),
572 }
573}
574
575fn parse_bracket(pair: Pair<Rule>) -> Step {
576 let inner = pair.into_inner().next().unwrap();
577 match inner.as_rule() {
578 Rule::idx_only => Step::Index(inner.as_str().parse().unwrap()),
579 Rule::slice_full => {
580 let mut i = inner.into_inner();
581 let a = i.next().unwrap().as_str().parse().ok();
582 let b = i.next().unwrap().as_str().parse().ok();
583 Step::Slice(a, b)
584 }
585 Rule::slice_from => {
586 let a = inner.into_inner().next().unwrap().as_str().parse().ok();
587 Step::Slice(a, None)
588 }
589 Rule::slice_to => {
590 let b = inner.into_inner().next().unwrap().as_str().parse().ok();
591 Step::Slice(None, b)
592 }
593 Rule::expr => Step::DynIndex(Box::new(parse_expr(inner))),
594 r => panic!("unexpected bracket rule: {:?}", r),
595 }
596}
597
598fn parse_primary(pair: Pair<Rule>) -> Expr {
601 let inner = if pair.as_rule() == Rule::primary {
602 pair.into_inner().next().unwrap()
603 } else {
604 pair
605 };
606 match inner.as_rule() {
607 Rule::literal => parse_literal(inner),
608 Rule::root => Expr::Root,
609 Rule::current => Expr::Current,
610 Rule::ident => Expr::Ident(inner.as_str().to_string()),
611 Rule::let_expr => parse_let(inner),
612 Rule::lambda_expr => parse_lambda(inner),
613 Rule::arrow_lambda => parse_arrow_lambda(inner),
614 Rule::list_comp => parse_list_comp(inner),
615 Rule::dict_comp => parse_dict_comp(inner),
616 Rule::set_comp => parse_set_comp(inner),
617 Rule::gen_comp => parse_gen_comp(inner),
618 Rule::obj_construct => parse_obj(inner),
619 Rule::arr_construct => parse_arr(inner),
620 Rule::global_call => parse_global_call(inner),
621 Rule::expr => parse_expr(inner),
622 Rule::patch_block => parse_patch(inner),
623 Rule::kw_delete => Expr::DeleteMark,
624 r => panic!("unexpected primary rule: {:?}", r),
625 }
626}
627
628fn parse_literal(pair: Pair<Rule>) -> Expr {
631 let inner = pair.into_inner().next().unwrap();
632 match inner.as_rule() {
633 Rule::lit_null => Expr::Null,
634 Rule::lit_true => Expr::Bool(true),
635 Rule::lit_false => Expr::Bool(false),
636 Rule::lit_int => Expr::Int(inner.as_str().parse().unwrap()),
637 Rule::lit_float => Expr::Float(inner.as_str().parse().unwrap()),
638 Rule::lit_fstring => {
639 let raw = inner.as_str();
640 let content = &raw[2..raw.len() - 1]; let parts = parse_fstring_content(content);
642 Expr::FString(parts)
643 }
644 Rule::lit_str => {
645 let s = inner.into_inner().next().unwrap();
646 let raw = s.as_str();
647 Expr::Str(raw[1..raw.len()-1].to_string())
649 }
650 r => panic!("unexpected literal rule: {:?}", r),
651 }
652}
653
654fn parse_fstring_content(raw: &str) -> Vec<FStringPart> {
657 let mut parts = Vec::new();
658 let mut lit = String::new();
659 let mut chars = raw.chars().peekable();
660
661 while let Some(c) = chars.next() {
662 match c {
663 '{' => {
664 if chars.peek() == Some(&'{') {
665 chars.next();
666 lit.push('{');
667 } else {
668 if !lit.is_empty() {
669 parts.push(FStringPart::Lit(std::mem::take(&mut lit)));
670 }
671 let mut inner = String::new();
672 let mut depth = 1usize;
673 for c2 in chars.by_ref() {
674 match c2 {
675 '{' => { depth += 1; inner.push(c2); }
676 '}' => {
677 depth -= 1;
678 if depth == 0 { break; }
679 inner.push(c2);
680 }
681 _ => inner.push(c2),
682 }
683 }
684 let (expr_str, fmt) = split_fstring_interp(&inner);
685 let expr = parse(expr_str.trim())
686 .unwrap_or_else(|e| panic!("f-string parse error in {{{}}}: {}", inner, e));
687 parts.push(FStringPart::Interp { expr, fmt });
688 }
689 }
690 '}' if chars.peek() == Some(&'}') => {
691 chars.next();
692 lit.push('}');
693 }
694 _ => lit.push(c),
695 }
696 }
697 if !lit.is_empty() {
698 parts.push(FStringPart::Lit(lit));
699 }
700 parts
701}
702
703fn split_fstring_interp(inner: &str) -> (&str, Option<FmtSpec>) {
704 let mut depth = 0usize;
706 let mut pipe_pos: Option<usize> = None;
707 let mut colon_pos: Option<usize> = None;
708 for (i, c) in inner.char_indices() {
709 match c {
710 '(' | '[' | '{' => depth += 1,
711 ')' | ']' | '}' => { if depth > 0 { depth -= 1; } }
712 '|' if depth == 0 && pipe_pos.is_none() => pipe_pos = Some(i),
713 ':' if depth == 0 && colon_pos.is_none() => colon_pos = Some(i),
714 _ => {}
715 }
716 }
717 if let Some(p) = pipe_pos {
718 return (&inner[..p], Some(FmtSpec::Pipe(inner[p + 1..].trim().to_string())));
719 }
720 if let Some(c) = colon_pos {
721 return (&inner[..c], Some(FmtSpec::Spec(inner[c + 1..].to_string())));
722 }
723 (inner, None)
724}
725
726fn parse_let(pair: Pair<Rule>) -> Expr {
729 let inner: Vec<Pair<Rule>> = pair.into_inner()
732 .filter(|p| !matches!(p.as_rule(), Rule::kw_let | Rule::kw_in))
733 .collect();
734 let (bindings, body_pair) = inner.split_at(inner.len() - 1);
735 let body = parse_expr(body_pair[0].clone());
736 bindings.iter().rev().fold(body, |acc, b| {
737 let mut bi = b.clone().into_inner();
738 let name = bi.next().unwrap().as_str().to_string();
739 let init = parse_expr(bi.next().unwrap());
740 Expr::Let { name, init: Box::new(init), body: Box::new(acc) }
741 })
742}
743
744fn parse_lambda(pair: Pair<Rule>) -> Expr {
747 let mut inner = pair.into_inner()
748 .filter(|p| p.as_rule() != Rule::kw_lambda);
749 let params_pair = inner.next().unwrap();
750 let params: Vec<String> = params_pair
751 .into_inner()
752 .filter(|p| p.as_rule() == Rule::ident)
753 .map(|p| p.as_str().to_string())
754 .collect();
755 let body = parse_expr(inner.next().unwrap());
756 Expr::Lambda { params, body: Box::new(body) }
757}
758
759fn parse_arrow_lambda(pair: Pair<Rule>) -> Expr {
762 let mut inner = pair.into_inner();
763 let params_pair = inner.next().unwrap();
764 let params: Vec<String> = params_pair
765 .into_inner()
766 .filter(|p| p.as_rule() == Rule::ident)
767 .map(|p| p.as_str().to_string())
768 .collect();
769 let body = parse_expr(inner.next().unwrap());
770 Expr::Lambda { params, body: Box::new(body) }
771}
772
773fn comp_inner_filter(pair: Pair<Rule>) -> impl Iterator<Item = Pair<Rule>> {
776 pair.into_inner()
777 .filter(|p| !matches!(p.as_rule(), Rule::kw_for | Rule::kw_in | Rule::kw_if))
778}
779
780fn parse_comp_vars(pair: Pair<Rule>) -> Vec<String> {
781 pair.into_inner()
782 .filter(|p| p.as_rule() == Rule::ident)
783 .map(|p| p.as_str().to_string())
784 .collect()
785}
786
787fn parse_list_comp(pair: Pair<Rule>) -> Expr {
788 let mut inner = comp_inner_filter(pair);
789 let expr = parse_expr(inner.next().unwrap());
790 let vars = parse_comp_vars(inner.next().unwrap());
791 let iter = parse_expr(inner.next().unwrap());
792 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
793 Expr::ListComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
794}
795
796fn parse_dict_comp(pair: Pair<Rule>) -> Expr {
797 let mut inner = comp_inner_filter(pair);
798 let key = parse_expr(inner.next().unwrap());
799 let val = parse_expr(inner.next().unwrap());
800 let vars = parse_comp_vars(inner.next().unwrap());
801 let iter = parse_expr(inner.next().unwrap());
802 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
803 Expr::DictComp { key: Box::new(key), val: Box::new(val), vars, iter: Box::new(iter), cond }
804}
805
806fn parse_set_comp(pair: Pair<Rule>) -> Expr {
807 let mut inner = comp_inner_filter(pair);
808 let expr = parse_expr(inner.next().unwrap());
809 let vars = parse_comp_vars(inner.next().unwrap());
810 let iter = parse_expr(inner.next().unwrap());
811 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
812 Expr::SetComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
813}
814
815fn parse_gen_comp(pair: Pair<Rule>) -> Expr {
816 let mut inner = comp_inner_filter(pair);
817 let expr = parse_expr(inner.next().unwrap());
818 let vars = parse_comp_vars(inner.next().unwrap());
819 let iter = parse_expr(inner.next().unwrap());
820 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
821 Expr::GenComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
822}
823
824fn parse_obj(pair: Pair<Rule>) -> Expr {
827 let fields = pair.into_inner()
828 .filter(|p| p.as_rule() == Rule::obj_field)
829 .map(parse_obj_field)
830 .collect();
831 Expr::Object(fields)
832}
833
834fn parse_obj_field(pair: Pair<Rule>) -> ObjField {
835 let inner = pair.into_inner().next().unwrap();
836 match inner.as_rule() {
837 Rule::obj_field_dyn => {
838 let mut i = inner.into_inner();
839 let key = parse_expr(i.next().unwrap());
840 let val = parse_expr(i.next().unwrap());
841 ObjField::Dynamic { key, val }
842 }
843 Rule::obj_field_opt_v => {
844 let mut i = inner.into_inner();
845 let key = obj_key_str(i.next().unwrap());
846 let val = parse_expr(i.next().unwrap());
847 ObjField::Kv { key, val, optional: true, cond: None }
848 }
849 Rule::obj_field_opt => {
850 let key = obj_key_str(inner.into_inner().next().unwrap());
851 ObjField::Kv { key: key.clone(), val: Expr::Ident(key), optional: true, cond: None }
852 }
853 Rule::obj_field_spread => {
854 let expr = parse_expr(inner.into_inner().next().unwrap());
855 ObjField::Spread(expr)
856 }
857 Rule::obj_field_spread_deep => {
858 let expr = parse_expr(inner.into_inner().next().unwrap());
859 ObjField::SpreadDeep(expr)
860 }
861 Rule::obj_field_kv => {
862 let mut cond: Option<Expr> = None;
863 let mut key: Option<String> = None;
864 let mut val: Option<Expr> = None;
865 let mut saw_when = false;
866 for p in inner.into_inner() {
867 match p.as_rule() {
868 Rule::kw_when => saw_when = true,
869 Rule::obj_key_expr => key = Some(obj_key_str(p)),
870 Rule::expr => {
871 if saw_when { cond = Some(parse_expr(p)); }
872 else { val = Some(parse_expr(p)); }
873 }
874 _ => {}
875 }
876 }
877 ObjField::Kv {
878 key: key.expect("obj_field_kv missing key"),
879 val: val.expect("obj_field_kv missing val"),
880 optional: false,
881 cond,
882 }
883 }
884 Rule::obj_field_short => {
885 let name = inner.into_inner().next().unwrap().as_str().to_string();
886 ObjField::Short(name)
887 }
888 r => panic!("unexpected obj_field rule: {:?}", r),
889 }
890}
891
892fn obj_key_str(pair: Pair<Rule>) -> String {
893 let inner = pair.into_inner().next().unwrap();
894 match inner.as_rule() {
895 Rule::ident => inner.as_str().to_string(),
896 Rule::lit_str => {
897 let s = inner.into_inner().next().unwrap();
898 let raw = s.as_str();
899 raw[1..raw.len()-1].to_string()
900 }
901 r => panic!("unexpected obj_key_expr rule: {:?}", r),
902 }
903}
904
905fn parse_arr(pair: Pair<Rule>) -> Expr {
906 let elems = pair.into_inner()
907 .filter(|p| p.as_rule() == Rule::arr_elem)
908 .map(|elem| {
909 let inner = elem.into_inner().next().unwrap();
910 match inner.as_rule() {
911 Rule::arr_spread => {
912 let expr = parse_expr(inner.into_inner().next().unwrap());
913 ArrayElem::Spread(expr)
914 }
915 _ => ArrayElem::Expr(parse_expr(inner)),
916 }
917 })
918 .collect();
919 Expr::Array(elems)
920}
921
922fn parse_global_call(pair: Pair<Rule>) -> Expr {
925 let mut inner = pair.into_inner();
926 let name = inner.next().unwrap().as_str().to_string();
927 let args = inner.next().map(parse_arg_list).unwrap_or_default();
928 Expr::GlobalCall { name, args }
929}
930
931fn parse_patch(pair: Pair<Rule>) -> Expr {
934 let mut root: Option<Expr> = None;
935 let mut ops: Vec<PatchOp> = Vec::new();
936 for p in pair.into_inner() {
937 match p.as_rule() {
938 Rule::kw_patch => {}
939 Rule::patch_field => ops.push(parse_patch_field(p)),
940 _ => {
941 if root.is_none() { root = Some(parse_expr(p)); }
944 }
945 }
946 }
947 Expr::Patch {
948 root: Box::new(root.expect("patch requires root expression")),
949 ops,
950 }
951}
952
953fn parse_patch_field(pair: Pair<Rule>) -> PatchOp {
954 let mut path: Vec<PathStep> = Vec::new();
955 let mut val: Option<Expr> = None;
956 let mut cond: Option<Expr> = None;
957 let mut saw_when = false;
958 for p in pair.into_inner() {
959 match p.as_rule() {
960 Rule::patch_key => path = parse_patch_key(p),
961 Rule::kw_when => saw_when = true,
962 Rule::expr => {
963 if saw_when { cond = Some(parse_expr(p)); }
964 else { val = Some(parse_expr(p)); }
965 }
966 _ => {}
967 }
968 }
969 PatchOp {
970 path,
971 val: val.expect("patch_field missing val"),
972 cond,
973 }
974}
975
976fn parse_patch_key(pair: Pair<Rule>) -> Vec<PathStep> {
977 let mut steps: Vec<PathStep> = Vec::new();
978 let mut first = true;
979 for p in pair.into_inner() {
980 match p.as_rule() {
981 Rule::ident if first => {
982 steps.push(PathStep::Field(p.as_str().to_string()));
983 first = false;
984 }
985 Rule::patch_step => steps.push(parse_patch_step(p)),
986 _ => {}
987 }
988 }
989 steps
990}
991
992fn parse_patch_step(pair: Pair<Rule>) -> PathStep {
993 let inner = pair.into_inner().next().unwrap();
994 match inner.as_rule() {
995 Rule::pp_dot_field => {
996 let name = inner.into_inner().next().unwrap().as_str().to_string();
997 PathStep::Field(name)
998 }
999 Rule::pp_index => {
1000 let idx: i64 = inner.into_inner().next().unwrap().as_str().parse().unwrap();
1001 PathStep::Index(idx)
1002 }
1003 Rule::pp_wild => PathStep::Wildcard,
1004 Rule::pp_wild_filter => {
1005 let mut e: Option<Expr> = None;
1007 for p in inner.into_inner() {
1008 if p.as_rule() == Rule::expr { e = Some(parse_expr(p)); }
1009 }
1010 PathStep::WildcardFilter(Box::new(e.expect("pp_wild_filter missing expr")))
1011 }
1012 Rule::pp_descendant => {
1013 let name = inner.into_inner().next().unwrap().as_str().to_string();
1014 PathStep::Descendant(name)
1015 }
1016 r => panic!("unexpected patch_step rule: {:?}", r),
1017 }
1018}
1019
1020fn parse_arg_list(pair: Pair<Rule>) -> Vec<Arg> {
1023 pair.into_inner()
1024 .filter(|p| p.as_rule() == Rule::arg)
1025 .map(parse_arg)
1026 .collect()
1027}
1028
1029fn parse_arg(pair: Pair<Rule>) -> Arg {
1030 let inner = pair.into_inner().next().unwrap();
1031 match inner.as_rule() {
1032 Rule::named_arg => {
1033 let mut i = inner.into_inner();
1034 let name = i.next().unwrap().as_str().to_string();
1035 let val = parse_expr(i.next().unwrap());
1036 Arg::Named(name, val)
1037 }
1038 Rule::pos_arg => {
1039 Arg::Pos(parse_expr(inner.into_inner().next().unwrap()))
1040 }
1041 r => panic!("unexpected arg rule: {:?}", r),
1042 }
1043}