]> git.kaiwu.me - njs.git/commitdiff
Added support for shorthand property names for Object literals.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 11 Feb 2019 15:15:43 +0000 (18:15 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 11 Feb 2019 15:15:43 +0000 (18:15 +0300)
This closes #87 issue on Github.

njs/njs_lexer.c
njs/njs_parser.c
njs/njs_parser.h
njs/test/njs_unit_test.c

index acf4400b2153f3fe46500b0e4d3ebae9b04cf655..469499bdd27f42787f811ceb7fee4025d2649d98 100644 (file)
@@ -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_char c)
     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;
 }
 
 
index 31c9c72544b6bb536ea9bff0dea6961ac7db10ab..7141c801902c04f51f24b568f6581954f9f084b0 100644 (file)
@@ -2215,13 +2215,29 @@ njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
 }
 
 
+/*
+ * 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_parser_t *parser, njs_parser_node_t *obj)
     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_parser_t *parser, njs_parser_node_t *obj)
         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;
-        }
+        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;
+            }
 
-        token = njs_parser_assignment_expression(vm, parser, token);
-        if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
-            return token;
+        } 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_parser_t *parser, njs_parser_node_t *obj)
 
         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)) {
index a2b536fd8c1c420368c6588ce8ef32969e15376a..63b9d948f71791eaec43e363e4a5afacb1a24483 100644 (file)
@@ -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;
index 95fae275f760687120d1b9c87b0ac2ef857e237e..90b5db41b4723dc4d31dad4774379299049d2cb5 100644 (file)
@@ -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") },