lispers/src/lisp/environment.rs

97 lines
2.9 KiB
Rust

use super::expression::Expression;
use std::collections::HashMap;
#[derive(PartialEq, Clone, Debug)]
/// A Environment is a stack of `EnvironmentLayer`s. Each `EnvironmentLayer` is a mapping from
/// variable names to their values.
pub struct Environment<'a> {
/// The current mapping.
layer: EnvironmentLayer,
/// The outer _fallback_ mapping.
outer: Option<&'a Environment<'a>>,
}
#[derive(PartialEq, Clone, Debug)]
/// A concrete EnvironmentLayer, containing a mapping from symbol names to Expressions.
pub struct EnvironmentLayer {
symbols: HashMap<String, Expression>,
}
impl EnvironmentLayer {
/// Construct an empty `EnvironmentLayer`.
pub fn new() -> Self {
EnvironmentLayer {
symbols: HashMap::new(),
}
}
/// Set a value in the `EnvironmentLayer`.
pub fn set(&mut self, key: String, value: Expression) {
self.symbols.insert(key, value);
}
/// Get a value in the `EnvironmentLayer`.
pub fn get(&self, key: &str) -> Option<&Expression> {
self.symbols.get(key)
}
}
impl<'a> Environment<'a> {
/// Construct an empty `Environment`.
pub fn new() -> Self {
Environment {
layer: EnvironmentLayer::new(),
outer: None,
}
}
/// Construct an `Environment` from a `EnvironmentLayer` with no outer `Environment`.
pub fn from_layer(layer: EnvironmentLayer) -> Self {
Environment { layer, outer: None }
}
/// Construct a new `Environment` with `self` as the outer `Environment`.
pub fn mk_inner(&self) -> Environment {
Environment {
layer: EnvironmentLayer::new(),
outer: Some(self),
}
}
/// Construct a new `Environment` with `self` as the outer `Environment` and `layer` as the
pub fn overlay(&'a self, layer: EnvironmentLayer) -> Environment<'a> {
Environment {
layer,
outer: Some(&self),
}
}
/// Get a value from the `Environment`.
pub fn get(&self, key: &str) -> Option<&Expression> {
if let Some(e) = self.layer.get(key) {
Some(e)
} else {
self.outer?.get(key)
}
}
/// Set a value in the current `EnvironmentLayer`.
pub fn set(&mut self, key: String, value: Expression) {
self.layer.set(key, value);
}
}
#[test]
fn test_environment() {
let mut env = Environment::new();
env.set("a".to_string(), Expression::Integer(1));
env.set("b".to_string(), Expression::Integer(2));
let mut inner = env.mk_inner();
inner.set("a".to_string(), Expression::Integer(3));
assert_eq!(inner.get("a"), Some(&Expression::Integer(3)));
assert_eq!(inner.get("b"), Some(&Expression::Integer(2)));
assert_eq!(env.get("a"), Some(&Expression::Integer(1)));
assert_eq!(env.get("b"), Some(&Expression::Integer(2)));
assert_eq!(env.get("c"), None);
}