| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 private: | 284 private: |
| 285 ZoneList<T*>* list_; | 285 ZoneList<T*>* list_; |
| 286 T* last_; | 286 T* last_; |
| 287 }; | 287 }; |
| 288 | 288 |
| 289 // Accumulates RegExp atoms and assertions into lists of terms and alternatives. | 289 // Accumulates RegExp atoms and assertions into lists of terms and alternatives. |
| 290 class RegExpBuilder { | 290 class RegExpBuilder { |
| 291 public: | 291 public: |
| 292 RegExpBuilder(); | 292 RegExpBuilder(); |
| 293 void AddCharacter(uc16 character); | 293 void AddCharacter(uc16 character); |
| 294 // "Adds" an empty expression. Does nothing except consume a |
| 295 // following quantifier |
| 296 void AddEmpty(); |
| 294 void AddAtom(RegExpTree* tree); | 297 void AddAtom(RegExpTree* tree); |
| 295 void AddAssertion(RegExpTree* tree); | 298 void AddAssertion(RegExpTree* tree); |
| 296 void NewAlternative(); // '|' | 299 void NewAlternative(); // '|' |
| 297 void AddQuantifierToAtom(int min, int max, bool is_greedy); | 300 void AddQuantifierToAtom(int min, int max, bool is_greedy); |
| 298 RegExpTree* ToRegExp(); | 301 RegExpTree* ToRegExp(); |
| 299 private: | 302 private: |
| 300 void FlushCharacters(); | 303 void FlushCharacters(); |
| 301 bool FlushTerms(); | 304 bool FlushTerms(); |
| 305 bool pending_empty_; |
| 302 ZoneList<uc16>* characters_; | 306 ZoneList<uc16>* characters_; |
| 303 BufferedZoneList<RegExpTree, 2> terms_; | 307 BufferedZoneList<RegExpTree, 2> terms_; |
| 304 BufferedZoneList<RegExpTree, 2> alternatives_; | 308 BufferedZoneList<RegExpTree, 2> alternatives_; |
| 305 #ifdef DEBUG | 309 #ifdef DEBUG |
| 306 enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_; | 310 enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_; |
| 307 #define LAST(x) last_added_ = x; | 311 #define LAST(x) last_added_ = x; |
| 308 #else | 312 #else |
| 309 #define LAST(x) | 313 #define LAST(x) |
| 310 #endif | 314 #endif |
| 311 }; | 315 }; |
| 312 | 316 |
| 313 | 317 |
| 314 RegExpBuilder::RegExpBuilder() : characters_(NULL), terms_(), alternatives_() | 318 RegExpBuilder::RegExpBuilder() |
| 319 : pending_empty_(false), characters_(NULL), terms_(), alternatives_() |
| 315 #ifdef DEBUG | 320 #ifdef DEBUG |
| 316 , last_added_(ADD_NONE) | 321 , last_added_(ADD_NONE) |
| 317 #endif | 322 #endif |
| 318 {} | 323 {} |
| 319 | 324 |
| 320 | 325 |
| 321 void RegExpBuilder::FlushCharacters() { | 326 void RegExpBuilder::FlushCharacters() { |
| 327 pending_empty_ = false; |
| 322 if (characters_ != NULL) { | 328 if (characters_ != NULL) { |
| 323 RegExpTree* atom = new RegExpAtom(characters_->ToConstVector()); | 329 RegExpTree* atom = new RegExpAtom(characters_->ToConstVector()); |
| 324 characters_ = NULL; | 330 characters_ = NULL; |
| 325 terms_.Add(atom); | 331 terms_.Add(atom); |
| 326 LAST(ADD_ATOM); | 332 LAST(ADD_ATOM); |
| 327 } | 333 } |
| 328 } | 334 } |
| 329 | 335 |
| 330 | 336 |
| 331 void RegExpBuilder::AddCharacter(uc16 c) { | 337 void RegExpBuilder::AddCharacter(uc16 c) { |
| 338 pending_empty_ = false; |
| 332 if (characters_ == NULL) { | 339 if (characters_ == NULL) { |
| 333 characters_ = new ZoneList<uc16>(4); | 340 characters_ = new ZoneList<uc16>(4); |
| 334 } | 341 } |
| 335 characters_->Add(c); | 342 characters_->Add(c); |
| 336 LAST(ADD_CHAR); | 343 LAST(ADD_CHAR); |
| 337 } | 344 } |
| 338 | 345 |
| 339 | 346 |
| 347 void RegExpBuilder::AddEmpty() { |
| 348 pending_empty_ = true; |
| 349 } |
| 350 |
| 351 |
| 340 void RegExpBuilder::AddAtom(RegExpTree* atom) { | 352 void RegExpBuilder::AddAtom(RegExpTree* atom) { |
| 341 FlushCharacters(); | 353 FlushCharacters(); |
| 342 terms_.Add(atom); | 354 terms_.Add(atom); |
| 343 LAST(ADD_ATOM); | 355 LAST(ADD_ATOM); |
| 344 } | 356 } |
| 345 | 357 |
| 346 | 358 |
| 347 void RegExpBuilder::AddAssertion(RegExpTree* assert) { | 359 void RegExpBuilder::AddAssertion(RegExpTree* assert) { |
| 348 FlushCharacters(); | 360 FlushCharacters(); |
| 349 terms_.Add(assert); | 361 terms_.Add(assert); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 return RegExpEmpty::GetInstance(); | 396 return RegExpEmpty::GetInstance(); |
| 385 } | 397 } |
| 386 if (num_alternatives == 1) { | 398 if (num_alternatives == 1) { |
| 387 return alternatives_.last(); | 399 return alternatives_.last(); |
| 388 } | 400 } |
| 389 return new RegExpDisjunction(alternatives_.GetList()); | 401 return new RegExpDisjunction(alternatives_.GetList()); |
| 390 } | 402 } |
| 391 | 403 |
| 392 | 404 |
| 393 void RegExpBuilder::AddQuantifierToAtom(int min, int max, bool is_greedy) { | 405 void RegExpBuilder::AddQuantifierToAtom(int min, int max, bool is_greedy) { |
| 406 if (pending_empty_) { |
| 407 pending_empty_ = false; |
| 408 return; |
| 409 } |
| 394 RegExpTree* atom; | 410 RegExpTree* atom; |
| 395 if (characters_ != NULL) { | 411 if (characters_ != NULL) { |
| 396 ASSERT(last_added_ == ADD_CHAR); | 412 ASSERT(last_added_ == ADD_CHAR); |
| 397 // Last atom was character. | 413 // Last atom was character. |
| 398 Vector<const uc16> char_vector = characters_->ToConstVector(); | 414 Vector<const uc16> char_vector = characters_->ToConstVector(); |
| 399 int num_chars = char_vector.length(); | 415 int num_chars = char_vector.length(); |
| 400 if (num_chars > 1) { | 416 if (num_chars > 1) { |
| 401 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1); | 417 Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1); |
| 402 terms_.Add(new RegExpAtom(prefix)); | 418 terms_.Add(new RegExpAtom(prefix)); |
| 403 char_vector = char_vector.SubVector(num_chars - 1, num_chars); | 419 char_vector = char_vector.SubVector(num_chars - 1, num_chars); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 // on the input stream. After pushing it back, it becomes the character | 474 // on the input stream. After pushing it back, it becomes the character |
| 459 // returned by current(). There is a limited amount of push-back buffer. | 475 // returned by current(). There is a limited amount of push-back buffer. |
| 460 // A function using PushBack should check that it doesn't push back more | 476 // A function using PushBack should check that it doesn't push back more |
| 461 // than kMaxPushback characters, and it should not push back more characters | 477 // than kMaxPushback characters, and it should not push back more characters |
| 462 // than it has read. | 478 // than it has read. |
| 463 void PushBack(uc32 character); | 479 void PushBack(uc32 character); |
| 464 bool CanPushBack(); | 480 bool CanPushBack(); |
| 465 | 481 |
| 466 bool HasCharacterEscapes(); | 482 bool HasCharacterEscapes(); |
| 467 | 483 |
| 468 int captures_started() { return captures_started_; } | 484 int captures_started() { return captures_ == NULL ? 0 : captures_->length(); } |
| 469 | 485 |
| 470 static const uc32 kEndMarker = unibrow::Utf8::kBadChar; | 486 static const uc32 kEndMarker = unibrow::Utf8::kBadChar; |
| 471 private: | 487 private: |
| 472 uc32 current() { return current_; } | 488 uc32 current() { return current_; } |
| 473 uc32 next() { return next_; } | 489 uc32 next() { return next_; } |
| 474 bool has_more() { return has_more_; } | 490 bool has_more() { return has_more_; } |
| 475 bool has_next() { return has_next_; } | 491 bool has_next() { return has_next_; } |
| 476 unibrow::CharacterStream* in() { return in_; } | 492 unibrow::CharacterStream* in() { return in_; } |
| 477 uc32 current_; | 493 uc32 current_; |
| 478 uc32 next_; | 494 uc32 next_; |
| 479 bool has_more_; | 495 bool has_more_; |
| 480 bool has_next_; | 496 bool has_next_; |
| 481 bool multiline_mode_; | 497 bool multiline_mode_; |
| 482 int captures_started_; | |
| 483 unibrow::CharacterStream* in_; | 498 unibrow::CharacterStream* in_; |
| 484 Handle<String>* error_; | 499 Handle<String>* error_; |
| 485 static const int kMaxPushback = 5; | 500 static const int kMaxPushback = 5; |
| 486 int pushback_count_; | 501 int pushback_count_; |
| 487 uc32 pushback_buffer_[kMaxPushback]; | 502 uc32 pushback_buffer_[kMaxPushback]; |
| 488 bool has_character_escapes_; | 503 bool has_character_escapes_; |
| 504 ZoneList<RegExpCapture*>* captures_; |
| 489 }; | 505 }; |
| 490 | 506 |
| 491 | 507 |
| 492 // A temporary scope stores information during parsing, just like | 508 // A temporary scope stores information during parsing, just like |
| 493 // a plain scope. However, temporary scopes are not kept around | 509 // a plain scope. However, temporary scopes are not kept around |
| 494 // after parsing or referenced by syntax trees so they can be stack- | 510 // after parsing or referenced by syntax trees so they can be stack- |
| 495 // allocated and hence used by the pre-parser. | 511 // allocated and hence used by the pre-parser. |
| 496 class TemporaryScope BASE_EMBEDDED { | 512 class TemporaryScope BASE_EMBEDDED { |
| 497 public: | 513 public: |
| 498 explicit TemporaryScope(Parser* parser); | 514 explicit TemporaryScope(Parser* parser); |
| (...skipping 2931 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3430 | 3446 |
| 3431 | 3447 |
| 3432 RegExpParser::RegExpParser(unibrow::CharacterStream* in, | 3448 RegExpParser::RegExpParser(unibrow::CharacterStream* in, |
| 3433 Handle<String>* error, | 3449 Handle<String>* error, |
| 3434 bool multiline_mode) | 3450 bool multiline_mode) |
| 3435 : current_(kEndMarker), | 3451 : current_(kEndMarker), |
| 3436 next_(kEndMarker), | 3452 next_(kEndMarker), |
| 3437 has_more_(true), | 3453 has_more_(true), |
| 3438 has_next_(true), | 3454 has_next_(true), |
| 3439 multiline_mode_(multiline_mode), | 3455 multiline_mode_(multiline_mode), |
| 3440 captures_started_(0), | |
| 3441 in_(in), | 3456 in_(in), |
| 3442 error_(error), | 3457 error_(error), |
| 3443 pushback_count_(0), | 3458 pushback_count_(0), |
| 3444 has_character_escapes_(false) { | 3459 has_character_escapes_(false), |
| 3460 captures_(NULL) { |
| 3445 Advance(2); | 3461 Advance(2); |
| 3446 } | 3462 } |
| 3447 | 3463 |
| 3448 | 3464 |
| 3449 void RegExpParser::Advance() { | 3465 void RegExpParser::Advance() { |
| 3450 current_ = next_; | 3466 current_ = next_; |
| 3451 has_more_ = has_next_; | 3467 has_more_ = has_next_; |
| 3452 if (pushback_count_ > 0) { | 3468 if (pushback_count_ > 0) { |
| 3453 pushback_count_--; | 3469 pushback_count_--; |
| 3454 next_ = pushback_buffer_[pushback_count_]; | 3470 next_ = pushback_buffer_[pushback_count_]; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3516 // Alternative | Disjunction | 3532 // Alternative | Disjunction |
| 3517 // Alternative :: | 3533 // Alternative :: |
| 3518 // [empty] | 3534 // [empty] |
| 3519 // Term Alternative | 3535 // Term Alternative |
| 3520 // Term :: | 3536 // Term :: |
| 3521 // Assertion | 3537 // Assertion |
| 3522 // Atom | 3538 // Atom |
| 3523 // Atom Quantifier | 3539 // Atom Quantifier |
| 3524 RegExpTree* RegExpParser::ParseDisjunction(bool* ok) { | 3540 RegExpTree* RegExpParser::ParseDisjunction(bool* ok) { |
| 3525 RegExpBuilder builder; | 3541 RegExpBuilder builder; |
| 3542 int capture_start_index = captures_started(); |
| 3526 while (true) { | 3543 while (true) { |
| 3527 switch (current()) { | 3544 switch (current()) { |
| 3528 case kEndMarker: | 3545 case kEndMarker: |
| 3529 case ')': | 3546 case ')': |
| 3530 return builder.ToRegExp(); | 3547 return builder.ToRegExp(); |
| 3531 case '|': | 3548 case '|': { |
| 3532 Advance(); | 3549 Advance(); |
| 3533 builder.NewAlternative(); | 3550 builder.NewAlternative(); |
| 3551 int capture_new_alt_start_index = captures_started(); |
| 3552 for (int i = capture_start_index; i < capture_new_alt_start_index; i++) { |
| 3553 RegExpCapture* capture = captures_->at(i); |
| 3554 if (capture->available() == CAPTURE_AVAILABLE) { |
| 3555 capture->set_available(CAPTURE_UNREACHABLE); |
| 3556 } |
| 3557 } |
| 3558 capture_start_index = capture_new_alt_start_index; |
| 3534 continue; | 3559 continue; |
| 3560 } |
| 3535 case '*': | 3561 case '*': |
| 3536 case '+': | 3562 case '+': |
| 3537 case '?': | 3563 case '?': |
| 3538 case '{': | 3564 case '{': |
| 3539 ReportError(CStrVector("Nothing to repeat."), CHECK_OK); | 3565 ReportError(CStrVector("Nothing to repeat."), CHECK_OK); |
| 3540 case '^': { | 3566 case '^': { |
| 3541 Advance(); | 3567 Advance(); |
| 3542 RegExpAssertion::Type type = | 3568 RegExpAssertion::Type type = |
| 3543 multiline_mode_ ? RegExpAssertion::START_OF_LINE : | 3569 multiline_mode_ ? RegExpAssertion::START_OF_LINE : |
| 3544 RegExpAssertion::START_OF_INPUT; | 3570 RegExpAssertion::START_OF_INPUT; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3599 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); | 3625 ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2); |
| 3600 CharacterRange::AddClassEscape(c, ranges); | 3626 CharacterRange::AddClassEscape(c, ranges); |
| 3601 RegExpTree* atom = new RegExpCharacterClass(ranges, false); | 3627 RegExpTree* atom = new RegExpCharacterClass(ranges, false); |
| 3602 builder.AddAtom(atom); | 3628 builder.AddAtom(atom); |
| 3603 goto has_read_atom; // Avoid setting has_character_escapes_. | 3629 goto has_read_atom; // Avoid setting has_character_escapes_. |
| 3604 } | 3630 } |
| 3605 case '1': case '2': case '3': case '4': case '5': case '6': | 3631 case '1': case '2': case '3': case '4': case '5': case '6': |
| 3606 case '7': case '8': case '9': { | 3632 case '7': case '8': case '9': { |
| 3607 int index = 0; | 3633 int index = 0; |
| 3608 if (ParseBackreferenceIndex(&index)) { | 3634 if (ParseBackreferenceIndex(&index)) { |
| 3609 RegExpTree* atom = new RegExpBackreference(index); | 3635 RegExpCapture* capture = captures_->at(index - 1); |
| 3636 if (capture == NULL || capture->available() != CAPTURE_AVAILABLE) { |
| 3637 // Prepare to ignore a following quantifier |
| 3638 builder.AddEmpty(); |
| 3639 goto has_read_atom; |
| 3640 } |
| 3641 RegExpTree* atom = new RegExpBackreference(capture); |
| 3610 builder.AddAtom(atom); | 3642 builder.AddAtom(atom); |
| 3611 goto has_read_atom; // Avoid setting has_character_escapes_. | 3643 goto has_read_atom; // Avoid setting has_character_escapes_. |
| 3612 } | 3644 } |
| 3613 uc32 first_digit = next(); | 3645 uc32 first_digit = next(); |
| 3614 if (first_digit == '8' || first_digit == '9') { | 3646 if (first_digit == '8' || first_digit == '9') { |
| 3615 // Treat as identity escape | 3647 // Treat as identity escape |
| 3616 builder.AddCharacter(first_digit); | 3648 builder.AddCharacter(first_digit); |
| 3617 Advance(2); | 3649 Advance(2); |
| 3618 break; | 3650 break; |
| 3619 } | 3651 } |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3768 | 3800 |
| 3769 bool RegExpParser::ParseBackreferenceIndex(int* index_out) { | 3801 bool RegExpParser::ParseBackreferenceIndex(int* index_out) { |
| 3770 ASSERT_EQ('\\', current()); | 3802 ASSERT_EQ('\\', current()); |
| 3771 ASSERT('1' <= next() && next() <= '9'); | 3803 ASSERT('1' <= next() && next() <= '9'); |
| 3772 ASSERT_EQ(0, pushback_count_); | 3804 ASSERT_EQ(0, pushback_count_); |
| 3773 // Try to parse a decimal literal that is no greater than the number | 3805 // Try to parse a decimal literal that is no greater than the number |
| 3774 // of previously encountered left capturing parentheses. | 3806 // of previously encountered left capturing parentheses. |
| 3775 // This is a not according the the ECMAScript specification. According to | 3807 // This is a not according the the ECMAScript specification. According to |
| 3776 // that, one must accept values up to the total number of left capturing | 3808 // that, one must accept values up to the total number of left capturing |
| 3777 // parentheses in the entire input, even if they are meaningless. | 3809 // parentheses in the entire input, even if they are meaningless. |
| 3778 if (captures_started_ == 0) | 3810 if (captures_ == NULL) |
| 3779 return false; | 3811 return false; |
| 3780 int value = next() - '0'; | 3812 int value = next() - '0'; |
| 3781 if (value > captures_started_) | 3813 if (value > captures_->length()) |
| 3782 return false; | 3814 return false; |
| 3783 static const int kMaxChars = kMaxPushback - 2; | 3815 static const int kMaxChars = kMaxPushback - 2; |
| 3784 EmbeddedVector<uc32, kMaxChars> chars_seen; | 3816 EmbeddedVector<uc32, kMaxChars> chars_seen; |
| 3785 chars_seen[0] = next(); | 3817 chars_seen[0] = next(); |
| 3786 int char_count = 1; | 3818 int char_count = 1; |
| 3787 Advance(2); | 3819 Advance(2); |
| 3788 while (true) { | 3820 while (true) { |
| 3789 uc32 c = current(); | 3821 uc32 c = current(); |
| 3790 if (IsDecimalDigit(c)) { | 3822 if (IsDecimalDigit(c)) { |
| 3791 value = 10 * value + (c - '0'); | 3823 value = 10 * value + (c - '0'); |
| 3792 // To avoid reading past the end of the stack-allocated pushback | 3824 // To avoid reading past the end of the stack-allocated pushback |
| 3793 // buffers we only read kMaxChars before giving up. | 3825 // buffers we only read kMaxChars before giving up. |
| 3794 if (value > captures_started_ || char_count > kMaxChars) { | 3826 if (value > captures_->length() || char_count > kMaxChars) { |
| 3795 // If we give up we have to push the characters we read back | 3827 // If we give up we have to push the characters we read back |
| 3796 // onto the pushback buffer in the reverse order. | 3828 // onto the pushback buffer in the reverse order. |
| 3797 for (int i = 0; i < char_count; i++) { | 3829 for (int i = 0; i < char_count; i++) { |
| 3798 PushBack(chars_seen[char_count - i - 1]); | 3830 PushBack(chars_seen[char_count - i - 1]); |
| 3799 } | 3831 } |
| 3800 PushBack('\\'); | 3832 PushBack('\\'); |
| 3801 return false; | 3833 return false; |
| 3802 } | 3834 } |
| 3803 chars_seen[char_count++] = current(); | 3835 chars_seen[char_count++] = current(); |
| 3804 Advance(); | 3836 Advance(); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3998 switch (next()) { | 4030 switch (next()) { |
| 3999 case ':': case '=': case '!': | 4031 case ':': case '=': case '!': |
| 4000 type = next(); | 4032 type = next(); |
| 4001 Advance(2); | 4033 Advance(2); |
| 4002 break; | 4034 break; |
| 4003 default: | 4035 default: |
| 4004 ReportError(CStrVector("Invalid group"), CHECK_OK); | 4036 ReportError(CStrVector("Invalid group"), CHECK_OK); |
| 4005 break; | 4037 break; |
| 4006 } | 4038 } |
| 4007 } else { | 4039 } else { |
| 4008 captures_started_++; | 4040 if (captures_ == NULL) { |
| 4041 captures_ = new ZoneList<RegExpCapture*>(2); |
| 4042 } |
| 4043 captures_->Add(NULL); |
| 4009 } | 4044 } |
| 4010 int capture_index = captures_started_; | 4045 int capture_index = captures_started(); |
| 4011 RegExpTree* body = ParseDisjunction(CHECK_OK); | 4046 RegExpTree* body = ParseDisjunction(CHECK_OK); |
| 4012 if (current() != ')') { | 4047 if (current() != ')') { |
| 4013 ReportError(CStrVector("Unterminated group"), CHECK_OK); | 4048 ReportError(CStrVector("Unterminated group"), CHECK_OK); |
| 4014 } | 4049 } |
| 4015 Advance(); | 4050 Advance(); |
| 4051 |
| 4052 int end_capture_index = captures_started(); |
| 4053 if (type == '!') { |
| 4054 // Captures inside a negative lookahead are never available outside it. |
| 4055 for (int i = capture_index; i < end_capture_index; i++) { |
| 4056 RegExpCapture* capture = captures_->at(i); |
| 4057 ASSERT(capture != NULL); |
| 4058 capture->set_available(CAPTURE_PERMANENTLY_UNREACHABLE); |
| 4059 } |
| 4060 } else { |
| 4061 // Captures temporarily unavailable because they are in different |
| 4062 // alternatives are all available after the disjunction. |
| 4063 for (int i = capture_index; i < end_capture_index; i++) { |
| 4064 RegExpCapture* capture = captures_->at(i); |
| 4065 ASSERT(capture != NULL); |
| 4066 if (capture->available() == CAPTURE_UNREACHABLE) { |
| 4067 capture->set_available(CAPTURE_AVAILABLE); |
| 4068 } |
| 4069 } |
| 4070 } |
| 4071 |
| 4016 if (type == '(') { | 4072 if (type == '(') { |
| 4017 return new RegExpCapture(body, capture_index); | 4073 RegExpCapture* capture = new RegExpCapture(body, capture_index); |
| 4074 captures_->at(capture_index - 1) = capture; |
| 4075 return capture; |
| 4018 } else if (type == ':') { | 4076 } else if (type == ':') { |
| 4019 return body; | 4077 return body; |
| 4020 } else { | 4078 } else { |
| 4021 ASSERT(type == '=' || type == '!'); | 4079 ASSERT(type == '=' || type == '!'); |
| 4022 bool is_positive = (type == '='); | 4080 bool is_positive = (type == '='); |
| 4023 return new RegExpLookahead(body, is_positive); | 4081 return new RegExpLookahead(body, is_positive); |
| 4024 } | 4082 } |
| 4025 } | 4083 } |
| 4026 | 4084 |
| 4027 | 4085 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4086 } else { | 4144 } else { |
| 4087 ranges->Add(first); | 4145 ranges->Add(first); |
| 4088 } | 4146 } |
| 4089 } | 4147 } |
| 4090 } | 4148 } |
| 4091 if (!has_more()) { | 4149 if (!has_more()) { |
| 4092 return ReportError(CStrVector(kUnterminated), CHECK_OK); | 4150 return ReportError(CStrVector(kUnterminated), CHECK_OK); |
| 4093 } | 4151 } |
| 4094 Advance(); | 4152 Advance(); |
| 4095 if (ranges->length() == 0) { | 4153 if (ranges->length() == 0) { |
| 4096 return RegExpEmpty::GetInstance(); | 4154 ranges->Add(CharacterRange::Range(0, 0xffff)); |
| 4097 } else { | 4155 is_negated = !is_negated; |
| 4098 return new RegExpCharacterClass(ranges, is_negated); | |
| 4099 } | 4156 } |
| 4157 return new RegExpCharacterClass(ranges, is_negated); |
| 4100 } | 4158 } |
| 4101 | 4159 |
| 4102 | 4160 |
| 4103 // ---------------------------------------------------------------------------- | 4161 // ---------------------------------------------------------------------------- |
| 4104 // The Parser interface. | 4162 // The Parser interface. |
| 4105 | 4163 |
| 4106 // MakeAST() is just a wrapper for the corresponding Parser calls | 4164 // MakeAST() is just a wrapper for the corresponding Parser calls |
| 4107 // so we don't have to expose the entire Parser class in the .h file. | 4165 // so we don't have to expose the entire Parser class in the .h file. |
| 4108 | 4166 |
| 4109 static bool always_allow_natives_syntax = false; | 4167 static bool always_allow_natives_syntax = false; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4214 start_position, | 4272 start_position, |
| 4215 is_expression); | 4273 is_expression); |
| 4216 return result; | 4274 return result; |
| 4217 } | 4275 } |
| 4218 | 4276 |
| 4219 | 4277 |
| 4220 #undef NEW | 4278 #undef NEW |
| 4221 | 4279 |
| 4222 | 4280 |
| 4223 } } // namespace v8::internal | 4281 } } // namespace v8::internal |
| OLD | NEW |