[njs] Refactored completions and backtrace matches.

Dmitry Volyntsev xeioex at nginx.com
Thu Oct 31 15:18:03 UTC 2019


details:   https://hg.nginx.org/njs/rev/2868545c461b
branches:  
changeset: 1212:2868545c461b
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Oct 31 18:17:31 2019 +0300
description:
Refactored completions and backtrace matches.

diffstat:

 src/njs_builtin.c        |  460 ++++++++++++++++++++++------------------------
 src/njs_crypto.c         |   56 +++++-
 src/njs_object.c         |   81 ++++++++
 src/njs_object.h         |   20 ++
 src/njs_value.c          |    1 +
 src/njs_value.h          |    1 +
 test/njs_expect_test.exp |    4 +-
 7 files changed, 381 insertions(+), 242 deletions(-)

diffs (808 lines):

diff -r c75a8fc6d534 -r 2868545c461b src/njs_builtin.c
--- a/src/njs_builtin.c	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_builtin.c	Thu Oct 31 18:17:31 2019 +0300
@@ -14,6 +14,19 @@ typedef struct {
 } njs_function_init_t;
 
 
+typedef struct {
+    enum {
+       NJS_BUILTIN_TRAVERSE_KEYS,
+       NJS_BUILTIN_TRAVERSE_MATCH,
+    }                          type;
+
+    njs_function_native_t      native;
+
+    njs_lvlhsh_t               keys;
+    njs_str_t                  match;
+} njs_builtin_traverse_t;
+
+
 static njs_int_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
 static njs_arr_t *njs_vm_expression_completions(njs_vm_t *vm,
@@ -503,17 +516,130 @@ njs_builtin_objects_clone(njs_vm_t *vm, 
 }
 
 
-static size_t
-njs_builtin_completions_size(njs_vm_t *vm)
+static njs_int_t
+njs_builtin_traverse(njs_vm_t *vm, njs_traverse_t *traverse, void *data)
 {
-    njs_uint_t               n;
+    size_t                  len;
+    u_char                  *p, *start, *end;
+    njs_int_t               ret, n;
+    njs_str_t               name;
+    njs_object_prop_t       *prop;
+    njs_lvlhsh_query_t      lhq;
+    njs_builtin_traverse_t  *ctx;
+    njs_traverse_t          *path[NJS_TRAVERSE_MAX_DEPTH];
+    u_char                  buf[256];
+
+    ctx = data;
+
+    if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) {
+        prop = traverse->prop;
+
+        if (!(njs_is_function(&prop->value)
+              && njs_function(&prop->value)->native
+              && njs_function(&prop->value)->u.native == ctx->native))
+        {
+            return NJS_OK;
+        }
+    }
+
+    n = 0;
+
+    while (traverse != NULL) {
+        path[n++] = traverse;
+        traverse = traverse->parent;
+    }
+
+    n--;
+
+    p = buf;
+    end = buf + sizeof(buf);
+
+    do {
+        njs_string_get(&path[n]->prop->name, &name);
+
+        if (njs_slow_path((p + name.length + 1) > end)) {
+            njs_type_error(vm, "njs_builtin_traverse() key is too long");
+            return NJS_ERROR;
+        }
+
+        p = njs_cpymem(p, name.start, name.length);
+
+        if (n != 0) {
+            *p++ = '.';
+        }
+
+    } while (n-- > 0);
+
+    if (ctx->type == NJS_BUILTIN_TRAVERSE_MATCH) {
+        len = ctx->match.length;
+        start = njs_mp_alloc(vm->mem_pool, len + (p - buf) + (len != 0));
+        if (njs_slow_path(start == NULL)) {
+            njs_memory_error(vm);
+            return NJS_ERROR;
+        }
+
+        if (len != 0) {
+            memcpy(start, ctx->match.start, len);
+            start[len++] = '.';
+        }
+
+        memcpy(start + len, buf, p - buf);
+        ctx->match.length = len + p - buf;
+        ctx->match.start = start;
+
+        return NJS_DONE;
+    }
+
+    /* NJS_BUILTIN_TRAVERSE_KEYS. */
+
+    prop = njs_object_prop_alloc(vm, &njs_value_undefined, &njs_value_null, 0);
+    if (njs_slow_path(prop == NULL)) {
+        return NJS_ERROR;
+    }
+
+    ret = njs_string_new(vm, &prop->name, buf, p - buf, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return ret;
+    }
+
+    lhq.value = prop;
+    njs_string_get(&prop->name, &lhq.key);
+    lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
+    lhq.replace = 1;
+    lhq.pool = vm->mem_pool;
+    lhq.proto = &njs_object_hash_proto;
+
+    ret = njs_lvlhsh_insert(&ctx->keys, &lhq);
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_internal_error(vm, "lvlhsh insert/replace failed");
+        return NJS_ERROR;
+    }
+
+    return NJS_OK;
+}
+
+
+static njs_arr_t *
+njs_builtin_completions(njs_vm_t *vm)
+{
+    u_char                   *compl;
+    size_t                   len;
+    njs_arr_t                *array;
+    njs_str_t                *completion;
+    njs_int_t                ret;
     njs_keyword_t            *keyword;
     njs_lvlhsh_each_t        lhe, lhe_prop;
     njs_extern_value_t       *ev;
     const njs_extern_t       *ext_proto, *ext_prop;
-    const njs_object_init_t  **p;
+    njs_builtin_traverse_t   ctx;
+    const njs_object_prop_t  *prop;
 
-    n = 0;
+    array = njs_arr_create(vm->mem_pool, 64, sizeof(njs_str_t));
+    if (njs_slow_path(array == NULL)) {
+        return NULL;
+    }
+
+    /* Keywords completions. */
 
     njs_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto);
 
