-- v2: jscript: Allow ES5 keywords in identifiers. jscript: Split tIdentifier into a separate Identifier rule where ES5 keywords
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Except for LabelledStatement which needs special treatment.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/parser.y | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 42d695e0846..5c0084b1747 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -221,7 +221,7 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t %type <expr> MemberExpression %type <expr> PrimaryExpression %type <expr> GetterSetterMethod -%type <identifier> Identifier_opt +%type <identifier> Identifier Identifier_opt %type <variable_list> VariableDeclarationList %type <variable_list> VariableDeclarationListNoIn %type <variable_declaration> VariableDeclaration @@ -268,9 +268,9 @@ FunctionStatementList FunctionExpression : kFUNCTION left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, NULL, $3, $6, NULL, ctx->begin + @1, @7 - @1 + 1); } - | kFUNCTION tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' + | kFUNCTION Identifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, $2, $4, $7, NULL, ctx->begin + @1, @8 - @1 + 1); } - | kFUNCTION tIdentifier kDCOL tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' + | kFUNCTION Identifier kDCOL Identifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}' { $$ = new_function_expression(ctx, $4, $6, $9, $2, ctx->begin + @1, @10 - @1 + 1); }
/* ECMA-262 10th Edition 14.1 */ @@ -279,8 +279,8 @@ FunctionBody
/* ECMA-262 3rd Edition 13 */ FormalParameterList - : tIdentifier { $$ = new_parameter_list(ctx, $1); } - | FormalParameterList ',' tIdentifier + : Identifier { $$ = new_parameter_list(ctx, $1); } + | FormalParameterList ',' Identifier { $$ = parameter_list_add(ctx, $1, $3); }
/* ECMA-262 3rd Edition 13 */ @@ -381,12 +381,12 @@ VariableDeclarationListNoIn
/* ECMA-262 3rd Edition 12.2 */ VariableDeclaration - : tIdentifier Initialiser_opt + : Identifier Initialiser_opt { $$ = new_variable_declaration(ctx, $1, $2); }
/* ECMA-262 3rd Edition 12.2 */ VariableDeclarationNoIn - : tIdentifier InitialiserNoIn_opt + : Identifier InitialiserNoIn_opt { $$ = new_variable_declaration(ctx, $1, $2); }
/* ECMA-262 3rd Edition 12.2 */ @@ -527,7 +527,7 @@ TryStatement
/* ECMA-262 3rd Edition 12.14 */ Catch - : kCATCH left_bracket tIdentifier right_bracket Block + : kCATCH left_bracket Identifier right_bracket Block { $$ = new_catch_block(ctx, $3, $5); }
/* ECMA-262 3rd Edition 12.14 */ @@ -786,7 +786,7 @@ ArgumentList /* ECMA-262 3rd Edition 11.1 */ PrimaryExpression : kTHIS { $$ = new_expression(ctx, EXPR_THIS, 0); } - | tIdentifier { $$ = new_identifier_expression(ctx, $1); } + | Identifier { $$ = new_identifier_expression(ctx, $1); } | Literal { $$ = new_literal_expression(ctx, $1); } | ArrayLiteral { $$ = $1; } | ObjectLiteral { $$ = $1; } @@ -860,7 +860,10 @@ PropertyName /* ECMA-262 3rd Edition 7.6 */ Identifier_opt : /* empty*/ { $$ = NULL; } - | tIdentifier { $$ = $1; } + | Identifier { $$ = $1; } + +Identifier + : tIdentifier { $$ = $1; }
/* ECMA-262 5.1 Edition 7.6 */ IdentifierName
From: Gabriel Ivăncescu gabrielopcode@gmail.com
ES5 keywords (let, get, set) are allowed as identifiers almost everywhere. We need to duplicate the rules for each keyword in LabelledStatement, because it is oterwise ambiguous using bison's parser, which only looks at one lookahead token to determine whether to shift or reduce.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/jscript/parser.y | 21 ++++++++++++++++----- dlls/mshtml/tests/es5.js | 25 +++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y index 5c0084b1747..5ba633235d0 100644 --- a/dlls/jscript/parser.y +++ b/dlls/jscript/parser.y @@ -241,10 +241,11 @@ static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t %type <literal> PropertyName %type <literal> BooleanLiteral %type <ival> AssignOper -%type <identifier> IdentifierName ReservedAsIdentifier +%type <identifier> IdentifierName ReservedAsIdentifier ES5Keyword
%nonassoc LOWER_THAN_ELSE -%nonassoc kELSE +%nonassoc kELSE kIN kINSTANCEOF ':' +%nonassoc kGET kLET kSET
%%
@@ -479,6 +480,12 @@ WithStatement LabelledStatement : tIdentifier ':' Statement { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kGET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kSET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); } + | kLET ':' Statement + { $$ = new_labelled_statement(ctx, @$, $1, $3); }
/* ECMA-262 3rd Edition 12.11 */ SwitchStatement @@ -864,6 +871,7 @@ Identifier_opt
Identifier : tIdentifier { $$ = $1; } + | ES5Keyword { $$ = $1; }
/* ECMA-262 5.1 Edition 7.6 */ IdentifierName @@ -893,15 +901,12 @@ ReservedAsIdentifier | kFINALLY { $$ = $1; } | kFOR { $$ = $1; } | kFUNCTION { $$ = $1; } - | kGET { $$ = $1; } | kIF { $$ = $1; } | kIN { $$ = $1; } | kINSTANCEOF { $$ = $1; } - | kLET { $$ = $1; } | kNEW { $$ = $1; } | kNULL { $$ = $1; } | kRETURN { $$ = $1; } - | kSET { $$ = $1; } | kSWITCH { $$ = $1; } | kTHIS { $$ = $1; } | kTHROW { $$ = $1; } @@ -912,6 +917,12 @@ ReservedAsIdentifier | kVOID { $$ = $1; } | kWHILE { $$ = $1; } | kWITH { $$ = $1; } + | ES5Keyword { $$ = $1; } + +ES5Keyword + : kGET { $$ = $1; } + | kLET { $$ = $1; } + | kSET { $$ = $1; }
/* ECMA-262 3rd Edition 7.8 */ Literal diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js index 18b106e2a82..31278bbb082 100644 --- a/dlls/mshtml/tests/es5.js +++ b/dlls/mshtml/tests/es5.js @@ -473,7 +473,14 @@ sync_test("array_sort", function() { });
sync_test("identifier_keywords", function() { + function get(let, set) { { get instanceof (Object); } return let + set; } + set: var let = get(1, 2); + { get /* asdf */: 10 } + var set = 0; var o = { + get: get, + set: set, + let /* comment */ : let, if: 1, default: 2, function: 3, @@ -486,8 +493,8 @@ sync_test("identifier_keywords", function() { else: true, finally: true, for: true, - in: true, - instanceof: true, + set in(x) { }, + get instanceof() { return 3; }, new: true, return: true, switch: true, @@ -508,6 +515,20 @@ sync_test("identifier_keywords", function() { ok(o.if === 1, "o.if = " + o.if); ok(ro().default === 2, "ro().default = " + ro().default); ok(o.false === true, "o.false = " + o.false); + ok(o.get === get, "o.get = " + o.get); + ok(o.set === set, "o.set = " + o.set); + ok(o.let === let, "o.let = " + o.let); + ok(o.instanceof === 3, "o.instanceof = " + o.instanceof); + ok(let === 3, "let = " + let); + + var tmp = false; + try { + eval('function var() { }'); + } + catch(set) { + tmp = true; + } + ok(tmp === true, "Expected exception for 'function var() { }'"); });
function test_own_data_prop_desc(obj, prop, expected_writable, expected_enumerable,
The first patch is no-op. While it's often fine, it doesn't improve bisects. I'd suggest something like: - A patch that introduces `Identifier` rule, including `ES5Keyword` and a test of affected rule - A patch that adds `noassoc` changes, a rule that depends on it and its tests - A patch that uses `Identifier` rule in more places (possibly a few patches, up to you) - A patch for `LabelledStatement`, it would be nice to have a comment about why we can't use `Identifier` there