onion_vm/types/lambda/
context.rs

1use rustc_hash::FxHashMap as HashMap;
2
3use crate::{
4    lambda::runnable::RuntimeError,
5    types::{
6        lambda::vm_instructions::instruction_set::VMInstructionPackage, object::OnionStaticObject,
7    },
8    utils::format_object_summary,
9};
10
11#[derive(Clone, Debug)]
12pub struct Frame {
13    pub variables: HashMap<usize, OnionStaticObject>,
14    pub stack: Vec<OnionStaticObject>,
15}
16
17impl Frame {
18    #[inline(always)]
19    pub fn get_stack(&self) -> &Vec<OnionStaticObject> {
20        &self.stack
21    }
22    #[inline(always)]
23    pub fn get_stack_mut(&mut self) -> &mut Vec<OnionStaticObject> {
24        &mut self.stack
25    }
26
27    pub fn format_context(&self, package: &VMInstructionPackage) -> String {
28        let mut parts = Vec::new();
29        let string_pool = package.get_string_pool();
30
31        // --- Part 1: Format Variables ---
32        if self.variables.is_empty() {
33            parts.push("  - Variables: (none)".to_string());
34        } else {
35            parts.push("  - Variables:".to_string());
36            for (id, value) in &self.variables {
37                // [关键修改] 使用 id 从 string_pool 中查找变量名
38                let var_name = string_pool
39                    .get(*id)
40                    .map(|s| s.as_ref())
41                    .unwrap_or("<Unknown Var>");
42
43                let value_summary = format_object_summary(value.weak());
44                parts.push(format!("    - {}: {}", var_name, value_summary));
45            }
46        }
47
48        // --- Part 2: Format Operand Stack ---
49        if self.stack.is_empty() {
50            parts.push("  - Operand Stack: (empty)".to_string());
51        } else {
52            parts.push(format!("  - Operand Stack ({} items):", self.stack.len()));
53            for (i, value) in self.stack.iter().rev().enumerate() {
54                // [修改点] 在这里也使用辅助函数
55                let value_summary = format_object_summary(value.weak());
56                parts.push(format!("    - [Top - {}]: {}", i, value_summary));
57            }
58        }
59
60        parts.join("\n")
61    }
62}
63
64#[derive(Clone)]
65pub struct Context {
66    pub(crate) frames: Vec<Frame>,
67}
68
69impl Context {
70    pub fn new() -> Self {
71        Context { frames: Vec::new() }
72    }
73
74    pub fn push_frame(&mut self, frame: Frame) {
75        self.frames.push(frame);
76    }
77
78    pub fn pop_frame(&mut self) -> Result<Frame, RuntimeError> {
79        match self.frames.pop() {
80            Some(frame) => Ok(frame),
81            None => Err(RuntimeError::DetailedError(
82                "Cannot pop frame from empty context".into(),
83            )),
84        }
85    }
86    pub fn concat_last_frame(&mut self) -> Result<(), RuntimeError> {
87        if self.frames.len() < 2 {
88            return Ok(());
89        }
90
91        let last_frame = self.frames.pop().unwrap();
92        let second_last_frame = self.frames.last_mut().unwrap();
93        second_last_frame.stack.extend(last_frame.stack);
94        Ok(())
95    }
96    pub fn clear_stack(&mut self) {
97        if self.frames.len() > 0 {
98            self.frames.last_mut().unwrap().stack.clear();
99        }
100    }
101
102    pub fn push_object(&mut self, object: OnionStaticObject) -> Result<(), RuntimeError> {
103        if self.frames.len() == 0 {
104            return Err(RuntimeError::DetailedError(
105                "Cannot push object to empty context".into(),
106            ));
107        }
108        self.frames.last_mut().unwrap().stack.push(object);
109        Ok(())
110    }
111
112    pub fn pop(&mut self) -> Result<OnionStaticObject, RuntimeError> {
113        if self.frames.len() == 0 {
114            return Err(RuntimeError::DetailedError(
115                "Cannot pop object from empty context".into(),
116            ));
117        }
118        let last_frame = self.frames.last_mut().unwrap();
119        if last_frame.get_stack().len() == 0 {
120            return Err(RuntimeError::DetailedError(
121                "Cannot pop object from empty stack".into(),
122            ));
123        }
124        let stack = last_frame.get_stack_mut();
125        Ok(stack.pop().unwrap())
126    }
127
128    pub fn discard_objects(&mut self, count: usize) -> Result<(), RuntimeError> {
129        if self.frames.len() == 0 {
130            return Err(RuntimeError::DetailedError(
131                "Cannot discard objects from empty context"
132                    .to_string()
133                    .into(),
134            ));
135        }
136        let last_frame = self.frames.last_mut().unwrap();
137        let stack = last_frame.get_stack_mut();
138        if stack.len() < count {
139            return Err(RuntimeError::DetailedError(
140                "Cannot discard more objects than available in stack"
141                    .to_string()
142                    .into(),
143            ));
144        }
145        // for _ in 0..count {
146        //     stack.pop();
147        // }
148        stack.truncate(stack.len() - count);
149        Ok(())
150    }
151
152    pub fn discard_objects_offset(
153        &mut self,
154        offset: usize,
155        count: usize,
156    ) -> Result<(), RuntimeError> {
157        if self.frames.len() == 0 {
158            return Err(RuntimeError::DetailedError(
159                "Cannot discard objects from empty context"
160                    .to_string()
161                    .into(),
162            ));
163        }
164        let last_frame = self.frames.last_mut().unwrap();
165        let stack = last_frame.get_stack_mut();
166        if stack.len() < offset + count {
167            return Err(RuntimeError::DetailedError(
168                "Cannot discard more objects than available in stack"
169                    .to_string()
170                    .into(),
171            ));
172        }
173
174        // 使用 drain 一次性删除范围内的元素
175        let remove_start = stack.len() - offset - count;
176        let remove_end = stack.len() - offset;
177        stack.drain(remove_start..remove_end);
178        Ok(())
179    }
180
181    pub fn get_object_rev(&self, idx: usize) -> Result<&OnionStaticObject, RuntimeError> {
182        if self.frames.len() == 0 {
183            return Err(RuntimeError::DetailedError(
184                "Cannot get object from empty context".into(),
185            ));
186        }
187        let last_frame = self.frames.last().unwrap();
188        if last_frame.get_stack().len() <= idx {
189            return Err(RuntimeError::DetailedError(
190                "Cannot get object from empty stack".into(),
191            ));
192        }
193        let stack = last_frame.get_stack();
194        match stack.get(stack.len() - 1 - idx) {
195            None => Err(RuntimeError::DetailedError(
196                "Index out of bounds".into(),
197            )),
198            Some(o) => Ok(o),
199        }
200    }
201
202    pub fn get_object_rev_mut(
203        &mut self,
204        idx: usize,
205    ) -> Result<&mut OnionStaticObject, RuntimeError> {
206        if self.frames.len() == 0 {
207            return Err(RuntimeError::DetailedError(
208                "Cannot get object from empty context".into(),
209            ));
210        }
211        let last_frame = self.frames.last_mut().unwrap();
212        if last_frame.get_stack().len() <= idx {
213            return Err(RuntimeError::DetailedError(
214                "Cannot get object from empty stack".into(),
215            ));
216        }
217        let stack = last_frame.get_stack_mut();
218        let idx = stack.len() - 1 - idx;
219        match stack.get_mut(idx) {
220            None => Err(RuntimeError::DetailedError(
221                "Index out of bounds".into(),
222            )),
223            Some(o) => Ok(o),
224        }
225    }
226
227    #[inline(always)]
228    pub fn let_variable(
229        &mut self,
230        name: usize,
231        value: OnionStaticObject,
232    ) -> Result<(), RuntimeError> {
233        if self.frames.len() == 0 {
234            return Err(RuntimeError::InvalidOperation(
235                "Cannot let variable in empty context".into(),
236            ));
237        }
238
239        let last_frame = self.frames.last_mut().unwrap();
240        last_frame.variables.insert(name, value);
241        Ok(())
242    }
243
244    #[inline(always)]
245    pub fn get_variable(&self, name: usize) -> Option<&OnionStaticObject> {
246        if self.frames.len() == 0 {
247            return None;
248        } // 反向遍历所有帧,从最新的帧开始查找
249        for frame in self.frames.iter().rev() {
250            if let Some(value) = frame.variables.get(&name) {
251                return Some(value);
252            }
253        }
254        None
255    }
256
257    fn _debug_print(&self) {
258        println!("Context Debug Print:");
259        for (i, frame) in self.frames.iter().enumerate() {
260            println!("Frame {}: {:?}", i, frame);
261        }
262    }
263
264    pub fn get_variable_mut(&mut self, name: usize) -> Option<&mut OnionStaticObject> {
265        if self.frames.len() == 0 {
266            return None;
267        } // 反向遍历所有帧,从最新的帧开始查找
268        for frame in self.frames.iter_mut().rev() {
269            if let Some(value) = frame.variables.get_mut(&name) {
270                return Some(value);
271            }
272        }
273        None
274    }
275
276    pub fn swap(&mut self, idx1: usize, idx2: usize) -> Result<(), RuntimeError> {
277        if self.frames.len() == 0 {
278            return Err(RuntimeError::DetailedError(
279                "Cannot swap objects in empty context".into(),
280            ));
281        }
282        let last_frame = self.frames.last_mut().unwrap();
283        let stack = last_frame.get_stack_mut();
284        if stack.len() <= idx1 || stack.len() <= idx2 {
285            return Err(RuntimeError::DetailedError(
286                "Cannot swap objects in empty stack".into(),
287            ));
288        }
289        let len = stack.len();
290        stack.swap(len - 1 - idx1, len - 1 - idx2);
291        Ok(())
292    }
293
294    pub fn get_current_stack_mut(&mut self) -> Result<&mut Vec<OnionStaticObject>, RuntimeError> {
295        if self.frames.len() == 0 {
296            return Err(RuntimeError::DetailedError(
297                "Cannot get stack from empty context".into(),
298            ));
299        }
300        let last_frame = self.frames.last_mut().unwrap();
301        Ok(last_frame.get_stack_mut())
302    }
303
304    #[inline(always)]
305    pub fn push_to_stack(stack: &mut Vec<OnionStaticObject>, object: OnionStaticObject) {
306        stack.push(object);
307    }
308
309    pub fn pop_from_stack(
310        stack: &mut Vec<OnionStaticObject>,
311    ) -> Result<OnionStaticObject, RuntimeError> {
312        if stack.is_empty() {
313            return Err(RuntimeError::DetailedError(
314                "Cannot pop from empty stack".into(),
315            ));
316        }
317        Ok(stack.pop().unwrap())
318    }
319
320    #[inline(always)]
321    pub fn discard_from_stack(
322        stack: &mut Vec<OnionStaticObject>,
323        count: usize,
324    ) -> Result<(), RuntimeError> {
325        if stack.len() < count {
326            return Err(RuntimeError::DetailedError(
327                "Cannot discard more objects than available in stack"
328                    .to_string()
329                    .into(),
330            ));
331        }
332        stack.truncate(stack.len() - count);
333        Ok(())
334    }
335
336    #[inline(always)]
337    pub fn get_object_from_stack(
338        stack: &Vec<OnionStaticObject>,
339        idx: usize,
340    ) -> Result<&OnionStaticObject, RuntimeError> {
341        if stack.len() <= idx {
342            return Err(RuntimeError::DetailedError(
343                "Index out of bounds".into(),
344            ));
345        }
346        Ok(&stack[stack.len() - 1 - idx])
347    }
348
349    pub fn replace_last_object(stack: &mut Vec<OnionStaticObject>, object: OnionStaticObject) {
350        let last_index = stack.len() - 1;
351        stack[last_index] = object;
352    }
353
354    pub fn format_context(&self, package: &VMInstructionPackage) -> String {
355        if self.frames.is_empty() {
356            return "Context: (No active frames)".to_string();
357        }
358
359        let mut parts = Vec::new();
360        parts.push(format!("Call Stack ({} frames):", self.frames.len()));
361
362        // 从栈顶(最近的调用帧)开始打印
363        for (i, frame) in self.frames.iter().rev().enumerate() {
364            // 你需要一种方法来命名你的帧。这通常与函数名相关联。
365            // 暂时我们用索引代替。
366            parts.push(format!("--- Frame #{} (most recent) ---", i));
367
368            // 调用我们刚刚为 Frame 实现的 format_context
369            let frame_context = frame.format_context(package);
370            parts.push(frame_context);
371        }
372
373        parts.join("\n")
374    }
375}