Files
ark_js_runtime/ecmascript/regexp/regexp_parser.cpp
T
zhaozhibo 4b279c9d79 fix codex warning
Signed-off-by: zhaozhibo <zhaozhibo3@huawei.com>
2022-04-30 10:31:33 +08:00

1304 lines
46 KiB
C++

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/regexp/regexp_parser.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/ecma_macros.h"
#include "ecmascript/regexp/regexp_opcode.h"
#include "libpandabase/utils/utils.h"
#include "securec.h"
#include "unicode/uniset.h"
#define _NO_DEBUG_
namespace panda::ecmascript {
static RangeSet g_rangeD(0x30, 0x39); // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
static RangeSet g_rangeS({
std::pair<uint32_t, uint32_t>(0x0009, 0x000D), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0020, 0x0020), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x00A0, 0x00A0), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x1680, 0x1680), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x2000, 0x200A), // NOLINTNEXTLINE(readability-magic-numbers)
/* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */
/* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */
std::pair<uint32_t, uint32_t>(0x2028, 0x2029), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x202F, 0x202F), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x205F, 0x205F), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x3000, 0x3000), // NOLINTNEXTLINE(readability-magic-numbers)
/* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */
std::pair<uint32_t, uint32_t>(0xFEFF, 0xFEFF), // NOLINTNEXTLINE(readability-magic-numbers)
});
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
static RangeSet g_rangeW({
std::pair<uint32_t, uint32_t>(0x0030, 0x0039), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0041, 0x005A), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x005F, 0x005F), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0061, 0x007A), // NOLINTNEXTLINE(readability-magic-numbers)
});
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
static RangeSet g_regexpIdentifyStart({
std::pair<uint32_t, uint32_t>(0x0024, 0x0024), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0041, 0x005A), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0061, 0x007A), // NOLINTNEXTLINE(readability-magic-numbers)
});
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
static RangeSet g_regexpIdentifyContinue({
std::pair<uint32_t, uint32_t>(0x0024, 0x0024), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0030, 0x0039), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0041, 0x005A), // NOLINTNEXTLINE(readability-magic-numbers)
std::pair<uint32_t, uint32_t>(0x0061, 0x007A), // NOLINTNEXTLINE(readability-magic-numbers)
});
void RegExpParser::Parse()
{
// dynbuffer head init [size,capture_count,statck_count,flags]
buffer_.EmitU32(0);
buffer_.EmitU32(0);
buffer_.EmitU32(0);
buffer_.EmitU32(0);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse Pattern------\n");
// Pattern[U, N]::
// Disjunction[?U, ?N]
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Advance();
SaveStartOpCode saveStartOp;
int captureIndex = captureCount_++;
saveStartOp.EmitOpCode(&buffer_, captureIndex);
ParseDisjunction(false);
if (c0_ != KEY_EOF) {
ParseError("extraneous characters at the end");
return;
}
SaveEndOpCode saveEndOp;
saveEndOp.EmitOpCode(&buffer_, captureIndex);
MatchEndOpCode matchEndOp;
matchEndOp.EmitOpCode(&buffer_, 0);
// dynbuffer head assignments
buffer_.PutU32(0, buffer_.size_);
buffer_.PutU32(NUM_CAPTURE__OFFSET, captureCount_);
buffer_.PutU32(NUM_STACK_OFFSET, stackCount_);
buffer_.PutU32(FLAGS_OFFSET, flags_);
#ifndef _NO_DEBUG_
RegExpOpCode::DumpRegExpOpCode(std::cout, buffer_);
#endif
}
void RegExpParser::ParseDisjunction(bool isBackward)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse Disjunction------\n");
size_t start = buffer_.size_;
ParseAlternative(isBackward);
if (isError_) {
return;
}
do {
if (c0_ == '|') {
SplitNextOpCode splitOp;
uint32_t len = buffer_.size_ - start;
GotoOpCode gotoOp;
splitOp.InsertOpCode(&buffer_, start, len + gotoOp.GetSize());
uint32_t pos = gotoOp.EmitOpCode(&buffer_, 0) - gotoOp.GetSize();
Advance();
ParseAlternative(isBackward);
gotoOp.UpdateOpPara(&buffer_, pos, buffer_.size_ - pos - gotoOp.GetSize());
}
} while (c0_ != KEY_EOF && c0_ != ')');
}
uint32_t RegExpParser::ParseOctalLiteral()
{
// For compatibility with some other browsers (not all), we parse
// up to three octal digits with a value below 256.
// ES#prod-annexB-LegacyOctalEscapeSequence
uint32_t value = c0_ - '0';
Advance();
if (c0_ >= '0' && c0_ <= '7') {
value = value * OCTAL_VALUE + c0_ - '0';
Advance();
if (value < OCTAL_VALUE_RANGE && c0_ >= '0' && c0_ <= '7') {
value = value * OCTAL_VALUE + c0_ - '0';
Advance();
}
}
return value;
}
bool RegExpParser::ParseUnlimitedLengthHexNumber(uint32_t maxValue, uint32_t *value)
{
uint32_t x = 0;
int d = static_cast<int>(HexValue(c0_));
if (d < 0) {
return false;
}
while (d >= 0) {
if (UNLIKELY(x > (std::numeric_limits<uint32_t>::max() - static_cast<uint32_t>(d)) / HEX_VALUE)) {
LOG_ECMA(FATAL) << "value overflow";
return false;
}
x = x * HEX_VALUE + static_cast<uint32_t>(d);
if (x > maxValue) {
return false;
}
Advance();
d = static_cast<int>(HexValue(c0_));
}
*value = x;
return true;
}
// This parses RegExpUnicodeEscapeSequence as described in ECMA262.
bool RegExpParser::ParseUnicodeEscape(uint32_t *value)
{
// Accept both \uxxxx and \u{xxxxxx} (if allowed).
// In the latter case, the number of hex digits between { } is arbitrary.
// \ and u have already been read.
if (c0_ == '{' && IsUtf16()) {
uint8_t *start = pc_ - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
Advance();
if (ParseUnlimitedLengthHexNumber(0x10FFFF, value)) { // NOLINTNEXTLINE(readability-magic-numbers)
if (c0_ == '}') {
Advance();
return true;
}
}
pc_ = start;
Advance();
return false;
}
// \u but no {, or \u{...} escapes not allowed.
bool result = ParseHexEscape(UNICODE_HEX_VALUE, value);
if (result && IsUtf16() && U16_IS_LEAD(*value) && c0_ == '\\') {
// Attempt to read trail surrogate.
uint8_t *start = pc_ - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (*pc_ == 'u') {
Advance(UNICODE_HEX_ADVANCE);
uint32_t trail;
if (ParseHexEscape(UNICODE_HEX_VALUE, &trail) && U16_IS_TRAIL(trail)) {
*value = U16_GET_SUPPLEMENTARY((*value), (trail)); // NOLINTNEXTLINE(hicpp-signed-bitwise)
return true;
}
}
pc_ = start;
Advance();
}
return result;
}
bool RegExpParser::ParseHexEscape(int length, uint32_t *value)
{
uint8_t *start = pc_ - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
uint32_t val = 0;
for (int i = 0; i < length; ++i) {
uint32_t c = c0_;
int d = static_cast<int>(HexValue(c));
if (d < 0) {
pc_ = start;
Advance();
return false;
}
val = val * HEX_VALUE + static_cast<uint32_t>(d);
Advance();
}
*value = val;
return true;
}
// NOLINTNEXTLINE(readability-function-size)
void RegExpParser::ParseAlternative(bool isBackward)
{
size_t start = buffer_.size_;
while (c0_ != '|' && c0_ != KEY_EOF && c0_ != ')') {
if (isError_) {
return;
}
size_t atomBcStart = buffer_.GetSize();
int captureIndex = 0;
bool isAtom = false;
switch (c0_) {
case '^': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion %c line start \n", c0_);
LineStartOpCode lineStartOp;
lineStartOp.EmitOpCode(&buffer_, 0);
Advance();
} break;
case '$': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion %c line end \n", c0_);
LineEndOpCode lineEndOp;
lineEndOp.EmitOpCode(&buffer_, 0);
Advance();
} break;
case '\\':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Escape %c \n", c0_);
Advance();
switch (c0_) {
case 'b': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion %c \n", c0_);
WordBoundaryOpCode wordBoundaryOp;
wordBoundaryOp.EmitOpCode(&buffer_, 0);
Advance();
} break;
case 'B': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion %c \n", c0_);
NotWordBoundaryOpCode notWordBoundaryOp;
notWordBoundaryOp.EmitOpCode(&buffer_, 0);
Advance();
} break;
default:
isAtom = true;
int atomValue = ParseAtomEscape(isBackward);
if (atomValue != -1) {
if (IsIgnoreCase()) {
if (!IsUtf16()) {
atomValue = Canonicalize(atomValue, false);
} else {
icu::UnicodeSet set(atomValue, atomValue);
set.closeOver(USET_CASE_INSENSITIVE);
set.removeAllStrings();
int32_t size = set.size();
RangeOpCode rangeOp;
RangeSet rangeResult;
for (int32_t idx = 0; idx < size; idx++) {
int32_t uc = set.charAt(idx);
RangeSet curRange(uc);
rangeResult.Insert(curRange);
}
rangeOp.InsertOpCode(&buffer_, rangeResult);
break;
}
}
if (atomValue <= UINT16_MAX) {
CharOpCode charOp;
charOp.EmitOpCode(&buffer_, atomValue);
} else {
Char32OpCode charOp;
charOp.EmitOpCode(&buffer_, atomValue);
}
}
break;
}
break;
case '(': {
Advance();
isAtom = ParseAssertionCapture(&captureIndex, isBackward);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
Advance();
} break;
case '.': {
PrevOpCode prevOp;
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
if (IsDotAll()) {
AllOpCode allOp;
allOp.EmitOpCode(&buffer_, 0);
} else {
DotsOpCode dotsOp;
dotsOp.EmitOpCode(&buffer_, 0);
}
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Atom %c match any \n", c0_);
isAtom = true;
Advance();
} break;
case '[': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Atom %c match range \n", c0_);
isAtom = true;
PrevOpCode prevOp;
Advance();
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
bool isInvert = false;
if (c0_ == '^') {
isInvert = true;
Advance();
}
RangeSet rangeResult;
if (!ParseClassRanges(&rangeResult)) {
break;
}
if (isInvert) {
rangeResult.Invert(IsUtf16());
}
uint32_t highValue = rangeResult.HighestValue();
if (highValue <= UINT16_MAX) {
RangeOpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, rangeResult);
} else {
Range32OpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, rangeResult);
}
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
} break;
case '*':
case '+':
case '?':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
ParseError("nothing to repeat");
return;
case '{': {
uint8_t *begin = pc_ - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
int dummy;
if (ParserIntervalQuantifier(&dummy, &dummy)) {
ParseError("nothing to repeat");
return;
}
pc_ = begin;
Advance();
}
[[fallthrough]];
case '}':
case ']':
if (IsUtf16()) {
ParseError("syntax error");
return;
}
[[fallthrough]];
default:
// PatternCharacter
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("PatternCharacter %c\n", c0_);
isAtom = true;
{
PrevOpCode prevOp;
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
uint32_t matchedChar = c0_;
if (c0_ > (INT8_MAX + 1)) {
Prev();
int i = 0;
UChar32 c;
int32_t length = end_ - pc_ + 1;
// NOLINTNEXTLINE(hicpp-signed-bitwise)
U8_NEXT(pc_, i, length, c); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
matchedChar = static_cast<uint32_t>(c);
pc_ += i; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
if (IsIgnoreCase()) {
matchedChar = static_cast<uint32_t>(Canonicalize(static_cast<int>(matchedChar), IsUtf16()));
}
if (matchedChar > UINT16_MAX) {
Char32OpCode charOp;
charOp.EmitOpCode(&buffer_, matchedChar);
} else {
CharOpCode charOp;
charOp.EmitOpCode(&buffer_, matchedChar);
}
if (isBackward) {
prevOp.EmitOpCode(&buffer_, 0);
}
}
Advance();
break;
}
if (isAtom && !isError_) {
ParseQuantifier(atomBcStart, captureIndex, captureCount_ - 1);
}
if (isBackward) {
size_t end = buffer_.GetSize();
size_t termSize = end - atomBcStart;
size_t moveSize = end - start;
buffer_.Expand(end + termSize);
if (memmove_s(buffer_.buf_ + start + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
termSize, // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
moveSize,
buffer_.buf_ + start, // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
moveSize) != EOK) {
LOG_ECMA(FATAL) << "memmove_s failed";
UNREACHABLE();
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (memcpy_s(buffer_.buf_ + start, termSize, buffer_.buf_ + end, termSize) != EOK) {
LOG_ECMA(FATAL) << "memcpy_s failed";
UNREACHABLE();
}
}
}
}
int RegExpParser::FindGroupName(const CString &name)
{
size_t len = 0;
size_t nameLen = name.size();
const char *p = reinterpret_cast<char *>(groupNames_.buf_);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const char *bufEnd = reinterpret_cast<char *>(groupNames_.buf_) + groupNames_.size_;
int captureIndex = 1;
while (p < bufEnd) {
len = strlen(p);
if (len == nameLen && memcmp(name.c_str(), p, nameLen) == 0) {
return captureIndex;
}
p += len + 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
captureIndex++;
}
return -1;
}
bool RegExpParser::ParseAssertionCapture(int *captureIndex, bool isBackward)
{
bool isAtom = false;
do {
if (c0_ == '?') {
Advance();
switch (c0_) {
// (?=Disjunction[?U, ?N])
case '=': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion(?= Disjunction)\n");
Advance();
uint32_t start = buffer_.size_;
ParseDisjunction(isBackward);
MatchOpCode matchOp;
matchOp.EmitOpCode(&buffer_, 0);
MatchAheadOpCode matchAheadOp;
uint32_t len = buffer_.size_ - start;
matchAheadOp.InsertOpCode(&buffer_, start, len);
} break;
// (?!Disjunction[?U, ?N])
case '!': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion(?! Disjunction)\n");
uint32_t start = buffer_.size_;
Advance();
ParseDisjunction(isBackward);
MatchOpCode matchOp;
matchOp.EmitOpCode(&buffer_, 0);
NegativeMatchAheadOpCode matchAheadOp;
uint32_t len = buffer_.size_ - start;
matchAheadOp.InsertOpCode(&buffer_, start, len);
} break;
case '<':
Advance();
// (?<=Disjunction[?U, ?N])
if (c0_ == '=') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion(?<= Disjunction)\n");
Advance();
uint32_t start = buffer_.size_;
ParseDisjunction(true);
MatchOpCode matchOp;
matchOp.EmitOpCode(&buffer_, 0);
MatchAheadOpCode matchAheadOp;
uint32_t len = buffer_.size_ - start;
matchAheadOp.InsertOpCode(&buffer_, start, len);
// (?<!Disjunction[?U, ?N])
} else if (c0_ == '!') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Assertion(?<! Disjunction)\n");
Advance();
uint32_t start = buffer_.size_;
ParseDisjunction(true);
MatchOpCode matchOp;
matchOp.EmitOpCode(&buffer_, 0);
NegativeMatchAheadOpCode matchAheadOp;
uint32_t len = buffer_.size_ - start;
matchAheadOp.InsertOpCode(&buffer_, start, len);
} else {
Prev();
CString name;
auto **pp = const_cast<const uint8_t **>(&pc_);
if (!ParseGroupSpecifier(pp, name)) {
ParseError("GroupName Syntax error.");
return false;
}
if (FindGroupName(name) > 0) {
ParseError("Duplicate GroupName error.");
return false;
}
groupNames_.EmitStr(name.c_str());
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("group name %s", name.c_str());
Advance();
goto parseCapture; // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto)
}
break;
// (?:Disjunction[?U, ?N])
case ':':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Atom(?<: Disjunction)\n");
isAtom = true;
Advance();
ParseDisjunction(isBackward);
break;
default:
Advance();
ParseError("? Syntax error.");
return false;
}
} else {
groupNames_.EmitChar(0);
parseCapture:
isAtom = true;
*captureIndex = captureCount_++;
SaveEndOpCode saveEndOp;
SaveStartOpCode saveStartOp;
if (isBackward) {
saveEndOp.EmitOpCode(&buffer_, *captureIndex);
} else {
saveStartOp.EmitOpCode(&buffer_, *captureIndex);
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("capture start %d \n", *captureIndex);
ParseDisjunction(isBackward);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("capture end %d \n", *captureIndex);
if (isBackward) {
saveStartOp.EmitOpCode(&buffer_, *captureIndex);
} else {
saveEndOp.EmitOpCode(&buffer_, *captureIndex);
}
}
} while (c0_ != ')' && c0_ != KEY_EOF);
if (c0_ != ')') {
ParseError("capture syntax error");
return false;
}
return isAtom;
}
int RegExpParser::ParseDecimalDigits()
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse DecimalDigits------\n");
uint32_t result = 0;
bool overflow = false;
while (true) {
if (c0_ < '0' || c0_ > '9') {
break;
}
if (!overflow) {
if (UNLIKELY(result > (INT32_MAX - c0_ + '0') / DECIMAL_DIGITS_ADVANCE)) {
overflow = true;
} else {
result = result * DECIMAL_DIGITS_ADVANCE + c0_ - '0';
}
}
Advance();
}
if (overflow) {
return INT32_MAX;
}
return result;
}
bool RegExpParser::ParserIntervalQuantifier(int *pmin, int *pmax)
{
// Quantifier::
// QuantifierPrefix
// QuantifierPrefix?
// QuantifierPrefix::
// *
// +
// ?
// {DecimalDigits}
// {DecimalDigits,}
// {DecimalDigits,DecimalDigits}
Advance();
*pmin = ParseDecimalDigits();
*pmax = *pmin;
switch (c0_) {
case ',':
Advance();
if (c0_ == '}') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix{DecimalDigits,}\n");
*pmax = INT32_MAX;
Advance();
} else {
*pmax = ParseDecimalDigits();
if (c0_ == '}') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix{DecimalDigits,DecimalDigits}\n");
Advance();
} else {
return false;
}
}
break;
case '}':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix{DecimalDigits}\n");
Advance();
break;
default:
Advance();
return false;
}
return true;
}
void RegExpParser::ParseQuantifier(size_t atomBcStart, int captureStart, int captureEnd)
{
int min = -1;
int max = -1;
bool isGreedy = true;
switch (c0_) {
case '*':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix %c\n", c0_);
min = 0;
max = INT32_MAX;
Advance();
break;
case '+':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix %c\n", c0_);
min = 1;
max = INT32_MAX;
Advance();
break;
case '?':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("QuantifierPrefix %c\n", c0_);
Advance();
min = 0;
max = 1;
break;
case '{': {
uint8_t *start = pc_ - 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (!ParserIntervalQuantifier(&min, &max)) {
pc_ = start;
Advance(); // back to '{'
return;
}
if (min > max) {
ParseError("Invalid repetition count");
return;
}
} break;
default:
break;
}
if (c0_ == '?') {
isGreedy = false;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Quantifier::QuantifierPrefix?\n");
Advance();
} else if (c0_ == '?' || c0_ == '+' || c0_ == '*' || c0_ == '{') {
ParseError("nothing to repeat");
return;
}
if (min != -1 && max != -1) {
stackCount_++;
PushOpCode pushOp;
pushOp.InsertOpCode(&buffer_, atomBcStart);
atomBcStart += pushOp.GetSize();
if (captureStart != 0) {
SaveResetOpCode saveResetOp;
saveResetOp.InsertOpCode(&buffer_, atomBcStart, captureStart, captureEnd);
}
// zero advance check
if (max == INT32_MAX) {
stackCount_++;
PushCharOpCode pushCharOp;
pushCharOp.InsertOpCode(&buffer_, atomBcStart);
CheckCharOpCode checkCharOp;
// NOLINTNEXTLINE(readability-magic-numbers)
checkCharOp.EmitOpCode(&buffer_, RegExpOpCode::GetRegExpOpCode(RegExpOpCode::OP_LOOP)->GetSize());
}
if (isGreedy) {
LoopGreedyOpCode loopOp;
loopOp.EmitOpCode(&buffer_, atomBcStart - buffer_.GetSize() - loopOp.GetSize(), min, max);
} else {
LoopOpCode loopOp;
loopOp.EmitOpCode(&buffer_, atomBcStart - buffer_.GetSize() - loopOp.GetSize(), min, max);
}
if (min == 0) {
if (isGreedy) {
SplitNextOpCode splitNextOp;
splitNextOp.InsertOpCode(&buffer_, atomBcStart, buffer_.GetSize() - atomBcStart);
} else {
SplitFirstOpCode splitFirstOp;
splitFirstOp.InsertOpCode(&buffer_, atomBcStart, buffer_.GetSize() - atomBcStart);
}
}
PopOpCode popOp;
popOp.EmitOpCode(&buffer_);
}
}
bool RegExpParser::ParseGroupSpecifier(const uint8_t **pp, CString &name)
{
const uint8_t *p = *pp;
int c = *p;
while (c != '>') {
if (c < (INT8_MAX + 1)) {
if (name.empty()) {
if (!g_regexpIdentifyStart.IsContain(c)) {
return false;
}
} else {
if (!g_regexpIdentifyContinue.IsContain(c)) {
return false;
}
}
name += static_cast<char>(c);
}
c = *++p; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
p++; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
*pp = p;
return true;
}
int RegExpParser::ParseCaptureCount(const char *groupName)
{
const uint8_t *p;
int captureIndex = 1;
CString name;
for (p = base_; p < end_; p++) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
switch (*p) {
case '(': {
if (p[1] == '?') { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (p[CAPTURE_CONUT_ADVANCE - 1] == '<' && p[CAPTURE_CONUT_ADVANCE] != '!' &&
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
p[CAPTURE_CONUT_ADVANCE] != '=') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
p += CAPTURE_CONUT_ADVANCE;
if (groupName != nullptr) {
if (ParseGroupSpecifier(&p, name)) {
if (strcmp(name.c_str(), groupName) == 0) {
return captureIndex;
}
}
}
captureIndex++;
}
} else {
captureIndex++;
}
} break;
case '\\':
p++; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
break;
case '[':
while (p < end_ && *p != ']') {
if (*p == '\\') {
p++; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
p++; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
}
break;
default:
break;
}
}
return captureIndex;
}
// NOLINTNEXTLINE(readability-function-size)
int RegExpParser::ParseAtomEscape(bool isBackward)
{
// AtomEscape[U, N]::
// DecimalEscape
// CharacterClassEscape[?U]
// CharacterEscape[?U]
// [+N]kGroupName[?U]
int result = -1;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse AtomEscape------\n");
switch (c0_) {
case KEY_EOF:
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
ParseError("unexpected end");
break;
// DecimalEscape
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("NonZeroDigit %c\n", c0_);
int capture = ParseDecimalDigits();
if (capture > captureCount_ - 1 && capture > ParseCaptureCount(nullptr) - 1) {
ParseError("invalid backreference count");
break;
}
if (isBackward) {
BackwardBackReferenceOpCode backReferenceOp;
backReferenceOp.EmitOpCode(&buffer_, capture);
} else {
BackReferenceOpCode backReferenceOp;
backReferenceOp.EmitOpCode(&buffer_, capture);
}
} break;
// CharacterClassEscape
case 'd': {
// [0-9]
RangeOpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, g_rangeD);
Advance();
} break;
case 'D': {
// [^0-9]
RangeSet atomRange(g_rangeD);
atomRange.Invert(IsUtf16());
Range32OpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, atomRange);
Advance();
} break;
case 's': {
// [\f\n\r\t\v]
RangeOpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, g_rangeS);
Advance();
} break;
case 'S': {
RangeSet atomRange(g_rangeS);
atomRange.Invert(IsUtf16());
Range32OpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, atomRange);
Advance();
} break;
case 'w': {
// [A-Za-z0-9]
RangeOpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, g_rangeW);
Advance();
} break;
case 'W': {
// [^A-Za-z0-9]
RangeSet atomRange(g_rangeW);
atomRange.Invert(IsUtf16());
Range32OpCode rangeOp;
rangeOp.InsertOpCode(&buffer_, atomRange);
Advance();
} break;
// P{UnicodePropertyValueExpression}
// p{UnicodePropertyValueExpression}
case 'P':
case 'p':
// [+N]kGroupName[?U]
case 'k':
default:
result = ParseCharacterEscape();
break;
}
return result;
}
int RegExpParser::ParseCharacterEscape()
{
// CharacterEscape[U]::
// ControlEscape
// c ControlLetter
// 0 [lookahead ∉ DecimalDigit]
// HexEscapeSequence
// RegExpUnicodeEscapeSequence[?U]
// IdentityEscape[?U]
uint32_t result = 0;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
switch (c0_) {
// ControlEscape
case 'f':
result = '\f';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlEscape %c\n", c0_);
Advance();
break;
case 'n':
result = '\n';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlEscape %c\n", c0_);
Advance();
break;
case 'r':
result = '\r';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlEscape %c\n", c0_);
Advance();
break;
case 't':
result = '\t';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlEscape %c\n", c0_);
Advance();
break;
case 'v':
result = '\v';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlEscape %c\n", c0_);
Advance();
break;
// c ControlLetter
case 'c':
Advance();
if ((c0_ >= 'A' && c0_ <= 'Z') || (c0_ >= 'a' && c0_ <= 'z')) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ControlLetter %c\n", c0_);
result = static_cast<uint32_t>(c0_) & 0x1f; // NOLINTNEXTLINE(readability-magic-numbers)
Advance();
} else {
if (!IsUtf16()) {
pc_--; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
result = '\\';
} else {
ParseError("Invalid control letter");
return -1;
}
}
break;
case '0':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("CharacterEscape 0 [lookahead ∉ DecimalDigit]\n");
if (IsUtf16() && !(*pc_ >= '0' && *pc_ <= '9')) { // NOLINTNEXTLINE(readability-magic-numbers)
Advance();
result = 0;
break;
}
[[fallthrough]];
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (IsUtf16()) {
// With /u, decimal escape is not interpreted as octal character code.
ParseError("Invalid class escape");
return 0;
}
result = ParseOctalLiteral();
break;
// ParseHexEscapeSequence
// ParseRegExpUnicodeEscapeSequence
case 'x': {
Advance();
if (ParseHexEscape(UNICODE_HEX_ADVANCE, &result)) {
return result;
}
if (IsUtf16()) {
ParseError("Invalid class escape");
return -1;
}
result = 'x';
break;
}
case 'u': {
Advance();
if (ParseUnicodeEscape(&result)) {
return result;
}
if (IsUtf16()) {
// With /u, invalid escapes are not treated as identity escapes.
ParseError("Invalid unicode escape");
return 0;
}
// If \u is not followed by a two-digit hexadecimal, treat it
// as an identity escape.
result = 'u';
} break;
// IdentityEscape[?U]
case '$':
case '(':
case ')':
case '*':
case '+':
case '.':
case '/':
case '?':
case '[':
case '\\':
case ']':
case '^':
case '{':
case '|':
case '}':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("IdentityEscape %c\n", c0_);
result = c0_;
Advance();
break;
default:
if (IsUtf16()) {
ParseError("Invalid unicode escape");
return 0;
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("SourceCharacter %c\n", c0_);
result = c0_;
Advance();
break;
}
return result;
}
bool RegExpParser::ParseClassRanges(RangeSet *result)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse ClassRanges------\n");
while (c0_ != ']') {
RangeSet s1;
uint32_t c1 = ParseClassAtom(&s1);
if (c1 == UINT32_MAX) {
ParseError("invalid class range");
return false;
}
int next_c0 = *pc_;
if (c0_ == '-' && next_c0 != ']') {
if (c1 == CLASS_RANGE_BASE) {
if (IsUtf16()) {
ParseError("invalid class range");
return false;
}
result->Insert(s1);
continue;
}
Advance();
RangeSet s2;
uint32_t c2 = ParseClassAtom(&s2);
if (c2 == UINT32_MAX) {
ParseError("invalid class range");
return false;
}
if (c2 == CLASS_RANGE_BASE) {
if (IsUtf16()) {
ParseError("invalid class range");
return false;
}
result->Insert(s2);
continue;
}
if (c1 > c2) {
ParseError("invalid class range");
return false;
}
if (IsIgnoreCase()) {
c1 = static_cast<uint32_t>(Canonicalize(c1, IsUtf16()));
c2 = static_cast<uint32_t>(Canonicalize(c2, IsUtf16()));
}
result->Insert(c1, c2);
} else {
result->Insert(s1);
}
}
Advance();
return true;
}
uint32_t RegExpParser::ParseClassAtom(RangeSet *atom)
{
uint32_t ret = UINT32_MAX;
switch (c0_) {
case '\\': {
Advance();
ret = static_cast<uint32_t>(ParseClassEscape(atom));
} break;
case KEY_EOF:
break;
case 0:
if (pc_ >= end_) {
return UINT32_MAX;
}
[[fallthrough]];
default:
uint32_t value = c0_;
size_t u16_size = 0;
if (c0_ > INT8_MAX) { // NOLINTNEXTLINE(readability-magic-numbers)
pc_ -= 1; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
auto u16_result = base::utf_helper::ConvertUtf8ToUtf16Pair(pc_, true);
value = u16_result.first;
u16_size = u16_result.second;
Advance(u16_size + 1);
} else {
Advance();
}
if (IsIgnoreCase()) {
value = static_cast<uint32_t>(Canonicalize(value, IsUtf16()));
}
atom->Insert(RangeSet(value));
ret = value;
break;
}
return ret;
}
int RegExpParser::ParseClassEscape(RangeSet *atom)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("Parse ClassEscape------\n");
int result = -1;
switch (c0_) {
case 'b':
Advance();
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ClassEscape %c", 'b');
result = '\b';
atom->Insert(RangeSet(static_cast<uint32_t>('\b')));
break;
case '-':
Advance();
result = '-';
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ClassEscape %c", '-');
atom->Insert(RangeSet(static_cast<uint32_t>('-')));
break;
// CharacterClassEscape
case 'd':
case 'D':
result = CLASS_RANGE_BASE;
atom->Insert(g_rangeD);
if (c0_ == 'D') {
atom->Invert(IsUtf16());
}
Advance();
break;
case 's':
case 'S':
result = CLASS_RANGE_BASE;
atom->Insert(g_rangeS);
if (c0_ == 'S') {
atom->Invert(IsUtf16());
}
Advance();
break;
case 'w':
case 'W':
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("ClassEscape::CharacterClassEscape %c\n", c0_);
result = CLASS_RANGE_BASE;
atom->Insert(g_rangeW);
if (c0_ == 'W') {
atom->Invert(IsUtf16());
}
Advance();
break;
// P{UnicodePropertyValueExpression}
// p{UnicodePropertyValueExpression}
case 'P':
case 'p':
PrintF("Warning: \\p is not supported in ECMA 2015!");
Advance();
if (c0_ == '{') {
Advance();
if (c0_ == '}') {
break; // p{}, invalid
}
bool isValue = false;
ParseUnicodePropertyValueCharacters(&isValue);
if (!isValue && c0_ == '=') {
// UnicodePropertyName = UnicodePropertyValue
Advance();
if (c0_ == '}') {
break; // p{xxx=}, invalid
}
ParseUnicodePropertyValueCharacters(&isValue);
}
if (c0_ != '}') {
break; // p{xxx, invalid
}
// should do atom->Invert() here after ECMA 9.0
Advance();
result = CLASS_RANGE_BASE;
}
break;
default:
result = ParseCharacterEscape();
int value = result;
if (IsIgnoreCase()) {
value = Canonicalize(value, IsUtf16());
}
atom->Insert(RangeSet(static_cast<uint32_t>(value)));
break;
}
return result;
}
void RegExpParser::ParseUnicodePropertyValueCharacters(bool *isValue)
{
if ((c0_ >= 'A' && c0_ <= 'Z') || (c0_ >= 'a' && c0_ <= 'z')) {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("UnicodePropertyCharacter::ControlLetter %c\n", c0_);
} else if (c0_ == '_') {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("UnicodePropertyCharacter:: _ \n");
} else if (c0_ >= '0' && c0_ <= '9') {
*isValue = true;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("UnicodePropertyValueCharacter::DecimalDigit %c\n", c0_);
} else {
return;
}
Advance();
ParseUnicodePropertyValueCharacters(isValue);
}
// NOLINTNEXTLINE(cert-dcl50-cpp)
void RegExpParser::PrintF(const char *fmt, ...)
{
#ifndef _NO_DEBUG_
va_list args;
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,)
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
#else
(void)fmt;
#endif
}
void RegExpParser::ParseError(const char *errorMessage)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("error: ");
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF(errorMessage);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
PrintF("\n");
SetIsError();
size_t length = strlen(errorMessage) + 1;
if (memcpy_s(errorMsg_, length, errorMessage, length) != EOK) {
LOG_ECMA(FATAL) << "memcpy_s failed";
UNREACHABLE();
}
}
} // namespace panda::ecmascript