# HG changeset patch # Parent af4f2eea4e27d92decb28b8205884219a0a38cd7 # User ziyunfei <446240525@qq.com> Bug 1108467 - Implement RegExp.prototype.flags. r=till diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -366,16 +366,82 @@ regexp_toString_impl(JSContext *cx, Call static bool regexp_toString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); return CallNonGenericMethod(cx, args); } +/* ES6 draft rev29 21.2.5.3 RegExp.prototype.flags */ +bool +regexp_flags(JSContext *cx, unsigned argc, JS::Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + /* Steps 1-2. */ + if (!args.thisv().isObject()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.thisv(), NullPtr()); + if (!bytes) + return false; + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNEXPECTED_TYPE, + bytes, "not an object"); + js_free(bytes); + return false; + } + RootedObject thisObj(cx, &args.thisv().toObject()); + + /* Step 3. */ + StringBuffer sb(cx); + + /* Steps 4-6. */ + RootedValue global(cx); + if (!JSObject::getProperty(cx, thisObj, thisObj, cx->names().global, &global)) + return false; + if (ToBoolean(global) && !sb.append('g')) + return false; + + /* Steps 7-9. */ + RootedValue ignoreCase(cx); + if (!JSObject::getProperty(cx, thisObj, thisObj, cx->names().ignoreCase, &ignoreCase)) + return false; + if (ToBoolean(ignoreCase) && !sb.append('i')) + return false; + + /* Steps 10-12. */ + RootedValue multiline(cx); + if (!JSObject::getProperty(cx, thisObj, thisObj, cx->names().multiline, &multiline)) + return false; + if (ToBoolean(multiline) && !sb.append('m')) + return false; + + /* Steps 13-15. */ + RootedValue sticky(cx); + if (!JSObject::getProperty(cx, thisObj, thisObj, cx->names().sticky, &sticky)) + return false; + if (ToBoolean(sticky) && !sb.append('y')) + return false; + + /* Steps 16-18. */ + RootedValue unicode(cx); + if (!JSObject::getProperty(cx, thisObj, thisObj, cx->names().unicode, &unicode)) + return false; + if (ToBoolean(unicode) && !sb.append('u')) + return false; + + /* Step 19. */ + args.rval().setString(sb.finishString()); + return true; +} + +static const JSPropertySpec regexp_properties[] = { + JS_PSG("flags", regexp_flags, 0), + JS_PS_END +}; + static const JSFunctionSpec regexp_methods[] = { #if JS_HAS_TOSOURCE JS_FN(js_toSource_str, regexp_toString, 0,0), #endif JS_FN(js_toString_str, regexp_toString, 0,0), JS_FN("compile", regexp_compile, 2,0), JS_FN("exec", regexp_exec, 1,0), JS_FN("test", regexp_test, 1,0), @@ -512,17 +578,17 @@ js_InitRegExpClass(JSContext *cx, Handle return nullptr; proto->NativeObject::setPrivate(nullptr); HandlePropertyName empty = cx->names().empty; RegExpObjectBuilder builder(cx, proto); if (!builder.build(empty, RegExpFlag(0))) return nullptr; - if (!DefinePropertiesAndFunctions(cx, proto, nullptr, regexp_methods)) + if (!DefinePropertiesAndFunctions(cx, proto, regexp_properties, regexp_methods)) return nullptr; RootedFunction ctor(cx); ctor = global->createConstructor(cx, regexp_construct, cx->names().RegExp, 2); if (!ctor) return nullptr; if (!LinkConstructorAndPrototype(cx, ctor, proto)) diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -7,16 +7,19 @@ #ifndef builtin_RegExp_h #define builtin_RegExp_h #include "vm/RegExpObject.h" JSObject * js_InitRegExpClass(JSContext *cx, js::HandleObject obj); +bool +regexp_flags(JSContext *cx, unsigned argc, JS::Value *vp); + /* * The following builtin natives are extern'd for pointer comparison in * other parts of the engine. */ namespace js { // Whether RegExp statics should be updated with the input and results of a diff --git a/js/src/tests/ecma_6/RegExp/browser.js b/js/src/tests/ecma_6/RegExp/browser.js new file mode 100644 diff --git a/js/src/tests/ecma_6/RegExp/flags.js b/js/src/tests/ecma_6/RegExp/flags.js new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/RegExp/flags.js @@ -0,0 +1,28 @@ +var BUGNUMBER = 1108467; +var summary = "Implement RegExp.prototype.flags"; + +print(BUGNUMBER + ": " + summary); + +assertEq(RegExp.prototype.flags, ""); +assertEq(/foo/iymg.flags, "gimy"); +assertEq(RegExp("").flags, ""); +assertEq(RegExp("", "mygi").flags, "gimy"); +assertThrowsInstanceOf(() => RegExp("", "mygui").flags, SyntaxError); +// When the /u flag is supported, uncomment the line below and remove the line above +// assertEq(RegExp("", "mygui").flags, "gimyu"); +assertEq(genericFlags({}), ""); +assertEq(genericFlags({ignoreCase: true}), "i"); +assertEq(genericFlags({sticky:1, unicode:1, global: 0}), "yu"); +assertEq(genericFlags({__proto__: {multiline: true}}), "m"); +assertEq(genericFlags(new Proxy({}, {get(){return true}})), "gimyu"); + +assertThrowsInstanceOf(() => genericFlags(), TypeError); +assertThrowsInstanceOf(() => genericFlags(1), TypeError); +assertThrowsInstanceOf(() => genericFlags(""), TypeError); + +function genericFlags(obj) { + return Object.getOwnPropertyDescriptor(RegExp.prototype,"flags").get.call(obj); +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/RegExp/shell.js b/js/src/tests/ecma_6/RegExp/shell.js new file mode 100644 diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -191,16 +191,17 @@ macro(toJSON, toJSON, "toJSON") \ macro(toLocaleString, toLocaleString, "toLocaleString") \ macro(toSource, toSource, "toSource") \ macro(toString, toString, "toString") \ macro(toUTCString, toUTCString, "toUTCString") \ macro(true, true_, "true") \ macro(unescape, unescape, "unescape") \ macro(uneval, uneval, "uneval") \ + macro(unicode, unicode, "unicode") \ macro(uninitialized, uninitialized, "uninitialized") \ macro(uint8, uint8, "uint8") \ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \ macro(uint16, uint16, "uint16") \ macro(uint32, uint32, "uint32") \ macro(unsized, unsized, "unsized") \ macro(unwatch, unwatch, "unwatch") \ macro(url, url, "url") \