Browse Source

Implement RegExp flag accessors (#1221)

pull/1236/head
Halid Odat 4 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::{ use crate::{
builtins::BuiltIn, builtins::BuiltIn,
gc::{empty_trace, Finalize, Trace}, gc::{empty_trace, Finalize, Trace},
object::{ConstructorBuilder, ObjectData, PROTOTYPE}, object::{ConstructorBuilder, FunctionBuilder, GcObject, ObjectData, PROTOTYPE},
property::{Attribute, DataDescriptor}, property::{Attribute, DataDescriptor},
value::{RcString, Value}, value::{RcString, Value},
BoaProfiler, Context, Result, BoaProfiler, Context, Result,
@ -71,6 +71,44 @@ impl BuiltIn for RegExp {
fn init(context: &mut Context) -> (&'static str, Value, Attribute) { fn init(context: &mut Context) -> (&'static str, Value, Attribute) {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); 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( let regexp_object = ConstructorBuilder::with_standard_object(
context, context,
Self::constructor, Self::constructor,
@ -82,6 +120,13 @@ 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)
.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(); .build();
// TODO: add them RegExp accessor properties // TODO: add them RegExp accessor properties
@ -207,76 +252,191 @@ impl RegExp {
Ok(this) Ok(this)
} }
// /// `RegExp.prototype.dotAll` #[inline]
// /// fn regexp_has_flag(this: &Value, flag: char, context: &mut Context) -> Result<Value> {
// /// The `dotAll` property indicates whether or not the "`s`" flag is used with the regular expression. if let Some(object) = this.as_object() {
// /// if let Some(regexp) = object.borrow().as_regexp() {
// /// More information: return Ok(Value::boolean(match flag {
// /// - [ECMAScript reference][spec] 'g' => regexp.global,
// /// - [MDN documentation][mdn] 'm' => regexp.multiline,
// /// 's' => regexp.dot_all,
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.dotAll 'i' => regexp.ignore_case,
// /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/dotAll 'u' => regexp.unicode,
// fn get_dot_all(this: &Value, _: &[Value], _: &mut Context) -> Result<Value> { 'y' => regexp.sticky,
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.dot_all))) _ => 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` context.throw_type_error(format!(
// /// "RegExp.prototype.{} getter called on non-RegExp object",
// /// The `flags` property returns a string consisting of the [`flags`][flags] of the current regular expression object. name
// /// ))
// /// 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())))
// }
// /// `RegExp.prototype.global` /// `get RegExp.prototype.global`
// /// ///
// /// The `global` property indicates whether or not the "`g`" flag is used with the regular expression. /// The `global` property indicates whether or not the "`g`" flag is used with the regular expression.
// /// ///
// /// More information: /// More information:
// /// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn] /// - [MDN documentation][mdn]
// /// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.global /// [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 /// [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> { pub(crate) fn get_global(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.global))) Self::regexp_has_flag(this, 'g', context)
// } }
// /// `RegExp.prototype.ignoreCase` /// `get RegExp.prototype.ignoreCase`
// /// ///
// /// The `ignoreCase` property indicates whether or not the "`i`" flag is used with the regular expression. /// The `ignoreCase` property indicates whether or not the "`i`" flag is used with the regular expression.
// /// ///
// /// More information: /// More information:
// /// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn] /// - [MDN documentation][mdn]
// /// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.ignorecase /// [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 /// [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> { pub(crate) fn get_ignore_case(
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.ignore_case))) this: &Value,
// } _: &[Value],
context: &mut Context,
) -> Result<Value> {
Self::regexp_has_flag(this, 'i', context)
}
// /// `RegExp.prototype.multiline` /// `get RegExp.prototype.multiline`
// /// ///
// /// The multiline property indicates whether or not the "m" flag is used with the regular expression. /// The multiline property indicates whether or not the "m" flag is used with the regular expression.
// /// ///
// /// More information: /// More information:
// /// - [ECMAScript reference][spec] /// - [ECMAScript reference][spec]
// /// - [MDN documentation][mdn] /// - [MDN documentation][mdn]
// /// ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.multiline /// [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 /// [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> { pub(crate) fn get_multiline(this: &Value, _: &[Value], context: &mut Context) -> Result<Value> {
// this.with_internal_state_ref(|regex: &RegExp| Ok(Value::from(regex.multiline))) 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` // /// `RegExp.prototype.source`
// /// // ///
@ -289,39 +449,10 @@ impl RegExp {
// /// // ///
// /// [spec]: https://tc39.es/ecma262/#sec-get-regexp.prototype.source // /// [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 // /// [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")) // 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 )` /// `RegExp.prototype.test( string )`
/// ///
/// The `test()` method executes a search for a match between a regular expression and a specified string. /// The `test()` method executes a search for a match between a regular expression and a specified string.

Loading…
Cancel
Save