[njs] Adding textual description for type converting exceptions.

Dmitry Volyntsev xeioex at nginx.com
Mon Feb 12 11:56:32 UTC 2018


details:   http://hg.nginx.org/njs/rev/0daf5a5cd37a
branches:  
changeset: 442:0daf5a5cd37a
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Feb 12 14:54:24 2018 +0300
description:
Adding textual description for type converting exceptions.

diffstat:

 njs/njs_array.c                 |   13 +-
 njs/njs_boolean.c               |    6 +-
 njs/njs_date.c                  |    2 +-
 njs/njs_error.c                 |    2 +-
 njs/njs_function.c              |   17 +--
 njs/njs_number.c                |    6 +-
 njs/njs_object.c                |   49 ++++++++--
 njs/njs_regexp.c                |    6 +-
 njs/njs_string.c                |   12 +-
 njs/njs_vm.c                    |  179 ++++++++++++++++++++++++++++++++++++---
 njs/njs_vm.h                    |    2 +
 njs/test/njs_expect_test.exp    |    7 +-
 njs/test/njs_interactive_test.c |   18 ++--
 njs/test/njs_unit_test.c        |  108 ++++++++++++-----------
 14 files changed, 306 insertions(+), 121 deletions(-)

diffs (truncated from 1155 to 1000 lines):

diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_array.c
--- a/njs/njs_array.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_array.c	Mon Feb 12 14:54:24 2018 +0300
@@ -1714,7 +1714,7 @@ njs_array_prototype_reduce(njs_vm_t *vm,
         n = njs_array_iterator_index(array, iter);
 
         if (n == NJS_ARRAY_INVALID_INDEX) {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "invalid index", NULL);
             return NXT_ERROR;
         }
 
@@ -1775,7 +1775,7 @@ njs_array_iterator_args(njs_vm_t *vm, nj
         return NXT_OK;
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "unexpected iterator arguments", NULL);
 
     return NXT_ERROR;
 }
@@ -1849,7 +1849,9 @@ njs_array_prototype_reduce_right(njs_vm_
         n = njs_array_reduce_right_index(array, iter);
 
         if (n == NJS_ARRAY_INVALID_INDEX) {
-            goto type_error;
+            njs_exception_type_error(vm, "invalid index", NULL);
+
+            return NXT_ERROR;
         }
 
         iter->retval = array->start[n];
@@ -1857,11 +1859,6 @@ njs_array_prototype_reduce_right(njs_vm_
 
     return njs_array_prototype_reduce_right_continuation(vm, args, nargs,
                                                          unused);
-type_error:
-
-    njs_exception_type_error(vm, NULL, NULL);
-
-    return NXT_ERROR;
 }
 
 
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_boolean.c
--- a/njs/njs_boolean.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_boolean.c	Mon Feb 12 14:54:24 2018 +0300
@@ -99,7 +99,8 @@ njs_boolean_prototype_value_of(njs_vm_t 
             value = &value->data.u.object_value->value;
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected value type:%s",
+                                     njs_type_string(value->type));
             return NXT_ERROR;
         }
     }
