conjure_cp_core/ast/
atom.rs

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