From 3d3ba28b4b0cbb250a8b572f636f9c0bc700875a Mon Sep 17 00:00:00 2001 From: nd419 <5161147+neeldug@users.noreply.github.com> Date: Tue, 29 Jun 2021 21:49:43 +0100 Subject: [PATCH 1/4] fix(boa): match and regexp construct fixes - match method adheres to spec - regexp method simplified to follow spec Closes #13 --- boa/src/builtins/regexp/mod.rs | 28 +++++++----------------- boa/src/builtins/string/mod.rs | 39 ++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 8043c68304f..45028aa1b05 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -183,26 +183,14 @@ impl RegExp { let arg = args.get(0).ok_or_else(Value::undefined)?; let (regex_body, mut regex_flags) = match arg { - Value::String(ref body) => { - // first argument is a string -> use it as regex pattern - ( - body.to_string().into_boxed_str(), - String::new().into_boxed_str(), - ) - } - Value::Object(ref obj) => { - let obj = obj.borrow(); - if let Some(regex) = obj.as_regexp() { - // first argument is another `RegExp` object, so copy its pattern and flags - (regex.original_source.clone(), regex.original_flags.clone()) - } else { - ( - String::new().into_boxed_str(), - String::new().into_boxed_str(), - ) - } - } - _ => return Err(Value::undefined()), + Value::Undefined => ( + String::new().into_boxed_str(), + String::new().into_boxed_str(), + ), + _ => ( + arg.to_string(ctx)?.to_string().into_boxed_str(), + String::new().into_boxed_str(), + ), }; // if a second argument is given and it's a string, use it as flags if let Some(Value::String(flags)) = args.get(1) { diff --git a/boa/src/builtins/string/mod.rs b/boa/src/builtins/string/mod.rs index b2ee8972e0f..910f3a3f9eb 100644 --- a/boa/src/builtins/string/mod.rs +++ b/boa/src/builtins/string/mod.rs @@ -894,12 +894,39 @@ impl String { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match /// [regex]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions pub(crate) fn r#match(this: &Value, args: &[Value], context: &mut Context) -> Result { - let re = RegExp::constructor( - &Value::from(Object::default()), - &[args.get(0).cloned().unwrap_or_default()], - context, - )?; - RegExp::r#match(&re, this.to_string(context)?, context) + // 1. Let O be ? RequireObjectCoercible(this value). + let this = this.require_object_coercible(context)?; + let regexp = args.get(0).cloned().unwrap_or_default(); + // 2. If regexp is neither undefined nor null, then + if !regexp.is_null_or_undefined() { + // a. Let matcher be ? GetMethod(regexp, @@match). + // b. If matcher is not undefined, then + if let Some(matcher) = regexp + .to_object(context)? + .get_method(context, WellKnownSymbols::match_())? + { + // i. Return ? Call(matcher, regexp, « O »). + return matcher.call(®exp, &[this.clone()], context); + } + } + + // 3. Let S be ? ToString(O). + let s = this.to_string(context)?; + + // 4. Let rx be ? RegExpCreate(regexp, undefined). + let rx = RegExp::constructor(&Value::from(Object::default()), &[regexp], context)?; + + // 5. Return ? Invoke(rx, @@search, « string »). + // todo: work out why below doesn't work + // if let Some(matcher) = rx + // .to_object(context)? + // .get_method(context, WellKnownSymbols::match_())? + // { + // matcher.call(&rx, &[Value::from(s)], context) + // } else { + // context.throw_type_error("regexp[Symbol.match] is not a function") + // } + RegExp::r#match(&rx, s, context) } /// Abstract method `StringPad`. From 4e28a22f67dfa699afd8b1e1bcd31897a3042b96 Mon Sep 17 00:00:00 2001 From: nd419 <5161147+neeldug@users.noreply.github.com> Date: Tue, 29 Jun 2021 21:57:05 +0100 Subject: [PATCH 2/4] cleanup --- boa/src/builtins/regexp/mod.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 45028aa1b05..c38013aec47 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -182,20 +182,16 @@ impl RegExp { .set_prototype_instance(prototype.into()); let arg = args.get(0).ok_or_else(Value::undefined)?; - let (regex_body, mut regex_flags) = match arg { - Value::Undefined => ( - String::new().into_boxed_str(), - String::new().into_boxed_str(), - ), - _ => ( - arg.to_string(ctx)?.to_string().into_boxed_str(), - String::new().into_boxed_str(), - ), + let regex_body = match arg { + Value::Undefined => String::new().into_boxed_str(), + _ => arg.to_string(ctx)?.to_string().into_boxed_str(), }; // if a second argument is given and it's a string, use it as flags - if let Some(Value::String(flags)) = args.get(1) { - regex_flags = flags.to_string().into_boxed_str(); - } + let regex_flags = if let Some(Value::String(flags)) = args.get(1) { + flags.to_string().into_boxed_str() + } else { + String::new().into_boxed_str() + }; // parse flags let mut sorted_flags = String::new(); From 5dea6a2073984701a656a7a43daade817263af89 Mon Sep 17 00:00:00 2001 From: nd419 <5161147+neeldug@users.noreply.github.com> Date: Tue, 29 Jun 2021 22:04:14 +0100 Subject: [PATCH 3/4] revert to regex filter on construct --- boa/src/builtins/regexp/mod.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index c38013aec47..562c31ff1ed 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -182,16 +182,23 @@ impl RegExp { .set_prototype_instance(prototype.into()); let arg = args.get(0).ok_or_else(Value::undefined)?; - let regex_body = match arg { - Value::Undefined => String::new().into_boxed_str(), - _ => arg.to_string(ctx)?.to_string().into_boxed_str(), + let (regex_body, mut regex_flags) = match arg { + Value::Undefined => (String::new().into_boxed_str(), String::new().into_boxed_str()), + Value::Object(ref obj) => { + let obj = obj.borrow(); + if let Some(regex) = obj.as_regexp() { + // first argument is another `RegExp` object, so copy its pattern and flags + (regex.original_source.clone(), regex.original_flags.clone()) + } else { + (arg.to_string(ctx)?.to_string().into_boxed_str(), String::new().into_boxed_str()) + } + }, + _ => (arg.to_string(ctx)?.to_string().into_boxed_str(), String::new().into_boxed_str()), }; // if a second argument is given and it's a string, use it as flags - let regex_flags = if let Some(Value::String(flags)) = args.get(1) { - flags.to_string().into_boxed_str() - } else { - String::new().into_boxed_str() - }; + if let Some(Value::String(flags)) = args.get(1) { + regex_flags = flags.to_string().into_boxed_str(); + } // parse flags let mut sorted_flags = String::new(); From 990db322a987d98524bea323faa73c8832e85583 Mon Sep 17 00:00:00 2001 From: nd419 <5161147+neeldug@users.noreply.github.com> Date: Tue, 29 Jun 2021 22:07:16 +0100 Subject: [PATCH 4/4] fmt --- boa/src/builtins/regexp/mod.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 562c31ff1ed..e475798b4c2 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -183,17 +183,26 @@ impl RegExp { let arg = args.get(0).ok_or_else(Value::undefined)?; let (regex_body, mut regex_flags) = match arg { - Value::Undefined => (String::new().into_boxed_str(), String::new().into_boxed_str()), + Value::Undefined => ( + String::new().into_boxed_str(), + String::new().into_boxed_str(), + ), Value::Object(ref obj) => { let obj = obj.borrow(); if let Some(regex) = obj.as_regexp() { // first argument is another `RegExp` object, so copy its pattern and flags (regex.original_source.clone(), regex.original_flags.clone()) } else { - (arg.to_string(ctx)?.to_string().into_boxed_str(), String::new().into_boxed_str()) + ( + arg.to_string(ctx)?.to_string().into_boxed_str(), + String::new().into_boxed_str(), + ) } - }, - _ => (arg.to_string(ctx)?.to_string().into_boxed_str(), String::new().into_boxed_str()), + } + _ => ( + arg.to_string(ctx)?.to_string().into_boxed_str(), + String::new().into_boxed_str(), + ), }; // if a second argument is given and it's a string, use it as flags if let Some(Value::String(flags)) = args.get(1) {