1use std::sync::Arc;
8
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
15pub enum Literal {
16 Bool(bool),
18 Int(i64),
20 Float(f64),
22 Str(String),
24 Bytes(Vec<u8>),
26 Null,
28 Record(Vec<(Arc<str>, Self)>),
30 List(Vec<Self>),
32 Closure {
38 param: Arc<str>,
40 body: Box<crate::Expr>,
42 env: Vec<(Arc<str>, Self)>,
44 },
45}
46
47impl Literal {
48 #[must_use]
50 pub const fn type_name(&self) -> &'static str {
51 match self {
52 Self::Bool(_) => "bool",
53 Self::Int(_) => "int",
54 Self::Float(_) => "float",
55 Self::Str(_) => "string",
56 Self::Bytes(_) => "bytes",
57 Self::Null => "null",
58 Self::Record(_) => "record",
59 Self::List(_) => "list",
60 Self::Closure { .. } => "function",
61 }
62 }
63
64 #[must_use]
66 pub const fn is_null(&self) -> bool {
67 matches!(self, Self::Null)
68 }
69
70 #[must_use]
72 pub const fn as_bool(&self) -> Option<bool> {
73 match self {
74 Self::Bool(b) => Some(*b),
75 _ => None,
76 }
77 }
78
79 #[must_use]
81 pub const fn as_int(&self) -> Option<i64> {
82 match self {
83 Self::Int(n) => Some(*n),
84 _ => None,
85 }
86 }
87
88 #[must_use]
90 pub const fn as_float(&self) -> Option<f64> {
91 match self {
92 Self::Float(f) => Some(*f),
93 _ => None,
94 }
95 }
96
97 #[must_use]
99 pub fn as_str(&self) -> Option<&str> {
100 match self {
101 Self::Str(s) => Some(s),
102 _ => None,
103 }
104 }
105
106 #[must_use]
108 pub fn as_record(&self) -> Option<&[(Arc<str>, Self)]> {
109 match self {
110 Self::Record(fields) => Some(fields),
111 _ => None,
112 }
113 }
114
115 #[must_use]
117 pub fn as_list(&self) -> Option<&[Self]> {
118 match self {
119 Self::List(items) => Some(items),
120 _ => None,
121 }
122 }
123
124 #[must_use]
126 pub fn field(&self, name: &str) -> Option<&Self> {
127 match self {
128 Self::Record(fields) => fields.iter().find(|(k, _)| &**k == name).map(|(_, v)| v),
129 _ => None,
130 }
131 }
132}
133
134impl PartialEq for Literal {
137 fn eq(&self, other: &Self) -> bool {
138 match (self, other) {
139 (Self::Bool(a), Self::Bool(b)) => a == b,
140 (Self::Int(a), Self::Int(b)) => a == b,
141 (Self::Float(a), Self::Float(b)) => a.to_bits() == b.to_bits(),
142 (Self::Str(a), Self::Str(b)) => a == b,
143 (Self::Bytes(a), Self::Bytes(b)) => a == b,
144 (Self::Null, Self::Null) => true,
145 (Self::Record(a), Self::Record(b)) => a == b,
146 (Self::List(a), Self::List(b)) => a == b,
147 (
148 Self::Closure {
149 param: p1,
150 body: b1,
151 env: e1,
152 },
153 Self::Closure {
154 param: p2,
155 body: b2,
156 env: e2,
157 },
158 ) => p1 == p2 && b1 == b2 && e1 == e2,
159 _ => false,
160 }
161 }
162}
163
164impl Eq for Literal {}
165
166impl std::hash::Hash for Literal {
167 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
168 std::mem::discriminant(self).hash(state);
169 match self {
170 Self::Bool(b) => b.hash(state),
171 Self::Int(n) => n.hash(state),
172 Self::Float(f) => f.to_bits().hash(state),
173 Self::Str(s) => s.hash(state),
174 Self::Bytes(b) => b.hash(state),
175 Self::Null => {}
176 Self::Record(fields) => fields.hash(state),
177 Self::List(items) => items.hash(state),
178 Self::Closure { param, body, env } => {
179 param.hash(state);
180 body.hash(state);
181 env.hash(state);
182 }
183 }
184 }
185}
186
187impl std::fmt::Display for Literal {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 match self {
190 Self::Bool(b) => write!(f, "{b}"),
191 Self::Int(n) => write!(f, "{n}"),
192 Self::Float(v) => write!(f, "{v}"),
193 Self::Str(s) => write!(f, "\"{s}\""),
194 Self::Bytes(b) => write!(f, "<{} bytes>", b.len()),
195 Self::Null => write!(f, "null"),
196 Self::Record(fields) => {
197 write!(f, "{{ ")?;
198 for (i, (k, v)) in fields.iter().enumerate() {
199 if i > 0 {
200 write!(f, ", ")?;
201 }
202 write!(f, "{k}: {v}")?;
203 }
204 write!(f, " }}")
205 }
206 Self::List(items) => {
207 write!(f, "[")?;
208 for (i, v) in items.iter().enumerate() {
209 if i > 0 {
210 write!(f, ", ")?;
211 }
212 write!(f, "{v}")?;
213 }
214 write!(f, "]")
215 }
216 Self::Closure { param, .. } => write!(f, "<closure λ{param}>"),
217 }
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn float_equality_uses_bits() {
227 let a = Literal::Float(f64::NAN);
229 let b = Literal::Float(f64::NAN);
230 assert_eq!(a, b);
231 }
232
233 #[test]
234 fn type_names() {
235 assert_eq!(Literal::Bool(true).type_name(), "bool");
236 assert_eq!(Literal::Int(42).type_name(), "int");
237 assert_eq!(Literal::Null.type_name(), "null");
238 assert_eq!(Literal::Record(vec![]).type_name(), "record");
239 assert_eq!(Literal::List(vec![]).type_name(), "list");
240 }
241
242 #[test]
243 fn record_field_lookup() {
244 let rec = Literal::Record(vec![
245 (Arc::from("name"), Literal::Str("alice".into())),
246 (Arc::from("age"), Literal::Int(30)),
247 ]);
248 assert_eq!(rec.field("name"), Some(&Literal::Str("alice".into())));
249 assert_eq!(rec.field("age"), Some(&Literal::Int(30)));
250 assert_eq!(rec.field("missing"), None);
251 }
252}