Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_REGEXP_REGEXP_AST_H_
6 : #define V8_REGEXP_REGEXP_AST_H_
7 :
8 : #include "src/objects.h"
9 : #include "src/objects/js-regexp.h"
10 : #include "src/objects/string.h"
11 : #include "src/utils.h"
12 : #include "src/zone/zone-containers.h"
13 : #include "src/zone/zone.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : #define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
19 : VISIT(Disjunction) \
20 : VISIT(Alternative) \
21 : VISIT(Assertion) \
22 : VISIT(CharacterClass) \
23 : VISIT(Atom) \
24 : VISIT(Quantifier) \
25 : VISIT(Capture) \
26 : VISIT(Group) \
27 : VISIT(Lookaround) \
28 : VISIT(BackReference) \
29 : VISIT(Empty) \
30 : VISIT(Text)
31 :
32 : #define FORWARD_DECLARE(Name) class RegExp##Name;
33 : FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
34 : #undef FORWARD_DECLARE
35 :
36 : class RegExpCompiler;
37 : class RegExpNode;
38 : class RegExpTree;
39 :
40 765 : class RegExpVisitor {
41 : public:
42 765 : virtual ~RegExpVisitor() = default;
43 : #define MAKE_CASE(Name) \
44 : virtual void* Visit##Name(RegExp##Name*, void* data) = 0;
45 : FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
46 : #undef MAKE_CASE
47 : };
48 :
49 :
50 : // A simple closed interval.
51 : class Interval {
52 : public:
53 : Interval() : from_(kNone), to_(kNone) {}
54 248138 : Interval(int from, int to) : from_(from), to_(to) {}
55 : Interval Union(Interval that) {
56 28291 : if (that.from_ == kNone)
57 : return *this;
58 1556 : else if (from_ == kNone)
59 : return that;
60 : else
61 : return Interval(Min(from_, that.from_), Max(to_, that.to_));
62 : }
63 47480 : bool Contains(int value) { return (from_ <= value) && (value <= to_); }
64 : bool is_empty() { return from_ == kNone; }
65 : int from() const { return from_; }
66 : int to() const { return to_; }
67 : static Interval Empty() { return Interval(); }
68 : static const int kNone = -1;
69 :
70 : private:
71 : int from_;
72 : int to_;
73 : };
74 :
75 :
76 : // Represents code units in the range from from_ to to_, both ends are
77 : // inclusive.
78 : class CharacterRange {
79 : public:
80 30 : CharacterRange() : from_(0), to_(0) {}
81 : // For compatibility with the CHECK_OK macro
82 : CharacterRange(void* null) { DCHECK_NULL(null); } // NOLINT
83 : V8_EXPORT_PRIVATE static void AddClassEscape(char type,
84 : ZoneList<CharacterRange>* ranges,
85 : Zone* zone);
86 : // Add class escapes. Add case equivalent closure for \w and \W if necessary.
87 : V8_EXPORT_PRIVATE static void AddClassEscape(
88 : char type, ZoneList<CharacterRange>* ranges,
89 : bool add_unicode_case_equivalents, Zone* zone);
90 : static Vector<const int> GetWordBounds();
91 : static inline CharacterRange Singleton(uc32 value) {
92 : return CharacterRange(value, value);
93 : }
94 : static inline CharacterRange Range(uc32 from, uc32 to) {
95 : DCHECK(0 <= from && to <= String::kMaxCodePoint);
96 : DCHECK(static_cast<uint32_t>(from) <= static_cast<uint32_t>(to));
97 : return CharacterRange(from, to);
98 : }
99 : static inline CharacterRange Everything() {
100 : return CharacterRange(0, String::kMaxCodePoint);
101 : }
102 60215 : static inline ZoneList<CharacterRange>* List(Zone* zone,
103 : CharacterRange range) {
104 : ZoneList<CharacterRange>* list =
105 : new (zone) ZoneList<CharacterRange>(1, zone);
106 60215 : list->Add(range, zone);
107 60215 : return list;
108 : }
109 679875 : bool Contains(uc32 i) { return from_ <= i && i <= to_; }
110 : uc32 from() const { return from_; }
111 : void set_from(uc32 value) { from_ = value; }
112 : uc32 to() const { return to_; }
113 : void set_to(uc32 value) { to_ = value; }
114 : bool is_valid() { return from_ <= to_; }
115 273741 : bool IsEverything(uc32 max) { return from_ == 0 && to_ >= max; }
116 : bool IsSingleton() { return (from_ == to_); }
117 : V8_EXPORT_PRIVATE static void AddCaseEquivalents(
118 : Isolate* isolate, Zone* zone, ZoneList<CharacterRange>* ranges,
119 : bool is_one_byte);
120 : // Whether a range list is in canonical form: Ranges ordered by from value,
121 : // and ranges non-overlapping and non-adjacent.
122 : V8_EXPORT_PRIVATE static bool IsCanonical(ZoneList<CharacterRange>* ranges);
123 : // Convert range list to canonical form. The characters covered by the ranges
124 : // will still be the same, but no character is in more than one range, and
125 : // adjacent ranges are merged. The resulting list may be shorter than the
126 : // original, but cannot be longer.
127 : static void Canonicalize(ZoneList<CharacterRange>* ranges);
128 : // Negate the contents of a character range in canonical form.
129 : static void Negate(ZoneList<CharacterRange>* src,
130 : ZoneList<CharacterRange>* dst, Zone* zone);
131 : static const int kStartMarker = (1 << 24);
132 : static const int kPayloadMask = (1 << 24) - 1;
133 :
134 : private:
135 : CharacterRange(uc32 from, uc32 to) : from_(from), to_(to) {}
136 :
137 : uc32 from_;
138 : uc32 to_;
139 : };
140 :
141 : class CharacterSet final {
142 : public:
143 : explicit CharacterSet(uc16 standard_set_type)
144 83019 : : ranges_(nullptr), standard_set_type_(standard_set_type) {}
145 : explicit CharacterSet(ZoneList<CharacterRange>* ranges)
146 249078 : : ranges_(ranges), standard_set_type_(0) {}
147 : ZoneList<CharacterRange>* ranges(Zone* zone);
148 : uc16 standard_set_type() const { return standard_set_type_; }
149 : void set_standard_set_type(uc16 special_set_type) {
150 9710 : standard_set_type_ = special_set_type;
151 : }
152 : bool is_standard() { return standard_set_type_ != 0; }
153 : V8_EXPORT_PRIVATE void Canonicalize();
154 :
155 : private:
156 : ZoneList<CharacterRange>* ranges_;
157 : // If non-zero, the value represents a standard set (e.g., all whitespace
158 : // characters) without having to expand the ranges.
159 : uc16 standard_set_type_;
160 : };
161 :
162 : class TextElement final {
163 : public:
164 : enum TextType { ATOM, CHAR_CLASS };
165 :
166 : static TextElement Atom(RegExpAtom* atom);
167 : static TextElement CharClass(RegExpCharacterClass* char_class);
168 :
169 : int cp_offset() const { return cp_offset_; }
170 379917 : void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
171 : int length() const;
172 :
173 : TextType text_type() const { return text_type_; }
174 :
175 : RegExpTree* tree() const { return tree_; }
176 :
177 : RegExpAtom* atom() const {
178 : DCHECK(text_type() == ATOM);
179 : return reinterpret_cast<RegExpAtom*>(tree());
180 : }
181 :
182 : RegExpCharacterClass* char_class() const {
183 : DCHECK(text_type() == CHAR_CLASS);
184 : return reinterpret_cast<RegExpCharacterClass*>(tree());
185 : }
186 :
187 : private:
188 : TextElement(TextType text_type, RegExpTree* tree)
189 : : cp_offset_(-1), text_type_(text_type), tree_(tree) {}
190 :
191 : int cp_offset_;
192 : TextType text_type_;
193 : RegExpTree* tree_;
194 : };
195 :
196 :
197 5249181 : class RegExpTree : public ZoneObject {
198 : public:
199 : static const int kInfinity = kMaxInt;
200 0 : virtual ~RegExpTree() = default;
201 : virtual void* Accept(RegExpVisitor* visitor, void* data) = 0;
202 : virtual RegExpNode* ToNode(RegExpCompiler* compiler,
203 : RegExpNode* on_success) = 0;
204 1110533 : virtual bool IsTextElement() { return false; }
205 83318 : virtual bool IsAnchoredAtStart() { return false; }
206 84317 : virtual bool IsAnchoredAtEnd() { return false; }
207 : virtual int min_match() = 0;
208 : virtual int max_match() = 0;
209 : // Returns the interval of registers used for captures within this
210 : // expression.
211 1026356 : virtual Interval CaptureRegisters() { return Interval::Empty(); }
212 : virtual void AppendToText(RegExpText* text, Zone* zone);
213 : V8_EXPORT_PRIVATE std::ostream& Print(std::ostream& os,
214 : Zone* zone); // NOLINT
215 : #define MAKE_ASTYPE(Name) \
216 : virtual RegExp##Name* As##Name(); \
217 : virtual bool Is##Name();
218 : FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ASTYPE)
219 : #undef MAKE_ASTYPE
220 : };
221 :
222 :
223 0 : class RegExpDisjunction final : public RegExpTree {
224 : public:
225 : explicit RegExpDisjunction(ZoneList<RegExpTree*>* alternatives);
226 : void* Accept(RegExpVisitor* visitor, void* data) override;
227 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
228 : RegExpDisjunction* AsDisjunction() override;
229 : Interval CaptureRegisters() override;
230 : bool IsDisjunction() override;
231 : bool IsAnchoredAtStart() override;
232 : bool IsAnchoredAtEnd() override;
233 21532 : int min_match() override { return min_match_; }
234 22900 : int max_match() override { return max_match_; }
235 : ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
236 :
237 : private:
238 : bool SortConsecutiveAtoms(RegExpCompiler* compiler);
239 : void RationalizeConsecutiveAtoms(RegExpCompiler* compiler);
240 : void FixSingleCharacterDisjunctions(RegExpCompiler* compiler);
241 : ZoneList<RegExpTree*>* alternatives_;
242 : int min_match_;
243 : int max_match_;
244 : };
245 :
246 :
247 0 : class RegExpAlternative final : public RegExpTree {
248 : public:
249 : explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes);
250 : void* Accept(RegExpVisitor* visitor, void* data) override;
251 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
252 : RegExpAlternative* AsAlternative() override;
253 : Interval CaptureRegisters() override;
254 : bool IsAlternative() override;
255 : bool IsAnchoredAtStart() override;
256 : bool IsAnchoredAtEnd() override;
257 23670 : int min_match() override { return min_match_; }
258 37023 : int max_match() override { return max_match_; }
259 : ZoneList<RegExpTree*>* nodes() { return nodes_; }
260 :
261 : private:
262 : ZoneList<RegExpTree*>* nodes_;
263 : int min_match_;
264 : int max_match_;
265 : };
266 :
267 :
268 0 : class RegExpAssertion final : public RegExpTree {
269 : public:
270 : enum AssertionType {
271 : START_OF_LINE,
272 : START_OF_INPUT,
273 : END_OF_LINE,
274 : END_OF_INPUT,
275 : BOUNDARY,
276 : NON_BOUNDARY
277 : };
278 : RegExpAssertion(AssertionType type, JSRegExp::Flags flags)
279 11236 : : assertion_type_(type), flags_(flags) {}
280 : void* Accept(RegExpVisitor* visitor, void* data) override;
281 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
282 : RegExpAssertion* AsAssertion() override;
283 : bool IsAssertion() override;
284 : bool IsAnchoredAtStart() override;
285 : bool IsAnchoredAtEnd() override;
286 10960 : int min_match() override { return 0; }
287 11372 : int max_match() override { return 0; }
288 : AssertionType assertion_type() { return assertion_type_; }
289 :
290 : private:
291 : const AssertionType assertion_type_;
292 : const JSRegExp::Flags flags_;
293 : };
294 :
295 :
296 0 : class RegExpCharacterClass final : public RegExpTree {
297 : public:
298 : // NEGATED: The character class is negated and should match everything but
299 : // the specified ranges.
300 : // CONTAINS_SPLIT_SURROGATE: The character class contains part of a split
301 : // surrogate and should not be unicode-desugared (crbug.com/641091).
302 : enum Flag {
303 : NEGATED = 1 << 0,
304 : CONTAINS_SPLIT_SURROGATE = 1 << 1,
305 : };
306 : using CharacterClassFlags = base::Flags<Flag>;
307 :
308 249073 : RegExpCharacterClass(
309 : Zone* zone, ZoneList<CharacterRange>* ranges, JSRegExp::Flags flags,
310 : CharacterClassFlags character_class_flags = CharacterClassFlags())
311 : : set_(ranges),
312 : flags_(flags),
313 498146 : character_class_flags_(character_class_flags) {
314 : // Convert the empty set of ranges to the negated Everything() range.
315 249073 : if (ranges->is_empty()) {
316 383 : ranges->Add(CharacterRange::Everything(), zone);
317 : character_class_flags_ ^= NEGATED;
318 : }
319 249073 : }
320 : RegExpCharacterClass(uc16 type, JSRegExp::Flags flags)
321 : : set_(type),
322 : flags_(flags),
323 166038 : character_class_flags_(CharacterClassFlags()) {}
324 : void* Accept(RegExpVisitor* visitor, void* data) override;
325 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
326 : RegExpCharacterClass* AsCharacterClass() override;
327 : bool IsCharacterClass() override;
328 178974 : bool IsTextElement() override { return true; }
329 229294 : int min_match() override { return 1; }
330 : // The character class may match two code units for unicode regexps.
331 : // TODO(yangguo): we should split this class for usage in TextElement, and
332 : // make max_match() dependent on the character class content.
333 110334 : int max_match() override { return 2; }
334 : void AppendToText(RegExpText* text, Zone* zone) override;
335 : CharacterSet character_set() { return set_; }
336 : // TODO(lrn): Remove need for complex version if is_standard that
337 : // recognizes a mangled standard set and just do { return set_.is_special(); }
338 : bool is_standard(Zone* zone);
339 : // Returns a value representing the standard character set if is_standard()
340 : // returns true.
341 : // Currently used values are:
342 : // s : unicode whitespace
343 : // S : unicode non-whitespace
344 : // w : ASCII word character (digit, letter, underscore)
345 : // W : non-ASCII word character
346 : // d : ASCII digit
347 : // D : non-ASCII digit
348 : // . : non-newline
349 : // * : All characters, for advancing unanchored regexp
350 : uc16 standard_type() const { return set_.standard_set_type(); }
351 805235 : ZoneList<CharacterRange>* ranges(Zone* zone) { return set_.ranges(zone); }
352 : bool is_negated() const { return (character_class_flags_ & NEGATED) != 0; }
353 : JSRegExp::Flags flags() const { return flags_; }
354 : bool contains_split_surrogate() const {
355 : return (character_class_flags_ & CONTAINS_SPLIT_SURROGATE) != 0;
356 : }
357 :
358 : private:
359 : CharacterSet set_;
360 : const JSRegExp::Flags flags_;
361 : CharacterClassFlags character_class_flags_;
362 : };
363 :
364 :
365 0 : class RegExpAtom final : public RegExpTree {
366 : public:
367 : explicit RegExpAtom(Vector<const uc16> data, JSRegExp::Flags flags)
368 1913217 : : data_(data), flags_(flags) {}
369 : void* Accept(RegExpVisitor* visitor, void* data) override;
370 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
371 : RegExpAtom* AsAtom() override;
372 : bool IsAtom() override;
373 73608 : bool IsTextElement() override { return true; }
374 6861640 : int min_match() override { return data_.length(); }
375 6106002 : int max_match() override { return data_.length(); }
376 : void AppendToText(RegExpText* text, Zone* zone) override;
377 : Vector<const uc16> data() { return data_; }
378 : int length() { return data_.length(); }
379 : JSRegExp::Flags flags() const { return flags_; }
380 : bool ignore_case() const { return (flags_ & JSRegExp::kIgnoreCase) != 0; }
381 :
382 : private:
383 : Vector<const uc16> data_;
384 : const JSRegExp::Flags flags_;
385 : };
386 :
387 :
388 0 : class RegExpText final : public RegExpTree {
389 : public:
390 75076 : explicit RegExpText(Zone* zone) : elements_(2, zone), length_(0) {}
391 : void* Accept(RegExpVisitor* visitor, void* data) override;
392 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
393 : RegExpText* AsText() override;
394 : bool IsText() override;
395 30 : bool IsTextElement() override { return true; }
396 35652 : int min_match() override { return length_; }
397 36814 : int max_match() override { return length_; }
398 : void AppendToText(RegExpText* text, Zone* zone) override;
399 : void AddElement(TextElement elm, Zone* zone) {
400 107024 : elements_.Add(elm, zone);
401 107024 : length_ += elm.length();
402 : }
403 18670 : ZoneList<TextElement>* elements() { return &elements_; }
404 :
405 : private:
406 : ZoneList<TextElement> elements_;
407 : int length_;
408 : };
409 :
410 :
411 0 : class RegExpQuantifier final : public RegExpTree {
412 : public:
413 : enum QuantifierType { GREEDY, NON_GREEDY, POSSESSIVE };
414 1451697 : RegExpQuantifier(int min, int max, QuantifierType type, RegExpTree* body)
415 : : body_(body),
416 : min_(min),
417 : max_(max),
418 1451697 : quantifier_type_(type) {
419 1451697 : if (min > 0 && body->min_match() > kInfinity / min) {
420 5 : min_match_ = kInfinity;
421 : } else {
422 1451692 : min_match_ = min * body->min_match();
423 : }
424 1451697 : if (max > 0 && body->max_match() > kInfinity / max) {
425 17731 : max_match_ = kInfinity;
426 : } else {
427 1433966 : max_match_ = max * body->max_match();
428 : }
429 1451697 : }
430 : void* Accept(RegExpVisitor* visitor, void* data) override;
431 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
432 : static RegExpNode* ToNode(int min, int max, bool is_greedy, RegExpTree* body,
433 : RegExpCompiler* compiler, RegExpNode* on_success,
434 : bool not_at_start = false);
435 : RegExpQuantifier* AsQuantifier() override;
436 : Interval CaptureRegisters() override;
437 : bool IsQuantifier() override;
438 1449220 : int min_match() override { return min_match_; }
439 1453168 : int max_match() override { return max_match_; }
440 : int min() { return min_; }
441 : int max() { return max_; }
442 : bool is_possessive() { return quantifier_type_ == POSSESSIVE; }
443 : bool is_non_greedy() { return quantifier_type_ == NON_GREEDY; }
444 926330 : bool is_greedy() { return quantifier_type_ == GREEDY; }
445 : RegExpTree* body() { return body_; }
446 :
447 : private:
448 : RegExpTree* body_;
449 : int min_;
450 : int max_;
451 : int min_match_;
452 : int max_match_;
453 : QuantifierType quantifier_type_;
454 : };
455 :
456 :
457 0 : class RegExpCapture final : public RegExpTree {
458 : public:
459 : explicit RegExpCapture(int index)
460 1082045 : : body_(nullptr), index_(index), name_(nullptr) {}
461 : void* Accept(RegExpVisitor* visitor, void* data) override;
462 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
463 : static RegExpNode* ToNode(RegExpTree* body, int index,
464 : RegExpCompiler* compiler, RegExpNode* on_success);
465 : RegExpCapture* AsCapture() override;
466 : bool IsAnchoredAtStart() override;
467 : bool IsAnchoredAtEnd() override;
468 : Interval CaptureRegisters() override;
469 : bool IsCapture() override;
470 54726 : int min_match() override { return body_->min_match(); }
471 69782 : int max_match() override { return body_->max_match(); }
472 : RegExpTree* body() { return body_; }
473 1082036 : void set_body(RegExpTree* body) { body_ = body; }
474 : int index() { return index_; }
475 : const ZoneVector<uc16>* name() const { return name_; }
476 1216 : void set_name(const ZoneVector<uc16>* name) { name_ = name; }
477 115301 : static int StartRegister(int index) { return index * 2; }
478 118681 : static int EndRegister(int index) { return index * 2 + 1; }
479 :
480 : private:
481 : RegExpTree* body_;
482 : int index_;
483 : const ZoneVector<uc16>* name_;
484 : };
485 :
486 0 : class RegExpGroup final : public RegExpTree {
487 : public:
488 19981 : explicit RegExpGroup(RegExpTree* body) : body_(body) {}
489 : void* Accept(RegExpVisitor* visitor, void* data) override;
490 10758 : RegExpNode* ToNode(RegExpCompiler* compiler,
491 : RegExpNode* on_success) override {
492 10758 : return body_->ToNode(compiler, on_success);
493 : }
494 : RegExpGroup* AsGroup() override;
495 277 : bool IsAnchoredAtStart() override { return body_->IsAnchoredAtStart(); }
496 271 : bool IsAnchoredAtEnd() override { return body_->IsAnchoredAtEnd(); }
497 : bool IsGroup() override;
498 23746 : int min_match() override { return body_->min_match(); }
499 22991 : int max_match() override { return body_->max_match(); }
500 11957 : Interval CaptureRegisters() override { return body_->CaptureRegisters(); }
501 : RegExpTree* body() { return body_; }
502 :
503 : private:
504 : RegExpTree* body_;
505 : };
506 :
507 0 : class RegExpLookaround final : public RegExpTree {
508 : public:
509 : enum Type { LOOKAHEAD, LOOKBEHIND };
510 :
511 : RegExpLookaround(RegExpTree* body, bool is_positive, int capture_count,
512 : int capture_from, Type type)
513 : : body_(body),
514 : is_positive_(is_positive),
515 : capture_count_(capture_count),
516 : capture_from_(capture_from),
517 3611 : type_(type) {}
518 :
519 : void* Accept(RegExpVisitor* visitor, void* data) override;
520 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
521 : RegExpLookaround* AsLookaround() override;
522 : Interval CaptureRegisters() override;
523 : bool IsLookaround() override;
524 : bool IsAnchoredAtStart() override;
525 3228 : int min_match() override { return 0; }
526 4590 : int max_match() override { return 0; }
527 : RegExpTree* body() { return body_; }
528 : bool is_positive() { return is_positive_; }
529 : int capture_count() { return capture_count_; }
530 : int capture_from() { return capture_from_; }
531 : Type type() { return type_; }
532 :
533 : class Builder {
534 : public:
535 : Builder(bool is_positive, RegExpNode* on_success,
536 : int stack_pointer_register, int position_register,
537 : int capture_register_count = 0, int capture_register_start = 0);
538 : RegExpNode* on_match_success() { return on_match_success_; }
539 : RegExpNode* ForMatch(RegExpNode* match);
540 :
541 : private:
542 : bool is_positive_;
543 : RegExpNode* on_match_success_;
544 : RegExpNode* on_success_;
545 : int stack_pointer_register_;
546 : int position_register_;
547 : };
548 :
549 : private:
550 : RegExpTree* body_;
551 : bool is_positive_;
552 : int capture_count_;
553 : int capture_from_;
554 : Type type_;
555 : };
556 :
557 :
558 0 : class RegExpBackReference final : public RegExpTree {
559 : public:
560 : explicit RegExpBackReference(JSRegExp::Flags flags)
561 285 : : capture_(nullptr), name_(nullptr), flags_(flags) {}
562 : RegExpBackReference(RegExpCapture* capture, JSRegExp::Flags flags)
563 4500 : : capture_(capture), name_(nullptr), flags_(flags) {}
564 : void* Accept(RegExpVisitor* visitor, void* data) override;
565 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
566 : RegExpBackReference* AsBackReference() override;
567 : bool IsBackReference() override;
568 4746 : int min_match() override { return 0; }
569 : // The back reference may be recursive, e.g. /(\2)(\1)/. To avoid infinite
570 : // recursion, we give up. Ignorance is bliss.
571 6573 : int max_match() override { return kInfinity; }
572 : int index() { return capture_->index(); }
573 : RegExpCapture* capture() { return capture_; }
574 185 : void set_capture(RegExpCapture* capture) { capture_ = capture; }
575 : const ZoneVector<uc16>* name() const { return name_; }
576 285 : void set_name(const ZoneVector<uc16>* name) { name_ = name; }
577 :
578 : private:
579 : RegExpCapture* capture_;
580 : const ZoneVector<uc16>* name_;
581 : const JSRegExp::Flags flags_;
582 : };
583 :
584 :
585 0 : class RegExpEmpty final : public RegExpTree {
586 : public:
587 330133 : RegExpEmpty() = default;
588 : void* Accept(RegExpVisitor* visitor, void* data) override;
589 : RegExpNode* ToNode(RegExpCompiler* compiler, RegExpNode* on_success) override;
590 : RegExpEmpty* AsEmpty() override;
591 : bool IsEmpty() override;
592 1784 : int min_match() override { return 0; }
593 2064 : int max_match() override { return 0; }
594 : };
595 :
596 : } // namespace internal
597 : } // namespace v8
598 :
599 : #endif // V8_REGEXP_REGEXP_AST_H_
|