Browse Source

implement string.match(regexp) (#131)

* implement string.match(regexp)
pull/188/head
Victor Tuekam 5 years ago committed by Jason Williams
parent
commit
a93f05cfe1
  1. 19
      src/lib/js/regexp.rs
  2. 51
      src/lib/js/string.rs

19
src/lib/js/regexp.rs

@ -254,6 +254,25 @@ pub fn exec(this: &Value, args: &[Value], _: &mut Interpreter) -> ResultValue {
result 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 /// Return a string representing the regular expression
pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue {
let body = from_value::<String>(this.get_internal_slot("OriginalSource")).map_err(to_value)?; let body = from_value::<String>(this.get_internal_slot("OriginalSource")).map_err(to_value)?;

51
src/lib/js/string.rs

@ -4,6 +4,7 @@ use crate::{
function::NativeFunctionData, function::NativeFunctionData,
object::{Object, ObjectKind, PROTOTYPE}, object::{Object, ObjectKind, PROTOTYPE},
property::Property, property::Property,
regexp::{make_regexp, r#match as regexp_match},
value::{from_value, to_value, ResultValue, Value, ValueData}, 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)) 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.
/// <https://tc39.es/ecma262/#sec-string.prototype.match>
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` /// Abstract method `StringPad`
/// Performs the actual string padding for padStart/End. /// Performs the actual string padding for padStart/End.
/// <https://tc39.es/ecma262/#sec-stringpad/> /// <https://tc39.es/ecma262/#sec-stringpad/>
@ -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("includes", to_value(includes as NativeFunctionData));
proto.set_field_slice("indexOf", to_value(index_of 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("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("padEnd", to_value(pad_end as NativeFunctionData));
proto.set_field_slice("padStart", to_value(pad_start as NativeFunctionData)); proto.set_field_slice("padStart", to_value(pad_start as NativeFunctionData));
proto.set_field_slice("trim", to_value(trim 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, "enLiteral.endsWith('h')"), pass);
assert_eq!(forward(&mut engine, "zhLiteral.endsWith('文')"), 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");
}
} }

Loading…
Cancel
Save