@@ -124,7 +125,8 @@ njs_boolean_prototype_to_string(njs_vm_t
             value = &value->data.u.object_value->value;
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected value type:%s",
+                                     njs_type_string(value->type));
             return NXT_ERROR;
         }
     }
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_date.c
--- a/njs/njs_date.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_date.c	Mon Feb 12 14:54:24 2018 +0300
@@ -1911,7 +1911,7 @@ njs_date_prototype_to_json(njs_vm_t *vm,
         }
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "'this' argument is not an object", NULL);
 
     return NXT_ERROR;
 }
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_error.c
--- a/njs/njs_error.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_error.c	Mon Feb 12 14:54:24 2018 +0300
@@ -612,7 +612,7 @@ njs_error_prototype_to_string(njs_vm_t *
     static const njs_value_t  default_name = njs_string("Error");
 
     if (nargs < 1 || !njs_is_object(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is not an object", NULL);
         return NXT_ERROR;
     }
 
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_function.c
--- a/njs/njs_function.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_function.c	Mon Feb 12 14:54:24 2018 +0300
@@ -509,7 +509,7 @@ njs_function_prototype_call(njs_vm_t *vm
     njs_function_t  *function;
 
     if (!njs_is_function(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is not a function", NULL);
         return NXT_ERROR;
     }
 
@@ -537,7 +537,8 @@ njs_function_prototype_apply(njs_vm_t *v
     njs_function_t  *function;
 
     if (!njs_is_function(&args[0])) {
-        goto type_error;
+        njs_exception_type_error(vm, "'this' argument is not a function", NULL);
+        return NXT_ERROR;
     }
 
     function = args[0].data.u.function;
@@ -545,7 +546,9 @@ njs_function_prototype_apply(njs_vm_t *v
 
     if (nargs > 2) {
         if (!njs_is_array(&args[2])) {
-            goto type_error;
+            njs_exception_type_error(vm, "second argument is not an array",
+                                     NULL);
+            return NXT_ERROR;
         }
 
         array = args[2].data.u.array;
@@ -561,12 +564,6 @@ njs_function_prototype_apply(njs_vm_t *v
     }
 
     return njs_function_activate(vm, function, this, args, nargs, retval);
-
-type_error:
-
-    njs_exception_type_error(vm, NULL, NULL);
-
-    return NXT_ERROR;
 }
 
 
@@ -622,7 +619,7 @@ njs_function_prototype_bind(njs_vm_t *vm
     njs_function_t  *function;
 
     if (!njs_is_function(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is not a function", NULL);
         return NXT_ERROR;
     }
 
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_number.c
--- a/njs/njs_number.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_number.c	Mon Feb 12 14:54:24 2018 +0300
@@ -586,7 +586,8 @@ njs_number_prototype_value_of(njs_vm_t *
             value = &value->data.u.object_value->value;
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected value type:%s",
+                                     njs_type_string(value->type));
             return NXT_ERROR;
         }
     }
@@ -612,7 +613,8 @@ njs_number_prototype_to_string(njs_vm_t 
             value = &value->data.u.object_value->value;
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected value type:%s",
+                                     njs_type_string(value->type));
             return NXT_ERROR;
         }
     }
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_object.c
--- a/njs/njs_object.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_object.c	Mon Feb 12 14:54:24 2018 +0300
@@ -224,8 +224,6 @@ njs_object_property(njs_vm_t *vm, njs_ob
 
     } while (object != NULL);
 
-    njs_exception_type_error(vm, NULL, NULL);
-
     return NULL;
 }
 
@@ -264,7 +262,8 @@ njs_object_constructor(njs_vm_t *vm, njs
             type = njs_object_value_type(value->type);
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected constructor argument:%s",
+                                     njs_type_string(value->type));
 
             return NXT_ERROR;
         }
@@ -312,7 +311,7 @@ njs_object_create(njs_vm_t *vm, njs_valu
         }
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "too few arguments", NULL);
 
     return NXT_ERROR;
 }
@@ -325,7 +324,10 @@ njs_object_keys(njs_vm_t *vm, njs_value_
     njs_array_t  *keys;
 
     if (nargs < 2 || !njs_is_object(&args[1])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "cannot convert %s argument to object",
+                                 (nargs >= 2) ? njs_type_string(args[1].type)
+                                              : "null");
+
         return NXT_ERROR;
     }
 
@@ -426,15 +428,24 @@ static njs_ret_t
 njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
-    nxt_int_t  ret;
+    nxt_int_t   ret;
+    const char  *type;
 
     if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        if (nargs < 2 || !njs_is_object(&args[1])) {
+            type = (nargs > 1) ? njs_type_string(args[1].type) : "null";
+            njs_exception_type_error(vm, "cannot convert %s argument to object",
+                                     type);
+
+        } else {
+            njs_exception_type_error(vm, "descriptor is not an object", NULL);
+        }
+
         return NXT_ERROR;
     }
 
     if (!args[1].data.u.object->extensible) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "object is not extensible", NULL);
         return NXT_ERROR;
     }
 
@@ -456,18 +467,27 @@ njs_object_define_properties(njs_vm_t *v
     njs_index_t unused)
 {
     nxt_int_t          ret;
+    const char         *type;
     nxt_lvlhsh_t       *hash;
     njs_object_t       *object;
     nxt_lvlhsh_each_t  lhe;
     njs_object_prop_t  *prop;
 
     if (nargs < 3 || !njs_is_object(&args[1]) || !njs_is_object(&args[2])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        if (nargs < 2 || !njs_is_object(&args[1])) {
+            type = (nargs > 1) ? njs_type_string(args[1].type) : "null";
+            njs_exception_type_error(vm, "cannot convert %s argument to object",
+                                     type);
+
+        } else {
+            njs_exception_type_error(vm, "descriptor is not an object", NULL);
+        }
+
         return NXT_ERROR;
     }
 
     if (!args[1].data.u.object->extensible) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "object is not extensible", NULL);
         return NXT_ERROR;
     }
 
