Commit 7e97b2cf authored by Jakob Gruber's avatar Jakob Gruber Committed by V8 LUCI CQ

[regexp] Remove experimental mode modifiers feature

The implementation came in with
https://chromium-review.googlesource.com/758999.

This feature was never enabled by default, is not used anywhere, and
is not on any standardization path.

Bug: v8:10953
Change-Id: Ia2b0a556c1fb504a4cd05bdfa9f0a9c5be608d26
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3053589Reviewed-by: 's avatarMathias Bynens <mathias@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75934}
parent 5a352b39
......@@ -1665,7 +1665,6 @@ DEFINE_BOOL(serialization_statistics, false,
"Collect statistics on serialized objects.")
// Regexp
DEFINE_BOOL(regexp_optimization, true, "generate optimized regexp code")
DEFINE_BOOL(regexp_mode_modifiers, false, "enable inline flags in regexp.")
DEFINE_BOOL(regexp_interpret_all, false, "interpret all regexp code")
#ifdef V8_TARGET_BIG_ENDIAN
#define REGEXP_PEEPHOLE_OPTIMIZATION_BOOL false
......
......@@ -64,17 +64,14 @@ class CanBeHandledVisitor final : private RegExpVisitor {
}
void* VisitCharacterClass(RegExpCharacterClass* node, void*) override {
result_ = result_ && AreSuitableFlags(node->flags());
return nullptr;
}
void* VisitAssertion(RegExpAssertion* node, void*) override {
result_ = result_ && AreSuitableFlags(node->flags());
return nullptr;
}
void* VisitAtom(RegExpAtom* node, void*) override {
result_ = result_ && AreSuitableFlags(node->flags());
return nullptr;
}
......
......@@ -280,8 +280,7 @@ class RegExpAssertion final : public RegExpTree {
NON_BOUNDARY = 5,
LAST_TYPE = NON_BOUNDARY,
};
RegExpAssertion(AssertionType type, JSRegExp::Flags flags)
: assertion_type_(type), flags_(flags) {}
explicit RegExpAssertion(AssertionType type) : assertion_type_(type) {}
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
RegExpAssertion* AsAssertion() override;
......@@ -291,11 +290,9 @@ class RegExpAssertion final : public RegExpTree {
int min_match() override { return 0; }
int max_match() override { return 0; }
AssertionType assertion_type() const { return assertion_type_; }
JSRegExp::Flags flags() const { return flags_; }
private:
const AssertionType assertion_type_;
const JSRegExp::Flags flags_;
};
......@@ -312,21 +309,17 @@ class RegExpCharacterClass final : public RegExpTree {
using CharacterClassFlags = base::Flags<Flag>;
RegExpCharacterClass(
Zone* zone, ZoneList<CharacterRange>* ranges, JSRegExp::Flags flags,
Zone* zone, ZoneList<CharacterRange>* ranges,
CharacterClassFlags character_class_flags = CharacterClassFlags())
: set_(ranges),
flags_(flags),
character_class_flags_(character_class_flags) {
: set_(ranges), character_class_flags_(character_class_flags) {
// Convert the empty set of ranges to the negated Everything() range.
if (ranges->is_empty()) {
ranges->Add(CharacterRange::Everything(), zone);
character_class_flags_ ^= NEGATED;
}
}
RegExpCharacterClass(base::uc16 type, JSRegExp::Flags flags)
: set_(type),
flags_(flags),
character_class_flags_(CharacterClassFlags()) {}
explicit RegExpCharacterClass(base::uc16 type)
: set_(type), character_class_flags_(CharacterClassFlags()) {}
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
RegExpCharacterClass* AsCharacterClass() override;
......@@ -356,23 +349,19 @@ class RegExpCharacterClass final : public RegExpTree {
base::uc16 standard_type() const { return set_.standard_set_type(); }
ZoneList<CharacterRange>* ranges(Zone* zone) { return set_.ranges(zone); }
bool is_negated() const { return (character_class_flags_ & NEGATED) != 0; }
JSRegExp::Flags flags() const { return flags_; }
bool contains_split_surrogate() const {
return (character_class_flags_ & CONTAINS_SPLIT_SURROGATE) != 0;
}
private:
CharacterSet set_;
const JSRegExp::Flags flags_;
CharacterClassFlags character_class_flags_;
};
class RegExpAtom final : public RegExpTree {
public:
explicit RegExpAtom(base::Vector<const base::uc16> data,
JSRegExp::Flags flags)
: data_(data), flags_(flags) {}
explicit RegExpAtom(base::Vector<const base::uc16> data) : data_(data) {}
void* Accept(RegExpVisitor* visitor, void* data) override;
RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
RegExpAtom* AsAtom() override;
......@@ -383,12 +372,9 @@ class RegExpAtom final : public RegExpTree {
void AppendToText(RegExpText* text, Zone* zone) override;
base::Vector<const base::uc16> data() { return data_; }
int length() { return data_.length(); }
JSRegExp::Flags flags() const { return flags_; }
bool ignore_case() const { return (flags_ & JSRegExp::kIgnoreCase) != 0; }
private:
base::Vector<const base::uc16> data_;
const JSRegExp::Flags flags_;
};
......
This diff is collapsed.
This diff is collapsed.
......@@ -424,7 +424,8 @@ struct PreloadState {
// Analysis performs assertion propagation and computes eats_at_least_ values.
// See the comments on AssertionPropagator and EatsAtLeastPropagator for more
// details.
RegExpError AnalyzeRegExp(Isolate* isolate, bool is_one_byte, RegExpNode* node);
RegExpError AnalyzeRegExp(Isolate* isolate, bool is_one_byte,
JSRegExp::Flags flags, RegExpNode* node);
class FrequencyCollator {
public:
......@@ -474,7 +475,7 @@ class FrequencyCollator {
class RegExpCompiler {
public:
RegExpCompiler(Isolate* isolate, Zone* zone, int capture_count,
bool is_one_byte);
JSRegExp::Flags flags, bool is_one_byte);
int AllocateRegister() {
if (next_register_ >= RegExpMacroAssembler::kMaxRegister) {
......@@ -531,8 +532,7 @@ class RegExpCompiler {
// If the regexp matching starts within a surrogate pair, step back to the
// lead surrogate and start matching from there.
RegExpNode* OptionallyStepBackToLeadSurrogate(RegExpNode* on_success,
JSRegExp::Flags flags);
RegExpNode* OptionallyStepBackToLeadSurrogate(RegExpNode* on_success);
inline void AddWork(RegExpNode* node) {
if (!node->on_work_list() && !node->label()->is_bound()) {
......@@ -553,6 +553,8 @@ class RegExpCompiler {
inline void IncrementRecursionDepth() { recursion_depth_++; }
inline void DecrementRecursionDepth() { recursion_depth_--; }
JSRegExp::Flags flags() const { return flags_; }
void SetRegExpTooBig() { reg_exp_too_big_ = true; }
inline bool one_byte() { return one_byte_; }
......@@ -583,6 +585,7 @@ class RegExpCompiler {
int unicode_lookaround_position_register_;
ZoneVector<RegExpNode*>* work_list_;
int recursion_depth_;
const JSRegExp::Flags flags_;
RegExpMacroAssembler* macro_assembler_;
bool one_byte_;
bool reg_exp_too_big_;
......
......@@ -205,7 +205,9 @@ class RegExpNode : public ZoneObject {
// If we know that the input is one-byte then there are some nodes that can
// never match. This method returns a node that can be substituted for
// itself, or nullptr if the node can never match.
virtual RegExpNode* FilterOneByte(int depth) { return this; }
virtual RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) {
return this;
}
// Helper for FilterOneByte.
RegExpNode* replacement() {
DCHECK(info()->replacement_calculated);
......@@ -294,7 +296,7 @@ class SeqRegExpNode : public RegExpNode {
: RegExpNode(on_success->zone()), on_success_(on_success) {}
RegExpNode* on_success() { return on_success_; }
void set_on_success(RegExpNode* node) { on_success_ = node; }
RegExpNode* FilterOneByte(int depth) override;
RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) override;
void FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) override {
on_success_->FillInBMInfo(isolate, offset, budget - 1, bm, not_at_start);
......@@ -302,7 +304,7 @@ class SeqRegExpNode : public RegExpNode {
}
protected:
RegExpNode* FilterSuccessor(int depth);
RegExpNode* FilterSuccessor(int depth, JSRegExp::Flags flags);
private:
RegExpNode* on_success_;
......@@ -406,15 +408,13 @@ class TextNode : public SeqRegExpNode {
static TextNode* CreateForCharacterRanges(Zone* zone,
ZoneList<CharacterRange>* ranges,
bool read_backward,
RegExpNode* on_success,
JSRegExp::Flags flags);
RegExpNode* on_success);
// Create TextNode for a surrogate pair with a range given for the
// lead and the trail surrogate each.
static TextNode* CreateForSurrogatePair(Zone* zone, CharacterRange lead,
CharacterRange trail,
bool read_backward,
RegExpNode* on_success,
JSRegExp::Flags flags);
RegExpNode* on_success);
void Accept(NodeVisitor* visitor) override;
void Emit(RegExpCompiler* compiler, Trace* trace) override;
void GetQuickCheckDetails(QuickCheckDetails* details,
......@@ -422,14 +422,15 @@ class TextNode : public SeqRegExpNode {
bool not_at_start) override;
ZoneList<TextElement>* elements() { return elms_; }
bool read_backward() { return read_backward_; }
void MakeCaseIndependent(Isolate* isolate, bool is_one_byte);
void MakeCaseIndependent(Isolate* isolate, bool is_one_byte,
JSRegExp::Flags flags);
int GreedyLoopTextLength() override;
RegExpNode* GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler) override;
void FillInBMInfo(Isolate* isolate, int offset, int budget,
BoyerMooreLookahead* bm, bool not_at_start) override;
void CalculateOffsets();
RegExpNode* FilterOneByte(int depth) override;
RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) override;
int Length();
private:
......@@ -622,7 +623,7 @@ class ChoiceNode : public RegExpNode {
virtual bool try_to_emit_quick_check_for_alternative(bool is_first) {
return true;
}
RegExpNode* FilterOneByte(int depth) override;
RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) override;
virtual bool read_backward() { return false; }
protected:
......@@ -694,7 +695,7 @@ class NegativeLookaroundChoiceNode : public ChoiceNode {
return !is_first;
}
void Accept(NodeVisitor* visitor) override;
RegExpNode* FilterOneByte(int depth) override;
RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) override;
};
class LoopChoiceNode : public ChoiceNode {
......@@ -727,7 +728,7 @@ class LoopChoiceNode : public ChoiceNode {
int min_loop_iterations() const { return min_loop_iterations_; }
bool read_backward() override { return read_backward_; }
void Accept(NodeVisitor* visitor) override;
RegExpNode* FilterOneByte(int depth) override;
RegExpNode* FilterOneByte(int depth, JSRegExp::Flags flags) override;
private:
// AddAlternative is made private for loop nodes because alternatives
......
......@@ -250,14 +250,10 @@ RegExpTree* RegExpParser::ParseDisjunction() {
return ReportError(RegExpError::kNothingToRepeat);
case '^': {
Advance();
if (builder->multiline()) {
builder->AddAssertion(zone()->New<RegExpAssertion>(
RegExpAssertion::START_OF_LINE, builder->flags()));
} else {
builder->AddAssertion(zone()->New<RegExpAssertion>(
RegExpAssertion::START_OF_INPUT, builder->flags()));
builder->multiline() ? RegExpAssertion::START_OF_LINE
: RegExpAssertion::START_OF_INPUT));
set_contains_anchor();
}
continue;
}
case '$': {
......@@ -265,8 +261,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
RegExpAssertion::AssertionType assertion_type =
builder->multiline() ? RegExpAssertion::END_OF_LINE
: RegExpAssertion::END_OF_INPUT;
builder->AddAssertion(
zone()->New<RegExpAssertion>(assertion_type, builder->flags()));
builder->AddAssertion(zone()->New<RegExpAssertion>(assertion_type));
continue;
}
case '.': {
......@@ -283,7 +278,7 @@ RegExpTree* RegExpParser::ParseDisjunction() {
}
RegExpCharacterClass* cc =
zone()->New<RegExpCharacterClass>(zone(), ranges, builder->flags());
zone()->New<RegExpCharacterClass>(zone(), ranges);
builder->AddCharacterClass(cc);
break;
}
......@@ -305,13 +300,13 @@ RegExpTree* RegExpParser::ParseDisjunction() {
return ReportError(RegExpError::kEscapeAtEndOfPattern);
case 'b':
Advance(2);
builder->AddAssertion(zone()->New<RegExpAssertion>(
RegExpAssertion::BOUNDARY, builder->flags()));
builder->AddAssertion(
zone()->New<RegExpAssertion>(RegExpAssertion::BOUNDARY));
continue;
case 'B':
Advance(2);
builder->AddAssertion(zone()->New<RegExpAssertion>(
RegExpAssertion::NON_BOUNDARY, builder->flags()));
builder->AddAssertion(
zone()->New<RegExpAssertion>(RegExpAssertion::NON_BOUNDARY));
continue;
// AtomEscape ::
// CharacterClassEscape
......@@ -330,8 +325,8 @@ RegExpTree* RegExpParser::ParseDisjunction() {
zone()->New<ZoneList<CharacterRange>>(2, zone());
CharacterRange::AddClassEscape(
c, ranges, unicode() && builder->ignore_case(), zone());
RegExpCharacterClass* cc = zone()->New<RegExpCharacterClass>(
zone(), ranges, builder->flags());
RegExpCharacterClass* cc =
zone()->New<RegExpCharacterClass>(zone(), ranges);
builder->AddCharacterClass(cc);
break;
}
......@@ -346,8 +341,8 @@ RegExpTree* RegExpParser::ParseDisjunction() {
ZoneVector<char> name_2(zone());
if (ParsePropertyClassName(&name_1, &name_2)) {
if (AddPropertyClassRange(ranges, p == 'P', name_1, name_2)) {
RegExpCharacterClass* cc = zone()->New<RegExpCharacterClass>(
zone(), ranges, builder->flags());
RegExpCharacterClass* cc =
zone()->New<RegExpCharacterClass>(zone(), ranges);
builder->AddCharacterClass(cc);
break;
}
......@@ -605,68 +600,6 @@ RegExpParser::RegExpParserState* RegExpParser::ParseOpenParenthesis(
lookaround_type = RegExpLookaround::LOOKAHEAD;
subexpr_type = NEGATIVE_LOOKAROUND;
break;
case '-':
case 'i':
case 's':
case 'm': {
if (!FLAG_regexp_mode_modifiers) {
ReportError(RegExpError::kInvalidGroup);
return nullptr;
}
Advance();
bool flags_sense = true; // Switching on flags.
while (subexpr_type != GROUPING) {
switch (current()) {
case '-':
if (!flags_sense) {
ReportError(RegExpError::kMultipleFlagDashes);
return nullptr;
}
flags_sense = false;
Advance();
continue;
case 's':
case 'i':
case 'm': {
JSRegExp::Flags bit = JSRegExp::kUnicode;
if (current() == 'i') bit = JSRegExp::kIgnoreCase;
if (current() == 'm') bit = JSRegExp::kMultiline;
if (current() == 's') bit = JSRegExp::kDotAll;
if (((switch_on | switch_off) & bit) != 0) {
ReportError(RegExpError::kRepeatedFlag);
return nullptr;
}
if (flags_sense) {
switch_on |= bit;
} else {
switch_off |= bit;
}
Advance();
continue;
}
case ')': {
Advance();
state->builder()
->FlushText(); // Flush pending text using old flags.
// These (?i)-style flag switches don't put us in a subexpression
// at all, they just modify the flags in the rest of the current
// subexpression.
JSRegExp::Flags flags =
(state->builder()->flags() | switch_on) & ~switch_off;
state->builder()->set_flags(flags);
return state;
}
case ':':
Advance();
subexpr_type = GROUPING; // Will break us out of the outer loop.
continue;
default:
ReportError(RegExpError::kInvalidFlagGroup);
return nullptr;
}
}
break;
}
case '<':
Advance();
if (Next() == '=') {
......@@ -1493,7 +1426,7 @@ RegExpTree* RegExpParser::GetPropertySequence(const ZoneVector<char>& name_1) {
prefix_ranges->Add(CharacterRange::Singleton('#'), zone());
prefix_ranges->Add(CharacterRange::Singleton('*'), zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), prefix_ranges, flags));
zone()->New<RegExpCharacterClass>(zone(), prefix_ranges));
builder.AddCharacter(0xFE0F);
builder.AddCharacter(0x20E3);
return builder.ToRegExp();
......@@ -1506,13 +1439,13 @@ RegExpTree* RegExpParser::GetPropertySequence(const ZoneVector<char>& name_1) {
LookupPropertyValueName(UCHAR_EMOJI_MODIFIER_BASE, "Y", false,
modifier_base_ranges, zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), modifier_base_ranges, flags));
zone()->New<RegExpCharacterClass>(zone(), modifier_base_ranges));
ZoneList<CharacterRange>* modifier_ranges =
zone()->New<ZoneList<CharacterRange>>(2, zone());
LookupPropertyValueName(UCHAR_EMOJI_MODIFIER, "Y", false, modifier_ranges,
zone());
builder.AddCharacterClass(
zone()->New<RegExpCharacterClass>(zone(), modifier_ranges, flags));
zone()->New<RegExpCharacterClass>(zone(), modifier_ranges));
return builder.ToRegExp();
}
......@@ -1780,7 +1713,7 @@ RegExpTree* RegExpParser::ParseCharacterClass(const RegExpBuilder* builder) {
Advance();
RegExpCharacterClass::CharacterClassFlags character_class_flags;
if (is_negated) character_class_flags = RegExpCharacterClass::NEGATED;
return zone()->New<RegExpCharacterClass>(zone(), ranges, builder->flags(),
return zone()->New<RegExpCharacterClass>(zone(), ranges,
character_class_flags);
}
......@@ -1874,7 +1807,7 @@ void RegExpBuilder::AddTrailSurrogate(base::uc16 trail_surrogate) {
surrogate_pair.Add(lead_surrogate, zone());
surrogate_pair.Add(trail_surrogate, zone());
RegExpAtom* atom =
zone()->New<RegExpAtom>(surrogate_pair.ToConstVector(), flags_);
zone()->New<RegExpAtom>(surrogate_pair.ToConstVector());
AddAtom(atom);
}
} else {
......@@ -1897,8 +1830,7 @@ void RegExpBuilder::FlushCharacters() {
FlushPendingSurrogate();
pending_empty_ = false;
if (characters_ != nullptr) {
RegExpTree* atom =
zone()->New<RegExpAtom>(characters_->ToConstVector(), flags_);
RegExpTree* atom = zone()->New<RegExpAtom>(characters_->ToConstVector());
characters_ = nullptr;
text_.Add(atom, zone());
LAST(ADD_ATOM);
......@@ -1972,8 +1904,7 @@ void RegExpBuilder::AddCharacterClass(RegExpCharacterClass* cc) {
void RegExpBuilder::AddCharacterClassForDesugaring(base::uc32 c) {
AddTerm(zone()->New<RegExpCharacterClass>(
zone(), CharacterRange::List(zone(), CharacterRange::Singleton(c)),
flags_));
zone(), CharacterRange::List(zone(), CharacterRange::Singleton(c))));
}
void RegExpBuilder::AddAtom(RegExpTree* term) {
......@@ -2083,11 +2014,11 @@ bool RegExpBuilder::AddQuantifierToAtom(
if (num_chars > 1) {
base::Vector<const base::uc16> prefix =
char_vector.SubVector(0, num_chars - 1);
text_.Add(zone()->New<RegExpAtom>(prefix, flags_), zone());
text_.Add(zone()->New<RegExpAtom>(prefix), zone());
char_vector = char_vector.SubVector(num_chars - 1, num_chars);
}
characters_ = nullptr;
atom = zone()->New<RegExpAtom>(char_vector, flags_);
atom = zone()->New<RegExpAtom>(char_vector);
FlushText();
} else if (text_.length() > 0) {
DCHECK(last_added_ == ADD_ATOM);
......
......@@ -225,7 +225,7 @@ MaybeHandle<Object> RegExp::Compile(Isolate* isolate, Handle<JSRegExp> re,
ASSIGN_RETURN_ON_EXCEPTION(
isolate, atom_string,
isolate->factory()->NewStringFromTwoByte(atom_pattern), Object);
if (!IgnoreCase(atom->flags()) && !HasFewDifferentCharacters(atom_string)) {
if (!IgnoreCase(flags) && !HasFewDifferentCharacters(atom_string)) {
RegExpImpl::AtomCompile(isolate, re, pattern, flags, atom_string);
has_been_compiled = true;
}
......@@ -802,7 +802,8 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
return false;
}
RegExpCompiler compiler(isolate, zone, data->capture_count, is_one_byte);
RegExpCompiler compiler(isolate, zone, data->capture_count, flags,
is_one_byte);
if (compiler.optimize()) {
compiler.set_optimize(!TooMuchRegExpCode(isolate, pattern));
......@@ -821,7 +822,7 @@ bool RegExpImpl::Compile(Isolate* isolate, Zone* zone, RegExpCompileData* data,
}
data->node = compiler.PreprocessRegExp(data, flags, is_one_byte);
data->error = AnalyzeRegExp(isolate, is_one_byte, data->node);
data->error = AnalyzeRegExp(isolate, is_one_byte, flags, data->node);
if (data->error != RegExpError::kNone) {
return false;
}
......
......@@ -416,8 +416,6 @@
'es6/unicode-regexp-ignore-case': [FAIL],
'regress/regress-5036': [FAIL],
'es7/regexp-ui-word': [FAIL],
'regexp-modifiers-i18n': [FAIL],
'regexp-modifiers-autogenerated-i18n': [FAIL],
# Desugaring regexp property class relies on ICU. Anything goes as long as we
# don't crash.
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --regexp-mode-modifiers
// These regexps are just grepped out of the other tests we already have
// and the syntax changed from out-of-line i flag to inline i flag.
// These tests won't all run on the noi18n build of V8.
assertTrue(/(?i)\u00e5/u.test("\u00c5"));
assertTrue(/(?i)\u00e5/u.test("\u00e5"));
assertTrue(/(?i)\u00c5/u.test("\u00e5"));
assertTrue(/(?i)\u00c5/u.test("\u00c5"));
assertTrue(/(?i)\u212b/u.test("\u212b"));
assertFalse(/(?i)\u00df/u.test("SS"));
assertFalse(/(?i)\u1f8d/u.test("\u1f05\u03b9"));
assertTrue(/(?i)\u1f6b/u.test("\u1f63"));
assertTrue(/(?i)\u00e5/u.test("\u212b"));
assertTrue(/(?i)\u00e5/u.test("\u00c5"));
assertTrue(/(?i)\u00e5/u.test("\u00e5"));
assertTrue(/(?i)\u00e5/u.test("\u212b"));
assertTrue(/(?i)\u00c5/u.test("\u00e5"));
assertTrue(/(?i)\u00c5/u.test("\u212b"));
assertTrue(/(?i)\u00c5/u.test("\u00c5"));
assertTrue(/(?i)\u212b/u.test("\u00c5"));
assertTrue(/(?i)\u212b/u.test("\u00e5"));
assertTrue(/(?i)\u212b/u.test("\u212b"));
assertTrue(/(?i)\u{10400}/u.test("\u{10428}"));
assertTrue(/(?i)\ud801\udc00/u.test("\u{10428}"));
assertTrue(/(?i)[\u{10428}]/u.test("\u{10400}"));
assertTrue(/(?i)[\ud801\udc28]/u.test("\u{10400}"));
assertFalse(/(?i)\u00df/u.test("SS"));
assertFalse(/(?i)\u1f8d/u.test("\u1f05\u03b9"));
assertTrue(/(?i)\u1f8d/u.test("\u1f85"));
assertTrue(/(?i)\u1f6b/u.test("\u1f63"));
assertTrue(/(?i)\u00e5\u00e5\u00e5/u.test("\u212b\u00e5\u00c5"));
assertTrue(/(?i)AB\u{10400}/u.test("ab\u{10428}"));
assertTrue(/(?i)\w/u.test('\u017F'));
assertTrue(/(?i)\w/u.test('\u212A'));
assertFalse(/(?i)\W/u.test('\u017F'));
assertFalse(/(?i)\W/u.test('\u212A'));
assertFalse(/(?i)\W/u.test('s'));
assertFalse(/(?i)\W/u.test('S'));
assertFalse(/(?i)\W/u.test('K'));
assertFalse(/(?i)\W/u.test('k'));
assertTrue(/(?i)[\w]/u.test('\u017F'));
assertTrue(/(?i)[\w]/u.test('\u212A'));
assertFalse(/(?i)[\W]/u.test('\u017F'));
assertFalse(/(?i)[\W]/u.test('\u212A'));
assertFalse(/(?i)[\W]/u.test('s'));
assertFalse(/(?i)[\W]/u.test('S'));
assertFalse(/(?i)[\W]/u.test('K'));
assertFalse(/(?i)[\W]/u.test('k'));
assertTrue(/(?i)\b/u.test('\u017F'));
assertTrue(/(?i)\b/u.test('\u212A'));
assertTrue(/(?i)\b/u.test('s'));
assertTrue(/(?i)\b/u.test('S'));
assertFalse(/(?i)\B/u.test('\u017F'));
assertFalse(/(?i)\B/u.test('\u212A'));
assertFalse(/(?i)\B/u.test('s'));
assertFalse(/(?i)\B/u.test('S'));
assertFalse(/(?i)\B/u.test('K'));
assertFalse(/(?i)\B/u.test('k'));
assertTrue(/(?i)\p{Ll}/u.test("a"));
assertTrue(/(?i)\p{Ll}/u.test("\u{118D4}"));
assertTrue(/(?i)\p{Ll}/u.test("A"));
assertTrue(/(?i)\p{Ll}/u.test("\u{118B4}"));
assertTrue(/(?i)\P{Ll}/u.test("a"));
assertTrue(/(?i)\P{Ll}/u.test("\u{118D4}"));
assertTrue(/(?i)\P{Ll}/u.test("A"));
assertTrue(/(?i)\P{Ll}/u.test("\u{118B4}"));
assertTrue(/(?i)\p{Lu}/u.test("a"));
assertTrue(/(?i)\p{Lu}/u.test("\u{118D4}"));
assertTrue(/(?i)\p{Lu}/u.test("A"));
assertTrue(/(?i)\p{Lu}/u.test("\u{118B4}"));
assertTrue(/(?i)\P{Lu}/u.test("a"));
assertTrue(/(?i)\P{Lu}/u.test("\u{118D4}"));
assertTrue(/(?i)\P{Lu}/u.test("A"));
assertTrue(/(?i)\P{Lu}/u.test("\u{118B4}"));
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --regexp-mode-modifiers
// These regexps are just grepped out of the other tests we already have
// and the syntax changed from out-of-line i flag to inline i flag.
assertFalse(/(?i)x(...)\1/.test("x\u03a3\u03c2\u03c3\u03c2\u03c3"));
assertTrue(/(?i)\u03a3((?:))\1\1x/.test("\u03c2x"), "backref-UC16-empty");
assertTrue(/(?i)x(?:...|(...))\1x/.test("x\u03a3\u03c2\u03c3x"));
assertTrue(/(?i)x(?:...|(...))\1x/.test("x\u03c2\u03c3\u039b\u03a3\u03c2\u03bbx"));
assertFalse(/(?i)\xc1/.test('fooA'), "quickcheck-uc16-pattern-ascii-subject");
assertFalse(/(?i)x(...)\1/.test("xaaaaa"), "backref-ASCII-short");
assertTrue(/(?i)x((?:))\1\1x/.test("xx"), "backref-ASCII-empty");
assertTrue(/(?i)x(?:...|(...))\1x/.test("xabcx"), "backref-ASCII-uncaptured");
assertTrue(/(?i)x(?:...|(...))\1x/.test("xabcABCx"), "backref-ASCII-backtrack");
assertFalse(/(?i)f/.test('b'));
assertFalse(/(?i)[abc]f/.test('x'));
assertFalse(/(?i)[abc]f/.test('xa'));
assertFalse(/(?i)[abc]</.test('x'));
assertFalse(/(?i)[abc]</.test('xa'));
assertFalse(/(?i)f[abc]/.test('x'));
assertFalse(/(?i)f[abc]/.test('xa'));
assertFalse(/(?i)<[abc]/.test('x'));
assertFalse(/(?i)<[abc]/.test('xa'));
assertFalse(/(?i)[\u00e5]/.test("\u212b"));
assertFalse(/(?i)[\u212b]/.test("\u00e5\u1234"));
assertFalse(/(?i)[\u212b]/.test("\u00e5"));
assertFalse(/(?i)\u{10400}/.test("\u{10428}"));
assertFalse(/(?i)[\u00e5]/.test("\u212b"));
assertFalse(/(?i)[\u212b]/.test("\u00e5\u1234"));
assertFalse(/(?i)[\u212b]/.test("\u00e5"));
assertFalse(/(?i)\u{10400}/.test("\u{10428}"));
assertTrue(/(?i)[@-A]/.test("a"));
assertTrue(/(?i)[@-A]/.test("A"));
assertTrue(/(?i)[@-A]/.test("@"));
assertFalse(/(?i)[¿-À]/.test('¾'));
assertTrue(/(?i)[¿-À]/.test('¿'));
assertTrue(/(?i)[¿-À]/.test('À'));
assertTrue(/(?i)[¿-À]/.test('à'));
assertFalse(/(?i)[¿-À]/.test('á'));
assertFalse(/(?i)[¿-À]/.test('Á'));
assertFalse(/(?i)[¿-À]/.test('Á'));
assertFalse(/(?i)[Ö-×]/.test('Õ'));
assertTrue(/(?i)[Ö-×]/.test('Ö'));
assertTrue(/(?i)[Ö-×]/.test('ö'));
assertTrue(/(?i)[Ö-×]/.test('×'));
assertFalse(/(?i)[Ö-×]/.test('Ø'));
assertTrue(/(?i)(a[\u1000A])+/.test('aa'));
assertTrue(/(?i)\u0178/.test('\u00ff'));
assertTrue(/(?i)\u039c/.test('\u00b5'));
assertTrue(/(?i)\u039c/.test('\u03bc'));
assertTrue(/(?i)\u00b5/.test('\u03bc'));
assertTrue(/(?i)[\u039b-\u039d]/.test('\u00b5'));
assertFalse(/(?i)[^\u039b-\u039d]/.test('\u00b5'));
assertTrue(/(?m)^bar/.test("bar"));
assertTrue(/(?m)^bar/.test("bar\nfoo"));
assertTrue(/(?m)^bar/.test("foo\nbar"));
assertTrue(/(?m)bar$/.test("bar"));
assertTrue(/(?m)bar$/.test("bar\nfoo"));
assertTrue(/(?m)bar$/.test("foo\nbar"));
assertFalse(/(?m)^bxr/.test("bar"));
assertFalse(/(?m)^bxr/.test("bar\nfoo"));
assertFalse(/(?m)^bxr/.test("foo\nbar"));
assertFalse(/(?m)bxr$/.test("bar"));
assertFalse(/(?m)bxr$/.test("bar\nfoo"));
assertFalse(/(?m)bxr$/.test("foo\nbar"));
assertTrue(/(?m)^.*$/.test("\n"));
assertTrue(/(?m)^([()]|.)*$/.test("()\n()"));
assertTrue(/(?m)^([()]|.)*$/.test("()\n"));
assertTrue(/(?m)^[()]*$/.test("()\n."));
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --regexp-mode-modifiers
// S flag switches dotall mode on and off. Combine with i flag changes to test
// the parser.
test(/.(?s).(?i-s).a(?-i)a/);
test(/.(?s:.)(?i:.a)a/);
test(/.(?s).(?i-s).a(?-i)a/u);
test(/.(?s:.)(?i:.a)a/u);
// m flag makes no difference
test(/.(?sm).(?i-s).a(?-i)a/);
test(/.(?s:.)(?i:.a)a/);
test(/.(?sm).(?im-s).a(?m-i)a/u);
test(/.(?s:.)(?i:.a)a/u);
function test(re) {
assertTrue(re.test("...aa"));
assertTrue(re.test(".\n.aa"));
assertTrue(re.test(".\n.Aa"));
assertFalse(re.test("\n\n.Aa"));
assertFalse(re.test(".\n\nAa"));
assertFalse(re.test(".\n.AA"));
}
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --regexp-mode-modifiers
// These tests won't all run on the noi18n build of V8.
aa(/(a)(?i)\1/u);
aa(/([az])(?i)\1/u);
function aa(re) {
assertTrue(re.test("aa"));
assertTrue(re.test("aA"));
assertFalse(re.test("Aa"));
assertFalse(re.test("AA"));
}
aai(/(a)(?-i)\1/iu);
aai(/([az])(?-i)\1/iu);
function aai(re) {
assertTrue(re.test("aa"));
assertFalse(re.test("aA"));
assertFalse(re.test("Aa"));
assertTrue(re.test("AA"));
}
abcd(/a(b(?i)c)d/u);
abcd(/[aw]([bx](?i)[cy])[dz]/u);
function abcd(re) {
assertTrue(re.test("abcd"));
assertFalse(re.test("abcD"));
assertTrue(re.test("abCd"));
assertFalse(re.test("abCD"));
assertFalse(re.test("aBcd"));
assertFalse(re.test("aBcD"));
assertFalse(re.test("aBCd"));
assertFalse(re.test("aBCD"));
assertFalse(re.test("Abcd"));
assertFalse(re.test("AbcD"));
assertFalse(re.test("AbCd"));
assertFalse(re.test("AbCD"));
assertFalse(re.test("ABcd"));
assertFalse(re.test("ABcD"));
assertFalse(re.test("ABCd"));
assertFalse(re.test("ABCD"));
}
abcdei(/a(b(?-i)c)d/iu);
abcdei(/[aw]([bx](?-i)[cy])[dz]/iu);
function abcdei(re) {
assertTrue(re.test("abcd"));
assertTrue(re.test("abcD"));
assertFalse(re.test("abCd"));
assertFalse(re.test("abCD"));
assertTrue(re.test("aBcd"));
assertTrue(re.test("aBcD"));
assertFalse(re.test("aBCd"));
assertFalse(re.test("aBCD"));
assertTrue(re.test("Abcd"));
assertTrue(re.test("AbcD"));
assertFalse(re.test("AbCd"));
assertFalse(re.test("AbCD"));
assertTrue(re.test("ABcd"));
assertTrue(re.test("ABcD"));
assertFalse(re.test("ABCd"));
assertFalse(re.test("ABCD"));
}
abc(/a(?i:b)c/u);
abc(/[ax](?i:[by])[cz]/u);
function abc(re) {
assertTrue(re.test("abc"));
assertFalse(re.test("abC"));
assertTrue(re.test("aBc"));
assertFalse(re.test("aBC"));
assertFalse(re.test("Abc"));
assertFalse(re.test("AbC"));
assertFalse(re.test("ABc"));
assertFalse(re.test("ABC"));
}
abci(/a(?-i:b)c/iu);
abci(/[ax](?-i:[by])[cz]/iu);
function abci(re) {
assertTrue(re.test("abc"));
assertTrue(re.test("abC"));
assertFalse(re.test("aBc"));
assertFalse(re.test("aBC"));
assertTrue(re.test("Abc"));
assertTrue(re.test("AbC"));
assertFalse(re.test("ABc"));
assertFalse(re.test("ABC"));
}
// The following tests are taken from test/mjsunit/es7/regexp-ui-word.js but
// using inline syntax instead of the global /i flag.
assertTrue(/(?i)\w/u.test('\u017F'));
assertTrue(/(?i)\w/u.test('\u212A'));
assertFalse(/(?i)\W/u.test('\u017F'));
assertFalse(/(?i)\W/u.test('\u212A'));
assertFalse(/(?i)\W/u.test('s'));
assertFalse(/(?i)\W/u.test('S'));
assertFalse(/(?i)\W/u.test('K'));
assertFalse(/(?i)\W/u.test('k'));
assertTrue(/(?i)[\w]/u.test('\u017F'));
assertTrue(/(?i)[\w]/u.test('\u212A'));
assertFalse(/(?i)[\W]/u.test('\u017F'));
assertFalse(/(?i)[\W]/u.test('\u212A'));
assertFalse(/(?i)[\W]/u.test('s'));
assertFalse(/(?i)[\W]/u.test('S'));
assertFalse(/(?i)[\W]/u.test('K'));
assertFalse(/(?i)[\W]/u.test('k'));
assertTrue(/(?i)\b/u.test('\u017F'));
assertFalse(/(?i:)\b/u.test('\u017F'));
assertTrue(/(?i)\b/u.test('\u212A'));
assertFalse(/(?i:)\b/u.test('\u212A'));
assertTrue(/(?i)\b/u.test('s'));
assertTrue(/(?i)\b/u.test('S'));
assertFalse(/(?i)\B/u.test('\u017F'));
assertFalse(/(?i)\B/u.test('\u212A'));
assertFalse(/(?i)\B/u.test('s'));
assertFalse(/(?i)\B/u.test('S'));
assertFalse(/(?i)\B/u.test('K'));
assertFalse(/(?i)\B/u.test('k'));
assertEquals(["abcd\u017F", "\u017F"], /a.*?(.)(?i)\b/u.exec('abcd\u017F cd'));
assertEquals(["abcd\u212A", "\u212A"], /a.*?(.)(?i)\b/u.exec('abcd\u212A cd'));
assertEquals(["a\u017F", "\u017F"], /a.*?(?i:\B)(.)/u.exec('a\u017F '));
assertEquals(["a\u212A", "\u212A"], /a.*?(?i:\B)(.)/u.exec('a\u212A '));
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --regexp-mode-modifiers
aa(/(a)(?i)\1/);
aa(/([az])(?i)\1/);
function aa(re) {
assertTrue(re.test("aa"));
assertTrue(re.test("aA"));
assertFalse(re.test("Aa"));
assertFalse(re.test("AA"));
}
aai(/(a)(?-i)\1/i);
aai(/([az])(?-i)\1/i);
function aai(re) {
assertTrue(re.test("aa"));
assertFalse(re.test("aA"));
assertFalse(re.test("Aa"));
assertTrue(re.test("AA"));
}
abcd(/a(b(?i)c)d/);
abcd(/[aw]([bx](?i)[cy])[dz]/);
function abcd(re) {
assertTrue(re.test("abcd"));
assertFalse(re.test("abcD"));
assertTrue(re.test("abCd"));
assertFalse(re.test("abCD"));
assertFalse(re.test("aBcd"));
assertFalse(re.test("aBcD"));
assertFalse(re.test("aBCd"));
assertFalse(re.test("aBCD"));
assertFalse(re.test("Abcd"));
assertFalse(re.test("AbcD"));
assertFalse(re.test("AbCd"));
assertFalse(re.test("AbCD"));
assertFalse(re.test("ABcd"));
assertFalse(re.test("ABcD"));
assertFalse(re.test("ABCd"));
assertFalse(re.test("ABCD"));
}
abcdei(/a(b(?-i)c)d/i);
abcdei(/[aw]([bx](?-i)[cy])[dz]/i);
function abcdei(re) {
assertTrue(re.test("abcd"));
assertTrue(re.test("abcD"));
assertFalse(re.test("abCd"));
assertFalse(re.test("abCD"));
assertTrue(re.test("aBcd"));
assertTrue(re.test("aBcD"));
assertFalse(re.test("aBCd"));
assertFalse(re.test("aBCD"));
assertTrue(re.test("Abcd"));
assertTrue(re.test("AbcD"));
assertFalse(re.test("AbCd"));
assertFalse(re.test("AbCD"));
assertTrue(re.test("ABcd"));
assertTrue(re.test("ABcD"));
assertFalse(re.test("ABCd"));
assertFalse(re.test("ABCD"));
}
abc(/a(?i:b)c/);
abc(/[ax](?i:[by])[cz]/);
function abc(re) {
assertTrue(re.test("abc"));
assertFalse(re.test("abC"));
assertTrue(re.test("aBc"));
assertFalse(re.test("aBC"));
assertFalse(re.test("Abc"));
assertFalse(re.test("AbC"));
assertFalse(re.test("ABc"));
assertFalse(re.test("ABC"));
}
abci(/a(?-i:b)c/i);
abci(/[ax](?-i:[by])[cz]/i);
function abci(re) {
assertTrue(re.test("abc"));
assertTrue(re.test("abC"));
assertFalse(re.test("aBc"));
assertFalse(re.test("aBC"));
assertTrue(re.test("Abc"));
assertTrue(re.test("AbC"));
assertFalse(re.test("ABc"));
assertFalse(re.test("ABC"));
}
assertThrows(() => new RegExp("foo(?i:"));
assertThrows(() => new RegExp("foo(?--i)"));
assertThrows(() => new RegExp("foo(?i-i)"));
assertThrows(() => new RegExp("foo(?m:"));
assertThrows(() => new RegExp("foo(?--m)"));
assertThrows(() => new RegExp("foo(?m-m)"));
var re = /^\s(?m)^.$\s(?-m)$/;
assertTrue(re.test("\n.\n"));
assertFalse(re.test(" .\n"));
assertFalse(re.test("\n. "));
assertFalse(re.test(" . "));
assertFalse(re.test("_\n.\n"));
assertFalse(re.test("\n.\n_"));
assertFalse(re.test("_\n.\n_"));
assertEquals(["abcd", "d"], /a.*?(.)(?i)\b/.exec('abcd\u017F cd'));
assertEquals(["abcd", "d"], /a.*?(.)(?i)\b/.exec('abcd\u212A cd'));
assertEquals(["a\u017F ", " "], /a.*?(?i)\B(.)/.exec('a\u017F '));
assertEquals(["a\u212A ", " "], /a.*?(?i)\B(.)/.exec('a\u212A '));
// Nested flags.
var res = [
/^a(?i:b(?-i:c(?i:d)e)f)g$/,
/^a(?i:b(?-i)c(?i)d(?-i)e(?i)f)g$/,
/^(?-i:a(?i:b(?-i:c(?i:d)e)f)g)$/i,
/^(?-i:a(?i:b(?-i)c(?i)d(?-i)e(?i)f)g)$/i,
];
for (var idx = 0; idx < res.length; idx++) {
var re = res[idx];
for (var i = 0; i < 128; i++) {
var s = (i & 1) ? "A" : "a";
s += (i & 2) ? "B" : "b";
s += (i & 4) ? "C" : "c";
s += (i & 8) ? "D" : "d";
s += (i & 16) ? "E" : "e";
s += (i & 32) ? "F" : "f";
s += (i & 64) ? "G" : "g";
if ((i & (1 | 4 | 16 | 64)) != 0) {
assertFalse(re.test(s), s);
} else {
assertTrue(re.test(s), s);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment