1use glyph_types::Value;
2use std::collections::HashMap;
3
4#[derive(Debug, Clone)]
12pub struct Frame {
13 pub function_idx: usize,
15 pub ip: usize,
17 pub bp: usize,
19 pub locals: HashMap<String, Value>,
21 pub return_ip: Option<usize>,
23 pub return_function: Option<usize>,
25}
26
27impl Frame {
28 pub fn new(function_idx: usize, bp: usize) -> Self {
30 Frame {
31 function_idx,
32 ip: 0,
33 bp,
34 locals: HashMap::new(),
35 return_ip: None,
36 return_function: None,
37 }
38 }
39
40 pub fn with_return(
42 function_idx: usize,
43 bp: usize,
44 return_ip: usize,
45 return_function: usize,
46 ) -> Self {
47 Frame {
48 function_idx,
49 ip: 0,
50 bp,
51 locals: HashMap::new(),
52 return_ip: Some(return_ip),
53 return_function: Some(return_function),
54 }
55 }
56
57 pub fn set_local(&mut self, name: String, value: Value) {
59 self.locals.insert(name, value);
60 }
61
62 pub fn get_local(&self, name: &str) -> Option<&Value> {
64 self.locals.get(name)
65 }
66
67 pub fn is_tail_position(
70 &self,
71 next_instruction: Option<&crate::instruction::Instruction>,
72 ) -> bool {
73 matches!(
74 next_instruction,
75 Some(crate::instruction::Instruction::Return)
76 )
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_frame_creation() {
86 let frame = Frame::new(0, 10);
87 assert_eq!(frame.function_idx, 0);
88 assert_eq!(frame.ip, 0);
89 assert_eq!(frame.bp, 10);
90 assert!(frame.locals.is_empty());
91 assert!(frame.return_ip.is_none());
92 assert!(frame.return_function.is_none());
93 }
94
95 #[test]
96 fn test_frame_with_return() {
97 let frame = Frame::with_return(1, 20, 15, 0);
98 assert_eq!(frame.function_idx, 1);
99 assert_eq!(frame.bp, 20);
100 assert_eq!(frame.return_ip, Some(15));
101 assert_eq!(frame.return_function, Some(0));
102 }
103
104 #[test]
105 fn test_locals() {
106 let mut frame = Frame::new(0, 0);
107
108 frame.set_local("x".to_string(), Value::Int(42));
109 frame.set_local("y".to_string(), Value::Str("hello".to_string()));
110
111 assert_eq!(frame.get_local("x"), Some(&Value::Int(42)));
112 assert_eq!(frame.get_local("y"), Some(&Value::Str("hello".to_string())));
113 assert_eq!(frame.get_local("z"), None);
114 }
115}