@@ -590,6 +610,7 @@ njs_object_get_own_property_descriptor(n
 {
     uint32_t            index;
     nxt_int_t           ret;
+    const char          *type;
     njs_array_t         *array;
     njs_object_t        *descriptor;
     njs_object_prop_t   *pr, *prop, array_prop;
@@ -597,7 +618,9 @@ njs_object_get_own_property_descriptor(n
     nxt_lvlhsh_query_t  lhq;
 
     if (nargs < 3 || !njs_is_object(&args[1])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        type = (nargs > 1) ? njs_type_string(args[1].type) : "null";
+        njs_exception_type_error(vm, "cannot convert %s argument to object",
+                                 type);
         return NXT_ERROR;
     }
 
@@ -726,7 +749,9 @@ njs_object_get_prototype_of(njs_vm_t *vm
         return NXT_OK;
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "cannot convert %s argument to object",
+                             (nargs > 1) ? njs_type_string(args[1].type)
+                                         : "null");
     return NXT_ERROR;
 }
 
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_regexp.c
--- a/njs/njs_regexp.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_regexp.c	Mon Feb 12 14:54:24 2018 +0300
@@ -573,7 +573,7 @@ njs_regexp_prototype_to_string(njs_vm_t 
         return njs_regexp_string_create(vm, &vm->retval, source, size, length);
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "'this' argument is not a regexp", NULL);
 
     return NXT_ERROR;
 }
@@ -591,7 +591,7 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
     njs_regexp_pattern_t  *pattern;
 
     if (!njs_is_regexp(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is not a regexp", NULL);
         return NXT_ERROR;
     }
 
@@ -641,7 +641,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, 
     nxt_regex_match_data_t  *match_data;
 
     if (!njs_is_regexp(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is not a regexp", NULL);
         return NXT_ERROR;
     }
 
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_string.c
--- a/njs/njs_string.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_string.c	Mon Feb 12 14:54:24 2018 +0300
@@ -553,7 +553,8 @@ njs_string_prototype_value_of(njs_vm_t *
             value = &value->data.u.object_value->value;
 
         } else {
-            njs_exception_type_error(vm, NULL, NULL);
+            njs_exception_type_error(vm, "unexpected value type:%s",
+                                     njs_type_string(value->type));
             return NXT_ERROR;
         }
     }
@@ -578,7 +579,8 @@ njs_string_prototype_concat(njs_vm_t *vm
     njs_string_prop_t  string;
 
     if (njs_is_null_or_void(&args[0])) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "'this' argument is null or undefined",
+                                 NULL);
         return NXT_ERROR;
     }
 
@@ -2539,7 +2541,8 @@ njs_string_replace_regexp_continuation(n
 
     nxt_regex_match_data_free(r->match_data, vm->regex_context);
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_internal_error(vm, "unexpected continuation retval type:%s",
+                                 njs_type_string(r->retval.type));
 
     return NXT_ERROR;
 }
@@ -2651,7 +2654,8 @@ njs_string_replace_search_continuation(n
         return njs_string_replace_join(vm, r);
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_internal_error(vm, "unexpected continuation retval type:%s",
+                                 njs_type_string(r->retval.type));
 
     return NXT_ERROR;
 }
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_vm.c
--- a/njs/njs_vm.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_vm.c	Mon Feb 12 14:54:24 2018 +0300
@@ -674,7 +674,8 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
     njs_vmcode_prop_set_t  *code;
 
     if (njs_is_primitive(object)) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "property set on primitive %s type",
+                                 njs_type_string(object->type));
         return NXT_ERROR;
     }
 
@@ -794,7 +795,7 @@ njs_vmcode_property_in(njs_vm_t *vm, njs
 
     case NJS_PRIMITIVE_VALUE:
     case NJS_STRING_VALUE:
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "property in on a primitive value", NULL);
 
         return NXT_ERROR;
 
