diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index cd33b591c..21bf7395c 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -32,15 +32,20 @@ */ /** - * Maximum precedence for right-to-left binary operation evaluation + * Maximum precedence for right-to-left binary operation evaluation. */ #define PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE 6 /** - * Precende for ternary operation + * Precende for ternary operation. */ #define PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE 4 +/** + * Value of grouping level increase and decrease. + */ +#define PARSER_GROUPING_LEVEL_INCREASE 2 + /** * Precedence of the binary tokens. * @@ -1167,7 +1172,7 @@ static void parser_parse_unary_expression (parser_context_t *context_p, /**< context */ size_t *grouping_level_p) /**< grouping level */ { - int new_was_seen = 0; + bool new_was_seen = false; /* Collect unary operators. */ while (true) @@ -1194,15 +1199,17 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ break; } #endif /* ENABLED (JERRY_ES2015) */ - (*grouping_level_p)++; - new_was_seen = 0; + (*grouping_level_p) += PARSER_GROUPING_LEVEL_INCREASE; + new_was_seen = false; } else if (context_p->token.type == LEXER_KEYW_NEW) { /* After 'new' unary operators are not allowed. */ - new_was_seen = 1; + new_was_seen = true; } - else if (new_was_seen || !LEXER_IS_UNARY_OP_TOKEN (context_p->token.type)) + else if (new_was_seen + || (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE) + || !LEXER_IS_UNARY_OP_TOKEN (context_p->token.type)) { break; } @@ -1449,7 +1456,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_ES2015) */ default: { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); + bool is_left_hand_side = (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE); + parser_raise_error (context_p, (is_left_hand_side ? PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED + : PARSER_ERR_PRIMARY_EXP_EXPECTED)); break; } } @@ -1461,7 +1470,8 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ * generate byte code for the whole expression. */ static void -parser_process_unary_expression (parser_context_t *context_p) /**< context */ +parser_process_unary_expression (parser_context_t *context_p, /**< context */ + size_t grouping_level) /**< grouping level */ { #if ENABLED (JERRY_ES2015) /* Track to see if a property was accessed or not */ @@ -1694,7 +1704,8 @@ parser_process_unary_expression (parser_context_t *context_p) /**< context */ } if (!(context_p->token.flags & LEXER_WAS_NEWLINE) - && (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE)) + && (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE) + && grouping_level != PARSE_EXPR_LEFT_HAND_SIDE) { cbc_opcode_t opcode = (context_p->token.type == LEXER_INCREASE) ? CBC_POST_INCR : CBC_POST_DECR; parser_push_result (context_p); @@ -2088,8 +2099,8 @@ static void parser_process_group_expression (parser_context_t *context_p, /**< context */ size_t *grouping_level_p) /**< grouping level */ { - JERRY_ASSERT (*grouping_level_p > 0); - (*grouping_level_p)--; + JERRY_ASSERT (*grouping_level_p >= PARSER_GROUPING_LEVEL_INCREASE); + (*grouping_level_p) -= PARSER_GROUPING_LEVEL_INCREASE; if (context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST) { @@ -2137,6 +2148,9 @@ parser_parse_expression_statement (parser_context_t *context_p, /**< context */ } } /* parser_parse_expression_statement */ +JERRY_STATIC_ASSERT (PARSE_EXPR_LEFT_HAND_SIDE == 0x1, + value_of_parse_expr_left_hand_side_must_be_1); + /** * Parse expression. */ @@ -2144,7 +2158,7 @@ void parser_parse_expression (parser_context_t *context_p, /**< context */ int options) /**< option flags */ { - size_t grouping_level = 0; + size_t grouping_level = (options & PARSE_EXPR_LEFT_HAND_SIDE); parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); @@ -2171,24 +2185,27 @@ parser_parse_expression (parser_context_t *context_p, /**< context */ while (true) { process_unary_expression: - parser_process_unary_expression (context_p); + parser_process_unary_expression (context_p, grouping_level); - uint8_t min_prec_treshold = 0; - - if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) + if (JERRY_LIKELY (grouping_level != PARSE_EXPR_LEFT_HAND_SIDE)) { - min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP]; + uint8_t min_prec_treshold = 0; - /* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND */ - if (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE - && min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE) + if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) { - /* Right-to-left evaluation order. */ - min_prec_treshold++; - } - } + min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP]; - parser_process_binary_opcodes (context_p, min_prec_treshold); + /* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND */ + if (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE + && min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE) + { + /* Right-to-left evaluation order. */ + min_prec_treshold++; + } + } + + parser_process_binary_opcodes (context_p, min_prec_treshold); + } if (context_p->token.type == LEXER_RIGHT_PAREN && (context_p->stack_top_uint8 == LEXER_LEFT_PAREN @@ -2198,7 +2215,8 @@ process_unary_expression: continue; } - if (context_p->token.type == LEXER_QUESTION_MARK) + if (JERRY_UNLIKELY (context_p->token.type == LEXER_QUESTION_MARK) + && (grouping_level != PARSE_EXPR_LEFT_HAND_SIDE)) { parser_process_ternary_expression (context_p); continue; @@ -2206,8 +2224,13 @@ process_unary_expression: break; } + if (grouping_level == PARSE_EXPR_LEFT_HAND_SIDE) + { + break; + } + if (JERRY_UNLIKELY (context_p->token.type == LEXER_COMMA) - && (!(options & PARSE_EXPR_NO_COMMA) || grouping_level > 0)) + && (!(options & PARSE_EXPR_NO_COMMA) || grouping_level >= PARSER_GROUPING_LEVEL_INCREASE)) { parser_process_expression_sequence (context_p); continue; @@ -2222,7 +2245,7 @@ process_unary_expression: break; } - if (grouping_level != 0) + if (grouping_level >= PARSER_GROUPING_LEVEL_INCREASE) { parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index a471733ac..c860f196b 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -93,9 +93,10 @@ typedef enum typedef enum { PARSE_EXPR = 0, /**< parse an expression without any special flags */ - PARSE_EXPR_NO_PUSH_RESULT = (1u << 0), /**< do not push the result of the expression onto the stack */ - PARSE_EXPR_NO_COMMA = (1u << 1), /**< do not parse comma operator */ - PARSE_EXPR_HAS_LITERAL = (1u << 2), /**< a primary literal is provided by a + PARSE_EXPR_LEFT_HAND_SIDE = (1u << 0), /**< parse a left-hand-side expression */ + PARSE_EXPR_NO_PUSH_RESULT = (1u << 1), /**< do not push the result of the expression onto the stack */ + PARSE_EXPR_NO_COMMA = (1u << 2), /**< do not parse comma operator */ + PARSE_EXPR_HAS_LITERAL = (1u << 3), /**< a primary literal is provided by a * CBC_PUSH_LITERAL instruction */ } parser_expression_flags_t; diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 05e93a175..ef8c642ae 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -695,10 +695,7 @@ parser_parse_super_class_context_start (parser_context_t *context_p) /**< contex { lexer_next_token (context_p); - /* NOTE: Currently there is no proper way to check whether the currently parsed expression - is a valid lefthand-side expression or not, so we do not throw syntax error and parse - the class extending value as an expression. */ - parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA); + parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE); } else { @@ -1058,7 +1055,7 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ { uint16_t opcode; - parser_parse_expression (context_p, PARSE_EXPR); + parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE); opcode = context_p->last_cbc_opcode; diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index f8684eef9..449f381d2 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -1016,6 +1016,10 @@ parser_error_to_string (parser_error_t error) /**< error code */ { return "Primary expression expected."; } + case PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED: + { + return "Left-hand-side expression expected."; + } case PARSER_ERR_STATEMENT_EXPECTED: { return "Statement expected."; diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 5eba00992..d900a8084 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -96,6 +96,7 @@ typedef enum PARSER_ERR_IDENTIFIER_EXPECTED, /**< identifier expected */ PARSER_ERR_EXPRESSION_EXPECTED, /**< expression expected */ PARSER_ERR_PRIMARY_EXP_EXPECTED, /**< primary expression expected */ + PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED, /**< left-hand-side expression expected */ PARSER_ERR_STATEMENT_EXPECTED, /**< statement expected */ PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED, /**< property identifier expected */ PARSER_ERR_ARGUMENT_LIST_EXPECTED, /**< argument list expected */ diff --git a/tests/jerry/es2015/class-inheritance-early-semantics.js b/tests/jerry/es2015/class-inheritance-early-semantics.js index 68b8622b8..479238171 100644 --- a/tests/jerry/es2015/class-inheritance-early-semantics.js +++ b/tests/jerry/es2015/class-inheritance-early-semantics.js @@ -107,6 +107,14 @@ must_throw ("class A extends A { }"); must_throw ("class A extends { constructor () { super () } }"); +must_throw ("class A extends a * b {}"); + +must_throw ("class A extends a = b {}"); + +must_throw ("class A extends a++ {}"); + +must_throw ("class A extends -a {}"); + class B extends A { constructor (a, b) { super (a); diff --git a/tests/jerry/es2015/regression-test-issue-2819.js b/tests/jerry/fail/regression-test-issue-2819.js similarity index 100% rename from tests/jerry/es2015/regression-test-issue-2819.js rename to tests/jerry/fail/regression-test-issue-2819.js diff --git a/tests/jerry/for-in.js b/tests/jerry/for-in.js index 84ef4e7fa..c06b6c31f 100644 --- a/tests/jerry/for-in.js +++ b/tests/jerry/for-in.js @@ -281,3 +281,11 @@ assert(count == 1 || 'base_prop2' in log || 'derived_prop1' in log || 'derived_prop2' in log)); + +try { + /* This form is a SyntaxError even in ES5.1. */ + eval("for (a = b in {}) ;"); + assert(false); +} catch (e) { + assert(e instanceof SyntaxError); +}