conjure_cp_core/ast/
reference.rs

1use crate::ast::declaration::serde::DeclarationPtrAsId;
2use crate::ast::serde::HasId;
3use crate::{ast::DeclarationPtr, bug};
4use derivative::Derivative;
5use serde::{Deserialize, Serialize};
6use serde_with::serde_as;
7use std::fmt::{Display, Formatter};
8use uniplate::Uniplate;
9
10use super::{
11    DomainPtr, Expression, GroundDomain, Metadata, Moo, Name,
12    categories::{Category, CategoryOf},
13    domains::HasDomain,
14};
15
16/// A reference to a declaration (variable, parameter, etc.)
17///
18/// This is a thin wrapper around [`DeclarationPtr`] with two main purposes:
19/// 1. Encapsulate the serde pragmas (e.g., serializing as IDs rather than full objects)
20/// 2. Enable type-directed traversals of references via uniplate
21#[serde_as]
22#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate, Derivative)]
23#[derivative(Hash)]
24#[uniplate()]
25#[biplate(to=DeclarationPtr)]
26#[biplate(to=Name)]
27pub struct Reference {
28    #[serde_as(as = "DeclarationPtrAsId")]
29    pub ptr: DeclarationPtr,
30}
31
32impl Reference {
33    pub fn new(ptr: DeclarationPtr) -> Self {
34        Reference { ptr }
35    }
36
37    pub fn ptr(&self) -> &DeclarationPtr {
38        &self.ptr
39    }
40
41    pub fn into_ptr(self) -> DeclarationPtr {
42        self.ptr
43    }
44
45    pub fn name(&self) -> std::cell::Ref<'_, Name> {
46        self.ptr.name()
47    }
48
49    pub fn id(&self) -> crate::ast::serde::ObjId {
50        self.ptr.id()
51    }
52
53    pub fn domain(&self) -> Option<DomainPtr> {
54        self.ptr.domain()
55    }
56
57    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
58        self.domain()?.resolve()
59    }
60}
61
62impl From<Reference> for Expression {
63    fn from(value: Reference) -> Self {
64        Expression::Atomic(Metadata::new(), value.into())
65    }
66}
67
68impl From<DeclarationPtr> for Reference {
69    fn from(ptr: DeclarationPtr) -> Self {
70        Reference::new(ptr)
71    }
72}
73
74impl CategoryOf for Reference {
75    fn category_of(&self) -> Category {
76        self.ptr.category_of()
77    }
78}
79
80impl HasDomain for Reference {
81    fn domain_of(&self) -> DomainPtr {
82        self.ptr.domain().unwrap_or_else(|| {
83            bug!(
84                "reference ({name}) should have a domain",
85                name = self.ptr.name()
86            )
87        })
88    }
89}
90
91impl Display for Reference {
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        self.ptr.name().fmt(f)
94    }
95}