1use crate::parsing::ast::{
7 ArithmeticComputation, CalendarPeriodUnit, ComparisonComputation, DateCalendarKind,
8 DateRelativeKind, MathematicalComputation, PrimitiveKind, RangeBound, 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 RangeBound {
107 bound: RangeBound,
108 operand: Box<ShowExpression>,
109 },
110 IsVeto {
111 operand: Box<ShowExpression>,
112 },
113 SpecMember {
115 base: String,
116 member: String,
117 },
118}
119
120pub fn show_expression_from(
125 expression: &Expression,
126 show_keys: &HashSet<String>,
127) -> ShowExpression {
128 match &expression.kind {
129 ExpressionKind::Literal(typed) => ShowExpression::Literal(Box::new(typed.as_ref().clone())),
130 ExpressionKind::DataPath(path) => ShowExpression::Data {
131 name: path.input_key(),
132 },
133 ExpressionKind::RulePath(path) => {
134 let key = path.input_key();
135 if !show_keys.contains(&key) {
136 panic!("BUG: rule leaf '{key}' not in Show.rules keys");
137 }
138 ShowExpression::Rule { name: key }
139 }
140 ExpressionKind::LogicalAnd(left, right) => ShowExpression::And {
141 left: Box::new(show_expression_from(left, show_keys)),
142 right: Box::new(show_expression_from(right, show_keys)),
143 },
144 ExpressionKind::LogicalNegation(operand, _) => ShowExpression::Not {
145 operand: Box::new(show_expression_from(operand, show_keys)),
146 },
147 ExpressionKind::Arithmetic(left, op, right) => ShowExpression::Arithmetic {
148 op: op.clone(),
149 left: Box::new(show_expression_from(left, show_keys)),
150 right: Box::new(show_expression_from(right, show_keys)),
151 },
152 ExpressionKind::Comparison(left, op, right) => ShowExpression::Comparison {
153 op: op.clone(),
154 left: Box::new(show_expression_from(left, show_keys)),
155 right: Box::new(show_expression_from(right, show_keys)),
156 },
157 ExpressionKind::UnitConversion(operand, target) => ShowExpression::UnitConversion {
158 operand: Box::new(show_expression_from(operand, show_keys)),
159 target: conversion_target_from(target),
160 },
161 ExpressionKind::MathematicalComputation(op, operand) => ShowExpression::Math {
162 op: op.clone(),
163 operand: Box::new(show_expression_from(operand, show_keys)),
164 },
165 ExpressionKind::Veto(VetoExpression { message }) => ShowExpression::Veto {
166 message: message.clone(),
167 },
168 ExpressionKind::Now => ShowExpression::Now,
169 ExpressionKind::DateRelative(kind, operand) => ShowExpression::DateRelative {
170 kind: *kind,
171 operand: Box::new(show_expression_from(operand, show_keys)),
172 },
173 ExpressionKind::DateCalendar(kind, unit, operand) => ShowExpression::DateCalendar {
174 kind: *kind,
175 unit: *unit,
176 operand: Box::new(show_expression_from(operand, show_keys)),
177 },
178 ExpressionKind::RangeLiteral(from, to) => ShowExpression::RangeLiteral {
179 from: Box::new(show_expression_from(from, show_keys)),
180 to: Box::new(show_expression_from(to, show_keys)),
181 },
182 ExpressionKind::PastFutureRange(kind, operand) => ShowExpression::PastFutureRange {
183 kind: *kind,
184 operand: Box::new(show_expression_from(operand, show_keys)),
185 },
186 ExpressionKind::RangeContainment(value, range) => ShowExpression::RangeContainment {
187 value: Box::new(show_expression_from(value, show_keys)),
188 range: Box::new(show_expression_from(range, show_keys)),
189 },
190 ExpressionKind::RangeBound(bound, operand) => ShowExpression::RangeBound {
191 bound: *bound,
192 operand: Box::new(show_expression_from(operand, show_keys)),
193 },
194 ExpressionKind::ResultIsVeto(operand) => ShowExpression::IsVeto {
195 operand: Box::new(show_expression_from(operand, show_keys)),
196 },
197 ExpressionKind::Piecewise(_) => {
198 panic!("BUG: piecewise inside a rule branch")
199 }
200 ExpressionKind::SpecMember {
201 base, path, name, ..
202 } => {
203 let key = base.input_key();
204 if !show_keys.contains(&key) {
205 panic!("BUG: spec member base '{key}' not in Show.rules keys");
206 }
207 let mut member = String::new();
208 for segment in path {
209 member.push_str(segment);
210 member.push('.');
211 }
212 member.push_str(name);
213 ShowExpression::SpecMember { base: key, member }
214 }
215 }
216}
217
218pub fn show_branches_from(
220 branches: &[(Option<Expression>, Expression)],
221 show_keys: &HashSet<String>,
222) -> Vec<ShowBranch> {
223 branches
224 .iter()
225 .map(|(condition, result)| ShowBranch {
226 condition: condition
227 .as_ref()
228 .map(|expression| show_expression_from(expression, show_keys)),
229 result: show_expression_from(result, show_keys),
230 })
231 .collect()
232}
233
234pub fn project_depends_on_rules(
236 deps: &std::collections::BTreeSet<crate::planning::semantics::RulePath>,
237 show_keys: &HashSet<String>,
238) -> Vec<String> {
239 let mut out = Vec::new();
240 for path in deps {
241 let key = path.input_key();
242 if !show_keys.contains(&key) {
243 panic!("BUG: depends_on_rules entry '{key}' missing from Show.rules keys");
244 }
245 out.push(key);
246 }
247 out
248}
249
250fn conversion_target_from(target: &SemanticConversionTarget) -> ShowConversionTarget {
251 match target {
252 SemanticConversionTarget::Type(kind) => ShowConversionTarget::Type(*kind),
253 SemanticConversionTarget::Unit { unit_name, .. } => ShowConversionTarget::Unit {
254 unit_name: unit_name.clone(),
255 },
256 }
257}