automatically heapify captured variables

This commit is contained in:
Moritz Gmeiner 2024-09-01 23:15:36 +02:00
commit 8e847847a6
5 changed files with 136 additions and 40 deletions

View file

@ -37,7 +37,60 @@ impl HeapedValue {
} }
} }
pub type Scope = FxHashMap<Box<str>, HeapedValue>; #[derive(Debug, Clone)]
enum ScopedValue {
LocalValue(Value),
HeapedValue(HeapedValue),
}
impl ScopedValue {
fn new(value: Value) -> Self {
Self::LocalValue(value)
}
// fn new_heaped(value: Value) -> Self {
// Self::HeapedValue(HeapedValue::new(value))
// }
fn cloned(&self) -> Value {
match self {
ScopedValue::LocalValue(value) => value.clone(),
ScopedValue::HeapedValue(heaped_value) => heaped_value.cloned(),
}
}
fn replace(&mut self, new_value: Value) {
match self {
ScopedValue::LocalValue(value) => *value = new_value,
ScopedValue::HeapedValue(heaped_value) => heaped_value.replace(new_value),
}
}
/// Heapifies self and returns the HeapedValue, i.e. if self if already a HeapedValue returns
/// inner HeapedValue and if self is LocalValue turns self into a HeapedValue and returns that.
fn heapified(&mut self) -> HeapedValue {
match self {
ScopedValue::LocalValue(value) => {
let heaped_value = HeapedValue::new(std::mem::take(value));
*self = ScopedValue::HeapedValue(heaped_value.clone());
heaped_value
}
ScopedValue::HeapedValue(heaped_value) => heaped_value.clone(),
}
}
}
impl Display for ScopedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ScopedValue::LocalValue(value) => write!(f, "{value}"),
ScopedValue::HeapedValue(heaped_value) => write!(f, "{}", heaped_value.borrow()),
}
}
}
type Scope = FxHashMap<Box<str>, ScopedValue>;
pub type ClosureScope = FxHashMap<Box<str>, HeapedValue>;
#[derive(Debug)] #[derive(Debug)]
pub struct Environment<'a> { pub struct Environment<'a> {
@ -79,23 +132,23 @@ impl<'a> Environment<'a> {
self.runtime.globals() self.runtime.globals()
} }
pub fn scopes(&self) -> &[Scope] { fn scopes(&self) -> &[Scope] {
&self.scope_stack &self.scope_stack
} }
pub fn scopes_mut(&mut self) -> &mut [Scope] { fn scopes_mut(&mut self) -> &mut [Scope] {
&mut self.scope_stack &mut self.scope_stack
} }
pub fn has_scope(&self) -> bool { fn has_scope(&self) -> bool {
!self.scope_stack.is_empty() !self.scope_stack.is_empty()
} }
pub fn current_scope(&self) -> &Scope { /* fn current_scope(&self) -> &Scope {
self.scope_stack.last().unwrap() self.scope_stack.last().unwrap()
} } */
pub fn current_scope_mut(&mut self) -> &mut Scope { fn current_scope_mut(&mut self) -> &mut Scope {
self.scope_stack.last_mut().unwrap() self.scope_stack.last_mut().unwrap()
} }
@ -118,11 +171,11 @@ impl<'a> Environment<'a> {
self.scope_stack.pop(); self.scope_stack.pop();
} }
pub fn insert_closure(&mut self, closure: Scope) { pub fn insert_closure(&mut self, closure: ClosureScope) {
let scope = self.current_scope_mut(); let scope = self.current_scope_mut();
for (name, value) in closure { for (name, value) in closure {
scope.insert(name, value); scope.insert(name, ScopedValue::HeapedValue(value));
} }
} }
@ -130,7 +183,7 @@ impl<'a> Environment<'a> {
self.runtime.get_global(name) self.runtime.get_global(name)
} }
pub fn get_local(&'a self, name: &str, level: usize) -> Result<Value, RuntimeError> { pub fn get_local(&self, name: &str, level: usize) -> Result<Value, RuntimeError> {
let len = self.scopes().len(); let len = self.scopes().len();
if level < len { if level < len {
@ -139,16 +192,38 @@ impl<'a> Environment<'a> {
} }
} }
Err(RuntimeError::NameNotDefined { panic!("Name not defined not caught by resolver");
/* Err(RuntimeError::NameNotDefined {
name: name.to_owned(), name: name.to_owned(),
}) }) */
}
pub fn get_local_heaped(
&mut self,
name: &str,
level: usize,
) -> Result<HeapedValue, RuntimeError> {
if level < self.scopes().len() {
let scope = self.scopes_mut().iter_mut().rev().nth(level).unwrap();
if let Some(scoped_value) = scope.get_mut(name) {
return Ok(scoped_value.heapified());
}
}
panic!("Name not defined not caught by resolver");
/* Err(RuntimeError::NameNotDefined {
name: name.to_owned(),
}) */
} }
pub fn define(&mut self, name: impl Into<Box<str>>, value: Value) { pub fn define(&mut self, name: impl Into<Box<str>>, value: Value) {
if self.has_scope() { if self.has_scope() {
let name = name.into(); let name = name.into();
self.current_scope_mut() self.current_scope_mut()
.insert(name, HeapedValue::new(value)); .insert(name, ScopedValue::new(value));
} else { } else {
self.runtime.define_global(name, value) self.runtime.define_global(name, value)
} }
@ -171,8 +246,8 @@ impl<'a> Environment<'a> {
}) })
} }
pub fn collect_closure(&self, closure_vars: &[(Box<str>, usize)]) -> Scope { pub fn collect_closure(&mut self, closure_vars: &[(Box<str>, usize)]) -> ClosureScope {
let mut closure_scope = Scope::default(); let mut closure_scope = ClosureScope::default();
for (name, level) in closure_vars { for (name, level) in closure_vars {
// special injected variables // special injected variables
@ -180,15 +255,17 @@ impl<'a> Environment<'a> {
continue; continue;
} }
let heap_value = self // let heap_value = self
.scopes() // .scopes()
.iter() // .iter()
.rev() // .rev()
.nth(*level) // .nth(*level)
.expect("Closure variable got resolved to level that doesn't exist") // .expect("Closure variable got resolved to level that doesn't exist")
.get(name) // .get(name)
.expect("Closure variable was resolved, but could not be found") // .expect("Closure variable was resolved, but could not be found")
.clone(); // .clone();
let heap_value = self.get_local_heaped(name, *level).unwrap();
let name = name.to_owned(); let name = name.to_owned();
@ -201,14 +278,30 @@ impl<'a> Environment<'a> {
impl Display for Environment<'_> { impl Display for Environment<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.runtime)?; // write!(f, "{}", self.runtime)?;
write!(f, "Globals:")?;
for (name, value) in self.globals().iter() {
write! {f, "\n global {name} = {}", value}?;
}
for (level, scope) in self.scopes().iter().enumerate() { for (level, scope) in self.scopes().iter().enumerate() {
write!(f, "\nScope {level}:")?; write!(f, "\n\nScope {level}:")?;
for (name, value) in scope.iter() { for (name, value) in scope.iter() {
write!(f, "\n\t{name} = {}", value.borrow())?; // write!(f, "\n\t{name} = {}", value)?;
match value {
ScopedValue::LocalValue(_) => {
write!(f, "\n local {name} = {}", value)?;
} }
ScopedValue::HeapedValue(_) => {
write! {f, "\n heaped {name} = {}", value}?;
}
}
}
writeln!(f)?;
} }
Ok(()) Ok(())

View file

@ -3,16 +3,16 @@ use std::rc::Rc;
use rlox2_frontend::parser::Stmt; use rlox2_frontend::parser::Stmt;
use crate::value::HeapedValue; use crate::environment::{ClosureScope, HeapedValue};
use super::environment::{Environment, Scope}; use super::environment::Environment;
use super::interpret::EvalResult; use super::interpret::EvalResult;
use super::{Runtime, Value}; use super::{Runtime, Value};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LoxFunction { pub struct LoxFunction {
name: Box<str>, name: Box<str>,
closure: Scope, closure: ClosureScope,
param_names: Vec<Box<str>>, param_names: Vec<Box<str>>,
body: Box<Stmt>, body: Box<Stmt>,
} }
@ -20,7 +20,7 @@ pub struct LoxFunction {
impl LoxFunction { impl LoxFunction {
pub fn new( pub fn new(
name: impl Into<Box<str>>, name: impl Into<Box<str>>,
closure: Scope, closure: ClosureScope,
param_names: Vec<Box<str>>, param_names: Vec<Box<str>>,
body: Stmt, body: Stmt,
) -> Rc<Self> { ) -> Rc<Self> {
@ -39,7 +39,7 @@ impl LoxFunction {
&self.name &self.name
} }
pub fn closure(&self) -> &Scope { pub fn closure(&self) -> &ClosureScope {
&self.closure &self.closure
} }

View file

@ -67,7 +67,7 @@ pub fn run_repl(runtime: &mut Runtime) {
pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> { pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
let tokens: Vec<Token> = scan_tokens(source)?; let tokens: Vec<Token> = scan_tokens(source)?;
if runtime.debug() { if runtime.is_debug() {
let token_str = let token_str =
itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " "); itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " ");
@ -77,13 +77,13 @@ pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
let statements = parse_tokens(tokens)?; let statements = parse_tokens(tokens)?;
for mut statement in statements { for mut statement in statements {
if runtime.debug() { if runtime.is_debug() {
println!("{statement}"); println!("{statement}");
} }
resolve(&mut statement, runtime)?; resolve(&mut statement, runtime)?;
if runtime.debug() { if runtime.is_debug() {
println!("{statement}"); println!("{statement}");
} }

View file

@ -40,7 +40,7 @@ impl Runtime {
self.debug = debug; self.debug = debug;
} }
pub fn debug(&self) -> bool { pub fn is_debug(&self) -> bool {
self.debug self.debug
} }
@ -76,9 +76,11 @@ impl Runtime {
*old_value = value; *old_value = value;
Ok(()) Ok(())
} else { } else {
Err(RuntimeError::GlobalNotDefined { panic!("Global not defined not caught by resolver");
name: name.to_owned(),
}) // Err(RuntimeError::GlobalNotDefined {
// name: name.to_owned(),
// })
} }
} }
} }

View file

@ -6,7 +6,7 @@ use crate::{LoxClass, LoxReference};
use super::function::LoxExternFunction; use super::function::LoxExternFunction;
use super::LoxFunction; use super::LoxFunction;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Default, Clone, PartialEq)]
pub enum Value { pub enum Value {
Object(LoxReference), Object(LoxReference),
Class(Rc<LoxClass>), Class(Rc<LoxClass>),
@ -15,6 +15,7 @@ pub enum Value {
String(Box<str>), String(Box<str>),
Number(f64), Number(f64),
Bool(bool), Bool(bool),
#[default]
Nil, Nil,
} }