Skip to content

Implement ES2015 module system #2599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2019
Merged

Implement ES2015 module system #2599

merged 1 commit into from
Mar 18, 2019

Conversation

vincedani
Copy link
Contributor

@vincedani vincedani commented Nov 16, 2018

This patch is the first part of the ES2015 module system implementation.

The language specification can be found here

The implemented feature is documented here

JerryScript-DCO-1.0-Signed-off-by: Daniel Vince vinced@inf.u-szeged.hu

@vincedani vincedani changed the title [WIP] ES6 module system Implement ES2015 module system Jan 10, 2019
Copy link
Member

@rerobika rerobika left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, please add the missing:

  • Function
  • Function argument
  • Structure
  • Structure member
    documentations.

Also, please try the avoid the layer violations and please use the JERRY_ASSERT macro to ensure prerequisites at certain points.

@@ -308,7 +313,8 @@ parser_parse_enclosed_expr (parser_context_t *context_p) /**< context */
* Parse var statement.
*/
static void
parser_parse_var_statement (parser_context_t *context_p) /**< context */
parser_parse_var_statement (parser_context_t *context_p, /**< context */
lexer_literal_t *variable_name) /**< variable name */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we return with that value?

Copy link
Member

@rerobika rerobika left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (informal)

# ES6 module support for JerryScript

The module system allows users to write import and export statements in scripts. Therefore the logic of the application could be separated in custom modules.
The standard's relevant part can be found [here]( https://www.ecma-international.org/ecma-262/6.0/#sec-modules).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 space before http

@@ -50,6 +50,12 @@
# define CONFIG_DISABLE_ES2015_TYPEDARRAY_BUILTIN
#endif /* CONFIG_DISABLE_ES2015 */

#if (defined (CONFIG_DISABLE_ES2015) || !defined (JERRY_ENABLE_MODULE_SYSTEM))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add this to the ifdef CONFIG_DISABLE_ES2015 above.

for (uint16_t i = 0; i < export_node_p->module_request_count; i++)
{
parser_module_names_t *next_p = current_p->next_p;
ecma_string_t *import_name_p = ecma_new_ecma_string_from_utf8 (current_p->local_name.value_p,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these not strings? Magic strings could be used and no conversion would be needed here.

JERRY_ASSERT (lex_env_p != NULL);
JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p));

ecma_module_lex_envs_t *new_wrapper_p;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new_module_lex_env.

