Browse Source

Fix `String.prototype.replace()` order of `ToString` execution (#2799)

Fix order of `ToString` execution, there are 3 failing tests on `.replace()` but they seem to be regex related
pull/2797/head
Haled Odat 2 years ago
parent
commit
7a4d6526b0
  1. 94
      boa_engine/src/builtins/string/mod.rs

94
boa_engine/src/builtins/string/mod.rs

@ -930,11 +930,16 @@ impl String {
args: &[JsValue],
context: &mut Context<'_>,
) -> JsResult<JsValue> {
// Helper enum.
enum CallableOrString<'a> {
FunctionalReplace(&'a JsObject),
ReplaceValue(JsString),
}
// 1. Let O be ? RequireObjectCoercible(this value).
this.require_object_coercible()?;
let o = this.require_object_coercible()?;
let search_value = args.get_or_undefined(0);
let replace_value = args.get_or_undefined(1);
// 2. If searchValue is neither undefined nor null, then
@ -945,73 +950,72 @@ impl String {
// b. If replacer is not undefined, then
if let Some(replacer) = replacer {
// i. Return ? Call(replacer, searchValue, « O, replaceValue »).
return replacer.call(
search_value,
&[this.clone(), replace_value.clone()],
context,
);
return replacer.call(search_value, &[o.clone(), replace_value.clone()], context);
}
}
// 3. Let string be ? ToString(O).
let this_str = this.to_string(context)?;
let string = o.to_string(context)?;
// 4. Let searchString be ? ToString(searchValue).
let search_str = search_value.to_string(context)?;
let search_string = search_value.to_string(context)?;
// 5. Let functionalReplace be IsCallable(replaceValue).
let replace_obj = replace_value.as_callable();
let functional_replace = replace_value.as_callable();
// 6. If functionalReplace is false, then
// a. Set replaceValue to ? ToString(replaceValue).
let replace_value = if let Some(callable) = functional_replace {
CallableOrString::FunctionalReplace(callable)
} else {
// a. Set replaceValue to ? ToString(replaceValue).
CallableOrString::ReplaceValue(replace_value.to_string(context)?)
};
// 7. Let searchLength be the length of searchString.
let search_length = search_str.len();
let search_length = search_string.len();
// 8. Let position be ! StringIndexOf(string, searchString, 0).
// 9. If position is -1, return string.
let Some(position) = this_str.index_of(&search_str, 0) else {
return Ok(this_str.into());
let Some(position) = string.index_of(&search_string, 0) else {
return Ok(string.into());
};
// 10. Let preserved be the substring of string from 0 to position.
let preserved = &this_str[..position];
// 11. If functionalReplace is true, then
// 12. Else,
let replacement = if let Some(replace_fn) = replace_obj {
// a. Let replacement be ? ToString(? Call(replaceValue, undefined, « searchString, 𝔽(position), string »)).
replace_fn
.call(
let preserved = &string[..position];
let replacement = match replace_value {
// 11. If functionalReplace is true, then
CallableOrString::FunctionalReplace(replace_fn) => {
// a. Let replacement be ? ToString(? Call(replaceValue, undefined, « searchString, 𝔽(position), string »)).
replace_fn
.call(
&JsValue::undefined(),
&[search_string.into(), position.into(), string.clone().into()],
context,
)?
.to_string(context)?
}
// 12. Else,
CallableOrString::ReplaceValue(replace_value) => {
// a. Assert: Type(replaceValue) is String.
// b. Let captures be a new empty List.
let captures = Vec::new();
// c. Let replacement be ! GetSubstitution(searchString, string, position, captures, undefined, replaceValue).
get_substitution(
&search_string,
&string,
position,
&captures,
&JsValue::undefined(),
&[search_str.into(), position.into(), this_str.clone().into()],
&replace_value,
context,
)?
.to_string(context)?
} else {
// a. Assert: Type(replaceValue) is String.
// b. Let captures be a new empty List.
let captures = Vec::new();
// c. Let replacement be ! GetSubstitution(searchString, string, position, captures, undefined, replaceValue).
get_substitution(
&search_str,
&this_str,
position,
&captures,
&JsValue::undefined(),
&replace_value.to_string(context)?,
context,
)?
}
};
// 13. Return the string-concatenation of preserved, replacement, and the substring of string from position + searchLength.
Ok(js_string!(
preserved,
&replacement,
&this_str[position + search_length..]
)
.into())
Ok(js_string!(preserved, &replacement, &string[position + search_length..]).into())
}
/// `22.1.3.18 String.prototype.replaceAll ( searchValue, replaceValue )`

Loading…
Cancel
Save