Skip to content

Commit

Permalink
fix: No more Shared<Environment>
Browse files Browse the repository at this point in the history
  • Loading branch information
can-keklik committed Jan 29, 2024
1 parent 8d5c300 commit e3ea713
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 170 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ Lykia is a toy document database basically written for educational purposes. It
- [x] Core scripting language
- [x] A minimal standard library
- [x] Data manipulation language ("SELECT", "INSERT", "UPDATE", "DELETE")
- [x] Event loop, client-server communication
- [ ] Data definition language ("CREATE COLLECTION", etc.) (in progress)
- [ ] In-memory (dummy) storage engine (in progress)
- [ ] Async runtime/event loop (in progress)
- [ ] Query planning
- [ ] Persistent storage engine (Bitcask)
- [ ] B-Tree implementation for indexing
Expand Down
147 changes: 84 additions & 63 deletions server/src/runtime/environment.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,65 @@
use crate::runtime::interpreter::HaltReason;
use crate::runtime::types::RV;
use crate::util::{alloc_shared, Shared};
use core::panic;
use std::borrow::{Borrow, BorrowMut};
use rustc_hash::FxHashMap;

use super::interpreter::InterpretError;

#[repr(transparent)]
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct EnvId(pub usize);

#[derive(Debug)]
pub struct Environment {
map: FxHashMap<String, RV>,
pub parent: Option<Shared<Environment>>,
pub parent: Option<EnvId>,
}

#[derive(Debug)]
pub struct EnvironmentArena {
pub envs: Vec<Environment>,
}

