njs_string_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t unused)
{
+ double pos;
ssize_t index, start, length, search_length;
const u_char *p, *end;
+ const njs_value_t *search_string;
njs_string_prop_t string, search;
index = -1;
- if (nargs > 1) {
- length = njs_string_prop(&string, &args[0]);
- search_length = njs_string_prop(&search, &args[1]);
+ length = njs_string_prop(&string, njs_arg(args, nargs, 0));
- if (length < search_length) {
- goto done;
- }
+ search_string = njs_arg(args, nargs, 1);
- index = NJS_STRING_MAX_LENGTH;
+ if (njs_is_undefined(search_string)) {
+ search_string = &njs_string_undefined;
+ }
- if (nargs > 2) {
- index = args[2].data.u.number;
+ search_length = njs_string_prop(&search, search_string);
- if (index < 0) {
- index = 0;
- }
- }
+ if (length < search_length) {
+ goto done;
+ }
- if (index > length) {
- index = length;
+ pos = njs_arg(args, nargs, 2)->data.u.number;
+
+ if (isnan(pos)) {
+ index = NJS_STRING_MAX_LENGTH;
+
+ } else {
+ index = njs_number_to_integer(pos);
+
+ if (index < 0) {
+ index = 0;
}
+ }
- if (string.size == (size_t) length) {
- /* Byte or ASCII string. */
+ if (index > length) {
+ index = length;
+ }
- start = length - search.size;
+ if (string.size == (size_t) length) {
+ /* Byte or ASCII string. */
- if (index > start) {
- index = start;
- }
+ start = length - search.size;
- p = string.start + index;
+ if (index > start) {
+ index = start;
+ }
- do {
- if (memcmp(p, search.start, search.size) == 0) {
- goto done;
- }
+ p = string.start + index;
- index--;
- p--;
+ do {
+ if (memcmp(p, search.start, search.size) == 0) {
+ goto done;
+ }
- } while (p >= string.start);
+ index--;
+ p--;
- } else {
- /* UTF-8 string. */
+ } while (p >= string.start);
- end = string.start + string.size;
- p = njs_string_offset(string.start, end, index);
- end -= search.size;
+ } else {
+ /* UTF-8 string. */
- while (p > end) {
- index--;
- p = nxt_utf8_prev(p);
- }
+ end = string.start + string.size;
+ p = njs_string_offset(string.start, end, index);
+ end -= search.size;
- for ( ;; ) {
- if (memcmp(p, search.start, search.size) == 0) {
- goto done;
- }
+ while (p > end) {
+ index--;
+ p = nxt_utf8_prev(p);
+ }
- index--;
+ for ( ;; ) {
+ if (memcmp(p, search.start, search.size) == 0) {
+ goto done;
+ }
- if (p <= string.start) {
- break;
- }
+ index--;
- p = nxt_utf8_prev(p);
+ if (p <= string.start) {
+ break;
}
+
+ p = nxt_utf8_prev(p);
}
}
.type = NJS_METHOD,
.name = njs_string("lastIndexOf"),
.value = njs_native_function(njs_string_prototype_last_index_of, 0,
- NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG),
+ NJS_STRING_OBJECT_ARG, NJS_STRING_ARG, NJS_NUMBER_ARG),
.configurable = 1,
},
{ nxt_string("'abc abc абвгд abc'.lastIndexOf('абвгд')"),
nxt_string("8") },
+ { nxt_string("'abc abc абвгд abc'.lastIndexOf('абвгд', undefined)"),
+ nxt_string("8") },
+
+ { nxt_string("'abc abc абвгд abc'.lastIndexOf('абвгд', NaN)"),
+ nxt_string("8") },
+
+ { nxt_string("'abc abc абвгд abc'.lastIndexOf('абвгд', {})"),
+ nxt_string("8") },
+
+ { nxt_string("String.prototype.lastIndexOf.call({toString:()=>'abc abc абвгд abc'}, 'абвгд')"),
+ nxt_string("8") },
+
{ nxt_string("'abc abc абвгдежз'.lastIndexOf('абвгд')"),
nxt_string("8") },
{ nxt_string("''.lastIndexOf('')"),
nxt_string("0") },
+ { nxt_string("''.lastIndexOf()"),
+ nxt_string("-1") },
+
+ { nxt_string("''.lastIndexOf(undefined)"),
+ nxt_string("-1") },
+
{ nxt_string("''.includes('')"),
nxt_string("true") },