Skip to main content

nu_protocol/engine/
overlay.rs

1use crate::{DeclId, ModuleId, OverlayId, VarId};
2use std::collections::HashMap;
3
4pub static DEFAULT_OVERLAY_NAME: &str = "zero";
5
6/// Tells whether a decl is visible or not
7#[derive(Debug, Clone)]
8pub struct Visibility {
9    decl_ids: HashMap<DeclId, bool>,
10}
11
12/// Name bindings introduced while parsing a single block/closure scope.
13///
14/// Nested scopes discard their name maps on `exit_scope`; this snapshot is stored on the
15/// [`Block`](crate::ast::Block) so `scope` commands can report locals at runtime.
16///
17/// # Lifecycle
18///
19/// 1. **Parse**: [`StateWorkingSet::snapshot_scope_bindings`] copies decls/modules from the
20///    innermost scope frame into a `ScopeBindings` attached to the block, immediately before
21///    the matching `exit_scope`.
22/// 2. **Eval**: whole blocks push bindings on [`Stack::active_scope_bindings`] in
23///    `eval_ir_block`. Keyword bodies that are IR-inlined record
24///    [`ScopeRegion`](crate::ir::ScopeRegion)s on the parent [`IrBlock`](crate::ir::IrBlock);
25///    `scope` matches the current instruction index against those regions.
26#[derive(Debug, Clone, Default)]
27pub struct ScopeBindings {
28    pub decls: HashMap<Vec<u8>, DeclId>,
29    pub modules: HashMap<Vec<u8>, ModuleId>,
30    pub visibility: Visibility,
31}
32
33impl ScopeBindings {
34    pub fn is_empty(&self) -> bool {
35        self.decls.is_empty() && self.modules.is_empty() && self.visibility.decl_ids.is_empty()
36    }
37
38    /// Merge decls, modules, and visibility from an overlay frame (other wins on name clash).
39    pub fn extend_from_overlay(&mut self, overlay: &OverlayFrame) {
40        self.decls
41            .extend(overlay.decls.iter().map(|(k, v)| (k.clone(), *v)));
42        self.modules
43            .extend(overlay.modules.iter().map(|(k, v)| (k.clone(), *v)));
44        self.visibility.merge_with(overlay.visibility.clone());
45    }
46
47    /// Merge another bindings map on top of this one (other wins on name clash).
48    pub fn extend_from_bindings(&mut self, other: &ScopeBindings) {
49        self.decls
50            .extend(other.decls.iter().map(|(k, v)| (k.clone(), *v)));
51        self.modules
52            .extend(other.modules.iter().map(|(k, v)| (k.clone(), *v)));
53        self.visibility.merge_with(other.visibility.clone());
54    }
55}
56
57impl Visibility {
58    pub fn new() -> Self {
59        Visibility {
60            decl_ids: HashMap::new(),
61        }
62    }
63
64    pub fn is_decl_id_visible(&self, decl_id: &DeclId) -> bool {
65        *self.decl_ids.get(decl_id).unwrap_or(&true) // by default it's visible
66    }
67
68    pub fn hide_decl_id(&mut self, decl_id: &DeclId) {
69        self.decl_ids.insert(*decl_id, false);
70    }
71
72    pub fn use_decl_id(&mut self, decl_id: &DeclId) {
73        self.decl_ids.insert(*decl_id, true);
74    }
75
76    /// Overwrite own values with the other
77    pub fn merge_with(&mut self, other: Visibility) {
78        self.decl_ids.extend(other.decl_ids);
79    }
80
81    /// Take new values from the other but keep own values
82    pub fn append(&mut self, other: &Visibility) {
83        for (decl_id, visible) in other.decl_ids.iter() {
84            if !self.decl_ids.contains_key(decl_id) {
85                self.decl_ids.insert(*decl_id, *visible);
86            }
87        }
88    }
89}
90
91#[derive(Debug, Clone)]
92pub struct ScopeFrame {
93    /// List of both active and inactive overlays in this ScopeFrame.
94    ///
95    /// The order does not have any meaning. Indexed locally (within this ScopeFrame) by
96    /// OverlayIds in active_overlays.
97    pub overlays: Vec<(Vec<u8>, OverlayFrame)>,
98
99    /// List of currently active overlays.
100    ///
101    /// Order is significant: The last item points at the last activated overlay.
102    pub active_overlays: Vec<OverlayId>,
103
104    /// Removed overlays from previous scope frames / permanent state
105    pub removed_overlays: Vec<Vec<u8>>,
106
107    /// temporary storage for predeclarations
108    pub predecls: HashMap<Vec<u8>, DeclId>,
109}
110
111impl ScopeFrame {
112    pub fn new() -> Self {
113        Self {
114            overlays: vec![],
115            active_overlays: vec![],
116            removed_overlays: vec![],
117            predecls: HashMap::new(),
118        }
119    }
120
121    pub fn with_empty_overlay(name: Vec<u8>, origin: ModuleId, prefixed: bool) -> Self {
122        Self {
123            overlays: vec![(name, OverlayFrame::from_origin(origin, prefixed))],
124            active_overlays: vec![OverlayId::new(0)],
125            removed_overlays: vec![],
126            predecls: HashMap::new(),
127        }
128    }
129
130    pub fn get_var(&self, var_name: &[u8]) -> Option<&VarId> {
131        for overlay_id in self.active_overlays.iter().rev() {
132            if let Some(var_id) = self
133                .overlays
134                .get(overlay_id.get())
135                .expect("internal error: missing overlay")
136                .1
137                .vars
138                .get(var_name)
139            {
140                return Some(var_id);
141            }
142        }
143
144        None
145    }
146
147    pub fn active_overlay_ids(&self, removed_overlays: &mut Vec<Vec<u8>>) -> Vec<OverlayId> {
148        for name in &self.removed_overlays {
149            if !removed_overlays.contains(name) {
150                removed_overlays.push(name.clone());
151            }
152        }
153
154        self.active_overlays
155            .iter()
156            .filter(|id| {
157                !removed_overlays
158                    .iter()
159                    .any(|name| name == self.get_overlay_name(**id))
160            })
161            .copied()
162            .collect()
163    }
164
165    pub fn active_overlays<'a, 'b>(
166        &'b self,
167        removed_overlays: &'a mut Vec<Vec<u8>>,
168    ) -> impl DoubleEndedIterator<Item = &'b OverlayFrame> + 'a
169    where
170        'b: 'a,
171    {
172        self.active_overlay_ids(removed_overlays)
173            .into_iter()
174            .map(|id| self.get_overlay(id))
175    }
176
177    pub fn active_overlay_names(&self, removed_overlays: &mut Vec<Vec<u8>>) -> Vec<&[u8]> {
178        self.active_overlay_ids(removed_overlays)
179            .iter()
180            .map(|id| self.get_overlay_name(*id))
181            .collect()
182    }
183
184    pub fn get_overlay_name(&self, overlay_id: OverlayId) -> &[u8] {
185        &self
186            .overlays
187            .get(overlay_id.get())
188            .expect("internal error: missing overlay")
189            .0
190    }
191
192    pub fn get_overlay(&self, overlay_id: OverlayId) -> &OverlayFrame {
193        &self
194            .overlays
195            .get(overlay_id.get())
196            .expect("internal error: missing overlay")
197            .1
198    }
199
200    pub fn get_overlay_mut(&mut self, overlay_id: OverlayId) -> &mut OverlayFrame {
201        &mut self
202            .overlays
203            .get_mut(overlay_id.get())
204            .expect("internal error: missing overlay")
205            .1
206    }
207
208    pub fn find_overlay(&self, name: &[u8]) -> Option<OverlayId> {
209        self.overlays
210            .iter()
211            .position(|(n, _)| n == name)
212            .map(OverlayId::new)
213    }
214
215    pub fn find_active_overlay(&self, name: &[u8]) -> Option<OverlayId> {
216        self.overlays
217            .iter()
218            .position(|(n, _)| n == name)
219            .map(OverlayId::new)
220            .filter(|id| self.active_overlays.contains(id))
221    }
222}
223
224#[derive(Debug, Clone)]
225pub struct OverlayFrame {
226    pub vars: HashMap<Vec<u8>, VarId>,
227    pub predecls: HashMap<Vec<u8>, DeclId>, // temporary storage for predeclarations
228    pub decls: HashMap<Vec<u8>, DeclId>,
229    pub modules: HashMap<Vec<u8>, ModuleId>,
230    pub shadowed_vars: Vec<VarId>,
231    pub visibility: Visibility,
232    pub origin: ModuleId, // The original module the overlay was created from
233    pub prefixed: bool,   // Whether the overlay has definitions prefixed with its name
234}
235
236impl OverlayFrame {
237    pub fn from_origin(origin: ModuleId, prefixed: bool) -> Self {
238        Self {
239            vars: HashMap::new(),
240            predecls: HashMap::new(),
241            decls: HashMap::new(),
242            modules: HashMap::new(),
243            shadowed_vars: Vec::new(),
244            visibility: Visibility::new(),
245            origin,
246            prefixed,
247        }
248    }
249
250    pub fn insert_decl(&mut self, name: Vec<u8>, decl_id: DeclId) -> Option<DeclId> {
251        self.decls.insert(name, decl_id)
252    }
253
254    pub fn insert_module(&mut self, name: Vec<u8>, module_id: ModuleId) -> Option<ModuleId> {
255        self.modules.insert(name, module_id)
256    }
257
258    pub fn insert_variable(&mut self, name: Vec<u8>, variable_id: VarId) -> Option<VarId> {
259        let res = self.vars.insert(name, variable_id);
260        if let Some(old_id) = res {
261            self.shadowed_vars.push(old_id);
262        }
263        res
264    }
265
266    pub fn get_decl(&self, name: &[u8]) -> Option<DeclId> {
267        self.decls.get(name).cloned()
268    }
269}
270
271impl Default for Visibility {
272    fn default() -> Self {
273        Self::new()
274    }
275}
276
277impl Default for ScopeFrame {
278    fn default() -> Self {
279        Self::new()
280    }
281}