blob: dbeb6e23ebedbef5be48e47bddc766d1b1b9fdb3 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_JSREGEXP_H_
29#define V8_JSREGEXP_H_
30
31namespace v8 { namespace internal {
32
ager@chromium.orga74f0da2008-12-03 16:05:52 +000033
34class RegExpMacroAssembler;
35
36
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037class RegExpImpl {
38 public:
39 // Creates a regular expression literal in the old space.
40 // This function calls the garbage collector if necessary.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041 static Handle<Object> CreateRegExpLiteral(Handle<JSFunction> constructor,
42 Handle<String> pattern,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043 Handle<String> flags,
44 bool* has_pending_exception);
45
46 // Returns a string representation of a regular expression.
47 // Implements RegExp.prototype.toString, see ECMA-262 section 15.10.6.4.
48 // This function calls the garbage collector if necessary.
49 static Handle<String> ToString(Handle<Object> value);
50
ager@chromium.org8bb60582008-12-11 12:02:20 +000051 // Parses the RegExp pattern and prepares the JSRegExp object with
52 // generic data and choice of implementation - as well as what
53 // the implementation wants to store in the data field.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000054 static Handle<Object> Compile(Handle<JSRegExp> re,
55 Handle<String> pattern,
56 Handle<String> flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
58 // Implements RegExp.prototype.exec(string) function.
59 // See ECMA-262 section 15.10.6.2.
60 // This function calls the garbage collector if necessary.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000061 static Handle<Object> Exec(Handle<JSRegExp> regexp,
62 Handle<String> subject,
63 Handle<Object> index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65 // Call RegExp.prototyp.exec(string) in a loop.
66 // Used by String.prototype.match and String.prototype.replace.
67 // This function calls the garbage collector if necessary.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000068 static Handle<Object> ExecGlobal(Handle<JSRegExp> regexp,
69 Handle<String> subject);
70
ager@chromium.orga74f0da2008-12-03 16:05:52 +000071 // Stores an uncompiled RegExp pattern in the JSRegExp object.
72 // It will be compiled by JSCRE when first executed.
73 static Handle<Object> JscrePrepare(Handle<JSRegExp> re,
74 Handle<String> pattern,
75 JSRegExp::Flags flags);
76
ager@chromium.org8bb60582008-12-11 12:02:20 +000077 // Prepares a JSRegExp object with Irregexp-specific data.
ager@chromium.orga74f0da2008-12-03 16:05:52 +000078 static Handle<Object> IrregexpPrepare(Handle<JSRegExp> re,
79 Handle<String> pattern,
ager@chromium.org8bb60582008-12-11 12:02:20 +000080 JSRegExp::Flags flags);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000081
82
83 // Compile the pattern using JSCRE and store the result in the
84 // JSRegExp object.
85 static Handle<Object> JscreCompile(Handle<JSRegExp> re);
86
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000087 static Handle<Object> AtomCompile(Handle<JSRegExp> re,
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000088 Handle<String> pattern,
ager@chromium.orga74f0da2008-12-03 16:05:52 +000089 JSRegExp::Flags flags,
90 Handle<String> match_pattern);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000091 static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
92 Handle<String> subject,
93 Handle<Object> index);
94
95 static Handle<Object> AtomExecGlobal(Handle<JSRegExp> regexp,
96 Handle<String> subject);
97
ager@chromium.orga74f0da2008-12-03 16:05:52 +000098 static Handle<Object> JscreCompile(Handle<JSRegExp> re,
99 Handle<String> pattern,
100 JSRegExp::Flags flags);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000101
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000102 // Execute a compiled JSCRE pattern.
103 static Handle<Object> JscreExec(Handle<JSRegExp> regexp,
104 Handle<String> subject,
105 Handle<Object> index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000106
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000107 // Execute an Irregexp bytecode pattern.
108 static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
109 Handle<String> subject,
110 Handle<Object> index);
111
112 static Handle<Object> JscreExecGlobal(Handle<JSRegExp> regexp,
113 Handle<String> subject);
114
115 static Handle<Object> IrregexpExecGlobal(Handle<JSRegExp> regexp,
116 Handle<String> subject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117
118 static void NewSpaceCollectionPrologue();
119 static void OldSpaceCollectionPrologue();
120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 // Converts a source string to a 16 bit flat string. The string
122 // will be either sequential or it will be a SlicedString backed
123 // by a flat string.
124 static Handle<String> StringToTwoByte(Handle<String> pattern);
125 static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
126
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000127 static const int kIrregexpImplementationIndex = 0;
128 static const int kIrregexpNumberOfCapturesIndex = 1;
129 static const int kIrregexpNumberOfRegistersIndex = 2;
130 static const int kIrregexpCodeIndex = 3;
131 static const int kIrregexpDataLength = 4;
132
133 static const int kJscreNumberOfCapturesIndex = 0;
134 static const int kJscreInternalIndex = 1;
135 static const int kJscreDataLength = 2;
136
137 private:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138 static String* last_ascii_string_;
139 static String* two_byte_cached_string_;
140
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000141 static int JscreNumberOfCaptures(Handle<JSRegExp> re);
142 static ByteArray* JscreInternal(Handle<JSRegExp> re);
143
ager@chromium.org8bb60582008-12-11 12:02:20 +0000144 static int IrregexpNumberOfCaptures(Handle<FixedArray> re);
145 static int IrregexpNumberOfRegisters(Handle<FixedArray> re);
146 static Handle<ByteArray> IrregexpByteCode(Handle<FixedArray> re);
147 static Handle<Code> IrregexpNativeCode(Handle<FixedArray> re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148
149 // Call jsRegExpExecute once
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000150 static Handle<Object> JscreExecOnce(Handle<JSRegExp> regexp,
151 int num_captures,
152 Handle<String> subject,
153 int previous_index,
154 const uc16* utf8_subject,
155 int* ovector,
156 int ovector_length);
157
ager@chromium.org8bb60582008-12-11 12:02:20 +0000158 static Handle<Object> IrregexpExecOnce(Handle<FixedArray> regexp,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000159 int num_captures,
160 Handle<String> subject16,
161 int previous_index,
162 int* ovector,
163 int ovector_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164
165 // Set the subject cache. The previous string buffer is not deleted, so the
166 // caller should ensure that it doesn't leak.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000167 static void SetSubjectCache(String* subject,
168 char* utf8_subject,
169 int uft8_length,
170 int character_position,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000171 int utf8_position);
172
173 // A one element cache of the last utf8_subject string and its length. The
174 // subject JS String object is cached in the heap. We also cache a
175 // translation between position and utf8 position.
176 static char* utf8_subject_cache_;
177 static int utf8_length_cache_;
178 static int utf8_position_;
179 static int character_position_;
180};
181
182
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000183class CharacterRange {
184 public:
185 CharacterRange() : from_(0), to_(0) { }
186 // For compatibility with the CHECK_OK macro
187 CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT
188 CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { }
189 static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges);
190 static Vector<const uc16> GetWordBounds();
191 static inline CharacterRange Singleton(uc16 value) {
192 return CharacterRange(value, value);
193 }
194 static inline CharacterRange Range(uc16 from, uc16 to) {
195 ASSERT(from <= to);
196 return CharacterRange(from, to);
197 }
198 static inline CharacterRange Everything() {
199 return CharacterRange(0, 0xFFFF);
200 }
201 bool Contains(uc16 i) { return from_ <= i && i <= to_; }
202 uc16 from() const { return from_; }
203 void set_from(uc16 value) { from_ = value; }
204 uc16 to() const { return to_; }
205 void set_to(uc16 value) { to_ = value; }
206 bool is_valid() { return from_ <= to_; }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000207 bool IsEverything(uc16 max) { return from_ == 0 && to_ >= max; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000208 bool IsSingleton() { return (from_ == to_); }
209 void AddCaseEquivalents(ZoneList<CharacterRange>* ranges);
210 static void Split(ZoneList<CharacterRange>* base,
211 Vector<const uc16> overlay,
212 ZoneList<CharacterRange>** included,
213 ZoneList<CharacterRange>** excluded);
214
215 static const int kRangeCanonicalizeMax = 0x346;
216 static const int kStartMarker = (1 << 24);
217 static const int kPayloadMask = (1 << 24) - 1;
218
219 private:
220 uc16 from_;
221 uc16 to_;
222};
223
224
225template <typename Node, class Callback>
226static void DoForEach(Node* node, Callback* callback);
227
228
229// A zone splay tree. The config type parameter encapsulates the
230// different configurations of a concrete splay tree:
231//
232// typedef Key: the key type
233// typedef Value: the value type
234// static const kNoKey: the dummy key used when no key is set
235// static const kNoValue: the dummy value used to initialize nodes
236// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
237//
238template <typename Config>
239class ZoneSplayTree : public ZoneObject {
240 public:
241 typedef typename Config::Key Key;
242 typedef typename Config::Value Value;
243
244 class Locator;
245
246 ZoneSplayTree() : root_(NULL) { }
247
248 // Inserts the given key in this tree with the given value. Returns
249 // true if a node was inserted, otherwise false. If found the locator
250 // is enabled and provides access to the mapping for the key.
251 bool Insert(const Key& key, Locator* locator);
252
253 // Looks up the key in this tree and returns true if it was found,
254 // otherwise false. If the node is found the locator is enabled and
255 // provides access to the mapping for the key.
256 bool Find(const Key& key, Locator* locator);
257
258 // Finds the mapping with the greatest key less than or equal to the
259 // given key.
260 bool FindGreatestLessThan(const Key& key, Locator* locator);
261
262 // Find the mapping with the greatest key in this tree.
263 bool FindGreatest(Locator* locator);
264
265 // Finds the mapping with the least key greater than or equal to the
266 // given key.
267 bool FindLeastGreaterThan(const Key& key, Locator* locator);
268
269 // Find the mapping with the least key in this tree.
270 bool FindLeast(Locator* locator);
271
272 // Remove the node with the given key from the tree.
273 bool Remove(const Key& key);
274
275 bool is_empty() { return root_ == NULL; }
276
277 // Perform the splay operation for the given key. Moves the node with
278 // the given key to the top of the tree. If no node has the given
279 // key, the last node on the search path is moved to the top of the
280 // tree.
281 void Splay(const Key& key);
282
283 class Node : public ZoneObject {
284 public:
285 Node(const Key& key, const Value& value)
286 : key_(key),
287 value_(value),
288 left_(NULL),
289 right_(NULL) { }
290 Key key() { return key_; }
291 Value value() { return value_; }
292 Node* left() { return left_; }
293 Node* right() { return right_; }
294 private:
295 friend class ZoneSplayTree;
296 friend class Locator;
297 Key key_;
298 Value value_;
299 Node* left_;
300 Node* right_;
301 };
302
303 // A locator provides access to a node in the tree without actually
304 // exposing the node.
305 class Locator {
306 public:
307 explicit Locator(Node* node) : node_(node) { }
308 Locator() : node_(NULL) { }
309 const Key& key() { return node_->key_; }
310 Value& value() { return node_->value_; }
311 void set_value(const Value& value) { node_->value_ = value; }
312 inline void bind(Node* node) { node_ = node; }
313 private:
314 Node* node_;
315 };
316
317 template <class Callback>
318 void ForEach(Callback* c) {
319 DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
320 }
321
322 private:
323 Node* root_;
324};
325
326
327// A set of unsigned integers that behaves especially well on small
328// integers (< 32). May do zone-allocation.
329class OutSet: public ZoneObject {
330 public:
331 OutSet() : first_(0), remaining_(NULL), successors_(NULL) { }
332 OutSet* Extend(unsigned value);
333 bool Get(unsigned value);
334 static const unsigned kFirstLimit = 32;
335
336 private:
337 // Destructively set a value in this set. In most cases you want
338 // to use Extend instead to ensure that only one instance exists
339 // that contains the same values.
340 void Set(unsigned value);
341
342 // The successors are a list of sets that contain the same values
343 // as this set and the one more value that is not present in this
344 // set.
345 ZoneList<OutSet*>* successors() { return successors_; }
346
347 OutSet(uint32_t first, ZoneList<unsigned>* remaining)
348 : first_(first), remaining_(remaining), successors_(NULL) { }
349 uint32_t first_;
350 ZoneList<unsigned>* remaining_;
351 ZoneList<OutSet*>* successors_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000352 friend class GenerationVariant;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000353};
354
355
356// A mapping from integers, specified as ranges, to a set of integers.
357// Used for mapping character ranges to choices.
358class DispatchTable : public ZoneObject {
359 public:
360 class Entry {
361 public:
362 Entry() : from_(0), to_(0), out_set_(NULL) { }
363 Entry(uc16 from, uc16 to, OutSet* out_set)
364 : from_(from), to_(to), out_set_(out_set) { }
365 uc16 from() { return from_; }
366 uc16 to() { return to_; }
367 void set_to(uc16 value) { to_ = value; }
368 void AddValue(int value) { out_set_ = out_set_->Extend(value); }
369 OutSet* out_set() { return out_set_; }
370 private:
371 uc16 from_;
372 uc16 to_;
373 OutSet* out_set_;
374 };
375
376 class Config {
377 public:
378 typedef uc16 Key;
379 typedef Entry Value;
380 static const uc16 kNoKey;
381 static const Entry kNoValue;
382 static inline int Compare(uc16 a, uc16 b) {
383 if (a == b)
384 return 0;
385 else if (a < b)
386 return -1;
387 else
388 return 1;
389 }
390 };
391
392 void AddRange(CharacterRange range, int value);
393 OutSet* Get(uc16 value);
394 void Dump();
395
396 template <typename Callback>
397 void ForEach(Callback* callback) { return tree()->ForEach(callback); }
398 private:
399 // There can't be a static empty set since it allocates its
400 // successors in a zone and caches them.
401 OutSet* empty() { return &empty_; }
402 OutSet empty_;
403 ZoneSplayTree<Config>* tree() { return &tree_; }
404 ZoneSplayTree<Config> tree_;
405};
406
407
408#define FOR_EACH_NODE_TYPE(VISIT) \
409 VISIT(End) \
410 VISIT(Action) \
411 VISIT(Choice) \
412 VISIT(BackReference) \
413 VISIT(Text)
414
415
416#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
417 VISIT(Disjunction) \
418 VISIT(Alternative) \
419 VISIT(Assertion) \
420 VISIT(CharacterClass) \
421 VISIT(Atom) \
422 VISIT(Quantifier) \
423 VISIT(Capture) \
424 VISIT(Lookahead) \
425 VISIT(BackReference) \
426 VISIT(Empty) \
427 VISIT(Text)
428
429
430#define FORWARD_DECLARE(Name) class RegExp##Name;
431FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
432#undef FORWARD_DECLARE
433
434
435class TextElement {
436 public:
437 enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
438 TextElement() : type(UNINITIALIZED) { }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000439 explicit TextElement(Type t) : type(t), cp_offset(-1) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000440 static TextElement Atom(RegExpAtom* atom);
441 static TextElement CharClass(RegExpCharacterClass* char_class);
442 Type type;
443 union {
444 RegExpAtom* u_atom;
445 RegExpCharacterClass* u_char_class;
446 } data;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000447 int cp_offset;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000448};
449
450
ager@chromium.org8bb60582008-12-11 12:02:20 +0000451class GenerationVariant;
452
453
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000454struct NodeInfo {
455 enum TriBool {
456 UNKNOWN = -1, FALSE = 0, TRUE = 1
457 };
458
459 NodeInfo()
460 : being_analyzed(false),
461 been_analyzed(false),
462 being_expanded(false),
463 been_expanded(false),
464 determine_word(false),
465 determine_newline(false),
466 determine_start(false),
467 does_determine_word(false),
468 does_determine_newline(false),
469 does_determine_start(false),
470 follows_word_interest(false),
471 follows_newline_interest(false),
472 follows_start_interest(false),
473 is_word(UNKNOWN),
474 is_newline(UNKNOWN),
475 at_end(false),
476 follows_word(UNKNOWN),
477 follows_newline(UNKNOWN),
478 follows_start(UNKNOWN),
479 visited(false) { }
480
481 // Returns true if the interests and assumptions of this node
482 // matches the given one.
483 bool Matches(NodeInfo* that) {
484 return (at_end == that->at_end) &&
485 (follows_word_interest == that->follows_word_interest) &&
486 (follows_newline_interest == that->follows_newline_interest) &&
487 (follows_start_interest == that->follows_start_interest) &&
488 (follows_word == that->follows_word) &&
489 (follows_newline == that->follows_newline) &&
490 (follows_start == that->follows_start) &&
491 (does_determine_word == that->does_determine_word) &&
492 (does_determine_newline == that->does_determine_newline) &&
493 (does_determine_start == that->does_determine_start);
494 }
495
496 bool HasAssertions() {
497 return (follows_word != UNKNOWN) ||
498 (follows_newline != UNKNOWN) ||
499 (follows_start != UNKNOWN);
500 }
501
502 // Updates the interests of this node given the interests of the
503 // node preceding it.
504 void AddFromPreceding(NodeInfo* that) {
505 at_end |= that->at_end;
506 follows_word_interest |= that->follows_word_interest;
507 follows_newline_interest |= that->follows_newline_interest;
508 follows_start_interest |= that->follows_start_interest;
509 }
510
511 void AddAssumptions(NodeInfo* that) {
512 if (that->follows_word != UNKNOWN) {
513 ASSERT(follows_word == UNKNOWN || follows_word == that->follows_word);
514 follows_word = that->follows_word;
515 }
516 if (that->follows_newline != UNKNOWN) {
517 ASSERT(follows_newline == UNKNOWN ||
518 follows_newline == that->follows_newline);
519 follows_newline = that->follows_newline;
520 }
521 if (that->follows_start != UNKNOWN) {
522 ASSERT(follows_start == UNKNOWN ||
523 follows_start == that->follows_start);
524 follows_start = that->follows_start;
525 }
526 does_determine_word = that->does_determine_word;
527 does_determine_newline = that->does_determine_newline;
528 does_determine_start = that->does_determine_start;
529 }
530
ager@chromium.org8bb60582008-12-11 12:02:20 +0000531 bool HasLookbehind() {
532 return follows_word_interest ||
533 follows_newline_interest ||
534 follows_start_interest;
535 }
536
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000537 // Sets the interests of this node to include the interests of the
538 // following node.
539 void AddFromFollowing(NodeInfo* that) {
540 follows_word_interest |= that->follows_word_interest;
541 follows_newline_interest |= that->follows_newline_interest;
542 follows_start_interest |= that->follows_start_interest;
543 }
544
545 void ResetCompilationState() {
546 being_analyzed = false;
547 been_analyzed = false;
548 being_expanded = false;
549 been_expanded = false;
550 }
551
552 bool being_analyzed: 1;
553 bool been_analyzed: 1;
554 bool being_expanded: 1;
555 bool been_expanded: 1;
556
557 // These bits are set if this node must propagate forward information
558 // about the last character it consumed (or, in the case of 'start',
559 // if it is at the start of the input).
560 bool determine_word: 1;
561 bool determine_newline: 1;
562 bool determine_start: 1;
563
564 bool does_determine_word: 1;
565 bool does_determine_newline: 1;
566 bool does_determine_start: 1;
567
568 // These bits are set of this node has to know what the preceding
569 // character was.
570 bool follows_word_interest: 1;
571 bool follows_newline_interest: 1;
572 bool follows_start_interest: 1;
573
574 TriBool is_word: 2;
575 TriBool is_newline: 2;
576
577 bool at_end: 1;
578
579 // These bits are set if the node can make assumptions about what
580 // the previous character was.
581 TriBool follows_word: 2;
582 TriBool follows_newline: 2;
583 TriBool follows_start: 2;
584
585 bool visited: 1;
586};
587
588
589class ExpansionGuard {
590 public:
591 explicit inline ExpansionGuard(NodeInfo* info) : info_(info) {
592 ASSERT(!info->being_expanded);
593 info->being_expanded = true;
594 }
595 inline ~ExpansionGuard() {
596 info_->being_expanded = false;
597 }
598 private:
599 NodeInfo* info_;
600};
601
602
603class SiblingList {
604 public:
605 SiblingList() : list_(NULL) { }
606 int length() {
607 return list_ == NULL ? 0 : list_->length();
608 }
609 void Ensure(RegExpNode* parent) {
610 if (list_ == NULL) {
611 list_ = new ZoneList<RegExpNode*>(2);
612 list_->Add(parent);
613 }
614 }
615 void Add(RegExpNode* node) { list_->Add(node); }
616 RegExpNode* Get(int index) { return list_->at(index); }
617 private:
618 ZoneList<RegExpNode*>* list_;
619};
620
621
622class RegExpNode: public ZoneObject {
623 public:
ager@chromium.org8bb60582008-12-11 12:02:20 +0000624 RegExpNode() : variants_generated_(0) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000625 virtual ~RegExpNode() { }
626 virtual void Accept(NodeVisitor* visitor) = 0;
627 // Generates a goto to this node or actually generates the code at this point.
628 // Until the implementation is complete we will return true for success and
629 // false for failure.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000630 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant) = 0;
631 static const int kNodeIsTooComplexForGreedyLoops = -1;
632 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
633 Label* label() { return &label_; }
634 static const int kMaxVariantsGenerated = 10;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000635
636 RegExpNode* EnsureExpanded(NodeInfo* info);
637 virtual RegExpNode* ExpandLocal(NodeInfo* info) = 0;
638 virtual void ExpandChildren() = 0;
639
640 // Propagates the given interest information forward. When seeing
641 // \bfoo for instance, the \b is implemented by propagating forward
642 // to the 'foo' string that it should only succeed if its first
643 // character is a letter xor the previous character was a letter.
644 virtual RegExpNode* PropagateForward(NodeInfo* info) = 0;
645
646 NodeInfo* info() { return &info_; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000647
648 void AddSibling(RegExpNode* node) { siblings_.Add(node); }
649
650 // Static version of EnsureSibling that expresses the fact that the
651 // result has the same type as the input.
652 template <class C>
653 static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) {
654 return static_cast<C*>(node->EnsureSibling(info, cloned));
655 }
656
657 SiblingList* siblings() { return &siblings_; }
658 void set_siblings(SiblingList* other) { siblings_ = *other; }
659
660 protected:
ager@chromium.org8bb60582008-12-11 12:02:20 +0000661 enum LimitResult { DONE, FAIL, CONTINUE };
662 LimitResult LimitVersions(RegExpCompiler* compiler,
663 GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000664
665 // Returns a sibling of this node whose interests and assumptions
666 // match the ones in the given node info. If no sibling exists NULL
667 // is returned.
668 RegExpNode* TryGetSibling(NodeInfo* info);
669
670 // Returns a sibling of this node whose interests match the ones in
671 // the given node info. The info must not contain any assertions.
672 // If no node exists a new one will be created by cloning the current
673 // node. The result will always be an instance of the same concrete
674 // class as this node.
675 RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned);
676
677 // Returns a clone of this node initialized using the copy constructor
678 // of its concrete class. Note that the node may have to be pre-
679 // processed before it is on a useable state.
680 virtual RegExpNode* Clone() = 0;
681
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000682 private:
683 Label label_;
684 NodeInfo info_;
685 SiblingList siblings_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000686 int variants_generated_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000687};
688
689
690class SeqRegExpNode: public RegExpNode {
691 public:
692 explicit SeqRegExpNode(RegExpNode* on_success)
693 : on_success_(on_success) { }
694 RegExpNode* on_success() { return on_success_; }
695 void set_on_success(RegExpNode* node) { on_success_ = node; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000696 private:
697 RegExpNode* on_success_;
698};
699
700
701class ActionNode: public SeqRegExpNode {
702 public:
703 enum Type {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000704 SET_REGISTER,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000705 INCREMENT_REGISTER,
706 STORE_POSITION,
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000707 BEGIN_SUBMATCH,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000708 POSITIVE_SUBMATCH_SUCCESS
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000709 };
ager@chromium.org8bb60582008-12-11 12:02:20 +0000710 static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000711 static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
712 static ActionNode* StorePosition(int reg, RegExpNode* on_success);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000713 static ActionNode* BeginSubmatch(
714 int stack_pointer_reg,
715 int position_reg,
716 RegExpNode* on_success);
717 static ActionNode* PositiveSubmatchSuccess(
718 int stack_pointer_reg,
719 int restore_reg,
720 RegExpNode* on_success);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000721 virtual void Accept(NodeVisitor* visitor);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000722 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000723 virtual RegExpNode* ExpandLocal(NodeInfo* info);
724 virtual void ExpandChildren();
725 virtual RegExpNode* PropagateForward(NodeInfo* info);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000726 Type type() { return type_; }
727 // TODO(erikcorry): We should allow some action nodes in greedy loops.
728 virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoops; }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000729 virtual ActionNode* Clone() { return new ActionNode(*this); }
730
731 private:
732 union {
733 struct {
734 int reg;
735 int value;
736 } u_store_register;
737 struct {
738 int reg;
739 } u_increment_register;
740 struct {
741 int reg;
742 } u_position_register;
743 struct {
744 int stack_pointer_register;
745 int current_position_register;
746 } u_submatch;
747 } data_;
748 ActionNode(Type type, RegExpNode* on_success)
749 : SeqRegExpNode(on_success),
750 type_(type) { }
751 Type type_;
752 friend class DotPrinter;
753};
754
755
756class TextNode: public SeqRegExpNode {
757 public:
758 TextNode(ZoneList<TextElement>* elms,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000759 RegExpNode* on_success)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000760 : SeqRegExpNode(on_success),
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000761 elms_(elms) { }
762 TextNode(RegExpCharacterClass* that,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000763 RegExpNode* on_success)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000764 : SeqRegExpNode(on_success),
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000765 elms_(new ZoneList<TextElement>(1)) {
766 elms_->Add(TextElement::CharClass(that));
767 }
768 virtual void Accept(NodeVisitor* visitor);
769 virtual RegExpNode* PropagateForward(NodeInfo* info);
770 virtual RegExpNode* ExpandLocal(NodeInfo* info);
771 virtual void ExpandChildren();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000772 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000773 ZoneList<TextElement>* elements() { return elms_; }
774 void MakeCaseIndependent();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000775 virtual int GreedyLoopTextLength();
776 virtual TextNode* Clone() {
777 TextNode* result = new TextNode(*this);
778 result->CalculateOffsets();
779 return result;
780 }
781 void CalculateOffsets();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000782 private:
783 void ExpandAtomChildren(RegExpAtom* that);
784 void ExpandCharClassChildren(RegExpCharacterClass* that);
785
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000786 ZoneList<TextElement>* elms_;
787};
788
789
790class BackReferenceNode: public SeqRegExpNode {
791 public:
792 BackReferenceNode(int start_reg,
793 int end_reg,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000794 RegExpNode* on_success)
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000795 : SeqRegExpNode(on_success),
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000796 start_reg_(start_reg),
797 end_reg_(end_reg) { }
798 virtual void Accept(NodeVisitor* visitor);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000799 int start_register() { return start_reg_; }
800 int end_register() { return end_reg_; }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000801 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000802 virtual RegExpNode* PropagateForward(NodeInfo* info);
803 virtual RegExpNode* ExpandLocal(NodeInfo* info);
804 virtual void ExpandChildren();
805 virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
806
807 private:
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000808 int start_reg_;
809 int end_reg_;
810};
811
812
813class EndNode: public RegExpNode {
814 public:
ager@chromium.org8bb60582008-12-11 12:02:20 +0000815 enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000816 explicit EndNode(Action action) : action_(action) { }
817 virtual void Accept(NodeVisitor* visitor);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000818 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000819 virtual RegExpNode* PropagateForward(NodeInfo* info);
820 virtual RegExpNode* ExpandLocal(NodeInfo* info);
821 virtual void ExpandChildren();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000822 virtual EndNode* Clone() { return new EndNode(*this); }
823
ager@chromium.org8bb60582008-12-11 12:02:20 +0000824 protected:
825 void EmitInfoChecks(RegExpMacroAssembler* macro, GenerationVariant* variant);
826
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000827 private:
828 Action action_;
829};
830
831
ager@chromium.org8bb60582008-12-11 12:02:20 +0000832class NegativeSubmatchSuccess: public EndNode {
833 public:
834 NegativeSubmatchSuccess(int stack_pointer_reg, int position_reg)
835 : EndNode(NEGATIVE_SUBMATCH_SUCCESS),
836 stack_pointer_register_(stack_pointer_reg),
837 current_position_register_(position_reg) { }
838 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
839
840 private:
841 int stack_pointer_register_;
842 int current_position_register_;
843};
844
845
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000846class Guard: public ZoneObject {
847 public:
848 enum Relation { LT, GEQ };
849 Guard(int reg, Relation op, int value)
850 : reg_(reg),
851 op_(op),
852 value_(value) { }
853 int reg() { return reg_; }
854 Relation op() { return op_; }
855 int value() { return value_; }
856
857 private:
858 int reg_;
859 Relation op_;
860 int value_;
861};
862
863
864class GuardedAlternative {
865 public:
866 explicit GuardedAlternative(RegExpNode* node) : node_(node), guards_(NULL) { }
867 void AddGuard(Guard* guard);
868 RegExpNode* node() { return node_; }
869 void set_node(RegExpNode* node) { node_ = node; }
870 ZoneList<Guard*>* guards() { return guards_; }
871
872 private:
873 RegExpNode* node_;
874 ZoneList<Guard*>* guards_;
875};
876
877
878class ChoiceNode: public RegExpNode {
879 public:
ager@chromium.org8bb60582008-12-11 12:02:20 +0000880 explicit ChoiceNode(int expected_size)
881 : alternatives_(new ZoneList<GuardedAlternative>(expected_size)),
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000882 table_(NULL),
883 being_calculated_(false) { }
884 virtual void Accept(NodeVisitor* visitor);
885 void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); }
886 ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
887 DispatchTable* GetTable(bool ignore_case);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000888 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000889 virtual RegExpNode* PropagateForward(NodeInfo* info);
890 virtual RegExpNode* ExpandLocal(NodeInfo* info);
891 virtual void ExpandChildren();
892 virtual ChoiceNode* Clone() { return new ChoiceNode(*this); }
893
894 bool being_calculated() { return being_calculated_; }
895 void set_being_calculated(bool b) { being_calculated_ = b; }
896
ager@chromium.org8bb60582008-12-11 12:02:20 +0000897 protected:
898 int GreedyLoopTextLength(GuardedAlternative *alternative);
899 ZoneList<GuardedAlternative>* alternatives_;
900
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000901 private:
902 friend class DispatchTableConstructor;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000903 friend class AssertionPropagation;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000904 void GenerateGuard(RegExpMacroAssembler* macro_assembler,
905 Guard *guard,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000906 GenerationVariant* variant);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000907 DispatchTable* table_;
908 bool being_calculated_;
909};
910
911
ager@chromium.org8bb60582008-12-11 12:02:20 +0000912class LoopChoiceNode: public ChoiceNode {
913 public:
914 explicit LoopChoiceNode(int expected_size) : ChoiceNode(expected_size) { }
915 virtual bool Emit(RegExpCompiler* compiler, GenerationVariant* variant);
916 virtual LoopChoiceNode* Clone() { return new LoopChoiceNode(*this); }
917};
918
919
920// There are many ways to generate code for a node. This class encapsulates
921// the current way we should be generating. In other words it encapsulates
922// the current state of the code generator.
923class GenerationVariant {
924 public:
925 class DeferredAction {
926 public:
927 DeferredAction(ActionNode::Type type, int reg)
928 : type_(type), reg_(reg), next_(NULL) { }
929 DeferredAction* next() { return next_; }
930 int reg() { return reg_; }
931 ActionNode::Type type() { return type_; }
932 private:
933 ActionNode::Type type_;
934 int reg_;
935 DeferredAction* next_;
936 friend class GenerationVariant;
937 };
938
939 class DeferredCapture: public DeferredAction {
940 public:
941 DeferredCapture(int reg, GenerationVariant* variant)
942 : DeferredAction(ActionNode::STORE_POSITION, reg),
943 cp_offset_(variant->cp_offset()) { }
944 int cp_offset() { return cp_offset_; }
945 private:
946 int cp_offset_;
947 void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
948 };
949
950 class DeferredSetRegister :public DeferredAction {
951 public:
952 DeferredSetRegister(int reg, int value)
953 : DeferredAction(ActionNode::SET_REGISTER, reg),
954 value_(value) { }
955 int value() { return value_; }
956 private:
957 int value_;
958 };
959
960 class DeferredIncrementRegister: public DeferredAction {
961 public:
962 explicit DeferredIncrementRegister(int reg)
963 : DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { }
964 };
965
966 explicit GenerationVariant(Label* backtrack)
967 : cp_offset_(0),
968 actions_(NULL),
969 backtrack_(backtrack),
970 stop_node_(NULL),
971 loop_label_(NULL) { }
972 GenerationVariant()
973 : cp_offset_(0),
974 actions_(NULL),
975 backtrack_(NULL),
976 stop_node_(NULL),
977 loop_label_(NULL) { }
978 bool Flush(RegExpCompiler* compiler, RegExpNode* successor);
979 int cp_offset() { return cp_offset_; }
980 DeferredAction* actions() { return actions_; }
981 bool is_trivial() {
982 return backtrack_ == NULL && actions_ == NULL && cp_offset_ == 0;
983 }
984 Label* backtrack() { return backtrack_; }
985 Label* loop_label() { return loop_label_; }
986 RegExpNode* stop_node() { return stop_node_; }
987 // These set methods should be used only on new GenerationVariants - the
988 // intention is that GenerationVariants are immutable after creation.
989 void add_action(DeferredAction* new_action) {
990 ASSERT(new_action->next_ == NULL);
991 new_action->next_ = actions_;
992 actions_ = new_action;
993 }
994 void set_cp_offset(int new_cp_offset) {
995 ASSERT(new_cp_offset >= cp_offset_);
996 cp_offset_ = new_cp_offset;
997 }
998 void set_backtrack(Label* backtrack) { backtrack_ = backtrack; }
999 void set_stop_node(RegExpNode* node) { stop_node_ = node; }
1000 void set_loop_label(Label* label) { loop_label_ = label; }
1001 bool mentions_reg(int reg);
1002 private:
1003 int FindAffectedRegisters(OutSet* affected_registers);
1004 void PerformDeferredActions(RegExpMacroAssembler* macro,
1005 int max_register,
1006 OutSet& affected_registers);
1007 void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
1008 int max_register,
1009 OutSet& affected_registers);
1010 void PushAffectedRegisters(RegExpMacroAssembler* macro,
1011 int max_register,
1012 OutSet& affected_registers);
1013 int cp_offset_;
1014 DeferredAction* actions_;
1015 Label* backtrack_;
1016 RegExpNode* stop_node_;
1017 Label* loop_label_;
1018};
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001019class NodeVisitor {
1020 public:
1021 virtual ~NodeVisitor() { }
1022#define DECLARE_VISIT(Type) \
1023 virtual void Visit##Type(Type##Node* that) = 0;
1024FOR_EACH_NODE_TYPE(DECLARE_VISIT)
1025#undef DECLARE_VISIT
1026};
1027
1028
1029// Node visitor used to add the start set of the alternatives to the
1030// dispatch table of a choice node.
1031class DispatchTableConstructor: public NodeVisitor {
1032 public:
1033 DispatchTableConstructor(DispatchTable* table, bool ignore_case)
1034 : table_(table),
1035 choice_index_(-1),
1036 ignore_case_(ignore_case) { }
1037
1038 void BuildTable(ChoiceNode* node);
1039
1040 void AddRange(CharacterRange range) {
1041 table()->AddRange(range, choice_index_);
1042 }
1043
1044 void AddInverse(ZoneList<CharacterRange>* ranges);
1045
1046#define DECLARE_VISIT(Type) \
1047 virtual void Visit##Type(Type##Node* that);
1048FOR_EACH_NODE_TYPE(DECLARE_VISIT)
1049#undef DECLARE_VISIT
1050
1051 DispatchTable* table() { return table_; }
1052 void set_choice_index(int value) { choice_index_ = value; }
1053
1054 protected:
1055 DispatchTable *table_;
1056 int choice_index_;
1057 bool ignore_case_;
1058};
1059
1060
ager@chromium.org8bb60582008-12-11 12:02:20 +00001061// Assertion propagation moves information about assertions such as
1062// \b to the affected nodes. For instance, in /.\b./ information must
1063// be propagated to the first '.' that whatever follows needs to know
1064// if it matched a word or a non-word, and to the second '.' that it
1065// has to check if it succeeds a word or non-word. In this case the
1066// result will be something like:
1067//
1068// +-------+ +------------+
1069// | . | | . |
1070// +-------+ ---> +------------+
1071// | word? | | check word |
1072// +-------+ +------------+
1073//
1074// At a later phase all nodes that determine information for their
1075// following nodes are split into several 'sibling' nodes. In this
1076// case the first '.' is split into one node that only matches words
1077// and one that only matches non-words. The second '.' is also split,
1078// into one node that assumes that the previous character was a word
1079// character and one that assumes that is was non-word. In this case
1080// the result is
1081//
1082// +------------------+ +------------------+
1083// /--> | intersect(., \w) | ---> | intersect(., \W) |
1084// | +------------------+ +------------------+
1085// | | follows \w |
1086// | +------------------+
1087// --?
1088// | +------------------+ +------------------+
1089// \--> | intersect(., \W) | ---> | intersect(., \w) |
1090// +------------------+ +------------------+
1091// | follows \W |
1092// +------------------+
1093//
1094// This way we don't need to explicitly check the previous character
1095// but can always assume that whoever consumed the previous character
1096// has propagated the relevant information forward.
1097class AssertionPropagation: public NodeVisitor {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001098 public:
ager@chromium.org8bb60582008-12-11 12:02:20 +00001099 explicit AssertionPropagation(bool ignore_case)
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001100 : ignore_case_(ignore_case) { }
1101 void EnsureAnalyzed(RegExpNode* node);
1102
1103#define DECLARE_VISIT(Type) \
1104 virtual void Visit##Type(Type##Node* that);
1105FOR_EACH_NODE_TYPE(DECLARE_VISIT)
1106#undef DECLARE_VISIT
1107
1108 private:
1109 bool ignore_case_;
1110
ager@chromium.org8bb60582008-12-11 12:02:20 +00001111 DISALLOW_IMPLICIT_CONSTRUCTORS(AssertionPropagation);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001112};
1113
1114
ager@chromium.org8bb60582008-12-11 12:02:20 +00001115struct RegExpCompileData {
1116 RegExpCompileData()
1117 : tree(NULL),
1118 node(NULL),
1119 has_lookbehind(false),
1120 has_character_escapes(false),
1121 capture_count(0) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001122 RegExpTree* tree;
ager@chromium.org8bb60582008-12-11 12:02:20 +00001123 RegExpNode* node;
1124 bool has_lookbehind;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001125 bool has_character_escapes;
1126 Handle<String> error;
1127 int capture_count;
1128};
1129
1130
1131class RegExpEngine: public AllStatic {
1132 public:
ager@chromium.org8bb60582008-12-11 12:02:20 +00001133 static Handle<FixedArray> Compile(RegExpCompileData* input,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001134 bool ignore_case,
ager@chromium.org8bb60582008-12-11 12:02:20 +00001135 bool multiline,
1136 Handle<String> pattern,
1137 bool is_ascii);
1138
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001139 static void DotPrint(const char* label, RegExpNode* node, bool ignore_case);
1140};
1141
1142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001143} } // namespace v8::internal
1144
1145#endif // V8_JSREGEXP_H_