diff --git a/src/jsregexp.cc b/src/jsregexp.cc index 851700b71f..0e4dee19de 100644 --- a/src/jsregexp.cc +++ b/src/jsregexp.cc @@ -32,6 +32,7 @@ #include "jsregexp.h" #include "third_party/jscre/pcre.h" #include "platform.h" +#include "runtime.h" #include "top.h" namespace v8 { namespace internal { @@ -142,6 +143,117 @@ Handle RegExpImpl::StringToTwoByte(Handle pattern) { } +unibrow::Predicate is_reg_exp_special_char; + + +Handle RegExpImpl::Compile(Handle re, + Handle pattern, + Handle flags) { + bool is_atom = true; + for (int i = 0; is_atom && i < flags->length(); i++) { + if (flags->Get(i) == 'i') + is_atom = false; + } + for (int i = 0; is_atom && i < pattern->length(); i++) { + if (is_reg_exp_special_char.get(pattern->Get(i))) + is_atom = false; + } + Handle result; + if (is_atom) { + result = AtomCompile(re, pattern); + } else { + result = JsreCompile(re, pattern, flags); + } + + LOG(RegExpCompileEvent(re)); + return result; +} + + +Handle RegExpImpl::Exec(Handle regexp, + Handle subject, + Handle index) { + switch (regexp->type_tag()) { + case JSRegExp::JSCRE: + return JsreExec(regexp, subject, index); + case JSRegExp::ATOM: + return AtomExec(regexp, subject, index); + default: + UNREACHABLE(); + return Handle(); + } +} + + +Handle RegExpImpl::ExecGlobal(Handle regexp, + Handle subject) { + switch (regexp->type_tag()) { + case JSRegExp::JSCRE: + return JsreExecGlobal(regexp, subject); + case JSRegExp::ATOM: + return AtomExecGlobal(regexp, subject); + default: + UNREACHABLE(); + return Handle(); + } +} + + +Handle RegExpImpl::AtomCompile(Handle re, + Handle pattern) { + re->set_type_tag(JSRegExp::ATOM); + re->set_data(*pattern); + return re; +} + + +Handle RegExpImpl::AtomExec(Handle re, + Handle subject, + Handle index) { + Handle needle(String::cast(re->data())); + + uint32_t start_index; + if (!Array::IndexFromObject(*index, &start_index)) { + return Handle(Smi::FromInt(-1)); + } + + LOG(RegExpExecEvent(re, start_index, subject)); + int value = Runtime::StringMatchKmp(*subject, *needle, start_index); + if (value == -1) return Factory::null_value(); + Handle result = Factory::NewJSArray(2); + SetElement(result, 0, Handle(Smi::FromInt(value))); + SetElement(result, 1, Handle(Smi::FromInt(value + needle->length()))); + return result; +} + + +Handle RegExpImpl::AtomExecGlobal(Handle re, + Handle subject) { + Handle needle(String::cast(re->data())); + Handle result = Factory::NewJSArray(1); + bool keep_going = true; + int index = 0; + int match_count = 0; + int needle_length = needle->length(); + while (keep_going) { + LOG(RegExpExecEvent(re, index, subject)); + int value = Runtime::StringMatchKmp(*subject, *needle, index); + if (value == -1) break; + HandleScope scope; + int end = value + needle_length; + Handle pair = Factory::NewJSArray(2); + SetElement(pair, 0, Handle(Smi::FromInt(value))); + SetElement(pair, 1, Handle(Smi::FromInt(end))); + SetElement(result, match_count, pair); + match_count++; + index = end; + if (needle_length == 0) + index++; + } + return result; +} + + Handle RegExpImpl::JsreCompile(Handle re, Handle pattern, Handle flags) { @@ -206,8 +318,6 @@ Handle RegExpImpl::JsreCompile(Handle re, re->set_type_tag(JSRegExp::JSCRE); re->set_data(*value); - LOG(RegExpCompileEvent(re)); - return re; } @@ -260,7 +370,6 @@ Handle RegExpImpl::JsreExecOnce(Handle regexp, SetElement(result, i, Handle(Smi::FromInt(offsets_vector[i]))); SetElement(result, i+1, Handle(Smi::FromInt(offsets_vector[i+1]))); } - return result; } diff --git a/src/jsregexp.h b/src/jsregexp.h index 9fc15bc17d..75d5c91d4d 100644 --- a/src/jsregexp.h +++ b/src/jsregexp.h @@ -44,20 +44,41 @@ class RegExpImpl { // This function calls the garbage collector if necessary. static Handle ToString(Handle value); - static Handle JsreCompile(Handle re, - Handle pattern, - Handle flags); + static Handle Compile(Handle re, + Handle pattern, + Handle flags); // Implements RegExp.prototype.exec(string) function. // See ECMA-262 section 15.10.6.2. // This function calls the garbage collector if necessary. - static Handle JsreExec(Handle regexp, - Handle subject, - Handle index); + static Handle Exec(Handle regexp, + Handle subject, + Handle index); // Call RegExp.prototyp.exec(string) in a loop. // Used by String.prototype.match and String.prototype.replace. // This function calls the garbage collector if necessary. + static Handle ExecGlobal(Handle regexp, + Handle subject); + + static Handle AtomCompile(Handle re, + Handle pattern); + + static Handle AtomExec(Handle regexp, + Handle subject, + Handle index); + + static Handle AtomExecGlobal(Handle regexp, + Handle subject); + + static Handle JsreCompile(Handle re, + Handle pattern, + Handle flags); + + static Handle JsreExec(Handle regexp, + Handle subject, + Handle index); + static Handle JsreExecGlobal(Handle regexp, Handle subject); diff --git a/src/log.cc b/src/log.cc index 80b5454224..09b03cabbd 100644 --- a/src/log.cc +++ b/src/log.cc @@ -258,7 +258,7 @@ SlidingStateWindow* Logger::sliding_state_window_ = NULL; void Logger::Preamble(const char* content) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s", content); #endif @@ -267,7 +267,7 @@ void Logger::Preamble(const char* content) { void Logger::StringEvent(const char* name, const char* value) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,\"%s\"\n", name, value); #endif @@ -276,7 +276,7 @@ void Logger::StringEvent(const char* name, const char* value) { void Logger::IntEvent(const char* name, int value) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,%d\n", name, value); #endif @@ -360,6 +360,15 @@ void Logger::LogRegExpSource(Handle regexp) { Handle source_string = Handle::cast(source); SmartPointer cstring = source_string->ToWideCString(); + if (regexp->type()->IsSmi()) { + switch (regexp->type_tag()) { + case JSRegExp::ATOM: + fprintf(logfile_, "a"); + break; + default: + break; + } + } fprintf(logfile_, "/"); for (int i = 0, n = source_string->length(); i < n; i++) { uc16 c = cstring[i]; @@ -475,7 +484,7 @@ void Logger::ApiEntryCall(const char* name) { void Logger::NewEvent(const char* name, void* object, size_t size) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "new,%s,0x%x,%u\n", name, reinterpret_cast(object), @@ -486,7 +495,7 @@ void Logger::NewEvent(const char* name, void* object, size_t size) { void Logger::DeleteEvent(const char* name, void* object) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "delete,%s,0x%x\n", name, reinterpret_cast(object)); @@ -559,7 +568,7 @@ void Logger::CodeDeleteEvent(Address from) { void Logger::ResourceEvent(const char* name, const char* tag) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "%s,%s,", name, tag); @@ -616,7 +625,7 @@ void Logger::HeapSampleItemEvent(const char* type, int number, int bytes) { void Logger::DebugTag(const char* call_site_tag) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "debug-tag,%s\n", call_site_tag); #endif @@ -625,7 +634,7 @@ void Logger::DebugTag(const char* call_site_tag) { void Logger::DebugEvent(const char* event_type, Vector parameter) { #ifdef ENABLE_LOGGING_AND_PROFILING - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; StringBuilder s(parameter.length() + 1); for (int i = 0; i < parameter.length(); ++i) { s.AddCharacter(static_cast(parameter[i])); @@ -644,7 +653,7 @@ void Logger::DebugEvent(const char* event_type, Vector parameter) { #ifdef ENABLE_LOGGING_AND_PROFILING void Logger::TickEvent(TickSample* sample, bool overflow) { - if (logfile_ == NULL) return; + if (logfile_ == NULL || !FLAG_log) return; ScopedLock sl(mutex_); fprintf(logfile_, "tick,0x%x,0x%x,%d", sample->pc, sample->sp, static_cast(sample->state)); @@ -669,15 +678,12 @@ bool Logger::Setup() { // --prof implies --log-code. if (FLAG_prof) FLAG_log_code = true; - // Each of the individual log flags implies --log. Check after - // checking --log-all and --prof in case they set --log-code. - if (FLAG_log_api || FLAG_log_code || FLAG_log_gc || - FLAG_log_handles || FLAG_log_suspect || FLAG_log_regexp) { - FLAG_log = true; - } + bool open_log_file = FLAG_log || FLAG_log_api || FLAG_log_code + || FLAG_log_gc || FLAG_log_handles || FLAG_log_suspect + || FLAG_log_regexp; // If we're logging anything, we need to open the log file. - if (FLAG_log) { + if (open_log_file) { if (strcmp(FLAG_logfile, "-") == 0) { logfile_ = stdout; } else { diff --git a/src/objects-debug.cc b/src/objects-debug.cc index d28015307b..951575c212 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -630,7 +630,19 @@ void JSArray::JSArrayVerify() { void JSRegExp::JSRegExpVerify() { JSObjectVerify(); ASSERT(type()->IsSmi() || type()->IsUndefined()); - ASSERT(data()->IsUndefined() || data()->IsFixedArray()); + if (type()->IsSmi()) { + switch (type_tag()) { + case JSRegExp::JSCRE: + ASSERT(data()->IsFixedArray()); + break; + default: + ASSERT_EQ(JSRegExp::ATOM, type_tag()); + ASSERT(data()->IsString()); + break; + } + } else { + ASSERT(data()->IsUndefined()); + } } diff --git a/src/objects.h b/src/objects.h index 9566fcaca1..9aaa24b9ba 100644 --- a/src/objects.h +++ b/src/objects.h @@ -2813,7 +2813,7 @@ class JSValue: public JSObject { // Regular expressions class JSRegExp: public JSObject { public: - enum Type { JSCRE, INDEX_OF }; + enum Type { JSCRE, ATOM }; inline Type type_tag(); inline void set_type_tag(Type value); diff --git a/src/runtime.cc b/src/runtime.cc index 9ac04bb987..11cf22f51e 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -251,7 +251,7 @@ static Object* Runtime_RegExpCompile(Arguments args) { Handle pattern(raw_pattern); CONVERT_CHECKED(String, raw_flags, args[2]); Handle flags(raw_flags); - return *RegExpImpl::JsreCompile(re, pattern, flags); + return *RegExpImpl::Compile(re, pattern, flags); } @@ -704,7 +704,7 @@ static Object* Runtime_RegExpExec(Arguments args) { Handle subject(raw_subject); Handle index(args[2]); ASSERT(index->IsNumber()); - return *RegExpImpl::JsreExec(regexp, subject, index); + return *RegExpImpl::Exec(regexp, subject, index); } @@ -715,7 +715,7 @@ static Object* Runtime_RegExpExecGlobal(Arguments args) { Handle regexp(raw_regexp); CONVERT_CHECKED(String, raw_subject, args[1]); Handle subject(raw_subject); - return *RegExpImpl::JsreExecGlobal(regexp, subject); + return *RegExpImpl::ExecGlobal(regexp, subject); } @@ -942,23 +942,15 @@ static inline void ComputeKMPNextTable(String* pattern, int next_table[]) { } -static Object* Runtime_StringIndexOf(Arguments args) { - NoHandleAllocation ha; - ASSERT(args.length() == 3); - - CONVERT_CHECKED(String, sub, args[0]); - CONVERT_CHECKED(String, pat, args[1]); - Object* index = args[2]; - +int Runtime::StringMatchKmp(String* sub, String* pat, int start_index) { sub->TryFlatten(); pat->TryFlatten(); int subject_length = sub->length(); int pattern_length = pat->length(); - uint32_t start_index; - if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); - if (pattern_length == 0) return Smi::FromInt(start_index); + if (start_index > subject_length) return -1; + if (pattern_length == 0) return start_index; // Searching for one specific character is common. For one // character patterns the KMP algorithm is guaranteed to slow down @@ -967,10 +959,10 @@ static Object* Runtime_StringIndexOf(Arguments args) { uint16_t pattern_char = pat->Get(0); for (int i = start_index; i < subject_length; i++) { if (sub->Get(i) == pattern_char) { - return Smi::FromInt(i); + return i; } } - return Smi::FromInt(-1); + return -1; } // For small searches, KMP is not worth the setup overhead. @@ -983,10 +975,10 @@ static Object* Runtime_StringIndexOf(Arguments args) { for (int j = 1; j < pattern_length; j++) { if (pat->Get(j) != sub->Get(j + i)) break; - if (j == pattern_length - 1) return Smi::FromInt(i); + if (j == pattern_length - 1) return i; } } - return Smi::FromInt(-1); + return -1; } // For patterns with a larger length we use the KMP algorithm. @@ -1010,11 +1002,25 @@ static Object* Runtime_StringIndexOf(Arguments args) { subject_index++; if (pattern_index >= pattern_length) { DeleteArray(next_table); - return Smi::FromInt(subject_index - pattern_index); + return subject_index - pattern_index; } } DeleteArray(next_table); - return Smi::FromInt(-1); + return -1; +} + + +static Object* Runtime_StringIndexOf(Arguments args) { + NoHandleAllocation ha; + ASSERT(args.length() == 3); + + CONVERT_CHECKED(String, sub, args[0]); + CONVERT_CHECKED(String, pat, args[1]); + Object* index = args[2]; + uint32_t start_index; + if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1); + + return Smi::FromInt(Runtime::StringMatchKmp(sub, pat, start_index)); } diff --git a/src/runtime.h b/src/runtime.h index d78341e7c3..9349b81205 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -332,6 +332,8 @@ class Runtime : public AllStatic { // Get the runtime function with the given name. static Function* FunctionForName(const char* name); + static int StringMatchKmp(String* sub, String* pat, int index); + // TODO(1240886): The following three methods are *not* handle safe, // but accept handle arguments. This seems fragile. diff --git a/src/unicode.cc b/src/unicode.cc index 50dc92f1c0..2f70bd3e3e 100644 --- a/src/unicode.cc +++ b/src/unicode.cc @@ -25,7 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// This file was generated at 2008-09-08 11:13:45.862026 +// This file was generated at 2008-10-01 18:05:45.480436 #include "unicode-inl.h" #include @@ -659,6 +659,20 @@ bool LineTerminator::Is(uchar c) { } } +// RegExpSpecialChar: 'Rx' in point.properties + +static const uint16_t kRegExpSpecialCharTable0Size = 9; +static const uint16_t kRegExpSpecialCharTable0[9] = { 36, 32808, 43, 46, 63, 32859, 94, 32891, 125 }; // NOLINT +bool RegExpSpecialChar::Is(uchar c) { + int chunk_index = c >> 15; + switch (chunk_index) { + case 0: return LookupPredicate(kRegExpSpecialCharTable0, + kRegExpSpecialCharTable0Size, + c); + default: return false; + } +} + // CombiningMark: point.category in ['Mn', 'Mc'] static const uint16_t kCombiningMarkTable0Size = 214; @@ -796,7 +810,7 @@ int ToUppercase::Convert(uchar c, uchar UnicodeData::kMaxCodePoint = 1114109; int UnicodeData::GetByteCount() { - return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kTitlecaseTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kDecimalDigitTable0Size) + (sizeof(uint16_t) * kDecimalDigitTable1Size) + (sizeof(uint16_t) * kDecimalDigitTable2Size) + (sizeof(uint16_t) * kDecimalDigitTable3Size) + (sizeof(uint16_t) * kIdeographicTable0Size) + (sizeof(uint16_t) * kIdeographicTable1Size) + (sizeof(uint16_t) * kIdeographicTable4Size) + (sizeof(uint16_t) * kIdeographicTable5Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kHexDigitTable0Size) + (sizeof(uint16_t) * kHexDigitTable1Size) + (sizeof(uint16_t) * kAsciiHexDigitTable0Size) + (sizeof(uint16_t) * kBidiControlTable0Size) + (sizeof(uint16_t) * kJoinControlTable0Size) + (sizeof(uint16_t) * kDashTable0Size) + (sizeof(uint16_t) * kDashTable1Size) + (sizeof(uint16_t) * kHyphenTable0Size) + (sizeof(uint16_t) * kHyphenTable1Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size); // NOLINT + return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kTitlecaseTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kDecimalDigitTable0Size) + (sizeof(uint16_t) * kDecimalDigitTable1Size) + (sizeof(uint16_t) * kDecimalDigitTable2Size) + (sizeof(uint16_t) * kDecimalDigitTable3Size) + (sizeof(uint16_t) * kIdeographicTable0Size) + (sizeof(uint16_t) * kIdeographicTable1Size) + (sizeof(uint16_t) * kIdeographicTable4Size) + (sizeof(uint16_t) * kIdeographicTable5Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kHexDigitTable0Size) + (sizeof(uint16_t) * kHexDigitTable1Size) + (sizeof(uint16_t) * kAsciiHexDigitTable0Size) + (sizeof(uint16_t) * kBidiControlTable0Size) + (sizeof(uint16_t) * kJoinControlTable0Size) + (sizeof(uint16_t) * kDashTable0Size) + (sizeof(uint16_t) * kDashTable1Size) + (sizeof(uint16_t) * kHyphenTable0Size) + (sizeof(uint16_t) * kHyphenTable1Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kRegExpSpecialCharTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size); // NOLINT } } // namespace unicode diff --git a/src/unicode.h b/src/unicode.h index 804671b698..fd7dfbcd8a 100644 --- a/src/unicode.h +++ b/src/unicode.h @@ -258,6 +258,9 @@ struct Hyphen { struct LineTerminator { static bool Is(uchar c); }; +struct RegExpSpecialChar { + static bool Is(uchar c); +}; struct CombiningMark { static bool Is(uchar c); }; diff --git a/test/mjsunit/regexp-indexof.js b/test/mjsunit/regexp-indexof.js new file mode 100644 index 0000000000..9b064b0f17 --- /dev/null +++ b/test/mjsunit/regexp-indexof.js @@ -0,0 +1,60 @@ +// Copyright 2008 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function CheckMatch(re, str, matches) { + assertEquals(matches.length > 0, re.test(str)); + var result = str.match(re); + if (matches.length > 0) { + assertEquals(matches.length, result.length); + for (idx in matches) { + var from = matches[idx][0]; + var length = matches[idx][1]; + var expected = str.substr(from, length); + assertEquals(expected, result[idx]); + } + assertEquals(expected, RegExp.lastMatch); + assertEquals(str.substr(0, from), RegExp.leftContext); + assertEquals(str.substr(from + length), RegExp.rightContext); + } else { + assertTrue(result === null); + } +} + +CheckMatch(/abc/, "xxxabcxxxabcxxx", [[3, 3]]); +CheckMatch(/abc/g, "xxxabcxxxabcxxx", [[3, 3], [9, 3]]); +CheckMatch(/abc/, "xxxabababcxxxabcxxx", [[7, 3]]); +CheckMatch(/abc/g, "abcabcabc", [[0, 3], [3, 3], [6, 3]]); +CheckMatch(/aba/g, "ababababa", [[0, 3], [4, 3]]); +CheckMatch(/foo/g, "ofooofoooofofooofo", [[1, 3], [5, 3], [12, 3]]); +CheckMatch(/foobarbaz/, "xx", []); +CheckMatch(new RegExp(""), "xxx", [[0, 0]]); +CheckMatch(/abc/, "abababa", []); + +assertEquals("xxxdefxxxdefxxx", "xxxabcxxxabcxxx".replace(/abc/g, "def")); +assertEquals("o-o-oofo-ofo", "ofooofoooofofooofo".replace(/foo/g, "-")); +assertEquals("deded", "deded".replace(/x/g, "-")); +assertEquals("-a-b-c-d-e-f-", "abcdef".replace(new RegExp("", "g"), "-"));