mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 15:58:39 +09:00
Issue #2305 Part 1: Add support for hasIndices to RegExpFlags (/d)
Adds recognition and parsing of the /d RegExp flag. Drive-by correction: add missing "s" for dotAll to RegExpObject::toString. Tag #1284 and #2008
This commit is contained in:
parent
9ba1057e54
commit
47ef1701b3
9 changed files with 99 additions and 35 deletions
|
|
@ -818,15 +818,42 @@ js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
|
|||
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_unicode_impl>(cx, args);
|
||||
}
|
||||
|
||||
// ES 2022 22.2.5.6.
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
regexp_hasIndices_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
|
||||
|
||||
// Step 2.a.
|
||||
if (!IsRegExpObject(args.thisv())) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Steps 3-5.
|
||||
Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
|
||||
args.rval().setBoolean(reObj->hasIndices());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
// Steps 1-3.
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_hasIndices_impl>(cx, args);
|
||||
}
|
||||
|
||||
const JSPropertySpec js::regexp_properties[] = {
|
||||
JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
|
||||
JS_PSG("hasIndices", regexp_hasIndices, 0),
|
||||
JS_PSG("global", regexp_global, 0),
|
||||
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
|
||||
JS_PSG("multiline", regexp_multiline, 0),
|
||||
JS_PSG("dotAll", regexp_dotAll, 0),
|
||||
JS_PSG("source", regexp_source, 0),
|
||||
JS_PSG("sticky", regexp_sticky, 0),
|
||||
JS_PSG("unicode", regexp_unicode, 0),
|
||||
JS_PSG("dotAll", regexp_dotAll, 0),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
|
@ -1802,6 +1829,13 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
|
|||
if (!IsSelfHostedFunctionWithName(flagsGetter, cx->names().RegExpFlagsGetter))
|
||||
return false;
|
||||
|
||||
JSNative hasIndicesGetter;
|
||||
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().hasIndices), &hasIndicesGetter))
|
||||
return false;
|
||||
|
||||
if (hasIndicesGetter != regexp_hasIndices)
|
||||
return false;
|
||||
|
||||
JSNative globalGetter;
|
||||
if (!GetOwnNativeGetterPure(cx, proto, NameToId(cx->names().global), &globalGetter))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -124,17 +124,19 @@ extern const JSFunctionSpec regexp_methods[];
|
|||
|
||||
// Used in RegExpObject::isOriginalFlagGetter.
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_hasIndices(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_global(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_dotAll(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
extern MOZ_MUST_USE bool
|
||||
regexp_dotAll(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags
|
||||
// Updated for ES2018 /s (dotAll)
|
||||
// ES2022 22.2.5.4 get RegExp.prototype.flags
|
||||
function RegExpFlagsGetter() {
|
||||
// Steps 1-2.
|
||||
var R = this;
|
||||
|
|
@ -13,31 +12,36 @@ function RegExpFlagsGetter() {
|
|||
// Step 3.
|
||||
var result = "";
|
||||
|
||||
// Steps 4-6.
|
||||
// Steps 4-5.
|
||||
if (R.hasIndices)
|
||||
result += "d";
|
||||
|
||||
// Steps 6-7.
|
||||
if (R.global)
|
||||
result += "g";
|
||||
|
||||
// Steps 7-9.
|
||||
// Steps 8-9.
|
||||
if (R.ignoreCase)
|
||||
result += "i";
|
||||
|
||||
// Steps 10-12.
|
||||
// Steps 10-11.
|
||||
if (R.multiline)
|
||||
result += "m";
|
||||
|
||||
// Steps 13-15.
|
||||
if (R.unicode)
|
||||
result += "u";
|
||||
|
||||
// Steps 16-18.
|
||||
if (R.sticky)
|
||||
result += "y";
|
||||
|
||||
// ES2018
|
||||
// Steps 12-13.
|
||||
if (R.dotAll)
|
||||
result += "s";
|
||||
|
||||
// Step 19.
|
||||
// Steps 14-15.
|
||||
if (R.unicode)
|
||||
result += "u";
|
||||
|
||||
// Steps 16-17.
|
||||
if (R.sticky)
|
||||
result += "y";
|
||||
|
||||
|
||||
// Step 18.
|
||||
return result;
|
||||
}
|
||||
_SetCanonicalName(RegExpFlagsGetter, "get flags");
|
||||
|
|
@ -227,9 +231,11 @@ function RegExpGlobalMatchOpt(rx, S, fullUnicode) {
|
|||
// Checks if following properties and getters are not modified, and accessing
|
||||
// them not observed by content script:
|
||||
// * flags
|
||||
// * hasIndices
|
||||
// * global
|
||||
// * ignoreCase
|
||||
// * multiline
|
||||
// * dotAll
|
||||
// * sticky
|
||||
// * unicode
|
||||
// * exec
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@
|
|||
#define REGEXP_STICKY_FLAG 0x08
|
||||
#define REGEXP_UNICODE_FLAG 0x10
|
||||
#define REGEXP_DOTALL_FLAG 0x20
|
||||
#define REGEXP_HASINDICES_FLAG 0x40
|
||||
|
||||
#define REGEXP_STRING_ITERATOR_REGEXP_SLOT 0
|
||||
#define REGEXP_STRING_ITERATOR_STRING_SLOT 1
|
||||
|
|
|
|||
|
|
@ -2083,7 +2083,9 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
|||
while (true) {
|
||||
if (!peekChar(&c))
|
||||
goto error;
|
||||
if (c == 'g' && !(reflags & GlobalFlag))
|
||||
if (c == 'd' && !(reflags & HasIndicesFlag))
|
||||
reflags = RegExpFlag(reflags | HasIndicesFlag);
|
||||
else if (c == 'g' && !(reflags & GlobalFlag))
|
||||
reflags = RegExpFlag(reflags | GlobalFlag);
|
||||
else if (c == 'i' && !(reflags & IgnoreCaseFlag))
|
||||
reflags = RegExpFlag(reflags | IgnoreCaseFlag);
|
||||
|
|
|
|||
|
|
@ -5824,12 +5824,13 @@ JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate);
|
|||
/*
|
||||
* Regular Expressions.
|
||||
*/
|
||||
#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */
|
||||
#define JSREG_GLOB 0x02u /* global exec, creates array of matches */
|
||||
#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */
|
||||
#define JSREG_STICKY 0x08u /* only match starting at lastIndex */
|
||||
#define JSREG_UNICODE 0x10u /* unicode */
|
||||
#define JSREG_DOTALL 0x20u /* match . to everything including newlines */
|
||||
#define JSREG_FOLD 0x01u /* fold uppercase to lowercase */
|
||||
#define JSREG_GLOB 0x02u /* global exec, creates array of matches */
|
||||
#define JSREG_MULTILINE 0x04u /* treat ^ and $ as begin and end of line */
|
||||
#define JSREG_STICKY 0x08u /* only match starting at lastIndex */
|
||||
#define JSREG_UNICODE 0x10u /* unicode */
|
||||
#define JSREG_DOTALL 0x20u /* match . to everything including newlines */
|
||||
#define JSREG_HASINDICES 0x40u /* add .indices property to the match result */
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_NewRegExpObject(JSContext* cx, const char* bytes, size_t length, unsigned flags);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,7 @@
|
|||
macro(groups, groups, "groups") \
|
||||
macro(Handle, Handle, "Handle") \
|
||||
macro(has, has, "has") \
|
||||
macro(hasIndices, hasIndices, "hasIndices") \
|
||||
macro(hasOwn, hasOwn, "hasOwn") \
|
||||
macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
|
||||
macro(highWaterMark, highWaterMark, "highWaterMark") \
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ JS_STATIC_ASSERT(MultilineFlag == JSREG_MULTILINE);
|
|||
JS_STATIC_ASSERT(StickyFlag == JSREG_STICKY);
|
||||
JS_STATIC_ASSERT(UnicodeFlag == JSREG_UNICODE);
|
||||
JS_STATIC_ASSERT(DotAllFlag == JSREG_DOTALL);
|
||||
JS_STATIC_ASSERT(HasIndicesFlag == JSREG_HASINDICES);
|
||||
|
||||
RegExpObject*
|
||||
js::RegExpAlloc(ExclusiveContext* cx, HandleObject proto /* = nullptr */)
|
||||
|
|
@ -136,6 +137,10 @@ RegExpObject::getShared(JSContext* cx, Handle<RegExpObject*> regexp,
|
|||
/* static */ bool
|
||||
RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
||||
{
|
||||
if (native == regexp_hasIndices) {
|
||||
*mask = HasIndicesFlag;
|
||||
return true;
|
||||
}
|
||||
if (native == regexp_global) {
|
||||
*mask = GlobalFlag;
|
||||
return true;
|
||||
|
|
@ -148,6 +153,10 @@ RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
|||
*mask = MultilineFlag;
|
||||
return true;
|
||||
}
|
||||
if (native == regexp_dotAll) {
|
||||
*mask = DotAllFlag;
|
||||
return true;
|
||||
}
|
||||
if (native == regexp_sticky) {
|
||||
*mask = StickyFlag;
|
||||
return true;
|
||||
|
|
@ -156,10 +165,6 @@ RegExpObject::isOriginalFlagGetter(JSNative native, RegExpFlag* mask)
|
|||
*mask = UnicodeFlag;
|
||||
return true;
|
||||
}
|
||||
if (native == regexp_dotAll) {
|
||||
*mask = DotAllFlag;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -488,12 +493,16 @@ RegExpObject::toString(JSContext* cx) const
|
|||
sb.infallibleAppend('/');
|
||||
|
||||
// Steps 5-7.
|
||||
if (hasIndices() && !sb.append('d'))
|
||||
return nullptr;
|
||||
if (global() && !sb.append('g'))
|
||||
return nullptr;
|
||||
if (ignoreCase() && !sb.append('i'))
|
||||
return nullptr;
|
||||
if (multiline() && !sb.append('m'))
|
||||
return nullptr;
|
||||
if (dotAll() && !sb.append('s'))
|
||||
return nullptr;
|
||||
if (unicode() && !sb.append('u'))
|
||||
return nullptr;
|
||||
if (sticky() && !sb.append('y'))
|
||||
|
|
@ -1483,14 +1492,18 @@ ParseRegExpFlags(const CharT* chars, size_t length, RegExpFlag* flagsOut, char16
|
|||
for (size_t i = 0; i < length; i++) {
|
||||
*lastParsedOut = chars[i];
|
||||
switch (chars[i]) {
|
||||
case 'i':
|
||||
if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
|
||||
case 'd':
|
||||
if (!HandleRegExpFlag(HasIndicesFlag, flagsOut))
|
||||
return false;
|
||||
break;
|
||||
case 'g':
|
||||
if (!HandleRegExpFlag(GlobalFlag, flagsOut))
|
||||
return false;
|
||||
break;
|
||||
case 'i':
|
||||
if (!HandleRegExpFlag(IgnoreCaseFlag, flagsOut))
|
||||
return false;
|
||||
break;
|
||||
case 'm':
|
||||
if (!HandleRegExpFlag(MultilineFlag, flagsOut))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ enum RegExpFlag : uint8_t
|
|||
StickyFlag = 0x08,
|
||||
UnicodeFlag = 0x10,
|
||||
DotAllFlag = 0x20,
|
||||
HasIndicesFlag = 0x40,
|
||||
|
||||
NoFlags = 0x00,
|
||||
AllFlags = 0x3f
|
||||
AllFlags = 0x7f
|
||||
};
|
||||
|
||||
static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
|
||||
|
|
@ -66,7 +67,8 @@ static_assert(IgnoreCaseFlag == REGEXP_IGNORECASE_FLAG &&
|
|||
MultilineFlag == REGEXP_MULTILINE_FLAG &&
|
||||
StickyFlag == REGEXP_STICKY_FLAG &&
|
||||
UnicodeFlag == REGEXP_UNICODE_FLAG &&
|
||||
DotAllFlag == REGEXP_DOTALL_FLAG,
|
||||
DotAllFlag == REGEXP_DOTALL_FLAG &&
|
||||
HasIndicesFlag == REGEXP_HASINDICES_FLAG,
|
||||
"Flag values should be in sync with self-hosted JS");
|
||||
|
||||
enum RegExpRunStatus
|
||||
|
|
@ -206,12 +208,13 @@ class RegExpShared : public gc::TenuredCell
|
|||
|
||||
JSAtom* getSource() const { return source; }
|
||||
RegExpFlag getFlags() const { return flags; }
|
||||
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
|
||||
bool hasIndices() const { return flags & HasIndicesFlag; }
|
||||
bool global() const { return flags & GlobalFlag; }
|
||||
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
|
||||
bool multiline() const { return flags & MultilineFlag; }
|
||||
bool sticky() const { return flags & StickyFlag; }
|
||||
bool unicode() const { return flags & UnicodeFlag; }
|
||||
bool dotAll() const { return flags & DotAllFlag; }
|
||||
bool unicode() const { return flags & UnicodeFlag; }
|
||||
bool sticky() const { return flags & StickyFlag; }
|
||||
|
||||
bool isCompiled(CompilationMode mode, bool latin1,
|
||||
ForceByteCodeEnum force = DontForceByteCode) const {
|
||||
|
|
@ -451,12 +454,13 @@ class RegExpObject : public NativeObject
|
|||
setSlot(FLAGS_SLOT, Int32Value(flags));
|
||||
}
|
||||
|
||||
bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
|
||||
bool hasIndices() const { return getFlags() & HasIndicesFlag; }
|
||||
bool global() const { return getFlags() & GlobalFlag; }
|
||||
bool ignoreCase() const { return getFlags() & IgnoreCaseFlag; }
|
||||
bool multiline() const { return getFlags() & MultilineFlag; }
|
||||
bool sticky() const { return getFlags() & StickyFlag; }
|
||||
bool unicode() const { return getFlags() & UnicodeFlag; }
|
||||
bool dotAll() const { return getFlags() & DotAllFlag; }
|
||||
bool unicode() const { return getFlags() & UnicodeFlag; }
|
||||
bool sticky() const { return getFlags() & StickyFlag; }
|
||||
|
||||
static bool isOriginalFlagGetter(JSNative native, RegExpFlag* mask);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue