onion_vm/types/lambda/
context.rs

1use rustc_hash::FxHashMap as HashMap;
2use serde_json::{Map, Value};
3
4use crate::{lambda::runnable::RuntimeError, types::object::OnionStaticObject};
5
6#[derive(Clone, Debug)]
7pub struct Frame {
8    pub variables: HashMap<usize, OnionStaticObject>,
9    pub stack: Vec<OnionStaticObject>,
10}
11
12impl Frame {
13    #[inline(always)]
14    pub fn get_stack(&self) -> &Vec<OnionStaticObject> {
15        &self.stack
16    }
17    #[inline(always)]
18    pub fn get_stack_mut(&mut self) -> &mut Vec<OnionStaticObject> {
19        &mut self.stack
20    }
21
22    pub fn format_context(&self) -> Value {
23        let mut frame_obj = Map::new();
24
25        // Format variables
26        let mut variables = Map::new();
27        for (var_name, var_value) in &self.variables {
28            let value_str = var_value
29                .weak()
30                .to_string(&vec![])
31                .unwrap_or("Unknown value".into());
32            variables.insert(var_name.to_string(), Value::String(value_str));
33        }
34        frame_obj.insert("variables".to_string(), Value::Object(variables));
35
36        // Format stack
37        let stack_values: Vec<Value> = self
38            .stack
39            .iter()
40            .map(|obj| {
41                let obj_str = obj
42                    .weak()
43                    .to_string(&vec![])
44                    .unwrap_or("Unknown object".into());
45                Value::String(obj_str)
46            })
47            .collect();
48        frame_obj.insert("stack".to_string(), Value::Array(stack_values));
49
50        Value::Object(frame_obj)
51    }
52}
53
54#[derive(Clone)]
55pub struct Context {
56    pub(crate) frames: Vec<Frame>,
57}
58
59impl Context {
60    pub fn new() -> Self {
61        Context { frames: Vec::new() }
62    }
63
64    pub fn push_frame(&mut self, frame: Frame) {
65        self.frames.push(frame);
66    }
67
68    pub fn pop_frame(&mut self) -> Result<Frame, RuntimeError> {
69        match self.frames.pop() {
70            Some(frame) => Ok(frame),
71            None => Err(RuntimeError::DetailedError(
72                "Cannot pop frame from empty context".to_string().into(),
73            )),
74        }
75    }
76    pub fn concat_last_frame(&mut self) -> Result<(), RuntimeError> {
77        if self.frames.len() < 2 {
78            return Ok(());
79        }
80
81        let last_frame = self.frames.pop().unwrap();
82        let second_last_frame = self.frames.last_mut().unwrap();
83        second_last_frame.stack.extend(last_frame.stack);
84        Ok(())
85    }
86    pub fn clear_stack(&mut self) {
87        if self.frames.len() > 0 {
88            self.frames.last_mut().unwrap().stack.clear();
89        }
90    }
91
92    pub fn push_object(&mut self, object: OnionStaticObject) -> Result<(), RuntimeError> {
93        if self.frames.len() == 0 {
94            return Err(RuntimeError::DetailedError(
95                "Cannot push object to empty context".to_string().into(),
96            ));
97        }
98        self.frames.last_mut().unwrap().stack.push(object);
99        Ok(())
100    }
101
102    pub fn pop(&mut self) -> Result<OnionStaticObject, RuntimeError> {
103        if self.frames.len() == 0 {
104            return Err(RuntimeError::DetailedError(
105                "Cannot pop object from empty context".to_string().into(),
106            ));
107        }
108        let last_frame = self.frames.last_mut().unwrap();
109        if last_frame.get_stack().len() == 0 {
110            return Err(RuntimeError::DetailedError(
111                "Cannot pop object from empty stack".to_string().into(),
112            ));
113        }
114        let stack = last_frame.get_stack_mut();
115        Ok(stack.pop().unwrap())
116    }
117
118    pub fn discard_objects(&mut self, count: usize) -> Result<(), RuntimeError> {
119        if self.frames.len() == 0 {
120            return Err(RuntimeError::DetailedError(
121                "Cannot discard objects from empty context"
122                    .to_string()
123                    .into(),
124            ));
125        }
126        let last_frame = self.frames.last_mut().unwrap();
127        let stack = last_frame.get_stack_mut();
128        if stack.len() < count {
129            return Err(RuntimeError::DetailedError(
130                "Cannot discard more objects than available in stack"
131                    .to_string()
132                    .into(),
133            ));
134        }
135        // for _ in 0..count {
136        //     stack.pop();
137        // }
138        stack.truncate(stack.len() - count);
139        Ok(())
140    }
141
142    pub fn discard_objects_offset(
143        &mut self,
144        offset: usize,
145        count: usize,
146    ) -> Result<(), RuntimeError> {
147        if self.frames.len() == 0 {
148            return Err(RuntimeError::DetailedError(
149                "Cannot discard objects from empty context"
150                    .to_string()
151                    .into(),
152            ));
153        }
154        let last_frame = self.frames.last_mut().unwrap();
155        let stack = last_frame.get_stack_mut();
156        if stack.len() < offset + count {
157            return Err(RuntimeError::DetailedError(
158                "Cannot discard more objects than available in stack"
159                    .to_string()
160                    .into(),
161            ));
162        }
163
164        // 使用 drain 一次性删除范围内的元素
165        let remove_start = stack.len() - offset - count;
166        let remove_end = stack.len() - offset;
167        stack.drain(remove_start..remove_end);
168        Ok(())
169    }
170
171    pub fn get_object_rev(&self, idx: usize) -> Result<&OnionStaticObject, RuntimeError> {
172        if self.frames.len() == 0 {
173            return Err(RuntimeError::DetailedError(
174                "Cannot get object from empty context".to_string().into(),
175            ));
176        }
177        let last_frame = self.frames.last().unwrap();
178        if last_frame.get_stack().len() <= idx {
179            return Err(RuntimeError::DetailedError(
180                "Cannot get object from empty stack".to_string().into(),
181            ));
182        }
183        let stack = last_frame.get_stack();
184        match stack.get(stack.len() - 1 - idx) {
185            None => Err(RuntimeError::DetailedError(
186                "Index out of bounds".to_string().into(),
187            )),
188            Some(o) => Ok(o),
189        }
190    }
191
192    pub fn get_object_rev_mut(
193        &mut self,
194        idx: usize,
195    ) -> Result<&mut OnionStaticObject, RuntimeError> {
196        if self.frames.len() == 0 {
197            return Err(RuntimeError::DetailedError(
198                "Cannot get object from empty context".to_string().into(),
199            ));
200        }
201        let last_frame = self.frames.last_mut().unwrap();
202        if last_frame.get_stack().len() <= idx {
203            return Err(RuntimeError::DetailedError(
204                "Cannot get object from empty stack".to_string().into(),
205            ));
206        }
207        let stack = last_frame.get_stack_mut();
208        let idx = stack.len() - 1 - idx;
209        match stack.get_mut(idx) {
210            None => Err(RuntimeError::DetailedError(
211                "Index out of bounds".to_string().into(),
212            )),
213            Some(o) => Ok(o),
214        }
215    }
216
217    // pub fn let_variable(
218    //     &mut self,
219    //     name: String,
220    //     value: OnionStaticObject,
221    // ) -> Result<(), RuntimeError> {
222    //     if self.frames.len() == 0 {
223    //         return Err(RuntimeError::InvalidOperation(
224    //             "Cannot let variable in empty context".to_string(),
225    //         ));
226    //     }
227
228    //     let last_frame = self.frames.last_mut().unwrap();
229
230    //     match last_frame {
231    //         Frame::Normal(vars, _) => {
232    //             vars.insert(name, value);
233    //         }
234    //     }    //     Ok(())
235    // }
236
237    #[inline(always)]
238    pub fn let_variable(
239        &mut self,
240        name: usize,
241        value: OnionStaticObject,
242    ) -> Result<(), RuntimeError> {
243        if self.frames.len() == 0 {
244            return Err(RuntimeError::InvalidOperation(
245                "Cannot let variable in empty context".to_string().into(),
246            ));
247        }
248
249        let last_frame = self.frames.last_mut().unwrap();
250        last_frame.variables.insert(name, value);
251        Ok(())
252    }
253
254    // pub fn get_variable(&self, name: &String) -> Result<&OnionStaticObject, RuntimeError> {
255    //     if self.frames.len() == 0 {
256    //         return Err(RuntimeError::DetailedError(
257    //             "Cannot get variable from empty context".to_string(),
258    //         ));
259    //     }
260
261    //     // 反向遍历所有帧,从最新的帧开始查找
262    //     for frame in self.frames.iter().rev() {
263    //         match frame {
264    //             Frame::Normal(vars, _) => {
265    //                 if let Some(value) = vars.get(name) {
266    //                     return Ok(value);
267    //                 }
268    //             }
269    //         }
270    //     }
271
272    //     Err(RuntimeError::DetailedError(format!(
273    //         "Variable `{}` not found",
274    //         name
275    //     )))
276    // }
277
278    #[inline(always)]
279    pub fn get_variable(&self, name: usize) -> Option<&OnionStaticObject> {
280        if self.frames.len() == 0 {
281            return None;
282        } // 反向遍历所有帧,从最新的帧开始查找
283        for frame in self.frames.iter().rev() {
284            if let Some(value) = frame.variables.get(&name) {
285                return Some(value);
286            }
287        }
288        None
289    }
290
291    fn _debug_print(&self) {
292        println!("Context Debug Print:");
293        for (i, frame) in self.frames.iter().enumerate() {
294            println!("Frame {}: {:?}", i, frame);
295        }
296    }
297
298    // pub fn get_variable_mut(
299    //     &mut self,
300    //     name: &String,
301    // ) -> Result<&mut OnionStaticObject, RuntimeError> {
302    //     if self.frames.len() == 0 {
303    //         return Err(RuntimeError::DetailedError(
304    //             "Cannot get variable from empty context".to_string(),
305    //         ));
306    //     }
307
308    //     // 反向遍历所有帧,从最新的帧开始查找
309    //     for frame in self.frames.iter_mut().rev() {
310    //         match frame {
311    //             Frame::Normal(vars, _) => {
312    //                 if let Some(value) = vars.get_mut(name) {
313    //                     return Ok(value);
314    //                 }
315    //             }
316    //         }
317    //     }
318
319    //     Err(RuntimeError::DetailedError(format!(
320    //         "Variable `{}` not found",
321    //         name
322    //     )))
323    // }
324
325    pub fn get_variable_mut(&mut self, name: usize) -> Option<&mut OnionStaticObject> {
326        if self.frames.len() == 0 {
327            return None;
328        } // 反向遍历所有帧,从最新的帧开始查找
329        for frame in self.frames.iter_mut().rev() {
330            if let Some(value) = frame.variables.get_mut(&name) {
331                return Some(value);
332            }
333        }
334        None
335    }
336
337    pub fn swap(&mut self, idx1: usize, idx2: usize) -> Result<(), RuntimeError> {
338        if self.frames.len() == 0 {
339            return Err(RuntimeError::DetailedError(
340                "Cannot swap objects in empty context".to_string().into(),
341            ));
342        }
343        let last_frame = self.frames.last_mut().unwrap();
344        let stack = last_frame.get_stack_mut();
345        if stack.len() <= idx1 || stack.len() <= idx2 {
346            return Err(RuntimeError::DetailedError(
347                "Cannot swap objects in empty stack".to_string().into(),
348            ));
349        }
350        let len = stack.len();
351        stack.swap(len - 1 - idx1, len - 1 - idx2);
352        Ok(())
353    }
354
355    pub fn get_current_stack_mut(&mut self) -> Result<&mut Vec<OnionStaticObject>, RuntimeError> {
356        if self.frames.len() == 0 {
357            return Err(RuntimeError::DetailedError(
358                "Cannot get stack from empty context".to_string().into(),
359            ));
360        }
361        let last_frame = self.frames.last_mut().unwrap();
362        Ok(last_frame.get_stack_mut())
363    }
364
365    #[inline(always)]
366    pub fn push_to_stack(stack: &mut Vec<OnionStaticObject>, object: OnionStaticObject) {
367        stack.push(object);
368    }
369
370    pub fn pop_from_stack(
371        stack: &mut Vec<OnionStaticObject>,
372    ) -> Result<OnionStaticObject, RuntimeError> {
373        if stack.is_empty() {
374            return Err(RuntimeError::DetailedError(
375                "Cannot pop from empty stack".to_string().into(),
376            ));
377        }
378        Ok(stack.pop().unwrap())
379    }
380
381    #[inline(always)]
382    pub fn discard_from_stack(
383        stack: &mut Vec<OnionStaticObject>,
384        count: usize,
385    ) -> Result<(), RuntimeError> {
386        if stack.len() < count {
387            return Err(RuntimeError::DetailedError(
388                "Cannot discard more objects than available in stack"
389                    .to_string()
390                    .into(),
391            ));
392        }
393        stack.truncate(stack.len() - count);
394        Ok(())
395    }
396
397    #[inline(always)]
398    pub fn get_object_from_stack(
399        stack: &Vec<OnionStaticObject>,
400        idx: usize,
401    ) -> Result<&OnionStaticObject, RuntimeError> {
402        if stack.len() <= idx {
403            return Err(RuntimeError::DetailedError(
404                "Index out of bounds".to_string().into(),
405            ));
406        }
407        Ok(&stack[stack.len() - 1 - idx])
408    }
409
410    pub fn replace_last_object(stack: &mut Vec<OnionStaticObject>, object: OnionStaticObject) {
411        let last_index = stack.len() - 1;
412        stack[last_index] = object;
413    }
414}
415
416impl Context {
417    pub fn format_to_json(&self) -> Value {
418        let mut frames = Map::new();
419
420        for (i, frame) in self.frames.iter().enumerate() {
421            let mut frame_obj = Map::new();
422
423            // Format variables
424            let mut variables = Map::new();
425            for (var_name, var_value) in &frame.variables {
426                let value_str = var_value
427                    .weak()
428                    .to_string(&vec![])
429                    .unwrap_or("Unknown value".into());
430
431                variables.insert(var_name.to_string(), Value::String(value_str));
432            }
433            frame_obj.insert("variables".to_string(), Value::Object(variables));
434
435            // Format stack
436            let stack_values: Vec<Value> = frame
437                .stack
438                .iter()
439                .map(|obj| {
440                    let obj_str = obj
441                        .weak()
442                        .to_string(&vec![])
443                        .unwrap_or("Unknown value".into());
444                    Value::String(obj_str)
445                })
446                .collect();
447            frame_obj.insert("stack".to_string(), Value::Array(stack_values));
448
449            frames.insert(format!("frame_{}", i), Value::Object(frame_obj));
450        }
451
452        Value::Object(frames)
453    }
454}