conjure_core/ast/
atom.rs

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