njs_regexp_prototype_symbol_replace(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
{
- int64_t n, last_index, ncaptures, pos, length;
- const u_char *p, *next;
- njs_str_t rep, m;
+ int64_t n, last_index, ncaptures, pos, length, next, mlength;
+ const u_char *p, *start;
+ njs_str_t rep, m, head, tail;
njs_int_t ret;
njs_arr_t results;
njs_chb_t chain;
njs_value_t *arguments, *r, *rx, *string, *replace;
njs_value_t s_lvalue, r_lvalue, value, matched, groups;
njs_function_t *func_replace;
- njs_string_prop_t s;
+ njs_string_prop_t s, ms;
rx = njs_argument(args, 0);
}
i = 0;
- p = s.start;
- next = p;
+ next = 0;
while (i < results.items) {
r = njs_arr_item(&results, i++);
pos = njs_max(njs_min(pos, (int64_t) length), 0);
+ mlength = njs_string_prop(vm, &ms, &matched);
+
+ p = njs_string_offset(&s, pos);
+
ret = njs_object_length(vm, r, &ncaptures);
if (njs_slow_path(ret != NJS_OK)) {
goto exception;
}
}
- ret = njs_string_get_substitution(vm, &matched, string, pos,
- arguments, ncaptures, &groups,
- replace, retval);
+ m.start = ms.start;
+ m.length = ms.size;
+
+ head.start = s.start;
+ head.length = p - s.start;
+
+ start = njs_string_offset(&s, njs_min(pos + mlength, length));
+ tail.start = (u_char *) start;
+ tail.length = (s.start + s.size) - start;
+
+ ret = njs_string_get_substitution(vm, &m, &head, &tail, arguments,
+ ncaptures, &groups, replace,
+ retval);
} else {
ret = njs_array_expand(vm, array, 0,
goto exception;
}
- p = njs_string_offset(&s, pos);
-
- if (p >= next) {
- njs_chb_append(&chain, next, p - next);
+ if (pos >= next) {
+ start = njs_string_offset(&s, next);
+ njs_chb_append(&chain, start, p - start);
njs_string_get(vm, retval, &rep);
njs_chb_append_str(&chain, &rep);
- njs_string_get(vm, &matched, &m);
-
- next = p + m.length;
+ next = pos + mlength;
}
if (!func_replace && njs_object_slots(r)) {
}
}
- if (next < s.start + s.size) {
- njs_chb_append(&chain, next, s.start + s.size - next);
+ if (next < length) {
+ start = njs_string_offset(&s, next);
+ njs_chb_append(&chain, start, s.start + s.size - start);
}
ret = njs_string_create_chb(vm, retval, &chain);
njs_int_t
-njs_string_get_substitution(njs_vm_t *vm, njs_value_t *matched,
- njs_value_t *string, int64_t pos, njs_value_t *captures, int64_t ncaptures,
+njs_string_get_substitution(njs_vm_t *vm, njs_str_t *matched, njs_str_t *head,
+ njs_str_t *tail, njs_value_t *captures, int64_t ncaptures,
njs_value_t *groups, njs_value_t *replacement, njs_value_t *retval)
{
- u_char c, c2, *p, *r, *end;
- size_t length;
- int64_t tail, n;
- njs_str_t rep, str, cap;
- njs_int_t ret;
- njs_chb_t chain;
- njs_value_t name, value;
- njs_string_prop_t s, m;
+ u_char c, c2, *p, *r, *end;
+ int64_t n;
+ njs_str_t rep, str, cap;
+ njs_int_t ret;
+ njs_chb_t chain;
+ njs_value_t name, value;
njs_string_get(vm, replacement, &rep);
p = rep.start;
break;
case '&':
- (void) njs_string_prop(vm, &m, matched);
- njs_chb_append(&chain, m.start, m.size);
+ njs_chb_append_str(&chain, matched);
p += 2;
break;
case '`':
- (void) njs_string_prop(vm, &s, string);
- n = njs_string_offset(&s, pos) - s.start;
- njs_chb_append(&chain, s.start, n);
+ njs_chb_append_str(&chain, head);
p += 2;
break;
case '\'':
- length = njs_string_prop(vm, &m, matched);
- (void) njs_string_prop(vm, &s, string);
-
- tail = njs_string_offset(&s, pos + length) - s.start;
-
- njs_chb_append(&chain, &s.start[tail],
- njs_max((int64_t) s.size - tail, 0));
+ njs_chb_append_str(&chain, tail);
p += 2;
break;
size_t length, size, end_of_last_match;
int64_t pos;
njs_int_t ret;
- njs_str_t str;
+ njs_str_t str, m, head, tail;
njs_chb_t chain;
njs_value_t *this, *search, *replace;
njs_value_t search_lvalue, replace_lvalue, replacer, value,
return NJS_OK;
}
+ m.start = s.start;
+ m.length = s.size;
+
if (!replaceAll) {
+ end = njs_string_offset(&string, pos);
+
if (func_replace == NULL) {
- ret = njs_string_get_substitution(vm, search, this, pos, NULL, 0,
+ head.start = string.start;
+ head.length = end - string.start;
+
+ tail.start = (u_char *) end + s.size;
+ tail.length = (string.start + string.size) - (end + s.size);
+
+ ret = njs_string_get_substitution(vm, &m, &head, &tail, NULL, 0,
NULL, replace, &value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
}
- end = njs_string_offset(&string, pos);
-
(void) njs_string_prop(vm, &ret_string, &value);
size = string.size + ret_string.size - s.size;
start = string.start;
do {
+ end = njs_string_offset(&string, pos);
+
if (func_replace == NULL) {
- ret = njs_string_get_substitution(vm, search, this, pos, NULL, 0,
+ head.start = string.start;
+ head.length = end - string.start;
+
+ tail.start = (u_char *) end + s.size;
+ tail.length = (string.start + string.size) - (end + s.size);
+
+ ret = njs_string_get_substitution(vm, &m, &head, &tail, NULL, 0,
NULL, replace, &value);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
}
- end = njs_string_offset(&string, pos);
(void) njs_string_prop(vm, &ret_string, &value);
njs_chb_append(&chain, start, end - start);
njs_int_t njs_string_prototype_concat(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused, njs_value_t *retval);
-njs_int_t njs_string_get_substitution(njs_vm_t *vm, njs_value_t *matched,
- njs_value_t *string, int64_t pos, njs_value_t *captures, int64_t ncaptures,
+njs_int_t njs_string_get_substitution(njs_vm_t *vm, njs_str_t *matched,
+ njs_str_t *head, njs_str_t *tail, njs_value_t *captures, int64_t ncaptures,
njs_value_t *groups, njs_value_t *replacement, njs_value_t *retval);
"'abc'.replaceAll(re, '@$1|$2|$3|$4|$99|$100|@')"),
njs_str("@|X||Y|Z|0|@") },
+ { njs_str("var n = 0, s = 'αβγ';"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'y'.repeat(100), index: 0}};"
+ "RegExp.prototype[Symbol.replace].call(re, s, \"[$']\")"),
+ njs_str("[]") },
+
+ { njs_str("var n = 0, s = 'αβγδε';"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'y'.repeat(1000), index: 2}};"
+ "RegExp.prototype[Symbol.replace].call(re, s, \"<$'>\")"),
+ njs_str("αβ<>") },
+
+ { njs_str("var n = 0, s = 'αβγ';"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'y', index: 0}};"
+ "RegExp.prototype[Symbol.replace].call(re, s, '')"),
+ njs_str("βγ") },
+
+ { njs_str("var n = 0, s = 'αβγ';"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'y', index: 1e9}};"
+ "RegExp.prototype[Symbol.replace].call(re, s, '[$`]')"),
+ njs_str("αβγ[αβγ]") },
+
+ { njs_str("var n = 0, s = 'αβγδ';"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'αβ', index: 1}};"
+ "RegExp.prototype[Symbol.replace].call(re, s, \"[$&|$`|$']\")"),
+ njs_str("α[αβ|α|δ]δ") },
+
+ { njs_str("var n = 0, s = 'αβγδεζ';"
+ "var a = [{0: 'y', index: 5}, {0: 'y', index: 0}];"
+ "var re = {global: true, flags: 'g',"
+ " exec: () => n < a.length ? a[n++] : null};"
+ "RegExp.prototype[Symbol.replace].call(re, s, '<$&>')"),
+ njs_str("αβγδε<y>") },
+
+ { njs_str("var n = 0;"
+ "var a = [{0: 'yyyy', index: 0}, {0: 'z', index: 3}];"
+ "var re = {global: true, flags: 'g',"
+ " exec: () => n < a.length ? a[n++] : null};"
+ "RegExp.prototype[Symbol.replace].call(re, 'abc', '[1]')"),
+ njs_str("[1]") },
+
+ { njs_str("var n = 0;"
+ "var re = {global: false, flags: '', exec: () =>"
+ " n++ ? null : {0: 'yyyyyyyyy', index: 1}};"
+ "RegExp.prototype[Symbol.replace].call(re, 'abcdef',"
+ " \"[$&|$`|$']\")"),
+ njs_str("a[yyyyyyyyy|a|]") },
+
{ njs_str("var a = [];"
"Object.defineProperty(a, 32768, {});"
"var re = /any_regexp/;"