@@ -524,149 +650,43 @@ njs_builtin_completions_size(njs_vm_t *v
             break;
         }
 
-        n++;
-    }
-
-    for (p = njs_object_init; *p != NULL; p++) {
-        n += (*p)->items;
-    }
-
-    for (p = njs_prototype_init; *p != NULL; p++) {
-        n += (*p)->items;
-    }
-
-    for (p = njs_constructor_init; *p != NULL; p++) {
-        n += (*p)->items;
-    }
-
-    njs_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto);
-
-    for ( ;; ) {
-        ev = njs_lvlhsh_each(&vm->externals_hash, &lhe);
-
-        if (ev == NULL) {
-            break;
+        completion = njs_arr_add(array);
+        if (njs_slow_path(completion == NULL)) {
+            return NULL;
         }
 
-        ext_proto = ev->value.external.proto;
-
-        njs_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto);
-
-        n++;
-
-        for ( ;; ) {
-            ext_prop = njs_lvlhsh_each(&ext_proto->hash, &lhe_prop);
-
-            if (ext_prop == NULL) {
-                break;
-            }
-
-            n++;
-        }
+        *completion = keyword->name;
     }
 
-    return n;
-}
+    /* Global object completions. */
 
+    ctx.type = NJS_BUILTIN_TRAVERSE_KEYS;
+    njs_lvlhsh_init(&ctx.keys);
 
