Rework module linking (#4632)

The module linking process from jerry_parse is moved out into
a new jerry_module_link function, and jerry_parse is limited to
create unlinked modules.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2021-03-30 15:40:09 +02:00
committed by GitHub
parent 874a6a49d5
commit 6c484f3529
22 changed files with 1574 additions and 789 deletions
+121
View File
@@ -747,6 +747,37 @@ typedef void (*jerry_error_object_created_callback_t) (const jerry_value_t error
- [jerry_set_error_object_created_callback](#jerry_set_error_object_created_callback)
## jerry_module_resolve_callback_t
**Summary**
Callback which is called by [jerry_module_link](#jerry_module_link) to get the referenced module.
*Note*:
- If realms are enabled, the returned module should be created in the current realm
(see: [jerry_get_global_object](#jerry_get_global_object))
**Prototype**
```c
typedef jerry_value_t (*jerry_module_resolve_callback_t) (const jerry_value_t specifier,
const jerry_value_t referrer,
void *user_p);
```
- `specifier` - a module specifier string (usually used as a path to the module)
- `referrer` - a module object which contains the `specifier` in its source code
- `user_p` - pointer passed to [jerry_module_link](#jerry_module_link).
- return value
- a module object - if it can be resolved successfully
- an error - otherwise
*New in version [[NEXT_RELEASE]]*.
**See also**
- [jerry_module_link](#jerry_module_link)
- [jerry_get_global_object](#jerry_get_global_object)
## jerry_backtrace_callback_t
**Summary**
@@ -4244,6 +4275,96 @@ jerry_value_as_uint32 (const jerry_value_t value);
}
```
# Functions for module objects
These APIs all depend on module support.
## jerry_module_link
**Summary**
Link modules to their dependencies. The dependencies are resolved by a user callback.
*Notes*:
- Returned value must be freed with [jerry_release_value](#jerry_release_value) when it
is no longer needed.
- This API depends on a build option (`JERRY_MODULE_SYSTEM`) and can be checked
in runtime with the `JERRY_FEATURE_MODULE` feature enum value,
see: [jerry_is_feature_enabled](#jerry_is_feature_enabled).
**Prototype**
```c
jerry_value_t jerry_module_link (const jerry_value_t module_val,
jerry_module_resolve_callback_t callback, void *user_p)
```
- `module_val` - module object in unlinked state
- `callback` - user callback which is called to resolve dependencies,
uses `jerry_port_module_resolve` when NULL is passed
- `user_p` - user pointer passed to the callback
- return
- true - if linking is successful
- error - otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
static jerry_value_t
module_resolve_callback (const jerry_value_t specifier,
const jerry_value_t referrer,
void *user_data_p)
{
/* In this case, the specifier contains 'b.mjs', and the referrer is the module
* created in the main() function below. Normally the specifier string should be
* extended to a full file system path, and it should be checked whether a module
* corresponding to this path has been loaded already. For simplicity, this function
* returns with a new module. */
const jerry_char_t script[] = "export var a = 5";
const jerry_char_t file[] = "b.mjs";
jerry_parse_options_t parse_options;
parse_options.options = JERRY_PARSE_MODULE | JERRY_PARSE_HAS_RESOURCE;
parse_options.resource_name_p = file;
parse_options.resource_name_length = sizeof (file) - 1;
return jerry_parse (script, sizeof (script) - 1, &parse_options);
} /* module_resolve_callback */
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "import a from 'b.mjs'";
const jerry_char_t file[] = "a.mjs";
jerry_parse_options_t parse_options;
parse_options.options = JERRY_PARSE_MODULE | JERRY_PARSE_HAS_RESOURCE;
parse_options.resource_name_p = file;
parse_options.resource_name_length = sizeof (file) - 1;
jerry_value_t ret_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
jerry_module_link (ret_value, module_resolve_callback, NULL);
jerry_release_value (ret_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_resolve_callback_t](#jerry_module_resolve_callback_t)
# Functions for promise objects
These APIs all depend on the es.next profile (or on some build options).
+32 -36
View File
@@ -85,12 +85,10 @@ void jerry_port_print_char (char c);
### Jerry Module system
The port API provides functions that can be used by the module system to open
and close source files, and normalize file paths.
The `jerry_port_get_native_module` port function can be used to provide native
modules to the engine. This function will be called when an import/export
statement is encountered with an unknown module specifier, which embedders can
use to supply native module objects based on the module name argument.
The port API provides optional functions that can be used by the
user application to resolve modules. If no callback is provided
to `jerry_module_link`, the `jerry_port_module_resolve` function
is used for resolving modules.
```c
/**
@@ -115,40 +113,38 @@ jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */
} /* jerry_port_release_source */
/**
* Normalize a file path
* Default module resolver.
*
* @return length of the path written to the output buffer
*/
size_t
jerry_port_normalize_path (const char *in_path_p, /**< input file path */
char *out_buf_p, /**< output buffer */
size_t out_buf_size, /**< size of output buffer */
char *base_file_p) /**< base file path */
{
// normalize in_path_p by expanding relative paths etc.
// if base_file_p is not NULL, in_path_p is relative to that file
// write to out_buf_p the normalized path
// return length of written path
} /* jerry_port_normalize_path */
/**
* Get the module object of a native module.
*
* Note:
* This port function is called by jerry-core when JERRY_MODULE_SYSTEM
* is enabled.
*
* @param name String value of the module specifier.
*
* @return Undefined, if 'name' is not a native module
* jerry_value_t containing the module object, otherwise
* @return a module object if resolving is successful, an error otherwise
*/
jerry_value_t
jerry_port_get_native_module (jerry_value_t name) /**< module specifier */
jerry_port_module_resolve (const jerry_value_t specifier, /**< module specifier string */
const jerry_value_t referrer, /**< parent module */
void *user_p) /**< user data */
{
(void) name;
return jerry_create_undefined ();
}
// Resolves a module using the specifier string. If a referrer is a module,
// and specifier is a relative path, the base path should be the directory
// part extracted from the path of the referrer module.
// The callback function of jerry_module_link may call this function
// if it cannot resolve a module. Furthermore if the callback is NULL,
// this function is used for resolving modules.
// The default implementation only resolves ECMAScript modules, and does
// not (currently) use the user data.
} /* jerry_port_module_resolve */
/**
* Release known modules.
*/
void
jerry_port_module_release (const jerry_value_t realm) /**< if this argument is object, release only those modules,
* which realm value is equal to this argument. */
{
// This function releases the known modules, forcing their reload
// when resolved again later. The released modules can be filtered
// by realms. This function is only called by user applications.
} /* jerry_port_module_release */
```
## Date