pulsar_utils/
environment.rs

1// Copyright (C) 2024 Ethan Uppal. All rights reserved.
2use std::{collections::HashMap, hash::Hash};
3
4/// A set of bindings between names and values.
5pub type Scope<Name, T> = HashMap<Name, T>;
6
7/// A scoped set of bindings between names and values.
8pub struct Environment<Name: Eq + Hash, T> {
9    scopes: Vec<Scope<Name, T>>
10}
11
12impl<Name: Eq + Hash, T> Environment<Name, T> {
13    /// Constructs a new context with a base scope that further scopes can be
14    /// pushed and popped on top of.
15    pub fn new() -> Self {
16        Environment {
17            scopes: vec![Scope::new()]
18        }
19    }
20
21    /// Creates a new scope.
22    pub fn push(&mut self) {
23        self.scopes.push(Scope::new());
24    }
25
26    /// Removes all bindings in the most recent scope, returning `true` unless
27    /// there are no scopes beside the base scope.
28    pub fn pop(&mut self) -> bool {
29        if self.scopes.len() == 1 {
30            false
31        } else {
32            self.scopes.pop();
33            true
34        }
35    }
36
37    /// Binds `name` to `value` in the top scope, returning
38    /// `Some(previous_value)` if `previous_value` had previously been bound to
39    /// `name`, or `None`.
40    pub fn bind(&mut self, name: Name, value: T) -> Option<T> {
41        self.scopes.last_mut().unwrap().insert(name, value)
42    }
43
44    /// Binds `name` to `value` in the base scope.
45    ///
46    /// @see [`Environment::bind`]
47    pub fn bind_base(&mut self, name: Name, value: T) -> Option<T> {
48        self.scopes.first_mut().unwrap().insert(name, value)
49    }
50
51    /// Finds the bound value for `name` in the highest scope possible.
52    pub fn find(&self, name: Name) -> Option<&T> {
53        for scope in self.scopes.iter().rev() {
54            if let Some(value) = scope.get(&name) {
55                return Some(value);
56            }
57        }
58        None
59    }
60}
61
62impl<Name: Eq + Hash, T> Default for Environment<Name, T> {
63    fn default() -> Self {
64        Self::new()
65    }
66}