-static njs_arr_t *
-njs_builtin_completions(njs_vm_t *vm, njs_arr_t *array)
-{
-    u_char                   *compl;
-    size_t                   n, len;
-    njs_str_t                string, *completions;
-    njs_uint_t               i, k;
-    njs_keyword_t            *keyword;
-    njs_lvlhsh_each_t        lhe, lhe_prop;
-    njs_extern_value_t       *ev;
-    const njs_extern_t       *ext_proto, *ext_prop;
-    const njs_object_prop_t  *prop;
-    const njs_object_init_t  *obj, **p;
+    ret = njs_object_traverse(vm, &vm->global_object, &ctx,
+                              njs_builtin_traverse);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
 
-    n = 0;
-    completions = array->start;
-
-    njs_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto);
+    njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
 
     for ( ;; ) {
-        keyword = njs_lvlhsh_each(&vm->shared->keywords_hash, &lhe);
+        prop = njs_lvlhsh_each(&ctx.keys, &lhe);
 
-        if (keyword == NULL) {
+        if (prop == NULL) {
             break;
         }
 
-        completions[n++] = keyword->name;
-    }
-
-    for (p = njs_object_init; *p != NULL; p++) {
-        obj = *p;
-
-        for (i = 0; i < obj->items; i++) {
-            prop = &obj->properties[i];
-            njs_string_get(&prop->name, &string);
-            len = obj->name.length + string.length + 2;
+        completion = njs_arr_add(array);
+        if (njs_slow_path(completion == NULL)) {
+            return NULL;
+        }
 
-            compl = njs_mp_zalloc(vm->mem_pool, len);
-            if (compl == NULL) {
-                return NULL;
-            }
-
-            njs_sprintf(compl, compl + len, "%s.%s%Z", obj->name.start,
-                        string.start);
-
-            completions[n].length = len;
-            completions[n++].start = (u_char *) compl;
-        }
+        njs_string_get(&prop->name, completion);
     }
 
-    for (p = njs_prototype_init; *p != NULL; p++) {
-        obj = *p;
-
-        for (i = 0; i < obj->items; i++) {
-            prop = &obj->properties[i];
-            njs_string_get(&prop->name, &string);
-            len = string.length + 2;
-
-            compl = njs_mp_zalloc(vm->mem_pool, len);
-            if (compl == NULL) {
-                return NULL;
-            }
-
-            njs_sprintf(compl, compl + len, ".%s%Z", string.start);
-
-            for (k = 0; k < n; k++) {
-                if (njs_strncmp(completions[k].start, compl, len) == 0) {
-                    break;
-                }
-            }
-
-            if (k == n) {
-                completions[n].length = len;
-                completions[n++].start = (u_char *) compl;
-            }
-        }
-    }
-
-    for (p = njs_constructor_init; *p != NULL; p++) {
-        obj = *p;
-
-        for (i = 0; i < obj->items; i++) {
-            prop = &obj->properties[i];
-            njs_string_get(&prop->name, &string);
-            len = obj->name.length + string.length + 2;
-
-            compl = njs_mp_zalloc(vm->mem_pool, len);
-            if (compl == NULL) {
-                return NULL;
-            }
-
-            njs_sprintf(compl, compl + len, "%s.%s%Z", obj->name.start,
-                        string.start);
-
-            completions[n].length = len;
-            completions[n++].start = (u_char *) compl;
-        }
-    }
+    /* Externals completions. */
 
     njs_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto);
 
@@ -689,8 +709,13 @@ njs_builtin_completions(njs_vm_t *vm, nj
 
         njs_sprintf(compl, compl + len, "%V%Z", &ev->name);
 
-        completions[n].length = len;
-        completions[n++].start = (u_char *) compl;
+        completion = njs_arr_add(array);
+        if (njs_slow_path(completion == NULL)) {
+            return NULL;
+        }
+
+        completion->length = len;
+        completion->start = (u_char *) compl;
 
         for ( ;; ) {
             ext_prop = njs_lvlhsh_each(&ext_proto->hash, &lhe_prop);
@@ -708,13 +733,16 @@ njs_builtin_completions(njs_vm_t *vm, nj
             njs_sprintf(compl, compl + len, "%V.%V%Z", &ev->name,
                         &ext_prop->name);
 
-            completions[n].length = len;
-            completions[n++].start = (u_char *) compl;
+            completion = njs_arr_add(array);
+            if (njs_slow_path(completion == NULL)) {
+                return NULL;
+            }
+
+            completion->length = len;
+            completion->start = (u_char *) compl;
         }
     }
 
-    array->items = n;
-
     return array;
 }
 
