nu_protocol/
module.rs

1use crate::{
2    ast::ImportPatternMember, engine::StateWorkingSet, BlockId, DeclId, FileId, ModuleId,
3    ParseError, Span, Value, VarId,
4};
5
6use crate::parser_path::ParserPath;
7use indexmap::IndexMap;
8
9pub struct ResolvedImportPattern {
10    pub decls: Vec<(Vec<u8>, DeclId)>,
11    pub modules: Vec<(Vec<u8>, ModuleId)>,
12    pub constants: Vec<(Vec<u8>, VarId)>,
13    /// TODO: for referencing module name as a record, e.g. `$module_name.const_name`
14    /// values got multiple duplicates in memory.
15    pub constant_values: Vec<(Vec<u8>, Value)>,
16}
17
18impl ResolvedImportPattern {
19    pub fn new(
20        decls: Vec<(Vec<u8>, DeclId)>,
21        modules: Vec<(Vec<u8>, ModuleId)>,
22        constants: Vec<(Vec<u8>, VarId)>,
23        constant_values: Vec<(Vec<u8>, Value)>,
24    ) -> Self {
25        ResolvedImportPattern {
26            decls,
27            modules,
28            constants,
29            constant_values,
30        }
31    }
32}
33
34/// Collection of definitions that can be exported from a module
35#[derive(Debug, Clone)]
36pub struct Module {
37    pub name: Vec<u8>,
38    pub decls: IndexMap<Vec<u8>, DeclId>,
39    pub submodules: IndexMap<Vec<u8>, ModuleId>,
40    pub constants: IndexMap<Vec<u8>, VarId>,
41    pub env_block: Option<BlockId>, // `export-env { ... }` block
42    pub main: Option<DeclId>,       // `export def main`
43    pub span: Option<Span>,
44    pub imported_modules: Vec<ModuleId>, // use other_module.nu
45    pub file: Option<(ParserPath, FileId)>,
46}
47
48impl Module {
49    pub fn new(name: Vec<u8>) -> Self {
50        Module {
51            name,
52            decls: IndexMap::new(),
53            submodules: IndexMap::new(),
54            constants: IndexMap::new(),
55            env_block: None,
56            main: None,
57            span: None,
58            imported_modules: vec![],
59            file: None,
60        }
61    }
62
63    pub fn from_span(name: Vec<u8>, span: Span) -> Self {
64        Module {
65            name,
66            decls: IndexMap::new(),
67            submodules: IndexMap::new(),
68            constants: IndexMap::new(),
69            env_block: None,
70            main: None,
71            span: Some(span),
72            imported_modules: vec![],
73            file: None,
74        }
75    }
76
77    pub fn name(&self) -> Vec<u8> {
78        self.name.clone()
79    }
80
81    pub fn add_decl(&mut self, name: Vec<u8>, decl_id: DeclId) -> Option<DeclId> {
82        self.decls.insert(name, decl_id)
83    }
84
85    pub fn add_submodule(&mut self, name: Vec<u8>, module_id: ModuleId) -> Option<ModuleId> {
86        self.submodules.insert(name, module_id)
87    }
88
89    pub fn add_variable(&mut self, name: Vec<u8>, var_id: VarId) -> Option<VarId> {
90        self.constants.insert(name, var_id)
91    }
92
93    pub fn add_env_block(&mut self, block_id: BlockId) {
94        self.env_block = Some(block_id);
95    }
96
97    pub fn track_imported_modules(&mut self, module_id: &[ModuleId]) {
98        for m in module_id {
99            self.imported_modules.push(*m)
100        }
101    }
102
103    pub fn has_decl(&self, name: &[u8]) -> bool {
104        if name == self.name && self.main.is_some() {
105            return true;
106        }
107
108        self.decls.contains_key(name)
109    }
110
111    /// Resolve `members` from given module, which is indicated by `self_id` to import.
112    ///
113    /// When resolving, all modules are recorded in `imported_modules`.
114    pub fn resolve_import_pattern(
115        &self,
116        working_set: &StateWorkingSet,
117        self_id: ModuleId,
118        members: &[ImportPatternMember],
119        name_override: Option<&[u8]>, // name under the module was stored (doesn't have to be the same as self.name)
120        backup_span: Span,
121        imported_modules: &mut Vec<ModuleId>,
122    ) -> (ResolvedImportPattern, Vec<ParseError>) {
123        imported_modules.push(self_id);
124        let final_name = name_override.unwrap_or(&self.name).to_vec();
125
126        let (head, rest) = if let Some((head, rest)) = members.split_first() {
127            (head, rest)
128        } else {
129            // Import pattern was just name without any members
130            let mut decls = vec![];
131            let mut const_vids = vec![];
132            let mut const_rows = vec![];
133            let mut errors = vec![];
134
135            for (_, id) in &self.submodules {
136                let submodule = working_set.get_module(*id);
137                let span = submodule.span.or(self.span).unwrap_or(backup_span);
138
139                let (sub_results, sub_errors) = submodule.resolve_import_pattern(
140                    working_set,
141                    *id,
142                    &[],
143                    None,
144                    span,
145                    imported_modules,
146                );
147                errors.extend(sub_errors);
148
149                for (sub_name, sub_decl_id) in sub_results.decls {
150                    let mut new_name = final_name.clone();
151                    new_name.push(b' ');
152                    new_name.extend(sub_name);
153
154                    decls.push((new_name, sub_decl_id));
155                }
156
157                const_vids.extend(sub_results.constants);
158                const_rows.extend(sub_results.constant_values);
159            }
160
161            decls.extend(self.decls_with_head(&final_name));
162
163            for (name, var_id) in self.consts() {
164                match working_set.get_constant(var_id) {
165                    Ok(const_val) => {
166                        const_vids.push((name.clone(), var_id));
167                        const_rows.push((name, const_val.clone()))
168                    }
169                    Err(err) => errors.push(err),
170                }
171            }
172
173            let span = self.span.unwrap_or(backup_span);
174
175            // only needs to bring `$module` with a record value if it defines any constants.
176            let constant_values = if const_rows.is_empty() {
177                vec![]
178            } else {
179                vec![(
180                    normalize_module_name(&final_name),
181                    Value::record(
182                        const_rows
183                            .into_iter()
184                            .map(|(name, val)| (String::from_utf8_lossy(&name).to_string(), val))
185                            .collect(),
186                        span,
187                    ),
188                )]
189            };
190
191            return (
192                ResolvedImportPattern::new(
193                    decls,
194                    vec![(final_name.clone(), self_id)],
195                    const_vids,
196                    constant_values,
197                ),
198                errors,
199            );
200        };
201
202        match head {
203            ImportPatternMember::Name { name, span } => {
204                // raise errors if user wants to do something like this:
205                // `use a b c`: but b is not a sub-module of a.
206                let errors = if !rest.is_empty() && self.submodules.get(name).is_none() {
207                    vec![ParseError::WrongImportPattern(
208                        format!("Trying to import something but the parent `{}` is not a module, maybe you want to try `use <module> [<name1>, <name2>]`", String::from_utf8_lossy(name)),
209                        rest[0].span(),
210                    )]
211                } else {
212                    vec![]
213                };
214
215                if name == b"main" {
216                    if let Some(main_decl_id) = self.main {
217                        (
218                            ResolvedImportPattern::new(
219                                vec![(final_name, main_decl_id)],
220                                vec![],
221                                vec![],
222                                vec![],
223                            ),
224                            errors,
225                        )
226                    } else {
227                        (
228                            ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
229                            vec![ParseError::ExportNotFound(*span)],
230                        )
231                    }
232                } else if let Some(decl_id) = self.decls.get(name) {
233                    (
234                        ResolvedImportPattern::new(
235                            vec![(name.clone(), *decl_id)],
236                            vec![],
237                            vec![],
238                            vec![],
239                        ),
240                        errors,
241                    )
242                } else if let Some(var_id) = self.constants.get(name) {
243                    match working_set.get_constant(*var_id) {
244                        Ok(_) => (
245                            ResolvedImportPattern::new(
246                                vec![],
247                                vec![],
248                                vec![(name.clone(), *var_id)],
249                                vec![],
250                            ),
251                            errors,
252                        ),
253                        Err(err) => (
254                            ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
255                            vec![err],
256                        ),
257                    }
258                } else if let Some(submodule_id) = self.submodules.get(name) {
259                    let submodule = working_set.get_module(*submodule_id);
260                    submodule.resolve_import_pattern(
261                        working_set,
262                        *submodule_id,
263                        rest,
264                        None,
265                        self.span.unwrap_or(backup_span),
266                        imported_modules,
267                    )
268                } else {
269                    (
270                        ResolvedImportPattern::new(vec![], vec![], vec![], vec![]),
271                        vec![ParseError::ExportNotFound(*span)],
272                    )
273                }
274            }
275            ImportPatternMember::Glob { .. } => {
276                let mut decls = vec![];
277                let mut submodules = vec![];
278                let mut constants = vec![];
279                let mut constant_values = vec![];
280                let mut errors = vec![];
281
282                for (_, id) in &self.submodules {
283                    let submodule = working_set.get_module(*id);
284                    let (sub_results, sub_errors) = submodule.resolve_import_pattern(
285                        working_set,
286                        *id,
287                        &[],
288                        None,
289                        self.span.unwrap_or(backup_span),
290                        imported_modules,
291                    );
292                    decls.extend(sub_results.decls);
293
294                    submodules.extend(sub_results.modules);
295                    constants.extend(sub_results.constants);
296                    constant_values.extend(sub_results.constant_values);
297                    errors.extend(sub_errors);
298                }
299
300                decls.extend(self.decls());
301                for (name, var_id) in self.constants.iter() {
302                    match working_set.get_constant(*var_id) {
303                        Ok(_) => {
304                            constants.push((name.clone(), *var_id));
305                        }
306                        Err(err) => {
307                            errors.push(err);
308                        }
309                    }
310                }
311                submodules.extend(self.submodules());
312
313                (
314                    ResolvedImportPattern::new(decls, submodules, constants, constant_values),
315                    errors,
316                )
317            }
318            ImportPatternMember::List { names } => {
319                let mut decls = vec![];
320                let mut modules = vec![];
321                let mut constants = vec![];
322                let mut constant_values = vec![];
323                let mut errors = vec![];
324
325                for (name, span) in names {
326                    if name == b"main" {
327                        if let Some(main_decl_id) = self.main {
328                            decls.push((final_name.clone(), main_decl_id));
329                        } else {
330                            errors.push(ParseError::ExportNotFound(*span));
331                        }
332                    } else if let Some(decl_id) = self.decls.get(name) {
333                        decls.push((name.clone(), *decl_id));
334                    } else if let Some(var_id) = self.constants.get(name) {
335                        match working_set.get_constant(*var_id) {
336                            Ok(_) => constants.push((name.clone(), *var_id)),
337                            Err(err) => errors.push(err),
338                        }
339                    } else if let Some(submodule_id) = self.submodules.get(name) {
340                        let submodule = working_set.get_module(*submodule_id);
341                        let (sub_results, sub_errors) = submodule.resolve_import_pattern(
342                            working_set,
343                            *submodule_id,
344                            rest,
345                            None,
346                            self.span.unwrap_or(backup_span),
347                            imported_modules,
348                        );
349
350                        decls.extend(sub_results.decls);
351                        modules.extend(sub_results.modules);
352                        constants.extend(sub_results.constants);
353                        constant_values.extend(sub_results.constant_values);
354                        errors.extend(sub_errors);
355                    } else {
356                        errors.push(ParseError::ExportNotFound(*span));
357                    }
358                }
359
360                (
361                    ResolvedImportPattern::new(decls, modules, constants, constant_values),
362                    errors,
363                )
364            }
365        }
366    }
367
368    pub fn decl_name_with_head(&self, name: &[u8], head: &[u8]) -> Option<Vec<u8>> {
369        if self.has_decl(name) {
370            let mut new_name = head.to_vec();
371            new_name.push(b' ');
372            new_name.extend(name);
373            Some(new_name)
374        } else {
375            None
376        }
377    }
378
379    pub fn decls_with_head(&self, head: &[u8]) -> Vec<(Vec<u8>, DeclId)> {
380        let mut result: Vec<(Vec<u8>, DeclId)> = self
381            .decls
382            .iter()
383            .map(|(name, id)| {
384                let mut new_name = head.to_vec();
385                new_name.push(b' ');
386                new_name.extend(name);
387                (new_name, *id)
388            })
389            .collect();
390
391        if let Some(decl_id) = self.main {
392            result.push((self.name.clone(), decl_id));
393        }
394
395        result
396    }
397
398    pub fn consts(&self) -> Vec<(Vec<u8>, VarId)> {
399        self.constants
400            .iter()
401            .map(|(name, id)| (name.to_vec(), *id))
402            .collect()
403    }
404
405    pub fn decl_names_with_head(&self, head: &[u8]) -> Vec<Vec<u8>> {
406        let mut result: Vec<Vec<u8>> = self
407            .decls
408            .keys()
409            .map(|name| {
410                let mut new_name = head.to_vec();
411                new_name.push(b' ');
412                new_name.extend(name);
413                new_name
414            })
415            .collect();
416
417        if self.main.is_some() {
418            result.push(self.name.clone());
419        }
420
421        result
422    }
423
424    pub fn decls(&self) -> Vec<(Vec<u8>, DeclId)> {
425        let mut result: Vec<(Vec<u8>, DeclId)> = self
426            .decls
427            .iter()
428            .map(|(name, id)| (name.clone(), *id))
429            .collect();
430
431        if let Some(decl_id) = self.main {
432            result.push((self.name.clone(), decl_id));
433        }
434
435        result
436    }
437
438    pub fn submodules(&self) -> Vec<(Vec<u8>, ModuleId)> {
439        self.submodules
440            .iter()
441            .map(|(name, id)| (name.clone(), *id))
442            .collect()
443    }
444
445    pub fn decl_names(&self) -> Vec<Vec<u8>> {
446        let mut result: Vec<Vec<u8>> = self.decls.keys().cloned().collect();
447
448        if self.main.is_some() {
449            result.push(self.name.clone());
450        }
451
452        result
453    }
454}
455
456/// normalize module names for exporting as record constant
457fn normalize_module_name(bytes: &[u8]) -> Vec<u8> {
458    bytes
459        .iter()
460        .map(|x| match is_identifier_byte(*x) {
461            true => *x,
462            false => b'_',
463        })
464        .collect()
465}
466
467fn is_identifier_byte(b: u8) -> bool {
468    b != b'.'
469        && b != b'['
470        && b != b'('
471        && b != b'{'
472        && b != b'+'
473        && b != b'-'
474        && b != b'*'
475        && b != b'^'
476        && b != b'/'
477        && b != b'='
478        && b != b'!'
479        && b != b'<'
480        && b != b'>'
481        && b != b'&'
482        && b != b'|'
483}