Skip to main content

air_parser/sema/
scope.rs

1use std::{
2    borrow::Borrow,
3    collections::HashMap,
4    hash::Hash,
5    ops::{Index, IndexMut},
6    rc::Rc,
7};
8
9/// A simple type alias for a boxed `HashMap` to aid in readability of the code below
10pub type Env<K, V> = Box<HashMap<K, V>>;
11
12/// A lexically scoped environment is essentially a hierarchical mapping of keys to values,
13/// where keys may be defined at multiple levels, but only a single definition at any point
14/// in the program is active - the definition closest to that point.
15///
16/// A [LexicalScope] starts out at the root, empty. Any number of keys may be inserted at
17/// the current scope, or a new nested scope may be entered. When entering a new nested scope,
18/// keys inserted there take precedence over the same keys in previous (higher) scopes, but
19/// do not overwrite those definitions. When exiting a scope, all definitions in that scope
20/// are discarded, and definitions from the parent scope take effect again.
21///
22/// When searching for keys, the search begins in the current scope, and searches upwards
23/// in the scope tree until either the root is reached and the search terminates, or the
24/// key is found in some intervening scope.
25#[derive(Debug)]
26pub enum LexicalScope<K, V> {
27    /// An empty scope, this is the default state in which all [LexicalScope] start
28    Empty,
29    /// Represents a non-empty, top-level (root) scope
30    Root(Env<K, V>),
31    /// Represents a (possibly empty) nested scope, as a tuple of the parent scope and
32    /// the environment of the current scope.
33    Nested(Rc<LexicalScope<K, V>>, Env<K, V>),
34}
35impl<K, V> Clone for LexicalScope<K, V>
36where
37    K: Clone,
38    V: Clone,
39{
40    fn clone(&self) -> Self {
41        match self {
42            Self::Empty => Self::Empty,
43            Self::Root(scope) => Self::Root(scope.clone()),
44            Self::Nested(parent, scope) => Self::Nested(Rc::clone(parent), scope.clone()),
45        }
46    }
47}
48impl<K, V> Default for LexicalScope<K, V> {
49    fn default() -> Self {
50        Self::Empty
51    }
52}
53impl<K, V> LexicalScope<K, V> {
54    /// Returns true if this scope is empty
55    pub fn is_empty(&self) -> bool {
56        match self {
57            Self::Empty => true,
58            Self::Root(_) => false,
59            Self::Nested(parent, env) => env.is_empty() && parent.is_empty(),
60        }
61    }
62}
63
64impl<K, V> LexicalScope<K, V>
65where
66    K: Clone,
67    V: Clone,
68{
69    /// Returns true if this scope is empty
70    /// Enters a new, nested lexical scope
71    pub fn enter(&mut self) {
72        let moved = Rc::new(core::mem::take(self));
73        *self = Self::Nested(moved, Env::default());
74    }
75
76    /// Exits the current lexical scope
77    pub fn exit(&mut self) {
78        match core::mem::replace(self, Self::Empty) {
79            Self::Empty | Self::Root(_) => (),
80            Self::Nested(parent, _) => {
81                *self = Rc::unwrap_or_clone(parent);
82            }
83        }
84    }
85}
86impl<K, V> LexicalScope<K, V>
87where
88    K: Eq + Hash,
89{
90    /// Inserts a new binding in the current scope, returning a conflicting definition
91    /// if one is present (i.e. the same name was already declared in the same (current) scope).
92    ///
93    /// NOTE: This does not return `Some` if a previous definition exists in an outer scope,
94    /// the new definition will shadow that one, but is not considered in conflict with it.
95    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
96        match self {
97            Self::Empty => {
98                let mut env = Env::default();
99                env.insert(k, v);
100                *self = Self::Root(env);
101                None
102            }
103            Self::Root(env) => env.insert(k, v),
104            Self::Nested(_, env) => env.insert(k, v),
105        }
106    }
107
108    pub fn get<Q>(&self, key: &Q) -> Option<&V>
109    where
110        K: Borrow<Q>,
111        Q: Eq + Hash + ?Sized,
112    {
113        match self {
114            Self::Empty => None,
115            Self::Root(env) => env.get(key),
116            Self::Nested(parent, env) => env.get(key).or_else(|| parent.get(key)),
117        }
118    }
119
120    pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
121    where
122        K: Borrow<Q>,
123        Q: Eq + Hash + ?Sized,
124    {
125        match self {
126            Self::Empty => None,
127            Self::Root(env) => env.get_mut(key),
128            Self::Nested(parent, env) => env
129                .get_mut(key)
130                .or_else(|| Rc::get_mut(parent).and_then(|p| p.get_mut(key))),
131        }
132    }
133
134    pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
135    where
136        K: Borrow<Q>,
137        Q: Eq + Hash + ?Sized,
138    {
139        match self {
140            Self::Empty => None,
141            Self::Root(env) => env.get_key_value(key),
142            Self::Nested(parent, env) => {
143                env.get_key_value(key).or_else(|| parent.get_key_value(key))
144            }
145        }
146    }
147
148    /// Gets the value of the key stored in this structure by `key`
149    ///
150    /// This is used in some cases where a field of the key contains useful metadata
151    /// (such as source spans), but is not part of the eq/hash impl. This function
152    /// allows you to obtain the actual key stored in the map.
153    pub fn get_key<Q>(&self, key: &Q) -> Option<&K>
154    where
155        K: Borrow<Q>,
156        Q: Eq + Hash + ?Sized,
157    {
158        self.get_key_value(key).map(|(k, _)| k)
159    }
160}
161impl<K, V, Q> Index<&Q> for LexicalScope<K, V>
162where
163    K: Eq + Hash + Borrow<Q>,
164    Q: Eq + Hash + ?Sized,
165{
166    type Output = V;
167
168    #[inline]
169    fn index(&self, key: &Q) -> &Self::Output {
170        self.get(key).unwrap()
171    }
172}
173impl<K, V, Q> IndexMut<&Q> for LexicalScope<K, V>
174where
175    K: Eq + Hash + Borrow<Q>,
176    Q: Eq + Hash + ?Sized,
177{
178    #[inline]
179    fn index_mut(&mut self, key: &Q) -> &mut Self::Output {
180        self.get_mut(key).unwrap()
181    }
182}