1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#[cfg(test)]
use crate::interpreter::Interpreter;
use crate::values::Value;
use crate::{error::*, interpreter::error::LogicError};
use cell::{Ref, RefCell, RefMut, RefVal};
use std::collections::HashMap;
#[cfg(test)]
use std::error::Error;
use std::rc::Rc;

pub type DefinitionIter<'a, V> = Box<dyn 'a + Iterator<Item = (&'a String, &'a V)>>;

#[derive(Clone, Debug, PartialEq)]
pub struct LexicalScope<V> {
    parent: Option<Rc<LexicalScope<V>>>,
    definitions: RefCell<HashMap<String, V>>,
}

impl<V> LexicalScope<V> {
    pub fn new() -> Self {
        Self {
            parent: None,
            definitions: RefCell::new(HashMap::new()),
        }
    }
    pub fn new_child(parent: Rc<LexicalScope<V>>) -> Self {
        Self {
            parent: Some(parent),
            definitions: RefCell::new(HashMap::new()),
        }
    }

    pub fn define(&self, name: String, value: V) {
        self.definitions.borrow_mut().insert(name, value);
    }

    pub fn get(&self, name: &str) -> Option<Ref<V>> {
        if self.definitions.borrow().contains_key(name) {
            Some(Ref::map(self.definitions.borrow(), |definitions| {
                definitions.get(name).unwrap()
            }))
        } else {
            match &self.parent {
                Some(parent) => parent.get(name),
                None => None,
            }
        }
    }
    pub fn get_mut(&self, name: &str) -> Option<RefMut<V>> {
        if self.definitions.borrow().contains_key(name) {
            Some(RefMut::map(self.definitions.borrow_mut(), |definitions| {
                definitions.get_mut(name).unwrap()
            }))
        } else {
            match &self.parent {
                Some(parent) => parent.get_mut(name),
                None => None,
            }
        }
    }

    pub fn set(&self, name: &str, value: V) -> Result<(), SchemeError> {
        match self.definitions.borrow_mut().get_mut(name) {
            None => match &self.parent {
                None => {
                    return Err(
                        ErrorData::Logic(LogicError::UnboundedSymbol(name.to_string())).no_locate(),
                    );
                }
                Some(parent) => parent.set(name, value)?,
            },
            Some(variable) => *variable = value,
        };
        Ok(())
    }

    pub fn iter_local_definitions<'a, 'b: 'a>(&'b self) -> RefVal<'a, DefinitionIter<'b, V>> {
        Ref::map_val(
            self.definitions.borrow(),
            |definitions| -> DefinitionIter<'b, V> { Box::new(definitions.iter()) },
        )
    }
}

pub type Environment<R> = LexicalScope<Value<R>>;

#[test]
fn iter_envs() -> Result<(), Box<dyn std::error::Error>> {
    let it = Interpreter::<f32>::new_with_stdlib();
    {
        it.env.define("a".to_string(), Value::Void);
    }
    let env = it.env;
    {
        let mut definitions = env.iter_local_definitions();
        assert_ne!(definitions.find(|(name, _)| *name == "a"), None);
    }

    {
        let mut definitions = env.iter_local_definitions();
        assert_ne!(definitions.find(|(name, _)| *name == "sqrt"), None);
    }

    Ok(())
}
#[test]
fn get_mut() -> Result<(), Box<dyn Error>> {
    use crate::values::Number;
    use std::ops::Deref;
    let env = Environment::<f32>::new();
    env.define("x".to_string(), Value::Number(Number::Integer(1)));
    {
        let value_mut = env.get_mut("x").unwrap();
        let mut i = RefMut::map(value_mut, |value_mut| {
            if let Value::Number(Number::Integer(i)) = value_mut {
                i
            } else {
                unreachable!()
            }
        });
        *i += 1;
    }
    assert_eq!(
        env.get("x").unwrap().deref(),
        &Value::Number(Number::Integer(2))
    );
    Ok(())
}