[njs] Added support for shorthand property names for Object literals.

Dmitry Volyntsev xeioex at nginx.com
Mon Feb 11 15:16:23 UTC 2019


details:   https://hg.nginx.org/njs/rev/eb099f4faf40
branches:  
changeset: 774:eb099f4faf40
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Feb 11 18:15:43 2019 +0300
description:
Added support for shorthand property names for Object literals.

This closes #87 issue on Github.

diffstat:

 njs/njs_lexer.c          |   8 +++++-
 njs/njs_parser.c         |  56 +++++++++++++++++++++++++++++++++++++++--------
 njs/njs_parser.h         |   3 ++
 njs/test/njs_unit_test.c |  38 ++++++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 12 deletions(-)

diffs (190 lines):

diff -r a091eaa9d8eb -r eb099f4faf40 njs/njs_lexer.c
--- a/njs/njs_lexer.c	Sat Feb 09 17:34:04 2019 +0800
+++ b/njs/njs_lexer.c	Mon Feb 11 18:15:43 2019 +0300
@@ -459,7 +459,8 @@ njs_lexer_next_token(njs_lexer_t *lexer)
 static njs_token_t
 njs_lexer_word(njs_lexer_t *lexer, u_char c)
 {
-    u_char  *p;
+    u_char       *p;
+    njs_token_t  token;
 
     /* TODO: UTF-8 */
 
@@ -498,11 +499,14 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha
     lexer->start = p;
     lexer->text.length = p - lexer->text.start;
 
+    token = njs_lexer_keyword(lexer);
+
     if (lexer->property) {
+        lexer->property_token = token;
         return NJS_TOKEN_NAME;
     }
 
-    return njs_lexer_keyword(lexer);
+    return token;
 }
 
 
diff -r a091eaa9d8eb -r eb099f4faf40 njs/njs_parser.c
--- a/njs/njs_parser.c	Sat Feb 09 17:34:04 2019 +0800
+++ b/njs/njs_parser.c	Mon Feb 11 18:15:43 2019 +0300
@@ -2215,13 +2215,29 @@ njs_parser_builtin(njs_vm_t *vm, njs_par
 }
 
 
