use std::collections::HashMap;
use std::rc::Rc;
use crate::code::{CallProtocol, CallableRef};
use crate::value::Value;
use crate::var::Variable;
use super::*;
pub const DEFAULT_LSTACK_SIZE: usize = 256;
pub const DEFAULT_VSTACK_SIZE: usize = 256;
#[derive(Debug)]
pub struct Context {
pub(super) entry: Option<Rc<dyn CallProtocol>>,
pub(super) globals: HashMap<String, Value>,
pub(super) scope: HashMap<Variable, CallableRef>,
pub(super) lstack: Vec<Frame>,
pub(super) vstack: Vec<Value>,
}
impl Context {
pub fn new() -> Self {
Self {
entry: None,
globals: HashMap::new(),
scope: HashMap::new(),
lstack: Vec::with_capacity(DEFAULT_LSTACK_SIZE),
vstack: Vec::with_capacity(DEFAULT_VSTACK_SIZE),
}
}
pub fn lookup_code_object(&self, name: &Variable) -> Lovm2Result<CallableRef> {
self.scope
.get(name)
.cloned()
.ok_or_else(|| (Lovm2ErrorTy::LookupFailed, name).into())
}
pub fn stack_mut(&mut self) -> &mut Vec<Value> {
&mut self.vstack
}
pub fn lstack_mut(&mut self) -> &mut Vec<Frame> {
&mut self.lstack
}
pub fn frame_mut(&mut self) -> Lovm2Result<&mut Frame> {
self.lstack
.last_mut()
.ok_or_else(|| Lovm2ErrorTy::FrameStackEmpty.into())
}
pub fn set_global<T>(&mut self, var: T, val: Value)
where
T: AsRef<str>,
{
self.globals.insert(var.as_ref().to_string(), val);
}
pub fn push_frame(&mut self, argn: u8) {
self.lstack.push(Frame::new(argn));
}
pub fn pop_frame(&mut self) {
self.lstack.pop();
}
pub fn push_value(&mut self, value: Value) {
self.vstack.push(value);
}
pub fn pop_value(&mut self) -> Lovm2Result<Value> {
self.vstack
.pop()
.ok_or_else(|| Lovm2ErrorTy::ValueStackEmpty.into())
}
pub fn last_value_mut(&mut self) -> Lovm2Result<&mut Value> {
self.vstack
.last_mut()
.ok_or_else(|| Lovm2ErrorTy::ValueStackEmpty.into())
}
pub fn value_of<T>(&self, var: T) -> Lovm2Result<&Value>
where
T: AsRef<str>,
{
self.globals
.get(var.as_ref())
.ok_or_else(|| (Lovm2ErrorTy::LookupFailed, var).into())
}
}