Skip to main content

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(
23    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Uniplate, Derivative,
24)]
25#[derivative(Hash)]
26#[uniplate()]
27#[biplate(to=DeclarationPtr)]
28#[biplate(to=Name)]
29pub struct Reference {
30    #[serde_as(as = "DeclarationPtrAsId")]
31    pub ptr: DeclarationPtr,
32}
33
34impl Reference {
35    pub fn new(ptr: DeclarationPtr) -> Self {
36        Reference { ptr }
37    }
38
39    pub fn ptr(&self) -> &DeclarationPtr {
40        &self.ptr
41    }
42
43    pub fn into_ptr(self) -> DeclarationPtr {
44        self.ptr
45    }
46
47    pub fn name(&self) -> std::cell::Ref<'_, Name> {
48        self.ptr.name()
49    }
50
51    pub fn id(&self) -> crate::ast::serde::ObjId {
52        self.ptr.id()
53    }
54
55    pub fn domain(&self) -> Option<DomainPtr> {
56        self.ptr.domain()
57    }
58
59    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
60        self.domain()?.resolve()
61    }
62}
63
64impl From<Reference> for Expression {
65    fn from(value: Reference) -> Self {
66        Expression::Atomic(Metadata::new(), value.into())
67    }
68}
69
70impl From<DeclarationPtr> for Reference {
71    fn from(ptr: DeclarationPtr) -> Self {
72        Reference::new(ptr)
73    }
74}
75
76impl CategoryOf for Reference {
77    fn category_of(&self) -> Category {
78        self.ptr.category_of()
79    }
80}
81
82impl HasDomain for Reference {
83    fn domain_of(&self) -> DomainPtr {
84        self.ptr.domain().unwrap_or_else(|| {
85            bug!(
86                "reference ({name}) should have a domain",
87                name = self.ptr.name()
88            )
89        })
90    }
91}
92
93impl Display for Reference {
94    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95        self.ptr.name().fmt(f)
96    }
97}