From a93f05cfe1fbf54680b8357dc497c875728a9b02 Mon Sep 17 00:00:00 2001 From: Victor Tuekam <19honor@gmail.com> Date: Wed, 16 Oct 2019 00:09:53 +0200 Subject: [PATCH] implement string.match(regexp) (#131) * implement string.match(regexp) --- src/lib/js/regexp.rs | 19 +++++++++++++++++ src/lib/js/string.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/lib/js/regexp.rs b/src/lib/js/regexp.rs index f73263653f..cf1ee8c6d3 100644 --- a/src/lib/js/regexp.rs +++ b/src/lib/js/regexp.rs @@ -254,6 +254,25 @@ pub fn exec(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue { result } +/// RegExp.prototype[Symbol.match] +/// Returns matches of the regular expression against a string +pub fn r#match(this: &Value, arg: String, ctx: &mut Interpreter) -> ResultValue { + let (matcher, flags) = + this.with_internal_state_ref(|regex: &RegExp| (regex.matcher.clone(), regex.flags.clone())); + if flags.contains('g') { + let mut matches = Vec::new(); + for mat in matcher.find_iter(&arg) { + matches.push(to_value(mat.as_str())); + } + if matches.is_empty() { + return Ok(Gc::new(ValueData::Null)); + } + Ok(to_value(matches)) + } else { + exec(this, &[to_value(arg)], ctx) + } +} + /// Return a string representing the regular expression pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { let body = from_value::(this.get_internal_slot("OriginalSource")).map_err(to_value)?; diff --git a/src/lib/js/string.rs b/src/lib/js/string.rs index a325d7670f..b07d8ae989 100644 --- a/src/lib/js/string.rs +++ b/src/lib/js/string.rs @@ -4,6 +4,7 @@ use crate::{ function::NativeFunctionData, object::{Object, ObjectKind, PROTOTYPE}, property::Property, + regexp::{make_regexp, r#match as regexp_match}, value::{from_value, to_value, ResultValue, Value, ValueData}, }, }; @@ -422,6 +423,15 @@ pub fn last_index_of(this: &Value, args: &[Value], ctx: &mut Interpreter) -> Res Ok(to_value(highest_index)) } +/// Returns an array whose contents is all the results matching the regular expression, if the global (g) flag is present, +/// in its absence, only the first complete match and its related capturing groups is returned, +/// otherwise null is returned if no match is found. +/// +pub fn r#match(this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { + let re = make_regexp(&to_value(Object::default()), &[args[0].clone()], ctx)?.clone(); + regexp_match(&re, ctx.value_to_rust_string(this), ctx) +} + /// Abstract method `StringPad` /// Performs the actual string padding for padStart/End. /// @@ -709,6 +719,7 @@ pub fn create_constructor(global: &Value) -> Value { proto.set_field_slice("includes", to_value(includes as NativeFunctionData)); proto.set_field_slice("indexOf", to_value(index_of as NativeFunctionData)); proto.set_field_slice("lastIndexOf", to_value(last_index_of as NativeFunctionData)); + proto.set_field_slice("match", to_value(r#match as NativeFunctionData)); proto.set_field_slice("padEnd", to_value(pad_end as NativeFunctionData)); proto.set_field_slice("padStart", to_value(pad_start as NativeFunctionData)); proto.set_field_slice("trim", to_value(trim as NativeFunctionData)); @@ -879,4 +890,44 @@ mod tests { assert_eq!(forward(&mut engine, "enLiteral.endsWith('h')"), pass); assert_eq!(forward(&mut engine, "zhLiteral.endsWith('文')"), pass); } + #[test] + fn test_match() { + let realm = Realm::create(); + let mut engine = Executor::new(realm); + let init = r#" + var str = new String('The Quick Brown Fox Jumps Over The Lazy Dog'); + var result1 = str.match(/quick\s(brown).+?(jumps)/i); + var result2 = str.match(/[A-Z]/g); + var result3 = str.match("T"); + var result4 = str.match(RegExp("B", 'g')); + "#; + + forward(&mut engine, init); + assert_eq!(forward(&mut engine, "result1[0]"), "Quick Brown Fox Jumps"); + assert_eq!(forward(&mut engine, "result1[1]"), "Brown"); + assert_eq!(forward(&mut engine, "result1[2]"), "Jumps"); + assert_eq!(forward(&mut engine, "result1.index"), "4"); + assert_eq!( + forward(&mut engine, "result1.input"), + "The Quick Brown Fox Jumps Over The Lazy Dog" + ); + + assert_eq!(forward(&mut engine, "result2[0]"), "T"); + assert_eq!(forward(&mut engine, "result2[1]"), "Q"); + assert_eq!(forward(&mut engine, "result2[2]"), "B"); + assert_eq!(forward(&mut engine, "result2[3]"), "F"); + assert_eq!(forward(&mut engine, "result2[4]"), "J"); + assert_eq!(forward(&mut engine, "result2[5]"), "O"); + assert_eq!(forward(&mut engine, "result2[6]"), "T"); + assert_eq!(forward(&mut engine, "result2[7]"), "L"); + assert_eq!(forward(&mut engine, "result2[8]"), "D"); + + assert_eq!(forward(&mut engine, "result3[0]"), "T"); + assert_eq!(forward(&mut engine, "result3.index"), "0"); + assert_eq!( + forward(&mut engine, "result3.input"), + "The Quick Brown Fox Jumps Over The Lazy Dog" + ); + assert_eq!(forward(&mut engine, "result4[0]"), "B"); + } }