@@ -1039,7 +1040,23 @@ njs_property_query(njs_vm_t *vm, njs_pro
         break;
 
     default:  /* NJS_VOID, NJS_NULL. */
-        njs_exception_type_error(vm, NULL, NULL);
+        if (nxt_fast_path(njs_is_primitive(property))) {
+
+            ret = njs_primitive_value_to_string(vm, &pq->value, property);
+
+            if (nxt_fast_path(ret == NXT_OK)) {
+                njs_string_get(&pq->value, &pq->lhq.key);
+                njs_exception_type_error(vm,
+                                      "cannot get property '%.*s' of undefined",
+                                      (int) pq->lhq.key.length,
+                                      pq->lhq.key.start);
+                return NXT_ERROR;
+            }
+        }
+
+        njs_exception_type_error(vm,
+                            "cannot get property 'unknown' of undefined", NULL);
+
         return NXT_ERROR;
     }
 
@@ -1322,7 +1339,7 @@ njs_vmcode_instance_of(njs_vm_t *vm, njs
     nxt_lvlhsh_query_t  lhq;
 
     if (!njs_is_function(constructor)) {
-        njs_exception_type_error(vm, NULL, NULL);
+        njs_exception_type_error(vm, "right argument is not a function", NULL);
         return NXT_ERROR;
     }
 
@@ -2245,7 +2262,7 @@ njs_function_frame_create(njs_vm_t *vm, 
         }
     }
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "object is not callable", NULL);
 
     return NXT_ERROR;
 }
@@ -2304,7 +2321,9 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
 
     pq.query = NJS_PROPERTY_QUERY_GET;
 
-    switch (njs_property_query(vm, &pq, object, name)) {
+    ret = njs_property_query(vm, &pq, object, name);
+
+    switch (ret) {
 
     case NXT_OK:
         prop = pq.lhq.value;
@@ -2326,13 +2345,20 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
         ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
 
         if (nxt_slow_path(ret != NXT_OK)) {
-            goto type_error;
+            njs_exception_type_error(vm,
+                            "cannot find property '%.*s' of an external object",
+                            (int) pq.lhq.key.length, pq.lhq.key.start);
+            return NXT_ERROR;
+
         }
 
         ext = pq.lhq.value;
 
         if (nxt_slow_path(ext->type != NJS_EXTERN_METHOD)) {
-            goto type_error;
+            njs_exception_type_error(vm,
+                          "method '%.*s' of an external object is not callable",
+                          (int) pq.lhq.key.length, pq.lhq.key.start);
+            return NXT_ERROR;
         }
 
         this.data.u.data = vm->external[ext->object];
@@ -2342,7 +2368,10 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
         break;
 
     default:
-        goto type_error;
+        njs_exception_internal_error(vm, "method '%.*s' query failed:%d",
+                                     (int) pq.lhq.key.length, pq.lhq.key.start,
+                                     ret);
+        return NXT_ERROR;
     }
 
     if (nxt_fast_path(ret == NXT_OK)) {
@@ -2350,12 +2379,6 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
     }
 
     return ret;
-
-type_error:
-
-    njs_exception_type_error(vm, NULL, NULL);
-
-    return NXT_ERROR;
 }
 
 
@@ -2574,12 +2597,130 @@ trap:
 
 type_error:
 
-    njs_exception_type_error(vm, NULL, NULL);
+    njs_exception_type_error(vm, "cannot convert %s to %s",
+                             njs_type_string(args->type),
+                             njs_arg_type_string(*args_types));
 
     return NXT_ERROR;
 }
 
 
