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);
}
+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[] =
{
{
.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),
+ },
};
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;
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;
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);
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;
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;
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;
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;
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);
}
njs_memory_error(vm);
+
return NJS_ERROR;
}
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;
}
+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)
{
} 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);
*/
#include <njs_core.h>
+#include <njs_json.h>
+#include <njs_date.h>
+#include <njs_regexp.h>
#include <stdio.h>
#include <string.h>
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);
} \
\
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); \
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;
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;
}
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:
/* 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;
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;
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;
dst_end = dst + 64;
- *dst++ = '\"';
+ *dst++ = quote;
while (p < end) {
- if (*p < ' ' || *p == '\"' || *p == '\\') {
+ if (*p < ' '
+ || *p == '\\'
+ || (*p == '\"' && quote == '\"'))
+ {
c = (u_char) *p++;
*dst++ = '\\';
*/
while (p < end && (dst_end - dst) > 6) {
- if (*p < ' ' || *p == '\"' || *p == '\\') {
+ if (*p < ' ' || (*p == '\"' && quote == '\"') || *p == '\\') {
break;
}
}
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;
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;
+}
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)
+{
+ 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");
+
+ return NXT_ERROR;
+}
+
+
+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_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);
- }
+ pattern = value->data.u.regexp->pattern;
+ source = pattern->source;
- njs_type_error(vm, "'this' argument is not a regexp");
+ size = strlen((char *) source);
+ length = nxt_utf8_length(source, size);
- return NXT_ERROR;
+ return njs_regexp_string_create(vm, retval, source, size, length);
}
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;
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);
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,
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;
}
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;
+ nxt_uint_t n;
+
+ n = 1;
+
+ while (n < nargs) {
+ if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1)
== NJS_ERROR)
{
return NJS_ERROR;
{"console.log(1)\r\n"
"console.log(1)\r\n1\r\nundefined\r\n>> "}
{"console.log(1, 'a')\r\n"
- "console.log(1, 'a')\r\n1 a\r\nundefined\r\n>> "}
+ "console.log(1, 'a')\r\n1 'a'\r\nundefined\r\n>> "}
+ {"console.dump()\r\n"
+ "console.dump()\r\nundefined\r\n>> "}
+ {"console.dump(1)\r\n"
+ "console.dump(1)\r\n1\r\nundefined\r\n>> "}
+ {"console.dump(1, 'a')\r\n"
+ "console.dump(1, 'a')\r\n1 'a'\r\nundefined\r\n>> "}
{"console.help()\r\n"
"console.help()\r\nVM built-in objects:"}
}
njs_test {
{"var print = console.log.bind(console); print(1, 'a', [1, 2])\r\n"
- "var print = console.log.bind(console); print(1, 'a', \\\[1, 2])\r\n1 a 1,2\r\nundefined\r\n>> "}
+ "1 'a' \\\[1,2]\r\nundefined\r\n>> "}
+ {"var print = console.dump.bind(console); print(1, 'a', [1, 2])\r\n"
+ "1 'a' \\\[\r\n 1,\r\n 2\r\n]\r\nundefined\r\n>> "}
}
# Backtraces for external objects
njs_test {
- {"console.log(console)\r\n"
- "console.log(console)\r\nTypeError:*at console.log (native)"}
+ {"console.log(console.a.a)\r\n"
+ "console.log(console.a.a)\r\nTypeError:*at console.log (native)"}
}
-# Exception in njs_vm_retval_to_ext_string()
+# dumper
njs_test {
- {"var o = { toString: function() { return [1] } }\r\n"
+ {"var o = {toString: function(){}, log: console.log}\r\n"
"undefined\r\n>> "}
{"o\r\n"
- "TypeError: cannot evaluate an object's value"}
+ "o\r\n{\r\n toString: \\\[Function],\r\n log: \\\[Function: native]\r\n}"}
+}
+
+njs_test {
+ {"[1, new Number(2), 'a', new String('αβZγ'), true, new Boolean(false)]\r\n"
+ "\\\[\r\n 1,\r\n \\\[Number: 2],\r\n 'a',\r\n \\\[String: 'αβZγ'],\r\n true,\r\n \\\[Boolean: false]\r\n]"}
+}
+
+njs_test {
+ {"[undefined,,null]\r\n"
+ "\\\[\r\n undefined,\r\n <empty>,\r\n null\r\n]"}
+}
+
+njs_test {
+ {"[InternalError(),TypeError('msg'), new RegExp(), /^undef$/m, new Date(0)]\r\n"
+ "\\\[\r\n InternalError,\r\n TypeError: msg,\r\n /(?:)/,\r\n /^undef$/m,\r\n 1970-01-01T00:00:00.000Z\r\n]"}
+}
+
+# dumper excapes special characters as JSON.stringify()
+# except '\"'
+njs_test {
+ {"\"\\r\\0\\\"\"\r\n"
+ "'\\\\r\\\\u0000\"'"}
+}
+
+njs_test {
+ {"[{a:1}]\r\n"
+ "\r\n\\\[\r\n {\r\n a: 1\r\n }\r\n]"}
}
# Backtraces are reset between invocations
"undefined"}
}
+njs_test {
+ {"(function() { throw 'test' })()\r\n"
+ "test\r\n at anonymous (:1)"}
+}
+
# Non-ASCII characters
njs_test {
{"'絵文字'\r\n"
- "絵文字"}
+ "'絵文字'"}
{"var v = 'абвгдеёжзийкл';v[10]\r\n"
- "й"}
+ "'й'"}
}
# require('fs')
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFile('njs_test_file', 'utf8', function (e, data) {console.log(data[2]+data.length)})\r\n"
- "Z4\r\nundefined\r\n>> "}
+ "'Z4'\r\nundefined\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFile('njs_test_file', function (e, data) {console.log(data[4]+data.length)})\r\n"
- "Z7\r\nundefined\r\n>> "}
+ "'Z7'\r\nundefined\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFile('njs_test_file', {encoding:'utf8',flag:'r+'}, function (e, data) {console.log(data)})\r\n"
- "αβZγ\r\nundefined\r\n>> "}
+ "'αβZγ'\r\nundefined\r\n>> "}
}
exec rm -fr njs_unknown_path
{"var fs = require('fs'); \r\n"
"undefined\r\n>> "}
{"fs.readFile('njs_unknown_path', 'utf8', function (e) {console.log(JSON.stringify(e))})\r\n"
- "{\"errno\":2,\"path\":\"njs_unknown_path\",\"syscall\":\"open\"}\r\nundefined\r\n>> "}
+ "'{\"errno\":2,\"path\":\"njs_unknown_path\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file').toString('base64')\r\n"
- "zrHOslrOsw==\r\n>> "}
+ "'zrHOslrOsw=='\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file', 'utf8')[2]\r\n"
- "Z\r\n>> "}
+ "'Z'\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file')[4]\r\n"
- "Z\r\n>> "}
+ "'Z'\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file', {encoding:'utf8',flag:'r+'})\r\n"
- "αβZγ\r\n>> "}
+ "'αβZγ'\r\n>> "}
}
njs_test {
{"var fs = require('fs'); \r\n"
"undefined\r\n>> "}
{"try { fs.readFileSync('njs_unknown_path')} catch (e) {console.log(JSON.stringify(e))}\r\n"
- "{\"errno\":2,\"path\":\"njs_unknown_path\",\"syscall\":\"open\"}\r\nundefined\r\n>> "}
+ "'{\"errno\":2,\"path\":\"njs_unknown_path\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "}
}
njs_test {
{"function h1(e) {if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))}\r\n"
"undefined\r\n>> "}
{"fs.writeFile('njs_test_file2', 'ABC', h1)\r\n"
- "ABC\r\nundefined\r\n>> "}
+ "'ABC'\r\nundefined\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.writeFile('njs_test_file2', 'ABC', 'utf8', function (e) { if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))})\r\n"
- "ABC\r\nundefined\r\n>> "}
+ "'ABC'\r\nundefined\r\n>> "}
}
njs_test {
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.writeFile('njs_test_file2', 'ABC', {encoding:'utf8', mode:0o666}, function (e) { if (e) {throw e}; console.log(fs.readFileSync('njs_test_file2'))})\r\n"
- "ABC\r\nundefined\r\n>> "}
+ "'ABC'\r\nundefined\r\n>> "}
}
exec rm -fr njs_wo_file
{"var fs = require('fs')\r\n"
"undefined\r\n>> "}
{"fs.writeFile('/invalid_path', 'ABC', function (e) { console.log(JSON.stringify(e))})\r\n"
- "{\"errno\":13,\"path\":\"/invalid_path\",\"syscall\":\"open\"}\r\nundefined\r\n>> "}
+ "'{\"errno\":13,\"path\":\"/invalid_path\",\"syscall\":\"open\"}'\r\nundefined\r\n>> "}
}
# require('fs').writeFileSync()
{"fs.writeFileSync('njs_test_file2', 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file2')\r\n"
- "ABC\r\n>> "}
+ "'ABC'\r\n>> "}
}
njs_test {
{"fs.writeFileSync('njs_test_file2', 'ABC', 'utf8')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file2')\r\n"
- "ABC\r\n>> "}
+ "'ABC'\r\n>> "}
}
njs_test {
{"fs.writeFileSync('njs_test_file2', 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file2')\r\n"
- "ABC\r\n>> "}
+ "'ABC'\r\n>> "}
}
njs_test {
{"fs.writeFileSync('njs_test_file2', 'ABC', {encoding:'utf8', mode:0o666})\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file2')\r\n"
- "ABC\r\n>> "}
+ "'ABC'\r\n>> "}
}
exec rm -fr njs_wo_file
{"function h2(e) {fs.appendFile('njs_test_file2', 'ABC', h1)}\r\n"
"undefined\r\n>> "}
{"fs.appendFile('njs_test_file2', 'ABC', h2)\r\n"
- "ABCABC\r\nundefined\r\n>> "}
+ "'ABCABC'\r\nundefined\r\n>> "}
}
# require('fs').appendFileSync()
{"fs.appendFileSync('njs_test_file2', 'ABC')\r\n"
"undefined\r\n>> "}
{"fs.readFileSync('njs_test_file2')\r\n"
- "ABCABC\r\n>> "}
+ "'ABCABC'\r\n>> "}
}
{ nxt_string("var a = {}; a.a = a; JSON.stringify(a)"),
nxt_string("TypeError: Nested too deep or a cyclic structure") },
+ /* njs.dump(). */
+
+ { nxt_string("njs.dump({a:1, b:[1,,2,{c:new Boolean(1)}]})"),
+ nxt_string("{a:1,b:[1,<empty>,2,{c:[Boolean: true]}]}") },
+
+ { nxt_string("njs.dump($r.props)"),
+ nxt_string("{a:{type:\"property\",props:[\"getter\"]},b:{type:\"property\",props:[\"getter\"]}}") },
+
+ { nxt_string("njs.dump($r.header)"),
+ nxt_string("{type:\"object\",props:[\"getter\",\"foreach\",\"next\"]}") },
+
/* require(). */
{ nxt_string("require('unknown_module')"),