use std::collections::HashMap;
use std::rc::Rc;
use crate::block::Block;
use crate::class::Class;
use crate::interner::Interned;
use crate::value::Value;
use crate::SOMRef;
#[derive(Debug, Clone)]
pub enum FrameKind {
Block {
block: Rc<Block>,
},
Method {
holder: SOMRef<Class>,
signature: Interned,
self_value: Value,
},
}
#[derive(Debug)]
pub struct Frame {
pub kind: FrameKind,
pub bindings: HashMap<String, Value>,
}
impl Frame {
pub fn from_kind(kind: FrameKind) -> Self {
Self {
kind,
bindings: HashMap::new(),
}
}
pub fn kind(&self) -> &FrameKind {
&self.kind
}
pub fn get_self(&self) -> Value {
match &self.kind {
FrameKind::Method { self_value, .. } => self_value.clone(),
FrameKind::Block { block, .. } => block.frame.borrow().get_self(),
}
}
pub fn get_method_holder(&self) -> SOMRef<Class> {
match &self.kind {
FrameKind::Method { holder, .. } => holder.clone(),
FrameKind::Block { block, .. } => block.frame.borrow().get_method_holder(),
}
}
pub fn get_method_signature(&self) -> Interned {
match &self.kind {
FrameKind::Method { signature, .. } => *signature,
FrameKind::Block { block, .. } => block.frame.borrow().get_method_signature(),
}
}
pub fn lookup_local(&self, name: impl AsRef<str>) -> Option<Value> {
let name = name.as_ref();
if let Some(value) = self.bindings.get(name).cloned() {
return Some(value);
}
match &self.kind {
FrameKind::Method {
self_value, holder, ..
} => {
if holder.borrow().is_static {
holder.borrow().lookup_local(name)
} else {
self_value.lookup_local(name)
}
}
FrameKind::Block { block, .. } => block.frame.borrow().lookup_local(name),
}
}
pub fn assign_local(&mut self, name: impl AsRef<str>, value: Value) -> Option<()> {
let name = name.as_ref();
if let Some(local) = self.bindings.get_mut(name) {
*local = value;
return Some(());
}
match &mut self.kind {
FrameKind::Method {
self_value, holder, ..
} => {
if holder.borrow().is_static {
holder.borrow_mut().assign_local(name, value)
} else {
self_value.assign_local(name, value)
}
}
FrameKind::Block { block, .. } => block.frame.borrow_mut().assign_local(name, value),
}
}
pub fn method_frame(frame: &SOMRef<Frame>) -> SOMRef<Frame> {
match frame.borrow().kind() {
FrameKind::Block { block, .. } => Frame::method_frame(&block.frame),
FrameKind::Method { .. } => frame.clone(),
}
}
}