]> git.kaiwu.me - njs.git/commitdiff
Improved working with undefined symbols.
authorAlexander Borisov <alexander.borisov@nginx.com>
Wed, 22 May 2019 18:01:39 +0000 (21:01 +0300)
committerAlexander Borisov <alexander.borisov@nginx.com>
Wed, 22 May 2019 18:01:39 +0000 (21:01 +0300)
Throwing ReferenceError in runtime.

This closes #150 issue on GitHub.

njs/njs_disassembler.c
njs/njs_generator.c
njs/njs_variable.c
njs/njs_variable.h
njs/njs_vm.c
njs/njs_vm.h
njs/test/njs_unit_test.c

index d3b64b8e0aae8ff2486d11c64a959838e027e36a..a94debe8b8b7e2dc9f4ec3eec6566e172ea5f706 100644 (file)
@@ -411,6 +411,14 @@ njs_disassemble(u_char *start, u_char *end)
             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);
 
index 8b8e69cdc0ea2d71636d99fb9cd6adb802a3eaac..883d274fd4b3ce6f7d0e808a5cebf58c4348df13 100644 (file)
@@ -174,6 +174,8 @@ static nxt_noinline nxt_int_t njs_generate_node_index_release(njs_vm_t *vm,
     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_generator_t *generator,
 
     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_generator_t *generator,
 
     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_t *vm, njs_generator_t *generator,
 
     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, njs_generator_t *generator,
         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);
@@ -3272,6 +3278,27 @@ njs_generate_index_release(njs_vm_t *vm, njs_generator_t *generator,
 }
 
 
+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)
index 9b930eb2ee2722eaf8aba1c037003b81e52f5d6a..0ce7477e1b6d9f0b76418aeeec2dc7d772489d7d 100644 (file)
@@ -280,7 +280,6 @@ njs_variables_scope_resolve(njs_vm_t *vm, njs_parser_scope_t *scope,
 {
     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, njs_parser_scope_t *scope,
                 }
             }
 
-            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_parser_node_t *node)
     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_parser_node_t *node)
     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;
 }
 
 
index 468890f91d3c803893164e149d9717c5ec829e7c..f5fc9db034aade4e373841faed7e45a2e26560bb 100644 (file)
@@ -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;
 
 
index f2123512708123b1af380778e2649b151f4f6036..882e42376af78d2f27ce75f474895b851abaa872 100644 (file)
@@ -2523,6 +2523,21 @@ 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)
+{
+    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,
index e1e18353d5d6786e71773d01fcff647702c7fc52..4ce29eeac2baced4b932a56476d194a8f08ba1cc 100644 (file)
@@ -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 *invld,
     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);
index 683a86c6dfb4548a7cb99cea6058e8c22f2344fc..6d285f2e39e03649ef1dadb8c46de1270d7e582a 100644 (file)
@@ -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]") },