@@ -722,18 +750,8 @@ njs_builtin_completions(njs_vm_t *vm, nj
 njs_arr_t *
 njs_vm_completions(njs_vm_t *vm, njs_str_t *expression)
 {
-    size_t       size;
-    njs_arr_t  *completions;
-
     if (expression == NULL) {
-        size = njs_builtin_completions_size(vm);
-
-        completions = njs_arr_create(vm->mem_pool, size, sizeof(njs_str_t));
-        if (njs_slow_path(completions == NULL)) {
-            return NULL;
-        }
-
-        return njs_builtin_completions(vm, completions);
+        return njs_builtin_completions(vm);
     }
 
     return njs_vm_expression_completions(vm, expression);
@@ -913,34 +931,71 @@ njs_object_completions(njs_vm_t *vm, njs
 }
 
 
-static njs_int_t
-njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function,
-    const njs_object_prop_t **prop, const njs_object_init_t **object)
+njs_int_t
+njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function,
+    njs_str_t *name)
 {
-    njs_uint_t               i;
-    njs_function_t           *fun;
-    const njs_object_init_t  *o, **p;
-    const njs_object_prop_t  *pr;
+    njs_int_t               ret;
+    njs_uint_t              i;
+    njs_value_t             value;
+    njs_module_t            *module;
+    njs_lvlhsh_each_t       lhe;
+    njs_builtin_traverse_t  ctx;
+
+    ctx.type = NJS_BUILTIN_TRAVERSE_MATCH;
+    ctx.native = function->u.native;
+
+    /* Global object. */
 
-    for (p = objects; *p != NULL; p++) {
-        o = *p;
+    ctx.match = njs_str_value("");
+
+    ret = njs_object_traverse(vm, &vm->global_object, &ctx,
+                              njs_builtin_traverse);
+
+    if (ret == NJS_DONE) {
+        *name = ctx.match;
+        return NJS_OK;
+    }
+
+    /* Constructor from built-in modules (not-mapped to global object). */
+
+    for (i = NJS_OBJ_TYPE_CRYPTO_HASH; i < NJS_OBJ_TYPE_ERROR; i++) {
+        njs_set_object(&value, &vm->constructors[i].object);
 
-        for (i = 0; i < o->items; i++) {
-            pr = &o->properties[i];
+        ret = njs_value_property(vm, &value, njs_value_arg(&njs_string_name),
+                                 &value);
+
+        if (ret == NJS_OK && njs_is_string(&value)) {
+            njs_string_get(&value, &ctx.match);
+        }
 
-            if (pr->type != NJS_PROPERTY || !njs_is_function(&pr->value)) {
-                continue;
-            }
+        ret = njs_object_traverse(vm, &vm->constructors[i].object, &ctx,
+                                  njs_builtin_traverse);
+
+        if (ret == NJS_DONE) {
+            *name = ctx.match;
+            return NJS_OK;
+        }
+    }
 
-            fun = njs_function(&pr->value);
+    /* Modules. */
+
+    njs_lvlhsh_each_init(&lhe, &njs_modules_hash_proto);
+
+    for ( ;; ) {
+        module = njs_lvlhsh_each(&vm->modules_hash, &lhe);
 
-            if (function->u.native != fun->u.native) {
-                continue;
-            }
+        if (module == NULL) {
+            break;
+        }
+
+        ctx.match = module->name;
 
-            *prop = pr;
-            *object = o;
+        ret = njs_object_traverse(vm, &module->object, &ctx,
+                                  njs_builtin_traverse);
 
+        if (ret == NJS_DONE) {
+            *name = ctx.match;
             return NJS_OK;
         }
     }
@@ -949,68 +1004,6 @@ njs_builtin_match(const njs_object_init_
 }
 
 
-njs_int_t
-njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function,
-    njs_str_t *name)
-{
-    size_t                   len;
-    njs_str_t                string, middle;
-    njs_int_t                ret;
-    const njs_object_init_t  *obj;
-    const njs_object_prop_t  *prop;
-
-    middle = njs_str_value(".");
-
-    ret = njs_builtin_match(njs_object_init, function, &prop, &obj);
-
-    if (ret == NJS_OK) {
-        if (!obj->name.length) {
-            middle = njs_str_value("");
-        }
-
-        goto found;
-    }
-
-    ret = njs_builtin_match(njs_prototype_init, function, &prop, &obj);
-
-    if (ret == NJS_OK) {
-        middle = njs_str_value(".prototype.");
-        goto found;
-    }
-
-    ret = njs_builtin_match(njs_constructor_init, function, &prop, &obj);
-
-    if (ret == NJS_OK) {
-        goto found;
-    }
-
-    ret = njs_builtin_match(njs_module_init, function, &prop, &obj);
-
-    if (ret == NJS_OK) {
-        goto found;
-    }
-
-    return NJS_DECLINED;
-
-found:
-
-    njs_string_get(&prop->name, &string);
-
-    len = obj->name.length + middle.length + string.length;
-
-    name->length = len;
-    name->start = njs_mp_zalloc(vm->mem_pool, len);
-    if (name->start == NULL) {
-        return NJS_ERROR;
-    }
-
-    njs_sprintf(name->start, name->start + len,
-                "%V%V%V", &obj->name, &middle, &string);
-
-    return NJS_OK;
-}
-
-
 static njs_int_t
 njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
@@ -1515,11 +1508,6 @@ njs_process_object_argv(njs_vm_t *vm, nj
 
     static const njs_value_t  argv_string = njs_string("argv");
 
-    if (njs_slow_path(vm->options.argv == NULL)) {
-        njs_internal_error(vm, "argv was not provided by host environment");
-        return NJS_ERROR;
-    }
-
     argv = njs_array_alloc(vm, vm->options.argc, 0);
     if (njs_slow_path(argv == NULL)) {
         return NJS_ERROR;
diff -r c75a8fc6d534 -r 2868545c461b src/njs_crypto.c
--- a/src/njs_crypto.c	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_crypto.c	Thu Oct 31 18:17:31 2019 +0300
@@ -361,10 +361,34 @@ njs_hash_constructor(njs_vm_t *vm, njs_v
 }
 
 
+static const njs_object_prop_t  njs_hash_constructor_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("Hash"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 2.0),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_object_prototype_create),
+    },
+};
+
+
 const njs_object_init_t  njs_hash_constructor_init = {
     njs_str("Hash"),
-    NULL,
-    0,
+    njs_hash_constructor_properties,
+    njs_nitems(njs_hash_constructor_properties),
 };
 
 
@@ -621,10 +645,34 @@ njs_hmac_constructor(njs_vm_t *vm, njs_v
 }
 
 
+static const njs_object_prop_t  njs_hmac_constructor_properties[] =
+{
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("name"),
+        .value = njs_string("Hmac"),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY,
+        .name = njs_string("length"),
+        .value = njs_value(NJS_NUMBER, 1, 3.0),
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("prototype"),
+        .value = njs_prop_handler(njs_object_prototype_create),
+    },
+};
+
+
 const njs_object_init_t  njs_hmac_constructor_init = {
     njs_str("Hmac"),
-    NULL,
-    0,
+    njs_hmac_constructor_properties,
+    njs_nitems(njs_hmac_constructor_properties),
 };
 
 
