[njs] Improved working with undefined symbols.

Alexander Borisov alexander.borisov at nginx.com
Wed May 22 18:05:22 UTC 2019


details:   https://hg.nginx.org/njs/rev/88c5787352b2
branches:  
changeset: 978:88c5787352b2
user:      Alexander Borisov <alexander.borisov at nginx.com>
date:      Wed May 22 21:01:39 2019 +0300
description:
Improved working with undefined symbols.

Throwing ReferenceError in runtime.

This closes #150 issue on GitHub.

diffstat:

 njs/njs_disassembler.c   |   8 ++++++++
 njs/njs_generator.c      |  33 ++++++++++++++++++++++++++++++---
 njs/njs_variable.c       |  19 +++----------------
 njs/njs_variable.h       |   1 +
 njs/njs_vm.c             |  15 +++++++++++++++
 njs/njs_vm.h             |   9 +++++++++
 njs/test/njs_unit_test.c |  24 ++++++++++++++++++++++++
 7 files changed, 90 insertions(+), 19 deletions(-)

diffs (244 lines):

diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_disassembler.c
--- a/njs/njs_disassembler.c	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_disassembler.c	Wed May 22 21:01:39 2019 +0300
@@ -411,6 +411,14 @@ njs_disassemble(u_char *start, u_char *e
             continue;
         }
 
+        if (operation == njs_vmcode_reference_error) {
+            nxt_printf("%05uz REFERENCE ERROR\n", p - start);
+
+            p += sizeof(njs_vmcode_reference_error_t);
+
+            continue;
+        }
+
         code_name = code_names;
         n = nxt_nitems(code_names);
 
diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_generator.c
--- a/njs/njs_generator.c	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_generator.c	Wed May 22 21:01:39 2019 +0300
@@ -174,6 +174,8 @@ static nxt_noinline nxt_int_t njs_genera
     njs_generator_t *generator, njs_parser_node_t *node);
 static nxt_noinline nxt_int_t njs_generate_index_release(njs_vm_t *vm,
     njs_generator_t *generator, njs_index_t index);
