Skip to main content

onion_frontend/parser/comptime/
mod.rs

1//! 编译时模块:提供 AST 与 Onion VM 对象间的双向转换和集成。
2//!
3//! 本模块实现了编译时 AST 节点的 VM 对象包装、绑定、以及相互转换机制。
4//! 主要类型 `OnionASTObject` 实现了 `OnionObjectExt` trait,使 AST 能在 VM 中以对象形式操作。
5//! 支持 AST <-> VM 对象的双向转换、序列化、运算符重载等。
6//!
7//! # 主要内容
8//! - `OnionASTObject`:AST 的 VM 对象包装器
9//! - AST 与 VM 基础类型(String/Boolean/Number/Tuple/Pair 等)的互转
10//! - 运算符重载(如 `<<` 用于替换子节点)
11//! - 子模块:`ast_bindings`(AST 构造绑定)、`native`(原生函数)、`solver`(求解器)
12//!
13//! # 用法示例
14//! ```ignore
15//! let ast_obj = OnionASTObject::new(ast_node);
16//! let vm_obj = OnionObject::Custom(Arc::new(ast_obj));
17//! let converted_back = OnionASTObject::from_onion(&vm_obj)?;
18//! ```
19
20pub mod ast_bindings;
21pub mod native;
22pub mod solver;
23use std::sync::Arc;
24
25use onion_vm::{
26    GCTraceable,
27    lambda::runnable::RuntimeError,
28    types::{
29        object::{OnionObject, OnionObjectCell, OnionObjectExt, OnionStaticObject},
30        tuple::OnionTuple,
31    },
32};
33
34use crate::parser::ast::{ASTNode, ASTNodeType};
35use base64::engine::Engine;
36
37/// AST 节点的 VM 对象包装器。
38///
39/// 将 AST 节点包装为 Onion VM 可操作的自定义对象,实现 VM 对象接口,
40/// 支持相等性比较、序列化、运算符重载、类型查询等。
41#[derive(Debug, Clone)]
42pub struct OnionASTObject {
43    ast: ASTNode,
44}
45
46impl GCTraceable<OnionObjectCell> for OnionASTObject {
47    fn collect(&self, _: &mut std::collections::VecDeque<onion_vm::GCArcWeak<OnionObjectCell>>) {}
48}
49
50impl OnionObjectExt for OnionASTObject {
51    fn as_any(&self) -> &dyn std::any::Any {
52        self
53    }
54
55    fn upgrade(&self, _: &mut Vec<onion_vm::GCArc<OnionObjectCell>>) {}
56
57    fn equals(&self, other: &OnionObject) -> Result<bool, RuntimeError> {
58        other.with_data(|data| match data {
59            OnionObject::Custom(data) => {
60                if let Some(ast_object) = data.as_any().downcast_ref::<OnionASTObject>() {
61                    Ok(self.ast == ast_object.ast)
62                } else {
63                    Ok(false)
64                }
65            }
66            _ => Ok(false),
67        })
68    }
69
70    fn key_of(&self) -> Result<OnionStaticObject, RuntimeError> {
71        // 获取一个移除了子节点的 AST 节点
72        let key_ast = ASTNode {
73            node_type: self.ast.node_type.clone(),
74            children: vec![],
75            source_location: self.ast.source_location.clone(),
76        };
77        Ok(OnionObject::Custom(Arc::new(OnionASTObject { ast: key_ast })).stabilize())
78    }
79
80    fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
81        // 获取 AST 的子节点列表
82        let children = self
83            .ast
84            .children
85            .iter()
86            .map(|child| OnionObject::Custom(Arc::new(OnionASTObject { ast: child.clone() })))
87            .collect::<Vec<_>>();
88        Ok(OnionObject::Tuple(OnionTuple::new(children).into()).stabilize())
89    }
90
91    fn len(&self) -> Result<OnionStaticObject, RuntimeError> {
92        Ok(OnionObject::Integer(self.ast.children.len() as i64).stabilize())
93    }
94
95    fn apply(&self, value: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
96        value.with_data(|data| match data {
97            OnionObject::Integer(i) => {
98                // 通过索引访问子节点
99                let index = if *i < 0 {
100                    return Err(RuntimeError::InvalidOperation(
101                        "Negative index is not allowed".into(),
102                    ));
103                } else {
104                    *i as usize
105                };
106
107                if index >= self.ast.children.len() {
108                    return Err(RuntimeError::InvalidOperation(
109                        format!(
110                            "Index {} out of bounds for AST children of length {}",
111                            index,
112                            self.ast.children.len()
113                        )
114                        .into(),
115                    ));
116                }
117
118                let child_ast = self.ast.children[index].clone();
119                Ok(OnionObject::Custom(Arc::new(OnionASTObject { ast: child_ast })).stabilize())
120            }
121            OnionObject::Pair(pair) => {
122                // 通过 Pair 替换指定索引的子节点
123                let index = pair.get_key().with_data(|key_data| match key_data {
124                    OnionObject::Integer(i) => {
125                        if *i < 0 {
126                            Err(RuntimeError::InvalidOperation(
127                                "Negative index is not allowed".into(),
128                            ))
129                        } else {
130                            Ok(*i as usize)
131                        }
132                    }
133                    _ => Err(RuntimeError::InvalidType(
134                        "Pair key must be an integer index".into()
135                    )),
136                })?;
137
138                if index >= self.ast.children.len() {
139                    return Err(RuntimeError::InvalidOperation(
140                        format!(
141                            "Index {} out of bounds for AST children of length {}",
142                            index,
143                            self.ast.children.len()
144                        )
145                        .into(),
146                    ));
147                }
148
149                // 将 Pair 的值转换为 AST 节点
150                let new_child_ast = OnionASTObject::from_onion(pair.get_value())?;
151
152                // 创建新的子节点列表,替换指定索引的节点
153                let mut new_children = self.ast.children.clone();
154                new_children[index] = new_child_ast;
155
156                // 创建新的 AST 对象
157                let new_ast = ASTNode {
158                    node_type: self.ast.node_type.clone(),
159                    source_location: self.ast.source_location.clone(),
160                    children: new_children,
161                };
162
163                Ok(OnionObject::Custom(Arc::new(OnionASTObject { ast: new_ast })).stabilize())
164            }
165            _ => Err(RuntimeError::InvalidType(
166                "Apply argument must be an integer (for access) or a pair (for replacement)".into()
167            )),
168        })
169    }
170
171    fn with_attribute(
172            &self,
173            key: &OnionObject,
174            f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
175        ) -> Result<(), RuntimeError> {
176        key.with_data(|key_data| match key_data {
177            OnionObject::String(attr_name) => {
178                match attr_name.as_ref() {
179                    "node_type" => {
180                        // 返回节点类型的字符串表示
181                        let type_name = match &self.ast.node_type {
182                            ASTNodeType::Null => "Null",
183                            ASTNodeType::Undefined => "Undefined",
184                            ASTNodeType::String(_) => "String",
185                            ASTNodeType::Boolean(_) => "Boolean",
186                            ASTNodeType::Number(_) => "Number",
187                            ASTNodeType::Base64(_) => "Base64",
188                            ASTNodeType::Variable(_) => "Variable",
189                            ASTNodeType::Required(_) => "Required",
190                            ASTNodeType::Let(_) => "Let",
191                            ASTNodeType::Frame => "Frame",
192                            ASTNodeType::Assign => "Assign",
193                            ASTNodeType::LambdaDef(_, _) => "LambdaDef",
194                            ASTNodeType::Expressions => "Expressions",
195                            ASTNodeType::Apply => "Apply",
196                            ASTNodeType::Operation(_) => "Operation",
197                            ASTNodeType::Tuple => "Tuple",
198                            ASTNodeType::AssumeTuple => "AssumeTuple",
199                            ASTNodeType::Pair => "Pair",
200                            ASTNodeType::GetAttr => "GetAttr",
201                            ASTNodeType::Return => "Return",
202                            ASTNodeType::If => "If",
203                            ASTNodeType::While => "While",
204                            ASTNodeType::Modifier(_) => "Modifier",
205                            ASTNodeType::Break => "Break",
206                            ASTNodeType::Continue => "Continue",
207                            ASTNodeType::Range => "Range",
208                            ASTNodeType::In => "In",
209                            ASTNodeType::Namespace(_) => "Namespace",
210                            ASTNodeType::LazySet => "Set",
211                            ASTNodeType::Map => "Map",
212                            ASTNodeType::Is => "Is",
213                            ASTNodeType::Raise => "Raise",
214                            ASTNodeType::Dynamic => "Dynamic",
215                            ASTNodeType::Static => "Static",
216                            ASTNodeType::Comptime => "Comptime",
217                        };
218                        let type_obj = OnionObject::String(type_name.into());
219                        f(&type_obj)
220                    },
221                    "has_data" => {
222                        // 返回是否携带数据
223                        let has_data = matches!(
224                            &self.ast.node_type,
225                            ASTNodeType::String(_) | ASTNodeType::Boolean(_) | ASTNodeType::Number(_) |
226                            ASTNodeType::Base64(_) | ASTNodeType::Variable(_) | ASTNodeType::Required(_) |
227                            ASTNodeType::Let(_) | ASTNodeType::LambdaDef(_, _) | ASTNodeType::Operation(_) |
228                            ASTNodeType::Modifier(_) | ASTNodeType::Namespace(_)
229                        );
230                        let has_data_obj = OnionObject::Boolean(has_data);
231                        f(&has_data_obj)
232                    },
233                    "data" => {
234                        // 返回节点类型携带的原始数据
235                        match &self.ast.node_type {
236                            ASTNodeType::String(s) => {
237                                let data_obj = OnionObject::String(s.clone().into());
238                                f(&data_obj)
239                            },
240                            ASTNodeType::Boolean(b) => {
241                                let data_obj = OnionObject::Boolean(*b);
242                                f(&data_obj)
243                            },
244                            ASTNodeType::Number(n) => {
245                                let data_obj = OnionObject::String(n.clone().into());
246                                f(&data_obj)
247                            },
248                            ASTNodeType::Base64(b64) => {
249                                let data_obj = OnionObject::String(b64.clone().into());
250                                f(&data_obj)
251                            },
252                            ASTNodeType::Variable(name) | ASTNodeType::Required(name) | 
253                            ASTNodeType::Let(name) | ASTNodeType::Namespace(name) => {
254                                let data_obj = OnionObject::String(name.clone().into());
255                                f(&data_obj)
256                            },
257                            ASTNodeType::LambdaDef(is_dyn, captures) => {
258                                // 返回一个包含 is_dyn 和 captures 的元组
259                                let captures_vec: Vec<OnionObject> = captures.iter()
260                                    .map(|s| OnionObject::String(s.clone().into()))
261                                    .collect();
262                                let captures_tuple = OnionObject::Tuple(OnionTuple::new(captures_vec).into());
263                                let data_tuple = OnionObject::Tuple(OnionTuple::new(vec![
264                                    OnionObject::Boolean(*is_dyn),
265                                    captures_tuple
266                                ]).into());
267                                f(&data_tuple)
268                            },
269                            ASTNodeType::Operation(op) => {
270                                let op_str = match op {
271                                    crate::parser::ast::ASTNodeOperation::Add => "+",
272                                    crate::parser::ast::ASTNodeOperation::Abs => "abs",
273                                    crate::parser::ast::ASTNodeOperation::Subtract => "-",
274                                    crate::parser::ast::ASTNodeOperation::Minus => "minus",
275                                    crate::parser::ast::ASTNodeOperation::Multiply => "*",
276                                    crate::parser::ast::ASTNodeOperation::Divide => "/",
277                                    crate::parser::ast::ASTNodeOperation::Modulus => "%",
278                                    crate::parser::ast::ASTNodeOperation::Power => "**",
279                                    crate::parser::ast::ASTNodeOperation::And => "and",
280                                    crate::parser::ast::ASTNodeOperation::Xor => "xor",
281                                    crate::parser::ast::ASTNodeOperation::Or => "or",
282                                    crate::parser::ast::ASTNodeOperation::Not => "not",
283                                    crate::parser::ast::ASTNodeOperation::Equal => "==",
284                                    crate::parser::ast::ASTNodeOperation::NotEqual => "!=",
285                                    crate::parser::ast::ASTNodeOperation::Greater => ">",
286                                    crate::parser::ast::ASTNodeOperation::Less => "<",
287                                    crate::parser::ast::ASTNodeOperation::GreaterEqual => ">=",
288                                    crate::parser::ast::ASTNodeOperation::LessEqual => "<=",
289                                    crate::parser::ast::ASTNodeOperation::LeftShift => "<<",
290                                    crate::parser::ast::ASTNodeOperation::RightShift => ">>",
291                                };
292                                let data_obj = OnionObject::String(op_str.into());
293                                f(&data_obj)
294                            },
295                            ASTNodeType::Modifier(mod_type) => {
296                                let mod_str = match mod_type {
297                                    crate::parser::ast::ASTNodeModifier::Mut => "mut",
298                                    crate::parser::ast::ASTNodeModifier::Const => "const",
299                                    crate::parser::ast::ASTNodeModifier::KeyOf => "keyof",
300                                    crate::parser::ast::ASTNodeModifier::ValueOf => "valueof",
301                                    crate::parser::ast::ASTNodeModifier::Assert => "assert",
302                                    crate::parser::ast::ASTNodeModifier::Import => "import",
303                                    crate::parser::ast::ASTNodeModifier::TypeOf => "typeof",
304                                    crate::parser::ast::ASTNodeModifier::LengthOf => "lengthof",
305                                    crate::parser::ast::ASTNodeModifier::Launch => "launch",
306                                    crate::parser::ast::ASTNodeModifier::Spawn => "spawn",
307                                    crate::parser::ast::ASTNodeModifier::Async => "async",
308                                    crate::parser::ast::ASTNodeModifier::Sync => "sync",
309                                    crate::parser::ast::ASTNodeModifier::Atomic => "atomic",
310                                };
311                                let data_obj = OnionObject::String(mod_str.into());
312                                f(&data_obj)
313                            },
314                            _ => {
315                                // 对于没有数据的节点类型,返回 null
316                                let null_obj = OnionObject::Null;
317                                f(&null_obj)
318                            }
319                        }
320                    },
321                    // 直接通过数据字段名访问
322                    "value" => {
323                        match &self.ast.node_type {
324                            ASTNodeType::String(s) | ASTNodeType::Number(s) | ASTNodeType::Base64(s) => {
325                                let value_obj = OnionObject::String(s.clone().into());
326                                f(&value_obj)
327                            },
328                            ASTNodeType::Boolean(b) => {
329                                let value_obj = OnionObject::Boolean(*b);
330                                f(&value_obj)
331                            },
332                            _ => Err(RuntimeError::InvalidOperation(
333                                "Attribute 'value' is only supported for String, Number, Base64, and Boolean node types".into()
334                            ))
335                        }
336                    },
337                    "name" => {
338                        match &self.ast.node_type {
339                            ASTNodeType::Variable(name) | ASTNodeType::Required(name) | 
340                            ASTNodeType::Let(name) | ASTNodeType::Namespace(name) => {
341                                let name_obj = OnionObject::String(name.clone().into());
342                                f(&name_obj)
343                            },
344                            _ => Err(RuntimeError::InvalidOperation(
345                                "Attribute 'name' is only supported for Variable, Required, Let, and Namespace node types".into()
346                            ))
347                        }
348                    },
349                    "op" => {
350                        match &self.ast.node_type {
351                            ASTNodeType::Operation(op) => {
352                                let op_str = match op {
353                                    crate::parser::ast::ASTNodeOperation::Add => "+",
354                                    crate::parser::ast::ASTNodeOperation::Abs => "abs",
355                                    crate::parser::ast::ASTNodeOperation::Subtract => "-",
356                                    crate::parser::ast::ASTNodeOperation::Minus => "minus",
357                                    crate::parser::ast::ASTNodeOperation::Multiply => "*",
358                                    crate::parser::ast::ASTNodeOperation::Divide => "/",
359                                    crate::parser::ast::ASTNodeOperation::Modulus => "%",
360                                    crate::parser::ast::ASTNodeOperation::Power => "**",
361                                    crate::parser::ast::ASTNodeOperation::And => "and",
362                                    crate::parser::ast::ASTNodeOperation::Xor => "xor",
363                                    crate::parser::ast::ASTNodeOperation::Or => "or",
364                                    crate::parser::ast::ASTNodeOperation::Not => "not",
365                                    crate::parser::ast::ASTNodeOperation::Equal => "==",
366                                    crate::parser::ast::ASTNodeOperation::NotEqual => "!=",
367                                    crate::parser::ast::ASTNodeOperation::Greater => ">",
368                                    crate::parser::ast::ASTNodeOperation::Less => "<",
369                                    crate::parser::ast::ASTNodeOperation::GreaterEqual => ">=",
370                                    crate::parser::ast::ASTNodeOperation::LessEqual => "<=",
371                                    crate::parser::ast::ASTNodeOperation::LeftShift => "<<",
372                                    crate::parser::ast::ASTNodeOperation::RightShift => ">>",
373                                };
374                                let op_obj = OnionObject::String(op_str.into());
375                                f(&op_obj)
376                            },
377                            _ => Err(RuntimeError::InvalidOperation(
378                                "Attribute 'op' is only supported for Operation node type".into()
379                            ))
380                        }
381                    },
382                    "modifier" => {
383                        match &self.ast.node_type {
384                            ASTNodeType::Modifier(mod_type) => {
385                                let mod_str = match mod_type {
386                                    crate::parser::ast::ASTNodeModifier::Mut => "mut",
387                                    crate::parser::ast::ASTNodeModifier::Const => "const",
388                                    crate::parser::ast::ASTNodeModifier::KeyOf => "keyof",
389                                    crate::parser::ast::ASTNodeModifier::ValueOf => "valueof",
390                                    crate::parser::ast::ASTNodeModifier::Assert => "assert",
391                                    crate::parser::ast::ASTNodeModifier::Import => "import",
392                                    crate::parser::ast::ASTNodeModifier::TypeOf => "typeof",
393                                    crate::parser::ast::ASTNodeModifier::LengthOf => "lengthof",
394                                    crate::parser::ast::ASTNodeModifier::Launch => "launch",
395                                    crate::parser::ast::ASTNodeModifier::Spawn => "spawn",
396                                    crate::parser::ast::ASTNodeModifier::Async => "async",
397                                    crate::parser::ast::ASTNodeModifier::Sync => "sync",
398                                    crate::parser::ast::ASTNodeModifier::Atomic => "atomic",
399                                };
400                                let mod_obj = OnionObject::String(mod_str.into());
401                                f(&mod_obj)
402                            },
403                            _ => Err(RuntimeError::InvalidOperation(
404                                "Attribute 'modifier' is only supported for Modifier node type".into()
405                            ))
406                        }
407                    },
408                    "is_dyn" | "dyn" => {
409                        match &self.ast.node_type {
410                            ASTNodeType::LambdaDef(is_dyn, _) => {
411                                let dyn_obj = OnionObject::Boolean(*is_dyn);
412                                f(&dyn_obj)
413                            },
414                            _ => Err(RuntimeError::InvalidOperation(
415                                "Attribute 'is_dyn'/'dyn' is only supported for LambdaDef node type".into()
416                            ))
417                        }
418                    },
419                    "captures" => {
420                        match &self.ast.node_type {
421                            ASTNodeType::LambdaDef(_, captures) => {
422                                let captures_vec: Vec<OnionObject> = captures.iter()
423                                    .map(|s| OnionObject::String(s.clone().into()))
424                                    .collect();
425                                let captures_obj = OnionObject::Tuple(OnionTuple::new(captures_vec).into());
426                                f(&captures_obj)
427                            },
428                            _ => Err(RuntimeError::InvalidOperation(
429                                "Attribute 'captures' is only supported for LambdaDef node type".into()
430                            ))
431                        }
432                    },
433                    _ => Err(RuntimeError::InvalidOperation(
434                        format!("Unknown attribute '{}'. Available attributes: node_type, has_data, data, value (for String/Number/Base64/Boolean), name (for Variable/Required/Let/Namespace), op (for Operation), modifier (for Modifier), is_dyn/dyn (for LambdaDef), captures (for LambdaDef)", attr_name).into()
435                    ))
436                }
437            },
438            _ => Err(RuntimeError::InvalidType(
439                "Attribute key must be a string".into()
440            ))
441        })
442    }
443
444    fn type_of(&self) -> Result<String, RuntimeError> {
445        Ok("OnionASTObject".to_string())
446    }
447
448    fn to_string(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
449        Ok(format!("OnionASTObject: {:?}", self.ast))
450    }
451    fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
452        Ok(format!("OnionASTObject: {:?}", self.ast))
453    }
454
455    fn binary_shl(&self, other: &OnionObject) -> Result<OnionStaticObject, RuntimeError> {
456        // self << tuple 用来将自身的元组替换成另一个
457        other.with_data(|data| match data {
458            OnionObject::Tuple(tuple) => {
459                let mut children = vec![];
460                for elem in tuple.get_elements() {
461                    children.push(OnionASTObject::from_onion(elem)?);
462                }
463                let new_ast = ASTNode {
464                    node_type: self.ast.node_type.clone(),
465                    source_location: self.ast.source_location.clone(),
466                    children,
467                };
468                Ok(OnionObject::Custom(Arc::new(OnionASTObject { ast: new_ast })).stabilize())
469            }
470            _ => Err(RuntimeError::InvalidType(
471                "Expected a tuple for binary shift left".into(),
472            )),
473        })
474    }
475}
476
477impl OnionASTObject {
478    /// 创建新的 AST 对象包装器。
479    pub fn new(ast: ASTNode) -> Self {
480        Self { ast }
481    }
482
483    /// 将 Onion VM 对象转换为 AST 节点。
484    ///
485    /// # 参数
486    /// - `object`:VM 对象引用。
487    ///
488    /// # 返回
489    /// 转换后的 AST 节点,或运行时错误。
490    ///
491    /// # 支持的类型
492    /// - Custom(OnionASTObject):直接提取 AST
493    /// - Boolean/String/Bytes/Float/Integer/Null/Undefined:转为对应字面量节点
494    /// - Tuple:转为 Tuple 节点(递归转换子元素)
495    /// - Range:转为 Range 节点
496    /// - Pair:转为 Pair 节点
497    pub fn from_onion(object: &OnionObject) -> Result<ASTNode, RuntimeError> {
498        match object {
499            OnionObject::Custom(ast_object) => {
500                if let Some(ast_object) = ast_object.as_any().downcast_ref::<OnionASTObject>() {
501                    Ok(ast_object.ast.clone())
502                } else {
503                    Err(RuntimeError::InvalidType(
504                        format!(
505                            "Unsupported OnionObject type for AST conversion: {:?}",
506                            object
507                        )
508                        .into(),
509                    ))
510                }
511            }
512            OnionObject::Mut(_) => Err(RuntimeError::InvalidOperation(
513                ("Mutable objects may introduce cyclic references, ".to_owned()
514                    + "which cannot be safely or deterministically converted to AST objects")
515                    .into(),
516            )),
517            OnionObject::Boolean(v) => Ok(ASTNode {
518                node_type: ASTNodeType::Boolean(*v),
519                source_location: None,
520                children: vec![],
521            }),
522            OnionObject::String(s) => Ok(ASTNode {
523                node_type: ASTNodeType::String(s.as_ref().into()),
524                source_location: None,
525                children: vec![],
526            }),
527            OnionObject::Bytes(b) => {
528                let b64 = base64::engine::general_purpose::STANDARD.encode(b);
529                Ok(ASTNode {
530                    node_type: ASTNodeType::Base64(b64),
531                    source_location: None,
532                    children: vec![],
533                })
534            }
535            OnionObject::Float(f) => Ok(ASTNode {
536                node_type: ASTNodeType::Number(f.to_string()),
537                source_location: None,
538                children: vec![],
539            }),
540            OnionObject::Integer(i) => Ok(ASTNode {
541                node_type: ASTNodeType::Number(i.to_string()),
542                source_location: None,
543                children: vec![],
544            }),
545            OnionObject::Null => Ok(ASTNode {
546                node_type: ASTNodeType::Null,
547                source_location: None,
548                children: vec![],
549            }),
550            OnionObject::Undefined(_) => Ok(ASTNode {
551                node_type: ASTNodeType::Undefined,
552                source_location: None,
553                children: vec![],
554            }),
555            OnionObject::Tuple(tuple) => {
556                let children = tuple
557                    .get_elements()
558                    .iter()
559                    .map(|elem| OnionASTObject::from_onion(elem))
560                    .collect::<Result<Vec<_>, _>>()?;
561                Ok(ASTNode {
562                    node_type: ASTNodeType::Tuple,
563                    source_location: None,
564                    children,
565                })
566            }
567            OnionObject::Range(start, end) => Ok(ASTNode {
568                node_type: ASTNodeType::Range,
569                source_location: None,
570                children: vec![
571                    ASTNode {
572                        node_type: ASTNodeType::Number(start.to_string()),
573                        source_location: None,
574                        children: vec![],
575                    },
576                    ASTNode {
577                        node_type: ASTNodeType::Number(end.to_string()),
578                        source_location: None,
579                        children: vec![],
580                    },
581                ],
582            }),
583            OnionObject::Pair(pair) => {
584                let left = OnionASTObject::from_onion(pair.get_key())?;
585                let right = OnionASTObject::from_onion(pair.get_value())?;
586                Ok(ASTNode {
587                    node_type: ASTNodeType::Pair,
588                    source_location: None,
589                    children: vec![left, right],
590                })
591            }
592            v => Err(RuntimeError::InvalidType(
593                format!("Unsupported OnionObject type for AST conversion: {:?}", v).into(),
594            )),
595        }
596    }
597}