Skip to main content

nu_protocol/engine/
overlay.rs

1use crate::{DeclId, ModuleId, OverlayId, VarId};
2use std::{collections::HashMap, ops::Deref};
3
4/// Name → id map for declarations that remembers the longest name it has ever held.
5///
6/// Command resolution tries the longest possible command name first (`find_longest_decl`), so
7/// for a call like `each {|x| ... }` the first candidate is the whole call text, and every
8/// non-empty map on the scope chain would hash all of it just to say "no". Knowing the longest
9/// name lets [`DeclNameMap::get`] reject such candidates by length before hashing. The bound only
10/// grows (removals leave it alone), so it is always an upper bound on the keys present.
11///
12/// Reads go through `Deref` to the underlying `HashMap`; all mutation goes through the inherent
13/// methods so the bound stays valid.
14#[derive(Debug, Clone, Default)]
15pub struct DeclNameMap {
16    map: HashMap<Vec<u8>, DeclId>,
17    longest_name: usize,
18}
19
20impl DeclNameMap {
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// Look up a declaration by name; names longer than any key ever inserted are rejected
26    /// without hashing.
27    pub fn get(&self, name: &[u8]) -> Option<&DeclId> {
28        if name.len() > self.longest_name {
29            return None;
30        }
31        self.map.get(name)
32    }
33
34    pub fn insert(&mut self, name: Vec<u8>, decl_id: DeclId) -> Option<DeclId> {
35        self.longest_name = self.longest_name.max(name.len());
36        self.map.insert(name, decl_id)
37    }
38
39    pub fn remove(&mut self, name: &[u8]) -> Option<DeclId> {
40        self.map.remove(name)
41    }
42
43    pub fn remove_entry(&mut self, name: &[u8]) -> Option<(Vec<u8>, DeclId)> {
44        self.map.remove_entry(name)
45    }
46}
47
48impl Deref for DeclNameMap {
49    type Target = HashMap<Vec<u8>, DeclId>;
50
51    fn deref(&self) -> &Self::Target {
52        &self.map
53    }
54}
55
56impl<'a> IntoIterator for &'a DeclNameMap {
57    type Item = (&'a Vec<u8>, &'a DeclId);
58    type IntoIter = std::collections::hash_map::Iter<'a, Vec<u8>, DeclId>;
59
60    fn into_iter(self) -> Self::IntoIter {
61        self.map.iter()
62    }
63}
64
65impl IntoIterator for DeclNameMap {
66    type Item = (Vec<u8>, DeclId);
67    type IntoIter = std::collections::hash_map::IntoIter<Vec<u8>, DeclId>;
68
69    fn into_iter(self) -> Self::IntoIter {
70        self.map.into_iter()
71    }
72}
73
74impl Extend<(Vec<u8>, DeclId)> for DeclNameMap {
75    fn extend<I: IntoIterator<Item = (Vec<u8>, DeclId)>>(&mut self, iter: I) {
76        for (name, decl_id) in iter {
77            self.insert(name, decl_id);
78        }
79    }
80}
81
82impl FromIterator<(Vec<u8>, DeclId)> for DeclNameMap {
83    fn from_iter<I: IntoIterator<Item = (Vec<u8>, DeclId)>>(iter: I) -> Self {
84        let mut map = Self::default();
85        map.extend(iter);
86        map
87    }
88}
89
90pub static DEFAULT_OVERLAY_NAME: &str = "zero";
91
92/// Tells whether a decl is visible or not
93#[derive(Debug, Clone)]
94pub struct Visibility {
95    decl_ids: HashMap<DeclId, bool>,
96}
97
98/// Name bindings introduced while parsing a single block/closure scope.
99///
100/// Nested scopes discard their name maps on `exit_scope`; this snapshot is stored on the
101/// [`Block`](crate::ast::Block) so `scope` commands can report locals at runtime.
102///
103/// # Lifecycle
104///
105/// 1. **Parse**: [`StateWorkingSet::snapshot_scope_bindings`] copies decls/modules from the
106///    innermost scope frame into a `ScopeBindings` attached to the block, immediately before
107///    the matching `exit_scope`.
108/// 2. **Eval**: whole blocks push bindings on [`Stack::active_scope_bindings`] in
109///    `eval_ir_block`. Keyword bodies that are IR-inlined record
110///    [`ScopeRegion`](crate::ir::ScopeRegion)s on the parent [`IrBlock`](crate::ir::IrBlock);
111///    `scope` matches the current instruction index against those regions.
112#[derive(Debug, Clone, Default)]
113pub struct ScopeBindings {
114    pub decls: HashMap<Vec<u8>, DeclId>,
115    pub modules: HashMap<Vec<u8>, ModuleId>,
116    pub visibility: Visibility,
117}
118
119impl ScopeBindings {
120    pub fn is_empty(&self) -> bool {
121        self.decls.is_empty() && self.modules.is_empty() && self.visibility.decl_ids.is_empty()
122    }
123
124    /// Merge decls, modules, and visibility from an overlay frame (other wins on name clash).
125    pub fn extend_from_overlay(&mut self, overlay: &OverlayFrame) {
126        self.decls
127            .extend(overlay.decls.iter().map(|(k, v)| (k.clone(), *v)));
128        self.modules
129            .extend(overlay.modules.iter().map(|(k, v)| (k.clone(), *v)));
130        self.visibility.merge_with(overlay.visibility.clone());
131    }
132
133    /// Merge another bindings map on top of this one (other wins on name clash).
134    pub fn extend_from_bindings(&mut self, other: &ScopeBindings) {
135        self.decls
136            .extend(other.decls.iter().map(|(k, v)| (k.clone(), *v)));
137        self.modules
138            .extend(other.modules.iter().map(|(k, v)| (k.clone(), *v)));
139        self.visibility.merge_with(other.visibility.clone());
140    }
141}
142
143impl Visibility {
144    pub fn new() -> Self {
145        Visibility {
146            decl_ids: HashMap::new(),
147        }
148    }
149
150    pub fn is_decl_id_visible(&self, decl_id: &DeclId) -> bool {
151        *self.decl_ids.get(decl_id).unwrap_or(&true) // by default it's visible
152    }
153
154    pub fn hide_decl_id(&mut self, decl_id: &DeclId) {
155        self.decl_ids.insert(*decl_id, false);
156    }
157
158    pub fn use_decl_id(&mut self, decl_id: &DeclId) {
159        self.decl_ids.insert(*decl_id, true);
160    }
161
162    /// Overwrite own values with the other
163    pub fn merge_with(&mut self, other: Visibility) {
164        self.decl_ids.extend(other.decl_ids);
165    }
166
167    /// Take new values from the other but keep own values
168    pub fn append(&mut self, other: &Visibility) {
169        for (decl_id, visible) in other.decl_ids.iter() {
170            if !self.decl_ids.contains_key(decl_id) {
171                self.decl_ids.insert(*decl_id, *visible);
172            }
173        }
174    }
175}
176
177/// Decl visibility resolved across the overlay frames walked so far, innermost frame first.
178///
179/// Name lookups walk the active overlays from the innermost one outwards. A decl is visible
180/// unless one of the frames walked so far has an explicit entry hiding it, and the innermost
181/// frame with an entry for the decl wins. This borrows each frame's [`Visibility`] instead of
182/// merging the maps: merging copied every entry of every frame on every lookup, which made
183/// `find_decl` (called for every command word the parser sees) cost as much as the maps were
184/// large.
185#[derive(Debug, Default)]
186pub struct VisibilityStack<'a> {
187    layers: Vec<&'a Visibility>,
188}
189
190impl<'a> VisibilityStack<'a> {
191    /// Add the visibility of the next (outer) frame. Frames pushed earlier take precedence.
192    ///
193    /// A frame that hides nothing can never answer a lookup, so it is not recorded; this keeps
194    /// the common lookup (no hidden declarations anywhere) free of allocation.
195    pub fn push(&mut self, visibility: &'a Visibility) {
196        if !visibility.decl_ids.is_empty() {
197            self.layers.push(visibility);
198        }
199    }
200
201    /// Whether `decl_id` is visible given the frames pushed so far.
202    pub fn is_decl_id_visible(&self, decl_id: &DeclId) -> bool {
203        self.layers
204            .iter()
205            .find_map(|visibility| visibility.decl_ids.get(decl_id))
206            .copied()
207            .unwrap_or(true) // by default it's visible
208    }
209}
210
211#[derive(Debug, Clone)]
212pub struct ScopeFrame {
213    /// List of both active and inactive overlays in this ScopeFrame.
214    ///
215    /// The order does not have any meaning. Indexed locally (within this ScopeFrame) by
216    /// OverlayIds in active_overlays.
217    pub overlays: Vec<(Vec<u8>, OverlayFrame)>,
218
219    /// List of currently active overlays.
220    ///
221    /// Order is significant: The last item points at the last activated overlay.
222    pub active_overlays: Vec<OverlayId>,
223
224    /// Removed overlays from previous scope frames / permanent state
225    pub removed_overlays: Vec<Vec<u8>>,
226
227    /// temporary storage for predeclarations
228    pub predecls: DeclNameMap,
229}
230
231impl ScopeFrame {
232    pub fn new() -> Self {
233        Self {
234            overlays: vec![],
235            active_overlays: vec![],
236            removed_overlays: vec![],
237            predecls: DeclNameMap::new(),
238        }
239    }
240
241    pub fn with_empty_overlay(name: Vec<u8>, origin: ModuleId, prefixed: bool) -> Self {
242        Self {
243            overlays: vec![(name, OverlayFrame::from_origin(origin, prefixed))],
244            active_overlays: vec![OverlayId::new(0)],
245            removed_overlays: vec![],
246            predecls: DeclNameMap::new(),
247        }
248    }
249
250    pub fn get_var(&self, var_name: &[u8]) -> Option<&VarId> {
251        for overlay_id in self.active_overlays.iter().rev() {
252            if let Some(var_id) = self
253                .overlays
254                .get(overlay_id.get())
255                .expect("internal error: missing overlay")
256                .1
257                .vars
258                .get(var_name)
259            {
260                return Some(var_id);
261            }
262        }
263
264        None
265    }
266
267    pub fn active_overlay_ids(&self, removed_overlays: &mut Vec<Vec<u8>>) -> Vec<OverlayId> {
268        for name in &self.removed_overlays {
269            if !removed_overlays.contains(name) {
270                removed_overlays.push(name.clone());
271            }
272        }
273
274        self.active_overlays
275            .iter()
276            .filter(|id| {
277                !removed_overlays
278                    .iter()
279                    .any(|name| name == self.get_overlay_name(**id))
280            })
281            .copied()
282            .collect()
283    }
284
285    pub fn active_overlays<'a, 'b>(
286        &'b self,
287        removed_overlays: &'a mut Vec<Vec<u8>>,
288    ) -> impl DoubleEndedIterator<Item = &'b OverlayFrame> + 'a
289    where
290        'b: 'a,
291    {
292        // Same filtering as `active_overlay_ids`, but iterated lazily: this runs for every scope
293        // frame on every declaration or variable lookup, so it must not allocate.
294        for name in &self.removed_overlays {
295            if !removed_overlays.contains(name) {
296                removed_overlays.push(name.clone());
297            }
298        }
299        let removed_overlays: &'a Vec<Vec<u8>> = removed_overlays;
300
301        self.active_overlays
302            .iter()
303            .filter(move |id| {
304                !removed_overlays
305                    .iter()
306                    .any(|name| name == self.get_overlay_name(**id))
307            })
308            .map(|id| self.get_overlay(*id))
309    }
310
311    pub fn active_overlay_names(&self, removed_overlays: &mut Vec<Vec<u8>>) -> Vec<&[u8]> {
312        self.active_overlay_ids(removed_overlays)
313            .iter()
314            .map(|id| self.get_overlay_name(*id))
315            .collect()
316    }
317
318    pub fn get_overlay_name(&self, overlay_id: OverlayId) -> &[u8] {
319        &self
320            .overlays
321            .get(overlay_id.get())
322            .expect("internal error: missing overlay")
323            .0
324    }
325
326    pub fn get_overlay(&self, overlay_id: OverlayId) -> &OverlayFrame {
327        &self
328            .overlays
329            .get(overlay_id.get())
330            .expect("internal error: missing overlay")
331            .1
332    }
333
334    pub fn get_overlay_mut(&mut self, overlay_id: OverlayId) -> &mut OverlayFrame {
335        &mut self
336            .overlays
337            .get_mut(overlay_id.get())
338            .expect("internal error: missing overlay")
339            .1
340    }
341
342    pub fn find_overlay(&self, name: &[u8]) -> Option<OverlayId> {
343        self.overlays
344            .iter()
345            .position(|(n, _)| n == name)
346            .map(OverlayId::new)
347    }
348
349    pub fn find_active_overlay(&self, name: &[u8]) -> Option<OverlayId> {
350        self.overlays
351            .iter()
352            .position(|(n, _)| n == name)
353            .map(OverlayId::new)
354            .filter(|id| self.active_overlays.contains(id))
355    }
356}
357
358#[derive(Debug, Clone)]
359pub struct OverlayFrame {
360    pub vars: HashMap<Vec<u8>, VarId>,
361    pub predecls: DeclNameMap, // temporary storage for predeclarations
362    pub decls: DeclNameMap,
363    pub modules: HashMap<Vec<u8>, ModuleId>,
364    pub shadowed_vars: Vec<VarId>,
365    pub visibility: Visibility,
366    pub origin: ModuleId, // The original module the overlay was created from
367    pub prefixed: bool,   // Whether the overlay has definitions prefixed with its name
368}
369
370impl OverlayFrame {
371    pub fn from_origin(origin: ModuleId, prefixed: bool) -> Self {
372        Self {
373            vars: HashMap::new(),
374            predecls: DeclNameMap::new(),
375            decls: DeclNameMap::new(),
376            modules: HashMap::new(),
377            shadowed_vars: Vec::new(),
378            visibility: Visibility::new(),
379            origin,
380            prefixed,
381        }
382    }
383
384    pub fn insert_decl(&mut self, name: Vec<u8>, decl_id: DeclId) -> Option<DeclId> {
385        self.decls.insert(name, decl_id)
386    }
387
388    pub fn insert_module(&mut self, name: Vec<u8>, module_id: ModuleId) -> Option<ModuleId> {
389        self.modules.insert(name, module_id)
390    }
391
392    pub fn insert_variable(&mut self, name: Vec<u8>, variable_id: VarId) -> Option<VarId> {
393        let res = self.vars.insert(name, variable_id);
394        if let Some(old_id) = res {
395            self.shadowed_vars.push(old_id);
396        }
397        res
398    }
399
400    pub fn get_decl(&self, name: &[u8]) -> Option<DeclId> {
401        self.decls.get(name).cloned()
402    }
403}
404
405impl Default for Visibility {
406    fn default() -> Self {
407        Self::new()
408    }
409}
410
411impl Default for ScopeFrame {
412    fn default() -> Self {
413        Self::new()
414    }
415}