onion_vm/types/lambda/
parameter.rs1use std::fmt::Display;
2
3use arc_gc::{arc::GCArc, traceable::GCTraceable};
4
5use crate::{
6 lambda::runnable::RuntimeError,
7 types::{
8 object::{OnionObject, OnionObjectCell, OnionStaticObject},
9 pair::OnionPair,
10 tuple::OnionTuple,
11 },
12};
13
14#[derive(Debug, Clone)]
15pub enum LambdaParameter {
16 Single((Box<str>, OnionObject)),
17 Multiple(Box<[LambdaParameter]>),
18}
19
20impl GCTraceable<OnionObjectCell> for LambdaParameter {
21 fn collect(
22 &self,
23 queue: &mut std::collections::VecDeque<arc_gc::arc::GCArcWeak<OnionObjectCell>>,
24 ) {
25 match self {
26 LambdaParameter::Single((_, obj)) => {
27 obj.collect(queue);
28 }
29 LambdaParameter::Multiple(params) => {
30 for param in params {
31 param.collect(queue);
32 }
33 }
34 }
35 }
36}
37
38impl Display for LambdaParameter {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 match self {
41 LambdaParameter::Single((key, obj)) => {
42 write!(f, "{} : {:?}", key, obj)
43 }
44 LambdaParameter::Multiple(params) => {
45 write!(
46 f,
47 "({})",
48 params
49 .iter()
50 .map(|p| p.to_string())
51 .collect::<Vec<_>>()
52 .join(", ")
53 )
54 }
55 }
56 }
57}
58
59impl LambdaParameter {
60 pub fn top(key: &str) -> Self {
61 Self::Single((key.into(), OnionObject::Boolean(true)))
62 }
63
64 pub fn bottom(key: &str) -> Self {
65 Self::Single((key.into(), OnionObject::Boolean(false)))
66 }
67}
68
69impl LambdaParameter {
70 pub fn len(&self) -> usize {
71 match self {
72 LambdaParameter::Single(_) => 1,
73 LambdaParameter::Multiple(params) => params.iter().map(LambdaParameter::len).sum(),
74 }
75 }
76
77 pub fn constraint_at(&self, index: usize) -> Option<&OnionObject> {
79 match self {
80 LambdaParameter::Single((_, obj)) => {
81 if index == 0 {
82 Some(obj)
83 } else {
84 None
85 }
86 }
87 LambdaParameter::Multiple(params) => {
88 let mut curr = index;
89 for param in params {
90 let len = param.len();
91 if curr < len {
92 return param.constraint_at(curr);
93 } else {
94 curr -= len;
95 }
96 }
97 None
98 }
99 }
100 }
101
102 #[allow(dead_code)]
103 pub fn key_at(&self, index: usize) -> Option<&str> {
104 match self {
105 LambdaParameter::Single((key, _)) => {
106 if index == 0 {
107 Some(key)
108 } else {
109 None
110 }
111 }
112 LambdaParameter::Multiple(params) => {
113 let mut curr = index;
114 for param in params {
115 let len = param.len();
116 if curr < len {
117 return param.key_at(curr);
118 } else {
119 curr -= len;
120 }
121 }
122 None
123 }
124 }
125 }
126
127 #[allow(dead_code)]
128 pub fn at(&self, index: usize) -> Option<(&str, &OnionObject)> {
129 match self {
130 LambdaParameter::Single((key, obj)) => {
131 if index == 0 {
132 Some((key, obj))
133 } else {
134 None
135 }
136 }
137 LambdaParameter::Multiple(params) => {
138 let mut curr = index;
139 for param in params {
140 let len = param.len();
141 if curr < len {
142 return param.at(curr);
143 } else {
144 curr -= len;
145 }
146 }
147 None
148 }
149 }
150 }
151
152 pub fn to_onion(&self) -> OnionStaticObject {
154 fn inner(param: &LambdaParameter) -> OnionObject {
155 match param {
156 LambdaParameter::Single((key, obj)) => OnionObject::Pair(
157 OnionPair::new(OnionObject::String(key.clone().into()), obj.clone()).into(),
158 ),
159 LambdaParameter::Multiple(params) => {
160 let mut pairs = vec![];
161 for param in params {
162 pairs.push(inner(param));
163 }
164 OnionObject::Tuple(OnionTuple::new(pairs).into())
165 }
166 }
167 }
168 inner(self).consume_and_stabilize()
169 }
170
171 pub fn from_onion(obj: &OnionObject) -> Result<LambdaParameter, RuntimeError> {
172 fn inner(obj: &OnionObject) -> Result<LambdaParameter, RuntimeError> {
173 match obj {
174 OnionObject::Pair(pair) => {
175 let key = match pair.get_key() {
176 OnionObject::String(s) => s.as_ref(),
177 _ => {
178 return Err(RuntimeError::InvalidType(
179 format!("Expected string key, found: {:?}", obj).into(),
180 ));
181 }
182 };
183 let value = pair.get_value();
184 Ok(LambdaParameter::Single((key.into(), value.clone())))
185 }
186 OnionObject::Tuple(tuple) => {
187 let mut params = Vec::with_capacity(tuple.get_elements().len());
188 for item in tuple.get_elements().iter() {
189 params.push(inner(item)?);
190 }
191 Ok(LambdaParameter::Multiple(params.into_boxed_slice()))
192 }
193 OnionObject::String(s) => {
194 Ok(LambdaParameter::Single((
196 Box::from(s.as_ref()),
197 OnionObject::Boolean(true),
198 )))
199 }
200 _ => Err(RuntimeError::InvalidType(
201 format!("Expected one of pair, tuple, or string, found: {:?}", obj).into(),
202 )),
203 }
204 }
205 inner(obj)
206 }
207}
208
209impl LambdaParameter {
210 pub fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
211 match self {
212 Self::Single((_, v)) => v.upgrade(collected),
213 Self::Multiple(v) => v.iter().for_each(|e| e.upgrade(collected)),
214 }
215 }
216}
217
218impl LambdaParameter {
219 pub fn unpack_arguments(
220 &self,
221 argument: &OnionObject,
222 ) -> Result<Vec<OnionObject>, RuntimeError> {
223 let mut collected = Vec::with_capacity(self.len());
224
225 fn inner(
226 object: &OnionObject,
227 layer: &LambdaParameter,
228 collected: &mut Vec<OnionObject>,
229 ) -> Result<(), RuntimeError> {
230 match layer {
231 LambdaParameter::Single(_) => {
232 collected.push(object.clone());
234 Ok(())
235 }
236 LambdaParameter::Multiple(v) => {
237 object.with_data(|data| match data {
239 OnionObject::Tuple(tuple) => {
240 if tuple.get_elements().len() != v.len() {
241 return Err(RuntimeError::InvalidOperation(
242 "Arity Mismatch".into(),
243 ));
244 }
245 for (i, object) in tuple.get_elements().iter().enumerate() {
246 inner(object, &v[i], collected)?;
247 }
248 Ok(())
249 }
250 _ => Err(RuntimeError::InvalidType(
251 format!("Expected tuple, found: {:?}", data).into(),
252 )),
253 })
254 }
255 }
256 }
257
258 inner(argument, &self, &mut collected)?;
259 Ok(collected)
260 }
261}
262
263impl LambdaParameter {
264 pub fn flatten_keys(&self) -> Box<[Box<str>]> {
268 let mut keys = Vec::with_capacity(self.len());
269 fn inner(param: &LambdaParameter, collected_keys: &mut Vec<Box<str>>) {
270 match param {
271 LambdaParameter::Single((name, _)) => {
272 collected_keys.push(name.clone());
273 }
274 LambdaParameter::Multiple(params) => {
275 for sub_param in params {
276 inner(sub_param, collected_keys);
277 }
278 }
279 }
280 }
281 inner(self, &mut keys);
282 keys.into_boxed_slice()
283 }
284
285 pub fn flatten_constraints(&self) -> Box<[OnionObject]> {
290 let mut constraints = Vec::with_capacity(self.len());
291
292 fn inner(param: &LambdaParameter, collected_constraints: &mut Vec<OnionObject>) {
293 match param {
294 LambdaParameter::Single((_, constraint_obj)) => {
295 collected_constraints.push(constraint_obj.clone());
296 }
297 LambdaParameter::Multiple(params) => {
298 for sub_param in params {
299 inner(sub_param, collected_constraints);
300 }
301 }
302 }
303 }
304 inner(self, &mut constraints);
305 constraints.into_boxed_slice()
306 }
307}