How nushell module system works
In nushell, you can define a module like this:
# spam.nu
export const b = 3
export def a [] {
"bcde"
}
Here you define a module named span.nu, and it exports a function a. Then you can use the module like this:
use spam.nu
spam a
Here I’ll take a note how this module system works.
High level insight
use spam.nu —–> parse spam.nu, treated it as a module —-> generate Module data structure, and register it to nushell’s engine.
Then use spam.nu will bring spam into our namespace.
The main entrypoint lays inside a function called parse_module_file_or_dir, we want to parse spam.nu, which is a file, then parse_module_file_or_dir will invoke parse_module_file to parse.
How a module is parsed
A module is actually a file with source code, so we’ll go into parse_module_block, which includes lex parsing --> lite parsing --> generate block, finally it’ll generate a Module data structure.
Module data structure includes the following attributes:
name: Vec<u8>,
decls: IndexMap<Vec<u8>, DeclId> // it includes exported custom commands.
submodules: IndexMap<Vec<u8>, ModuleId> // it includes modules indside a module.
constants: IndexMap<Vec<u8>, VarId> // it includes exported const.
Ok, we have a module, what next?
Nushell will do the following 2 things:
- parse user imports into
ImportPattern, and inject it intoparser_infobyset_parser_info, so we can retrieve it in runtime. - resolve import from
ImportPatterntoResolvedImportPattern.
Nushell will resolve_import_pattern accoring to what user want to import, because we can import the following:
use spam.nu # import spam module itself.
use spam.nu a # import custom command `a` only.
use spam.nu b # import const `b` only.
For use spam.nu a and use spam.nu b cases, we needs to bring a and b into our scope directly. Then we have the following inside parse_use function:
// Extend the current scope with the module's exportables
working_set.use_decls(definitions.decls);
working_set.use_modules(definitions.modules);
working_set.use_variables(constants);
For constants, it’s a little bit special, because variables are founded in stack, we also needs to add these varaibles to stack in runtime.
Something to notes:
- nushell retrieves variables from
stack - nushell retrieves custom commands from
engine_state