conjure_cp_core/ast/
atom.rs1use 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#[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}