+/*
+ * ES6: 12.2.6 Object Initializer
+ * Supported syntax:
+ *   PropertyDefinition:
+ *     PropertyName : AssignmentExpression
+ *     IdentifierReference
+ *   PropertyName:
+ *    IdentifierName, StringLiteral, NumericLiteral.
+ */
 static njs_token_t
 njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
 {
+    uint32_t           hash;
+    nxt_str_t          name;
     njs_token_t        token;
-    njs_parser_node_t  *stmt, *assign, *object, *propref, *left;
+    njs_lexer_t        *lexer;
+    njs_parser_node_t  *stmt, *assign, *object, *propref, *left, *expression;
 
     left = NULL;
+    lexer = parser->lexer;
+
+    /* GCC and Clang complain about uninitialized hash. */
+    hash = 0;
 
     object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
     if (nxt_slow_path(object == NULL)) {
@@ -2233,12 +2249,17 @@ njs_parser_object(njs_vm_t *vm, njs_pars
     for ( ;; ) {
         token = njs_parser_property_token(vm, parser);
 
+        name.start = NULL;
+
         switch (token) {
 
         case NJS_TOKEN_CLOSE_BRACE:
             return njs_parser_token(parser);
 
         case NJS_TOKEN_NAME:
+            name = lexer->text;
+            hash = lexer->key_hash;
+
             token = njs_parser_token(parser);
             break;
 
@@ -2264,14 +2285,29 @@ njs_parser_object(njs_vm_t *vm, njs_pars
         propref->left = object;
         propref->right = parser->node;
 
-        token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
-        }
-
-        token = njs_parser_assignment_expression(vm, parser, token);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
+        if (name.start != NULL
+            && (token == NJS_TOKEN_COMMA || token == NJS_TOKEN_CLOSE_BRACE)
+            && lexer->property_token != NJS_TOKEN_THIS
+            && lexer->property_token != NJS_TOKEN_GLOBAL_THIS)
+        {
+            expression = njs_parser_reference(vm, parser, lexer->property_token,
+                                              &name, hash);
+            if (nxt_slow_path(expression == NULL)) {
+                return NJS_TOKEN_ERROR;
+            }
+
+        } else {
+            token = njs_parser_match(vm, parser, token, NJS_TOKEN_COLON);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            token = njs_parser_assignment_expression(vm, parser, token);
+            if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
+                return token;
+            }
+
+            expression = parser->node;
         }
 
         assign = njs_parser_node_new(vm, parser, NJS_TOKEN_ASSIGNMENT);
@@ -2281,7 +2317,7 @@ njs_parser_object(njs_vm_t *vm, njs_pars
 
         assign->u.operation = njs_vmcode_move;
         assign->left = propref;
-        assign->right = parser->node;
+        assign->right = expression;
 
         stmt = njs_parser_node_new(vm, parser, NJS_TOKEN_STATEMENT);
         if (nxt_slow_path(stmt == NULL)) {
diff -r a091eaa9d8eb -r eb099f4faf40 njs/njs_parser.h
--- a/njs/njs_parser.h	Sat Feb 09 17:34:04 2019 +0800
+++ b/njs/njs_parser.h	Mon Feb 11 18:15:43 2019 +0300
@@ -210,7 +210,10 @@ typedef enum {
 typedef struct {
     njs_token_t                     token:16;
     njs_token_t                     prev_token:16;
+
     uint8_t                         property;      /* 1 bit */
+    njs_token_t                     property_token:16;
+
     uint32_t                        key_hash;
 
     uint32_t                        token_line;
diff -r a091eaa9d8eb -r eb099f4faf40 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Sat Feb 09 17:34:04 2019 +0800
+++ b/njs/test/njs_unit_test.c	Mon Feb 11 18:15:43 2019 +0300
@@ -2761,6 +2761,44 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("var x = { a: 1 }, b = delete x.a; x.a +' '+ b"),
       nxt_string("undefined true") },
 
+    /* Shorthand Object literals. */
+
+    { nxt_string("var a = 1; njs.dump({a})"),
+      nxt_string("{a:1}") },
+
+    { nxt_string("var a = 1, b; njs.dump({a,b})"),
+      nxt_string("{a:1,b:undefined}") },
+
+    { nxt_string("var a = 1, b = 2; ({a,b,c})"),
+      nxt_string("ReferenceError: \"c\" is not defined in 1") },
+
+    { nxt_string("var a = 1, b = 2; njs.dump({a,b,c:3})"),
+      nxt_string("{a:1,b:2,c:3}") },
+
+    { nxt_string("var b = 2, c = 3; njs.dump({a:1,b,c})"),
+      nxt_string("{a:1,b:2,c:3}") },
+
+    { nxt_string("({1})"),
+      nxt_string("SyntaxError: Unexpected token \"}\" in 1") },
+
+    { nxt_string("({default})"),
+      nxt_string("SyntaxError: Unexpected token \"}\" in 1") },
+
+    { nxt_string("({var})"),
+      nxt_string("SyntaxError: Unexpected token \"}\" in 1") },
+
+    { nxt_string("({this})"),
+        nxt_string("SyntaxError: Unexpected token \"}\" in 1") },
+
+    { nxt_string("typeof ({Number}).Number"),
+      nxt_string("function") },
+
+    { nxt_string("typeof ({eval}).eval"),
+      nxt_string("function") },
+
+    { nxt_string("typeof ({Math}).Math.sin"),
+      nxt_string("function") },
+
     { nxt_string("delete null"),
       nxt_string("true") },
 


More information about the nginx-devel mailing list