Modules

Project source code is available at https://github.com/GaijinEntertainment/quirrel

Quirrel provides modules functionality via separate library. Modules are useful to encapsulate code (only explicitly exported data/methods become available outside), to make the code reusable and to prevent contaminating global namespace (root table). The provided reference implementation also allows reloading of script code while keeping data intact.

Script API

Module code is executed with a special table as context (‘this’). It has the following functions bound:

require(filename)

If given module was not loaded yet, reads the file, executes it and returns module exports. Module exports are data returned by module body code. If module was loaded before, just returns its exports. If file was not found, throws an error.

require_optional(filename)

The same as require(), but for missing file it returns null instead of throwing an error.

persist(key, initializer)

Used to keep data between sequential execution of the same file for hot reloading. For the first run of the module calls provided initializer function and returns the result. Also it stores a reference to the result in a special table that is later reused when the file with the same name is executed. The ‘key’ parameter is the unique-per-module identifier of the variable.

Example:

let counter = persist("counter", @() {value=0})
keepref(var)

An utility function that keeps a reference to the given object. Might be useful to keep an object from deleting itself if it is not exported outside the module.

Also module ‘this’ table contains field __name__ which is set to file name for module loaded by script require() function or parameter __name__ passed to C++ requireModule() function (defaults to “__main__” for entry point script).

Module that allow to list all registered native modules.

Example:

require("quirrel.native_modules").each(println)

Will print all currently registered native modules.

Native API

Module functionality is implemented in SqModules C++ class with the following public methods:

SqModules::SqModules(HSQUIRRELVM vm)

Constructs a module manager instance for the given Quirrel VM.

HSQUIRRELVM SqModules::getVM()

Returns module manager VM.

bool SqModules::requireModule(const char *fn, bool must_exist, const char *__name__, SqObjPtr &exports, std::string &out_err_msg)
Parameters
  • const char *fn – name of the file to load

  • bool must_exist – if set to false treat missing file as success (return true)

  • const char *__name__ – value of module’s __name__ field (set nullptr to use actual file name)

  • SqObjPtr &exports – object to store export to

  • std::string &out_err_msg – receives error message if call failed

Returns

true if succeeded

Remarks

Actually this is a function bound to script as require()

Loads and executes script module or just returns its exports if it was already run.

bool SqModules::reloadModule(const char *fn, bool must_exist, const char *__name__, SqObjPtr &exports, std::string &out_err_msg)

Basically the same as requireModule, but it unloads all previously loaded modules and newly executes all modules pulled by require() calls. This can also be used for initial module execution - so that the first call to reloadModule(entry_point_fn) will load all modules and initialize persistent data and subsequent calls to reloadModule(entry_point_fn) will reload the module and all it depends on while reusing kept persistent data.

bool SqModules::addNativeModule(const char *module_name, const SqObjPtr &exports)

Registers a Quirrel object ‘exports’ under the provided ‘module_name’, so that it can be require()-d in script.

void SqModules::registerBaseLibs()

Registers standard math, string and blob libraries as native modules (“math”, “string” and “blob” respectively)

void SqModules::registerSystemLib()

Registers standard ‘system’ library as “system” native module

void SqModules::registerIoLib()

Registers standard ‘io’ library as “io” native module