Browse Source

Implement RegExp flag accessors (#1221)

pull/1236/head
Halid Odat 3 years ago committed by GitHub
parent
commit
f47ed7b1e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 325
      boa/src/builtins/regexp/mod.rs

325
boa/src/builtins/regexp/mod.rs

@ -12,7 +12,7 @@
use crate::{
builtins::BuiltIn,
gc::{empty_trace, Finalize, Trace},
object::{ConstructorBuilder, ObjectData, PROTOTYPE},
object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE},
property::{Attribute, DataDescriptor},
value::{RcString, Value},
BoaProfiler, Context, Result,
@ -71,6 +71,44 @@ impl BuiltIn for RegExp {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init");
let flag_attributes = Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE;
let get_global = FunctionBuilder::new(context, Self::get_global)
.name("get global")
.constructable(false)
.callable(true)
.build();
let get_ignore_case = FunctionBuilder::new(context, Self::get_ignore_case)
.name("get ignoreCase")
.constructable(false)
.callable(true)
.build();
let get_multiline = FunctionBuilder::new(context, Self::get_multiline)
.name("get multiline")
.constructable(false)
.callable(true)
.build();
let get_dot_all = FunctionBuilder::new(context, Self::get_dot_all)
.name("get dotAll")
.constructable(false)
.callable(true)
.build();
let get_unicode = FunctionBuilder::new(context, Self::get_unicode)
.name("get unicode")
.constructable(false)
.callable(true)
.build();
let get_sticky = FunctionBuilder::new(context, Self::get_sticky)
.name("get sticky")
.constructable(false)
.callable(true)
.build();
let get_flags = FunctionBuilder::new(context, Self::get_flags)
.name("get flags")
.constructable(false)
.callable(true)
.build();
let regexp_object = ConstructorBuilder::with_standard_object(
context,
Self::constructor,
@ -82,6 +120,13 @@ impl BuiltIn for RegExp {
.method(Self::test, "test", 1)
.method(Self::exec, "exec", 1)
.method(Self::to_string, "toString", 0)
.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)
.accessor("dotAll", Some(get_dot_all), None, flag_attributes)
.accessor("unicode", Some(get_unicode), None, flag_attributes)
.accessor("sticky", Some(get_sticky), None, flag_attributes)
.accessor("flags", Some(get_flags), None, flag_attributes)
.build();
// TODO: add them RegExp accessor properties
@ -207,76 +252,191 @@ impl RegExp {
Ok(this)
}
// /// `RegExp.prototype.dotAll`
// ///
// /// The `dotAll` property indicates whether or not the "`s`" flag is used with the regular expression.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.dotAll
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll
// fn get_dot_all(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.dot_all)))
// }
#[inline]
fn regexp_has_flag(this: &Value, flag: char, context: &mut Context) -> Result<Value> {
if let Some(object) = this.as_object() {
if let Some(regexp) = object.borrow().as_regexp() {
return Ok(Value::boolean(match flag {
'g' => regexp.global,
'm' => regexp.multiline,
's' => regexp.dot_all,
'i' => regexp.ignore_case,
'u' => regexp.unicode,
'y' => regexp.sticky,
_ => unreachable!(),
}));
}
if GcObject::equals(
&object,
&context.standard_objects().regexp_object().prototype,
) {
return Ok(Value::undefined());
}
}
let name = match flag {
'g' => "global",
'm' => "multiline",
's' => "dotAll",
'i' => "ignoreCase",
'u' => "unicode",
'y' => "sticky",
_ => unreachable!(),
};
// /// `RegExp.prototype.flags`
// ///
// /// The `flags` property returns a string consisting of the [`flags`][flags] of the current regular expression object.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags
// /// [flags]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2
// fn get_flags(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.flags.clone())))
// }
context.throw_type_error(format!(
"RegExp.prototype.{} getter called on non-RegExp object",
name
))
}
// /// `RegExp.prototype.global`
// ///
// /// The `global` property indicates whether or not the "`g`" flag is used with the regular expression.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.global
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global
// fn get_global(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.global)))
// }
/// `get RegExp.prototype.global`
///
/// The `global` property indicates whether or not the "`g`" flag is used with the regular expression.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.global
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/global
pub(crate) fn get_global(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
Self::regexp_has_flag(this, 'g', context)
}
// /// `RegExp.prototype.ignoreCase`
// ///
// /// The `ignoreCase` property indicates whether or not the "`i`" flag is used with the regular expression.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.ignorecase
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase
// fn get_ignore_case(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.ignore_case)))
// }
/// `get RegExp.prototype.ignoreCase`
///
/// The `ignoreCase` property indicates whether or not the "`i`" flag is used with the regular expression.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.ignorecase
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/ignoreCase
pub(crate) fn get_ignore_case(
this: &Value,
_: &[Value],
context: &mut Context,
) -> Result<Value> {
Self::regexp_has_flag(this, 'i', context)
}
// /// `RegExp.prototype.multiline`
// ///
// /// The multiline property indicates whether or not the "m" flag is used with the regular expression.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.multiline
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline
// fn get_multiline(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.multiline)))
// }
/// `get RegExp.prototype.multiline`
///
/// The multiline property indicates whether or not the "m" flag is used with the regular expression.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.multiline
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/multiline
pub(crate) fn get_multiline(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
Self::regexp_has_flag(this, 'm', context)
}
/// `get RegExp.prototype.dotAll`
///
/// The `dotAll` property indicates whether or not the "`s`" flag is used with the regular expression.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.dotAll
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll
pub(crate) fn get_dot_all(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
Self::regexp_has_flag(this, 's', context)
}
/// `get RegExp.prototype.unicode`
///
/// The unicode property indicates whether or not the "`u`" flag is used with a regular expression.
/// unicode is a read-only property of an individual regular expression instance.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.unicode
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode
pub(crate) fn get_unicode(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
Self::regexp_has_flag(this, 'u', context)
}
/// `get RegExp.prototype.sticky`
///
/// This flag indicates that it matches only from the index indicated by the `lastIndex` property
/// of this regular expression in the target string (and does not attempt to match from any later indexes).
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.sticky
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky
pub(crate) fn get_sticky(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
Self::regexp_has_flag(this, 'y', context)
}
/// `get RegExp.prototype.flags`
///
/// The `flags` property returns a string consisting of the [`flags`][flags] of the current regular expression object.
///
/// More information:
/// - [ECMAScript reference][spec]
/// - [MDN documentation][mdn]
///
/// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags
/// [flags]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Advanced_searching_with_flags_2
pub(crate) fn get_flags(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
if let Some(object) = this.as_object() {
let mut result = String::new();
if object
.get(&"global".into(), this.clone(), context)?
.to_boolean()
{
result.push('g');
}
if object
.get(&"ignoreCase".into(), this.clone(), context)?
.to_boolean()
{
result.push('i');
}
if object
.get(&"multiline".into(), this.clone(), context)?
.to_boolean()
{
result.push('m');
}
if object
.get(&"dotAll".into(), this.clone(), context)?
.to_boolean()
{
result.push('s');
}
if object
.get(&"unicode".into(), this.clone(), context)?
.to_boolean()
{
result.push('u');
}
if object
.get(&"sticky".into(), this.clone(), context)?
.to_boolean()
{
result.push('y');
}
return Ok(result.into());
}
context.throw_type_error("RegExp.prototype.flags getter called on non-object")
}
// /// `RegExp.prototype.source`
// ///
@ -289,39 +449,10 @@ impl RegExp {
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.source
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/source
// fn get_source(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// pub(crate) fn get_source(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// Ok(this.get_internal_slot("OriginalSource"))
// }
// /// `RegExp.prototype.sticky`
// ///
// /// The `flags` property returns a string consisting of the [`flags`][flags] of the current regular expression object.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.sticky
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/sticky
// fn get_sticky(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.sticky)))
// }
// /// `RegExp.prototype.unicode`
// ///
// /// The unicode property indicates whether or not the "`u`" flag is used with a regular expression.
// /// unicode is a read-only property of an individual regular expression instance.
// ///
// /// More information:
// /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn]
// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.unicode
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/unicode
// fn get_unicode(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.unicode)))
// }
/// `RegExp.prototype.test( string )`
///
/// The `test()` method executes a search for a match between a regular expression and a specified string.

Loading…
Cancel
Save