turtle/interpreter/
environment.rs

1use std::collections::HashMap;
2
3use std::fmt;
4
5use crate::Locker;
6
7use crate::{
8    exp, CallSnapshot, Exception, ExceptionValue as EV, Expression, Operator, Symbol, Value,
9};
10
11#[derive(Debug, Clone)]
12struct ParentEnvironment {
13    namespace: Option<String>,
14    environment: Locker<Environment>,
15}
16
17#[derive(Debug, Clone)]
18pub struct Environment {
19    values: HashMap<Symbol, Locker<Expression>>,
20    // This unreadable memory model might cause issues going forward
21    parents: Vec<ParentEnvironment>,
22    // Whether this environment is a "shadow environment" -- that is, whether
23    // it defers local assignment to the first non-namespaced parent.
24    shadow: bool,
25}
26
27impl Environment {
28    // TODO: see if this can be done without mutexes, at least for values
29
30    pub fn root() -> Self {
31        Self {
32            values: HashMap::new(),
33            parents: vec![],
34            shadow: false,
35        }
36    }
37
38    pub fn shadow(mut self) -> Self {
39        self.shadow = true;
40        self
41    }
42
43    pub fn with_parent(mut self, parent: Locker<Self>, namespace: Option<String>) -> Self {
44        self.add_parent(parent, namespace);
45        self
46    }
47
48    fn get_literal(symbol: &Symbol) -> Option<Value> {
49        use Operator::*;
50
51        match symbol.string_value().as_str() {
52            "nil" => Some(Value::List(vec![])),
53            "t" | "true" => Some(Value::True),
54            "quote" => Some(Value::Operator(Quote)),
55            "atom" => Some(Value::Operator(Atom)),
56            "eq" => Some(Value::Operator(Eq)),
57            "car" => Some(Value::Operator(Car)),
58            "cdr" => Some(Value::Operator(Cdr)),
59            "cons" => Some(Value::Operator(Cons)),
60            "cond" => Some(Value::Operator(Cond)),
61            "export" => Some(Value::Operator(Export)),
62            "let" => Some(Value::Operator(Let)),
63            "sum" => Some(Value::Operator(Sum)),
64            "prod" => Some(Value::Operator(Prod)),
65            "exp" => Some(Value::Operator(Exp)),
66            "modulo" => Some(Value::Operator(Modulo)),
67            "gt" => Some(Value::Operator(Gt)),
68            "ge" => Some(Value::Operator(Ge)),
69            "type" => Some(Value::Operator(Type)),
70            "disp" => Some(Value::Operator(Disp)),
71            "import" => Some(Value::Operator(Import)),
72            "eval" => Some(Value::Operator(Eval)),
73            "while" => Some(Value::Operator(While)),
74            "macro" => Some(Value::Operator(Macro)),
75            "lambda" => Some(Value::Operator(Lambda)),
76            "list" => Some(Value::Operator(List)),
77            "catch" => Some(Value::Operator(Catch)),
78            "throw" => Some(Value::Operator(Throw)),
79            "format" => Some(Value::Operator(Format)),
80            "parse" => Some(Value::Operator(Parse)),
81            "length" => Some(Value::Operator(Length)),
82            "append" => Some(Value::Operator(Append)),
83            "do" => Some(Value::Operator(Do)),
84            "floor" => Some(Value::Operator(Floor)),
85            "rand" => Some(Value::Operator(Rand)),
86            "equiv" => Some(Value::Operator(Equiv)),
87            _ => None,
88        }
89    }
90
91    fn resolve_symbol(
92        &self,
93        symbol: &Symbol,
94        namespace: Option<String>,
95    ) -> Option<(Locker<Expression>, usize)> {
96        if namespace == None {
97            if let Some(value) = self.values.get(&symbol) {
98                return Some((value.clone(), 0));
99            }
100        } else {
101            for parent in self.parents.iter() {
102                if namespace == parent.namespace {
103                    return parent
104                        .environment
105                        .read()
106                        .unwrap()
107                        .resolve_symbol(symbol, None);
108                }
109            }
110        }
111        let mut best_match: (Option<Locker<Expression>>, usize) = (None, 0);
112        for parent in self.parents.iter() {
113            if parent.namespace.is_some() {
114                continue;
115            }
116            if let Some((exp, depth)) = parent
117                .environment
118                .read()
119                .unwrap()
120                .resolve_symbol(symbol, None)
121            {
122                if best_match.0.is_none() || depth < best_match.1 {
123                    best_match = (Some(exp), depth);
124                }
125            }
126        }
127        if let Some(exp) = best_match.0 {
128            return Some((exp, best_match.1 + 1));
129        }
130        match Self::get_literal(symbol) {
131            Some(value) => Some((Locker::new(Expression::new(value)), 9999)),
132            None => None,
133        }
134    }
135
136    fn extract_components(symbol: &Symbol) -> (Option<String>, Symbol) {
137        let components: Vec<&str> = symbol.string_value().split("::").collect();
138
139        match components.len() {
140            1 => (None, Symbol::from_str(components.get(0).unwrap())),
141            _ => (
142                Some(components.get(0).unwrap().to_string()),
143                Symbol::from_str(
144                    &components
145                        .iter()
146                        .skip(1)
147                        .map(|x| x.to_string())
148                        .collect::<Vec<String>>()
149                        .join("::"),
150                ),
151            ),
152        }
153    }
154
155    pub fn lookup(&self, symbol: &Symbol) -> Option<Locker<Expression>> {
156        let (namespace, identifier) = Self::extract_components(symbol);
157        match self.resolve_symbol(&identifier, namespace) {
158            Some((exp, _)) => Some(exp),
159            None => None,
160        }
161    }
162
163    pub fn add_parent(&mut self, parent: Locker<Self>, namespace: Option<String>) {
164        self.parents.push(ParentEnvironment {
165            namespace,
166            environment: parent,
167        });
168    }
169
170    pub fn assign(
171        &mut self,
172        symbol: Symbol,
173        exp: Expression,
174        only_local: bool,
175        snapshot: Locker<CallSnapshot>,
176    ) -> Result<Locker<Expression>, Exception> {
177        let (namespace, identifier) = Self::extract_components(&symbol);
178
179        if only_local && namespace.is_some() {
180            exp!(
181                EV::Assignment(symbol, exp),
182                snapshot,
183                "cannot perform local assignment with namespace".to_string()
184            )
185        }
186
187        if !self.shadow
188            && (only_local || self.values.contains_key(&identifier) || self.parents.is_empty())
189        {
190            let lock = Locker::new(exp);
191            self.values.insert(identifier, lock.clone());
192            Ok(lock)
193        } else {
194            for parent in self.parents.iter() {
195                if parent.namespace == namespace {
196                    return parent
197                        .environment
198                        .write()
199                        .unwrap()
200                        .assign(identifier, exp, only_local, snapshot);
201                }
202            }
203            exp!(EV::Assignment(symbol, exp), snapshot, format!("could not find suitable environment for assignment (namespace `{}` not available for assignment)", match namespace {
204                Some(value) => value,
205                None => "no namespace".to_string(),
206            }))
207        }
208    }
209}
210
211impl fmt::Display for Environment {
212    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213        write!(
214            f,
215            "[values: {}]\n{}\nimported namespaces: {}",
216            self.values.len(),
217            self.values
218                .iter()
219                .map(|(k, v)| format!("{} := {}", k, v.read().unwrap()))
220                .collect::<Vec<String>>()
221                .join("\n"),
222            self.parents
223                .iter()
224                .map(|p| match &p.namespace {
225                    Some(val) => val.clone(),
226                    None => "(directly injected)".to_string(),
227                })
228                .collect::<Vec<String>>()
229                .join(", ")
230        )
231    }
232}