diff -r c75a8fc6d534 -r 2868545c461b src/njs_object.c
--- a/src/njs_object.c	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_object.c	Thu Oct 31 18:17:31 2019 +0300
@@ -1084,6 +1084,87 @@ njs_object_own_enumerate_object(njs_vm_t
 }
 
 
+njs_int_t
+njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
+    njs_object_traverse_cb_t cb)
+{
+    njs_int_t          depth, ret;
+    njs_str_t          name;
+    njs_value_t        value, obj;
+    njs_object_prop_t  *prop;
+    njs_traverse_t     state[NJS_TRAVERSE_MAX_DEPTH];
+
+    static const njs_str_t  constructor_key = njs_str("constructor");
+
+    depth = 0;
+
+    state[depth].prop = NULL;
+    state[depth].parent = NULL;
+    state[depth].object = object;
+    state[depth].hash = &object->shared_hash;
+    njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+
+    for ( ;; ) {
+        prop = njs_lvlhsh_each(state[depth].hash, &state[depth].lhe);
+
+        if (prop == NULL) {
+            if (state[depth].hash == &state[depth].object->shared_hash) {
+                state[depth].hash = &state[depth].object->hash;
+                njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+                continue;
+            }
+
+            if (depth == 0) {
+                return NJS_OK;
+            }
+
+            depth--;
+            continue;
+        }
+
+        state[depth].prop = prop;
+
+        ret = cb(vm, &state[depth], ctx);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return ret;
+        }
+
+        value = prop->value;
+
+        if (prop->type == NJS_PROPERTY_HANDLER) {
+            njs_set_object(&obj, state[depth].object);
+            ret = prop->value.data.u.prop_handler(vm, prop, &obj, NULL, &value);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                return ret;
+
+            }
+        }
+
+        njs_string_get(&prop->name, &name);
+
+        /*
+         * "constructor" properties make loops in object hierarchies.
+         * Object.prototype.constructor -> Object.
+         */
+
+        if (njs_is_object(&value) && !njs_strstr_eq(&name, &constructor_key)) {
+            if (++depth > (NJS_TRAVERSE_MAX_DEPTH - 1)) {
+                njs_type_error(vm, "njs_object_traverse() recursion limit:%d",
+                               depth);
+                return NJS_ERROR;
+            }
+
+            state[depth].prop = NULL;
+            state[depth].parent = &state[depth - 1];
+            state[depth].object = njs_object(&value);
+            state[depth].hash = &njs_object(&value)->shared_hash;
+            njs_lvlhsh_each_init(&state[depth].lhe, &njs_object_hash_proto);
+        }
+
+    }
+}
+
+
 static njs_int_t
 njs_object_define_property(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
diff -r c75a8fc6d534 -r 2868545c461b src/njs_object.h
--- a/src/njs_object.h	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_object.h	Thu Oct 31 18:17:31 2019 +0300
@@ -43,6 +43,24 @@ struct njs_object_init_s {
 };
 
 
+typedef struct njs_traverse_s  njs_traverse_t;
+
+struct njs_traverse_s {
+    struct njs_traverse_s      *parent;
+    njs_object_prop_t          *prop;
+
+    njs_object_t               *object;
+    njs_lvlhsh_t               *hash;
+    njs_lvlhsh_each_t          lhe;
+
+#define NJS_TRAVERSE_MAX_DEPTH 32
+};
+
+
+typedef njs_int_t (*njs_object_traverse_cb_t)(njs_vm_t *vm,
+    njs_traverse_t *traverse, void *ctx);
+
+
 njs_object_t *njs_object_alloc(njs_vm_t *vm);
 njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value);
 njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
