onion_vm/types/lambda/
parameter.rs

1//! Lambda 参数定义与处理模块。
2//!
3//! 支持单参数和多参数的递归定义,提供参数约束、解包、扁平化等功能。
4//! 参数可以是简单的键值对,也可以是嵌套的参数结构。
5
6use 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/// Lambda 参数定义。
20///
21/// 支持单参数和多参数的递归结构:
22/// - `Single`: 单个参数,包含参数名和约束对象
23/// - `Multiple`: 多个参数,支持嵌套结构
24///
25/// # 示例
26/// ```ignore
27/// // 单参数: x : Int
28/// LambdaParameter::Single(("x".into(), OnionObject::Integer(0)))
29///
30/// // 多参数: (a : String, (b : Int, c : Bool))
31/// LambdaParameter::Multiple(box [
32///     LambdaParameter::Single(("a".into(), OnionObject::String(...))),
33///     LambdaParameter::Multiple(box [...])
34/// ])
35/// ```
36#[derive(Debug, Clone)]
37pub enum LambdaParameter {
38    /// 单个参数:(参数名, 约束对象)
39    Single((Box<str>, OnionObject)),
40    /// 多个参数:递归参数列表
41    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    /// 创建 top 参数(约束为 true,顶类型)。
85    pub fn top(key: &str) -> Self {
86        Self::Single((key.into(), OnionObject::Boolean(true)))
87    }
88
89    /// 创建 bottom 参数(约束为 false,底类型)。
90    pub fn bottom(key: &str) -> Self {
91        Self::Single((key.into(), OnionObject::Boolean(false)))
92    }
93}
94
95impl LambdaParameter {
96    /// 获取参数的总数量(扁平化后)。
97    ///
98    /// 递归计算所有嵌套参数的数量总和。
99    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    /// 按扁平化顺序获取指定索引的参数约束定义。
107    ///
108    /// # 参数
109    /// - `index`: 扁平化后的参数索引
110    ///
111    /// # 返回
112    /// - `Some(&OnionObject)`: 对应位置的约束对象
113    /// - `None`: 索引超出范围
114    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    /// 按扁平化顺序获取指定索引的参数名。
139    #[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    /// 按扁平化顺序获取指定索引的参数名和约束。
165    #[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    /// 将参数结构打包为 Onion 对象。
191    ///
192    /// - 单参数打包为 Pair 对象
193    /// - 多参数打包为 Tuple 对象,递归处理嵌套结构
194    ///
195    /// # 返回
196    /// 稳定化的 Onion 对象,可用于序列化或传输
197    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    /// 从 Onion 对象解析参数结构。
216    ///
217    /// 支持从 Pair、Tuple、String 等对象解析参数:
218    /// - Pair: 解析为单参数
219    /// - Tuple: 解析为多参数,递归处理
220    /// - String: 解析为简单参数(约束为 true)
221    ///
222    /// # 错误
223    /// 当对象格式不符合预期时返回 `RuntimeError::InvalidType`
224    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                    // 处理单个字符串参数
248                    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    /// 升级参数中的弱引用为强引用。
264    ///
265    /// 遍历参数结构,将所有对象的弱引用升级为强引用,
266    /// 防止在垃圾回收过程中被意外回收。
267    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    /// 根据参数结构解包实际参数。
277    ///
278    /// 将传入的参数对象按照当前参数结构进行解包:
279    /// - 单参数:直接接受任意对象
280    /// - 多参数:要求传入 Tuple,且元素数量匹配
281    ///
282    /// # 参数
283    /// - `argument`: 待解包的参数对象
284    ///
285    /// # 返回
286    /// 解包后的参数列表,按扁平化顺序排列
287    ///
288    /// # 错误
289    /// - `Arity Mismatch`: 参数数量不匹配
290    /// - `InvalidType`: 期望 Tuple 但传入其他类型
291    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                    // If expecting one param, the argument can be a single object.
305                    collected.push(object.clone());
306                    Ok(())
307                }
308                LambdaParameter::Multiple(v) => {
309                    // If expecting multiple, the argument must be a tuple.
310                    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    /// 递归扁平化参数结构,生成参数名列表。
337    ///
338    /// 将嵌套的参数结构展开为一维的参数名列表。
339    /// 例如:`(a, (b, c))` 会返回 `["a", "b", "c"]`。
340    ///
341    /// # 返回
342    /// 按深度优先顺序排列的参数名列表
343    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    /// 递归扁平化参数结构,生成约束对象列表。
362    ///
363    /// 将嵌套的参数结构展开为一维的约束对象列表。
364    /// 例如:`(a: Int, (b: String, c: Bool))` 会返回 `[Int, String, Bool]`。
365    ///
366    /// # 返回
367    /// 按深度优先顺序排列的约束对象列表
368    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}