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_info
byset_parser_info
, so we can retrieve it in runtime. - resolve import from
ImportPattern
toResolvedImportPattern
.
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