+static nxt_int_t njs_generate_reference_error(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node);
 
 static nxt_int_t njs_generate_function_debug(njs_vm_t *vm,
     const nxt_str_t *name, njs_function_lambda_t *lambda,
@@ -550,7 +552,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
 
     var = njs_variable_resolve(vm, node);
     if (nxt_slow_path(var == NULL)) {
-        return NXT_ERROR;
+        return njs_generate_reference_error(vm, generator, node);
     }
 
     if (var->type == NJS_VARIABLE_FUNCTION) {
@@ -606,7 +608,7 @@ njs_generate_variable(njs_vm_t *vm, njs_
 
     index = njs_variable_index(vm, node);
     if (nxt_slow_path(index == NJS_INDEX_NONE)) {
-        return NXT_ERROR;
+        return njs_generate_reference_error(vm, generator, node);
     }
 
     node->index = index;
@@ -2304,7 +2306,7 @@ njs_generate_function_declaration(njs_vm
 
     var = njs_variable_resolve(vm, node);
     if (nxt_slow_path(var == NULL)) {
-        return NXT_ERROR;
+        return njs_generate_reference_error(vm, generator, node);
     }
 
     if (!njs_is_function(&var->value)) {
@@ -2591,6 +2593,10 @@ njs_generate_function_call(njs_vm_t *vm,
         name = node;
     }
 
+    if (node->u.reference.not_defined) {
+        return NXT_OK;
+    }
+
     njs_generate_code(generator, njs_vmcode_function_frame_t, func,
                       njs_vmcode_function_frame, 2, 0);
     func_offset = njs_code_offset(generator, func);
@@ -3273,6 +3279,27 @@ njs_generate_index_release(njs_vm_t *vm,
 
 
 static nxt_int_t
+njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
+                             njs_parser_node_t *node)
+{
+    njs_vmcode_reference_error_t  *ref_err;
+
+    if (nxt_slow_path(!node->u.reference.not_defined)) {
+        njs_internal_error(vm, "variable is not defined but not_defined "
+                               "is not set");
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_reference_error_t, ref_err,
+                      njs_vmcode_reference_error, 0, 0);
+
+    ref_err->token_line = node->token_line;
+
+    return njs_name_copy(vm, &ref_err->name, &node->u.reference.name);
+}
+
+
+static nxt_int_t
 njs_generate_function_debug(njs_vm_t *vm, const nxt_str_t *name,
     njs_function_lambda_t *lambda, njs_parser_node_t *node)
 {
diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_variable.c
--- a/njs/njs_variable.c	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_variable.c	Wed May 22 21:01:39 2019 +0300
@@ -280,7 +280,6 @@ njs_variables_scope_resolve(njs_vm_t *vm
 {
     njs_ret_t                 ret;
     nxt_queue_t               *nested;
-    njs_variable_t            *var;
     nxt_queue_link_t          *lnk;
     njs_parser_node_t         *node;
     nxt_lvlhsh_each_t         lhe;
@@ -321,13 +320,7 @@ njs_variables_scope_resolve(njs_vm_t *vm
                 }
             }
 
-            var = njs_variable_resolve(vm, node);
-
-            if (nxt_slow_path(var == NULL)) {
-                if (vr->type != NJS_TYPEOF) {
-                    return NXT_ERROR;
-                }
-            }
+            (void) njs_variable_resolve(vm, node);
         }
     }
 
@@ -415,7 +408,8 @@ njs_variable_resolve(njs_vm_t *vm, njs_p
     ret = njs_variable_reference_resolve(vm, vr, node->scope);
 
     if (nxt_slow_path(ret != NXT_OK)) {
-        goto not_found;
+        node->u.reference.not_defined = 1;
+        return NULL;
     }
 
     scope_index = vr->scope_index;
@@ -455,13 +449,6 @@ njs_variable_resolve(njs_vm_t *vm, njs_p
     node->index = index;
 
     return var;
-
-not_found:
-
-    njs_parser_node_error(vm, node, NJS_OBJECT_REF_ERROR,
-                          "\"%V\" is not defined", &vr->name);
-
-    return NULL;
 }
 
 
diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_variable.h
--- a/njs/njs_variable.h	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_variable.h	Wed May 22 21:01:39 2019 +0300
@@ -50,6 +50,7 @@ typedef struct {
     njs_variable_t        *variable;
     njs_parser_scope_t    *scope;
     nxt_uint_t            scope_index;  /* NJS_SCOPE_INDEX_... */
+    nxt_bool_t            not_defined;
 } njs_variable_reference_t;
 
 
diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_vm.c
--- a/njs/njs_vm.c	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_vm.c	Wed May 22 21:01:39 2019 +0300
@@ -2523,6 +2523,21 @@ njs_vmcode_finally(njs_vm_t *vm, njs_val
 }
 
 
+njs_ret_t
+njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1,
+    njs_value_t *invld2)
+{
+    njs_vmcode_reference_error_t  *ref_err;
+
+    ref_err = (njs_vmcode_reference_error_t *) vm->current;
+
+    njs_reference_error(vm, "\"%V\" is not defined in %uD", &ref_err->name,
+                        ref_err->token_line);
+
+    return NJS_ERROR;
+}
+
+
 static const njs_vmcode_1addr_t  njs_trap_number[] = {
     { .code = { .operation = njs_vmcode_number_primitive,
                 .operands =  NJS_VMCODE_1OPERAND,
diff -r 260d9d4f29ee -r 88c5787352b2 njs/njs_vm.h
--- a/njs/njs_vm.h	Tue May 21 21:15:21 2019 +0300
+++ b/njs/njs_vm.h	Wed May 22 21:01:39 2019 +0300
@@ -849,6 +849,13 @@ typedef struct {
 } njs_vmcode_finally_t;
 
 
+typedef struct {
+    njs_vmcode_t               code;
+    nxt_str_t                  name;
+    uint32_t                   token_line;
+} njs_vmcode_reference_error_t;
+
+
 typedef enum {
     NJS_SCOPE_ABSOLUTE = 0,
     NJS_SCOPE_GLOBAL = 1,
@@ -1303,6 +1310,8 @@ njs_ret_t njs_vmcode_catch(njs_vm_t *vm,
     njs_value_t *exception);
 njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
     njs_value_t *retval);
+njs_ret_t njs_vmcode_reference_error(njs_vm_t *vm, njs_value_t *invld1,
+    njs_value_t *invld2);
 
 nxt_bool_t njs_values_strict_equal(const njs_value_t *val1,
     const njs_value_t *val2);
diff -r 260d9d4f29ee -r 88c5787352b2 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Tue May 21 21:15:21 2019 +0300
+++ b/njs/test/njs_unit_test.c	Wed May 22 21:01:39 2019 +0300
@@ -6294,8 +6294,32 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("a") },
 
     { nxt_string("function f() { var a = f2(); }"),
+      nxt_string("undefined") },
+
+    { nxt_string("function f() { var a = f2(); } f();"),
       nxt_string("ReferenceError: \"f2\" is not defined in 1") },
 
+    { nxt_string("typeof Buffer !== 'undefined' ? Buffer : function Buffer(){}"),
+      nxt_string("[object Function]") },
+
+    { nxt_string("1 == 2 ? func() : '123'"),
+      nxt_string("123") },
+
+    { nxt_string("1 == 1 ? func() : '123'"),
+      nxt_string("ReferenceError: \"func\" is not defined in 1") },
+
+    { nxt_string("function f(){ if (1 == 1) { 1 == 2 ? some_var : '123' } }; f()"),
+      nxt_string("undefined") },
+
+    { nxt_string("function f(){ if (1 == 1) { 1 == 1 ? some_var : '123' } }; f()"),
+      nxt_string("ReferenceError: \"some_var\" is not defined in 1") },
+
+    { nxt_string("function f(){ if (1 == 1) { 1 == 2 ? some_func() : '123' } }; f()"),
+      nxt_string("undefined") },
+
+    { nxt_string("function f(){ if (1 == 1) { 1 == 1 ? some_func() : '123' } }; f()"),
+      nxt_string("ReferenceError: \"some_func\" is not defined in 1") },
+
     { nxt_string("(function(){ function f() {return f}; return f()})()"),
       nxt_string("[object Function]") },
 


More information about the nginx-devel mailing list