]> git.kaiwu.me - njs.git/commitdiff
This object as a variable.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 10 Apr 2019 14:46:29 +0000 (17:46 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 10 Apr 2019 14:46:29 +0000 (17:46 +0300)
Non-local this is introduced to support arrow functions.
this is non-local when reference scope != first non-arrow
function scope.

njs/njs_disassembler.c
njs/njs_generator.c
njs/njs_lexer.h
njs/njs_parser.h
njs/njs_parser_terminal.c
njs/njs_variable.h
njs/njs_vm.c
njs/njs_vm.h

index 55a7bcbf854c2e57c6ae649e0f051f3135e6bf60..f3f9f8371310454cd23bf83c116bbf616c15c989 100644 (file)
@@ -23,6 +23,8 @@ static njs_code_name_t  code_names[] = {
           nxt_string("OBJECT          ") },
     { njs_vmcode_function, sizeof(njs_vmcode_function_t),
           nxt_string("FUNCTION        ") },
+    { njs_vmcode_this, sizeof(njs_vmcode_this_t),
+          nxt_string("THIS            ") },
     { njs_vmcode_arguments, sizeof(njs_vmcode_arguments_t),
           nxt_string("ARGUMENTS       ") },
     { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
index f114332333b1473e262e788a00ace5c88081ef6c..35beb5804333a17a50508c44ed2b6170531fc5fa 100644 (file)
@@ -427,6 +427,7 @@ njs_generator(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
 
     case NJS_TOKEN_NAME:
     case NJS_TOKEN_ARGUMENTS:
+    case NJS_TOKEN_NON_LOCAL_THIS:
         return njs_generate_name(vm, generator, node);
 
     case NJS_TOKEN_GLOBAL_THIS:
@@ -2414,6 +2415,7 @@ njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator,
     njs_variable_t          *var;
     njs_vmcode_move_t       *move;
     nxt_lvlhsh_each_t       lhe;
+    njs_vmcode_this_t       *this;
     njs_vmcode_arguments_t  *arguments;
 
     nxt_lvlhsh_each_init(&lhe, &njs_variables_hash_proto);
@@ -2431,6 +2433,12 @@ njs_generate_lambda_variables(njs_vm_t *vm, njs_generator_t *generator,
             njs_generate_code_move(generator, move, var->index, index);
         }
 
+        if (var->this_object) {
+            njs_generate_code(generator, njs_vmcode_this_t, this,
+                              njs_vmcode_this, 1, 0);
+            this->dst = var->index;
+        }
+
         if (var->arguments_object) {
             njs_generate_code(generator, njs_vmcode_arguments_t, arguments,
                               njs_vmcode_arguments, 1, 0);
index 62712ac8a08d70e2faebb549470ab245a4af8223..957587477ad26e55ceb5806c12e941cafe8b0c38 100644 (file)
@@ -159,6 +159,7 @@ typedef enum {
     NJS_TOKEN_THROW,
 
     NJS_TOKEN_THIS,
+    NJS_TOKEN_NON_LOCAL_THIS,
     NJS_TOKEN_ARGUMENTS,
 
 #define NJS_TOKEN_FIRST_OBJECT     NJS_TOKEN_GLOBAL_THIS
index 95fb681ac535d1a4c0d0632dfaa14c4ca1c5920d..d2cfff5f168d7e2d42269038cb50be31f7601884 100644 (file)
@@ -225,6 +225,21 @@ njs_parser_global_scope(njs_vm_t *vm)
 }
 
 
+nxt_inline njs_parser_scope_t *
+njs_function_scope(njs_parser_scope_t *scope)
+{
+    while (scope->type != NJS_SCOPE_GLOBAL) {
+        if (scope->type == NJS_SCOPE_FUNCTION) {
+            return scope;
+        }
+
+        scope = scope->parent;
+    }
+
+    return NULL;
+}
+
+
 extern const nxt_lvlhsh_proto_t  njs_keyword_hash_proto;
 
 
index 554619026ae2b8f89625f7aaca22f7e6a901c534..1e552f90d1ce0d39d0e61211e97189b9dc092e31 100644 (file)
@@ -215,14 +215,38 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
 
         while (scope->type != NJS_SCOPE_GLOBAL) {
             if (scope->type == NJS_SCOPE_FUNCTION) {
-                node->index = NJS_INDEX_THIS;
                 break;
             }
 
             scope = scope->parent;
         }
 
-        if (node->index == NJS_INDEX_THIS) {
+        if (scope->type != NJS_SCOPE_GLOBAL) {
+            if (njs_function_scope(scope)
+                == njs_function_scope(parser->scope))
+            {
+                node->index = NJS_INDEX_THIS;
+
+            } else {
+                node->token = NJS_TOKEN_NON_LOCAL_THIS;
+
+                node->token_line = token_line;
+
+                ret = njs_variable_reference(vm, parser->scope, node, name,
+                                             hash, NJS_REFERENCE);
+                if (nxt_slow_path(ret != NXT_OK)) {
+                    return NULL;
+                }
+
+                var = njs_variable_add(vm, parser->scope, name, hash,
+                                       NJS_VARIABLE_VAR);
+                if (nxt_slow_path(var == NULL)) {
+                    return NULL;
+                }
+
+                var->this_object = 1;
+            }
+
             break;
         }
 
index 12d38b92cf86ed706fd11ec57184089aeae23155..468890f91d3c803893164e149d9717c5ec829e7c 100644 (file)
@@ -23,6 +23,7 @@ typedef struct {
 
     njs_variable_type_t   type:8;    /* 3 bits */
     uint8_t               argument;
+    uint8_t               this_object;
     uint8_t               arguments_object;
 
     njs_index_t           index;
index ff2c0fe3f6b7c4f6d50e5675bd56b84a99838d93..7c630461bce59039e0325359d1284a2c3a45b3a1 100644 (file)
@@ -390,6 +390,23 @@ njs_vmcode_function(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 }
 
 
+njs_ret_t
+njs_vmcode_this(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
+{
+    njs_frame_t        *frame;
+    njs_value_t        *value;
+    njs_vmcode_this_t  *code;
+
+    frame = (njs_frame_t *) vm->active_frame;
+    code = (njs_vmcode_this_t *) vm->current;
+
+    value = njs_vmcode_operand(vm, code->dst);
+    *value = frame->native.arguments[0];
+
+    return sizeof(njs_vmcode_this_t);
+}
+
+
 njs_ret_t
 njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
 {
index 565620e4287d616c641c0e65fb2dbc0a19ae8a3f..2fdc5a4db06246337a31e2f7b15b60772a7046bf 100644 (file)
@@ -637,6 +637,12 @@ typedef struct {
 } njs_vmcode_object_t;
 
 
+typedef struct {
+     njs_vmcode_t              code;
+     njs_index_t               dst;
+} njs_vmcode_this_t;
+
+
 typedef struct {
     njs_vmcode_t               code;
     njs_index_t                dst;
@@ -1141,6 +1147,8 @@ njs_ret_t njs_vmcode_array(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *inlvd2);
 njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *invld2);
+njs_ret_t njs_vmcode_this(njs_vm_t *vm, njs_value_t *inlvd1,
+    njs_value_t *invld2);
 njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *inlvd1,
     njs_value_t *invld2);
 njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,