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)]
|
#[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(())
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue