66b072d5ae
The resolvers argument that is passed to jerryx_module_resolve() is not mutated by the function. Therefore the argument should be const. In the docs, a static const array is passed, but this currently does not work w/o a cast. This patch fixes this. JerryScript-DCO-1.0-Signed-off-by: Martijn The martijn.the@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,
|
|
const 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)
|
|
```
|