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_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::pipe_expr => parse_pipeline(pair),
77 Rule::coalesce_expr => parse_coalesce(pair),
78 Rule::or_expr => parse_or(pair),
79 Rule::and_expr => parse_and(pair),
80 Rule::not_expr => parse_not(pair),
81 Rule::kind_expr => parse_kind(pair),
82 Rule::cmp_expr => parse_cmp(pair),
83 Rule::add_expr => parse_add(pair),
84 Rule::mul_expr => parse_mul(pair),
85 Rule::cast_expr => parse_cast(pair),
86 Rule::unary_expr => parse_unary(pair),
87 Rule::postfix_expr => parse_postfix_expr(pair),
88 Rule::primary => parse_primary(pair),
89 r => panic!("unexpected rule in parse_expr: {:?}", r),
90 }
91}
92
93fn parse_pipeline(pair: Pair<Rule>) -> Expr {
96 let mut inner = pair.into_inner();
97 let base = parse_expr(inner.next().unwrap()); let mut steps: Vec<PipeStep> = Vec::new();
99 for step_pair in inner {
100 let inner_step = step_pair.into_inner().next().unwrap();
102 match inner_step.as_rule() {
103 Rule::pipe_forward => {
104 let inner_pair = inner_step.into_inner().next().unwrap();
105 let expr = if inner_pair.as_rule() == Rule::pipe_method_call {
106 let mut mi = inner_pair.into_inner();
107 let name = mi.next().unwrap().as_str().to_string();
108 let args = mi.next().map(parse_arg_list).unwrap_or_default();
109 Expr::Chain(Box::new(Expr::Current), vec![Step::Method(name, args)])
110 } else {
111 parse_expr(inner_pair)
112 };
113 steps.push(PipeStep::Forward(expr));
114 }
115 Rule::pipe_bind => {
116 let target = parse_bind_target(inner_step.into_inner().next().unwrap());
117 steps.push(PipeStep::Bind(target));
118 }
119 r => panic!("unexpected pipe_step inner: {:?}", r),
120 }
121 }
122 if steps.is_empty() { base } else { Expr::Pipeline { base: Box::new(base), steps } }
123}
124
125fn parse_bind_target(pair: Pair<Rule>) -> BindTarget {
126 let inner = pair.into_inner().next().unwrap();
128 match inner.as_rule() {
129 Rule::ident => BindTarget::Name(inner.as_str().to_string()),
130 Rule::bind_obj => {
131 let mut fields = Vec::new();
132 let mut rest = None;
133 for p in inner.into_inner() {
134 match p.as_rule() {
135 Rule::ident => fields.push(p.as_str().to_string()),
136 Rule::bind_rest => {
137 rest = Some(
138 p.into_inner()
139 .find(|x| x.as_rule() == Rule::ident)
140 .unwrap()
141 .as_str()
142 .to_string()
143 );
144 }
145 _ => {}
146 }
147 }
148 BindTarget::Obj { fields, rest }
149 }
150 Rule::bind_arr => {
151 let fields: Vec<String> = inner.into_inner()
152 .filter(|p| p.as_rule() == Rule::ident)
153 .map(|p| p.as_str().to_string())
154 .collect();
155 BindTarget::Arr(fields)
156 }
157 r => panic!("unexpected bind_target inner: {:?}", r),
158 }
159}
160
161fn parse_coalesce(pair: Pair<Rule>) -> Expr {
164 let mut inner = pair.into_inner();
165 let first = parse_expr(inner.next().unwrap());
166 inner.fold(first, |acc, rhs| {
167 Expr::Coalesce(Box::new(acc), Box::new(parse_expr(rhs)))
168 })
169}
170
171fn parse_or(pair: Pair<Rule>) -> Expr {
174 let mut inner = pair.into_inner().filter(|p| !is_kw(p.as_rule()));
175 let first = parse_expr(inner.next().unwrap());
176 inner.fold(first, |acc, rhs| {
177 Expr::BinOp(Box::new(acc), BinOp::Or, Box::new(parse_expr(rhs)))
178 })
179}
180
181fn parse_and(pair: Pair<Rule>) -> Expr {
182 let mut inner = pair.into_inner().filter(|p| !is_kw(p.as_rule()));
183 let first = parse_expr(inner.next().unwrap());
184 inner.fold(first, |acc, rhs| {
185 Expr::BinOp(Box::new(acc), BinOp::And, Box::new(parse_expr(rhs)))
186 })
187}
188
189fn parse_not(pair: Pair<Rule>) -> Expr {
190 let mut inner = pair.into_inner();
191 let first = inner.next().unwrap();
192 if first.as_rule() == Rule::kw_not {
193 let operand = inner.next().unwrap();
194 Expr::Not(Box::new(parse_expr(operand)))
195 } else {
196 parse_expr(first)
197 }
198}
199
200fn parse_kind(pair: Pair<Rule>) -> Expr {
203 let mut inner = pair.into_inner();
204 let cmp = parse_expr(inner.next().unwrap());
205 match inner.next() {
206 None => cmp,
207 Some(p) if matches!(p.as_rule(), Rule::kw_kind | Rule::kw_is) => {
208 let next = inner.next().unwrap();
209 let (negate, kind_type_str) = if next.as_rule() == Rule::kw_not {
210 (true, inner.next().unwrap().as_str())
211 } else {
212 (false, next.as_str())
213 };
214 let ty = match kind_type_str {
215 "null" => KindType::Null,
216 "bool" => KindType::Bool,
217 "number" => KindType::Number,
218 "string" => KindType::Str,
219 "array" => KindType::Array,
220 "object" => KindType::Object,
221 other => panic!("unknown kind type: {}", other),
222 };
223 Expr::Kind { expr: Box::new(cmp), ty, negate }
224 }
225 _ => cmp,
226 }
227}
228
229fn parse_cmp(pair: Pair<Rule>) -> Expr {
232 let mut inner = pair.into_inner();
233 let lhs = parse_expr(inner.next().unwrap());
234 if let Some(op_pair) = inner.next() {
235 let op = match op_pair.as_str() {
236 "==" => BinOp::Eq, "!=" => BinOp::Neq,
237 "<" => BinOp::Lt, "<=" => BinOp::Lte,
238 ">" => BinOp::Gt, ">=" => BinOp::Gte,
239 "~=" => BinOp::Fuzzy,
240 o => panic!("unknown cmp op: {}", o),
241 };
242 let rhs = parse_expr(inner.next().unwrap());
243 Expr::BinOp(Box::new(lhs), op, Box::new(rhs))
244 } else {
245 lhs
246 }
247}
248
249fn parse_add(pair: Pair<Rule>) -> Expr {
252 parse_left_assoc(pair, |s| match s {
253 "+" => Some(BinOp::Add), "-" => Some(BinOp::Sub), _ => None,
254 })
255}
256
257fn parse_mul(pair: Pair<Rule>) -> Expr {
258 parse_left_assoc(pair, |s| match s {
259 "*" => Some(BinOp::Mul), "/" => Some(BinOp::Div), "%" => Some(BinOp::Mod), _ => None,
260 })
261}
262
263fn parse_left_assoc<F>(pair: Pair<Rule>, op_fn: F) -> Expr
264where
265 F: Fn(&str) -> Option<BinOp>,
266{
267 let mut inner = pair.into_inner().peekable();
268 let first = parse_expr(inner.next().unwrap());
269 let mut acc = first;
270 while inner.peek().is_some() {
271 let op_pair = inner.next().unwrap();
272 let op = op_fn(op_pair.as_str()).unwrap();
273 let rhs = parse_expr(inner.next().unwrap());
274 acc = Expr::BinOp(Box::new(acc), op, Box::new(rhs));
275 }
276 acc
277}
278
279fn parse_cast(pair: Pair<Rule>) -> Expr {
282 let mut inner = pair.into_inner().peekable();
284 let mut acc = parse_expr(inner.next().unwrap());
285 while inner.peek().is_some() {
286 let kw = inner.next().unwrap();
288 debug_assert_eq!(kw.as_rule(), Rule::kw_as);
289 let ty_pair = inner.next().unwrap();
290 let ty = match ty_pair.as_str() {
291 "int" => CastType::Int,
292 "float" => CastType::Float,
293 "number" => CastType::Number,
294 "string" => CastType::Str,
295 "bool" => CastType::Bool,
296 "array" => CastType::Array,
297 "object" => CastType::Object,
298 "null" => CastType::Null,
299 o => panic!("unknown cast type: {}", o),
300 };
301 acc = Expr::Cast { expr: Box::new(acc), ty };
302 }
303 acc
304}
305
306fn parse_unary(pair: Pair<Rule>) -> Expr {
309 let mut inner = pair.into_inner();
310 let first = inner.next().unwrap();
311 match first.as_rule() {
312 Rule::unary_neg => {
313 let operand = parse_expr(inner.next().unwrap());
314 Expr::UnaryNeg(Box::new(operand))
315 }
316 _ => parse_expr(first),
317 }
318}
319
320fn parse_postfix_expr(pair: Pair<Rule>) -> Expr {
323 let mut inner = pair.into_inner();
324 let base = parse_primary(inner.next().unwrap());
325 let steps: Vec<Step> = inner.flat_map(parse_postfix_step).collect();
326 base.maybe_chain(steps)
327}
328
329fn parse_postfix_step(pair: Pair<Rule>) -> Vec<Step> {
330 let inner_pair = pair.into_inner().next().unwrap();
331 match inner_pair.as_rule() {
332 Rule::field_access => {
333 let name = inner_pair.into_inner().next().unwrap().as_str().to_string();
334 vec![Step::Field(name)]
335 }
336 Rule::opt_field => {
337 let name = inner_pair.into_inner().next().unwrap().as_str().to_string();
338 vec![Step::OptField(name)]
339 }
340 Rule::descendant => {
341 let mut di = inner_pair.into_inner();
342 match di.next() {
343 Some(p) => vec![Step::Descendant(p.as_str().to_string())],
344 None => vec![Step::DescendAll],
345 }
346 }
347 Rule::inline_filter => {
348 let expr = parse_expr(inner_pair.into_inner().next().unwrap());
349 vec![Step::InlineFilter(Box::new(expr))]
350 }
351 Rule::quantifier => {
352 let s = inner_pair.as_str();
353 if s.starts_with('!') { vec![Step::Quantifier(QuantifierKind::One)] }
354 else { vec![Step::Quantifier(QuantifierKind::First)] }
355 }
356 Rule::method_call => {
357 let mut mi = inner_pair.into_inner();
358 let name = mi.next().unwrap().as_str().to_string();
359 let args = mi.next().map(parse_arg_list).unwrap_or_default();
360 vec![Step::Method(name, args)]
361 }
362 Rule::opt_method => {
363 let mut mi = inner_pair.into_inner();
364 let name = mi.next().unwrap().as_str().to_string();
365 let args = mi.next().map(parse_arg_list).unwrap_or_default();
366 vec![Step::OptMethod(name, args)]
367 }
368 Rule::index_access => {
369 let bi = inner_pair.into_inner().next().unwrap();
370 vec![parse_bracket(bi)]
371 }
372 Rule::dyn_field => {
373 let expr = parse_expr(inner_pair.into_inner().next().unwrap());
374 vec![Step::DynIndex(Box::new(expr))]
375 }
376 Rule::map_into_shape => {
377 let mut guard: Option<Expr> = None;
381 let mut body: Option<Expr> = None;
382 let mut saw_if = false;
383 for p in inner_pair.into_inner() {
384 match p.as_rule() {
385 Rule::kw_if => saw_if = true,
386 Rule::expr => {
387 if saw_if && guard.is_none() { guard = Some(parse_expr(p)); }
388 else { body = Some(parse_expr(p)); }
389 }
390 _ => {}
391 }
392 }
393 let body = body.expect("map_into_shape requires body");
394 let mut steps = Vec::new();
395 if let Some(g) = guard {
396 steps.push(Step::Method("filter".into(), vec![Arg::Pos(g)]));
397 }
398 steps.push(Step::Method("map".into(), vec![Arg::Pos(body)]));
399 steps
400 }
401 r => panic!("unexpected postfix rule: {:?}", r),
402 }
403}
404
405fn parse_bracket(pair: Pair<Rule>) -> Step {
406 let inner = pair.into_inner().next().unwrap();
407 match inner.as_rule() {
408 Rule::idx_only => Step::Index(inner.as_str().parse().unwrap()),
409 Rule::slice_full => {
410 let mut i = inner.into_inner();
411 let a = i.next().unwrap().as_str().parse().ok();
412 let b = i.next().unwrap().as_str().parse().ok();
413 Step::Slice(a, b)
414 }
415 Rule::slice_from => {
416 let a = inner.into_inner().next().unwrap().as_str().parse().ok();
417 Step::Slice(a, None)
418 }
419 Rule::slice_to => {
420 let b = inner.into_inner().next().unwrap().as_str().parse().ok();
421 Step::Slice(None, b)
422 }
423 Rule::expr => Step::DynIndex(Box::new(parse_expr(inner))),
424 r => panic!("unexpected bracket rule: {:?}", r),
425 }
426}
427
428fn parse_primary(pair: Pair<Rule>) -> Expr {
431 let inner = if pair.as_rule() == Rule::primary {
432 pair.into_inner().next().unwrap()
433 } else {
434 pair
435 };
436 match inner.as_rule() {
437 Rule::literal => parse_literal(inner),
438 Rule::root => Expr::Root,
439 Rule::current => Expr::Current,
440 Rule::ident => Expr::Ident(inner.as_str().to_string()),
441 Rule::let_expr => parse_let(inner),
442 Rule::lambda_expr => parse_lambda(inner),
443 Rule::arrow_lambda => parse_arrow_lambda(inner),
444 Rule::list_comp => parse_list_comp(inner),
445 Rule::dict_comp => parse_dict_comp(inner),
446 Rule::set_comp => parse_set_comp(inner),
447 Rule::gen_comp => parse_gen_comp(inner),
448 Rule::obj_construct => parse_obj(inner),
449 Rule::arr_construct => parse_arr(inner),
450 Rule::global_call => parse_global_call(inner),
451 Rule::expr => parse_expr(inner),
452 Rule::patch_block => parse_patch(inner),
453 Rule::kw_delete => Expr::DeleteMark,
454 r => panic!("unexpected primary rule: {:?}", r),
455 }
456}
457
458fn parse_literal(pair: Pair<Rule>) -> Expr {
461 let inner = pair.into_inner().next().unwrap();
462 match inner.as_rule() {
463 Rule::lit_null => Expr::Null,
464 Rule::lit_true => Expr::Bool(true),
465 Rule::lit_false => Expr::Bool(false),
466 Rule::lit_int => Expr::Int(inner.as_str().parse().unwrap()),
467 Rule::lit_float => Expr::Float(inner.as_str().parse().unwrap()),
468 Rule::lit_fstring => {
469 let raw = inner.as_str();
470 let content = &raw[2..raw.len() - 1]; let parts = parse_fstring_content(content);
472 Expr::FString(parts)
473 }
474 Rule::lit_str => {
475 let s = inner.into_inner().next().unwrap();
476 let raw = s.as_str();
477 Expr::Str(raw[1..raw.len()-1].to_string())
479 }
480 r => panic!("unexpected literal rule: {:?}", r),
481 }
482}
483
484fn parse_fstring_content(raw: &str) -> Vec<FStringPart> {
487 let mut parts = Vec::new();
488 let mut lit = String::new();
489 let mut chars = raw.chars().peekable();
490
491 while let Some(c) = chars.next() {
492 match c {
493 '{' => {
494 if chars.peek() == Some(&'{') {
495 chars.next();
496 lit.push('{');
497 } else {
498 if !lit.is_empty() {
499 parts.push(FStringPart::Lit(std::mem::take(&mut lit)));
500 }
501 let mut inner = String::new();
502 let mut depth = 1usize;
503 for c2 in chars.by_ref() {
504 match c2 {
505 '{' => { depth += 1; inner.push(c2); }
506 '}' => {
507 depth -= 1;
508 if depth == 0 { break; }
509 inner.push(c2);
510 }
511 _ => inner.push(c2),
512 }
513 }
514 let (expr_str, fmt) = split_fstring_interp(&inner);
515 let expr = parse(expr_str.trim())
516 .unwrap_or_else(|e| panic!("f-string parse error in {{{}}}: {}", inner, e));
517 parts.push(FStringPart::Interp { expr, fmt });
518 }
519 }
520 '}' if chars.peek() == Some(&'}') => {
521 chars.next();
522 lit.push('}');
523 }
524 _ => lit.push(c),
525 }
526 }
527 if !lit.is_empty() {
528 parts.push(FStringPart::Lit(lit));
529 }
530 parts
531}
532
533fn split_fstring_interp(inner: &str) -> (&str, Option<FmtSpec>) {
534 let mut depth = 0usize;
536 let mut pipe_pos: Option<usize> = None;
537 let mut colon_pos: Option<usize> = None;
538 for (i, c) in inner.char_indices() {
539 match c {
540 '(' | '[' | '{' => depth += 1,
541 ')' | ']' | '}' => { if depth > 0 { depth -= 1; } }
542 '|' if depth == 0 && pipe_pos.is_none() => pipe_pos = Some(i),
543 ':' if depth == 0 && colon_pos.is_none() => colon_pos = Some(i),
544 _ => {}
545 }
546 }
547 if let Some(p) = pipe_pos {
548 return (&inner[..p], Some(FmtSpec::Pipe(inner[p + 1..].trim().to_string())));
549 }
550 if let Some(c) = colon_pos {
551 return (&inner[..c], Some(FmtSpec::Spec(inner[c + 1..].to_string())));
552 }
553 (inner, None)
554}
555
556fn parse_let(pair: Pair<Rule>) -> Expr {
559 let inner: Vec<Pair<Rule>> = pair.into_inner()
562 .filter(|p| !matches!(p.as_rule(), Rule::kw_let | Rule::kw_in))
563 .collect();
564 let (bindings, body_pair) = inner.split_at(inner.len() - 1);
565 let body = parse_expr(body_pair[0].clone());
566 bindings.iter().rev().fold(body, |acc, b| {
567 let mut bi = b.clone().into_inner();
568 let name = bi.next().unwrap().as_str().to_string();
569 let init = parse_expr(bi.next().unwrap());
570 Expr::Let { name, init: Box::new(init), body: Box::new(acc) }
571 })
572}
573
574fn parse_lambda(pair: Pair<Rule>) -> Expr {
577 let mut inner = pair.into_inner()
578 .filter(|p| p.as_rule() != Rule::kw_lambda);
579 let params_pair = inner.next().unwrap();
580 let params: Vec<String> = params_pair
581 .into_inner()
582 .filter(|p| p.as_rule() == Rule::ident)
583 .map(|p| p.as_str().to_string())
584 .collect();
585 let body = parse_expr(inner.next().unwrap());
586 Expr::Lambda { params, body: Box::new(body) }
587}
588
589fn parse_arrow_lambda(pair: Pair<Rule>) -> Expr {
592 let mut inner = pair.into_inner();
593 let params_pair = inner.next().unwrap();
594 let params: Vec<String> = params_pair
595 .into_inner()
596 .filter(|p| p.as_rule() == Rule::ident)
597 .map(|p| p.as_str().to_string())
598 .collect();
599 let body = parse_expr(inner.next().unwrap());
600 Expr::Lambda { params, body: Box::new(body) }
601}
602
603fn comp_inner_filter(pair: Pair<Rule>) -> impl Iterator<Item = Pair<Rule>> {
606 pair.into_inner()
607 .filter(|p| !matches!(p.as_rule(), Rule::kw_for | Rule::kw_in | Rule::kw_if))
608}
609
610fn parse_comp_vars(pair: Pair<Rule>) -> Vec<String> {
611 pair.into_inner()
612 .filter(|p| p.as_rule() == Rule::ident)
613 .map(|p| p.as_str().to_string())
614 .collect()
615}
616
617fn parse_list_comp(pair: Pair<Rule>) -> Expr {
618 let mut inner = comp_inner_filter(pair);
619 let expr = parse_expr(inner.next().unwrap());
620 let vars = parse_comp_vars(inner.next().unwrap());
621 let iter = parse_expr(inner.next().unwrap());
622 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
623 Expr::ListComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
624}
625
626fn parse_dict_comp(pair: Pair<Rule>) -> Expr {
627 let mut inner = comp_inner_filter(pair);
628 let key = parse_expr(inner.next().unwrap());
629 let val = parse_expr(inner.next().unwrap());
630 let vars = parse_comp_vars(inner.next().unwrap());
631 let iter = parse_expr(inner.next().unwrap());
632 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
633 Expr::DictComp { key: Box::new(key), val: Box::new(val), vars, iter: Box::new(iter), cond }
634}
635
636fn parse_set_comp(pair: Pair<Rule>) -> Expr {
637 let mut inner = comp_inner_filter(pair);
638 let expr = parse_expr(inner.next().unwrap());
639 let vars = parse_comp_vars(inner.next().unwrap());
640 let iter = parse_expr(inner.next().unwrap());
641 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
642 Expr::SetComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
643}
644
645fn parse_gen_comp(pair: Pair<Rule>) -> Expr {
646 let mut inner = comp_inner_filter(pair);
647 let expr = parse_expr(inner.next().unwrap());
648 let vars = parse_comp_vars(inner.next().unwrap());
649 let iter = parse_expr(inner.next().unwrap());
650 let cond = inner.next().map(|p| Box::new(parse_expr(p)));
651 Expr::GenComp { expr: Box::new(expr), vars, iter: Box::new(iter), cond }
652}
653
654fn parse_obj(pair: Pair<Rule>) -> Expr {
657 let fields = pair.into_inner()
658 .filter(|p| p.as_rule() == Rule::obj_field)
659 .map(parse_obj_field)
660 .collect();
661 Expr::Object(fields)
662}
663
664fn parse_obj_field(pair: Pair<Rule>) -> ObjField {
665 let inner = pair.into_inner().next().unwrap();
666 match inner.as_rule() {
667 Rule::obj_field_dyn => {
668 let mut i = inner.into_inner();
669 let key = parse_expr(i.next().unwrap());
670 let val = parse_expr(i.next().unwrap());
671 ObjField::Dynamic { key, val }
672 }
673 Rule::obj_field_opt_v => {
674 let mut i = inner.into_inner();
675 let key = obj_key_str(i.next().unwrap());
676 let val = parse_expr(i.next().unwrap());
677 ObjField::Kv { key, val, optional: true, cond: None }
678 }
679 Rule::obj_field_opt => {
680 let key = obj_key_str(inner.into_inner().next().unwrap());
681 ObjField::Kv { key: key.clone(), val: Expr::Ident(key), optional: true, cond: None }
682 }
683 Rule::obj_field_spread => {
684 let expr = parse_expr(inner.into_inner().next().unwrap());
685 ObjField::Spread(expr)
686 }
687 Rule::obj_field_spread_deep => {
688 let expr = parse_expr(inner.into_inner().next().unwrap());
689 ObjField::SpreadDeep(expr)
690 }
691 Rule::obj_field_kv => {
692 let mut cond: Option<Expr> = None;
693 let mut key: Option<String> = None;
694 let mut val: Option<Expr> = None;
695 let mut saw_when = false;
696 for p in inner.into_inner() {
697 match p.as_rule() {
698 Rule::kw_when => saw_when = true,
699 Rule::obj_key_expr => key = Some(obj_key_str(p)),
700 Rule::expr => {
701 if saw_when { cond = Some(parse_expr(p)); }
702 else { val = Some(parse_expr(p)); }
703 }
704 _ => {}
705 }
706 }
707 ObjField::Kv {
708 key: key.expect("obj_field_kv missing key"),
709 val: val.expect("obj_field_kv missing val"),
710 optional: false,
711 cond,
712 }
713 }
714 Rule::obj_field_short => {
715 let name = inner.into_inner().next().unwrap().as_str().to_string();
716 ObjField::Short(name)
717 }
718 r => panic!("unexpected obj_field rule: {:?}", r),
719 }
720}
721
722fn obj_key_str(pair: Pair<Rule>) -> String {
723 let inner = pair.into_inner().next().unwrap();
724 match inner.as_rule() {
725 Rule::ident => inner.as_str().to_string(),
726 Rule::lit_str => {
727 let s = inner.into_inner().next().unwrap();
728 let raw = s.as_str();
729 raw[1..raw.len()-1].to_string()
730 }
731 r => panic!("unexpected obj_key_expr rule: {:?}", r),
732 }
733}
734
735fn parse_arr(pair: Pair<Rule>) -> Expr {
736 let elems = pair.into_inner()
737 .filter(|p| p.as_rule() == Rule::arr_elem)
738 .map(|elem| {
739 let inner = elem.into_inner().next().unwrap();
740 match inner.as_rule() {
741 Rule::arr_spread => {
742 let expr = parse_expr(inner.into_inner().next().unwrap());
743 ArrayElem::Spread(expr)
744 }
745 _ => ArrayElem::Expr(parse_expr(inner)),
746 }
747 })
748 .collect();
749 Expr::Array(elems)
750}
751
752fn parse_global_call(pair: Pair<Rule>) -> Expr {
755 let mut inner = pair.into_inner();
756 let name = inner.next().unwrap().as_str().to_string();
757 let args = inner.next().map(parse_arg_list).unwrap_or_default();
758 Expr::GlobalCall { name, args }
759}
760
761fn parse_patch(pair: Pair<Rule>) -> Expr {
764 let mut root: Option<Expr> = None;
765 let mut ops: Vec<PatchOp> = Vec::new();
766 for p in pair.into_inner() {
767 match p.as_rule() {
768 Rule::kw_patch => {}
769 Rule::patch_field => ops.push(parse_patch_field(p)),
770 _ => {
771 if root.is_none() { root = Some(parse_expr(p)); }
774 }
775 }
776 }
777 Expr::Patch {
778 root: Box::new(root.expect("patch requires root expression")),
779 ops,
780 }
781}
782
783fn parse_patch_field(pair: Pair<Rule>) -> PatchOp {
784 let mut path: Vec<PathStep> = Vec::new();
785 let mut val: Option<Expr> = None;
786 let mut cond: Option<Expr> = None;
787 let mut saw_when = false;
788 for p in pair.into_inner() {
789 match p.as_rule() {
790 Rule::patch_key => path = parse_patch_key(p),
791 Rule::kw_when => saw_when = true,
792 Rule::expr => {
793 if saw_when { cond = Some(parse_expr(p)); }
794 else { val = Some(parse_expr(p)); }
795 }
796 _ => {}
797 }
798 }
799 PatchOp {
800 path,
801 val: val.expect("patch_field missing val"),
802 cond,
803 }
804}
805
806fn parse_patch_key(pair: Pair<Rule>) -> Vec<PathStep> {
807 let mut steps: Vec<PathStep> = Vec::new();
808 let mut first = true;
809 for p in pair.into_inner() {
810 match p.as_rule() {
811 Rule::ident if first => {
812 steps.push(PathStep::Field(p.as_str().to_string()));
813 first = false;
814 }
815 Rule::patch_step => steps.push(parse_patch_step(p)),
816 _ => {}
817 }
818 }
819 steps
820}
821
822fn parse_patch_step(pair: Pair<Rule>) -> PathStep {
823 let inner = pair.into_inner().next().unwrap();
824 match inner.as_rule() {
825 Rule::pp_dot_field => {
826 let name = inner.into_inner().next().unwrap().as_str().to_string();
827 PathStep::Field(name)
828 }
829 Rule::pp_index => {
830 let idx: i64 = inner.into_inner().next().unwrap().as_str().parse().unwrap();
831 PathStep::Index(idx)
832 }
833 Rule::pp_wild => PathStep::Wildcard,
834 Rule::pp_wild_filter => {
835 let mut e: Option<Expr> = None;
837 for p in inner.into_inner() {
838 if p.as_rule() == Rule::expr { e = Some(parse_expr(p)); }
839 }
840 PathStep::WildcardFilter(Box::new(e.expect("pp_wild_filter missing expr")))
841 }
842 Rule::pp_descendant => {
843 let name = inner.into_inner().next().unwrap().as_str().to_string();
844 PathStep::Descendant(name)
845 }
846 r => panic!("unexpected patch_step rule: {:?}", r),
847 }
848}
849
850fn parse_arg_list(pair: Pair<Rule>) -> Vec<Arg> {
853 pair.into_inner()
854 .filter(|p| p.as_rule() == Rule::arg)
855 .map(parse_arg)
856 .collect()
857}
858
859fn parse_arg(pair: Pair<Rule>) -> Arg {
860 let inner = pair.into_inner().next().unwrap();
861 match inner.as_rule() {
862 Rule::named_arg => {
863 let mut i = inner.into_inner();
864 let name = i.next().unwrap().as_str().to_string();
865 let val = parse_expr(i.next().unwrap());
866 Arg::Named(name, val)
867 }
868 Rule::pos_arg => {
869 Arg::Pos(parse_expr(inner.into_inner().next().unwrap()))
870 }
871 r => panic!("unexpected arg rule: {:?}", r),
872 }
873}