+const char *
+njs_type_string(njs_value_type_t type)
+{
+    switch (type) {
+    case NJS_NULL:
+        return "null";
+
+    case NJS_VOID:
+        return "void";
+
+    case NJS_BOOLEAN:
+        return "boolean";
+
+    case NJS_NUMBER:
+        return "number";
+
+    case NJS_STRING:
+        return "string";
+
+    case NJS_EXTERNAL:
+        return "external";
+
+    case NJS_INVALID:
+        return "invalid";
+
+    case NJS_OBJECT:
+        return "object";
+
+    case NJS_ARRAY:
+        return "array";
+
+    case NJS_OBJECT_BOOLEAN:
+        return "object boolean";
+
+    case NJS_OBJECT_NUMBER:
+        return "object number";
+
+    case NJS_OBJECT_STRING:
+        return "object string";
+
+    case NJS_FUNCTION:
+        return "function";
+
+    case NJS_REGEXP:
+        return "regexp";
+
+    case NJS_DATE:
+        return "date";
+
+    case NJS_OBJECT_ERROR:
+        return "error";
+
+    case NJS_OBJECT_EVAL_ERROR:
+        return "eval error";
+
+    case NJS_OBJECT_INTERNAL_ERROR:
+        return "internal error";
+
+    case NJS_OBJECT_RANGE_ERROR:
+        return "range error";
+
+    case NJS_OBJECT_REF_ERROR:
+        return "reference error";
+
+    case NJS_OBJECT_SYNTAX_ERROR:
+        return "syntax error";
+
+    case NJS_OBJECT_TYPE_ERROR:
+        return "type error";
+
+    case NJS_OBJECT_URI_ERROR:
+        return "uri error";
+
+    default:
+        return NULL;
+    }
+}
+
+
+const char *
+njs_arg_type_string(uint8_t arg)
+{
+    switch (arg) {
+    case NJS_SKIP_ARG:
+        return "skip";
+
+    case NJS_NUMBER_ARG:
+        return "number";
+
+    case NJS_INTEGER_ARG:
+        return "integer";
+
+    case NJS_STRING_ARG:
+        return "string";
+
+    case NJS_OBJECT_ARG:
+        return "object";
+
+    case NJS_STRING_OBJECT_ARG:
+        return "string object";
+
+    case NJS_FUNCTION_ARG:
+        return "function";
+
+    case NJS_REGEXP_ARG:
+        return "regexp";
+
+    case NJS_DATE_ARG:
+        return "regexp";
+
+    default:
+        return "unknown";
+    }
+}
+
+
 njs_ret_t
 njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
 {
@@ -3173,7 +3314,6 @@ njs_primitive_value(njs_vm_t *vm, njs_va
         if (!njs_is_primitive(retval)) {
 
             for ( ;; ) {
-                njs_exception_type_error(vm, NULL, NULL);
                 ret = NXT_ERROR;
 
                 if (njs_is_object(value) && vm->top_frame->trap_tries < 2) {
@@ -3221,6 +3361,11 @@ njs_primitive_value(njs_vm_t *vm, njs_va
                     }
                 }
 
+                if (ret == NXT_ERROR) {
+                    njs_exception_type_error(vm, "cannot evaluate an object's "
+                                             "value", NULL);
+                }
+
                 return ret;
             }
         }
diff -r 700daa193d35 -r 0daf5a5cd37a njs/njs_vm.h
--- a/njs/njs_vm.h	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/njs_vm.h	Mon Feb 12 14:54:24 2018 +0300
@@ -1152,6 +1152,8 @@ nxt_bool_t njs_values_strict_equal(const
 
 njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args,
     uint8_t *args_types, nxt_uint_t nargs);
+const char *njs_type_string(njs_value_type_t type);
+const char *njs_arg_type_string(uint8_t arg);
 
 njs_ret_t njs_native_function_arguments(njs_vm_t *vm, njs_value_t *args,
     uint8_t *args_types, nxt_uint_t nargs);
diff -r 700daa193d35 -r 0daf5a5cd37a njs/test/njs_expect_test.exp
--- a/njs/test/njs_expect_test.exp	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/test/njs_expect_test.exp	Mon Feb 12 14:54:24 2018 +0300
@@ -166,12 +166,17 @@ njs_test {
      "console.help()\r\nVM built-in objects:"}
 }
 
+njs_test {
+    {"console.ll()\r\n"
+     "console.ll()\r\nTypeError: cannot find property 'll' of an external object"}
+}
+
 # Exception in njs_vm_retval()
 njs_test {
     {"var o = { toString: function() { return [1] } }\r\n"
      "undefined\r\n>> "}
     {"o\r\n"
-     "TypeError"}
+     "TypeError: cannot evaluate an object's value"}
 }
 
 # Backtraces are reset between invocations
