diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 7594e731f..6c5ff1d1d 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -145,7 +145,7 @@ lexer_skip_spaces (parser_context_t *context_p) /**< context */ if (context_p->token.flags & LEXER_NO_SKIP_SPACES) { - context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES); + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; return; } @@ -1428,6 +1428,22 @@ lexer_check_next_characters (parser_context_t *context_p, /**< context */ || context_p->source_p[0] == (uint8_t) character2)); } /* lexer_check_next_characters */ +/** + * Consumes the next character. The character cannot be a white space. + * + * @return consumed character + */ +uint8_t +lexer_consume_next_character (parser_context_t *context_p) +{ + JERRY_ASSERT (context_p->source_p < context_p->source_end_p); + + context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES; + + PARSER_PLUS_EQUAL_LC (context_p->column, 1); + return *context_p->source_p++; +} /* lexer_consume_next_character */ + #if ENABLED (JERRY_ES2015) /** @@ -1450,6 +1466,35 @@ lexer_check_arrow (parser_context_t *context_p) /**< context */ && context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN); } /* lexer_check_arrow */ +/** + * Checks whether the next token is a comma or equal sign. + * + * @return true if the next token is a comma or equal sign + */ +bool +lexer_check_arrow_param (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.flags & LEXER_NO_SKIP_SPACES); + + if (context_p->source_p >= context_p->source_end_p) + { + return false; + } + + if (context_p->source_p[0] == LIT_CHAR_COMMA) + { + return true; + } + + if (context_p->source_p[0] != LIT_CHAR_EQUALS) + { + return false; + } + + return (context_p->source_p + 1 >= context_p->source_end_p + || context_p->source_p[1] != LIT_CHAR_EQUALS); +} /* lexer_check_arrow_param */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 85655bf62..7ac4819d2 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -619,9 +619,11 @@ void lexer_next_token (parser_context_t *context_p); bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t character); bool lexer_check_next_characters (parser_context_t *context_p, lit_utf8_byte_t character1, lit_utf8_byte_t character2); +uint8_t lexer_consume_next_character (parser_context_t *context_p); #if ENABLED (JERRY_ES2015) void lexer_skip_empty_statements (parser_context_t *context_p); bool lexer_check_arrow (parser_context_t *context_p); +bool lexer_check_arrow_param (parser_context_t *context_p); #endif /* ENABLED (JERRY_ES2015) */ void lexer_parse_string (parser_context_t *context_p); void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type); diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 0366f12e1..f3b73922d 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -284,8 +284,173 @@ scanner_process_arrow_arg (parser_context_t *context_p, /**< context */ } } /* scanner_process_arrow_arg */ +/** + * Arrow types for scanner_handle_bracket() function. + */ +typedef enum +{ + SCANNER_HANDLE_BRACKET_NO_ARROW, /**< not an arrow function */ + SCANNER_HANDLE_BRACKET_SIMPLE_ARROW, /**< simple arrow function */ + SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG, /**< arrow function with one argument */ +} scanner_handle_bracket_arrow_type_t; + #endif /* ENABLED (JERRY_ES2015) */ +/** + * Detect special cases in bracketed expressions. + */ +static void +scanner_handle_bracket (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + size_t depth = 0; +#if ENABLED (JERRY_ES2015) + const uint8_t *arrow_source_p; + scanner_handle_bracket_arrow_type_t arrow_type = SCANNER_HANDLE_BRACKET_NO_ARROW; +#endif /* ENABLED (JERRY_ES2015) */ + + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_PAREN); + + do + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = context_p->source_p; +#endif /* ENABLED (JERRY_ES2015) */ + depth++; + lexer_next_token (context_p); + } + while (context_p->token.type == LEXER_LEFT_PAREN); + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + switch (context_p->token.type) + { + case LEXER_LITERAL: + { + if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } + +#if ENABLED (JERRY_ES2015) + const uint8_t *source_p = context_p->source_p; + + if (lexer_check_arrow (context_p)) + { + arrow_source_p = source_p; + arrow_type = SCANNER_HANDLE_BRACKET_SIMPLE_ARROW; + break; + } + + size_t total_depth = depth; +#endif /* ENABLED (JERRY_ES2015) */ + + while (depth > 0 && lexer_check_next_character (context_p, LIT_CHAR_RIGHT_PAREN)) + { + lexer_consume_next_character (context_p); + depth--; + } + + if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) + { +#if ENABLED (JERRY_ES2015) + /* A function call cannot be an eval function. */ + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + + if (context_p->token.lit_location.length == 4 + && lexer_compare_identifiers (context_p->token.lit_location.char_p, (const uint8_t *) "eval", 4)) + { + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; + } + break; + } + +#if ENABLED (JERRY_ES2015) + if (total_depth == depth) + { + if (lexer_check_arrow_param (context_p)) + { + JERRY_ASSERT (depth > 0); + depth--; + break; + } + } + else if (depth == total_depth - 1 + && lexer_check_arrow (context_p)) + { + arrow_type = SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG; + break; + } + + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } +#if ENABLED (JERRY_ES2015) + case LEXER_THREE_DOTS: + case LEXER_LEFT_SQUARE: + case LEXER_LEFT_BRACE: + case LEXER_RIGHT_PAREN: + { + JERRY_ASSERT (depth > 0); + depth--; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + default: + { +#if ENABLED (JERRY_ES2015) + arrow_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ + break; + } + } + + while (depth > 0) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); + depth--; + } + +#if ENABLED (JERRY_ES2015) + if (arrow_source_p != NULL) + { + if (arrow_type == SCANNER_HANDLE_BRACKET_SIMPLE_ARROW) + { + scanner_process_simple_arrow (context_p, scanner_context_p, arrow_source_p); + return; + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS); + + scanner_literal_pool_t *literal_pool_p; + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, 0); + literal_pool_p->source_p = arrow_source_p; + + if (arrow_type == SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG) + { + scanner_append_argument (context_p, scanner_context_p); + scanner_detect_eval_call (context_p, scanner_context_p); + + context_p->token.type = LEXER_RIGHT_PAREN; + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } + else if (context_p->token.type == LEXER_RIGHT_PAREN) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + } + else + { + scanner_process_arrow_arg (context_p, scanner_context_p); + } + } +#endif /* ENABLED (JERRY_ES2015) */ +} /* scanner_handle_bracket */ + /** * Scan primary expression. * @@ -328,28 +493,8 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ } case LEXER_LEFT_PAREN: { -#if ENABLED (JERRY_ES2015) - parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS); - - scanner_literal_pool_t *literal_pool_p; - literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, 0); - literal_pool_p->source_p = context_p->source_p; - - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_RIGHT_PAREN) - { - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - return SCAN_KEEP_TOKEN; - } - - scanner_process_arrow_arg (context_p, scanner_context_p); + scanner_handle_bracket (context_p, scanner_context_p); return SCAN_KEEP_TOKEN; -#else /* ENABLED (JERRY_ES2015) */ - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); - scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; -#endif /* ENABLED (JERRY_ES2015) */ - break; } case LEXER_LEFT_SQUARE: { diff --git a/tests/jerry/es2015/arrow-function.js b/tests/jerry/es2015/arrow-function.js index 64d499d04..ebc3f4305 100644 --- a/tests/jerry/es2015/arrow-function.js +++ b/tests/jerry/es2015/arrow-function.js @@ -137,7 +137,9 @@ default: must_throw ("var x => x;"); must_throw ("(()) => 0"); must_throw ("((x)) => 0"); +must_throw ("(((x))) => 0"); must_throw ("(x,) => 0"); +must_throw ("(x==6) => 0"); must_throw ("(x y) => 0"); must_throw ("(x,y,) => 0"); must_throw ("x\n => 0"); @@ -148,3 +150,27 @@ must_throw_strict ("(package) => 0"); must_throw_strict ("(package) => { return 5 }"); must_throw_strict ("(x,x,x) => 0"); must_throw_strict ("(x,x,x) => { }"); + +var f = (a) => 1; +assert(f() === 1); + +var f = (a => 2); +assert(f() === 2); + +var f = ((((a => ((3)))))); +assert(f() === 3); + +var f = (((a) => 4)); +assert(f() === 4); + +var f = (a,b) => 5; +assert(f() === 5); + +var f = (((a,b) => 6)); +assert(f() === 6); + +var f = ((a,b) => x => (a) => 7); +assert(f()()() === 7); + +var f = (((a=1,b=2) => ((x => (((a) => 8)))))); +assert(f()()() === 8); diff --git a/tests/jerry/eval.js b/tests/jerry/eval.js index 4d0c4b607..a63861665 100644 --- a/tests/jerry/eval.js +++ b/tests/jerry/eval.js @@ -122,3 +122,33 @@ catch(e) code = 'eval("(function (){})")'; code = "eval ('" + code + "')"; eval (code); + +// Eval enclosed in brackets is still an eval. +var p1 = 0; + +function f3() { + var p1 = 5; + (eval)("assert(p1 === 5)"); +} +f3(); + +function f4() { + var p1 = 6; + ((eval))("assert(p1 === 6)"); +} +f4(); + +function f5() { + var p1 = 7; + (((((eval)))("assert(p1 === 7)"))); +} +f5(); + +function f6() { + var p1 = 8; + var e = eval; + + e("assert(p1 === 0)"); + (((((e)))("assert(p1 === 0)"))); +} +f6();