1use crate::parsing::arena::{ExprId, ExprKind, ExprRef};
7use crate::parsing::ast::{
8 ArithmeticComputation, CalendarPeriodUnit, ComparisonComputation, DateCalendarKind,
9 DateRelativeKind, MathematicalComputation, PrimitiveKind, RangeBound, VetoExpression,
10};
11use crate::planning::semantics::{
12 Expression, ExpressionKind, ListOp, SemanticConversionTarget, TypedLiteral,
13};
14use serde::{Deserialize, Serialize};
15use std::collections::HashSet;
16
17#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct ShowBranch {
20 pub condition: Option<ShowExpression>,
22 pub result: ShowExpression,
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
27pub struct ShowRule {
28 pub lemma_type: crate::planning::semantics::LemmaType,
29 pub path: Vec<crate::planning::semantics::PathSegment>,
31 pub branches: Vec<ShowBranch>,
32 pub depends_on_rules: Vec<String>,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39pub enum ShowConversionTarget {
40 Type(PrimitiveKind),
41 Unit { unit_name: String },
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub enum ShowExpression {
50 Literal(Box<TypedLiteral>),
51 Data {
52 name: String,
53 },
54 Rule {
55 name: String,
56 },
57 And {
59 operands: Vec<ShowExpression>,
60 },
61 Not {
62 operand: Box<ShowExpression>,
63 },
64 Arithmetic {
66 first: Box<ShowExpression>,
67 steps: Vec<ShowArithmeticStep>,
68 },
69 Comparison {
70 op: ComparisonComputation,
71 left: Box<ShowExpression>,
72 right: Box<ShowExpression>,
73 },
74 UnitConversion {
76 operand: Box<ShowExpression>,
77 targets: Vec<ShowConversionTarget>,
78 },
79 Math {
80 op: MathematicalComputation,
81 operand: Box<ShowExpression>,
82 },
83 Veto {
84 message: Option<String>,
85 },
86 Now,
87 DateRelative {
88 kind: DateRelativeKind,
89 operand: Box<ShowExpression>,
90 },
91 DateCalendar {
92 kind: DateCalendarKind,
93 unit: CalendarPeriodUnit,
94 operand: Box<ShowExpression>,
95 },
96 RangeLiteral {
97 from: Box<ShowExpression>,
98 to: Box<ShowExpression>,
99 },
100 PastFutureRange {
101 kind: DateRelativeKind,
102 operand: Box<ShowExpression>,
103 },
104 RangeContainment {
105 value: Box<ShowExpression>,
106 range: Box<ShowExpression>,
107 },
108 RangeBound {
109 bound: RangeBound,
110 operand: Box<ShowExpression>,
111 },
112 IsVeto {
113 operand: Box<ShowExpression>,
114 },
115 SpecMember {
117 base: String,
118 member: String,
119 },
120 Member {
122 base: Box<ShowExpression>,
123 member: String,
124 },
125 RowField {
127 field: String,
128 },
129 RowValue,
131 RowFieldValue {
133 field: String,
134 value: Box<ShowExpression>,
135 },
136 ListCommand {
138 list: Box<ShowExpression>,
139 command: ShowListCommand,
140 direction: Option<SortDirection>,
141 args: Vec<ShowExpression>,
142 },
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147pub struct ShowArithmeticStep {
148 pub op: ArithmeticComputation,
149 pub operand: ShowExpression,
150}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
154#[serde(rename_all = "snake_case")]
155pub enum ShowListCommand {
156 Find,
157 First,
158 Last,
159 Count,
160 Sum,
161 Avg,
162 Product,
163 Min,
164 Max,
165 Any,
166 All,
167 Where,
168 Sort,
169 Top,
170 With,
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
174#[serde(rename_all = "snake_case")]
175pub enum SortDirection {
176 Asc,
177 Desc,
178}
179
180impl ShowExpression {
181 pub(crate) fn operands(&self) -> Vec<&ShowExpression> {
183 match self {
184 Self::Literal(_)
185 | Self::Data { .. }
186 | Self::Rule { .. }
187 | Self::Veto { .. }
188 | Self::Now
189 | Self::SpecMember { .. }
190 | Self::RowField { .. }
191 | Self::RowValue => Vec::new(),
192 Self::And { operands } => operands.iter().collect(),
193 Self::Not { operand }
194 | Self::UnitConversion { operand, .. }
195 | Self::Math { operand, .. }
196 | Self::DateRelative { operand, .. }
197 | Self::DateCalendar { operand, .. }
198 | Self::PastFutureRange { operand, .. }
199 | Self::RangeBound { operand, .. }
200 | Self::IsVeto { operand } => vec![operand.as_ref()],
201 Self::Arithmetic { first, steps } => {
202 let mut out = vec![first.as_ref()];
203 out.extend(steps.iter().map(|step| &step.operand));
204 out
205 }
206 Self::Comparison { left, right, .. }
207 | Self::RangeLiteral {
208 from: left,
209 to: right,
210 }
211 | Self::RangeContainment {
212 value: left,
213 range: right,
214 } => vec![left.as_ref(), right.as_ref()],
215 Self::Member { base, .. } => vec![base.as_ref()],
216 Self::RowFieldValue { value, .. } => vec![value.as_ref()],
217 Self::ListCommand { list, args, .. } => {
218 let mut out = vec![list.as_ref()];
219 out.extend(args.iter());
220 out
221 }
222 }
223 }
224
225 pub(crate) fn fold<U>(&self, mut step: impl FnMut(&ShowExpression, Vec<U>) -> U) -> U {
228 let mut values: Vec<U> = Vec::new();
229 let mut stack: Vec<(&ShowExpression, bool)> = vec![(self, false)];
230 while let Some((node, expanded)) = stack.pop() {
231 let operands = node.operands();
232 if !expanded {
233 stack.push((node, true));
234 stack.extend(operands.iter().rev().map(|&operand| (operand, false)));
235 continue;
236 }
237 let split = values
238 .len()
239 .checked_sub(operands.len())
240 .expect("BUG: operand folded before its parent");
241 let args = values.split_off(split);
242 values.push(step(node, args));
243 }
244 values
245 .pop()
246 .expect("BUG: fold produced no value for its root")
247 }
248}
249
250pub(crate) fn take_operand<T, I: Iterator<Item = T>>(operands: &mut I) -> T {
252 operands
253 .next()
254 .expect("BUG: operand missing for its parent node")
255}
256
257fn project(
265 root: ExprRef<'_, ExpressionKind>,
266 show_keys: &HashSet<String>,
267 scratch: &mut ProjectScratch,
268) -> ShowExpression {
269 let ProjectScratch { values, stack } = scratch;
270 stack.push((root.id, false));
271 while let Some((id, expanded)) = stack.pop() {
272 let node = root.child(id);
273 if !expanded {
274 stack.push((id, true));
275 let start = stack.len();
276 for_each_projection_operand(node, |operand| stack.push((operand, false)));
277 stack[start..].reverse();
278 continue;
279 }
280 let mut arity = 0;
281 for_each_projection_operand(node, |_| arity += 1);
282 let split = values
283 .len()
284 .checked_sub(arity)
285 .expect("BUG: operand projected before its parent");
286 let shown = project_node(node, values.drain(split..), show_keys);
287 values.push(shown);
288 }
289 let shown = values
290 .pop()
291 .expect("BUG: projection produced no value for its root");
292 assert!(
293 values.is_empty(),
294 "BUG: projection left operands without a parent"
295 );
296 shown
297}
298
299#[derive(Default)]
301struct ProjectScratch {
302 values: Vec<ShowExpression>,
303 stack: Vec<(ExprId, bool)>,
304}
305
306fn for_each_projection_operand(node: ExprRef<'_, ExpressionKind>, mut f: impl FnMut(ExprId)) {
309 match node.kind() {
310 ExpressionKind::Piecewise(_) => {}
311 ExpressionKind::SpecMember { base, .. } => {
312 if !matches!(node.child(*base).kind(), ExpressionKind::RulePath(_)) {
313 f(*base);
314 }
315 }
316 ExpressionKind::UnitConversion(_, _) => f(conversion_operand(node)),
317 other => other.for_each_child(f),
318 }
319}
320
321fn conversion_operand(node: ExprRef<'_, ExpressionKind>) -> ExprId {
323 let mut current = node;
324 while let ExpressionKind::UnitConversion(operand, _) = current.kind() {
325 current = current.child(*operand);
326 }
327 current.id
328}
329
330fn conversion_run(node: ExprRef<'_, ExpressionKind>) -> (ExprId, Vec<ShowConversionTarget>) {
332 let mut current = node;
333 let mut targets = Vec::new();
334 while let ExpressionKind::UnitConversion(operand, target) = current.kind() {
335 targets.push(conversion_target_from(target));
336 current = current.child(*operand);
337 }
338 targets.reverse();
339 (current.id, targets)
340}
341
342fn project_node(
344 node: ExprRef<'_, ExpressionKind>,
345 mut operands: std::vec::Drain<'_, ShowExpression>,
346 show_keys: &HashSet<String>,
347) -> ShowExpression {
348 match node.kind() {
349 ExpressionKind::Literal(typed) => ShowExpression::Literal(Box::new(typed.as_ref().clone())),
350 ExpressionKind::DataPath(path) => ShowExpression::Data {
351 name: path.input_key(),
352 },
353 ExpressionKind::RulePath(path) => {
354 let key = path.input_key();
355 if !show_keys.contains(&key) {
356 panic!("BUG: rule leaf '{key}' not in Show.rules keys");
357 }
358 ShowExpression::Rule { name: key }
359 }
360 ExpressionKind::LogicalAnd { .. } => ShowExpression::And {
361 operands: operands.collect(),
362 },
363 ExpressionKind::LogicalNegation(_, _) => ShowExpression::Not {
364 operand: Box::new(take_operand(&mut operands)),
365 },
366 ExpressionKind::Arithmetic { steps, .. } => {
367 let first = Box::new(take_operand(&mut operands));
368 let steps = steps
369 .iter()
370 .map(|step| ShowArithmeticStep {
371 op: step.op.clone(),
372 operand: take_operand(&mut operands),
373 })
374 .collect();
375 ShowExpression::Arithmetic { first, steps }
376 }
377 ExpressionKind::Comparison(_, op, _) => {
378 let left = Box::new(take_operand(&mut operands));
379 let right = Box::new(take_operand(&mut operands));
380 ShowExpression::Comparison {
381 op: op.clone(),
382 left,
383 right,
384 }
385 }
386 ExpressionKind::UnitConversion(_, _) => {
387 let (_, targets) = conversion_run(node);
388 ShowExpression::UnitConversion {
389 operand: Box::new(take_operand(&mut operands)),
390 targets,
391 }
392 }
393 ExpressionKind::MathematicalComputation(op, _) => ShowExpression::Math {
394 op: op.clone(),
395 operand: Box::new(take_operand(&mut operands)),
396 },
397 ExpressionKind::Veto(VetoExpression { message }) => ShowExpression::Veto {
398 message: message.clone(),
399 },
400 ExpressionKind::Now => ShowExpression::Now,
401 ExpressionKind::DateRelative(kind, _) => ShowExpression::DateRelative {
402 kind: *kind,
403 operand: Box::new(take_operand(&mut operands)),
404 },
405 ExpressionKind::DateCalendar(kind, unit, _) => ShowExpression::DateCalendar {
406 kind: *kind,
407 unit: *unit,
408 operand: Box::new(take_operand(&mut operands)),
409 },
410 ExpressionKind::RangeLiteral(_, _) => {
411 let from = Box::new(take_operand(&mut operands));
412 let to = Box::new(take_operand(&mut operands));
413 ShowExpression::RangeLiteral { from, to }
414 }
415 ExpressionKind::PastFutureRange(kind, _) => ShowExpression::PastFutureRange {
416 kind: *kind,
417 operand: Box::new(take_operand(&mut operands)),
418 },
419 ExpressionKind::RangeContainment(_, _) => {
420 let value = Box::new(take_operand(&mut operands));
421 let range = Box::new(take_operand(&mut operands));
422 ShowExpression::RangeContainment { value, range }
423 }
424 ExpressionKind::RangeBound(bound, _) => ShowExpression::RangeBound {
425 bound: *bound,
426 operand: Box::new(take_operand(&mut operands)),
427 },
428 ExpressionKind::ResultIsVeto(_) => ShowExpression::IsVeto {
429 operand: Box::new(take_operand(&mut operands)),
430 },
431 ExpressionKind::Piecewise(_) => {
432 panic!("BUG: piecewise inside a rule branch")
433 }
434 ExpressionKind::SpecMember {
435 base, path, name, ..
436 } => {
437 let mut member = String::new();
438 for segment in path {
439 member.push_str(segment);
440 member.push('.');
441 }
442 member.push_str(name);
443 match node.child(*base).kind() {
444 ExpressionKind::RulePath(rule) => {
445 let key = rule.input_key();
446 if !show_keys.contains(&key) {
447 panic!("BUG: spec member base '{key}' not in Show.rules keys");
448 }
449 ShowExpression::SpecMember { base: key, member }
450 }
451 _ => ShowExpression::Member {
452 base: Box::new(take_operand(&mut operands)),
453 member,
454 },
455 }
456 }
457 ExpressionKind::RowField { end, .. } => ShowExpression::RowField {
458 field: end.to_string(),
459 },
460 ExpressionKind::ListCommand { op, .. } => {
461 let list = Box::new(take_operand(&mut operands));
462 let (command, direction, args) = show_list_op(op, &mut operands);
463 ShowExpression::ListCommand {
464 list,
465 command,
466 direction,
467 args,
468 }
469 }
470 }
471}
472
473fn show_list_op(
475 op: &ListOp,
476 operands: &mut std::vec::Drain<'_, ShowExpression>,
477) -> (ShowListCommand, Option<SortDirection>, Vec<ShowExpression>) {
478 use crate::parsing::ast::RowCondition;
479 use crate::planning::semantics::{ListPredKind, ListReduce};
480 let predicate = |kind: &ListPredKind| match kind {
481 ListPredKind::Any => ShowListCommand::Any,
482 ListPredKind::All => ShowListCommand::All,
483 ListPredKind::Where => ShowListCommand::Where,
484 };
485 match op {
486 ListOp::Find { keys } => (
487 ShowListCommand::Find,
488 None,
489 operands.by_ref().take(keys.len()).collect(),
490 ),
491 ListOp::First => (ShowListCommand::First, None, Vec::new()),
492 ListOp::Last => (ShowListCommand::Last, None, Vec::new()),
493 ListOp::Count => (ShowListCommand::Count, None, Vec::new()),
494 ListOp::Reduce { kind, argument } => {
495 let command = match kind {
496 ListReduce::Sum => ShowListCommand::Sum,
497 ListReduce::Avg => ShowListCommand::Avg,
498 ListReduce::Product => ShowListCommand::Product,
499 ListReduce::Min => ShowListCommand::Min,
500 ListReduce::Max => ShowListCommand::Max,
501 };
502 let args = if argument.is_some() {
503 vec![take_operand(operands)]
504 } else {
505 Vec::new()
506 };
507 (command, None, args)
508 }
509 ListOp::Predicate { kind, op, .. } => {
510 let right = Box::new(take_operand(operands));
511 let condition = match op {
512 RowCondition::Compare(comparison) => ShowExpression::Comparison {
513 op: comparison.clone(),
514 left: Box::new(ShowExpression::RowValue),
515 right,
516 },
517 RowCondition::In => ShowExpression::RangeContainment {
518 value: Box::new(ShowExpression::RowValue),
519 range: right,
520 },
521 };
522 (predicate(kind), None, vec![condition])
523 }
524 ListOp::InstancePredicate { kind, .. } => {
525 (predicate(kind), None, vec![take_operand(operands)])
526 }
527 ListOp::Sort {
528 descending,
529 argument,
530 } => {
531 let direction = if *descending {
532 SortDirection::Desc
533 } else {
534 SortDirection::Asc
535 };
536 let args = if argument.is_some() {
537 vec![take_operand(operands)]
538 } else {
539 Vec::new()
540 };
541 (ShowListCommand::Sort, Some(direction), args)
542 }
543 ListOp::Top { .. } => (ShowListCommand::Top, None, vec![take_operand(operands)]),
544 ListOp::With { rows } => (
545 ShowListCommand::With,
546 None,
547 operands.by_ref().take(rows.len()).collect(),
548 ),
549 ListOp::WithRow { fields } => (
550 ShowListCommand::With,
551 None,
552 fields
553 .iter()
554 .map(|(path, _)| ShowExpression::RowFieldValue {
555 field: path.input_key(),
556 value: Box::new(take_operand(operands)),
557 })
558 .collect(),
559 ),
560 }
561}
562
563pub fn show_branches_from(
565 expression: &Expression,
566 branches: &[(Option<ExprId>, ExprId)],
567 show_keys: &HashSet<String>,
568) -> Vec<ShowBranch> {
569 let mut scratch = ProjectScratch::default();
570 branches
571 .iter()
572 .map(|(condition, result)| ShowBranch {
573 condition: condition
574 .map(|condition| project(expression.at(condition), show_keys, &mut scratch)),
575 result: project(expression.at(*result), show_keys, &mut scratch),
576 })
577 .collect()
578}
579
580pub fn project_depends_on_rules(
582 deps: &std::collections::BTreeSet<crate::planning::semantics::RulePath>,
583 show_keys: &HashSet<String>,
584) -> Vec<String> {
585 let mut out = Vec::new();
586 for path in deps {
587 let key = path.input_key();
588 if !show_keys.contains(&key) {
589 panic!("BUG: depends_on_rules entry '{key}' missing from Show.rules keys");
590 }
591 out.push(key);
592 }
593 out
594}
595
596pub(crate) fn prefix_show_expression(prefix: &str, expression: &ShowExpression) -> ShowExpression {
598 expression.fold(|node, operands| prefix_show_node(prefix, node, operands))
599}
600
601fn prefix_show_node(
602 prefix: &str,
603 node: &ShowExpression,
604 operands: Vec<ShowExpression>,
605) -> ShowExpression {
606 let qualify = |name: &str| format!("{prefix}.{name}");
607 let mut operands = operands.into_iter();
608 match node {
609 ShowExpression::Literal(literal) => ShowExpression::Literal(literal.clone()),
610 ShowExpression::Data { name } => ShowExpression::Data {
611 name: qualify(name),
612 },
613 ShowExpression::Rule { name } => ShowExpression::Rule {
614 name: qualify(name),
615 },
616 ShowExpression::And { .. } => ShowExpression::And {
617 operands: operands.collect(),
618 },
619 ShowExpression::Not { .. } => ShowExpression::Not {
620 operand: Box::new(take_operand(&mut operands)),
621 },
622 ShowExpression::Arithmetic { steps, .. } => {
623 let first = Box::new(take_operand(&mut operands));
624 let steps = steps
625 .iter()
626 .map(|step| ShowArithmeticStep {
627 op: step.op.clone(),
628 operand: take_operand(&mut operands),
629 })
630 .collect();
631 ShowExpression::Arithmetic { first, steps }
632 }
633 ShowExpression::Comparison { op, .. } => {
634 let left = Box::new(take_operand(&mut operands));
635 let right = Box::new(take_operand(&mut operands));
636 ShowExpression::Comparison {
637 op: op.clone(),
638 left,
639 right,
640 }
641 }
642 ShowExpression::UnitConversion { targets, .. } => ShowExpression::UnitConversion {
643 operand: Box::new(take_operand(&mut operands)),
644 targets: targets.clone(),
645 },
646 ShowExpression::Math { op, .. } => ShowExpression::Math {
647 op: op.clone(),
648 operand: Box::new(take_operand(&mut operands)),
649 },
650 ShowExpression::Veto { message } => ShowExpression::Veto {
651 message: message.clone(),
652 },
653 ShowExpression::Now => ShowExpression::Now,
654 ShowExpression::DateRelative { kind, .. } => ShowExpression::DateRelative {
655 kind: *kind,
656 operand: Box::new(take_operand(&mut operands)),
657 },
658 ShowExpression::DateCalendar { kind, unit, .. } => ShowExpression::DateCalendar {
659 kind: *kind,
660 unit: *unit,
661 operand: Box::new(take_operand(&mut operands)),
662 },
663 ShowExpression::RangeLiteral { .. } => {
664 let from = Box::new(take_operand(&mut operands));
665 let to = Box::new(take_operand(&mut operands));
666 ShowExpression::RangeLiteral { from, to }
667 }
668 ShowExpression::PastFutureRange { kind, .. } => ShowExpression::PastFutureRange {
669 kind: *kind,
670 operand: Box::new(take_operand(&mut operands)),
671 },
672 ShowExpression::RangeContainment { .. } => {
673 let value = Box::new(take_operand(&mut operands));
674 let range = Box::new(take_operand(&mut operands));
675 ShowExpression::RangeContainment { value, range }
676 }
677 ShowExpression::RangeBound { bound, .. } => ShowExpression::RangeBound {
678 bound: *bound,
679 operand: Box::new(take_operand(&mut operands)),
680 },
681 ShowExpression::IsVeto { .. } => ShowExpression::IsVeto {
682 operand: Box::new(take_operand(&mut operands)),
683 },
684 ShowExpression::SpecMember { base, member } => ShowExpression::SpecMember {
685 base: qualify(base),
686 member: member.clone(),
687 },
688 ShowExpression::Member { member, .. } => ShowExpression::Member {
689 base: Box::new(take_operand(&mut operands)),
690 member: member.clone(),
691 },
692 ShowExpression::RowField { field } => ShowExpression::RowField {
693 field: field.clone(),
694 },
695 ShowExpression::RowValue => ShowExpression::RowValue,
696 ShowExpression::RowFieldValue { field, .. } => ShowExpression::RowFieldValue {
697 field: field.clone(),
698 value: Box::new(take_operand(&mut operands)),
699 },
700 ShowExpression::ListCommand {
701 command, direction, ..
702 } => {
703 let list = Box::new(take_operand(&mut operands));
704 ShowExpression::ListCommand {
705 list,
706 command: *command,
707 direction: *direction,
708 args: operands.collect(),
709 }
710 }
711 }
712}
713
714fn conversion_target_from(target: &SemanticConversionTarget) -> ShowConversionTarget {
715 match target {
716 SemanticConversionTarget::Type(kind) => ShowConversionTarget::Type(*kind),
717 SemanticConversionTarget::Unit { unit_name, .. } => ShowConversionTarget::Unit {
718 unit_name: unit_name.clone(),
719 },
720 }
721}