Add module C API functions (#4636)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2021-03-31 19:40:58 +02:00
committed by GitHub
parent 6677fa0a12
commit 4377ef684d
8 changed files with 715 additions and 62 deletions
+350
View File
@@ -747,6 +747,21 @@ 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_state_t
An enum representing the current status of a module
- JERRY_MODULE_STATE_INVALID - Return value for jerry_module_get_state when its argument is not a module
- JERRY_MODULE_STATE_UNLINKED - Module is currently unlinked
- JERRY_MODULE_STATE_LINKING - Module is currently being linked
- JERRY_MODULE_STATE_LINKED - Module has been linked (its depencencies has been resolved)
- JERRY_MODULE_STATE_EVALUATING - Module is currently being evaluated
- JERRY_MODULE_STATE_EVALUATED - Module has been evaluated (its source code has been executed)
- JERRY_MODULE_STATE_ERROR - An error has been encountered before the evaluated state is reached
- JERRY_MODULE_STATE_NATIVE - Module is native module
*New in version [[NEXT_RELEASE]]*.
## jerry_module_resolve_callback_t
**Summary**
@@ -4365,6 +4380,341 @@ main (void)
**See also**
- [jerry_module_resolve_callback_t](#jerry_module_resolve_callback_t)
## jerry_module_evaluate
Evaluate a module and its dependencies. The module must be in linked state.
*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_evaluate (const jerry_value_t module_val);
```
- `module_val` - module object
- return
- result of module bytecode execution - if evaluation was successful
- error, otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
#include <stdio.h>
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "export var a = 6";
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 module_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
jerry_release_value (jerry_module_link (module_value, NULL, NULL));
jerry_release_value (jerry_module_evaluate (module_value));
jerry_release_value (module_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_link](#jerry_module_link)
## jerry_module_get_state
**Summary**
Returns the current status of a module. The available values
are listed in [jerry_module_state_t](#jerry_module_state_t)
*Notes*:
- 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_module_state_t jerry_module_get_state (const jerry_value_t module_val);
```
- `module_val` - module object
- return
- current status - if module_val is a module
- JERRY_MODULE_STATE_INVALID - otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
#include <stdio.h>
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 module_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
if (jerry_module_get_state (module_value) == JERRY_MODULE_STATE_UNLINKED)
{
printf ("Module parsing has been successful\n");
}
jerry_release_value (module_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_state_t](#jerry_module_state_t)
## jerry_module_get_number_of_requests
**Summary**
Returns the number of import/export requests of a module.
The requests can be queried by [jerry_module_get_request](#jerry_module_get_request).
*Notes*:
- 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
size_t jerry_module_get_number_of_requests (const jerry_value_t module_val);
```
- `module_val` - module object
- return
- number of import/export requests of a module, if `module_val` is module,
- 0, otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
#include <stdio.h>
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "export * from 'b.mjs'"
"import a from 'c.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 module_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
/* Prints 2. */
printf ("Number of requests: %d\n", (int) jerry_module_get_number_of_requests (module_value));
jerry_release_value (module_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_get_request](#jerry_module_get_request)
- [jerry_parse](#jerry_parse)
- [jerry_module_link](#jerry_module_link)
## jerry_module_get_request
**Summary**
Returns the module request specified by the `request_index` argument. The requests
are ordered in source code occurence. When parsing is completed, all returned values
are strings. If [jerry_module_link](#jerry_module_link) is completed successfully
all returned values are module objects instead. If linking is in progress or fails,
the successfully resolved dependencies are module objects, the rest are strings.
The number of requests can be queried by
[jerry_module_get_number_of_requests](#jerry_module_get_number_of_requests).
*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_get_request (const jerry_value_t module_val, size_t request_index);
```
- `module_val` - module object
- return
- string, if the request has not been resolved yet
- module object, if the request has been resolved successfully
- error, otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "export * from 'b.mjs'"
"import a from 'c.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 module_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
jerry_value_t request_value = jerry_module_get_request (module_value, 0);
/* Returns with b.mjs */
jerry_release_value (request_value);
request_value = jerry_module_get_request (module_value, 1);
/* Returns with c.mjs */
jerry_release_value (request_value);
jerry_release_value (module_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_get_number_of_requests](#jerry_module_get_number_of_requests)
- [jerry_parse](#jerry_parse)
- [jerry_module_link](#jerry_module_link)
## jerry_module_get_namespace
Returns the namespace object of a module
*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_get_namespace (const jerry_value_t module_val);
```
- `module_val` - module object
- return
- object, if namespace object is available
- error, otherwise
*New in version [[NEXT_RELEASE]]*.
**Example**
[doctest]: # (test="compile")
```c
#include <jerryscript.h>
#include <stdio.h>
int
main (void)
{
jerry_init (JERRY_INIT_EMPTY);
const jerry_char_t script[] = "export var a = 6";
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 module_value = jerry_parse (script, sizeof (script) - 1, &parse_options);
jerry_release_value (jerry_module_link (module_value, NULL, NULL));
jerry_release_value (jerry_module_evaluate (module_value));
jerry_value_t namespace_value = jerry_module_get_namespace (module_value);
/* Exports can be checked. */
jerry_release_value (namespace_value);
jerry_release_value (module_value);
jerry_cleanup ();
return 0;
}
```
**See also**
- [jerry_module_link](#jerry_module_link)
- [jerry_module_evaluate](#jerry_module_evaluate)
# Functions for promise objects
These APIs all depend on the es.next profile (or on some build options).
+187 -14
View File
@@ -689,20 +689,6 @@ jerry_run (const jerry_value_t func_val) /**< function to run */
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
#if JERRY_MODULE_SYSTEM
if (JERRY_UNLIKELY (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_MODULE_UL))
{
ecma_module_t *root_module_p = (ecma_module_t *) ext_object_p;
if (root_module_p->header.u.class_prop.extra_info != ECMA_MODULE_STATE_LINKED)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Module must be in linked state")));
}
return jerry_return (ecma_module_evaluate (root_module_p));
}
#endif /* JERRY_MODULE_SYSTEM */
if (ext_object_p->u.class_prop.class_id != LIT_MAGIC_STRING_SCRIPT_UL)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (wrong_args_msg_p)));
@@ -757,6 +743,8 @@ jerry_module_link (const jerry_value_t module_val, /**< root module */
* jerry_port_module_resolve when NULL is passed */
void *user_p) /**< pointer passed to the resolve callback */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
if (callback == NULL)
{
@@ -780,6 +768,191 @@ jerry_module_link (const jerry_value_t module_val, /**< root module */
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_link */
/**
* Evaluate a module and its dependencies. The module must be in linked state.
*
* Note:
* returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return result of module bytecode execution - if evaluation was successful
* error - otherwise
*/
jerry_value_t
jerry_module_evaluate (const jerry_value_t module_val) /**< root module */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module_val);
if (module_p == NULL)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_not_module_p)));
}
if (module_p->header.u.class_prop.extra_info != JERRY_MODULE_STATE_LINKED)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG ("Module must be in linked state")));
}
return jerry_return (ecma_module_evaluate (module_p));
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module_val);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_module_not_supported_p)));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_evaluate */
/**
* Returns the current status of a module
*
* @return current status - if module_val is a module,
* JERRY_MODULE_STATE_INVALID - otherwise
*/
jerry_module_state_t
jerry_module_get_state (const jerry_value_t module_val) /**< module object */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module_val);
if (module_p == NULL)
{
return JERRY_MODULE_STATE_INVALID;
}
return (jerry_module_state_t) module_p->header.u.class_prop.extra_info;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module_val);
return JERRY_MODULE_STATE_INVALID;
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_get_state */
/**
* Returns the number of import/export requests of a module
*
* @return number of import/export requests of a module
*/
size_t
jerry_module_get_number_of_requests (const jerry_value_t module_val) /**< module */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module_val);
if (module_p == NULL)
{
return 0;
}
size_t number_of_requests = 0;
ecma_module_node_t *node_p = module_p->imports_p;
while (node_p != NULL)
{
number_of_requests++;
node_p = node_p->next_p;
}
return number_of_requests;
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module_val);
return 0;
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_get_number_of_requests */
/**
* Returns the module request specified by the request_index argument
*
* Note:
* returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return string - if the request has not been resolved yet,
* module object - if the request has been resolved successfully,
* error - otherwise
*/
jerry_value_t
jerry_module_get_request (const jerry_value_t module_val, /**< module */
size_t request_index) /**< request index */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module_val);
if (module_p == NULL)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_not_module_p)));
}
ecma_module_node_t *node_p = module_p->imports_p;
while (node_p != NULL)
{
if (request_index == 0)
{
return ecma_copy_value (node_p->u.path_or_module);
}
--request_index;
node_p = node_p->next_p;
}
return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("Request is not available")));
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module_val);
JERRY_UNUSED (request_index);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_module_not_supported_p)));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_get_request */
/**
* Returns the namespace object of a module
*
* Note:
* returned value must be freed with jerry_release_value, when it is no longer needed.
*
* @return object - if namespace object is available,
* error - otherwise
*/
jerry_value_t
jerry_module_get_namespace (const jerry_value_t module_val) /**< module */
{
jerry_assert_api_available ();
#if JERRY_MODULE_SYSTEM
ecma_module_t *module_p = ecma_module_get_resolved_module (module_val);
if (module_p == NULL)
{
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_not_module_p)));
}
if (module_p->namespace_object_p == NULL)
{
if (module_p->header.u.class_prop.extra_info != JERRY_MODULE_STATE_EVALUATED)
{
return jerry_throw (ecma_raise_range_error (ECMA_ERR_MSG ("Namespace object has not been created yet")));
}
ecma_module_create_namespace_object (module_p);
}
ecma_ref_object (module_p->namespace_object_p);
return ecma_make_object_value (module_p->namespace_object_p);
#else /* !JERRY_MODULE_SYSTEM */
JERRY_UNUSED (module_val);
return jerry_throw (ecma_raise_type_error (ECMA_ERR_MSG (error_module_not_supported_p)));
#endif /* JERRY_MODULE_SYSTEM */
} /* jerry_module_get_namespace */
/**
* Run enqueued Promise jobs until the first thrown error or until all get executed.
*
+26 -24
View File
@@ -40,7 +40,7 @@ ecma_module_initialize_context (void)
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_MODULE_UL;
ext_object_p->u.class_prop.extra_info = ECMA_MODULE_STATE_UNLINKED;
ext_object_p->u.class_prop.extra_info = JERRY_MODULE_STATE_UNLINKED;
ecma_module_t *module_p = (ecma_module_t *) obj_p;
@@ -219,7 +219,7 @@ ecma_module_resolve_export (ecma_module_t *const module_p, /**< base module */
continue;
}
if (current_module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_NATIVE)
if (current_module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_NATIVE)
{
ecma_object_t *object_p = current_module_p->namespace_object_p;
ecma_value_t prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p),
@@ -382,17 +382,17 @@ ecma_module_resolve_export (ecma_module_t *const module_p, /**< base module */
ecma_value_t
ecma_module_evaluate (ecma_module_t *module_p) /**< module */
{
if (module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_ERROR)
if (module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_ERROR)
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Module is in error state"));
}
if (module_p->header.u.class_prop.extra_info >= ECMA_MODULE_STATE_EVALUATING)
if (module_p->header.u.class_prop.extra_info >= JERRY_MODULE_STATE_EVALUATING)
{
return ECMA_VALUE_EMPTY;
}
JERRY_ASSERT (module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_LINKED);
JERRY_ASSERT (module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_LINKED);
#if JERRY_BUILTIN_REALMS
ecma_object_t *global_object_p = (ecma_object_t *) ecma_op_function_get_realm (module_p->compiled_code_p);
@@ -400,18 +400,18 @@ ecma_module_evaluate (ecma_module_t *module_p) /**< module */
ecma_object_t *global_object_p = ecma_builtin_get_global ();
#endif /* JERRY_BUILTIN_REALMS */
module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_EVALUATING;
module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_EVALUATING;
module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment (global_object_p));
ecma_value_t ret_value;
ret_value = vm_run_module (module_p);
module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_ERROR;
module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_ERROR;
if (!ECMA_IS_VALUE_ERROR (ret_value))
{
ecma_free_value (ret_value);
module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_EVALUATED;
module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_EVALUATED;
ret_value = ECMA_VALUE_EMPTY;
}
@@ -482,7 +482,7 @@ ecma_module_namespace_object_add_export_if_needed (ecma_module_t *module_p, /**<
* @return ECMA_VALUE_ERROR - if an error occured
* ECMA_VALUE_EMPTY - otherwise
*/
static ecma_value_t
ecma_value_t
ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */
{
ecma_value_t result = ECMA_VALUE_EMPTY;
@@ -491,7 +491,7 @@ ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */
return result;
}
JERRY_ASSERT (module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_EVALUATED);
JERRY_ASSERT (module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_EVALUATED);
ecma_module_resolve_set_t *resolve_set_p = NULL;
ecma_module_resolve_stack_t *stack_p = NULL;
@@ -688,7 +688,7 @@ ecma_module_connect_imports (ecma_module_t *module_p)
return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous import request"));
}
if (record.module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_NATIVE)
if (record.module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_NATIVE)
{
ecma_object_t *object_p = record.module_p->namespace_object_p;
prop_value = ecma_op_object_find_own (ecma_make_object_value (object_p), object_p, record.name_p);
@@ -858,12 +858,12 @@ ecma_module_link (ecma_module_t *module_p, /**< root module */
jerry_module_resolve_callback_t callback, /**< resolve module callback */
void *user_p) /**< pointer passed to the resolve callback */
{
if (module_p->header.u.class_prop.extra_info != ECMA_MODULE_STATE_UNLINKED)
if (module_p->header.u.class_prop.extra_info != JERRY_MODULE_STATE_UNLINKED)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Module must be in unlinked state"));
}
module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_LINKING;
module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_LINKING;
uint32_t dfs_index = 0;
ecma_module_stack_item_t *last_p;
@@ -919,7 +919,7 @@ restart:
node_p->u.path_or_module = resolve_result;
ecma_deref_object (ecma_get_object_from_value (resolve_result));
if (resolved_module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_ERROR)
if (resolved_module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_ERROR)
{
ecma_raise_type_error (ECMA_ERR_MSG ("Cannot link to a module which is in error state"));
goto error;
@@ -938,10 +938,10 @@ restart:
{
module_p = ecma_module_get_from_object (node_p->u.path_or_module);
if (module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_UNLINKED)
if (module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_UNLINKED)
{
current_p->node_p = node_p->next_p;
module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_LINKING;
module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_LINKING;
ecma_module_stack_item_t *item_p;
item_p = (ecma_module_stack_item_t *) jmem_heap_alloc_block (sizeof (ecma_module_stack_item_t));
@@ -962,7 +962,7 @@ restart:
goto restart;
}
if (module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_LINKING)
if (module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_LINKING)
{
uint32_t dfs_ancestor_index = module_p->header.u.class_prop.u.dfs_ancestor_index;
@@ -996,8 +996,8 @@ restart:
{
ecma_module_stack_item_t *prev_p = last_p->prev_p;
JERRY_ASSERT (last_p->module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_LINKING);
last_p->module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_LINKED;
JERRY_ASSERT (last_p->module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_LINKING);
last_p->module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_LINKED;
jmem_heap_free_block (last_p, sizeof (ecma_module_stack_item_t));
last_p = prev_p;
@@ -1017,8 +1017,8 @@ error:
{
ecma_module_stack_item_t *prev_p = last_p->prev_p;
JERRY_ASSERT (last_p->module_p->header.u.class_prop.extra_info == ECMA_MODULE_STATE_LINKING);
last_p->module_p->header.u.class_prop.extra_info = ECMA_MODULE_STATE_UNLINKED;
JERRY_ASSERT (last_p->module_p->header.u.class_prop.extra_info == JERRY_MODULE_STATE_LINKING);
last_p->module_p->header.u.class_prop.extra_info = JERRY_MODULE_STATE_UNLINKED;
jmem_heap_free_block (last_p, sizeof (ecma_module_stack_item_t));
last_p = prev_p;
@@ -1075,7 +1075,9 @@ ecma_module_release_module_nodes (ecma_module_node_t *module_node_p, /**< first
void
ecma_module_release_module (ecma_module_t *module_p) /**< module */
{
ecma_module_state_t state = (ecma_module_state_t) module_p->header.u.class_prop.extra_info;
jerry_module_state_t state = (jerry_module_state_t) module_p->header.u.class_prop.extra_info;
JERRY_ASSERT (state != JERRY_MODULE_STATE_INVALID);
if (module_p->namespace_object_p != NULL)
{
@@ -1087,7 +1089,7 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */
#endif /* JERRY_NDEBUG */
}
if (state == ECMA_MODULE_STATE_NATIVE)
if (state == JERRY_MODULE_STATE_NATIVE)
{
return;
}
@@ -1097,7 +1099,7 @@ ecma_module_release_module (ecma_module_t *module_p) /**< module */
ecma_module_release_module_nodes (module_p->indirect_exports_p, false);
ecma_module_release_module_nodes (module_p->star_exports_p, false);
if (state >= ECMA_MODULE_STATE_EVALUATING)
if (state >= JERRY_MODULE_STATE_EVALUATING)
{
/* The module structure keeps a strong reference to the module scope, which will require an extra GC call. */
JERRY_CONTEXT (ecma_gc_new_objects)++;
+1 -14
View File
@@ -35,20 +35,6 @@ typedef struct ecma_module_names
ecma_string_t *local_name_p; /**< Local name of the item */
} ecma_module_names_t;
/**
* An enum identifing the current state of the module
*/
typedef enum
{
ECMA_MODULE_STATE_UNLINKED = 0, /**< module is currently unlinked */
ECMA_MODULE_STATE_LINKING = 1, /**< module is currently being linked */
ECMA_MODULE_STATE_LINKED = 2, /**< module has been linked */
ECMA_MODULE_STATE_EVALUATING = 3, /**< module is currently being evaluated */
ECMA_MODULE_STATE_EVALUATED = 4, /**< module has been evaluated */
ECMA_MODULE_STATE_ERROR = 5, /**< error is encountered during module init */
ECMA_MODULE_STATE_NATIVE = 6, /**< module is native */
} ecma_module_state_t;
/**
* Module structure storing an instance of a module
*
@@ -130,6 +116,7 @@ ecma_value_t ecma_module_evaluate (ecma_module_t *module_p);
void ecma_module_initialize_context (void);
void ecma_module_cleanup_context (void);
ecma_value_t ecma_module_create_namespace_object (ecma_module_t *module_p);
void ecma_module_release_module_names (ecma_module_names_t *module_name_p);
void ecma_module_release_module (ecma_module_t *module_p);
+5
View File
@@ -267,6 +267,11 @@ jerry_value_t jerry_to_property_descriptor (jerry_value_t obj_value, jerry_prope
jerry_value_t jerry_module_link (const jerry_value_t module_val,
jerry_module_resolve_callback_t callback_p, void *user_p);
jerry_value_t jerry_module_evaluate (const jerry_value_t module_val);
jerry_module_state_t jerry_module_get_state (const jerry_value_t module_val);
size_t jerry_module_get_number_of_requests (const jerry_value_t module_val);
jerry_value_t jerry_module_get_request (const jerry_value_t module_val, size_t request_index);
jerry_value_t jerry_module_get_namespace (const jerry_value_t module_val);
/**
* Promise functions.
+26 -7
View File
@@ -288,13 +288,6 @@ typedef void (*jerry_object_native_free_callback_t) (void *native_p);
*/
typedef void (*jerry_error_object_created_callback_t) (const jerry_value_t error_object, void *user_p);
/**
* Callback which is called by jerry_module_link to get the referenced module.
*/
typedef jerry_value_t (*jerry_module_resolve_callback_t) (const jerry_value_t specifier,
const jerry_value_t referrer,
void *user_p);
/**
* Callback which tells whether the ECMAScript execution should be stopped.
*
@@ -522,6 +515,32 @@ typedef enum
JERRY_ITERATOR_TYPE_SET, /**< Set iterator */
} jerry_iterator_type_t;
/**
* Module related types.
*/
/**
* An enum representing the current status of a module
*/
typedef enum
{
JERRY_MODULE_STATE_INVALID = 0, /**< return value for jerry_module_get_state when its argument is not a module */
JERRY_MODULE_STATE_UNLINKED = 1, /**< module is currently unlinked */
JERRY_MODULE_STATE_LINKING = 2, /**< module is currently being linked */
JERRY_MODULE_STATE_LINKED = 3, /**< module has been linked (its depencencies has been resolved) */
JERRY_MODULE_STATE_EVALUATING = 4, /**< module is currently being evaluated */
JERRY_MODULE_STATE_EVALUATED = 5, /**< module has been evaluated (its source code has been executed) */
JERRY_MODULE_STATE_ERROR = 6, /**< an error has been encountered before the evaluated state is reached */
JERRY_MODULE_STATE_NATIVE = 7, /**< module is native module */
} jerry_module_state_t;
/**
* Callback which is called by jerry_module_link to get the referenced module.
*/
typedef jerry_value_t (*jerry_module_resolve_callback_t) (const jerry_value_t specifier,
const jerry_value_t referrer,
void *user_p);
/**
* Proxy related types.
*/
+10 -3
View File
@@ -88,6 +88,13 @@ restart:
if (!jerry_value_is_error (ret_value))
{
if (jerry_module_get_state (ret_value) != JERRY_MODULE_STATE_UNLINKED)
{
/* A module can be evaluated only once. */
jerry_release_value (ret_value);
continue;
}
jerry_value_t link_val = jerry_module_link (ret_value, NULL, NULL);
if (jerry_value_is_error (link_val))
@@ -99,9 +106,9 @@ restart:
{
jerry_release_value (link_val);
jerry_value_t func_val = ret_value;
ret_value = jerry_run (func_val);
jerry_release_value (func_val);
jerry_value_t module_val = ret_value;
ret_value = jerry_module_evaluate (module_val);
jerry_release_value (module_val);
}
}
+110
View File
@@ -39,6 +39,21 @@ compare_specifier (jerry_value_t specifier, /* string value */
TEST_ASSERT (memcmp (buffer, string, length) == 0);
} /* compare_specifier */
static void
compare_property (jerry_value_t namespace_object, /**< namespace object */
const char *name_p, /**< property name */
double expected_value) /**< property value (number for simplicity) */
{
jerry_value_t name = jerry_create_string ((const jerry_char_t *) name_p);
jerry_value_t result = jerry_get_property (namespace_object, name);
TEST_ASSERT (jerry_value_is_number (result));
TEST_ASSERT (jerry_get_number_value (result) == expected_value);
jerry_release_value (result);
jerry_release_value (name);
} /* compare_property */
static jerry_value_t
create_module (int id) /**< module id */
{
@@ -110,6 +125,18 @@ resolve_callback2 (const jerry_value_t specifier, /**< module specifier */
return prev_module;
} /* resolve_callback2 */
static jerry_value_t
resolve_callback3 (const jerry_value_t specifier, /**< module specifier */
const jerry_value_t referrer, /**< parent module */
void *user_p) /**< user data */
{
(void) specifier;
(void) referrer;
(void) user_p;
TEST_ASSERT (false);
} /* resolve_callback3 */
int
main (void)
{
@@ -163,6 +190,13 @@ main (void)
TEST_ASSERT (jerry_value_is_boolean (result) && jerry_get_boolean_value (result));
TEST_ASSERT (counter == 32);
jerry_release_value (result);
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_LINKED);
TEST_ASSERT (jerry_module_get_number_of_requests (module) == 1);
result = jerry_module_get_request (module, 0);
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_LINKED);
jerry_release_value (result);
jerry_release_value (module);
module = create_module (1);
@@ -176,6 +210,82 @@ main (void)
jerry_release_value (result);
jerry_release_value (module);
TEST_ASSERT (jerry_module_get_state (number) == JERRY_MODULE_STATE_INVALID);
jerry_parse_options_t module_parse_options;
module_parse_options.options = JERRY_PARSE_MODULE;
jerry_char_t source1[] = TEST_STRING_LITERAL (
"import a from '16_module.mjs'\n"
"export * from '07_module.mjs'\n"
"export * from '44_module.mjs'\n"
"import * as b from '36_module.mjs'\n"
);
module = jerry_parse (source1, sizeof (source1) - 1, &module_parse_options);
TEST_ASSERT (!jerry_value_is_error (module));
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_UNLINKED);
TEST_ASSERT (jerry_module_get_number_of_requests (number) == 0);
TEST_ASSERT (jerry_module_get_number_of_requests (module) == 4);
result = jerry_module_get_request (object, 0);
TEST_ASSERT (jerry_value_is_error (result));
jerry_release_value (result);
result = jerry_module_get_request (module, 0);
compare_specifier (result, 16);
jerry_release_value (result);
result = jerry_module_get_request (module, 1);
compare_specifier (result, 7);
jerry_release_value (result);
result = jerry_module_get_request (module, 2);
compare_specifier (result, 44);
jerry_release_value (result);
result = jerry_module_get_request (module, 3);
compare_specifier (result, 36);
jerry_release_value (result);
result = jerry_module_get_request (module, 4);
TEST_ASSERT (jerry_value_is_error (result));
jerry_release_value (result);
jerry_release_value (module);
result = jerry_module_get_namespace (number);
TEST_ASSERT (jerry_value_is_error (result));
jerry_release_value (result);
jerry_char_t source2[] = TEST_STRING_LITERAL (
"export let a = 6\n"
"export let b = 8.5\n"
);
module = jerry_parse (source2, sizeof (source2) - 1, &module_parse_options);
TEST_ASSERT (!jerry_value_is_error (module));
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_UNLINKED);
result = jerry_module_link (module, resolve_callback3, NULL);
TEST_ASSERT (!jerry_value_is_error (result));
jerry_release_value (result);
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_LINKED);
result = jerry_module_evaluate (module);
TEST_ASSERT (!jerry_value_is_error (result));
jerry_release_value (result);
TEST_ASSERT (jerry_module_get_state (module) == JERRY_MODULE_STATE_EVALUATED);
result = jerry_module_get_namespace (module);
TEST_ASSERT (jerry_value_is_object (result));
compare_property (result, "a", 6);
compare_property (result, "b", 8.5);
jerry_release_value (result);
jerry_release_value (module);
jerry_release_value (object);
jerry_release_value (number);