use glyph_types::Value;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Frame {
pub function_idx: usize,
pub ip: usize,
pub bp: usize,
pub locals: HashMap<String, Value>,
pub return_ip: Option<usize>,
pub return_function: Option<usize>,
}
impl Frame {
pub fn new(function_idx: usize, bp: usize) -> Self {
Frame {
function_idx,
ip: 0,
bp,
locals: HashMap::new(),
return_ip: None,
return_function: None,
}
}
pub fn with_return(
function_idx: usize,
bp: usize,
return_ip: usize,
return_function: usize,
) -> Self {
Frame {
function_idx,
ip: 0,
bp,
locals: HashMap::new(),
return_ip: Some(return_ip),
return_function: Some(return_function),
}
}
pub fn set_local(&mut self, name: String, value: Value) {
self.locals.insert(name, value);
}
pub fn get_local(&self, name: &str) -> Option<&Value> {
self.locals.get(name)
}
pub fn is_tail_position(
&self,
next_instruction: Option<&crate::instruction::Instruction>,
) -> bool {
matches!(
next_instruction,
Some(crate::instruction::Instruction::Return)
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_frame_creation() {
let frame = Frame::new(0, 10);
assert_eq!(frame.function_idx, 0);
assert_eq!(frame.ip, 0);
assert_eq!(frame.bp, 10);
assert!(frame.locals.is_empty());
assert!(frame.return_ip.is_none());
assert!(frame.return_function.is_none());
}
#[test]
fn test_frame_with_return() {
let frame = Frame::with_return(1, 20, 15, 0);
assert_eq!(frame.function_idx, 1);
assert_eq!(frame.bp, 20);
assert_eq!(frame.return_ip, Some(15));
assert_eq!(frame.return_function, Some(0));
}
#[test]
fn test_locals() {
let mut frame = Frame::new(0, 0);
frame.set_local("x".to_string(), Value::Int(42));
frame.set_local("y".to_string(), Value::Str("hello".to_string()));
assert_eq!(frame.get_local("x"), Some(&Value::Int(42)));
assert_eq!(frame.get_local("y"), Some(&Value::Str("hello".to_string())));
assert_eq!(frame.get_local("z"), None);
}
}