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)]
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<Value, RuntimeError> {
pub fn get_local(&self, name: &str, level: usize) -> Result<Value, RuntimeError> {
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<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) {
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<str>, usize)]) -> Scope {
let mut closure_scope = Scope::default();
pub fn collect_closure(&mut self, closure_vars: &[(Box<str>, 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(())

View file

@ -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<str>,
closure: Scope,
closure: ClosureScope,
param_names: Vec<Box<str>>,
body: Box<Stmt>,
}
@ -20,7 +20,7 @@ pub struct LoxFunction {
impl LoxFunction {
pub fn new(
name: impl Into<Box<str>>,
closure: Scope,
closure: ClosureScope,
param_names: Vec<Box<str>>,
body: Stmt,
) -> Rc<Self> {
@ -39,7 +39,7 @@ impl LoxFunction {
&self.name
}
pub fn closure(&self) -> &Scope {
pub fn closure(&self) -> &ClosureScope {
&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> {
let tokens: Vec<Token> = 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}");
}

View file

@ -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(),
// })
}
}
}

View file

@ -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<LoxClass>),
@ -15,6 +15,7 @@ pub enum Value {
String(Box<str>),
Number(f64),
Bool(bool),
#[default]
Nil,
}