sim_lib_standard_core/
diff.rs1use sim_kernel::{Cx, Expr, OpKey, Result, Symbol};
4
5use crate::{LanguageProfile, standard_diff_capability};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum ProfileDiffStatus {
10 Same,
12 Different,
14}
15
16#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct ProfileDifference {
20 pub field: Symbol,
22 pub left: Expr,
24 pub right: Expr,
26}
27
28#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct ProfileDiff {
32 pub left: Symbol,
34 pub right: Symbol,
36 pub status: ProfileDiffStatus,
38 pub shared_organs: Vec<Symbol>,
40 pub left_only_organs: Vec<Symbol>,
42 pub right_only_organs: Vec<Symbol>,
44 pub differences: Vec<ProfileDifference>,
46}
47
48impl ProfileDiff {
49 pub fn is_same(&self) -> bool {
51 self.status == ProfileDiffStatus::Same
52 }
53}
54
55pub fn standard_diff_op_key() -> OpKey {
57 OpKey::new(Symbol::new("standard"), Symbol::new("diff"), 1)
58}
59
60pub fn profile_diff_symbol() -> Symbol {
62 Symbol::qualified("profile", "diff")
63}
64
65pub fn standard_diff_stub(
92 cx: &Cx,
93 left: &LanguageProfile,
94 right: &LanguageProfile,
95) -> Result<ProfileDiff> {
96 cx.require(&standard_diff_capability())?;
97 let left_organs = left
98 .organs
99 .iter()
100 .map(|organ| organ.organ.clone())
101 .collect::<Vec<_>>();
102 let right_organs = right
103 .organs
104 .iter()
105 .map(|organ| organ.organ.clone())
106 .collect::<Vec<_>>();
107 let mut differences = Vec::new();
108 push_difference(
109 &mut differences,
110 "reader",
111 Expr::Symbol(left.reader.clone()),
112 Expr::Symbol(right.reader.clone()),
113 );
114 push_difference(
115 &mut differences,
116 "lowering",
117 Expr::Symbol(left.lowering.clone()),
118 Expr::Symbol(right.lowering.clone()),
119 );
120 push_difference(
121 &mut differences,
122 "eval-policy",
123 Expr::Symbol(left.eval_policy.clone()),
124 Expr::Symbol(right.eval_policy.clone()),
125 );
126 push_difference(
127 &mut differences,
128 "organs",
129 symbols_expr(&left_organs),
130 symbols_expr(&right_organs),
131 );
132 push_difference(
133 &mut differences,
134 "numeric",
135 optional_symbol_expr(left.numeric_tower.as_ref()),
136 optional_symbol_expr(right.numeric_tower.as_ref()),
137 );
138 push_difference(
139 &mut differences,
140 "capabilities",
141 capability_expr(left),
142 capability_expr(right),
143 );
144 push_difference(
145 &mut differences,
146 "unsupported",
147 symbols_expr(&left.unsupported_forms),
148 symbols_expr(&right.unsupported_forms),
149 );
150 push_difference(
151 &mut differences,
152 "conformance-tests",
153 symbols_expr(&left.conformance_tests),
154 symbols_expr(&right.conformance_tests),
155 );
156
157 Ok(ProfileDiff {
158 left: left.symbol.clone(),
159 right: right.symbol.clone(),
160 status: if differences.is_empty() {
161 ProfileDiffStatus::Same
162 } else {
163 ProfileDiffStatus::Different
164 },
165 shared_organs: left_organs
166 .iter()
167 .filter(|organ| right_organs.contains(organ))
168 .cloned()
169 .collect(),
170 left_only_organs: left_organs
171 .iter()
172 .filter(|organ| !right_organs.contains(organ))
173 .cloned()
174 .collect(),
175 right_only_organs: right_organs
176 .iter()
177 .filter(|organ| !left_organs.contains(organ))
178 .cloned()
179 .collect(),
180 differences,
181 })
182}
183
184fn push_difference(differences: &mut Vec<ProfileDifference>, field: &str, left: Expr, right: Expr) {
185 if left != right {
186 differences.push(ProfileDifference {
187 field: Symbol::qualified("profile/diff", field.to_owned()),
188 left,
189 right,
190 });
191 }
192}
193
194fn symbols_expr(symbols: &[Symbol]) -> Expr {
195 Expr::List(symbols.iter().cloned().map(Expr::Symbol).collect())
196}
197
198fn optional_symbol_expr(symbol: Option<&Symbol>) -> Expr {
199 symbol.cloned().map(Expr::Symbol).unwrap_or(Expr::Nil)
200}
201
202fn capability_expr(profile: &LanguageProfile) -> Expr {
203 Expr::List(
204 profile
205 .capabilities
206 .iter()
207 .map(|capability| Expr::Symbol(capability.as_symbol()))
208 .collect(),
209 )
210}