|
|
@ -14,6 +14,7 @@ use crate::{ |
|
|
|
gc::{empty_trace, Finalize, Trace}, |
|
|
|
gc::{empty_trace, Finalize, Trace}, |
|
|
|
object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, |
|
|
|
object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE}, |
|
|
|
property::{Attribute, DataDescriptor}, |
|
|
|
property::{Attribute, DataDescriptor}, |
|
|
|
|
|
|
|
symbol::WellKnownSymbols, |
|
|
|
value::{RcString, Value}, |
|
|
|
value::{RcString, Value}, |
|
|
|
BoaProfiler, Context, Result, |
|
|
|
BoaProfiler, Context, Result, |
|
|
|
}; |
|
|
|
}; |
|
|
@ -120,6 +121,11 @@ impl BuiltIn for RegExp { |
|
|
|
.method(Self::test, "test", 1) |
|
|
|
.method(Self::test, "test", 1) |
|
|
|
.method(Self::exec, "exec", 1) |
|
|
|
.method(Self::exec, "exec", 1) |
|
|
|
.method(Self::to_string, "toString", 0) |
|
|
|
.method(Self::to_string, "toString", 0) |
|
|
|
|
|
|
|
.method( |
|
|
|
|
|
|
|
Self::search, |
|
|
|
|
|
|
|
(WellKnownSymbols::search(), "[Symbol.search]"), |
|
|
|
|
|
|
|
1, |
|
|
|
|
|
|
|
) |
|
|
|
.accessor("global", Some(get_global), None, flag_attributes) |
|
|
|
.accessor("global", Some(get_global), None, flag_attributes) |
|
|
|
.accessor("ignoreCase", Some(get_ignore_case), None, flag_attributes) |
|
|
|
.accessor("ignoreCase", Some(get_ignore_case), None, flag_attributes) |
|
|
|
.accessor("multiline", Some(get_multiline), None, flag_attributes) |
|
|
|
.accessor("multiline", Some(get_multiline), None, flag_attributes) |
|
|
@ -714,4 +720,62 @@ impl RegExp { |
|
|
|
|
|
|
|
|
|
|
|
Ok(result) |
|
|
|
Ok(result) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// `RegExp.prototype[ @@search ]( string )`
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This method executes a search for a match between a this regular expression and a string.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// More information:
|
|
|
|
|
|
|
|
/// - [ECMAScript reference][spec]
|
|
|
|
|
|
|
|
/// - [MDN documentation][mdn]
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [spec]: https://tc39.es/ecma262/#sec-regexp.prototype-@@search
|
|
|
|
|
|
|
|
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@search
|
|
|
|
|
|
|
|
pub(crate) fn search(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> { |
|
|
|
|
|
|
|
// 1. Let rx be the this value.
|
|
|
|
|
|
|
|
// 2. If Type(rx) is not Object, throw a TypeError exception.
|
|
|
|
|
|
|
|
if !this.is_object() { |
|
|
|
|
|
|
|
return context.throw_type_error( |
|
|
|
|
|
|
|
"RegExp.prototype[Symbol.search] method called on incompatible value", |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. Let S be ? ToString(string).
|
|
|
|
|
|
|
|
let arg_str = args |
|
|
|
|
|
|
|
.get(0) |
|
|
|
|
|
|
|
.cloned() |
|
|
|
|
|
|
|
.unwrap_or_default() |
|
|
|
|
|
|
|
.to_string(context)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 4. Let previousLastIndex be ? Get(rx, "lastIndex").
|
|
|
|
|
|
|
|
let previous_last_index = this.get_field("lastIndex", context)?.to_length(context)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 5. If SameValue(previousLastIndex, +0𝔽) is false, then
|
|
|
|
|
|
|
|
if previous_last_index != 0 { |
|
|
|
|
|
|
|
// a. Perform ? Set(rx, "lastIndex", +0𝔽, true).
|
|
|
|
|
|
|
|
this.set_field("lastIndex", 0, context)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 6. Let result be ? RegExpExec(rx, S).
|
|
|
|
|
|
|
|
let result = Self::exec(this, &[Value::from(arg_str)], context)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 7. Let currentLastIndex be ? Get(rx, "lastIndex").
|
|
|
|
|
|
|
|
let current_last_index = this.get_field("lastIndex", context)?.to_length(context)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 8. If SameValue(currentLastIndex, previousLastIndex) is false, then
|
|
|
|
|
|
|
|
if current_last_index != previous_last_index { |
|
|
|
|
|
|
|
// a. Perform ? Set(rx, "lastIndex", previousLastIndex, true).
|
|
|
|
|
|
|
|
this.set_field("lastIndex", previous_last_index, context)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 9. If result is null, return -1𝔽.
|
|
|
|
|
|
|
|
// 10. Return ? Get(result, "index").
|
|
|
|
|
|
|
|
if result.is_null() { |
|
|
|
|
|
|
|
Ok(Value::from(-1)) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
result |
|
|
|
|
|
|
|
.get_field("index", context) |
|
|
|
|
|
|
|
.map_err(|_| context.construct_type_error("Could not find property `index`")) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|