impl Environment {
pub fn new(parent: Option<Shared<Environment>>) -> Shared<Environment> {
alloc_shared(Environment {
impl EnvironmentArena {
pub fn new() -> Self {
let mut arena = EnvironmentArena {
envs: vec![]
};
arena.push(None);
arena
}

fn get(&self, idx: EnvId) -> &Environment {
&self.envs[idx.0]
}

pub fn push(&mut self, parent: Option<EnvId>) -> EnvId {
self.envs.push(Environment {
map: FxHashMap::default(),
parent,
})
});
EnvId(self.envs.len() - 1)
}

pub fn pop(&mut self) -> Shared<Environment> {
self.parent.clone().unwrap()
pub fn pop(&self, env_id: EnvId) -> EnvId {
// TODO: Remove the env for real
self.get(env_id).parent.unwrap()
}

pub fn declare(&mut self, name: String, value: RV) {
self.map.insert(name, value);
pub fn top(&self) -> EnvId {
EnvId(self.envs.len() - 1)
}

pub fn assign(&mut self, name: String, value: RV) -> Result<bool, HaltReason> {
if self.map.contains_key(&name) {
self.map.insert(name, value);
pub fn assign(&mut self, env_id: EnvId, name: String, value: RV) -> Result<bool, HaltReason> {
let env = self.envs[env_id.0].borrow();
if env.map.contains_key(&name) {
self.envs[env_id.0].borrow_mut().map.insert(name, value);
return Ok(true);
}

if self.parent.is_some() {
return self
.parent
.as_mut()
.unwrap()
.borrow_mut()
.assign(name, value);
if env.parent.is_some() {
return self.assign(env.parent.unwrap(), name, value);
}
Err(HaltReason::Error(InterpretError::Other {
message: format!("Assignment to an undefined variable '{}'", &name),
Expand All @@ -49,109 +68,111 @@ impl Environment {

pub fn assign_at(
&mut self,
env_id: EnvId,
distance: usize,
name: &str,
value: RV,
) -> Result<bool, HaltReason> {
let ancestor = self.ancestor(distance);
let ancestor = self.ancestor(env_id, distance);

if let Some(unwrapped) = ancestor {
unwrapped.borrow_mut().map.insert(name.to_string(), value);
self.envs[unwrapped.0].borrow_mut().map.insert(name.to_string(), value);
} else {
self.map.insert(name.to_string(), value);
self.envs[env_id.0].borrow_mut().map.insert(name.to_string(), value);
}

Ok(true)
}

pub fn read(&self, name: &str) -> Result<RV, HaltReason> {
if self.map.contains_key(name) {
pub fn read(&self, env_id: EnvId, name: &str) -> Result<RV, HaltReason> {
if self.get(env_id).map.contains_key(name) {
// TODO(vck): Remove clone
return Ok(self.map.get(name).unwrap().clone());
return Ok(self.get(env_id).map.get(name).unwrap().clone());
}

if self.parent.is_some() {
return self.parent.as_ref().unwrap().borrow().read(name);
if self.get(env_id).parent.is_some() {
return self.read(self.get(env_id).parent.unwrap(), name);
}

Err(HaltReason::Error(InterpretError::Other {
message: format!("Variable '{}' was not found", &name),
}))
}

pub fn read_at(&self, distance: usize, name: &str) -> Result<RV, HaltReason> {
let ancestor = self.ancestor(distance);
pub fn read_at(&self, env_id: EnvId, distance: usize, name: &str) -> Result<RV, HaltReason> {
let ancestor = self.ancestor(env_id, distance);

if let Some(unwrapped) = ancestor {
// TODO(vck): Remove clone
return Ok(unwrapped.borrow().map.get(name).unwrap().clone());
return Ok(self.get(unwrapped).map.get(name).unwrap().clone());
}
return Ok(self.map.get(name).unwrap().clone());
return Ok(self.get(env_id).map.get(name).unwrap().clone());
}

pub fn ancestor(&self, distance: usize) -> Option<Shared<Environment>> {
pub fn ancestor(&self, env_id: EnvId, distance: usize) -> Option<EnvId> {
if distance == 0 {
return None;
}
if distance == 1 {
return Some(self.parent.as_ref().unwrap().clone());
return Some(self.get(env_id).parent.unwrap());
}
if self.parent.is_some() {
let pref = self.parent.as_ref().unwrap().borrow_mut();
return pref.ancestor(distance - 1);
if self.get(env_id).parent.is_some() {
let pref = self.get(env_id).parent.unwrap();
return self.ancestor(pref, distance - 1);
}
panic!("Invalid variable distance.");
}

pub fn declare(&mut self, env_id: EnvId, name: String, value: RV) {
self.envs[env_id.0].map.insert(name, value);
}
}


#[cfg(test)]
mod test {
use crate::runtime::types::RV;

#[test]
fn test_read_basic() {
let env = super::Environment::new(None);
env.borrow_mut().declare("five".to_string(), RV::Num(5.0));
assert_eq!(env.borrow().read("five").unwrap(), RV::Num(5.0));
let mut env_arena = super::EnvironmentArena::new();
let env = env_arena.top();
env_arena.declare(env, "five".to_string(), RV::Num(5.0));
assert_eq!(env_arena.read(env, "five").unwrap(), RV::Num(5.0));
}

#[test]
fn test_read_from_parent() {
let parent = super::Environment::new(None);
parent
.borrow_mut()
.declare("five".to_string(), RV::Num(5.0));
let child = super::Environment::new(Some(parent.clone()));
assert_eq!(child.borrow().read("five").unwrap(), RV::Num(5.0));
let mut env_arena = super::EnvironmentArena::new();
let parent = env_arena.top();
env_arena.declare(parent, "five".to_string(), RV::Num(5.0));
let child = env_arena.push(Some(parent));
assert_eq!(env_arena.read(child, "five").unwrap(), RV::Num(5.0));
}

#[test]
fn test_write_to_parent() {
let parent = super::Environment::new(None);
parent
.borrow_mut()
.declare("five".to_string(), RV::Num(5.0));
let child = super::Environment::new(Some(parent.clone()));
child
.borrow_mut()
.assign("five".to_string(), RV::Num(5.1))
let mut env_arena = super::EnvironmentArena::new();
let parent = env_arena.top();
env_arena.declare(parent, "five".to_string(), RV::Num(5.0));
let child = env_arena.push(Some(parent));
env_arena.assign(child, "five".to_string(), RV::Num(5.1))
.unwrap();
assert_eq!(parent.borrow().read("five").unwrap(), RV::Num(5.1));
assert_eq!(child.borrow().read("five").unwrap(), RV::Num(5.1));
assert_eq!(env_arena.read(parent, "five").unwrap(), RV::Num(5.1));
assert_eq!(env_arena.read(child, "five").unwrap(), RV::Num(5.1));
}

#[test]
fn test_read_undefined_variable() {
let env = super::Environment::new(None);
assert!(env.borrow().read("five").is_err());
let env_arena = super::EnvironmentArena::new();
let env = env_arena.top();
assert!(env_arena.read(env, "five").is_err());
}

#[test]
fn test_assign_to_undefined_variable() {
let env = super::Environment::new(None);
assert!(env
.borrow_mut()
.assign("five".to_string(), RV::Num(5.0))
.is_err());
let mut env_arena = super::EnvironmentArena::new();
let env = env_arena.top();
assert!(env_arena.assign(env, "five".to_string(), RV::Num(5.0)).is_err());
}
}
Loading

0 comments on commit e3ea713

Please sign in to comment.