typedef struct parser_module_names
{
parser_module_utf8_string_t import_name; /**< local name of the import - export item */
parser_module_utf8_string_t local_name; /**< import name of the import - export item */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a local->import map? If yes, what about using objects for this (for faster property search).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review, I’ve updated the patch.

import { a as b } from 'module.js';

If a specific module (module.js) has been run, its lexical environment is being checked. If that lexical environment contains a property with the given name (a), then a new property is created in the parent context with the imported name (b) and assigned with the value of a.

If objects are being used for the local name -> import name mapping, the key should be the module path. This object should contain as many key-value pairs as many import items were in the import statement.
module_map

I think in this scenario objects won’t worth it, because we now have 1 property search per import item (in the lexical environment), then we should have min. 2 (in the object too).

@@ -90,6 +90,8 @@ typedef enum
PARSER_ERR_LEFT_BRACE_EXPECTED, /**< left brace expected */
PARSER_ERR_RIGHT_PAREN_EXPECTED, /**< right paren expected */
PARSER_ERR_RIGHT_SQUARE_EXPECTED, /**< right square expected */
PARSER_ERR_LEFT_PAREN_MULTIPLY_LITERAL_EXPECTED, /**< left paren or multiply or literal expected */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this module specific?


if (current_p != NULL && current_length == import_name_p->prop.length)
{
if (memcmp (current_p, import_name_p->u.char_p, current_length) == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge these two if statements

while (stored_imports != NULL)
{
if (stored_imports->script_path.length == module_node_p->script_path.length
&& memcmp (stored_imports->script_path.value_p,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong indentation

bool is_import_item) /**< given item is import item */
{
if (is_import_item &&
parser_module_check_for_duplicates (context_p, module_node_p, import_name_p))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move && to this line


parser_module_context_t *parent_context_p = JERRY_CONTEXT (module_top_context_p);
if ((parent_context_p == NULL || parent_context_p->exports_p == NULL || parent_context_p->imports_p == NULL)
&& module_context_p->exports_p != NULL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong indentation


if (context_p->token.type == LEXER_RIGHT_BRACE
|| (context_p->token.type == LEXER_LITERAL
&& lexer_compare_raw_identifier_to_current (context_p, "from", 4)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong indentation

* @return the source of the file
*/
uint8_t *
jerry_port_module_read_source (const char *file_name_p, /**< file name */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation update is missing for the new port API functions. BTW, why are these needed? Might be better to put the port API changes into a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, I’ve updated the port API documentation. The port functions are necessary for the modules, because without these Jerry could not open custom files (source files). For this reason, the changes can’t be separated into another PR.


int request_count = exports_p->module_request_count + module_node_p->module_request_count;

if (request_count < MAX_IMPORT_COUNT)
Copy link
Contributor

@rtakacs rtakacs Mar 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ((uint16_t) request_count < MAX_IMPORT_COUNT)  // error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]

stored_imports->module_names_p = module_node_p->module_names_p;

int request_count = stored_imports->module_request_count + module_node_p->module_request_count;
if (request_count < MAX_IMPORT_COUNT)
Copy link
Contributor

@rtakacs rtakacs Mar 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ((uint16_t) request_count < MAX_IMPORT_COUNT)  // error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]

@rtakacs
Copy link
Contributor

rtakacs commented Mar 5, 2019

Other notes:

  • jerry-core/module/module.c should be renamed to module_import.c (or something like this). An other module.c already exist in the jerry-ext folder.
    The Makefile of the NuttX target doesn't like if a filename is used multiple times (see nuttx-stm32f4/Makefile#L47 - All the archive files are copied from JerryScript to NuttX. The copied archives are extracted to get the object files. If there are two module.o files (in different archive files) the (jerry-core)module.o will be overwritten by the (jerry-ext)module.o file). This causes linker errors.

  • The targets/nuttx-stm32f4/jerry-main.c implements jerry-port-log. This functions is also implemented in jerry-port/default/default-io.c. Since both files are compiled, there is a linker error that Travis shows. (I've removed jerry-port-log from jerry-main.c to solve the linker error.)

  • Test files contain paths (tests/jerry/...) that should be opened. These paths can be different on boards - e.g. js-remote-test mounts tests/jerry/ folder as /test/.

@vincedani
Copy link
Contributor Author

Other notes:

  • jerry-core/module/module.c should be renamed to module_import.c (or something like this). An other module.c already exist in the jerry-ext folder.
    The Makefile of the NuttX target doesn't like if a filename is used multiple times (see nuttx-stm32f4/Makefile#L47 - All the archive files are copied from JerryScript to NuttX. The copied archives are extracted to get the object files. If there are two module.o files (in different archive files) the (jerry-core)module.o will be overwritten by the (jerry-ext)module.o file). This causes linker errors.
  • The targets/nuttx-stm32f4/jerry-main.c implements jerry-port-log. This functions is also implemented in jerry-port/default/default-io.c. Since both files are compiled, there is a linker error that Travis shows. (I've removed jerry-port-log from jerry-main.c to solve the linker error.)
  • Test files contain paths (tests/jerry/...) that should be opened. These paths can be different on boards - e.g. js-remote-test mounts tests/jerry/ folder as /test/.

Thank you @rtakacs for your review. I've moved and renamed the module.{h, c} as you suggested.

The paths in the test files are adjusted to the ./tools/runners/run-test-suite.sh, which runs on Travis too. I think we should figure out how to adjust these paths when the the js-remote-test environment is running.

Copy link
Member

@zherczeg zherczeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only minor changes. Good for a first patch.

size_t path_size, /**< length of the path */
const char *source_p, /**< module source */
size_t source_size, /**< length of the source */
parser_module_node_t *module_node_p) /**< module node */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misaligned arguments

path_length,
(const char *) buffer_p,
size,
current_p);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Please fix all of them.

JerryScript-DCO-1.0-Signed-off-by: Daniel Vince vinced@inf.u-szeged.hu
Copy link
Contributor

@LaszloLango LaszloLango left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants