conjure_core/ast/
atom.rs

1use std::borrow::Borrow;
2
3use super::{literals::AbstractLiteral, Expression, Literal, Name};
4use serde::{Deserialize, Serialize};
5use uniplate::derive::Uniplate;
6
7/// An `Atom` is an indivisible expression, such as a literal or a reference.
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
9#[uniplate()]
10#[biplate(to=Literal)]
11#[biplate(to=Expression)]
12#[biplate(to=AbstractLiteral<Literal>,walk_into=[Literal])]
13#[biplate(to=Name)]
14pub enum Atom {
15    Literal(Literal),
16    Reference(Name),
17}
18
19impl Atom {
20    /// Shorthand to create a reference by user name.
21    pub fn new_uref(name: &str) -> Atom {
22        Atom::Reference(Name::UserName(name.to_string()))
23    }
24}
25
26impl std::fmt::Display for Atom {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        match self {
29            Atom::Literal(x) => x.fmt(f),
30            Atom::Reference(x) => x.fmt(f),
31        }
32    }
33}
34
35impl From<Literal> for Atom {
36    fn from(value: Literal) -> Self {
37        Atom::Literal(value)
38    }
39}
40
41impl From<Name> for Atom {
42    fn from(value: Name) -> Self {
43        Atom::Reference(value)
44    }
45}
46
47impl From<i32> for Atom {
48    fn from(value: i32) -> Self {
49        Atom::Literal(value.into())
50    }
51}
52
53impl From<bool> for Atom {
54    fn from(value: bool) -> Self {
55        Atom::Literal(value.into())
56    }
57}
58
59impl TryFrom<Expression> for Atom {
60    type Error = &'static str;
61
62    fn try_from(value: Expression) -> Result<Self, Self::Error> {
63        match value {
64            Expression::Atomic(_, atom) => Ok(atom),
65            _ => Err("Cannot convert non-atomic expression to Atom"),
66        }
67    }
68}
69
70impl<'a> TryFrom<&'a Expression> for &'a Atom {
71    type Error = &'static str;
72
73    fn try_from(value: &'a Expression) -> Result<Self, Self::Error> {
74        match value {
75            Expression::Atomic(_, atom) => Ok(atom),
76            _ => Err("Cannot convert non-atomic expression to Atom"),
77        }
78    }
79}
80
81impl TryFrom<Box<Expression>> for Atom {
82    type Error = &'static str;
83
84    fn try_from(value: Box<Expression>) -> Result<Self, Self::Error> {
85        (*value).try_into()
86    }
87}
88
89impl<'a> TryFrom<&'a Box<Expression>> for &'a Atom {
90    type Error = &'static str;
91
92    fn try_from(value: &'a Box<Expression>) -> Result<Self, Self::Error> {
93        let expr: &'a Expression = value.borrow();
94        expr.try_into()
95    }
96}
97
98impl TryFrom<Atom> for Literal {
99    type Error = &'static str;
100
101    fn try_from(value: Atom) -> Result<Self, Self::Error> {
102        match value {
103            Atom::Literal(l) => Ok(l),
104            _ => Err("Cannot convert non-literal atom to Literal"),
105        }
106    }
107}
108
109impl<'a> TryFrom<&'a Atom> for &'a Literal {
110    type Error = &'static str;
111
112    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
113        match value {
114            Atom::Literal(l) => Ok(l),
115            _ => Err("Cannot convert non-literal atom to Literal"),
116        }
117    }
118}
119
120impl TryFrom<Atom> for Name {
121    type Error = &'static str;
122
123    fn try_from(value: Atom) -> Result<Self, Self::Error> {
124        match value {
125            Atom::Reference(n) => Ok(n),
126            _ => Err("Cannot convert non-reference atom to Name"),
127        }
128    }
129}
130
131impl<'a> TryFrom<&'a Atom> for &'a Name {
132    type Error = &'static str;
133
134    fn try_from(value: &'a Atom) -> Result<Self, Self::Error> {
135        match value {
136            Atom::Reference(n) => Ok(n),
137            _ => Err("Cannot convert non-reference atom to Name"),
138        }
139    }
140}
141
142impl TryFrom<Atom> for i32 {
143    type Error = &'static str;
144
145    fn try_from(value: Atom) -> Result<Self, Self::Error> {
146        let lit: Literal = value.try_into()?;
147        lit.try_into()
148    }
149}
150
151impl TryFrom<&Atom> for i32 {
152    type Error = &'static str;
153
154    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
155        let lit: &Literal = value.try_into()?;
156        lit.try_into()
157    }
158}
159
160impl TryFrom<Atom> for bool {
161    type Error = &'static str;
162
163    fn try_from(value: Atom) -> Result<Self, Self::Error> {
164        let lit: Literal = value.try_into()?;
165        lit.try_into()
166    }
167}
168
169impl TryFrom<&Atom> for bool {
170    type Error = &'static str;
171
172    fn try_from(value: &Atom) -> Result<Self, Self::Error> {
173        let lit: &Literal = value.try_into()?;
174        lit.try_into()
175    }
176}