Upstream irregexp assumes that the flags_ will be initialized to zero when checking for modifiers. Currently, this is not initialized, which is why we saw inconsistent test failures between running locally and on try. Adding an initializer means that RegExpFlags now has a non-trivial default constructor, which is not permitted for a union, so I added a no-op constructor to the formerly anonymous union that is a part of the Token struct. This also fixes operator& to return the result, rather than the lhs argument. Differential Revision: https://phabricator.services.mozilla.com/D219108
207 lines
5.7 KiB
C++
207 lines
5.7 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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/. */
|
|
|
|
/* Regular expression flags. */
|
|
|
|
#ifndef js_RegExpFlags_h
|
|
#define js_RegExpFlags_h
|
|
|
|
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
|
#include "mozilla/Attributes.h" // MOZ_IMPLICIT
|
|
|
|
#include <ostream> // ostream
|
|
#include <stdint.h> // uint8_t
|
|
|
|
namespace JS {
|
|
|
|
/**
|
|
* Regular expression flag values, suitable for initializing a collection of
|
|
* regular expression flags as defined below in |RegExpFlags|. Flags are listed
|
|
* in alphabetical order by syntax -- /d, /g, /i, /m, /s, /u, /v, /y.
|
|
*/
|
|
class RegExpFlag {
|
|
// WARNING TO SPIDERMONKEY HACKERS (embedders must assume these values can
|
|
// change):
|
|
//
|
|
// Flag-bit values appear in XDR and structured clone data formats, so none of
|
|
// these values can be changed (including to assign values in numerically
|
|
// ascending order) unless you also add a translation layer.
|
|
|
|
public:
|
|
/**
|
|
* Add .indices property to the match result, i.e. /d
|
|
*/
|
|
static constexpr uint8_t HasIndices = 0b0100'0000;
|
|
|
|
/**
|
|
* Act globally and find *all* matches (rather than stopping after just the
|
|
* first one), i.e. /g.
|
|
*/
|
|
static constexpr uint8_t Global = 0b0000'0010;
|
|
|
|
/**
|
|
* Interpret regular expression source text case-insensitively by folding
|
|
* uppercase letters to lowercase, i.e. /i.
|
|
*/
|
|
static constexpr uint8_t IgnoreCase = 0b0000'0001;
|
|
|
|
/** Treat ^ and $ as begin and end of line, i.e. /m. */
|
|
static constexpr uint8_t Multiline = 0b0000'0100;
|
|
|
|
/* Allow . to match newline characters, i.e. /s. */
|
|
static constexpr uint8_t DotAll = 0b0010'0000;
|
|
|
|
/** Use Unicode semantics, i.e. /u. */
|
|
static constexpr uint8_t Unicode = 0b0001'0000;
|
|
|
|
/** Use Unicode Sets semantics, i.e. /v. */
|
|
static constexpr uint8_t UnicodeSets = 0b1000'0000;
|
|
|
|
/** Only match starting from <regular expression>.lastIndex, i.e. /y. */
|
|
static constexpr uint8_t Sticky = 0b0000'1000;
|
|
|
|
/** No regular expression flags. */
|
|
static constexpr uint8_t NoFlags = 0b0000'0000;
|
|
|
|
/** All regular expression flags. */
|
|
static constexpr uint8_t AllFlags = 0b1111'1111;
|
|
};
|
|
|
|
/**
|
|
* A collection of regular expression flags. Individual flag values may be
|
|
* combined into a collection using bitwise operators.
|
|
*/
|
|
class RegExpFlags {
|
|
public:
|
|
using Flag = uint8_t;
|
|
|
|
private:
|
|
Flag flags_ = 0;
|
|
|
|
public:
|
|
RegExpFlags() = default;
|
|
|
|
MOZ_IMPLICIT RegExpFlags(Flag flags) : flags_(flags) {
|
|
MOZ_ASSERT((flags & RegExpFlag::AllFlags) == flags,
|
|
"flags must not contain unrecognized flags");
|
|
}
|
|
|
|
RegExpFlags(const RegExpFlags&) = default;
|
|
RegExpFlags& operator=(const RegExpFlags&) = default;
|
|
|
|
bool operator==(const RegExpFlags& other) const {
|
|
return flags_ == other.flags_;
|
|
}
|
|
|
|
bool operator!=(const RegExpFlags& other) const { return !(*this == other); }
|
|
|
|
RegExpFlags& operator&=(const RegExpFlags& rhs) {
|
|
flags_ &= rhs.flags_;
|
|
return *this;
|
|
}
|
|
|
|
RegExpFlags& operator|=(const RegExpFlags& rhs) {
|
|
flags_ |= rhs.flags_;
|
|
return *this;
|
|
}
|
|
|
|
RegExpFlags operator&(Flag flag) const { return RegExpFlags(flags_ & flag); }
|
|
|
|
RegExpFlags operator|(Flag flag) const { return RegExpFlags(flags_ | flag); }
|
|
|
|
RegExpFlags operator^(Flag flag) const { return RegExpFlags(flags_ ^ flag); }
|
|
|
|
RegExpFlags operator~() const {
|
|
return RegExpFlags(~flags_ & RegExpFlag::AllFlags);
|
|
}
|
|
|
|
bool hasIndices() const { return flags_ & RegExpFlag::HasIndices; }
|
|
bool global() const { return flags_ & RegExpFlag::Global; }
|
|
bool ignoreCase() const { return flags_ & RegExpFlag::IgnoreCase; }
|
|
bool multiline() const { return flags_ & RegExpFlag::Multiline; }
|
|
bool dotAll() const { return flags_ & RegExpFlag::DotAll; }
|
|
bool unicode() const { return flags_ & RegExpFlag::Unicode; }
|
|
bool unicodeSets() const { return flags_ & RegExpFlag::UnicodeSets; }
|
|
bool sticky() const { return flags_ & RegExpFlag::Sticky; }
|
|
|
|
explicit operator bool() const { return flags_ != 0; }
|
|
|
|
Flag value() const { return flags_; }
|
|
constexpr operator Flag() const { return flags_; }
|
|
|
|
void set(Flag flags, bool value) {
|
|
if (value) {
|
|
flags_ |= flags;
|
|
} else {
|
|
flags_ &= ~flags;
|
|
}
|
|
}
|
|
};
|
|
|
|
inline RegExpFlags& operator&=(RegExpFlags& flags, RegExpFlags::Flag flag) {
|
|
flags = flags & flag;
|
|
return flags;
|
|
}
|
|
|
|
inline RegExpFlags& operator|=(RegExpFlags& flags, RegExpFlags::Flag flag) {
|
|
flags = flags | flag;
|
|
return flags;
|
|
}
|
|
|
|
inline RegExpFlags& operator^=(RegExpFlags& flags, RegExpFlags::Flag flag) {
|
|
flags = flags ^ flag;
|
|
return flags;
|
|
}
|
|
|
|
inline RegExpFlags operator&(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
|
RegExpFlags result = lhs;
|
|
result &= rhs;
|
|
return result;
|
|
}
|
|
|
|
inline RegExpFlags operator|(const RegExpFlags& lhs, const RegExpFlags& rhs) {
|
|
RegExpFlags result = lhs;
|
|
result |= rhs;
|
|
return result;
|
|
}
|
|
|
|
inline bool MaybeParseRegExpFlag(char c, RegExpFlags::Flag* flag) {
|
|
switch (c) {
|
|
case 'd':
|
|
*flag = RegExpFlag::HasIndices;
|
|
return true;
|
|
case 'g':
|
|
*flag = RegExpFlag::Global;
|
|
return true;
|
|
case 'i':
|
|
*flag = RegExpFlag::IgnoreCase;
|
|
return true;
|
|
case 'm':
|
|
*flag = RegExpFlag::Multiline;
|
|
return true;
|
|
case 's':
|
|
*flag = RegExpFlag::DotAll;
|
|
return true;
|
|
case 'u':
|
|
*flag = RegExpFlag::Unicode;
|
|
return true;
|
|
case 'v':
|
|
*flag = RegExpFlag::UnicodeSets;
|
|
return true;
|
|
case 'y':
|
|
*flag = RegExpFlag::Sticky;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, RegExpFlags flags);
|
|
|
|
} // namespace JS
|
|
|
|
#endif // js_RegExpFlags_h
|