Skip to main content

conjure_cp_core/ast/
atom.rs

1use std::borrow::Borrow;
2use uniplate::Uniplate;
3
4use super::{
5    AbstractLiteral, DeclarationPtr, DomainPtr, Expression, Literal, Moo, Name,
6    categories::{Category, CategoryOf},
7    domains::HasDomain,
8    records::RecordValue,
9};
10use derivative::Derivative;
11use parking_lot::MappedRwLockReadGuard;
12use polyquine::Quine;
13use serde::{Deserialize, Serialize};
14
15/// An `Atom` is an indivisible expression, such as a literal or a reference.
16#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate, Derivative, Quine)]
17#[derivative(Hash)]
18#[uniplate()]
19#[biplate(to=Literal)]
20#[biplate(to=Expression)]
21#[biplate(to=AbstractLiteral<Literal>)]
22#[biplate(to=RecordValue<Literal>)]
23#[biplate(to=DeclarationPtr)]
24#[biplate(to=Name)]
25#[biplate(to=super::Reference)]
26#[path_prefix(conjure_cp::ast)]
27pub enum Atom {
28    Literal(Literal),
29    #[polyquine_skip]
30    Reference(super::Reference),
31}
32
33impl Atom {
34    pub fn new_ref(decl: DeclarationPtr) -> Atom {
35        Atom::Reference(super::Reference::new(decl))
36    }
37
38    pub fn into_declaration(self) -> DeclarationPtr {
39        match self {
40            Atom::Reference(reference) => reference.into_ptr(),
41            _ => panic!("Called into_declaration on a non-reference Atom"),
42        }
43    }
44}
45
46impl CategoryOf for Atom {
47    fn category_of(&self) -> Category {
48        match self {
49            Atom::Literal(_) => Category::Constant,
50            Atom::Reference(reference) => reference.category_of(),
51        }
52    }
53}
54
55impl HasDomain for Atom {
56    fn domain_of(&self) -> DomainPtr {
57        match self {
58            Atom::Literal(literal) => literal.domain_of(),
59            Atom::Reference(reference) => reference.domain_of(),
60        }
61    }
62}
63
64impl std::fmt::Display for Atom {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        match self {
67            Atom::Literal(x) => x.fmt(f),
68            Atom::Reference(x) => x.fmt(f),
69        }
70    }
71}
72
73impl From<Literal> for Atom {
74    fn from(value: Literal) -> Self {
75        Atom::Literal(value)
76    }
77}
78
79impl From<DeclarationPtr> for Atom {
80    fn from(value: DeclarationPtr) -> Self {
81        Atom::Reference(super::Reference::new(value))
82    }
83}
84
85impl From<super::Reference> for Atom {
86    fn from(value: super::Reference) -> Self {
87        Atom::Reference(value)
88    }
89}
90
91impl From<i32> for Atom {
92    fn from(value: i32) -> Self {
93        Atom::Literal(value.into())
94    }
95}
96
97impl From<bool> for Atom {
98    fn from(value: bool) -> Self {
99        Atom::Literal(value.into())
100    }
101}
102
103impl TryFrom<Expression> for Atom {
104    type Error = &'static str;
105
106    fn try_from(value: Expression) -> Result<Self, Self::Error> {
107        match value {
108            Expression::Atomic(_, atom) => Ok(atom),
109            _ => Err("Cannot convert non-atomic expression to Atom"),
110        }
111    }
112}
113
114impl TryFrom<Box<Expression>> for Atom {
115    type Error = &'static str;
116
117    fn try_from(value: Box<Expression>) -> Result<Self, Self::Error> {
118        TryFrom::try_from(*value)
119    }
120}
121
122impl TryFrom<Moo<Expression>> for Atom {
123    type Error = &'static str;
124
125    fn try_from(value: Moo<Expression>) -> Result<Self, Self::Error> {
126        TryFrom::try_from(Moo::unwrap_or_clone(value))
127    }
128}
129impl<'a> TryFrom<&'a Expression> for &'a Atom {
130    type Error = &'static str;
131
132    fn try_from(value: &'a Expression) -> Result<Self, Self::Error> {
133        match value {
134            Expression::Atomic(_, atom) => Ok(atom),
135            _ => Err("Cannot convert non-atomic expression to Atom"),
136        }
137    }
138}
139
140impl<'a> TryFrom<&'a Box<Expression>> for &'a Atom {
141    type Error = &'static str;
142
143    fn try_from(value: &'a Box<Expression>) -> Result<Self, Self::Error> {
144        let expr: &'a Expression = value.borrow();
145        expr.try_into()
146    }
147}
148
149impl<'a> TryFrom<&'a Moo<Expression>> for &'a Atom {
150    type Error = &'static str;
151
152    fn try_from(value: &'a Moo<Expression>) -> Result<Self, Self::Error> {
153        let expr: &'a Expression = value.borrow();
154        expr.try_into()
155    }
156}
157
158impl TryFrom<Atom> for Literal {
159    type Error = &'static str;
160
161    fn try_from(value: Atom) -> Result<Self, Self::Error> {
162        match value {
163            Atom::Literal(l) => Ok(l),
164            _ => Err("Cannot convert non-literal atom to Literal"),
165        }
166    }
167}
168
169impl<'a> TryFrom<&'a Atom> for &'a Literal {
170    type Error = &'static str;
171
172    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
173        match value {
174            Atom::Literal(l) => Ok(l),
175            _ => Err("Cannot convert non-literal atom to Literal"),
176        }
177    }
178}
179
180impl TryFrom<Atom> for Name {
181    type Error = &'static str;
182
183    fn try_from(value: Atom) -> Result<Self, Self::Error> {
184        match value {
185            Atom::Reference(x) => Ok(x.ptr().name().clone()),
186            _ => Err("Cannot convert non-reference atom to Name"),
187        }
188    }
189}
190
191impl<'a> TryFrom<&'a Atom> for MappedRwLockReadGuard<'a, Name> {
192    type Error = &'static str;
193
194    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
195        match value {
196            Atom::Reference(x) => Ok(x.ptr().name()),
197            _ => Err("Cannot convert non-reference atom to Name"),
198        }
199    }
200}
201
202impl TryFrom<Atom> for i32 {
203    type Error = &'static str;
204
205    fn try_from(value: Atom) -> Result<Self, Self::Error> {
206        let lit: Literal = value.try_into()?;
207        lit.try_into()
208    }
209}
210
211impl TryFrom<&Box<Atom>> for i32 {
212    type Error = &'static str;
213
214    fn try_from(value: &Box<Atom>) -> Result<Self, Self::Error> {
215        TryFrom::<&Atom>::try_from(value.as_ref())
216    }
217}
218
219impl TryFrom<Box<Atom>> for i32 {
220    type Error = &'static str;
221
222    fn try_from(value: Box<Atom>) -> Result<Self, Self::Error> {
223        let lit: Literal = (*value).try_into()?;
224        lit.try_into()
225    }
226}
227
228impl TryFrom<&Moo<Atom>> for i32 {
229    type Error = &'static str;
230
231    fn try_from(value: &Moo<Atom>) -> Result<Self, Self::Error> {
232        TryFrom::<&Atom>::try_from(value.as_ref())
233    }
234}
235
236impl TryFrom<Moo<Atom>> for i32 {
237    type Error = &'static str;
238
239    fn try_from(value: Moo<Atom>) -> Result<Self, Self::Error> {
240        TryFrom::<&Atom>::try_from(value.as_ref())
241    }
242}
243
244impl TryFrom<&Atom> for i32 {
245    type Error = &'static str;
246
247    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
248        match value {
249            Atom::Literal(lit) => lit.try_into(),
250            Atom::Reference(reference) => {
251                let lit = reference
252                    .resolve_constant()
253                    .ok_or("Cannot convert non-constant reference atom to literal")?;
254                lit.try_into()
255                    .map_err(|_| "Cannot convert non-int reference atom to i32")
256            }
257        }
258    }
259}
260
261impl TryFrom<Atom> for bool {
262    type Error = &'static str;
263
264    fn try_from(value: Atom) -> Result<Self, Self::Error> {
265        let lit: Literal = value.try_into()?;
266        lit.try_into()
267    }
268}
269
270impl TryFrom<&Atom> for bool {
271    type Error = &'static str;
272
273    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
274        match value {
275            Atom::Literal(lit) => lit.try_into(),
276            Atom::Reference(reference) => {
277                let lit = reference
278                    .resolve_constant()
279                    .ok_or("Cannot convert non-constant reference atom to literal")?;
280                lit.try_into()
281                    .map_err(|_| "Cannot convert non-bool reference atom to bool")
282            }
283        }
284    }
285}