@@ -51,6 +69,8 @@ njs_array_t *njs_object_enumerate(njs_vm
     njs_object_enum_t kind, njs_bool_t all);
 njs_array_t *njs_object_own_enumerate(njs_vm_t *vm, const njs_object_t *object,
     njs_object_enum_t kind, njs_bool_t all);
+njs_int_t njs_object_traverse(njs_vm_t *vm, njs_object_t *object, void *ctx,
+    njs_object_traverse_cb_t cb);
 njs_int_t njs_object_hash_create(njs_vm_t *vm, njs_lvlhsh_t *hash,
     const njs_object_prop_t *prop, njs_uint_t n);
 njs_int_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args,
diff -r c75a8fc6d534 -r 2868545c461b src/njs_value.c
--- a/src/njs_value.c	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_value.c	Thu Oct 31 18:17:31 2019 +0300
@@ -48,6 +48,7 @@ const njs_value_t  njs_string_plus_infin
                                             njs_string("Infinity");
 const njs_value_t  njs_string_nan =         njs_string("NaN");
 const njs_value_t  njs_string_string =      njs_string("string");
+const njs_value_t  njs_string_name =        njs_string("name");
 const njs_value_t  njs_string_data =        njs_string("data");
 const njs_value_t  njs_string_external =    njs_string("external");
 const njs_value_t  njs_string_invalid =     njs_string("invalid");
diff -r c75a8fc6d534 -r 2868545c461b src/njs_value.h
--- a/src/njs_value.h	Thu Oct 31 18:17:31 2019 +0300
+++ b/src/njs_value.h	Thu Oct 31 18:17:31 2019 +0300
@@ -665,6 +665,7 @@ extern const njs_value_t  njs_string_plu
 extern const njs_value_t  njs_string_nan;
 extern const njs_value_t  njs_string_string;
 extern const njs_value_t  njs_string_data;
+extern const njs_value_t  njs_string_name;
 extern const njs_value_t  njs_string_external;
 extern const njs_value_t  njs_string_invalid;
 extern const njs_value_t  njs_string_object;
diff -r c75a8fc6d534 -r 2868545c461b test/njs_expect_test.exp
--- a/test/njs_expect_test.exp	Thu Oct 31 18:17:31 2019 +0300
+++ b/test/njs_expect_test.exp	Thu Oct 31 18:17:31 2019 +0300
@@ -101,7 +101,7 @@ njs_test {
 
 njs_test {
     {"O\t"
-     "O\a*bject."}
+     "O\a*bject"}
     {"\t\t"
      "Object.create*Object.isSealed"}
 }
@@ -120,7 +120,7 @@ njs_test {
 
 njs_test {
     {"Ma\t"
-     "Ma\a*th."}
+     "Ma\a*th"}
     {"\t\t"
      "Math.abs*Math.atan2"}
 }


More information about the nginx-devel mailing list