mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
automatically heapify captured variables
This commit is contained in:
parent
9d447d9266
commit
8e847847a6
5 changed files with 136 additions and 40 deletions
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue