mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
This extension provides the following facilities: - registering modules, - module resolvers, and - an API for retrieving a module instance given its name. A module is defined as a global static structure containing a pointer to a string which is the name of the module, and a pointer to a function which will be called when an instance of the module is needed. A module resolver is a function that accepts a string holding the name of the module and returns a `jerry_value_t` in an out-parameter and `true` if the module was found, or `false` if it was not. If it returns `true` and the out-parameter has the error flag set then the API will pass it through without caching. This extension provides a built-in module resolver which attempts to load modules that follow the above module definition. The API provided by this extension invokes all module resolvers it receives in sequence to attempt to resolve the name of a single module. After one resolver returns `true` and a `jerry_value_t` that represents the module the API stops iterating over the remaining resolvers and caches the value if its error flag is not set. It then returns the `jerry_value_t`. The API will return a `jerry_value_t` containing an error indicating that the module was not found if it reaches the end of the list of resolvers. The error it returns has an extra property `"moduleName"` the value of which is a string containing the name of the module that the API was asked to resolve. JerryScript-DCO-1.0-Signed-off-by: Gabriel Schulhof gabriel.schulhof@intel.com
187 lines
6.5 KiB
Markdown
187 lines
6.5 KiB
Markdown
# Module API
|
|
|
|
This is a JerryScript extension that provides a means of loading modules. Fundamentally, a module is a name (stored as
|
|
a string) that resolves to a `jerry_value_t`. This extension provides the function `jerryx_module_resolve()` which
|
|
accepts the name of the module being requested as well as an array of so-called "resolvers" - functions which satisfy
|
|
the signature `jerryx_module_resolver_t`. The resolvers in the list are called in sequence until one of them returns
|
|
`true` and a `jerry_value_t` in its out parameter. The value is cached if it is not an error, so subsequent requests
|
|
for the same name will not result in additional calls to the resolvers.
|
|
|
|
The purpose of having resolvers is to be able to account for the fact that different types of modules may be structured
|
|
differently and thus, for each type of module a module resolver must be supplied at the point where an instance of that
|
|
type of module is requested.
|
|
|
|
Additionally, this extension provides a means of easily defining so-called "native" JerryScript modules which can be
|
|
resolved using the JerryScript native module resolver `jerryx_module_native_resolver()`, which can be passed to
|
|
`jerryx_module_resolve()`. Note, however, that native JerryScript modules are only supported and
|
|
`jerryx_module_native_resolver()` is only compiled in if compiler support for `__attribute__` extensions is present. In
|
|
effect this means that native JerryScript modules are available only when this extension is built with GCC or
|
|
LLVM/clang. In the absence of such support, you may construct alternative module systems and provide your own resolver
|
|
to `jerryx_module_resolve()`.
|
|
|
|
`jerryscript-ext/module.h` defines the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` only if support for
|
|
native JerryScript modules is available.
|
|
|
|
## jerryx_module_resolve
|
|
|
|
**Summary**
|
|
|
|
Load a copy of a module into the current context or return one that was already loaded if it is found.
|
|
|
|
Each function in `resolvers_p` will be called in sequence until one returns `true` and fills out its out-parameter with
|
|
the `jerry_value_t` representing the requested module. If the `jerry_value_t` does not have the error flag set it will
|
|
be cached. Thus, on subsequent calls with the same value for `name`, none of the functions in `resolvers_p` will be
|
|
called.
|
|
|
|
**Prototype**
|
|
|
|
```c
|
|
jerry_value_t
|
|
jerryx_module_resolve (const jerry_char_t *name,
|
|
jerryx_module_resolver_t *resolvers_p,
|
|
size_t resolver_count);
|
|
```
|
|
|
|
- `name` - the name of the module to load
|
|
- `resolvers_p` - the list of resolvers to call in sequence
|
|
- `resolver_count` - the number of resolvers in `resolvers_p`
|
|
- return value - `jerry_value_t` representing the module that was loaded, or the error that occurred in the process.
|
|
|
|
|
|
## jerryx_module_native_resolver
|
|
|
|
**Summary**
|
|
|
|
The resolver for JerryScript modules. A pointer to this function can be passed in the second parameter to
|
|
`jerryx_module_resolve` to search for the module among the JerryScript modules built into the binary. This function is
|
|
available only if the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` is defined.
|
|
|
|
**Prototype**
|
|
|
|
```c
|
|
bool
|
|
jerryx_module_native_resolver (const jerry_char_t *name,
|
|
jerry_value_t *result)
|
|
```
|
|
- `name` - the name of the module to find
|
|
- `result` - out - place where to store the resulting module instance
|
|
- return value - `true` if the module was found and stored in `result`, and `false` otherwise
|
|
|
|
|
|
# Module data types
|
|
|
|
## jerryx_native_module_on_resolve_t
|
|
|
|
**Summary**
|
|
|
|
Function pointer type for a function that will create an instance of a native module. This type is only defined if the
|
|
preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` is defined.
|
|
|
|
**Prototype**
|
|
|
|
```c
|
|
typedef jerry_value_t (*jerryx_native_module_on_resolve_t) (void);
|
|
```
|
|
|
|
## jerryx_module_resolver_t
|
|
|
|
**Summary**
|
|
|
|
Function pointer type for a module resolver
|
|
|
|
**Prototype**
|
|
|
|
```c
|
|
typedef bool (*jerryx_module_resolver_t) (const jerry_char_t *name, jerry_value_t *result);
|
|
```
|
|
|
|
**Example**
|
|
```c
|
|
bool
|
|
load_and_evaluate_js_file (const jerry_char_t *name, jerry_value_t *result)
|
|
{
|
|
bool return_value = false;
|
|
char *js_file_contents = NULL;
|
|
int file_size = 0;
|
|
FILE *js_file = fopen (name, "r");
|
|
|
|
if (js_file)
|
|
{
|
|
/* We have successfully opened the file. Now, we establish its size. */
|
|
file_size = fseek (js_file, 0, SEEK_END);
|
|
fseek (js_file, 0, SEEK_SET);
|
|
|
|
/* We allocate enough memory to store the contents of the file. */
|
|
js_file_contents = malloc (file_size);
|
|
if (js_file_contents)
|
|
{
|
|
/* We read the file into memory and call jerry_eval (), assigning the result to the out-parameter. */
|
|
fread (js_file_contents, file_size, 1, js_file);
|
|
(*result) = jerry_eval (js_file_contents, file_size, false);
|
|
|
|
/* We release the memory holding the contents of the file. */
|
|
free (js_file_contents);
|
|
return_value = true;
|
|
}
|
|
|
|
/* We close the file. */
|
|
fclose (js_file);
|
|
}
|
|
|
|
return return_value;
|
|
}
|
|
```
|
|
|
|
We can now load JavaScript files:
|
|
```c
|
|
static const jerryx_module_resolver_t resolvers =
|
|
{
|
|
/* Consult the JerryScript module resolver first, in case the requested module is a compiled-in JerryScript module. */
|
|
jerryx_module_native_resolver,
|
|
|
|
/*
|
|
* If the requested module is not a JerryScript module, assume it is a JavaScript file on disk and use the above-
|
|
* defined JavaScript file loader to load it.
|
|
*/
|
|
load_and_evaluate_js_file
|
|
};
|
|
jerry_value_t js_module = jerryx_module_resolve (requested_module, resolvers, 2);
|
|
```
|
|
|
|
# Module helper macros
|
|
|
|
## JERRYX_NATIVE_MODULE
|
|
|
|
**Summary**
|
|
|
|
Helper macro to define a JerryScript module. Currently stores the name of the module and its initializer in an
|
|
executable linker section. This macro is available only if the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED`
|
|
is defined.
|
|
|
|
**Note**: The helper macro must appear at the bottom of a source file, and no semicolon must follow it.
|
|
|
|
**Prototype**
|
|
```c
|
|
#define JERRYX_NATIVE_MODULE(module_name, on_resolve_cb)
|
|
```
|
|
|
|
- `module_name` - the name of the module without quotes
|
|
- `on_resolve_cb` - the function of type `jerryx_native_module_on_resolve_t` that will be called when the module needs to be
|
|
loaded.
|
|
|
|
**Example**
|
|
|
|
```c
|
|
#include "jerryscript.h"
|
|
#include "jerryscript-ext/module.h"
|
|
|
|
static jerry_value_t
|
|
my_module_on_resolve (void)
|
|
{
|
|
return jerry_create_external_function (very_useful_function);
|
|
} /* my_module_on_resolve */
|
|
|
|
/* Note that there is no semicolon at the end of the next line. This is how it must be. */
|
|
JERRYX_NATIVE_MODULE (my_module, my_module_on_resolve)
|
|
```
|