Paul Gofman : jscript: Parse 'let' and 'const' variable declarations.

Alexandre Julliard julliard at winehq.org
Wed Jun 16 16:26:24 CDT 2021


Module: wine
Branch: master
Commit: b3569629979e7fae612adc407ba37c292c7dffd1
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=b3569629979e7fae612adc407ba37c292c7dffd1

Author: Paul Gofman <pgofman at codeweavers.com>
Date:   Tue Jun 15 18:07:34 2021 +0300

jscript: Parse 'let' and 'const' variable declarations.

Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/jscript/compile.c     |  5 +++++
 dlls/jscript/lex.c         |  2 ++
 dlls/jscript/parser.h      |  1 +
 dlls/jscript/parser.y      | 37 ++++++++++++++++++++++++++++++++-----
 dlls/jscript/tests/lang.js | 34 ++++++++++++++++++++++++++++++++++
 dlls/mshtml/tests/es5.js   | 17 +++++++++++++++++
 6 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/dlls/jscript/compile.c b/dlls/jscript/compile.c
index 9bb9ff13d14..2a17639641f 100644
--- a/dlls/jscript/compile.c
+++ b/dlls/jscript/compile.c
@@ -1138,6 +1138,11 @@ static HRESULT compile_variable_list(compiler_ctx_t *ctx, variable_declaration_t
         if(!iter->expr)
             continue;
 
+        if (iter->block_scope)
+            FIXME("Block scope variables are not supported.\n");
+        if (iter->constant)
+            FIXME("Constant variables are not supported.\n");
+
         hres = emit_identifier_ref(ctx, iter->identifier, 0);
         if(FAILED(hres))
             return hres;
diff --git a/dlls/jscript/lex.c b/dlls/jscript/lex.c
index efed1038a95..695615721a7 100644
--- a/dlls/jscript/lex.c
+++ b/dlls/jscript/lex.c
@@ -41,6 +41,7 @@ static const struct {
     {L"break",       kBREAK,       TRUE},
     {L"case",        kCASE},
     {L"catch",       kCATCH},
+    {L"const",       kCONST},
     {L"continue",    kCONTINUE,    TRUE},
     {L"default",     kDEFAULT},
     {L"delete",      kDELETE},
@@ -54,6 +55,7 @@ static const struct {
     {L"if",          kIF},
     {L"in",          kIN},
     {L"instanceof",  kINSTANCEOF},
+    {L"let",         kLET,         FALSE, SCRIPTLANGUAGEVERSION_ES5},
     {L"new",         kNEW},
     {L"null",        kNULL},
     {L"return",      kRETURN,      TRUE},
diff --git a/dlls/jscript/parser.h b/dlls/jscript/parser.h
index b88a52af242..c4dd0752ee9 100644
--- a/dlls/jscript/parser.h
+++ b/dlls/jscript/parser.h
@@ -95,6 +95,7 @@ literal_t *new_boolean_literal(parser_ctx_t*,BOOL) DECLSPEC_HIDDEN;
 
 typedef struct _variable_declaration_t {
     const WCHAR *identifier;
+    BOOL block_scope, constant;
     expression_t *expr;
 
     struct _variable_declaration_t *next;
diff --git a/dlls/jscript/parser.y b/dlls/jscript/parser.y
index f11119143b8..6de39e43fac 100644
--- a/dlls/jscript/parser.y
+++ b/dlls/jscript/parser.y
@@ -87,7 +87,7 @@ static variable_list_t *variable_list_add(parser_ctx_t*,variable_list_t*,variabl
 
 static void *new_statement(parser_ctx_t*,statement_type_t,size_t,unsigned);
 static statement_t *new_block_statement(parser_ctx_t*,unsigned,statement_list_t*);
-static statement_t *new_var_statement(parser_ctx_t*,unsigned,variable_list_t*);
+static statement_t *new_var_statement(parser_ctx_t*,BOOL,BOOL,unsigned,variable_list_t*);
 static statement_t *new_expression_statement(parser_ctx_t*,unsigned,expression_t*);
 static statement_t *new_if_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*,statement_t*);
 static statement_t *new_while_statement(parser_ctx_t*,unsigned,BOOL,expression_t*,statement_t*);
@@ -168,8 +168,9 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
 }
 
 /* keywords */
-%token <identifier> kBREAK kCASE kCATCH kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR kGET kIN kSET
-%token <identifier> kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE kTRY kTYPEOF kVAR kVOID kWHILE kWITH
+%token <identifier> kBREAK kCASE kCATCH kCONST kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR
+%token <identifier> kGET kIN kLET kSET kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE
+%token <identifier> kTRY kTYPEOF kVAR kVOID kWHILE kWITH
 %token tANDAND tOROR tINC tDEC tHTMLCOMMENT kDIVEQ kDCOL
 
 /* tokens */
@@ -182,6 +183,7 @@ static source_elements_t *source_elements_add_statement(source_elements_t*,state
 %type <source_elements> FunctionBody
 %type <statement> Statement
 %type <statement> Block
+%type <statement> LexicalDeclaration
 %type <statement> VariableStatement
 %type <statement> EmptyStatement
 %type <statement> ExpressionStatement
@@ -291,6 +293,7 @@ FormalParameterList_opt
 /* ECMA-262 3rd Edition    12 */
 Statement
         : Block                 { $$ = $1; }
+        | LexicalDeclaration    { $$ = $1; }
         | VariableStatement     { $$ = $1; }
         | EmptyStatement        { $$ = $1; }
         | FunctionExpression    { $$ = new_expression_statement(ctx, @$, $1); }
@@ -322,10 +325,25 @@ Block
         : '{' StatementList '}' { $$ = new_block_statement(ctx, @2, $2); }
         | '{' '}'               { $$ = new_block_statement(ctx, @$, NULL); }
 
+/* ECMA-262 10th Edition   13.3.1, TODO:  BindingList*/
+LexicalDeclaration
+        : kLET VariableDeclarationList semicolon_opt
+                                { $$ = new_var_statement(ctx, TRUE, FALSE, @$, $2); }
+        | kCONST VariableDeclarationList semicolon_opt
+                                {
+                                    if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) {
+                                        WARN("const var declaration %s in legacy mode.\n",
+                                                debugstr_w($1));
+                                        set_error(ctx, @$, JS_E_SYNTAX);
+                                        YYABORT;
+                                    }
+                                    $$ = new_var_statement(ctx, TRUE, TRUE, @$, $2);
+                                }
+
 /* ECMA-262 3rd Edition    12.2 */
 VariableStatement
         : kVAR VariableDeclarationList semicolon_opt
-                                { $$ = new_var_statement(ctx, @$, $2); }
+                                { $$ = new_var_statement(ctx, FALSE, FALSE, @$, $2); }
 
 /* ECMA-262 3rd Edition    12.2 */
 VariableDeclarationList
@@ -834,6 +852,7 @@ ReservedAsIdentifier
         : kBREAK                { $$ = $1; }
         | kCASE                 { $$ = $1; }
         | kCATCH                { $$ = $1; }
+        | kCONST                { $$ = $1; }
         | kCONTINUE             { $$ = $1; }
         | kDEFAULT              { $$ = $1; }
         | kDELETE               { $$ = $1; }
@@ -847,6 +866,7 @@ ReservedAsIdentifier
         | kIF                   { $$ = $1; }
         | kIN                   { $$ = $1; }
         | kINSTANCEOF           { $$ = $1; }
+        | kLET                  { $$ = $1; }
         | kNEW                  { $$ = $1; }
         | kNULL                 { $$ = $1; }
         | kRETURN               { $$ = $1; }
@@ -1144,8 +1164,10 @@ static variable_list_t *variable_list_add(parser_ctx_t *ctx, variable_list_t *li
     return list;
 }
 
-static statement_t *new_var_statement(parser_ctx_t *ctx, unsigned loc, variable_list_t *variable_list)
+static statement_t *new_var_statement(parser_ctx_t *ctx, BOOL block_scope, BOOL constant, unsigned loc,
+        variable_list_t *variable_list)
 {
+    variable_declaration_t *var;
     var_statement_t *ret;
 
     ret = new_statement(ctx, STAT_VAR, sizeof(*ret), loc);
@@ -1153,6 +1175,11 @@ static statement_t *new_var_statement(parser_ctx_t *ctx, unsigned loc, variable_
         return NULL;
 
     ret->variable_list = variable_list->head;
+    for (var = ret->variable_list; var; var = var->next)
+    {
+        var->block_scope = block_scope;
+        var->constant = constant;
+    }
 
     return &ret->stat;
 }
diff --git a/dlls/jscript/tests/lang.js b/dlls/jscript/tests/lang.js
index 9e6e6ad239f..0db86c89985 100644
--- a/dlls/jscript/tests/lang.js
+++ b/dlls/jscript/tests/lang.js
@@ -2030,3 +2030,37 @@ Math = 6;
 ok(Math === 6, "NaN !== 6");
 
 reportSuccess();
+
+function test_es5_keywords() {
+    var let = 1
+    var tmp
+    ok(let == 1, "let != 1");
+
+    tmp = false
+    try {
+        eval('var var = 1;');
+    }
+    catch(e) {
+        tmp = true
+    }
+    ok(tmp === true, "Expected exception for 'var var = 1;'");
+
+    tmp = false
+    try {
+        eval('var const = 1;');
+    }
+    catch(e) {
+        tmp = true
+    }
+    ok(tmp === true, "Expected exception for 'var const = 1;'");
+
+    tmp = false
+    try {
+        eval('const c1 = 1;');
+    }
+    catch(e) {
+        tmp = true
+    }
+    ok(tmp === true, "Expected exception for 'const c1 = 1;'");
+}
+test_es5_keywords();
diff --git a/dlls/mshtml/tests/es5.js b/dlls/mshtml/tests/es5.js
index 7e46848d40e..24906de5231 100644
--- a/dlls/mshtml/tests/es5.js
+++ b/dlls/mshtml/tests/es5.js
@@ -1207,3 +1207,20 @@ sync_test("head_setter", function() {
     document.head = "";
     ok(typeof(document.head) === "object", "typeof(document.head) = " + typeof(document.head));
 });
+
+
+sync_test("declaration_let", function() {
+    ok(a === undefined, "a is not undefined");
+    var a = 3;
+
+    {
+        let a = 2;
+
+        ok(a == 2, "a != 2");
+
+        a = 4;
+        ok(a == 4, "a != 4");
+    }
+
+    todo_wine.ok(a == 3, "a != 3");
+});




More information about the wine-cvs mailing list