Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Implement get RegExp.prototype.hasIndices #2031

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 43 additions & 14 deletions boa_engine/src/builtins/regexp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ impl BuiltIn for RegExp {

let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;

let get_has_indices = FunctionBuilder::native(context, Self::get_has_indices)
.name("get hasIndices")
.constructor(false)
.build();
let get_global = FunctionBuilder::native(context, Self::get_global)
.name("get global")
.constructor(false)
Expand Down Expand Up @@ -137,6 +141,7 @@ impl BuiltIn for RegExp {
(WellKnownSymbols::split(), "[Symbol.split]"),
2,
)
.accessor("hasIndices", Some(get_has_indices), None, flag_attributes)
.accessor("global", Some(get_global), None, flag_attributes)
.accessor("ignoreCase", Some(get_ignore_case), None, flag_attributes)
.accessor("multiline", Some(get_multiline), None, flag_attributes)
Expand All @@ -145,7 +150,6 @@ impl BuiltIn for RegExp {
.accessor("sticky", Some(get_sticky), None, flag_attributes)
.accessor("flags", Some(get_flags), None, flag_attributes)
.accessor("source", Some(get_source), None, flag_attributes)
// TODO: add them RegExp accessor properties
.build()
.conv::<JsValue>()
.pipe(Some)
Expand Down Expand Up @@ -333,6 +337,7 @@ impl RegExp {
if let Some(object) = this.as_object() {
if let Some(regexp) = object.borrow().as_regexp() {
return Ok(JsValue::new(match flag {
b'd' => regexp.flags.contains(RegExpFlags::HAS_INDICES),
b'g' => regexp.flags.contains(RegExpFlags::GLOBAL),
b'm' => regexp.flags.contains(RegExpFlags::MULTILINE),
b's' => regexp.flags.contains(RegExpFlags::DOT_ALL),
Expand All @@ -352,6 +357,7 @@ impl RegExp {
}

let name = match flag {
b'd' => "hasIndices",
b'g' => "global",
b'm' => "multiline",
b's' => "dotAll",
Expand All @@ -366,6 +372,22 @@ impl RegExp {
))
}

/// `get RegExp.prototype.hasIndices`
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.hasindices
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global
pub(crate) fn get_has_indices(
this: &JsValue,
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
Self::regexp_has_flag(this, b'd', context)
}

/// `get RegExp.prototype.global`
///
/// The `global` property indicates whether or not the "`g`" flag is used with the regular expression.
Expand Down Expand Up @@ -497,41 +519,48 @@ impl RegExp {
if let Some(object) = this.as_object() {
// 3. Let result be the empty String.
let mut result = String::new();
// 4. Let global be ! ToBoolean(? Get(R, "global")).
// 5. If global is true, append the code unit 0x0067 (LATIN SMALL LETTER G) as the last code unit of result.

// 4. Let hasIndices be ToBoolean(? Get(R, "hasIndices")).
// 5. If hasIndices is true, append the code unit 0x0064 (LATIN SMALL LETTER D) as the last code unit of result.
if object.get("hasIndices", context)?.to_boolean() {
result.push('d');
}

// 6. Let global be ! ToBoolean(? Get(R, "global")).
// 7. If global is true, append the code unit 0x0067 (LATIN SMALL LETTER G) as the last code unit of result.
if object.get("global", context)?.to_boolean() {
result.push('g');
}
// 6. Let ignoreCase be ! ToBoolean(? Get(R, "ignoreCase")).
// 7. If ignoreCase is true, append the code unit 0x0069 (LATIN SMALL LETTER I) as the last code unit of result.
// 8. Let ignoreCase be ! ToBoolean(? Get(R, "ignoreCase")).
// 9. If ignoreCase is true, append the code unit 0x0069 (LATIN SMALL LETTER I) as the last code unit of result.
if object.get("ignoreCase", context)?.to_boolean() {
result.push('i');
}

// 8. Let multiline be ! ToBoolean(? Get(R, "multiline")).
// 9. If multiline is true, append the code unit 0x006D (LATIN SMALL LETTER M) as the last code unit of result.
// 10. Let multiline be ! ToBoolean(? Get(R, "multiline")).
// 11. If multiline is true, append the code unit 0x006D (LATIN SMALL LETTER M) as the last code unit of result.
if object.get("multiline", context)?.to_boolean() {
result.push('m');
}

// 10. Let dotAll be ! ToBoolean(? Get(R, "dotAll")).
// 11. If dotAll is true, append the code unit 0x0073 (LATIN SMALL LETTER S) as the last code unit of result.
// 12. Let dotAll be ! ToBoolean(? Get(R, "dotAll")).
// 13. If dotAll is true, append the code unit 0x0073 (LATIN SMALL LETTER S) as the last code unit of result.
if object.get("dotAll", context)?.to_boolean() {
result.push('s');
}
// 12. Let unicode be ! ToBoolean(? Get(R, "unicode")).
// 13. If unicode is true, append the code unit 0x0075 (LATIN SMALL LETTER U) as the last code unit of result.
// 14. Let unicode be ! ToBoolean(? Get(R, "unicode")).
// 15. If unicode is true, append the code unit 0x0075 (LATIN SMALL LETTER U) as the last code unit of result.
if object.get("unicode", context)?.to_boolean() {
result.push('u');
}

// 14. Let sticky be ! ToBoolean(? Get(R, "sticky")).
// 15. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) as the last code unit of result.
// 16. Let sticky be ! ToBoolean(? Get(R, "sticky")).
// 17. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) as the last code unit of result.
if object.get("sticky", context)?.to_boolean() {
result.push('y');
}

// 16. Return result.
// 18. Return result.
return Ok(result.into());
}

Expand Down
5 changes: 5 additions & 0 deletions boa_engine/src/syntax/lexer/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ bitflags! {
const DOT_ALL = 0b0000_1000;
const UNICODE = 0b0001_0000;
const STICKY = 0b0010_0000;
const HAS_INDICES = 0b0100_0000;
}
}

Expand All @@ -154,6 +155,7 @@ impl FromStr for RegExpFlags {
b's' => Self::DOT_ALL,
b'u' => Self::UNICODE,
b'y' => Self::STICKY,
b'd' => Self::HAS_INDICES,
_ => return Err(format!("invalid regular expression flag {}", char::from(c))),
};

Expand All @@ -180,6 +182,9 @@ fn parse_regex_flags(s: &str, start: Position, interner: &mut Interner) -> Resul
impl ToString for RegExpFlags {
fn to_string(&self) -> String {
let mut s = String::new();
if self.contains(Self::HAS_INDICES) {
s.push('d');
}
if self.contains(Self::GLOBAL) {
s.push('g');
}
Expand Down