diff -r 700daa193d35 -r 0daf5a5cd37a njs/test/njs_interactive_test.c
--- a/njs/test/njs_interactive_test.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/test/njs_interactive_test.c	Mon Feb 12 14:54:24 2018 +0300
@@ -120,7 +120,7 @@ static njs_interactive_test_t  njs_test[
     { nxt_string("function ff(o) {return o.a.a}" ENTER
                  "function f(o) {return ff(o)}" ENTER
                  "f({})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at ff (:1)\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
@@ -129,27 +129,27 @@ static njs_interactive_test_t  njs_test[
                  "function f(o) {try {return ff(o)} "
                                  "finally {return o.a.a}}" ENTER
                  "f({})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
 
     { nxt_string("function f(ff, o) {return ff(o)}" ENTER
                  "f(function (o) {return o.a.a}, {})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at anonymous (:1)\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
 
     { nxt_string("'str'.replace(/t/g,"
                  "              function(m) {return m.a.a})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at anonymous (:1)\n"
                  "    at String.prototype.replace (native)\n"
                  "    at main (native)\n") },
 
     { nxt_string("function f(o) {return Object.keys(o)}" ENTER
                  "f()" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot convert void to object\n"
                  "    at Object.keys (native)\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
@@ -160,20 +160,20 @@ static njs_interactive_test_t  njs_test[
                  "    at main (native)\n") },
 
     { nxt_string("Math.log({}.a.a)" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at Math.log (native)\n"
                  "    at main (native)\n") },
 
     { nxt_string("function f(o) {function f_in(o) {return o.a.a};"
                  "               return f_in(o)}; f({})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at f_in (:1)\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
 
     { nxt_string("function f(o) {var ff = function (o) {return o.a.a};"
                  "               return ff(o)}; f({})" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot get property 'a' of undefined\n"
                  "    at anonymous (:1)\n"
                  "    at f (:1)\n"
                  "    at main (native)\n") },
@@ -187,7 +187,7 @@ static njs_interactive_test_t  njs_test[
 
     { nxt_string("var o = { toString: function() { return [1] } }" ENTER
                  "o" ENTER),
-      nxt_string("TypeError\n"
+      nxt_string("TypeError: cannot evaluate an object's value\n"
                  "    at main (native)\n") },
 
 };
diff -r 700daa193d35 -r 0daf5a5cd37a njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Mon Feb 12 14:54:23 2018 +0300
+++ b/njs/test/njs_unit_test.c	Mon Feb 12 14:54:24 2018 +0300
@@ -2309,10 +2309,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("undefined") },
 
     { nxt_string("var a = {}; a.b.c"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot get property 'c' of undefined") },
 
     { nxt_string("'a'.b = 1"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property set on primitive string type") },
 
     { nxt_string("var a = {}; a.b = 1; a.b"),
       nxt_string("1") },
@@ -2342,16 +2342,16 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("3") },
 
     { nxt_string("var a = undefined; a.b++; a.b"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot get property 'b' of undefined") },
 
     { nxt_string("var a = null; a.b++; a.b"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot get property 'b' of undefined") },
 
     { nxt_string("var a = true; a.b++; a.b"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property set on primitive boolean type") },
 
     { nxt_string("var a = 1; a.b++; a.b"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property set on primitive number type") },
 
     { nxt_string("var n = 1, o = { p: n += 1 }; o.p"),
       nxt_string("2") },
@@ -2369,7 +2369,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("2 1") },
 
     { nxt_string("var a = 2; a.b = 1; var c = a.b++; a +' '+ a.b +' '+ c"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property set on primitive number type") },
 
     { nxt_string("var x = { a: 1 }; x.a"),
       nxt_string("1") },
@@ -2408,7 +2408,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("SyntaxError: Unexpected token \";\" in 1") },
 
     { nxt_string("var x = { a: 1, b: x.a }"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot get property 'a' of undefined") },
 
     { nxt_string("var a = { b: 2 }; a.b += 1"),
       nxt_string("3") },
@@ -2481,10 +2481,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("false") },
 
     { nxt_string("var a = 1; 1 in a"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property in on a primitive value") },
 
     { nxt_string("var a = true; 1 in a"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: property in on a primitive value") },
 
     { nxt_string("var n = { toString: function() { return 'a' } };"
                  "var o = { a: 5 }; o[n]"),
@@ -3224,7 +3224,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var a = [];"
                  "a.reduce(function(p, v, i, a) { return p + v })"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: invalid index") },
 
     { nxt_string("var a = [];"
                  "a.reduce(function(p, v, i, a) { return p + v }, 10)"),
@@ -3232,7 +3232,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var a = [,,];"
                  "a.reduce(function(p, v, i, a) { return p + v })"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: invalid index") },
 
     { nxt_string("var a = [,,];"
                  "a.reduce(function(p, v, i, a) { return p + v }, 10)"),
@@ -3260,7 +3260,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var a = [];"
                  "a.reduceRight(function(p, v, i, a) { return p + v })"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: invalid index") },
 
     { nxt_string("var a = [];"
                  "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
@@ -3268,7 +3268,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var a = [,,];"
                  "a.reduceRight(function(p, v, i, a) { return p + v })"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: invalid index") },
 
     { nxt_string("var a = [,,];"
                  "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"),
@@ -3725,7 +3725,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("abc") },
 
     { nxt_string("String.prototype.toString.call(1)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: unexpected value type:number") },
 
     { nxt_string("'abc'.valueOf()"),
       nxt_string("abc") },
@@ -4131,7 +4131,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var r = { toString: function() { return /45/ } };"
                  "'123456'.search(r)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot evaluate an object's value") },
 
     { nxt_string("var r = { toString: function() { return /34/ },"
                  "          valueOf:  function() { return 45 } };"
@@ -4265,7 +4265,7 @@ static njs_unit_test_t  njs_test[] =
 
     { nxt_string("var r = { toString: function() { return /45/ } };"
                  "'123456'.match(r)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot evaluate an object's value") },
 
     { nxt_string("var r = { toString: function() { return /34/ },"
                  "          valueOf:  function() { return 45 } };"
@@ -4509,10 +4509,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("OKundefined") },
 
     { nxt_string("var a = 1; a()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: object is not callable") },
 
     { nxt_string("var o = {a:1}; o.a()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: object is not callable") },
 
     { nxt_string("(function(){})()"),
       nxt_string("undefined") },
@@ -4800,7 +4800,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("5") },
 
     { nxt_string("var f = function(a) { return this + a }; f.apply(5, 1)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: second argument is not an array") },
 
     { nxt_string("var f = function(a, b) { return this + a + b };"
                  "f.apply(5, [1, 2])"),
@@ -4814,7 +4814,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("[object Function]") },
 
     { nxt_string("''.concat.call()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: 'this' argument is null or undefined") },
 
     { nxt_string("''.concat.call('a', 'b', 'c')"),
       nxt_string("abc") },
@@ -4829,13 +4829,13 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("ab,cd") },
 
     { nxt_string("''.concat.apply()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: 'this' argument is null or undefined") },
 
     { nxt_string("''.concat.apply('a')"),
       nxt_string("a") },
 
     { nxt_string("''.concat.apply('a', 'b')"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: second argument is not an array") },
 
     { nxt_string("''.concat.apply('a', [ 'b', 'c' ])"),
       nxt_string("abc") },
@@ -4853,10 +4853,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("1552553") },
 
     { nxt_string("[].join.call()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot convert void to object") },
 
     { nxt_string("[].slice.call()"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot convert void to object") },
 
     { nxt_string("function f(a) {} ; var a = f; var b = f; a === b"),
       nxt_string("true") },
@@ -4900,7 +4900,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("01") },
 
     { nxt_string("var concat = ''.concat; concat(1,2,3)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: 'this' argument is null or undefined") },
 
     { nxt_string("var concat = ''.concat; concat.call(1,2,3)"),
       nxt_string("123") },
@@ -4997,10 +4997,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("object") },
 
     { nxt_string("new decodeURI('%00')"),
-      nxt_string("TypeError")},
+      nxt_string("TypeError: object is not callable")},
 
     { nxt_string("new ''.toString"),
-      nxt_string("TypeError")},
+      nxt_string("TypeError: object is not callable")},
 
     { nxt_string("function F() { return Number }"
                  "var o = new (F())(5);"
@@ -5214,7 +5214,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("true") },
 
     { nxt_string("[0].map(RegExp().toString)"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: 'this' argument is not a regexp") },
 
     /* Non-standard ECMA-262 features. */
 
@@ -5565,10 +5565,10 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("o:OK") },
 
     { nxt_string("var o = { toString: function() { return [1] } }; o"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot evaluate an object's value") },
 
     { nxt_string("var o = { toString: function() { return [1] } }; 'o:' + o"),
-      nxt_string("TypeError") },
+      nxt_string("TypeError: cannot evaluate an object's value") },
 
     { nxt_string("var a = { valueOf: function() { return '3' } };"
                  "var b = { toString: function() { return 10 - a + 'OK' } };"
@@ -5620,7 +5620,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("true") },
 
     { nxt_string("[] instanceof []"),
-      nxt_string("TypeError") },


More information about the nginx-devel mailing list