[njs] Added the pretty string representation for values.
Dmitry Volyntsev
xeioex at nginx.com
Fri Jul 27 14:02:21 UTC 2018
details: http://hg.nginx.org/njs/rev/058162fce59a
branches:
changeset: 572:058162fce59a
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Fri Jul 27 17:01:52 2018 +0300
description:
Added the pretty string representation for values.
Interactive shell: dumping the pretty string representation of
the last expression.
>> [1, new Number(2), {a: new String('??Z?')}, true, console.log,
/^undef$/m, new Date(0)]
[
1,
[Number: 2],
{
a: [String: '??Z?']
},
true,
[Function: native],
/^undef$/m,
1970-01-01T00:00:00.000Z
]
njs.dump(value[, indent]):
Returns the pretty string representation of a value.
value - a value of any type.
indent - a number.
A number of space characters per indentation level.
njs.dump({a:[]}) -> '{a:[]}'
njs.dump({a:[]}, 1) -> '{\n a: [\n \n ]\n}'
console.log([value1[, values]])
Prints to stdout the flat pretty string representation
of values (no new lines).
console.dump([value1[, values]])
Prints to stdout the pretty string representation of values.
This fixes #11 issue on GitHub.
diffstat:
njs/njs.h | 2 +
njs/njs_builtin.c | 29 ++
njs/njs_date.c | 11 +-
njs/njs_date.h | 3 +
njs/njs_error.c | 28 +-
njs/njs_error.h | 2 +
njs/njs_extern.c | 54 ++++
njs/njs_extern.h | 1 +
njs/njs_json.c | 485 +++++++++++++++++++++++++++++++++++++++++-
njs/njs_regexp.c | 37 +-
njs/njs_regexp.h | 2 +
njs/njs_shell.c | 49 ++++-
njs/test/njs_expect_test.exp | 100 ++++++--
njs/test/njs_unit_test.c | 11 +
14 files changed, 738 insertions(+), 76 deletions(-)
diffs (truncated from 1288 to 1000 lines):
diff -r 766fcec15744 -r 058162fce59a njs/njs.h
--- a/njs/njs.h Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs.h Fri Jul 27 17:01:52 2018 +0300
@@ -217,6 +217,8 @@ NXT_EXPORT nxt_int_t njs_value_is_string
NXT_EXPORT nxt_int_t njs_value_is_object(njs_value_t *value);
NXT_EXPORT nxt_int_t njs_value_is_function(njs_value_t *value);
+NXT_EXPORT njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval,
+ const njs_value_t *value, nxt_uint_t indent);
NXT_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, njs_value_t *value,
const nxt_str_t *key);
diff -r 766fcec15744 -r 058162fce59a njs/njs_builtin.c
--- a/njs/njs_builtin.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_builtin.c Fri Jul 27 17:01:52 2018 +0300
@@ -1069,6 +1069,28 @@ njs_builtin_match_native_function(njs_vm
}
+static njs_ret_t
+njs_dump_value(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_str_t str;
+ nxt_uint_t n;
+ const njs_value_t *value, *indent;
+
+ value = njs_arg(args, nargs, 1);
+ indent = njs_arg(args, nargs, 2);
+
+ n = indent->data.u.number;
+ n = nxt_min(n, 5);
+
+ if (njs_vm_value_dump(vm, &str, value, n) != NXT_OK) {
+ return NXT_ERROR;
+ }
+
+ return njs_string_new(vm, &vm->retval, str.start, str.length, 0);
+}
+
+
static const njs_object_prop_t njs_njs_object_properties[] =
{
{
@@ -1076,6 +1098,13 @@ static const njs_object_prop_t njs_njs_
.name = njs_string("version"),
.value = njs_string(NJS_VERSION),
},
+
+ {
+ .type = NJS_METHOD,
+ .name = njs_string("dump"),
+ .value = njs_native_function(njs_dump_value, 0,
+ NJS_SKIP_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG),
+ },
};
diff -r 766fcec15744 -r 058162fce59a njs/njs_date.c
--- a/njs/njs_date.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_date.c Fri Jul 27 17:01:52 2018 +0300
@@ -1019,6 +1019,13 @@ static njs_ret_t
njs_date_prototype_to_iso_string(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused)
{
+ return njs_date_to_string(vm, &vm->retval, &args[0]);
+}
+
+
+njs_ret_t
+njs_date_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *date)
+{
int32_t year;
double time;
size_t size;
@@ -1026,7 +1033,7 @@ njs_date_prototype_to_iso_string(njs_vm_
u_char buf[NJS_ISO_DATE_TIME_LEN];
struct tm tm;
- time = args[0].data.u.date->time;
+ time = date->data.u.date->time;
if (!isnan(time)) {
clock = time / 1000;
@@ -1042,7 +1049,7 @@ njs_date_prototype_to_iso_string(njs_vm_
tm.tm_hour, tm.tm_min, tm.tm_sec,
(int) ((int64_t) time % 1000));
- return njs_string_new(vm, &vm->retval, buf, size, size);
+ return njs_string_new(vm, retval, buf, size, size);
}
njs_range_error(vm, NULL);
diff -r 766fcec15744 -r 058162fce59a njs/njs_date.h
--- a/njs/njs_date.h Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_date.h Fri Jul 27 17:01:52 2018 +0300
@@ -11,6 +11,9 @@
njs_ret_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_date_to_string(njs_vm_t *vm, njs_value_t *retval,
+ const njs_value_t *date);
+
extern const njs_object_init_t njs_date_constructor_init;
extern const njs_object_init_t njs_date_prototype_init;
diff -r 766fcec15744 -r 058162fce59a njs/njs_error.c
--- a/njs/njs_error.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_error.c Fri Jul 27 17:01:52 2018 +0300
@@ -586,6 +586,18 @@ static njs_ret_t
njs_error_prototype_to_string(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
{
+ if (nargs < 1 || !njs_is_object(&args[0])) {
+ njs_type_error(vm, "'this' argument is not an object");
+ return NXT_ERROR;
+ }
+
+ return njs_error_to_string(vm, &vm->retval, &args[0]);
+}
+
+
+njs_ret_t
+njs_error_to_string(njs_vm_t *vm, njs_value_t *retval, const njs_value_t *error)
+{
size_t size;
u_char *p;
nxt_str_t name, message;
@@ -595,16 +607,11 @@ 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_type_error(vm, "'this' argument is not an object");
- return NXT_ERROR;
- }
-
lhq.key_hash = NJS_NAME_HASH;
lhq.key = nxt_string_value("name");
lhq.proto = &njs_object_hash_proto;
- prop = njs_object_property(vm, args[0].data.u.object, &lhq);
+ prop = njs_object_property(vm, error->data.u.object, &lhq);
if (prop != NULL) {
name_value = &prop->value;
@@ -618,7 +625,7 @@ njs_error_prototype_to_string(njs_vm_t *
lhq.key_hash = NJS_MESSAGE_HASH;
lhq.key = nxt_string_value("message");
- prop = njs_object_property(vm, args[0].data.u.object, &lhq);
+ prop = njs_object_property(vm, error->data.u.object, &lhq);
if (prop != NULL) {
message_value = &prop->value;
@@ -630,18 +637,18 @@ njs_error_prototype_to_string(njs_vm_t *
njs_string_get(message_value, &message);
if (name.length == 0) {
- vm->retval = *message_value;
+ *retval = *message_value;
return NJS_OK;
}
if (message.length == 0) {
- vm->retval = *name_value;
+ *retval = *name_value;
return NJS_OK;
}
size = name.length + message.length + 2;
- p = njs_string_alloc(vm, &vm->retval, size, size);
+ p = njs_string_alloc(vm, retval, size, size);
if (nxt_fast_path(p != NULL)) {
p = nxt_cpymem(p, name.start, name.length);
@@ -653,6 +660,7 @@ njs_error_prototype_to_string(njs_vm_t *
}
njs_memory_error(vm);
+
return NJS_ERROR;
}
diff -r 766fcec15744 -r 058162fce59a njs/njs_error.h
--- a/njs/njs_error.h Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_error.h Fri Jul 27 17:01:52 2018 +0300
@@ -53,6 +53,8 @@ njs_ret_t njs_uri_error_constructor(njs_
njs_ret_t njs_memory_error_constructor(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_error_to_string(njs_vm_t *vm, njs_value_t *retval,
+ const njs_value_t *error);
extern const njs_object_init_t njs_error_constructor_init;
extern const njs_object_init_t njs_eval_error_constructor_init;
diff -r 766fcec15744 -r 058162fce59a njs/njs_extern.c
--- a/njs/njs_extern.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_extern.c Fri Jul 27 17:01:52 2018 +0300
@@ -228,6 +228,60 @@ njs_vm_external_bind(njs_vm_t *vm, const
}
+njs_array_t *
+njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external)
+{
+ uint32_t n, keys_length;
+ njs_ret_t ret;
+ njs_array_t *keys;
+ const nxt_lvlhsh_t *hash;
+ nxt_lvlhsh_each_t lhe;
+ const njs_extern_t *ext;
+
+ keys_length = 0;
+
+ nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
+
+ hash = &external->hash;
+
+ for ( ;; ) {
+ ext = nxt_lvlhsh_each(hash, &lhe);
+
+ if (ext == NULL) {
+ break;
+ }
+
+ keys_length++;
+ }
+
+ keys = njs_array_alloc(vm, keys_length, NJS_ARRAY_SPARE);
+ if (nxt_slow_path(keys == NULL)) {
+ return NULL;
+ }
+
+ n = 0;
+
+ nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
+
+ for ( ;; ) {
+ ext = nxt_lvlhsh_each(hash, &lhe);
+
+ if (ext == NULL) {
+ break;
+ }
+
+ ret = njs_string_create(vm, &keys->start[n++], ext->name.start,
+ ext->name.length, 0);
+
+ if (ret != NXT_OK) {
+ return NULL;
+ }
+ }
+
+ return keys;
+}
+
+
njs_value_t *
njs_parser_external(njs_vm_t *vm, njs_parser_t *parser)
{
diff -r 766fcec15744 -r 058162fce59a njs/njs_extern.h
--- a/njs/njs_extern.h Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_extern.h Fri Jul 27 17:01:52 2018 +0300
@@ -38,6 +38,7 @@ typedef struct {
} njs_extern_value_t;
+njs_array_t *njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external);
nxt_int_t njs_external_match_native_function(njs_vm_t *vm,
njs_function_native_t func, nxt_str_t *name);
diff -r 766fcec15744 -r 058162fce59a njs/njs_json.c
--- a/njs/njs_json.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_json.c Fri Jul 27 17:01:52 2018 +0300
@@ -5,6 +5,9 @@
*/
#include <njs_core.h>
+#include <njs_json.h>
+#include <njs_date.h>
+#include <njs_regexp.h>
#include <stdio.h>
#include <string.h>
@@ -127,16 +130,16 @@ static njs_ret_t njs_json_stringify_repl
static njs_ret_t njs_json_stringify_array(njs_vm_t *vm,
njs_json_stringify_t *stringify);
static njs_json_state_t *njs_json_push_stringify_state(njs_vm_t *vm,
- njs_json_stringify_t *stringify, njs_value_t *value);
+ njs_json_stringify_t *stringify, const njs_value_t *value);
static njs_json_state_t *njs_json_pop_stringify_state(
njs_json_stringify_t *stringify);
static nxt_int_t njs_json_append_value(njs_json_stringify_t *stringify,
- njs_value_t *value);
+ const njs_value_t *value);
static nxt_int_t njs_json_append_string(njs_json_stringify_t *stringify,
- njs_value_t *value);
+ const njs_value_t *value, char quote);
static nxt_int_t njs_json_append_number(njs_json_stringify_t *stringify,
- njs_value_t *value);
+ const njs_value_t *value);
static njs_value_t *njs_json_wrap_value(njs_vm_t *vm, njs_value_t *value);
@@ -1162,7 +1165,7 @@ njs_json_parse_exception(njs_json_parse_
} \
\
state->written = 1; \
- njs_json_append_string(stringify, key); \
+ njs_json_append_string(stringify, key, '\"'); \
njs_json_stringify_append(":", 1); \
if (stringify->space.length != 0) { \
njs_json_stringify_append(" ", 1); \
@@ -1621,7 +1624,7 @@ njs_json_stringify_array(njs_vm_t *vm, n
static njs_json_state_t *
njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify,
- njs_value_t *value)
+ const njs_value_t *value)
{
njs_json_state_t *state;
@@ -1654,7 +1657,13 @@ njs_json_push_stringify_state(njs_vm_t *
state->keys = stringify->replacer.data.u.array;
} else {
- state->keys = njs_object_keys_array(vm, value);
+ if (njs_is_external(value)) {
+ state->keys = njs_extern_keys_array(vm, value->external.proto);
+
+ } else {
+ state->keys = njs_object_keys_array(vm, value);
+ }
+
if (state->keys == NULL) {
return NULL;
}
@@ -1681,7 +1690,7 @@ njs_json_pop_stringify_state(njs_json_st
static nxt_int_t
-njs_json_append_value(njs_json_stringify_t *stringify, njs_value_t *value)
+njs_json_append_value(njs_json_stringify_t *stringify, const njs_value_t *value)
{
switch (value->type) {
case NJS_OBJECT_STRING:
@@ -1689,7 +1698,7 @@ njs_json_append_value(njs_json_stringify
/* Fall through. */
case NJS_STRING:
- return njs_json_append_string(stringify, value);
+ return njs_json_append_string(stringify, value, '\"');
case NJS_OBJECT_NUMBER:
value = &value->data.u.object_value->value;
@@ -1724,7 +1733,8 @@ njs_json_append_value(njs_json_stringify
static nxt_int_t
-njs_json_append_string(njs_json_stringify_t *stringify, njs_value_t *value)
+njs_json_append_string(njs_json_stringify_t *stringify,
+ const njs_value_t *value, char quote)
{
u_char c, *dst, *dst_end;
size_t length;
@@ -1734,7 +1744,7 @@ njs_json_append_string(njs_json_stringif
static char hex2char[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- (void) njs_string_prop(&str, value);
+ (void) njs_string_prop(&str, (njs_value_t *) value);
p = str.start;
end = p + str.size;
@@ -1747,11 +1757,14 @@ njs_json_append_string(njs_json_stringif
dst_end = dst + 64;
- *dst++ = '\"';
+ *dst++ = quote;
while (p < end) {
- if (*p < ' ' || *p == '\"' || *p == '\\') {
+ if (*p < ' '
+ || *p == '\\'
+ || (*p == '\"' && quote == '\"'))
+ {
c = (u_char) *p++;
*dst++ = '\\';
@@ -1793,7 +1806,7 @@ njs_json_append_string(njs_json_stringif
*/
while (p < end && (dst_end - dst) > 6) {
- if (*p < ' ' || *p == '\"' || *p == '\\') {
+ if (*p < ' ' || (*p == '\"' && quote == '\"') || *p == '\\') {
break;
}
@@ -1820,14 +1833,15 @@ njs_json_append_string(njs_json_stringif
}
njs_json_buf_written(stringify, dst - stringify->last->pos);
- njs_json_buf_append(stringify, "\"", 1);
+ njs_json_buf_append(stringify, "e, 1);
return NXT_OK;
}
static nxt_int_t
-njs_json_append_number(njs_json_stringify_t *stringify, njs_value_t *value)
+njs_json_append_number(njs_json_stringify_t *stringify,
+ const njs_value_t *value)
{
u_char *p;
size_t size;
@@ -2037,3 +2051,442 @@ const njs_object_init_t njs_json_object
njs_json_object_properties,
nxt_nitems(njs_json_object_properties),
};
+
+
+#define njs_dump(str) \
+ ret = njs_json_buf_append(stringify, str, nxt_length(str)); \
+ if (nxt_slow_path(ret != NXT_OK)) { \
+ goto memory_error; \
+ }
+
+
+#define njs_dump_item(str) \
+ if (written) { \
+ njs_json_buf_append(stringify, ",", 1); \
+ } \
+ \
+ written = 1; \
+ ret = njs_json_buf_append(stringify, str, nxt_length(str)); \
+ if (nxt_slow_path(ret != NXT_OK)) { \
+ goto memory_error; \
+ }
+
+
+static nxt_int_t
+njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value)
+{
+ size_t len;
+ njs_ret_t ret;
+ nxt_str_t str;
+ nxt_uint_t written;
+ njs_value_t str_val;
+ const njs_extern_t *ext_proto;
+ char buf[32];
+
+ njs_ret_t (*to_string)(njs_vm_t *, njs_value_t *,
+ const njs_value_t *);
+
+ switch (value->type) {
+ case NJS_OBJECT_STRING:
+ value = &value->data.u.object_value->value;
+
+ njs_string_get(value, &str);
+
+ njs_dump("[String: ");
+ njs_json_append_string(stringify, value, '\'');
+ njs_dump("]")
+ break;
+
+ case NJS_STRING:
+ njs_string_get(value, &str);
+ return njs_json_append_string(stringify, value, '\'');
+
+ case NJS_OBJECT_NUMBER:
+ value = &value->data.u.object_value->value;
+
+ ret = njs_number_to_string(stringify->vm, &str_val, value);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
+ njs_string_get(&str_val, &str);
+
+ njs_dump("[Number: ");
+ njs_json_buf_append(stringify, (char *) str.start, str.length);
+ njs_dump("]")
+ break;
+
+ case NJS_OBJECT_BOOLEAN:
+ value = &value->data.u.object_value->value;
+
+ if (njs_is_true(value)) {
+ njs_dump("[Boolean: true]");
+
+ } else {
+ njs_dump("[Boolean: false]");
+ }
+
+ break;
+
+ case NJS_BOOLEAN:
+ if (njs_is_true(value)) {
+ njs_dump("true");
+
+ } else {
+ njs_dump("false");
+ }
+
+ break;
+
+ case NJS_VOID:
+ njs_dump("undefined");
+ break;
+
+ case NJS_NULL:
+ njs_dump("null");
+ break;
+
+ case NJS_INVALID:
+ njs_dump("<empty>");
+ break;
+
+ case NJS_FUNCTION:
+ if (value->data.u.function->native) {
+ njs_dump("[Function: native]");
+
+ } else {
+ njs_dump("[Function]");
+ }
+
+ break;
+
+ case NJS_EXTERNAL:
+ ext_proto = value->external.proto;
+
+ written = 0;
+ njs_dump_item("{type:");
+
+ switch (ext_proto->type) {
+ case NJS_EXTERN_PROPERTY:
+ njs_dump("\"property\"");
+ break;
+ case NJS_EXTERN_METHOD:
+ njs_dump("\"method\"");
+ break;
+ case NJS_EXTERN_OBJECT:
+ njs_dump("\"object\"");
+ break;
+ case NJS_EXTERN_CASELESS_OBJECT:
+ njs_dump("\"caseless_object\"");
+ break;
+ }
+
+ njs_dump_item("props:[");
+ written = 0;
+
+ if (ext_proto->get != NULL) {
+ njs_dump_item("\"getter\"");
+ }
+
+ if (ext_proto->set != NULL) {
+ njs_dump_item("\"setter\"");
+ }
+
+ if (ext_proto->function != NULL) {
+ njs_dump_item("\"method\"");
+ }
+
+ if (ext_proto->find != NULL) {
+ njs_dump_item("\"find\"");
+ }
+
+ if (ext_proto->foreach != NULL) {
+ njs_dump_item("\"foreach\"");
+ }
+
+ if (ext_proto->next != NULL) {
+ njs_dump_item("\"next\"");
+ }
+
+ return njs_json_buf_append(stringify, "]}", 2);
+
+ case NJS_NUMBER:
+ case NJS_REGEXP:
+ case NJS_DATE:
+ case NJS_OBJECT_ERROR:
+ case NJS_OBJECT_EVAL_ERROR:
+ case NJS_OBJECT_INTERNAL_ERROR:
+ case NJS_OBJECT_RANGE_ERROR:
+ case NJS_OBJECT_REF_ERROR:
+ case NJS_OBJECT_SYNTAX_ERROR:
+ case NJS_OBJECT_TYPE_ERROR:
+ case NJS_OBJECT_URI_ERROR:
+
+ switch (value->type) {
+ case NJS_NUMBER:
+ to_string = njs_number_to_string;
+ break;
+
+ case NJS_REGEXP:
+ to_string = njs_regexp_to_string;
+ break;
+
+ case NJS_DATE:
+ to_string = njs_date_to_string;
+ break;
+
+ default:
+ to_string = njs_error_to_string;
+ }
+
+ ret = to_string(stringify->vm, &str_val, value);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return NXT_ERROR;
+ }
+
+ njs_string_get(&str_val, &str);
+
+ return njs_json_buf_append(stringify, (char *) str.start, str.length);
+
+ default:
+ len = snprintf(buf, sizeof(buf), "[Unknown value type:%d]",
+ value->type);
+ return njs_json_buf_append(stringify, buf, len);
+ }
+
+ return ret;
+
+memory_error:
+
+ njs_memory_error(stringify->vm);
+
+ return NXT_ERROR;
+}
+
+
+#define njs_dump_is_object(value) \
+ (((value)->type == NJS_OBJECT) \
+ || ((value)->type == NJS_ARRAY) \
+ || ((value)->type == NJS_OBJECT_VALUE) \
+ || ((value)->type == NJS_EXTERNAL \
+ && !nxt_lvlhsh_is_empty(&(value)->external.proto->hash)))
+
+
+#define njs_dump_append_value(value) \
+ state->written = 1; \
+ ret = njs_dump_value(stringify, value); \
+ if (nxt_slow_path(ret != NXT_OK)) { \
+ if (ret == NXT_DECLINED) { \
+ goto exception; \
+ } \
+ \
+ goto memory_error; \
+ }
+
+
+njs_ret_t
+njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval, const njs_value_t *value,
+ nxt_uint_t indent)
+{
+ nxt_int_t i;
+ njs_ret_t ret;
+ nxt_str_t str;
+ njs_value_t *key, *val, ext_val;
+ njs_json_state_t *state;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+ njs_json_stringify_t *stringify;
+
+ if (njs_vm_backtrace(vm) != NULL) {
+ goto exception;
+ }
+
+ stringify = nxt_mem_cache_alloc(vm->mem_cache_pool,
+ sizeof(njs_json_stringify_t));
+
+ if (nxt_slow_path(stringify == NULL)) {
+ goto memory_error;
+ }
+
+ stringify->vm = vm;
+ stringify->pool = vm->mem_cache_pool;
+ stringify->nodes = NULL;
+ stringify->last = NULL;
+
+ if (!njs_dump_is_object(value)) {
+ ret = njs_dump_value(stringify, value);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto memory_error;
+ }
+
+ goto done;
+ }
+
+ stringify->space.length = indent;
+ stringify->space.start = nxt_mem_cache_alloc(vm->mem_cache_pool, indent);
+ if (nxt_slow_path(stringify->space.start == NULL)) {
+ goto memory_error;
+ }
+
+ memset(stringify->space.start, ' ', indent);
+
+ if (nxt_array_init(&stringify->stack, NULL, 4, sizeof(njs_json_state_t),
+ &njs_array_mem_proto, vm->mem_cache_pool)
+ == NULL)
+ {
+ goto memory_error;
+ }
+
+ if (njs_json_push_stringify_state(vm, stringify, value) == NULL) {
+ goto memory_error;
+ }
+
+ state = stringify->state;
+
+ for ( ;; ) {
+ switch (state->type) {
+ case NJS_JSON_OBJECT_START:
+ njs_json_stringify_append("{", 1);
+ njs_json_stringify_indent(stringify->stack.items + 1);
+ state->type = NJS_JSON_OBJECT_CONTINUE;
+
+ /* Fall through. */
+
+ case NJS_JSON_OBJECT_CONTINUE:
+ if (state->index >= state->keys->length) {
+ njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_append("}", 1);
+
+ state = njs_json_pop_stringify_state(stringify);
+ if (state == NULL) {
+ goto done;
+ }
+
+ break;
+ }
+
+ key = &state->keys->start[state->index++];
+ njs_string_get(key, &lhq.key);
+ lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+
+ if (njs_is_external(&state->value)) {
+ lhq.proto = &njs_extern_hash_proto;
+
+ ret = nxt_lvlhsh_find(&state->value.external.proto->hash, &lhq);
+ if (nxt_slow_path(ret == NXT_DECLINED)) {
+ break;
+ }
+
+ ext_val.type = NJS_EXTERNAL;
+ ext_val.data.truth = 1;
+ ext_val.external.proto = lhq.value;
+
+ val = &ext_val;
+
+ } else {
+ lhq.proto = &njs_object_hash_proto;
+
+ ret = nxt_lvlhsh_find(&state->value.data.u.object->hash, &lhq);
+ if (nxt_slow_path(ret == NXT_DECLINED)) {
+ break;
+ }
+
+ prop = lhq.value;
+ val = &prop->value;
+
+ if (!prop->enumerable) {
+ break;
+ }
+ }
+
+ if (state->written) {
+ njs_json_stringify_append(",", 1);
+ njs_json_stringify_indent(stringify->stack.items + 1);
+ }
+
+ state->written = 1;
+ njs_json_stringify_append((char *) lhq.key.start, lhq.key.length);
+ njs_json_stringify_append(":", 1);
+ if (stringify->space.length != 0) {
+ njs_json_stringify_append(" ", 1);
+ }
+
+ if (njs_dump_is_object(val)) {
+ state = njs_json_push_stringify_state(vm, stringify, val);
+ if (state == NULL) {
+ goto exception;
+ }
+
+ break;
+ }
+
+ njs_dump_append_value(val);
+
+ break;
+
+ case NJS_JSON_ARRAY_START:
+ njs_json_stringify_append("[", 1);
+ njs_json_stringify_indent(stringify->stack.items + 1);
+ state->type = NJS_JSON_ARRAY_CONTINUE;
+
+ /* Fall through. */
+
+ case NJS_JSON_ARRAY_CONTINUE:
+ if (state->index >= state->value.data.u.array->length) {
+ njs_json_stringify_indent(stringify->stack.items);
+ njs_json_stringify_append("]", 1);
+
+ state = njs_json_pop_stringify_state(stringify);
+ if (state == NULL) {
+ goto done;
+ }
+
+ break;
+ }
+
+ if (state->written) {
+ njs_json_stringify_append(",", 1);
+ njs_json_stringify_indent(stringify->stack.items + 1);
+ }
+
+ val = &state->value.data.u.array->start[state->index++];
+
+ if (njs_dump_is_object(val)) {
+ state = njs_json_push_stringify_state(vm, stringify, val);
+ if (state == NULL) {
+ goto exception;
+ }
+
+ break;
+ }
+
+ njs_dump_append_value(val);
+
+ break;
+
+ default:
+ nxt_unreachable();
+ }
+ }
+
+done:
+
+ ret = njs_json_buf_pullup(stringify, &str);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto memory_error;
+ }
+
+ *retval = str;
+
+ return NXT_OK;
+
+memory_error:
+
+ njs_memory_error(vm);
+
+exception:
+
+ njs_vm_value_to_ext_string(vm, retval, &vm->retval, 1);
+
+ return NXT_OK;
+}
diff -r 766fcec15744 -r 058162fce59a njs/njs_regexp.c
--- a/njs/njs_regexp.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_regexp.c Fri Jul 27 17:01:52 2018 +0300
@@ -527,22 +527,8 @@ static njs_ret_t
njs_regexp_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused)
{
- u_char *source;
- int32_t length;
- uint32_t size;
- njs_value_t *value;
- njs_regexp_pattern_t *pattern;
-
- value = &args[0];
-
- if (njs_is_regexp(value)) {
- pattern = value->data.u.regexp->pattern;
- source = pattern->source;
-
- size = strlen((char *) source);
- length = nxt_utf8_length(source, size);
-
- return njs_regexp_string_create(vm, &vm->retval, source, size, length);
+ if (njs_is_regexp(&args[0])) {
+ return njs_regexp_to_string(vm, &vm->retval, &args[0]);
}
njs_type_error(vm, "'this' argument is not a regexp");
@@ -551,6 +537,25 @@ njs_regexp_prototype_to_string(njs_vm_t
}
+njs_ret_t
+njs_regexp_to_string(njs_vm_t *vm, njs_value_t *retval,
+ const njs_value_t *value)
+{
+ u_char *source;
+ int32_t length;
+ uint32_t size;
+ njs_regexp_pattern_t *pattern;
+
+ pattern = value->data.u.regexp->pattern;
+ source = pattern->source;
+
+ size = strlen((char *) source);
+ length = nxt_utf8_length(source, size);
+
+ return njs_regexp_string_create(vm, retval, source, size, length);
+}
+
+
static njs_ret_t
njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
njs_index_t unused)
diff -r 766fcec15744 -r 058162fce59a njs/njs_regexp.h
--- a/njs/njs_regexp.h Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_regexp.h Fri Jul 27 17:01:52 2018 +0300
@@ -31,6 +31,8 @@ njs_regexp_t *njs_regexp_alloc(njs_vm_t
njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
+njs_ret_t njs_regexp_to_string(njs_vm_t *vm, njs_value_t *retval,
+ const njs_value_t *regexp);
extern const njs_object_init_t njs_regexp_constructor_init;
extern const njs_object_init_t njs_regexp_prototype_init;
diff -r 766fcec15744 -r 058162fce59a njs/njs_shell.c
--- a/njs/njs_shell.c Tue Jul 24 19:50:02 2018 +0300
+++ b/njs/njs_shell.c Fri Jul 27 17:01:52 2018 +0300
@@ -58,6 +58,8 @@ static char *njs_completion_generator(co
static njs_ret_t njs_ext_console_log(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
+static njs_ret_t njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t unused);
static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused);
@@ -76,6 +78,18 @@ static njs_external_t njs_ext_console[]
njs_ext_console_log,
0 },
+ { nxt_string("dump"),
+ NJS_EXTERN_METHOD,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ njs_ext_console_dump,
+ 0 },
+
{ nxt_string("help"),
NJS_EXTERN_METHOD,
NULL,
@@ -431,7 +445,7 @@ njs_process_script(njs_vm_t *vm, njs_opt
ret = njs_vm_run(vm);
}
- if (njs_vm_retval_to_ext_string(vm, out) != NXT_OK) {
+ if (njs_vm_value_dump(vm, out, njs_vm_retval(vm), 1) != NXT_OK) {
*out = nxt_string_value("failed to get retval from VM");
return NXT_ERROR;
}
@@ -625,7 +639,38 @@ njs_ext_console_log(njs_vm_t *vm, njs_va
n = 1;
while (n < nargs) {
- if (njs_vm_value_to_ext_string(vm, &msg, njs_argument(args, n), 0)
+ if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 0)
+ == NJS_ERROR)
+ {
+ return NJS_ERROR;
+ }
+
+ printf("%s%.*s", (n != 1) ? " " : "", (int) msg.length, msg.start);
+
+ n++;
+ }
+
+ if (nargs > 1) {
+ printf("\n");
+ }
+
+ vm->retval = njs_value_void;
+
+ return NJS_OK;
+}
+
+
+static njs_ret_t
+njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+ njs_index_t unused)
+{
+ nxt_str_t msg;
More information about the nginx-devel
mailing list