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 crate::result_value::{type_scoped_result_value_from_literal, RuleResultValue};
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 branches: Vec<ShowBranch>,
30 pub depends_on_rules: Vec<String>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum ShowConversionTarget {
38 Type(PrimitiveKind),
39 Unit { unit_name: String },
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub enum ShowExpression {
45 Literal(Box<RuleResultValue>),
46 Data {
47 name: String,
48 },
49 Rule {
50 name: String,
51 },
52 And {
53 left: Box<ShowExpression>,
54 right: Box<ShowExpression>,
55 },
56 Not {
57 operand: Box<ShowExpression>,
58 },
59 Arithmetic {
60 op: ArithmeticComputation,
61 left: Box<ShowExpression>,
62 right: Box<ShowExpression>,
63 },
64 Comparison {
65 op: ComparisonComputation,
66 left: Box<ShowExpression>,
67 right: Box<ShowExpression>,
68 },
69 UnitConversion {
70 operand: Box<ShowExpression>,
71 target: ShowConversionTarget,
72 },
73 Math {
74 op: MathematicalComputation,
75 operand: Box<ShowExpression>,
76 },
77 Veto {
78 message: Option<String>,
79 },
80 Now,
81 DateRelative {
82 kind: DateRelativeKind,
83 operand: Box<ShowExpression>,
84 },
85 DateCalendar {
86 kind: DateCalendarKind,
87 unit: CalendarPeriodUnit,
88 operand: Box<ShowExpression>,
89 },
90 RangeLiteral {
91 from: Box<ShowExpression>,
92 to: Box<ShowExpression>,
93 },
94 PastFutureRange {
95 kind: DateRelativeKind,
96 operand: Box<ShowExpression>,
97 },
98 RangeContainment {
99 value: Box<ShowExpression>,
100 range: Box<ShowExpression>,
101 },
102 IsVeto {
103 operand: Box<ShowExpression>,
104 },
105}
106
107pub fn show_expression_from(
112 expression: &Expression,
113 local_rule_names: &HashSet<String>,
114) -> ShowExpression {
115 match &expression.kind {
116 ExpressionKind::Literal(typed) => ShowExpression::Literal(Box::new(literal_to_show(typed))),
117 ExpressionKind::DataPath(path) => ShowExpression::Data {
118 name: path.input_key(),
119 },
120 ExpressionKind::RulePath(path) => {
121 if path.segments.is_empty() && !local_rule_names.contains(&path.rule) {
122 panic!(
123 "BUG: local rule leaf '{}' not in plan local rules",
124 path.rule
125 );
126 }
127 ShowExpression::Rule {
128 name: path.to_string(),
129 }
130 }
131 ExpressionKind::LogicalAnd(left, right) => ShowExpression::And {
132 left: Box::new(show_expression_from(left, local_rule_names)),
133 right: Box::new(show_expression_from(right, local_rule_names)),
134 },
135 ExpressionKind::LogicalNegation(operand, _) => ShowExpression::Not {
136 operand: Box::new(show_expression_from(operand, local_rule_names)),
137 },
138 ExpressionKind::Arithmetic(left, op, right) => ShowExpression::Arithmetic {
139 op: op.clone(),
140 left: Box::new(show_expression_from(left, local_rule_names)),
141 right: Box::new(show_expression_from(right, local_rule_names)),
142 },
143 ExpressionKind::Comparison(left, op, right) => ShowExpression::Comparison {
144 op: op.clone(),
145 left: Box::new(show_expression_from(left, local_rule_names)),
146 right: Box::new(show_expression_from(right, local_rule_names)),
147 },
148 ExpressionKind::UnitConversion(operand, target) => ShowExpression::UnitConversion {
149 operand: Box::new(show_expression_from(operand, local_rule_names)),
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, local_rule_names)),
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, local_rule_names)),
163 },
164 ExpressionKind::DateCalendar(kind, unit, operand) => ShowExpression::DateCalendar {
165 kind: *kind,
166 unit: *unit,
167 operand: Box::new(show_expression_from(operand, local_rule_names)),
168 },
169 ExpressionKind::RangeLiteral(from, to) => ShowExpression::RangeLiteral {
170 from: Box::new(show_expression_from(from, local_rule_names)),
171 to: Box::new(show_expression_from(to, local_rule_names)),
172 },
173 ExpressionKind::PastFutureRange(kind, operand) => ShowExpression::PastFutureRange {
174 kind: *kind,
175 operand: Box::new(show_expression_from(operand, local_rule_names)),
176 },
177 ExpressionKind::RangeContainment(value, range) => ShowExpression::RangeContainment {
178 value: Box::new(show_expression_from(value, local_rule_names)),
179 range: Box::new(show_expression_from(range, local_rule_names)),
180 },
181 ExpressionKind::ResultIsVeto(operand) => ShowExpression::IsVeto {
182 operand: Box::new(show_expression_from(operand, local_rule_names)),
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 local_rule_names: &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, local_rule_names)),
201 result: show_expression_from(result, local_rule_names),
202 })
203 .collect()
204}
205
206pub fn project_depends_on_rules(
208 deps: &std::collections::BTreeSet<crate::planning::semantics::RulePath>,
209 local_rule_names: &HashSet<String>,
210) -> Vec<String> {
211 let mut out = Vec::new();
212 for path in deps {
213 if !path.segments.is_empty() {
214 continue;
215 }
216 if !local_rule_names.contains(&path.rule) {
217 panic!(
218 "BUG: local depends_on_rules entry '{}' missing from plan local rules",
219 path.rule
220 );
221 }
222 out.push(path.rule.clone());
223 }
224 out
225}
226
227fn literal_to_show(typed: &TypedLiteral) -> RuleResultValue {
228 type_scoped_result_value_from_literal(&typed.to_literal(), typed.lemma_type.as_ref())
229 .unwrap_or_else(|failure| {
230 panic!(
231 "BUG: show branch literal failed type_scoped_result_value_from_literal: {}",
232 crate::result_value::rule_result_value_failure_message(failure)
233 )
234 })
235}
236
237fn conversion_target_from(target: &SemanticConversionTarget) -> ShowConversionTarget {
238 match target {
239 SemanticConversionTarget::Type(kind) => ShowConversionTarget::Type(*kind),
240 SemanticConversionTarget::Unit { unit_name, .. } => ShowConversionTarget::Unit {
241 unit_name: unit_name.clone(),
242 },
243 }
244}