From 8e847847a6e6ee576bb1e8eda03c757d178ef48e Mon Sep 17 00:00:00 2001 From: Moritz Gmeiner Date: Sun, 1 Sep 2024 23:15:36 +0200 Subject: [PATCH] automatically heapify captured variables --- interpreter/src/environment.rs | 147 +++++++++++++++++++++++++++------ interpreter/src/function.rs | 10 +-- interpreter/src/run.rs | 6 +- interpreter/src/runtime.rs | 10 ++- interpreter/src/value.rs | 3 +- 5 files changed, 136 insertions(+), 40 deletions(-) diff --git a/interpreter/src/environment.rs b/interpreter/src/environment.rs index bab4e73..a77872b 100644 --- a/interpreter/src/environment.rs +++ b/interpreter/src/environment.rs @@ -37,7 +37,60 @@ impl HeapedValue { } } -pub type Scope = FxHashMap, 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, ScopedValue>; +pub type ClosureScope = FxHashMap, HeapedValue>; #[derive(Debug)] pub struct Environment<'a> { @@ -79,23 +132,23 @@ impl<'a> Environment<'a> { self.runtime.globals() } - pub fn scopes(&self) -> &[Scope] { + fn scopes(&self) -> &[Scope] { &self.scope_stack } - pub fn scopes_mut(&mut self) -> &mut [Scope] { + fn scopes_mut(&mut self) -> &mut [Scope] { &mut self.scope_stack } - pub fn has_scope(&self) -> bool { + fn has_scope(&self) -> bool { !self.scope_stack.is_empty() } - pub fn current_scope(&self) -> &Scope { + /* fn current_scope(&self) -> &Scope { 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() } @@ -118,11 +171,11 @@ impl<'a> Environment<'a> { 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(); 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) } - pub fn get_local(&'a self, name: &str, level: usize) -> Result { + pub fn get_local(&self, name: &str, level: usize) -> Result { let len = self.scopes().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(), - }) + }) */ + } + + pub fn get_local_heaped( + &mut self, + name: &str, + level: usize, + ) -> Result { + 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>, value: Value) { if self.has_scope() { let name = name.into(); self.current_scope_mut() - .insert(name, HeapedValue::new(value)); + .insert(name, ScopedValue::new(value)); } else { self.runtime.define_global(name, value) } @@ -171,8 +246,8 @@ impl<'a> Environment<'a> { }) } - pub fn collect_closure(&self, closure_vars: &[(Box, usize)]) -> Scope { - let mut closure_scope = Scope::default(); + pub fn collect_closure(&mut self, closure_vars: &[(Box, usize)]) -> ClosureScope { + let mut closure_scope = ClosureScope::default(); for (name, level) in closure_vars { // special injected variables @@ -180,15 +255,17 @@ impl<'a> Environment<'a> { continue; } - let heap_value = self - .scopes() - .iter() - .rev() - .nth(*level) - .expect("Closure variable got resolved to level that doesn't exist") - .get(name) - .expect("Closure variable was resolved, but could not be found") - .clone(); + // let heap_value = self + // .scopes() + // .iter() + // .rev() + // .nth(*level) + // .expect("Closure variable got resolved to level that doesn't exist") + // .get(name) + // .expect("Closure variable was resolved, but could not be found") + // .clone(); + + let heap_value = self.get_local_heaped(name, *level).unwrap(); let name = name.to_owned(); @@ -201,14 +278,30 @@ impl<'a> Environment<'a> { impl Display for Environment<'_> { 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() { - write!(f, "\nScope {level}:")?; + write!(f, "\n\nScope {level}:")?; 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(()) diff --git a/interpreter/src/function.rs b/interpreter/src/function.rs index 5f0f0c0..0983df3 100644 --- a/interpreter/src/function.rs +++ b/interpreter/src/function.rs @@ -3,16 +3,16 @@ use std::rc::Rc; 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::{Runtime, Value}; #[derive(Debug, Clone)] pub struct LoxFunction { name: Box, - closure: Scope, + closure: ClosureScope, param_names: Vec>, body: Box, } @@ -20,7 +20,7 @@ pub struct LoxFunction { impl LoxFunction { pub fn new( name: impl Into>, - closure: Scope, + closure: ClosureScope, param_names: Vec>, body: Stmt, ) -> Rc { @@ -39,7 +39,7 @@ impl LoxFunction { &self.name } - pub fn closure(&self) -> &Scope { + pub fn closure(&self) -> &ClosureScope { &self.closure } diff --git a/interpreter/src/run.rs b/interpreter/src/run.rs index a58c5a0..457300a 100644 --- a/interpreter/src/run.rs +++ b/interpreter/src/run.rs @@ -67,7 +67,7 @@ pub fn run_repl(runtime: &mut Runtime) { pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(source)?; - if runtime.debug() { + if runtime.is_debug() { let token_str = 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)?; for mut statement in statements { - if runtime.debug() { + if runtime.is_debug() { println!("{statement}"); } resolve(&mut statement, runtime)?; - if runtime.debug() { + if runtime.is_debug() { println!("{statement}"); } diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index baff0b0..3d1fd2a 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -40,7 +40,7 @@ impl Runtime { self.debug = debug; } - pub fn debug(&self) -> bool { + pub fn is_debug(&self) -> bool { self.debug } @@ -76,9 +76,11 @@ impl Runtime { *old_value = value; Ok(()) } else { - Err(RuntimeError::GlobalNotDefined { - name: name.to_owned(), - }) + panic!("Global not defined not caught by resolver"); + + // Err(RuntimeError::GlobalNotDefined { + // name: name.to_owned(), + // }) } } } diff --git a/interpreter/src/value.rs b/interpreter/src/value.rs index eef7900..1796376 100644 --- a/interpreter/src/value.rs +++ b/interpreter/src/value.rs @@ -6,7 +6,7 @@ use crate::{LoxClass, LoxReference}; use super::function::LoxExternFunction; use super::LoxFunction; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Default, Clone, PartialEq)] pub enum Value { Object(LoxReference), Class(Rc), @@ -15,6 +15,7 @@ pub enum Value { String(Box), Number(f64), Bool(bool), + #[default] Nil, }