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