Skip to main content

amaru_uplc/machine/
value.rs

1use bumpalo::collections::Vec as BumpVec;
2
3use crate::{
4    arena::Arena,
5    binder::Eval,
6    constant::{Constant, Integer},
7    term::Term,
8    typ::Type,
9};
10
11use super::{env::Env, runtime::Runtime, MachineError};
12
13#[derive(Debug)]
14pub enum Value<'a, V>
15where
16    V: Eval<'a>,
17{
18    Con(&'a Constant<'a>),
19    Lambda {
20        parameter: &'a V,
21        body: &'a Term<'a, V>,
22        env: &'a Env<'a, V>,
23    },
24    Builtin(&'a Runtime<'a, V>),
25    Delay(&'a Term<'a, V>, &'a Env<'a, V>),
26    Constr(usize, &'a [&'a Value<'a, V>]),
27}
28
29impl<'a, V> Value<'a, V>
30where
31    V: Eval<'a>,
32{
33    pub fn con(arena: &'a Arena, constant: &'a Constant<'a>) -> &'a Value<'a, V> {
34        arena.alloc(Value::Con(constant))
35    }
36
37    pub fn lambda(
38        arena: &'a Arena,
39        parameter: &'a V,
40        body: &'a Term<'a, V>,
41        env: &'a Env<'a, V>,
42    ) -> &'a Value<'a, V> {
43        arena.alloc(Value::Lambda {
44            parameter,
45            body,
46            env,
47        })
48    }
49
50    pub fn delay(arena: &'a Arena, body: &'a Term<'a, V>, env: &'a Env<'a, V>) -> &'a Value<'a, V> {
51        arena.alloc(Value::Delay(body, env))
52    }
53
54    pub fn constr_empty(arena: &'a Arena, tag: usize) -> &'a Value<'a, V> {
55        let empty = BumpVec::new_in(arena.as_bump());
56        let empty = arena.alloc(empty);
57
58        arena.alloc(Value::Constr(tag, empty))
59    }
60
61    pub fn constr(
62        arena: &'a Arena,
63        tag: usize,
64        values: &'a [&'a Value<'a, V>],
65    ) -> &'a Value<'a, V> {
66        arena.alloc(Value::Constr(tag, values))
67    }
68
69    pub fn builtin(arena: &'a Arena, runtime: &'a Runtime<'a, V>) -> &'a Value<'a, V> {
70        arena.alloc(Value::Builtin(runtime))
71    }
72
73    pub fn integer(arena: &'a Arena, i: &'a Integer) -> &'a Value<'a, V> {
74        let con = arena.alloc(Constant::Integer(i));
75
76        Value::con(arena, con)
77    }
78
79    pub fn byte_string(arena: &'a Arena, b: &'a [u8]) -> &'a Value<'a, V> {
80        let con = arena.alloc(Constant::ByteString(b));
81
82        Value::con(arena, con)
83    }
84
85    pub fn string(arena: &'a Arena, s: &'a str) -> &'a Value<'a, V> {
86        let con = arena.alloc(Constant::String(s));
87
88        Value::con(arena, con)
89    }
90
91    pub fn bool(arena: &'a Arena, b: bool) -> &'a Value<'a, V> {
92        let con = arena.alloc(Constant::Boolean(b));
93
94        Value::con(arena, con)
95    }
96
97    pub fn unwrap_integer(&'a self) -> Result<&'a Integer, MachineError<'a, V>> {
98        let inner = self.unwrap_constant()?;
99
100        let Constant::Integer(integer) = inner else {
101            return Err(MachineError::type_mismatch(Type::Integer, inner));
102        };
103
104        Ok(integer)
105    }
106
107    pub fn unwrap_byte_string(&'a self) -> Result<&'a [u8], MachineError<'a, V>> {
108        let inner = self.unwrap_constant()?;
109
110        let Constant::ByteString(byte_string) = inner else {
111            return Err(MachineError::type_mismatch(Type::ByteString, inner));
112        };
113
114        Ok(byte_string)
115    }
116
117    pub fn unwrap_string(&'a self) -> Result<&'a str, MachineError<'a, V>> {
118        let inner = self.unwrap_constant()?;
119
120        let Constant::String(string) = inner else {
121            return Err(MachineError::type_mismatch(Type::String, inner));
122        };
123
124        Ok(string)
125    }
126
127    pub fn unwrap_bool(&'a self) -> Result<bool, MachineError<'a, V>> {
128        let inner = self.unwrap_constant()?;
129
130        let Constant::Boolean(b) = inner else {
131            return Err(MachineError::type_mismatch(Type::Bool, inner));
132        };
133
134        Ok(*b)
135    }
136
137    pub fn unwrap_pair(
138        &'a self,
139    ) -> Result<
140        (
141            &'a Type<'a>,
142            &'a Type<'a>,
143            &'a Constant<'a>,
144            &'a Constant<'a>,
145        ),
146        MachineError<'a, V>,
147    > {
148        let inner = self.unwrap_constant()?;
149
150        let Constant::ProtoPair(t1, t2, first, second) = inner else {
151            return Err(MachineError::expected_pair(inner));
152        };
153
154        Ok((t1, t2, first, second))
155    }
156
157    pub fn unwrap_list(
158        &'a self,
159    ) -> Result<(&'a Type<'a>, &'a [&'a Constant<'a>]), MachineError<'a, V>> {
160        let inner = self.unwrap_constant()?;
161
162        let Constant::ProtoList(t1, list) = inner else {
163            return Err(MachineError::expected_list(inner));
164        };
165
166        Ok((t1, list))
167    }
168
169    pub fn unwrap_array(
170        &'a self,
171    ) -> Result<(&'a Type<'a>, &'a [&'a Constant<'a>]), MachineError<'a, V>> {
172        let inner = self.unwrap_constant()?;
173
174        let Constant::ProtoArray(t1, array) = inner else {
175            return Err(MachineError::expected_array(inner));
176        };
177
178        Ok((t1, array))
179    }
180
181    pub fn unwrap_map(
182        &'a self,
183    ) -> Result<(&'a Type<'a>, &'a [&'a Constant<'a>]), MachineError<'a, V>> {
184        let inner = self.unwrap_constant()?;
185
186        let Constant::ProtoList(t1, list) = inner else {
187            return Err(MachineError::expected_list(inner));
188        };
189
190        Ok((t1, list))
191    }
192
193    pub fn unwrap_constant(&'a self) -> Result<&'a Constant<'a>, MachineError<'a, V>> {
194        let Value::Con(item) = self else {
195            return Err(MachineError::NotAConstant(self));
196        };
197
198        Ok(item)
199    }
200
201    pub fn unwrap_unit(&'a self) -> Result<(), MachineError<'a, V>> {
202        let inner = self.unwrap_constant()?;
203
204        let Constant::Unit = inner else {
205            return Err(MachineError::type_mismatch(Type::Unit, inner));
206        };
207
208        Ok(())
209    }
210
211    pub(super) fn unwrap_int_list(&'a self) -> Result<&'a [&'a Constant<'a>], MachineError<'a, V>> {
212        let inner = self.unwrap_constant()?;
213
214        let Constant::ProtoList(Type::Integer, list) = inner else {
215            return Err(MachineError::type_mismatch(
216                Type::List(&Type::Integer),
217                inner,
218            ));
219        };
220
221        Ok(list)
222    }
223
224    pub fn unwrap_bls12_381_g1_element(&'a self) -> Result<&'a blst::blst_p1, MachineError<'a, V>> {
225        let inner = self.unwrap_constant()?;
226
227        let Constant::Bls12_381G1Element(g1) = inner else {
228            return Err(MachineError::type_mismatch(Type::Bls12_381G1Element, inner));
229        };
230
231        Ok(g1)
232    }
233
234    pub fn unwrap_bls12_381_g2_element(&'a self) -> Result<&'a blst::blst_p2, MachineError<'a, V>> {
235        let inner = self.unwrap_constant()?;
236
237        let Constant::Bls12_381G2Element(g2) = inner else {
238            return Err(MachineError::type_mismatch(Type::Bls12_381G2Element, inner));
239        };
240
241        Ok(g2)
242    }
243
244    pub fn unwrap_bls12_381_ml_result(
245        &'a self,
246    ) -> Result<&'a blst::blst_fp12, MachineError<'a, V>> {
247        let inner = self.unwrap_constant()?;
248
249        let Constant::Bls12_381MlResult(ml_res) = inner else {
250            return Err(MachineError::type_mismatch(Type::Bls12_381MlResult, inner));
251        };
252
253        Ok(ml_res)
254    }
255}
256
257impl<'a> Constant<'a> {
258    pub fn value<V>(&'a self, arena: &'a Arena) -> &'a Value<'a, V>
259    where
260        V: Eval<'a>,
261    {
262        Value::con(arena, self)
263    }
264}