[PATCH 0/3] MR11462: jscript: Allow reserved keywords as IdentifierName.
Native Windows JScript accepts reserved keywords (continue, break, return, throw, etc.) as property names in member expressions and object literals regardless of script language version. Remove the ES5 version check that was incorrectly rejecting them in legacy mode. Pls tell me if anything else is required mainly tests on either c/js sides Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55447 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11462
From: Lokesh Poovaragan <lokesh.poovaragan@gmail.com> Native Windows JScript accepts reserved keywords (continue, break, return, throw, etc.) as property names in member expressions and object literals regardless of script language version. Remove the ES5 version check that was incorrectly rejecting them in legacy mode. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55447 --- dlls/jscript/parser.y | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 949d9131b80..02a86c2f7cb 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -883,16 +883,7 @@ Identifier /* ECMA-262 5.1 Edition 7.6 */ IdentifierName : tIdentifier { $$ = $1; } - | ReservedAsIdentifier - { - if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) { - WARN("%s keyword used as an identifier in legacy mode.\n", - debugstr_w($1)); - set_error(ctx, @$, JS_E_SYNTAX); - YYABORT; - } - $$ = $1; - } + | ReservedAsIdentifier { $$ = $1; } ReservedAsIdentifier : kBREAK { $$ = $1; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11462
From: Lokesh Poovaragan <lokesh.poovaragan@gmail.com> When a keyword like 'continue' follows a '.' (member expression), it is always an IdentifierName, never a statement keyword. Suppress automatic semicolon insertion in this context so that code like: var x = { label: O.continue }; parses correctly instead of inserting a spurious semicolon after 'continue'. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55447 --- dlls/jscript/lex.c | 13 ++++++++++++- dlls/jscript/parser.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c index ee29bff1e37..818848b4e0b 100644 --- a/dlls/jscript/lex.c +++ b/dlls/jscript/lex.c @@ -545,6 +545,8 @@ static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret) static int next_token(parser_ctx_t *ctx, unsigned *loc, void *lval) { + BOOL prev_was_dot; + do { if(!skip_spaces(ctx)) { *loc = ctx->ptr - ctx->begin; @@ -559,10 +561,18 @@ static int next_token(parser_ctx_t *ctx, unsigned *loc, void *lval) ctx->implicit_nl_semicolon = FALSE; } + /* A keyword following '.' is always an IdentifierName (property access), + * never a statement keyword, so don't insert an implicit semicolon. */ + prev_was_dot = ctx->prev_was_dot; + ctx->prev_was_dot = FALSE; + if(iswalpha(*ctx->ptr)) { int ret = check_keywords(ctx, lval); - if(ret) + if(ret) { + if(prev_was_dot) + ctx->implicit_nl_semicolon = FALSE; return ret; + } return parse_identifier(ctx, lval); } @@ -603,6 +613,7 @@ static int next_token(parser_ctx_t *ctx, unsigned *loc, void *lval) return tNumericLiteral; } ctx->ptr++; + ctx->prev_was_dot = TRUE; return '.'; case '<': diff --git a/dlls/jscript/parser.h b/dlls/jscript/parser.h index 406bedc6607..a537f941346 100644 --- a/dlls/jscript/parser.h +++ b/dlls/jscript/parser.h @@ -39,6 +39,7 @@ typedef struct _parser_ctx_t { statement_t *source; BOOL nl; BOOL implicit_nl_semicolon; + BOOL prev_was_dot; BOOL is_html; BOOL lexer_error; HRESULT hres; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11462
From: Lokesh Poovaragan <lokesh.poovaragan@gmail.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55447 --- dlls/jscript/tests/lang.js | 21 ++++++++++++ dlls/jscript/tests/run.c | 67 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js index 89f52298fb3..42f3c793d76 100644 --- a/dlls/jscript/tests/lang.js +++ b/dlls/jscript/tests/lang.js @@ -2096,6 +2096,27 @@ function returnTest() { ok(returnTest() === undefined, "returnTest = " + returnTest()); +/* keywords as property names in member expressions should not trigger ASI */ +(function() { + var O = { continue: 1, break: 2, return: 3, throw: 4 }; + var x = { + label: O.continue + }; + ok(x.label === 1, "x.label = " + x.label); + var y = { + label: O.break + }; + ok(y.label === 2, "y.label = " + y.label); + var z = { + label: O.return + }; + ok(z.label === 3, "z.label = " + z.label); + var w = { + label: O.throw + }; + ok(w.label === 4, "w.label = " + w.label); +})(); + ActiveXObject = 1; ok(ActiveXObject === 1, "ActiveXObject = " + ActiveXObject); diff --git a/dlls/jscript/tests/run.c b/dlls/jscript/tests/run.c index 5d555b05eb0..f80e5586420 100644 --- a/dlls/jscript/tests/run.c +++ b/dlls/jscript/tests/run.c @@ -4293,6 +4293,73 @@ static BOOL run_tests(void) CHECK_CALLED(global_propargput_d); CHECK_CALLED(global_propargput_i); + strict_dispid_check = FALSE; + + /* test 1: non-keyword property access with newline */ + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { cont: 1 };\n" + L"var x = { label: O.cont\n" + L"};\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 1 (non-keyword) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + /* test 2: keyword continue after '.' */ + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { cont: 1 };\n" + L"var x = O.continue;\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 2a (continue after dot) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { cont: 1 };\n" + L"var x = O.continue\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 2b (continue after dot, newline) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { cont: 1 };\n" + L"var x = { label: O.continue\n" + L"};\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 2c (continue after dot in object literal, newline) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + /* test 3: keyword in object literal */ + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { continue: 1 };\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 3a (continue as property name) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + + SET_EXPECT(global_success_d); + SET_EXPECT(global_success_i); + hres = parse_script(SCRIPTITEM_GLOBALMEMBERS, + L"var O = { continue: 1 };\n" + L"var x = { label: O.continue\n" + L"};\n" + L"reportSuccess();"); + ok(hres == S_OK, "test 3b (both contexts) parse_script failed: %08lx\n", hres); + CHECK_CALLED(global_success_d); + CHECK_CALLED(global_success_i); + SET_EXPECT(global_propargputop_d); SET_EXPECT(global_propargputop_get_i); SET_EXPECT(global_propargputop_put_i); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11462
participants (2)
-
Lokesh Poovaragan -
Lokesh Poovaragan (@lokeshpoovaragan)