No issue - Refactor parsing of unicode escapes to be more general

This commit is contained in:
Martok 2022-12-21 18:53:26 +01:00 • committed by roytam1
commit 05a8a5271c
2 changed files with 69 additions and 64 deletions

View file

@ -90,6 +90,26 @@ RegExpBuilder::AddCharacter(char16_t c)
#endif #endif
} }
// forward declare atom helpers from below
static inline RegExpTree* SurrogatePairAtom(LifoAlloc* alloc, char16_t lead, char16_t trail, bool ignore_case);
static inline RegExpTree* LeadSurrogateAtom(LifoAlloc* alloc, char16_t value);
static inline RegExpTree* TrailSurrogateAtom(LifoAlloc* alloc, char16_t value);
void
RegExpBuilder::AddUnicodeCharacter(widechar c, bool ignore_case) {
if (c > unicode::UTF16Max) {
char16_t lead, trail;
unicode::UTF16Encode(c, &lead, &trail);
AddAtom(SurrogatePairAtom(alloc, lead, trail, ignore_case));
} else if (unicode::IsLeadSurrogate(c)) {
AddAtom(LeadSurrogateAtom(alloc, c));
} else if (unicode::IsTrailSurrogate(c)) {
AddAtom(TrailSurrogateAtom(alloc, c));
} else {
AddCharacter(static_cast<char16_t>(c));
}
}
void void
RegExpBuilder::AddEmpty() RegExpBuilder::AddEmpty()
{ {
@ -362,6 +382,39 @@ RegExpParser<CharT>::ParseBracedHexEscape(widechar* value)
return true; return true;
} }
template <typename CharT>
bool
RegExpParser<CharT>::ParseUnicodeEscape(widechar* value)
{
// Parse a RegExpUnicodeEscapeSequence
// Both \uxxxx and \u{xxxxx} are allowed. \u has already been consumed.
const CharT* start = position();
if (current() == '{' && unicode_) {
bool result = ParseBracedHexEscape(value);
if (!result) {
Reset(start);
}
return result;
}
// \u but no {, or \u{...} escapes not allowed.
bool result = ParseHexEscape(4, value);
if (result && unicode_ && unicode::IsLeadSurrogate(static_cast<char16_t>(*value)) && current() == '\\') {
// Attempt to read trail surrogate.
const CharT* start = position();
if (Next() == 'u') {
Advance(2);
widechar trail;
if (ParseHexEscape(4, &trail) &&
unicode::IsTrailSurrogate(static_cast<char16_t>(trail))) {
*value = unicode::UTF16Decode(static_cast<char16_t>(*value), static_cast<char16_t>(trail));
return true;
}
}
Reset(start);
}
return result;
}
template <typename CharT> template <typename CharT>
bool bool
RegExpParser<CharT>::ParseTrailSurrogate(widechar* value) RegExpParser<CharT>::ParseTrailSurrogate(widechar* value)
@ -560,30 +613,13 @@ RegExpParser<CharT>::ParseClassCharacterEscape(widechar* code)
case 'u': { case 'u': {
Advance(); Advance();
widechar value; widechar value;
if (unicode_) { if (ParseUnicodeEscape(&value)) {
if (current() == '{') { *code = value;
if (!ParseBracedHexEscape(&value)) return true;
return false;
*code = value;
return true;
}
if (ParseHexEscape(4, &value)) {
if (unicode::IsLeadSurrogate(value)) {
widechar trail;
if (ParseTrailSurrogate(&trail)) {
*code = unicode::UTF16Decode(value, trail);
return true;
}
}
*code = value;
return true;
}
ReportError(JSMSG_INVALID_UNICODE_ESCAPE);
return false;
} }
if (ParseHexEscape(4, &value)) { if (unicode_) {
*code = value; ReportError(JSMSG_INVALID_UNICODE_ESCAPE);
return true; return false;
} }
// If \u is not followed by a four-digit or braced hexadecimal, treat it // If \u is not followed by a four-digit or braced hexadecimal, treat it
// as an identity escape. // as an identity escape.
@ -1789,45 +1825,12 @@ RegExpParser<CharT>::ParseDisjunction()
case 'u': { case 'u': {
Advance(2); Advance(2);
widechar value; widechar value;
if (unicode_) { if (ParseUnicodeEscape(&value)) {
if (current() == '{') { builder->AddUnicodeCharacter(value, ignore_case_);
if (!ParseBracedHexEscape(&value)) } else if (!unicode_) {
return nullptr; builder->AddCharacter('u');
if (unicode::IsLeadSurrogate(value)) {
builder->AddAtom(LeadSurrogateAtom(alloc, value));
} else if (unicode::IsTrailSurrogate(value)) {
builder->AddAtom(TrailSurrogateAtom(alloc, value));
} else if (value >= unicode::NonBMPMin) {
char16_t lead, trail;
unicode::UTF16Encode(value, &lead, &trail);
builder->AddAtom(SurrogatePairAtom(alloc, lead, trail,
ignore_case_));
} else {
builder->AddCharacter(value);
}
} else if (ParseHexEscape(4, &value)) {
if (unicode::IsLeadSurrogate(value)) {
widechar trail;
if (ParseTrailSurrogate(&trail)) {
builder->AddAtom(SurrogatePairAtom(alloc, value, trail,
ignore_case_));
} else {
builder->AddAtom(LeadSurrogateAtom(alloc, value));
}
} else if (unicode::IsTrailSurrogate(value)) {
builder->AddAtom(TrailSurrogateAtom(alloc, value));
} else {
builder->AddCharacter(value);
}
} else {
return ReportError(JSMSG_INVALID_UNICODE_ESCAPE);
}
break;
}
if (ParseHexEscape(4, &value)) {
builder->AddCharacter(value);
} else { } else {
builder->AddCharacter('u'); return ReportError(JSMSG_INVALID_UNICODE_ESCAPE);
} }
break; break;
} }

View file

@ -133,12 +133,16 @@ class BufferedVector
}; };
// Characters parsed by RegExpParser can be either char16_t or kEndMarker.
typedef uint32_t widechar;
// Accumulates RegExp atoms and assertions into lists of terms and alternatives. // Accumulates RegExp atoms and assertions into lists of terms and alternatives.
class RegExpBuilder class RegExpBuilder
{ {
public: public:
explicit RegExpBuilder(LifoAlloc* alloc); explicit RegExpBuilder(LifoAlloc* alloc);
void AddCharacter(char16_t character); void AddCharacter(char16_t character);
void AddUnicodeCharacter(widechar c, bool ignore_case);
// "Adds" an empty expression. Does nothing except consume a // "Adds" an empty expression. Does nothing except consume a
// following quantifier // following quantifier
void AddEmpty(); void AddEmpty();
@ -168,9 +172,6 @@ class RegExpBuilder
#endif #endif
}; };
// Characters parsed by RegExpParser can be either char16_t or kEndMarker.
typedef uint32_t widechar;
template <typename CharT> template <typename CharT>
class RegExpParser class RegExpParser
{ {
@ -198,6 +199,7 @@ class RegExpParser
bool ParseHexEscape(int length, widechar* value); bool ParseHexEscape(int length, widechar* value);
bool ParseBracedHexEscape(widechar* value); bool ParseBracedHexEscape(widechar* value);
bool ParseUnicodeEscape(widechar* value);
bool ParseTrailSurrogate(widechar* value); bool ParseTrailSurrogate(widechar* value);
bool ParseRawSurrogatePair(char16_t* lead, char16_t* trail); bool ParseRawSurrogatePair(char16_t* lead, char16_t* trail);