}
+/*
+ * Array.slice(start[, end]).
+ * JavaScript 1.2, ECMAScript 3.
+ */
+
static njs_ret_t
njs_array_prototype_slice(njs_vm_t *vm, njs_param_t *param)
{
uint32_t n;
uintptr_t nargs;
njs_array_t *array;
- njs_value_t *this, *args, *value;
+ njs_value_t *this, *value;
start = 0;
length = 0;
nargs = param->nargs;
if (nargs != 0) {
- args = param->args;
- start = njs_value_to_number(&args[0]);
+ start = param->args[0].data.u.number;
if (start < 0) {
start += length;
end = length;
if (nargs > 1) {
- end = njs_value_to_number(&args[1]);
+ end = param->args[1].data.u.number;
if (end < 0) {
end += length;
{
.type = NJS_METHOD,
.name = njs_string("slice"),
- .value = njs_native_function(njs_array_prototype_slice, 0),
+ .value = njs_native_function(njs_array_prototype_slice, 0,
+ NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("push"),
- .value = njs_native_function(njs_array_prototype_push, 0),
+ .value = njs_native_function(njs_array_prototype_push, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("pop"),
- .value = njs_native_function(njs_array_prototype_pop, 0),
+ .value = njs_native_function(njs_array_prototype_pop, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("unshift"),
- .value = njs_native_function(njs_array_prototype_unshift, 0),
+ .value = njs_native_function(njs_array_prototype_unshift, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("shift"),
- .value = njs_native_function(njs_array_prototype_shift, 0),
+ .value = njs_native_function(njs_array_prototype_shift, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_array_prototype_to_string, 0),
+ .value = njs_native_function(njs_array_prototype_to_string, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("join"),
- .value = njs_native_function(njs_array_prototype_join, 0),
+ .value = njs_native_function(njs_array_prototype_join, 0,
+ NJS_OBJECT_ARG, NJS_STRING_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("concat"),
- .value = njs_native_function(njs_array_prototype_concat, 0),
+ .value = njs_native_function(njs_array_prototype_concat, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("forEach"),
.value = njs_native_function(njs_array_prototype_for_each,
- njs_method_data_size(sizeof(njs_array_next_t))),
+ njs_method_data_size(sizeof(njs_array_next_t)), 0),
},
{
.type = NJS_METHOD,
.name = njs_string("some"),
.value = njs_native_function(njs_array_prototype_some,
- njs_method_data_size(sizeof(njs_array_next_t))),
+ njs_method_data_size(sizeof(njs_array_next_t)), 0),
},
{
.type = NJS_METHOD,
.name = njs_string("every"),
.value = njs_native_function(njs_array_prototype_every,
- njs_method_data_size(sizeof(njs_array_next_t))),
+ njs_method_data_size(sizeof(njs_array_next_t)), 0),
},
};
{
.type = NJS_METHOD,
.name = njs_string("valueOf"),
- .value = njs_native_function(njs_boolean_prototype_value_of, 0),
+ .value = njs_native_function(njs_boolean_prototype_value_of, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_boolean_prototype_to_string, 0),
+ .value = njs_native_function(njs_boolean_prototype_to_string, 0, 0),
},
};
#include <string.h>
+typedef struct {
+ njs_native_t native;
+ uint8_t args_types[NJS_ARGS_TYPES_MAX];
+} njs_function_init_t;
+
+
nxt_int_t
njs_builtin_objects_create(njs_vm_t *vm)
{
- nxt_int_t ret;
- nxt_uint_t i;
- njs_object_t *prototypes;
- njs_function_t *functions;
+ nxt_int_t ret;
+ nxt_uint_t i;
+ njs_object_t *prototypes;
+ njs_function_t *functions;
- static const njs_object_init_t *prototype_init[] = {
+ static const njs_object_init_t *prototype_init[] = {
&njs_object_prototype_init,
&njs_array_prototype_init,
&njs_boolean_prototype_init,
&njs_regexp_prototype_init,
};
- static const njs_object_init_t *function_init[] = {
+ static const njs_object_init_t *function_init[] = {
&njs_object_constructor_init,
&njs_array_constructor_init,
&njs_boolean_constructor_init,
&njs_eval_function_init,
};
- static const njs_native_t native_functions[] = {
- njs_object_constructor,
- njs_array_constructor,
- njs_boolean_constructor,
- njs_number_constructor,
- njs_string_constructor,
- njs_function_constructor,
- njs_regexp_constructor,
-
- njs_eval_function,
+ static const njs_function_init_t native_functions[] = {
+ { njs_object_constructor, {} },
+ { njs_array_constructor, {} },
+ { njs_boolean_constructor, {} },
+ { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } },
+ { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } },
+ { njs_function_constructor, {} },
+ { njs_regexp_constructor,
+ { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } },
+ { njs_eval_function, {} },
};
static const njs_object_prop_t null_proto_property = {
for (i = NJS_FUNCTION_OBJECT; i < NJS_FUNCTION_MAX; i++) {
functions[i].native = 1;
functions[i].args_offset = 1;
- functions[i].u.native = native_functions[i];
+ functions[i].u.native = native_functions[i].native;
+ functions[i].args_types[0] = native_functions[i].args_types[0];
+ functions[i].args_types[1] = native_functions[i].args_types[1];
+ functions[i].args_types[2] = native_functions[i].args_types[2];
ret = njs_object_hash_create(vm, &functions[i].object.shared_hash,
function_init[i]->properties,
njs_function_t *function;
njs_vmcode_function_call_t *call;
+ if (!njs_is_function(param->this)) {
+ vm->exception = &njs_exception_type_error;
+ return NXT_ERROR;
+ }
+
p.this = ¶m->args[0];
p.args = ¶m->args[1];
if (function->native) {
if (nargs != 0) {
- p.nargs = nargs - 1;
- p.retval = param->retval;
+ nargs--;
- return function->u.native(vm, &p);
+ } else {
+ param->args[0] = njs_value_void;
}
- vm->exception = &njs_exception_type_error;
- return NXT_ERROR;
+ p.nargs = nargs;
+ p.retval = param->retval;
+
+ ret = njs_normalize_args(vm, ¶m->args[0], function->args_types,
+ nargs + 1);
+ if (ret != NJS_OK) {
+ return ret;
+ }
+
+ return function->u.native(vm, &p);
}
if (nargs != 0) {
njs_function_t *function;
njs_vmcode_function_call_t *code;
+ if (!njs_is_function(param->this)) {
+ goto type_error;
+ }
+
args = param->args;
p.this = &args[0];
{
.type = NJS_METHOD,
.name = njs_string("call"),
- .value = njs_native_function(njs_function_prototype_call, 0),
+ .value = njs_native_function(njs_function_prototype_call, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("apply"),
- .value = njs_native_function(njs_function_prototype_apply, 0),
+ .value = njs_native_function(njs_function_prototype_apply, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("bind"),
- .value = njs_native_function(njs_function_prototype_bind, 0),
+ .value = njs_native_function(njs_function_prototype_bind, 0, 0),
},
};
#define _NJS_FUNCTION_H_INCLUDED_
+#define NJS_SKIP_ARG 1
+#define NJS_NUMBER_ARG 2
+#define NJS_INTEGER_ARG 3
+#define NJS_STRING_OBJECT_ARG 4
+#define NJS_STRING_ARG 5
+#define NJS_OBJECT_ARG 6
+#define NJS_REGEXP_ARG 7
+
+
struct njs_function_lambda_s {
uint32_t nargs;
uint32_t local_size;
value = &njs_value_zero;
} else {
- /* TODO: to_number. */
value = ¶m->args[0];
}
{
.type = NJS_METHOD,
.name = njs_string("valueOf"),
- .value = njs_native_function(njs_number_prototype_value_of, 0),
+ .value = njs_native_function(njs_number_prototype_value_of, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_number_prototype_to_string, 0),
+ .value = njs_native_function(njs_number_prototype_to_string, 0, 0),
},
};
{
.type = NJS_METHOD,
.name = njs_string("create"),
- .value = njs_native_function(njs_object_create, 0),
+ .value = njs_native_function(njs_object_create, 0, 0),
},
};
{
.type = NJS_METHOD,
.name = njs_string("valueOf"),
- .value = njs_native_function(njs_object_prototype_value_of, 0),
+ .value = njs_native_function(njs_object_prototype_value_of, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_object_prototype_to_string, 0),
+ .value = njs_native_function(njs_object_prototype_to_string, 0, 0),
},
};
case 1:
string.length = njs_string_prop(&string, ¶m->args[0]);
- break;
+
+ if (string.length != 0) {
+ break;
+ }
+
+ /* Fall through. */
case 0:
string.start = (u_char *) "(?:)";
{
njs_ret_t ret;
nxt_uint_t n;
- njs_value_t val;
+ njs_value_t *value;
const njs_value_t *retval;
njs_string_prop_t string;
njs_regexp_pattern_t *pattern;
- if (param->nargs != 0) {
- ret = njs_value_to_string(vm, &val, ¶m->args[0]);
+ if (!njs_is_regexp(param->this)) {
+ vm->exception = &njs_exception_type_error;
+ return NXT_ERROR;
+ }
- if (nxt_fast_path(ret == NXT_OK)) {
- retval = &njs_value_false;
+ retval = &njs_value_false;
- (void) njs_string_prop(&string, &val);
+ if (param->nargs != 0) {
+ value = ¶m->args[0];
- n = (string.length != 0 && string.length != string.size);
- pattern = param->this->data.u.regexp->pattern;
+ } else {
+ value = (njs_value_t *) &njs_string_void;
+ }
- if (pattern->code[n] != NULL) {
- ret = pcre_exec(pattern->code[n], pattern->extra[n],
- (char *) string.start, string.size,
- 0, 0, NULL, 0);
+ (void) njs_string_prop(&string, value);
- if (ret >= 0) {
- retval = &njs_value_true;
+ n = (string.length != 0 && string.length != string.size);
- } else if (ret != PCRE_ERROR_NOMATCH) {
- /* TODO: exception */
- return NXT_ERROR;
- }
- }
+ pattern = param->this->data.u.regexp->pattern;
- vm->retval = *retval;
+ if (pattern->code[n] != NULL) {
+ ret = pcre_exec(pattern->code[n], pattern->extra[n],
+ (char *) string.start, string.size, 0, 0, NULL, 0);
- return NXT_OK;
+ if (ret >= 0) {
+ retval = &njs_value_true;
+
+ } else if (ret != PCRE_ERROR_NOMATCH) {
+ vm->exception = &njs_exception_internal_error;
+ return NXT_ERROR;
}
}
- return NXT_ERROR;
+ vm->retval = *retval;
+
+ return NXT_OK;
}
int *captures, ncaptures;
njs_ret_t ret;
nxt_uint_t n, utf8;
+ njs_value_t *value;
njs_regexp_t *regexp;
njs_string_prop_t string;
njs_regexp_pattern_t *pattern;
- if (param->nargs != 0) {
- regexp = param->this->data.u.regexp;
+ if (!njs_is_regexp(param->this)) {
+ vm->exception = &njs_exception_type_error;
+ return NXT_ERROR;
+ }
- ret = njs_value_to_string(vm, ®exp->string, ¶m->args[0]);
+ if (param->nargs != 0) {
+ value = ¶m->args[0];
- if (nxt_fast_path(ret == NXT_OK)) {
- (void) njs_string_prop(&string, ®exp->string);
+ } else {
+ value = (njs_value_t *) &njs_string_void;
+ }
- utf8 = 0;
- n = 0;
+ regexp = param->this->data.u.regexp;
+ regexp->string = *value;
- if (string.length != 0) {
- utf8 = 1;
- n = 1;
+ (void) njs_string_prop(&string, value);
- if (string.length != string.size) {
- utf8 = 2;
- }
- }
+ utf8 = 0;
+ n = 0;
- pattern = regexp->pattern;
+ if (string.length != 0) {
+ utf8 = 1;
+ n = 1;
- if (pattern->code[n] != NULL) {
- string.start += regexp->last_index;
- string.size -= regexp->last_index;
+ if (string.length != string.size) {
+ utf8 = 2;
+ }
+ }
- /* Each capture is stored in 3 vector elements. */
- ncaptures = pattern->ncaptures * 3;
+ pattern = regexp->pattern;
- captures = alloca(ncaptures * sizeof(int));
+ if (pattern->code[n] != NULL) {
+ string.start += regexp->last_index;
+ string.size -= regexp->last_index;
- ret = pcre_exec(pattern->code[n], pattern->extra[n],
- (char *) string.start, string.size,
- 0, 0, captures, ncaptures);
+ /* Each capture is stored in 3 vector elements. */
+ ncaptures = pattern->ncaptures * 3;
- if (ret >= 0) {
- return njs_regexp_exec_result(vm, regexp, string.start,
- captures, utf8);
- }
+ captures = alloca(ncaptures * sizeof(int));
- if (nxt_slow_path(ret != PCRE_ERROR_NOMATCH)) {
- /* TODO: exception */
- return NXT_ERROR;
- }
- }
+ ret = pcre_exec(pattern->code[n], pattern->extra[n],
+ (char *) string.start, string.size,
+ 0, 0, captures, ncaptures);
- regexp->last_index = 0;
- vm->retval = njs_value_null;
+ if (ret >= 0) {
+ return njs_regexp_exec_result(vm, regexp, string.start,
+ captures, utf8);
+ }
- return NXT_OK;
+ if (nxt_slow_path(ret != PCRE_ERROR_NOMATCH)) {
+ vm->exception = &njs_exception_internal_error;
+ return NXT_ERROR;
}
}
- return NXT_ERROR;
+ regexp->last_index = 0;
+ vm->retval = njs_value_null;
+
+ return NXT_OK;
}
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_regexp_prototype_to_string, 0),
+ .value = njs_native_function(njs_regexp_prototype_to_string, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("test"),
- .value = njs_native_function(njs_regexp_prototype_test, 0),
+ .value = njs_native_function(njs_regexp_prototype_test, 0,
+ NJS_OBJECT_ARG, NJS_STRING_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("exec"),
- .value = njs_native_function(njs_regexp_prototype_exec, 0),
+ .value = njs_native_function(njs_regexp_prototype_exec, 0,
+ NJS_OBJECT_ARG, NJS_STRING_ARG),
},
};
value = &njs_string_empty;
} else {
- /* TODO: to_string. */
value = ¶m->args[0];
}
size_t size;
uintptr_t length;
+ /*
+ * This getter can be called for string primitive, String object,
+ * String.prototype. The zero should be returned for the latter case.
+ */
length = 0;
- /* TODO: String object. */
+ if (value->type == NJS_OBJECT_STRING) {
+ value = &value->data.u.object_value->value;
+ }
if (njs_is_string(value)) {
size = value->short_string.size;
return NXT_OK;
}
+/*
+ * String.concat(string2[, ..., stringN]).
+ * JavaScript 1.2, ECMAScript 3.
+ */
static njs_ret_t
njs_string_prototype_concat(njs_vm_t *vm, njs_param_t *param)
u_char *p, *start;
size_t size, length, mask;
uintptr_t nargs;
- njs_ret_t ret;
nxt_uint_t i;
- njs_value_t *this, *args, *values;
+ njs_value_t *this, *args;
njs_string_prop_t string;
this = param->this;
nargs = param->nargs;
- if (nargs == 0) {
- njs_string_copy(&vm->retval, this);
- return NXT_OK;
+ if (njs_is_null_or_void(this)) {
+ vm->exception = &njs_exception_type_error;
+ return NXT_ERROR;
}
- values = alloca((nargs + 1) * sizeof(njs_value_t));
+ args = param->args - 1;
- ret = njs_value_to_string(vm, &values[0], this);
- if (nxt_slow_path(ret != NXT_OK)) {
- return NXT_ERROR;
+ for (i = 0; i <= nargs; i++) {
+
+ if (!njs_is_string(&args[i])) {
+ vm->frame->trap_scratch.data.u.value = &args[i];
+
+ return NJS_TRAP_STRING_ARG;
+ }
+ }
+
+ if (nargs == 0) {
+ njs_string_copy(&vm->retval, this);
+ return NXT_OK;
}
- (void) njs_string_prop(&string, &values[0]);
+ (void) njs_string_prop(&string, this);
size = string.size;
length = string.length;
args = param->args;
for (i = 0; i < nargs; i++) {
- ret = njs_value_to_string(vm, &values[i + 1], &args[i]);
- if (nxt_slow_path(ret != NXT_OK)) {
- return NXT_ERROR;
- }
-
- (void) njs_string_prop(&string, &values[i + 1]);
+ (void) njs_string_prop(&string, &args[i]);
size += string.size;
length += string.length;
return NXT_ERROR;
}
- p = start;
+ (void) njs_string_prop(&string, this);
- for (i = 0; i <= nargs; i++) {
- (void) njs_string_prop(&string, &values[i]);
+ p = memcpy(start, string.start, string.size);
+ p += string.size;
+
+ for (i = 0; i < nargs; i++) {
+ (void) njs_string_prop(&string, &args[i]);
p = memcpy(p, string.start, string.size);
p += string.size;
}
+/*
+ * String.fromUTF8(start[, end]).
+ */
+
static njs_ret_t
njs_string_prototype_from_utf8(njs_vm_t *vm, njs_param_t *param)
{
}
+/*
+ * String.toUTF8(start[, end]).
+ */
+
static njs_ret_t
njs_string_prototype_to_utf8(njs_vm_t *vm, njs_param_t *param)
{
}
+/*
+ * String.fromBytes(start[, end]).
+ */
+
static njs_ret_t
njs_string_prototype_from_bytes(njs_vm_t *vm, njs_param_t *param)
{
}
+/*
+ * String.toBytes(start[, end]).
+ */
+
static njs_ret_t
njs_string_prototype_to_bytes(njs_vm_t *vm, njs_param_t *param)
{
{
ssize_t start, end, length;
uintptr_t nargs;
- njs_value_t *args;
njs_slice_prop_t slice;
njs_string_prop_t string;
nargs = param->nargs;
if (nargs != 0) {
- args = param->args;
-
- start = njs_value_to_number(&args[0]);
+ start = param->args[0].data.u.number;
if (start < 0) {
start = 0;
}
if (nargs > 1) {
- end = njs_value_to_number(&args[1]);
+ end = param->args[1].data.u.number;
if (end < 0) {
end = 0;
{
ssize_t start, length;
uintptr_t nargs;
- njs_value_t *args;
njs_slice_prop_t slice;
njs_string_prop_t string;
nargs = param->nargs;
if (nargs != 0) {
- args = param->args;
-
- start = njs_value_to_number(&args[0]);
+ start = param->args[0].data.u.number;
if (start < 0) {
}
if (nargs > 1) {
- length = njs_value_to_number(&args[1]);
+ length = param->args[1].data.u.number;
}
}
length = 1;
if (param->nargs != 0) {
- start = njs_value_to_number(¶m->args[0]);
+ start = param->args[0].data.u.number;
if (start < 0) {
length = 0;
static nxt_noinline void
njs_string_slice_params(njs_param_t *param, njs_slice_prop_t *slice)
{
- ssize_t start, end, length;
- uintptr_t nargs;
- njs_value_t *args;
+ ssize_t start, end, length;
+ uintptr_t nargs;
length = slice->string_length;
start = 0;
nargs = param->nargs;
if (nargs != 0) {
- args = param->args;
-
- start = njs_value_to_number(&args[0]);
+ start = param->args[0].data.u.number;
if (start < 0) {
start += length;
end = length;
if (nargs > 1) {
- end = njs_value_to_number(&args[1]);
+ end = param->args[1].data.u.number;
if (end < 0) {
end += length;
index = 0;
if (param->nargs != 0) {
- index = njs_value_to_number(¶m->args[0]);
+ index = param->args[0].data.u.number;
if (nxt_slow_path(index < 0 || index >= length)) {
num = NJS_NAN;
static njs_ret_t
njs_string_prototype_index_of(njs_vm_t *vm, njs_param_t *param)
{
- ssize_t start, index;
- uintptr_t nargs;
- njs_value_t *args;
+ ssize_t start, index;
+ uintptr_t nargs;
index = -1;
nargs = param->nargs;
if (nargs != 0) {
start = 0;
- args = param->args;
if (nargs > 1) {
- start = njs_value_to_number(&args[1]);
+ start = param->args[1].data.u.number;
if (start < 0) {
start = 0;
}
}
- index = njs_string_index_of(vm, param->this, &args[0], start);
+ index = njs_string_index_of(vm, param->this, ¶m->args[0], start);
}
njs_number_set(&vm->retval, index);
static njs_ret_t
njs_string_prototype_last_index_of(njs_vm_t *vm, njs_param_t *param)
{
- ssize_t ret, index, last;
- uintptr_t nargs;
- njs_value_t *args;
+ ssize_t ret, index, last;
+ uintptr_t nargs;
index = -1;
nargs = param->nargs;
if (nargs != 0) {
last = NJS_STRING_MAX_LENGTH;
- args = param->args;
if (nargs > 1) {
- last = njs_value_to_number(&args[1]);
+ last = param->args[1].data.u.number;
if (last < 0) {
last = 0;
ret = 0;
for ( ;; ) {
- ret = njs_string_index_of(vm, param->this, &args[0], ret);
+ ret = njs_string_index_of(vm, param->this, ¶m->args[0], ret);
if (ret < 0 || ret >= last) {
break;
int ret;
nxt_int_t index;
nxt_uint_t n;
- njs_value_t *args;
njs_string_prop_t string;
njs_regexp_pattern_t *pattern;
int captures[3];
- /* TODO: convert object to String. */
-
index = 0;
if (param->nargs != 0) {
- args = param->args;
+ switch (param->args[0].type) {
- switch (args[0].type) {
-
- case NJS_REGEXP:
- pattern = args[0].data.u.regexp->pattern;
- break;
+ case NJS_VOID:
+ goto done;
case NJS_STRING:
- (void) njs_string_prop(&string, &args[0]);
+ (void) njs_string_prop(&string, ¶m->args[0]);
- pattern = njs_regexp_pattern_create(vm, string.start,
- string.length, 0);
- if (nxt_slow_path(pattern == NULL)) {
- return NXT_ERROR;
+ if (string.size == 0) {
+ goto done;
}
- break;
-
- case NJS_VOID:
- /* STUB: precompiled "/(?:)/" pattern. */
- string.start = (u_char *) "(?:)";
- string.length = sizeof("(?:)") - 1;
-
pattern = njs_regexp_pattern_create(vm, string.start,
string.length, 0);
if (nxt_slow_path(pattern == NULL)) {
break;
- default:
- /* STUB: convert args[0] to String, then to RegExp. */
- vm->exception = &njs_exception_type_error;
-
- return NXT_ERROR;
+ default: /* NJS_REGEXP */
+ pattern = param->args[0].data.u.regexp->pattern;
}
index = -1;
index = njs_string_index(&string, captures[0]);
} else if (ret != PCRE_ERROR_NOMATCH) {
- /* TODO: exception */
+ vm->exception = &njs_exception_internal_error;
return NXT_ERROR;
}
}
}
+done:
+
njs_number_set(&vm->retval, index);
return NXT_OK;
}
+/*
+ * String.match([regexp])
+ */
+
static njs_ret_t
njs_string_prototype_match(njs_vm_t *vm, njs_param_t *param)
{
nxt_uint_t n, utf8;
njs_value_t *args;
njs_array_t *array;
- njs_regexp_t *regexp;
njs_string_prop_t string;
njs_regexp_pattern_t *pattern;
int captures[3];
- /* TODO: empty regexp */
+ if (param->nargs == 0) {
+ goto empty;
+ }
args = param->args;
- regexp = args[0].data.u.regexp;
- if (!regexp->pattern->global) {
- /*
- * string.match(regexp) is the same as regexp.exec(string)
- * if the regexp has no global flag.
- */
- param->args = param->this;
- param->this = args;
- param->nargs = 1;
+ switch (args[0].type) {
+
+ case NJS_VOID:
+ goto empty;
+
+ case NJS_STRING:
+ (void) njs_string_prop(&string, &args[0]);
+
+ if (string.size == 0) {
+ goto empty;
+ }
+
+ pattern = njs_regexp_pattern_create(vm, string.start, string.length, 0);
+ if (nxt_slow_path(pattern == NULL)) {
+ return NXT_ERROR;
+ }
+
+ break;
+
+ default: /* NJS_REGEXP */
+ pattern = args[0].data.u.regexp->pattern;
+
+ if (!pattern->global) {
+ /*
+ * string.match(regexp) is the same as regexp.exec(string)
+ * if the regexp has no global flag.
+ */
+ param->args = param->this;
+ param->this = args;
+ param->nargs = 1;
- return njs_regexp_prototype_exec(vm, param);
+ return njs_regexp_prototype_exec(vm, param);
+ }
}
vm->retval = njs_value_null;
}
}
- pattern = regexp->pattern;
-
if (pattern->code[n] != NULL) {
array = NULL;
break;
} else {
- /* TODO: internal error exception */
+ vm->exception = &njs_exception_internal_error;
return NXT_ERROR;
}
} while (string.size > 0);
}
- regexp->last_index = 0;
+ if (njs_is_regexp(&args[0])) {
+ args[0].data.u.regexp->last_index = 0;
+ }
+
+ return NXT_OK;
+
+empty:
+
+ array = njs_array_alloc(vm, 1, 0);
+ if (nxt_slow_path(array == NULL)) {
+ return NXT_ERROR;
+ }
+
+ array->length = 1;
+ array->start[0] = njs_string_empty;
+
+ vm->retval.data.u.array = array;
+ vm->retval.type = NJS_ARRAY;
+ vm->retval.data.truth = 1;
return NXT_OK;
}
{
.type = NJS_METHOD,
.name = njs_string("valueOf"),
- .value = njs_native_function(njs_string_prototype_value_of, 0),
+ .value = njs_native_function(njs_string_prototype_value_of, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("toString"),
- .value = njs_native_function(njs_string_prototype_value_of, 0),
+ .value = njs_native_function(njs_string_prototype_value_of, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("concat"),
- .value = njs_native_function(njs_string_prototype_concat, 0),
+ .value = njs_native_function(njs_string_prototype_concat, 0, 0),
},
{
.type = NJS_METHOD,
.name = njs_string("fromUTF8"),
- .value = njs_native_function(njs_string_prototype_from_utf8, 0),
+ .value = njs_native_function(njs_string_prototype_from_utf8, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("toUTF8"),
- .value = njs_native_function(njs_string_prototype_to_utf8, 0),
+ .value = njs_native_function(njs_string_prototype_to_utf8, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("fromBytes"),
- .value = njs_native_function(njs_string_prototype_from_bytes, 0),
+ .value = njs_native_function(njs_string_prototype_from_bytes, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("toBytes"),
- .value = njs_native_function(njs_string_prototype_to_bytes, 0),
+ .value = njs_native_function(njs_string_prototype_to_bytes, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("slice"),
- .value = njs_native_function(njs_string_prototype_slice, 0),
+ .value = njs_native_function(njs_string_prototype_slice, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("substring"),
- .value = njs_native_function(njs_string_prototype_substring, 0),
+ .value = njs_native_function(njs_string_prototype_substring, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("substr"),
- .value = njs_native_function(njs_string_prototype_substr, 0),
+ .value = njs_native_function(njs_string_prototype_substr, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("charAt"),
- .value = njs_native_function(njs_string_prototype_char_at, 0),
+ .value = njs_native_function(njs_string_prototype_char_at, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("charCodeAt"),
- .value = njs_native_function(njs_string_prototype_char_code_at, 0),
+ .value = njs_native_function(njs_string_prototype_char_code_at, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG),
},
/* ECMAScript 6, codePointAt(). */
{
.type = NJS_METHOD,
.name = njs_string("codePointAt"),
- .value = njs_native_function(njs_string_prototype_char_code_at, 0),
+ .value = njs_native_function(njs_string_prototype_char_code_at, 0,
+ NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("indexOf"),
- .value = njs_native_function(njs_string_prototype_index_of, 0),
+ .value = njs_native_function(njs_string_prototype_index_of, 0,
+ NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("lastIndexOf"),
- .value = njs_native_function(njs_string_prototype_last_index_of, 0),
+ .value = njs_native_function(njs_string_prototype_last_index_of, 0,
+ NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("search"),
- .value = njs_native_function(njs_string_prototype_search, 0),
+ .value = njs_native_function(njs_string_prototype_search, 0,
+ NJS_STRING_OBJECT_ARG, NJS_REGEXP_ARG),
},
{
.type = NJS_METHOD,
.name = njs_string("match"),
- .value = njs_native_function(njs_string_prototype_match, 0),
+ .value = njs_native_function(njs_string_prototype_match, 0,
+ NJS_STRING_ARG, NJS_REGEXP_ARG),
},
};
static void njs_vm_trap(njs_vm_t *vm, nxt_uint_t trap, njs_value_t *value1,
njs_value_t *value2);
+static void njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap);
static njs_ret_t njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld,
njs_value_t *narg);
static njs_ret_t njs_vmcode_string_primitive(njs_vm_t *vm, njs_value_t *invld,
njs_value_t *narg);
+static njs_ret_t njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *inlvd2);
+static njs_ret_t njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *inlvd2);
static njs_ret_t njs_primitive_value(njs_vm_t *vm, njs_value_t *value,
nxt_uint_t hint);
static njs_ret_t njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1,
const njs_value_t njs_exception_type_error = njs_string("TypeError");
const njs_value_t njs_exception_range_error = njs_string("RangeError");
const njs_value_t njs_exception_memory_error = njs_string("MemoryError");
+const njs_value_t njs_exception_internal_error = njs_string("InternalError");
/*
goto again;
+ case NJS_TRAP_NUMBER_ARG:
+ case NJS_TRAP_STRING_ARG:
+
+ njs_vm_trap_argument(vm, ret - NJS_TRAP_BASE);
+
+ goto again;
+
default:
break;
}
njs_ret_t ret;
njs_value_t *args;
njs_param_t param;
+ njs_function_t *function;
njs_native_frame_t *frame, *previous, *skip;
njs_vmcode_function_call_t *call;
- if (!vm->frame->u.function->native) {
+ function = vm->frame->u.function;
+
+ if (!function->native) {
(void) njs_function_call(vm, (njs_index_t) retval,
sizeof(njs_vmcode_function_call_t));
return 0;
}
- param.retval = (njs_index_t) retval;
call = (njs_vmcode_function_call_t *) vm->current;
- param.nargs = call->code.nargs - 1;
args = vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS];
+
+ ret = njs_normalize_args(vm, args - 1, function->args_types,
+ call->code.nargs);
+ if (ret != NJS_OK) {
+ return ret;
+ }
+
+ param.retval = (njs_index_t) retval;
+ param.nargs = call->code.nargs - 1;
param.args = args;
param.this = args - 1;
}
+njs_ret_t
+njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types,
+ nxt_uint_t nargs)
+{
+ njs_ret_t trap;
+ nxt_uint_t n;
+
+ n = nxt_min(nargs, NJS_ARGS_TYPES_MAX);
+
+ while (n != 0) {
+
+ switch (*args_types) {
+
+ case NJS_STRING_OBJECT_ARG:
+
+ if (njs_is_null_or_void(args)) {
+ goto type_error;
+ }
+
+ /* Fall through. */
+
+ case NJS_STRING_ARG:
+
+ if (njs_is_string(args)) {
+ break;
+ }
+
+ trap = NJS_TRAP_STRING_ARG;
+ goto trap;
+
+ case NJS_NUMBER_ARG:
+
+ if (njs_is_numeric(args)) {
+ break;
+ }
+
+ trap = NJS_TRAP_NUMBER_ARG;
+ goto trap;
+
+ case NJS_INTEGER_ARG:
+
+ if (njs_is_numeric(args)) {
+
+ /* Convert NaN and Infinities to integer. */
+
+ if (njs_is_nan(args->data.u.number)) {
+ args->data.u.number = 0;
+
+ } else if (njs_is_infinity(args->data.u.number)) {
+
+ if (args->data.u.number > 0) {
+ args->data.u.number = 0x7fffffffffffffff;
+
+ } else {
+ args->data.u.number = 0x8000000000000000;
+ }
+ }
+
+ break;
+ }
+
+ trap = NJS_TRAP_NUMBER_ARG;
+ goto trap;
+
+ case NJS_REGEXP_ARG:
+
+ switch (args->type) {
+ case NJS_VOID:
+ case NJS_STRING:
+ case NJS_REGEXP:
+ break;
+
+ default:
+ trap = NJS_TRAP_STRING_ARG;
+ goto trap;
+ }
+
+ break;
+
+ case NJS_OBJECT_ARG:
+
+ if (njs_is_null_or_void(args)) {
+ goto type_error;
+ }
+
+ break;
+
+ case NJS_SKIP_ARG:
+
+ break;
+ }
+
+ args++;
+ args_types++;
+ n--;
+ }
+
+ return NJS_OK;
+
+trap:
+
+ vm->frame->trap_scratch.data.u.value = args;
+
+ return trap;
+
+type_error:
+
+ vm->exception = &njs_exception_type_error;
+
+ return NXT_ERROR;
+}
+
+
njs_ret_t
njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
{
};
+static const njs_vmcode_1addr_t njs_trap_number_argument = {
+ .code = { .operation = njs_vmcode_number_argument,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL }
+};
+
+
+static const njs_vmcode_1addr_t njs_trap_string_argument = {
+ .code = { .operation = njs_vmcode_string_argument,
+ .operands = NJS_VMCODE_NO_OPERAND,
+ .retval = NJS_VMCODE_NO_RETVAL }
+};
+
+
static const njs_vm_trap_t njs_vm_traps[] = {
- /* NJS_TRAP_PROPERTY */ { &njs_trap_strings[1], 0 },
- /* NJS_TRAP_STRINGS */ { &njs_trap_strings[0], 0 },
- /* NJS_TRAP_INCDEC */ { &njs_trap_numbers[1], 1 },
- /* NJS_TRAP_NUMBERS */ { &njs_trap_numbers[0], 0 },
- /* NJS_TRAP_NUMBER */ { &njs_trap_number[0], 0 },
+ /* NJS_TRAP_STRING_ARG */ { &njs_trap_string_argument, 0 },
+ /* NJS_TRAP_INTEGER_ARG */ { &njs_trap_number_argument, 0 },
+ /* NJS_TRAP_PROPERTY */ { &njs_trap_strings[1], 0 },
+ /* NJS_TRAP_STRINGS */ { &njs_trap_strings[0], 0 },
+ /* NJS_TRAP_INCDEC */ { &njs_trap_numbers[1], 1 },
+ /* NJS_TRAP_NUMBERS */ { &njs_trap_numbers[0], 0 },
+ /* NJS_TRAP_NUMBER */ { &njs_trap_number[0], 0 },
};
}
+static void
+njs_vm_trap_argument(njs_vm_t *vm, nxt_uint_t trap)
+{
+ njs_value_t *value;
+
+ value = vm->frame->trap_scratch.data.u.value;
+ vm->frame->trap_values[1].data.u.value = value;
+ vm->frame->trap_values[0] = *value;
+
+ njs_set_invalid(&vm->frame->trap_scratch);
+
+ vm->frame->trap_restart = vm->current;
+ vm->current = (u_char *) njs_vm_traps[trap].code;
+}
+
+
static njs_ret_t
njs_vmcode_number_primitive(njs_vm_t *vm, njs_value_t *invld, njs_value_t *narg)
{
}
+static njs_ret_t
+njs_vmcode_number_argument(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *inlvd2)
+{
+ double num;
+ njs_ret_t ret;
+ njs_value_t *value;
+
+ value = &vm->frame->trap_values[0];
+
+ ret = njs_primitive_value(vm, value, 0);
+
+ if (nxt_fast_path(ret > 0)) {
+
+ if (!njs_is_numeric(value)) {
+ num = NJS_NAN;
+
+ if (njs_is_string(value)) {
+ num = njs_string_to_number(value);
+ }
+
+ njs_number_set(value, num);
+ }
+
+ *vm->frame->trap_values[1].data.u.value = *value;
+ vm->current = vm->frame->trap_restart;
+
+ return 0;
+ }
+
+ return ret;
+}
+
+
+static njs_ret_t
+njs_vmcode_string_argument(njs_vm_t *vm, njs_value_t *invld1,
+ njs_value_t *inlvd2)
+{
+ njs_ret_t ret;
+ njs_value_t *value;
+
+ value = &vm->frame->trap_values[0];
+
+ ret = njs_primitive_value(vm, value, 1);
+
+ if (nxt_fast_path(ret > 0)) {
+ ret = njs_primitive_value_to_string(vm, value, value);
+
+ if (nxt_fast_path(ret == NXT_OK)) {
+ *vm->frame->trap_values[1].data.u.value = *value;
+ vm->current = vm->frame->trap_restart;
+ }
+ }
+
+ return ret;
+}
+
+
/*
* A hint value is 0 for numbers and 1 for strings. The value chooses
* method calls order specified by ECMAScript 5.1: "valueOf", "toString"
* -3: not used;
* -4 (NJS_STOP/NXT_DONE): njs_vmcode_stop() has stopped execution,
* execution has completed successfully;
- * -5 .. -9: traps to convert objects to primitive values;
- * -10 .. -15: not used.
+ * -5 .. -11: traps to convert objects to primitive values;
+ * -12 .. -15: not used.
*/
#define NJS_STOP NXT_DONE
#define NJS_TRAP_INCDEC (-7)
#define NJS_TRAP_STRINGS (-8)
#define NJS_TRAP_PROPERTY (-9)
-#define NJS_TRAP_BASE NJS_TRAP_PROPERTY
+#define NJS_TRAP_NUMBER_ARG (-10)
+#define NJS_TRAP_STRING_ARG (-11)
+#define NJS_TRAP_BASE NJS_TRAP_STRING_ARG
#define NJS_PREEMPT (-15)
};
+#define NJS_ARGS_TYPES_MAX 3
+
typedef struct {
njs_object_t object;
+ uint8_t args_types[NJS_ARGS_TYPES_MAX];
+
#if (NXT_64BIT)
uint8_t native;
uint8_t local_state_size;
}
-#define njs_native_function(_function, _local_size) { \
+#define njs_native_function(_function, _local_size, ...) { \
.data = { \
.type = NJS_FUNCTION, \
.truth = 1, \
.u.function = & (njs_function_t) { \
.native = 1, \
.local_state_size = _local_size, \
+ .args_types = { __VA_ARGS__ }, \
.args_offset = 1, \
.u.native = _function, \
} \
njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld,
njs_value_t *retval);
+njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args,
+ uint8_t *args_types, nxt_uint_t nargs);
+
njs_ret_t njs_value_to_ext_string(njs_vm_t *vm, nxt_str_t *dst,
const njs_value_t *src);
void njs_number_set(njs_value_t *value, double num);
extern const njs_value_t njs_exception_type_error;
extern const njs_value_t njs_exception_range_error;
extern const njs_value_t njs_exception_memory_error;
+extern const njs_value_t njs_exception_internal_error;
extern const nxt_mem_proto_t njs_array_mem_proto;
extern const nxt_lvlhsh_proto_t njs_object_hash_proto;
{ nxt_string("a = 'abc'; a.concat('абв', 123)"),
nxt_string("abcабв123") },
+ { nxt_string("''.concat.call(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)"),
+ nxt_string("0123456789") },
+
+#if 0
+ { nxt_string("''.concat.apply(0, [1, 2, 3, 4, 5, 6, 7, 8, 9])"),
+ nxt_string("0123456789") },
+#endif
+
+ { nxt_string("var s = { toString: function() { return '123' } };"
+ "var a = 'abc'; a.concat('абв', s)"),
+ nxt_string("abcабв123") },
+
{ nxt_string("'\\u00CE\\u00B1'.toBytes() == 'α'"),
nxt_string("true") },
{ nxt_string("'abc'.charAt(3)"),
nxt_string("") },
+ { nxt_string("'abc'.charAt(undefined)"),
+ nxt_string("a") },
+
+ { nxt_string("'abc'.charAt(null)"),
+ nxt_string("a") },
+
+ { nxt_string("'abc'.charAt(false)"),
+ nxt_string("a") },
+
+ { nxt_string("'abc'.charAt(true)"),
+ nxt_string("b") },
+
+ { nxt_string("'abc'.charAt(NaN)"),
+ nxt_string("a") },
+
+ { nxt_string("'abc'.charAt(Infinity)"),
+ nxt_string("") },
+
+ { nxt_string("'abc'.charAt(-Infinity)"),
+ nxt_string("") },
+
+ { nxt_string("var o = { valueOf: function() {return 2} }"
+ "'abc'.charAt(o)"),
+ nxt_string("c") },
+
+ { nxt_string("var o = { toString: function() {return '2'} }"
+ "'abc'.charAt(o)"),
+ nxt_string("c") },
+
{ nxt_string("'abc'.charCodeAt(1 + 1)"),
nxt_string("99") },
{ nxt_string("'abcdef'.indexOf('', 3)"),
nxt_string("3") },
+ { nxt_string("'12345'.indexOf()"),
+ nxt_string("-1") },
+
+ { nxt_string("'12345'.indexOf(45, '0')"),
+ nxt_string("3") },
+
+ { nxt_string("''.indexOf.call(12345, 45, '0')"),
+ nxt_string("3") },
+
{ nxt_string("'abc abc abc abc'.lastIndexOf('abc')"),
nxt_string("12") },
{ nxt_string("'abcdefgh'.search('def')"),
nxt_string("3") },
+ { nxt_string("'123456'.search('45')"),
+ nxt_string("3") },
+
+ { nxt_string("'123456'.search(45)"),
+ nxt_string("3") },
+
+ { nxt_string("'123456'.search(String(45))"),
+ nxt_string("3") },
+
+ { nxt_string("'123456'.search(Number('45'))"),
+ nxt_string("3") },
+
+ { nxt_string("var r = { toString: function() { return '45' } }"
+ "'123456'.search(r)"),
+ nxt_string("3") },
+
+ { nxt_string("var r = { toString: function() { return 45 } }"
+ "'123456'.search(r)"),
+ nxt_string("3") },
+
+ { nxt_string("var r = { toString: function() { return /45/ } }"
+ "'123456'.search(r)"),
+ nxt_string("TypeError") },
+
+ { nxt_string("var r = { toString: function() { return /34/ },"
+ " valueOf: function() { return 45 } }"
+ "'123456'.search(r)"),
+ nxt_string("3") },
+
+ { nxt_string("'abcdefgh'.match()"),
+ nxt_string("") },
+
+ { nxt_string("'abcdefgh'.match('')"),
+ nxt_string("") },
+
+ { nxt_string("'abcdefgh'.match(undefined)"),
+ nxt_string("") },
+
+ { nxt_string("'abcdefgh'.match(/def/)"),
+ nxt_string("def") },
+
+ { nxt_string("'abcdefgh'.match('def')"),
+ nxt_string("def") },
+
+ { nxt_string("'123456'.match('45')"),
+ nxt_string("45") },
+
+ { nxt_string("'123456'.match(45)"),
+ nxt_string("45") },
+
+ { nxt_string("'123456'.match(String(45))"),
+ nxt_string("45") },
+
+ { nxt_string("'123456'.match(Number('45'))"),
+ nxt_string("45") },
+
+ { nxt_string("var r = { toString: function() { return '45' } }"
+ "'123456'.match(r)"),
+ nxt_string("45") },
+
+ { nxt_string("var r = { toString: function() { return 45 } }"
+ "'123456'.match(r)"),
+ nxt_string("45") },
+
+ { nxt_string("var r = { toString: function() { return /45/ } }"
+ "'123456'.match(r)"),
+ nxt_string("TypeError") },
+
+ { nxt_string("var r = { toString: function() { return /34/ },"
+ " valueOf: function() { return 45 } }"
+ "'123456'.match(r)"),
+ nxt_string("45") },
+
{ nxt_string("''.match(/^$/)"),
nxt_string("") },
{ nxt_string("[].join.call([1,2,3], ':')"),
nxt_string("1:2:3") },
+ { nxt_string("[].join.call([1,2,3], 55)"),
+ nxt_string("1552553") },
+
{ nxt_string("[].join.call()"),
nxt_string("TypeError") },
+ { nxt_string("[].slice.call()"),
+ nxt_string("TypeError") },
+
{ nxt_string("function F(a, b) { this.a = a + b }"
"var o = new F(1, 2)"
"o.a"),
{ nxt_string("/\\d/.test('123')"),
nxt_string("true") },
+ { nxt_string("/\\d/.test(123)"),
+ nxt_string("true") },
+
+ { nxt_string("/undef/.test()"),
+ nxt_string("true") },
+
+ { nxt_string("var s = { toString: function() { return 123 } };"
+ "/\\d/.test(s)"),
+ nxt_string("true") },
+
{ nxt_string("/\\d/.test('abc')"),
nxt_string("false") },
{ nxt_string("/α/.test('\\u00CE\\u00B1'.toBytes())"),
nxt_string("true") },
+ { nxt_string("/\\d/.exec('123')"),
+ nxt_string("1") },
+
+ { nxt_string("/\\d/.exec(123)"),
+ nxt_string("1") },
+
+ { nxt_string("/undef/.exec()"),
+ nxt_string("undef") },
+
+ { nxt_string("var s = { toString: function() { return 123 } };"
+ "/\\d/.exec(s)"),
+ nxt_string("1") },
+
{ nxt_string("var a = /^$/.exec(''); a.length +' '+ a"),
nxt_string("1 ") },
{ nxt_string("Number()"),
nxt_string("0") },
+ { nxt_string("Number(123)"),
+ nxt_string("123") },
+
+ { nxt_string("Number('123')"),
+ nxt_string("123") },
+
+ { nxt_string("var o = { valueOf: function() { return 123 } };"
+ "Number(o)"),
+ nxt_string("123") },
+
+ { nxt_string("var o = { valueOf: function() { return 123 } };"
+ "new Number(o)"),
+ nxt_string("123") },
+
{ nxt_string("typeof Number(1)"),
nxt_string("number") },
{ nxt_string("String()"),
nxt_string("") },
+ { nxt_string("String(123)"),
+ nxt_string("123") },
+
+ { nxt_string("new String(123)"),
+ nxt_string("123") },
+
+ { nxt_string("String([1,2,3])"),
+ nxt_string("1,2,3") },
+
+ { nxt_string("new String([1,2,3])"),
+ nxt_string("1,2,3") },
+
+ { nxt_string("var o = { toString: function() { return 'OK' } }"
+ "String(o)"),
+ nxt_string("OK") },
+
+ { nxt_string("var o = { toString: function() { return 'OK' } }"
+ "new String(o)"),
+ nxt_string("OK") },
+
{ nxt_string("typeof String('abc')"),
nxt_string("string") },
{ nxt_string("Function.constructor === Function"),
nxt_string("true") },
+ { nxt_string("RegExp()"),
+ nxt_string("/(?:)/") },
+
+ { nxt_string("RegExp('')"),
+ nxt_string("/(?:)/") },
+
+ { nxt_string("RegExp(123)"),
+ nxt_string("/123/") },
+
{ nxt_string("RegExp.name"),
nxt_string("RegExp") },
{ nxt_string("RegExp.constructor === Function"),
nxt_string("true") },
-#if 0
{ nxt_string("Object.prototype.toString.call()"),
nxt_string("[object Undefined]") },
-#endif
{ nxt_string("Object.prototype.toString.call(undefined)"),
nxt_string("[object Undefined]") },