-
Notifications
You must be signed in to change notification settings - Fork 0
Importing modules
Import brings other namespace visible to current namespace so that its symbols can be referred via dot-notation.
Values represented by module symbols are like values in current namespace. Function/procedure implementation in module see namespace in which that modules namespace is root of the scope.
Module implementation is searched in following ways (in that order):
- See if its standard library module (those are built-in)
- From module cache (if it's there it's just returned from there)
- Search file named "(module-name).fnl" in current working directory and all its subdirectories
- Search file named "(module-name).fnl" in directory read from FUNLPATH environment variable and all its subdirectories (if FUNLPATH is set)
- Search file named "(module-name).fnl" from any package files (.fpack) in current working directory and all its subdirectories
- Search file named "(module-name).fnl" from any package files (.fpack) in directory read from FUNLPATH environment variable and all its subdirectories (if FUNLPATH is set)
- Search file named "(module-name).so" in current working directory and all its subdirectories
- Search file named "(module-name).so" in directory read from FUNLPATH environment variable and all its subdirectories (if FUNLPATH is set)
By default module name is source file name with ".fnl" (or ".so") file extension.
Module can be implemented as Go plugin library (supported in FreeBSD/Linux/Mac, not in Windows) so that module implementation is shared object library (.so). Steps 5 and 6 are made to find such libraries.
If module is implemented in FunL source file (.fnl) following steps are executed:
- source file content is read
- content is tokenized and parsed
- module top level let-definitions are evaluated and imports are done
- namespace (root level frame) is put to module cache
- module is added to callers scope
If module is implemented as shared object library (.so) following steps are done:
- library is loaded
- root level frame is created
- setup of module is done by calling "Setup" Go function in library which makes initializations (adds symbols to root level frame)
- namespace (root level frame) is put to module cache
- module is added to callers scope
If FUNLPATH environment variable is set it's used so that module implementation (file) is searched from directory which is FUNLPATH content and from all its subdirectories. FUNLPATH accepts directory path in Windows format and in Unix/Linux format.
Example: setting FUNLPATH in Linux:
export FUNLPATH=/mnt/any_dir/some_path/
export FUNLPATH=/mnt/any_dir/some_path
Example: setting FUNLPATH in Windows:
set FUNLPATH=C:\Users\any_dir\some_path
Example: setting FUNLPATH in Cygwin:
export FUNLPATH="C:\Users\any_dir\some_path"
After modules are read and loaded interpreter puts those to module cache which global storage of modules. Whenever module is found from module cache it's used from there and not searched/read from file anymore. Module cache is common for all fibers in interpreter.
Several FunL source files can be combined to one package file. Imports can be directed to use package file.
See more about Packages
There's alternative way to import modules by using imp -operator. It returns module as map value where symbol names are keys (string type) and values related to symbols are values in map. So module can be handled this way as a value.
Example: module implementation
ns some_module
some-func = func()
'some function called'
end
endns
Example: use REPL to demonstrate getting module (some_module) to map m and call modules function some-func:
Welcome to FunL REPL (interactive command shell)
funl>
funl> let(m imp(some_module))
map('some-func' : func-value: file: /Users/anydir/some_path/some_module.fnl line: 4 pos: 17)
funl>
funl> call(get(m 'some-func'))
some function called