1use crate::parsing::ast::{
7 ArithmeticComputation, CalendarPeriodUnit, ComparisonComputation, DateCalendarKind,
8 DateRelativeKind, MathematicalComputation, PrimitiveKind, VetoExpression,
9};
10use crate::planning::semantics::{
11 Expression, ExpressionKind, SemanticConversionTarget, TypedLiteral,
12};
13use serde::{Deserialize, Serialize};
14use std::collections::HashSet;
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
18pub struct ShowBranch {
19 pub condition: Option<ShowExpression>,
21 pub result: ShowExpression,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct ShowRule {
27 pub lemma_type: crate::planning::semantics::LemmaType,
28 pub path: Vec<crate::planning::semantics::PathSegment>,
30 pub branches: Vec<ShowBranch>,
31 pub depends_on_rules: Vec<String>,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum ShowConversionTarget {
39 Type(PrimitiveKind),
40 Unit { unit_name: String },
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
48pub enum ShowExpression {
49 Literal(Box<TypedLiteral>),
50 Data {
51 name: String,
52 },
53 Rule {
54 name: String,
55 },
56 And {
57 left: Box<ShowExpression>,
58 right: Box<ShowExpression>,
59 },
60 Not {
61 operand: Box<ShowExpression>,
62 },
63 Arithmetic {
64 op: ArithmeticComputation,
65 left: Box<ShowExpression>,
66 right: Box<ShowExpression>,
67 },
68 Comparison {
69 op: ComparisonComputation,
70 left: Box<ShowExpression>,
71 right: Box<ShowExpression>,
72 },
73 UnitConversion {
74 operand: Box<ShowExpression>,
75 target: ShowConversionTarget,
76 },
77 Math {
78 op: MathematicalComputation,
79 operand: Box<ShowExpression>,
80 },
81 Veto {
82 message: Option<String>,
83 },
84 Now,
85 DateRelative {
86 kind: DateRelativeKind,
87 operand: Box<ShowExpression>,
88 },
89 DateCalendar {
90 kind: DateCalendarKind,
91 unit: CalendarPeriodUnit,
92 operand: Box<ShowExpression>,
93 },
94 RangeLiteral {
95 from: Box<ShowExpression>,
96 to: Box<ShowExpression>,
97 },
98 PastFutureRange {
99 kind: DateRelativeKind,
100 operand: Box<ShowExpression>,
101 },
102 RangeContainment {
103 value: Box<ShowExpression>,
104 range: Box<ShowExpression>,
105 },
106 IsVeto {
107 operand: Box<ShowExpression>,
108 },
109}
110
111pub fn show_expression_from(
116 expression: &Expression,
117 show_keys: &HashSet<String>,
118) -> ShowExpression {
119 match &expression.kind {
120 ExpressionKind::Literal(typed) => ShowExpression::Literal(Box::new(typed.as_ref().clone())),
121 ExpressionKind::DataPath(path) => ShowExpression::Data {
122 name: path.input_key(),
123 },
124 ExpressionKind::RulePath(path) => {
125 let key = path.input_key();
126 if !show_keys.contains(&key) {
127 panic!("BUG: rule leaf '{key}' not in Show.rules keys");
128 }
129 ShowExpression::Rule { name: key }
130 }
131 ExpressionKind::LogicalAnd(left, right) => ShowExpression::And {
132 left: Box::new(show_expression_from(left, show_keys)),
133 right: Box::new(show_expression_from(right, show_keys)),
134 },
135 ExpressionKind::LogicalNegation(operand, _) => ShowExpression::Not {
136 operand: Box::new(show_expression_from(operand, show_keys)),
137 },
138 ExpressionKind::Arithmetic(left, op, right) => ShowExpression::Arithmetic {
139 op: op.clone(),
140 left: Box::new(show_expression_from(left, show_keys)),
141 right: Box::new(show_expression_from(right, show_keys)),
142 },
143 ExpressionKind::Comparison(left, op, right) => ShowExpression::Comparison {
144 op: op.clone(),
145 left: Box::new(show_expression_from(left, show_keys)),
146 right: Box::new(show_expression_from(right, show_keys)),
147 },
148 ExpressionKind::UnitConversion(operand, target) => ShowExpression::UnitConversion {
149 operand: Box::new(show_expression_from(operand, show_keys)),
150 target: conversion_target_from(target),
151 },
152 ExpressionKind::MathematicalComputation(op, operand) => ShowExpression::Math {
153 op: op.clone(),
154 operand: Box::new(show_expression_from(operand, show_keys)),
155 },
156 ExpressionKind::Veto(VetoExpression { message }) => ShowExpression::Veto {
157 message: message.clone(),
158 },
159 ExpressionKind::Now => ShowExpression::Now,
160 ExpressionKind::DateRelative(kind, operand) => ShowExpression::DateRelative {
161 kind: *kind,
162 operand: Box::new(show_expression_from(operand, show_keys)),
163 },
164 ExpressionKind::DateCalendar(kind, unit, operand) => ShowExpression::DateCalendar {
165 kind: *kind,
166 unit: *unit,
167 operand: Box::new(show_expression_from(operand, show_keys)),
168 },
169 ExpressionKind::RangeLiteral(from, to) => ShowExpression::RangeLiteral {
170 from: Box::new(show_expression_from(from, show_keys)),
171 to: Box::new(show_expression_from(to, show_keys)),
172 },
173 ExpressionKind::PastFutureRange(kind, operand) => ShowExpression::PastFutureRange {
174 kind: *kind,
175 operand: Box::new(show_expression_from(operand, show_keys)),
176 },
177 ExpressionKind::RangeContainment(value, range) => ShowExpression::RangeContainment {
178 value: Box::new(show_expression_from(value, show_keys)),
179 range: Box::new(show_expression_from(range, show_keys)),
180 },
181 ExpressionKind::ResultIsVeto(operand) => ShowExpression::IsVeto {
182 operand: Box::new(show_expression_from(operand, show_keys)),
183 },
184 ExpressionKind::Piecewise(_) => {
185 panic!("BUG: piecewise inside a rule branch")
186 }
187 }
188}
189
190pub fn show_branches_from(
192 branches: &[(Option<Expression>, Expression)],
193 show_keys: &HashSet<String>,
194) -> Vec<ShowBranch> {
195 branches
196 .iter()
197 .map(|(condition, result)| ShowBranch {
198 condition: condition
199 .as_ref()
200 .map(|expression| show_expression_from(expression, show_keys)),
201 result: show_expression_from(result, show_keys),
202 })
203 .collect()
204}
205
206pub fn project_depends_on_rules(
208 deps: &std::collections::BTreeSet<crate::planning::semantics::RulePath>,
209 show_keys: &HashSet<String>,
210) -> Vec<String> {
211 let mut out = Vec::new();
212 for path in deps {
213 let key = path.input_key();
214 if !show_keys.contains(&key) {
215 panic!("BUG: depends_on_rules entry '{key}' missing from Show.rules keys");
216 }
217 out.push(key);
218 }
219 out
220}
221
222fn conversion_target_from(target: &SemanticConversionTarget) -> ShowConversionTarget {
223 match target {
224 SemanticConversionTarget::Type(kind) => ShowConversionTarget::Type(*kind),
225 SemanticConversionTarget::Unit { unit_name, .. } => ShowConversionTarget::Unit {
226 unit_name: unit_name.clone(),
227 },
228 }
229}