From 448984dd74b0d489816aee0033aa53d59eea0ce7 Mon Sep 17 00:00:00 2001 From: Hanjoung Lee Date: Thu, 8 Oct 2015 16:47:35 +0900 Subject: [PATCH] Fix: parsing regex and div operator correctly JerryScript-DCO-1.0-Signed-off-by: Hanjoung Lee hanjoung.lee@samsung.com --- jerry-core/parser/js/lexer.cpp | 25 ++++++++---------- jerry-core/parser/js/lexer.h | 2 +- jerry-core/parser/js/parser.cpp | 31 +++++++++++++++++------ tests/jerry/regexp-literal.js | 18 +++++++++++++ tests/jerry/regression-test-issue-563.js | 32 ++++++++++++++++++++++++ tests/jerry/regression-test-issue-652.js | 32 ++++++++++++++++++++++++ tests/jerry/regression-test-issue-655.js | 20 +++++++++++++++ 7 files changed, 137 insertions(+), 23 deletions(-) create mode 100644 tests/jerry/regression-test-issue-563.js create mode 100644 tests/jerry/regression-test-issue-652.js create mode 100644 tests/jerry/regression-test-issue-655.js diff --git a/jerry-core/parser/js/lexer.cpp b/jerry-core/parser/js/lexer.cpp index ad7f65884..01cda92d3 100644 --- a/jerry-core/parser/js/lexer.cpp +++ b/jerry-core/parser/js/lexer.cpp @@ -1262,10 +1262,15 @@ lexer_parse_comment (void) * Currently, lexer token doesn't fully correspond to Token, defined in ECMA-262, v5, 7.5. * For example, there is no new-line token type in the token definition of ECMA-262 v5. * + * Note: + * For Lexer alone, it is hard to find out a token is whether a regexp or a division. + * Parser must set maybe_regexp to true if a regexp is expected. + * Otherwise, a division is expected. + * * @return constructed token */ static token -lexer_parse_token (void) +lexer_parse_token (bool maybe_regexp) /**< read '/' as regexp? */ { ecma_char_t c = LA (0); @@ -1335,21 +1340,11 @@ lexer_parse_token (void) } else { - return lexer_parse_token (); + return lexer_parse_token (maybe_regexp); } } - if (c == LIT_CHAR_SLASH - && !(prev_non_lf_token.type == TOK_NAME - || prev_non_lf_token.type == TOK_NULL - || prev_non_lf_token.type == TOK_BOOL - || prev_non_lf_token.type == TOK_CLOSE_BRACE - || prev_non_lf_token.type == TOK_CLOSE_SQUARE - || prev_non_lf_token.type == TOK_CLOSE_PAREN - || prev_non_lf_token.type == TOK_SMALL_INT - || prev_non_lf_token.type == TOK_NUMBER - || prev_non_lf_token.type == TOK_STRING - || prev_non_lf_token.type == TOK_REGEXP)) + if (c == LIT_CHAR_SLASH && maybe_regexp) { return lexer_parse_regexp (); } @@ -1517,7 +1512,7 @@ lexer_parse_token (void) } /* lexer_parse_token */ token -lexer_next_token (void) +lexer_next_token (bool maybe_regexp) /**< read '/' as regexp? */ { lit_utf8_iterator_pos_t src_pos = lit_utf8_iterator_get_pos (&src_iter); if (src_pos.offset == 0 && !src_pos.is_non_bmp_middle) @@ -1546,7 +1541,7 @@ lexer_next_token (void) } prev_token = sent_token; - sent_token = lexer_parse_token (); + sent_token = lexer_parse_token (maybe_regexp); if (sent_token.type == TOK_NEWLINE) { diff --git a/jerry-core/parser/js/lexer.h b/jerry-core/parser/js/lexer.h index 851779ada..5c8003198 100644 --- a/jerry-core/parser/js/lexer.h +++ b/jerry-core/parser/js/lexer.h @@ -171,7 +171,7 @@ typedef struct void lexer_init (const jerry_api_char_t *, size_t, bool); -token lexer_next_token (void); +token lexer_next_token (bool); void lexer_save_token (token); token lexer_prev_token (void); diff --git a/jerry-core/parser/js/parser.cpp b/jerry-core/parser/js/parser.cpp index ec4944c21..0e634bb5f 100644 --- a/jerry-core/parser/js/parser.cpp +++ b/jerry-core/parser/js/parser.cpp @@ -95,9 +95,19 @@ token_data_as_lit_cp (void) static void skip_token (void) { - tok = lexer_next_token (); + tok = lexer_next_token (false); } +/** + * In case a regexp token is scanned as a division operator, rescan it + */ +static void +rescan_regexp_token (void) +{ + lexer_seek (tok.loc); + tok = lexer_next_token (true); +} /* rescan_regexp_token */ + static void assert_keyword (keyword kw) { @@ -252,7 +262,7 @@ jsp_find_next_token_before_the_locus (token_type token_to_find, /**< token to se if (lit_utf8_iterator_pos_cmp (tok.loc, end_loc) >= 0) { lexer_seek (end_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); return false; } @@ -830,6 +840,13 @@ parse_primary_expression (void) switch (tok.type) { + case TOK_DIV: + case TOK_DIV_EQ: + { + // must be a regexp literal so rescan the token + rescan_regexp_token (); + /* FALLTHRU */ + } case TOK_NULL: case TOK_BOOL: case TOK_SMALL_INT: @@ -2129,7 +2146,7 @@ jsp_parse_for_in_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost // Dump assignment VariableDeclarationNoIn / LeftHandSideExpression <- VM_REG_SPECIAL_FOR_IN_PROPERTY_NAME lexer_seek (iterator_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); jsp_operand_t iterator_base, iterator_identifier, for_in_special_reg; for_in_special_reg = jsp_create_operand_for_in_special_reg (); @@ -2146,7 +2163,7 @@ jsp_parse_for_in_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost // Body lexer_seek (for_body_statement_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); parse_statement (NULL); @@ -2164,7 +2181,7 @@ jsp_parse_for_in_statement (jsp_label_t *outermost_stmt_label_p, /**< outermost dump_for_in_end (); lexer_seek (loop_end_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); if (tok.type != TOK_CLOSE_BRACE) { lexer_save_token (tok); @@ -2201,13 +2218,13 @@ jsp_parse_for_or_for_in_statement (jsp_label_t *outermost_stmt_label_p) /**< out for_body_statement_loc = tok.loc; lexer_seek (for_open_paren_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); bool is_plain_for = jsp_find_next_token_before_the_locus (TOK_SEMICOLON, for_body_statement_loc, true); lexer_seek (for_open_paren_loc); - tok = lexer_next_token (); + tok = lexer_next_token (false); if (is_plain_for) { diff --git a/tests/jerry/regexp-literal.js b/tests/jerry/regexp-literal.js index 7519093e4..588d4a957 100644 --- a/tests/jerry/regexp-literal.js +++ b/tests/jerry/regexp-literal.js @@ -65,3 +65,21 @@ try { } catch (e) { assert(e instanceof SyntaxError); } + +try { + eval("var x = /aaa/"); +} catch (e) { + assert (false); +} + +try { + eval("{}/a/g"); +} catch (e) { + assert (false); +} + +try { + eval("var a, g; +{}/a/g"); +} catch (e) { + assert (false); +} diff --git a/tests/jerry/regression-test-issue-563.js b/tests/jerry/regression-test-issue-563.js new file mode 100644 index 000000000..e2fd26853 --- /dev/null +++ b/tests/jerry/regression-test-issue-563.js @@ -0,0 +1,32 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval('if (true) /abc/.exec("abc");'); +} catch (e) { + assert (false); +} + +try { + eval('if (true) {} /abc/.exec("abc");'); +} catch (e) { + assert (false); +} + +try { + eval('var a\n/abc/.exec("abc");'); +} catch (e) { + assert (false); +} diff --git a/tests/jerry/regression-test-issue-652.js b/tests/jerry/regression-test-issue-652.js new file mode 100644 index 000000000..4166adfa8 --- /dev/null +++ b/tests/jerry/regression-test-issue-652.js @@ -0,0 +1,32 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval("this / 10"); +} catch (e) { + assert (false); +} + +try { + eval("var v_0 = 10;\nv_0++ / 1"); +} catch (e) { + assert (false); +} + +try { + eval("var v_0 = 10;\nif (v_0++ / 1) {\n}"); +} catch (e) { + assert (false); +} diff --git a/tests/jerry/regression-test-issue-655.js b/tests/jerry/regression-test-issue-655.js new file mode 100644 index 000000000..d7c7fcb78 --- /dev/null +++ b/tests/jerry/regression-test-issue-655.js @@ -0,0 +1,20 @@ +// Copyright 2015 Samsung Electronics Co., Ltd. +// Copyright 2015 University of Szeged. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +try { + eval("if (true) {}\n/a/;"); +} catch (e) { + assert (false); +}