onion_vm/types/lambda/
parameter.rs1use std::fmt::Display;
7
8use arc_gc::{arc::GCArc, traceable::GCTraceable};
9
10use crate::{
11 lambda::runnable::RuntimeError,
12 types::{
13 object::{OnionObject, OnionObjectCell, OnionStaticObject},
14 pair::OnionPair,
15 tuple::OnionTuple,
16 },
17};
18
19#[derive(Debug, Clone)]
37pub enum LambdaParameter {
38 Single((Box<str>, OnionObject)),
40 Multiple(Box<[LambdaParameter]>),
42}
43
44impl GCTraceable<OnionObjectCell> for LambdaParameter {
45 fn collect(
46 &self,
47 queue: &mut std::collections::VecDeque<arc_gc::arc::GCArcWeak<OnionObjectCell>>,
48 ) {
49 match self {
50 LambdaParameter::Single((_, obj)) => {
51 obj.collect(queue);
52 }
53 LambdaParameter::Multiple(params) => {
54 for param in params {
55 param.collect(queue);
56 }
57 }
58 }
59 }
60}
61
62impl Display for LambdaParameter {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 LambdaParameter::Single((key, obj)) => {
66 write!(f, "{} : {:?}", key, obj)
67 }
68 LambdaParameter::Multiple(params) => {
69 write!(
70 f,
71 "({})",
72 params
73 .iter()
74 .map(|p| p.to_string())
75 .collect::<Vec<_>>()
76 .join(", ")
77 )
78 }
79 }
80 }
81}
82
83impl LambdaParameter {
84 pub fn top(key: &str) -> Self {
86 Self::Single((key.into(), OnionObject::Boolean(true)))
87 }
88
89 pub fn bottom(key: &str) -> Self {
91 Self::Single((key.into(), OnionObject::Boolean(false)))
92 }
93}
94
95impl LambdaParameter {
96 pub fn len(&self) -> usize {
100 match self {
101 LambdaParameter::Single(_) => 1,
102 LambdaParameter::Multiple(params) => params.iter().map(LambdaParameter::len).sum(),
103 }
104 }
105
106 pub fn constraint_at(&self, index: usize) -> Option<&OnionObject> {
115 match self {
116 LambdaParameter::Single((_, obj)) => {
117 if index == 0 {
118 Some(obj)
119 } else {
120 None
121 }
122 }
123 LambdaParameter::Multiple(params) => {
124 let mut curr = index;
125 for param in params {
126 let len = param.len();
127 if curr < len {
128 return param.constraint_at(curr);
129 } else {
130 curr -= len;
131 }
132 }
133 None
134 }
135 }
136 }
137
138 #[allow(dead_code)]
140 pub fn key_at(&self, index: usize) -> Option<&str> {
141 match self {
142 LambdaParameter::Single((key, _)) => {
143 if index == 0 {
144 Some(key)
145 } else {
146 None
147 }
148 }
149 LambdaParameter::Multiple(params) => {
150 let mut curr = index;
151 for param in params {
152 let len = param.len();
153 if curr < len {
154 return param.key_at(curr);
155 } else {
156 curr -= len;
157 }
158 }
159 None
160 }
161 }
162 }
163
164 #[allow(dead_code)]
166 pub fn at(&self, index: usize) -> Option<(&str, &OnionObject)> {
167 match self {
168 LambdaParameter::Single((key, obj)) => {
169 if index == 0 {
170 Some((key, obj))
171 } else {
172 None
173 }
174 }
175 LambdaParameter::Multiple(params) => {
176 let mut curr = index;
177 for param in params {
178 let len = param.len();
179 if curr < len {
180 return param.at(curr);
181 } else {
182 curr -= len;
183 }
184 }
185 None
186 }
187 }
188 }
189
190 pub fn to_onion(&self) -> OnionStaticObject {
198 fn inner(param: &LambdaParameter) -> OnionObject {
199 match param {
200 LambdaParameter::Single((key, obj)) => OnionObject::Pair(
201 OnionPair::new(OnionObject::String(key.clone().into()), obj.clone()).into(),
202 ),
203 LambdaParameter::Multiple(params) => {
204 let mut pairs = vec![];
205 for param in params {
206 pairs.push(inner(param));
207 }
208 OnionObject::Tuple(OnionTuple::new(pairs).into())
209 }
210 }
211 }
212 inner(self).consume_and_stabilize()
213 }
214
215 pub fn from_onion(obj: &OnionObject) -> Result<LambdaParameter, RuntimeError> {
225 fn inner(obj: &OnionObject) -> Result<LambdaParameter, RuntimeError> {
226 match obj {
227 OnionObject::Pair(pair) => {
228 let key = match pair.get_key() {
229 OnionObject::String(s) => s.as_ref(),
230 _ => {
231 return Err(RuntimeError::InvalidType(
232 format!("Expected string key, found: {:?}", obj).into(),
233 ));
234 }
235 };
236 let value = pair.get_value();
237 Ok(LambdaParameter::Single((key.into(), value.clone())))
238 }
239 OnionObject::Tuple(tuple) => {
240 let mut params = Vec::with_capacity(tuple.get_elements().len());
241 for item in tuple.get_elements().iter() {
242 params.push(inner(item)?);
243 }
244 Ok(LambdaParameter::Multiple(params.into_boxed_slice()))
245 }
246 OnionObject::String(s) => {
247 Ok(LambdaParameter::Single((
249 Box::from(s.as_ref()),
250 OnionObject::Boolean(true),
251 )))
252 }
253 _ => Err(RuntimeError::InvalidType(
254 format!("Expected one of pair, tuple, or string, found: {:?}", obj).into(),
255 )),
256 }
257 }
258 inner(obj)
259 }
260}
261
262impl LambdaParameter {
263 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
268 match self {
269 Self::Single((_, v)) => v.upgrade(collected),
270 Self::Multiple(v) => v.iter().for_each(|e| e.upgrade(collected)),
271 }
272 }
273}
274
275impl LambdaParameter {
276 pub fn unpack_arguments(
292 &self,
293 argument: &OnionObject,
294 ) -> Result<Vec<OnionObject>, RuntimeError> {
295 let mut collected = Vec::with_capacity(self.len());
296
297 fn inner(
298 object: &OnionObject,
299 layer: &LambdaParameter,
300 collected: &mut Vec<OnionObject>,
301 ) -> Result<(), RuntimeError> {
302 match layer {
303 LambdaParameter::Single(_) => {
304 collected.push(object.clone());
306 Ok(())
307 }
308 LambdaParameter::Multiple(v) => {
309 object.with_data(|data| match data {
311 OnionObject::Tuple(tuple) => {
312 if tuple.get_elements().len() != v.len() {
313 return Err(RuntimeError::InvalidOperation(
314 "Arity Mismatch".into(),
315 ));
316 }
317 for (i, object) in tuple.get_elements().iter().enumerate() {
318 inner(object, &v[i], collected)?;
319 }
320 Ok(())
321 }
322 _ => Err(RuntimeError::InvalidType(
323 format!("Expected tuple, found: {:?}", data).into(),
324 )),
325 })
326 }
327 }
328 }
329
330 inner(argument, &self, &mut collected)?;
331 Ok(collected)
332 }
333}
334
335impl LambdaParameter {
336 pub fn flatten_keys(&self) -> Box<[Box<str>]> {
344 let mut keys = Vec::with_capacity(self.len());
345 fn inner(param: &LambdaParameter, collected_keys: &mut Vec<Box<str>>) {
346 match param {
347 LambdaParameter::Single((name, _)) => {
348 collected_keys.push(name.clone());
349 }
350 LambdaParameter::Multiple(params) => {
351 for sub_param in params {
352 inner(sub_param, collected_keys);
353 }
354 }
355 }
356 }
357 inner(self, &mut keys);
358 keys.into_boxed_slice()
359 }
360
361 pub fn flatten_constraints(&self) -> Box<[OnionObject]> {
369 let mut constraints = Vec::with_capacity(self.len());
370
371 fn inner(param: &LambdaParameter, collected_constraints: &mut Vec<OnionObject>) {
372 match param {
373 LambdaParameter::Single((_, constraint_obj)) => {
374 collected_constraints.push(constraint_obj.clone());
375 }
376 LambdaParameter::Multiple(params) => {
377 for sub_param in params {
378 inner(sub_param, collected_constraints);
379 }
380 }
381 }
382 }
383 inner(self, &mut constraints);
384 constraints.into_boxed_slice()
385 }
386}