RegExpParser(FlatStringReader* in,
Handle<String>* error,
bool multiline_mode);
- RegExpTree* ParsePattern(bool* ok);
- RegExpTree* ParseDisjunction(bool* ok);
- RegExpTree* ParseGroup(bool* ok);
- RegExpTree* ParseCharacterClass(bool* ok);
+ RegExpTree* ParsePattern();
+ RegExpTree* ParseDisjunction();
+ RegExpTree* ParseGroup();
+ RegExpTree* ParseCharacterClass();
// Parses a {...,...} quantifier and stores the range in the given
// out parameters.
// Parses and returns a single escaped character. The character
// must not be 'b' or 'B' since they are usually handle specially.
- uc32 ParseClassCharacterEscape(bool* ok);
+ uc32 ParseClassCharacterEscape();
// Checks whether the following is a length-digit hexadecimal number,
// and sets the value if it is.
bool ParseHexEscape(int length, uc32* value);
- uc32 ParseControlLetterEscape(bool* ok);
+ uc32 ParseControlLetterEscape();
uc32 ParseOctalLiteral();
// Tries to parse the input as a back reference. If successful it
// can be reparsed.
bool ParseBackReferenceIndex(int* index_out);
- CharacterRange ParseClassAtom(uc16* char_class,
- bool* ok);
- RegExpTree* ReportError(Vector<const char> message, bool* ok);
+ CharacterRange ParseClassAtom(uc16* char_class);
+ RegExpTree* ReportError(Vector<const char> message);
void Advance();
void Advance(int dist);
void Reset(int pos);
int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
int position() { return next_pos_ - 1; }
+ bool failed() { return failed_; }
static const uc32 kEndMarker = (1 << 21);
private:
bool is_scanned_for_captures_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
+ bool failed_;
};
#define DUMMY ) // to make indentation work
#undef DUMMY
+#define CHECK_FAILED ); \
+ if (failed_) return NULL; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
// ----------------------------------------------------------------------------
// Implementation of Parser
has_character_escapes_(false),
captures_(NULL),
is_scanned_for_captures_(false),
- capture_count_(0) {
+ capture_count_(0),
+ failed_(false) {
Advance(1);
}
void RegExpParser::Advance() {
if (next_pos_ < in()->length()) {
- current_ = in()->Get(next_pos_);
- next_pos_++;
+ StackLimitCheck check;
+ if (check.HasOverflowed()) {
+ ReportError(CStrVector(Top::kStackOverflowMessage));
+ } else if (Zone::excess_allocation()) {
+ ReportError(CStrVector("Regular expression too large"));
+ } else {
+ current_ = in()->Get(next_pos_);
+ next_pos_++;
+ }
} else {
current_ = kEndMarker;
has_more_ = false;
return has_character_escapes_;
}
-RegExpTree* RegExpParser::ReportError(Vector<const char> message, bool* ok) {
- *ok = false;
+RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
+ failed_ = true;
*error_ = Factory::NewStringFromAscii(message, NOT_TENURED);
+ // Zip to the end to make sure the no more input is read.
+ current_ = kEndMarker;
+ next_pos_ = in()->length();
return NULL;
}
// Pattern ::
// Disjunction
-RegExpTree* RegExpParser::ParsePattern(bool* ok) {
- RegExpTree* result = ParseDisjunction(CHECK_OK);
+RegExpTree* RegExpParser::ParsePattern() {
+ RegExpTree* result = ParseDisjunction(CHECK_FAILED);
if (has_more()) {
- ReportError(CStrVector("Unmatched ')'"), CHECK_OK);
+ ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
}
return result;
}
// Assertion
// Atom
// Atom Quantifier
-RegExpTree* RegExpParser::ParseDisjunction(bool* ok) {
+RegExpTree* RegExpParser::ParseDisjunction() {
RegExpBuilder builder;
int capture_start_index = captures_started();
while (true) {
case '*':
case '+':
case '?':
- ReportError(CStrVector("Nothing to repeat"), CHECK_OK);
+ ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
case '^': {
Advance();
RegExpAssertion::Type type =
break;
}
case '(': {
- RegExpTree* atom = ParseGroup(CHECK_OK);
+ RegExpTree* atom = ParseGroup(CHECK_FAILED);
builder.AddAtom(atom);
break;
}
case '[': {
- RegExpTree* atom = ParseCharacterClass(CHECK_OK);
+ RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
builder.AddAtom(atom);
break;
}
case '\\':
switch (Next()) {
case kEndMarker:
- ReportError(CStrVector("\\ at end of pattern"), CHECK_OK);
+ ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
case 'b':
Advance(2);
builder.AddAssertion(
break;
case 'c': {
Advance(2);
- uc32 control = ParseControlLetterEscape(ok);
+ uc32 control = ParseControlLetterEscape();
builder.AddCharacter(control);
break;
}
case '{': {
int dummy;
if (ParseIntervalQuantifier(&dummy, &dummy)) {
- ReportError(CStrVector("Nothing to repeat"), CHECK_OK);
+ ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
}
// fallthrough
}
// Upper and lower case letters differ by one bit.
STATIC_CHECK(('a' ^ 'A') == 0x20);
-uc32 RegExpParser::ParseControlLetterEscape(bool* ok) {
+uc32 RegExpParser::ParseControlLetterEscape() {
if (!has_more()) {
- ReportError(CStrVector("\\c at end of pattern"), ok);
+ ReportError(CStrVector("\\c at end of pattern"));
return '\0';
}
uc32 letter = current() & ~(0x20); // Collapse upper and lower case letters.
}
-uc32 RegExpParser::ParseClassCharacterEscape(bool* ok) {
+uc32 RegExpParser::ParseClassCharacterEscape() {
ASSERT(current() == '\\');
ASSERT(has_next() && !IsSpecialClassEscape(Next()));
Advance();
Advance();
return '\v';
case 'c':
- return ParseControlLetterEscape(ok);
+ return ParseControlLetterEscape();
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7':
// For compatibility, we interpret a decimal escape that isn't
}
-RegExpTree* RegExpParser::ParseGroup(bool* ok) {
+RegExpTree* RegExpParser::ParseGroup() {
ASSERT_EQ(current(), '(');
char type = '(';
Advance();
Advance(2);
break;
default:
- ReportError(CStrVector("Invalid group"), CHECK_OK);
+ ReportError(CStrVector("Invalid group") CHECK_FAILED);
break;
}
} else {
captures_->Add(NULL);
}
int capture_index = captures_started();
- RegExpTree* body = ParseDisjunction(CHECK_OK);
+ RegExpTree* body = ParseDisjunction(CHECK_FAILED);
if (current() != ')') {
- ReportError(CStrVector("Unterminated group"), CHECK_OK);
+ ReportError(CStrVector("Unterminated group") CHECK_FAILED);
}
Advance();
}
-CharacterRange RegExpParser::ParseClassAtom(uc16* char_class, bool* ok) {
+CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
ASSERT_EQ(0, *char_class);
uc32 first = current();
if (first == '\\') {
return CharacterRange::Singleton(0); // Return dummy value.
}
default:
- uc32 c = ParseClassCharacterEscape(CHECK_OK);
+ uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
return CharacterRange::Singleton(c);
}
} else {
}
-RegExpTree* RegExpParser::ParseCharacterClass(bool* ok) {
+RegExpTree* RegExpParser::ParseCharacterClass() {
static const char* kUnterminated = "Unterminated character class";
static const char* kRangeOutOfOrder = "Range out of order in character class";
ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
while (has_more() && current() != ']') {
uc16 char_class = 0;
- CharacterRange first = ParseClassAtom(&char_class, CHECK_OK);
+ CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
if (char_class) {
CharacterRange::AddClassEscape(char_class, ranges);
continue;
ranges->Add(CharacterRange::Singleton('-'));
break;
}
- CharacterRange next = ParseClassAtom(&char_class, CHECK_OK);
+ CharacterRange next = ParseClassAtom(&char_class CHECK_FAILED);
if (char_class) {
ranges->Add(first);
ranges->Add(CharacterRange::Singleton('-'));
continue;
}
if (first.from() > next.to()) {
- return ReportError(CStrVector(kRangeOutOfOrder), CHECK_OK);
+ return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
}
ranges->Add(CharacterRange::Range(first.from(), next.to()));
} else {
}
}
if (!has_more()) {
- return ReportError(CStrVector(kUnterminated), CHECK_OK);
+ return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
}
Advance();
if (ranges->length() == 0) {
bool multiline,
RegExpParseResult* result) {
ASSERT(result != NULL);
+ // Make sure we have a stack guard.
+ StackGuard guard;
RegExpParser parser(input, &result->error, multiline);
- bool ok = true;
- result->tree = parser.ParsePattern(&ok);
- if (!ok) {
+ result->tree = parser.ParsePattern();
+ if (parser.failed()) {
ASSERT(result->tree == NULL);
ASSERT(!result->error.is_null());
} else {
ASSERT(result->tree != NULL);
ASSERT(result->error.is_null());
- }
- if (ok) {
result->has_character_escapes = parser.HasCharacterEscapes();
result->capture_count = parser.captures_started();
}
- return ok;
+ return !parser.failed();
}