1use crate::ast::serde::{AsId, HasId};
2use crate::representation::types::ReprGetOrInitResult;
3use crate::representation::{
4 ReferenceReprError, ReprError, ReprRule, ReprRulePtr, ReprSelectError, ReprStateStored,
5};
6use crate::{ast::DeclarationPtr, bug};
7use derivative::Derivative;
8use parking_lot::{MappedRwLockReadGuard, RwLockReadGuard};
9use serde::{Deserialize, Serialize};
10use serde_with::serde_as;
11use std::fmt::{Display, Formatter};
12use uniplate::Uniplate;
13
14use super::{
15 Atom, DeclarationKind, DomainPtr, Expression, GroundDomain, Literal, Metadata, Moo, Name,
16 ReturnType,
17 categories::{Category, CategoryOf},
18 domains::HasDomain,
19};
20
21#[serde_as]
27#[derive(
28 Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Uniplate, Derivative,
29)]
30#[derivative(Hash)]
31#[uniplate()]
32#[biplate(to=DeclarationPtr)]
33#[biplate(to=Name)]
34pub struct Reference {
35 #[serde_as(as = "AsId")]
36 pub ptr: DeclarationPtr,
37 pub repr: Option<ReprRulePtr>,
38}
39
40impl Reference {
41 pub fn new(ptr: DeclarationPtr) -> Self {
42 Reference { ptr, repr: None }
43 }
44
45 pub fn ptr(&self) -> &DeclarationPtr {
46 &self.ptr
47 }
48
49 pub fn into_ptr(self) -> DeclarationPtr {
50 self.ptr
51 }
52
53 pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
54 self.ptr.name()
55 }
56
57 pub fn id(&self) -> crate::ast::serde::ObjId {
58 self.ptr.id()
59 }
60
61 pub fn domain(&self) -> Option<DomainPtr> {
62 self.ptr.domain()
63 }
64
65 pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
66 self.domain()?.resolve().ok()
67 }
68
69 pub fn select_repr<R: ReprRule + ?Sized>(
79 &mut self,
80 ) -> Result<MappedRwLockReadGuard<'_, R::DeclLevel>, ReprSelectError> {
81 let _ = self.select_repr_via(R::STORED);
82 Ok(self.repr_state_as_unchecked::<R>())
83 }
84
85 pub fn select_repr_via(
87 &mut self,
88 rule: ReprRulePtr,
89 ) -> Result<MappedRwLockReadGuard<'_, dyn ReprStateStored>, ReprSelectError> {
90 if let Some(repr) = self.repr
91 && repr != rule
92 {
93 return Err(ReprSelectError::AlreadySelected(repr));
94 }
95 if !self.ptr.reprs().has_repr(rule) {
96 return Err(ReprSelectError::DoesNotExist(self.ptr.clone(), rule.name()));
97 }
98 self.repr = Some(rule);
99 Ok(self.repr_state_unchecked())
100 }
101
102 pub fn select_or_init_repr_via(
104 &mut self,
105 rule: ReprRulePtr,
106 ) -> ReprGetOrInitResult<'_, dyn ReprStateStored, ReferenceReprError> {
107 if let Some(repr) = self.repr
108 && repr != rule
109 {
110 return Err(ReprSelectError::AlreadySelected(repr).into());
111 }
112 self.update_or_init_repr_via(rule).map_err(Into::into)
113 }
114
115 pub fn select_or_init_repr<R: ReprRule + ?Sized>(
130 &mut self,
131 ) -> ReprGetOrInitResult<'_, R::DeclLevel, ReferenceReprError> {
132 let (_, symbols, constraints) = self.select_or_init_repr_via(R::STORED)?;
133 let state = self.repr_state_as_unchecked::<R>();
134 Ok((state, symbols, constraints))
135 }
136
137 pub fn update_or_init_repr<R: ReprRule + ?Sized>(
151 &mut self,
152 ) -> ReprGetOrInitResult<'_, R::DeclLevel, ReprError> {
153 let (_, symbols, constraints) = self.update_or_init_repr_via(R::STORED)?;
154 let state = self.repr_state_as_unchecked::<R>();
155 Ok((state, symbols, constraints))
156 }
157
158 pub fn update_or_init_repr_via(
160 &mut self,
161 rule: ReprRulePtr,
162 ) -> ReprGetOrInitResult<'_, dyn ReprStateStored, ReprError> {
163 let (symbols, constraints) = rule.init_for_if_not_exists(&mut self.ptr)?;
164 self.repr = Some(rule);
165 let state = self.repr_state_unchecked();
166 Ok((state, symbols, constraints))
167 }
168
169 pub fn get_repr(
174 &self,
175 ) -> Option<(ReprRulePtr, MappedRwLockReadGuard<'_, dyn ReprStateStored>)> {
176 let rule = self.repr?;
177 Some((rule, self.repr_state_unchecked()))
178 }
179
180 pub fn get_repr_as<R: ReprRule + ?Sized>(
182 &self,
183 ) -> Option<MappedRwLockReadGuard<'_, R::DeclLevel>> {
184 if let Some(rule) = self.repr
185 && rule == R::STORED
186 {
187 return Some(self.repr_state_as_unchecked::<R>());
188 }
189 None
190 }
191
192 fn repr_state_unchecked(&self) -> MappedRwLockReadGuard<'_, dyn ReprStateStored> {
194 let rule = self
195 .repr
196 .unwrap_or_else(|| bug!("`{}` had no representation", self.name()));
197 RwLockReadGuard::map(self.ptr.reprs(), |reprs| {
198 reprs.get_by_rule(rule).unwrap_or_else(|| {
199 bug!(
200 "Representation '{}' was selected for '{}' but its state was not stored!",
201 rule.name(),
202 self.name()
203 )
204 })
205 })
206 }
207
208 fn repr_state_as_unchecked<R: ReprRule + ?Sized>(
211 &self,
212 ) -> MappedRwLockReadGuard<'_, R::DeclLevel> {
213 R::get_for(&self.ptr).unwrap_or_else(|| {
214 bug!(
215 "`{}` did not have the expected representation `{}`",
216 self.name(),
217 R::NAME
218 )
219 })
220 }
221
222 pub fn resolve_expression(&self) -> Option<Expression> {
228 if let Some(expr) = self.ptr().as_value_letting() {
229 return Some(expr.clone());
230 }
231
232 let generator = {
233 let kind = self.ptr.kind();
234 if let DeclarationKind::Quantified(inner) = &*kind {
235 inner.generator().cloned()
236 } else {
237 None
238 }
239 };
240
241 if let Some(generator) = generator
242 && let Some(expr) = generator.as_value_letting()
243 {
244 return Some(expr.clone());
245 }
246
247 None
248 }
249
250 pub fn boolean_formula_letting_body(&self) -> Option<Expression> {
257 let body = self.resolve_expression()?;
258 boolean_formula_letting(&body).then_some(body)
259 }
260
261 pub fn with_resolved_expression<T>(&self, inspect: impl FnOnce(&Expression) -> T) -> Option<T> {
267 if let Some(expr) = self.ptr().as_value_letting() {
268 return Some(inspect(&expr));
269 }
270
271 let generator = {
272 let kind = self.ptr.kind();
273 if let DeclarationKind::Quantified(inner) = &*kind {
274 inner.generator().cloned()
275 } else {
276 None
277 }
278 }?;
279 let expr = generator.as_value_letting()?;
280 Some(inspect(&expr))
281 }
282
283 pub fn resolve_constant(&self) -> Option<Literal> {
285 self.with_resolved_expression(super::eval::eval_constant)
286 .flatten()
287 }
288
289 pub fn resolve_atomic(&self) -> Option<Atom> {
291 self.with_resolved_expression(|expr| match expr {
292 Expression::Atomic(_, atom) => Some(atom.clone()),
293 _ => None,
294 })
295 .flatten()
296 }
297}
298
299fn boolean_formula_letting(body: &Expression) -> bool {
301 match body {
302 Expression::Atomic(_, Atom::Reference(next)) => next.resolve_expression().is_some(),
303 Expression::Atomic(_, _) => false,
304 other => {
305 other.try_return_type() == Some(ReturnType::Bool)
306 || matches!(
307 other,
308 Expression::Not(_, _)
309 | Expression::Or(_, _)
310 | Expression::And(_, _)
311 | Expression::Imply(_, _, _)
312 | Expression::Iff(_, _, _)
313 | Expression::Eq(_, _, _)
314 | Expression::Neq(_, _, _)
315 | Expression::Geq(_, _, _)
316 | Expression::Leq(_, _, _)
317 | Expression::Gt(_, _, _)
318 | Expression::Lt(_, _, _)
319 | Expression::FlatIneq(_, _, _, _)
320 | Expression::MinionReify(_, _, _)
321 | Expression::MinionReifyImply(_, _, _)
322 )
323 }
324 }
325}
326
327impl From<Reference> for Expression {
328 fn from(value: Reference) -> Self {
329 Expression::Atomic(Metadata::new(), value.into())
330 }
331}
332
333impl From<Reference> for Moo<Expression> {
334 fn from(value: Reference) -> Self {
335 Moo::new(value.into())
336 }
337}
338
339impl From<DeclarationPtr> for Reference {
340 fn from(ptr: DeclarationPtr) -> Self {
341 Reference::new(ptr)
342 }
343}
344
345impl CategoryOf for Reference {
346 fn category_of(&self) -> Category {
347 self.ptr.category_of()
348 }
349}
350
351impl HasDomain for Reference {
352 fn domain_of(&self) -> DomainPtr {
353 self.ptr
354 .domain()
355 .or_else(|| self.resolve_constant().map(|literal| literal.domain_of()))
356 .unwrap_or_else(|| {
357 bug!(
358 "reference ({name}) should have a domain",
359 name = self.ptr.name()
360 )
361 })
362 }
363}
364
365impl Display for Reference {
366 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
367 self.ptr.name().fmt(f)
368 }
369}