diff options
Diffstat (limited to 'src/bun.js/bindings/OnigurumaRegExp.cpp')
-rw-r--r-- | src/bun.js/bindings/OnigurumaRegExp.cpp | 903 |
1 files changed, 0 insertions, 903 deletions
diff --git a/src/bun.js/bindings/OnigurumaRegExp.cpp b/src/bun.js/bindings/OnigurumaRegExp.cpp deleted file mode 100644 index 446a576e8..000000000 --- a/src/bun.js/bindings/OnigurumaRegExp.cpp +++ /dev/null @@ -1,903 +0,0 @@ -#include "OnigurumaRegExp.h" - -#include "ZigGlobalObject.h" -#define ONIG_ESCAPE_UCHAR_COLLISION -#include "oniguruma/src/oniguruma.h" - -using namespace JSC; -using namespace WebCore; - -#include "WebCoreJSClientData.h" - -extern "C" EncodedJSValue jsFunctionGetOnigurumaRegExpConstructor(JSGlobalObject* lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName) -{ - auto& vm = lexicalGlobalObject->vm(); - Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); - return JSValue::encode(globalObject->OnigurumaRegExpConstructor()); -} - -namespace Zig { - -static WTF::String to16Bit(ASCIILiteral str) -{ - UChar* buffer = nullptr; - auto out = WTF::StringImpl::createUninitialized(str.length(), buffer); - WTF::StringImpl::copyCharacters(buffer, str.characters8(), str.length()); - return WTF::String(WTFMove(out)); -} - -static WTF::String to16Bit(JSC::JSString* str, JSC::JSGlobalObject* globalObject) -{ - if (!str->is8Bit() || str->length() == 0) { - return str->value(globalObject); - } - - auto value = str->value(globalObject); - auto outStr = WTF::String(value.characters8(), value.length()); - outStr.convertTo16Bit(); - return outStr; -} - -static WTF::String to16Bit(WTF::String str) -{ - if (str.is8Bit()) { - auto out = str.isolatedCopy(); - out.convertTo16Bit(); - return out; - } - - return str; -} - -static WTF::String to16Bit(JSValue jsValue, JSC::JSGlobalObject* globalObject, ASCIILiteral defaultValue) -{ - if (!jsValue || jsValue.isUndefinedOrNull()) { - return to16Bit(defaultValue); - } - - auto* jsString = jsValue.toString(globalObject); - if (jsString->length() == 0) { - return to16Bit(defaultValue); - } - - return to16Bit(jsString, globalObject); -} - -static WTF::String convertToOnigurumaSyntax(const WTF::String& string) -{ - WTF::StringBuilder sb; - uint32_t length = string.length(); - const UChar* characters = string.characters16(); - bool inCharacterClass = false; - bool inCharacterProperty = false; - - for (int i = 0; i < length; i++) { - - // extend multibyte hex characters - while (characters[i] == '\\') { - if (i + 1 < length && characters[i + 1] == 'x') { - if (i + 2 < length && isxdigit(characters[i + 2])) { - if (i + 3 < length && isxdigit(characters[i + 3])) { - sb.append(string.substring(i, 4)); - sb.append("\\x00"_s); - i += 4; - } else { - // skip '\' - sb.append(string.substring(i + 1, 2)); - i += 3; - } - } else { - break; - } - } else { - break; - } - } - - if (i >= length) { - break; - } - - // convert character properties - if (UNLIKELY(characters[i] == '{' && i - 2 >= 0 && (characters[i - 1] == 'p' || characters[i - 1] == 'P') && characters[i - 2] == '\\')) { - sb.append(characters[i]); - i += 1; - if (i == length) { - break; - } - - // handle negative - if (characters[i] == '^') { - sb.append(characters[i]); - i += 1; - if (i == length) { - break; - } - } - - // could be \p{propName=propValue} or \p{propValue}. - bool foundEquals = false; - WTF::StringBuilder propName; - while (characters[i] != '}') { - if (characters[i] == '=') { - foundEquals = true; - i += 1; - if (i == length) { - break; - } - continue; - } - - if (foundEquals) { - sb.append(characters[i]); - } else { - propName.append(characters[i]); - } - - i += 1; - if (i == length) { - break; - } - } - - if (!foundEquals) { - sb.append(propName.toString()); - } - } - - if (i >= length) { - break; - } - - // escape brackets in character classes - if (inCharacterClass) { - // we know ']' will be escaped so there isn't a need to scan for the closing bracket - if (characters[i] == '[' || characters[i] == ']') { - if (characters[i - 1] != '\\') { - // character class intersections not supported, assume end of character class - if (characters[i] == ']') { - inCharacterClass = false; - } else { - sb.append('\\'); - } - } - } - } else { - if (characters[i] == '[') { - if (i - 1 >= 0) { - if (characters[i - 1] != '\\') { - inCharacterClass = true; - } - } else { - inCharacterClass = true; - } - } - } - - sb.append(characters[i]); - } - - return to16Bit(sb.toString()); -} - -static inline bool is16BitLineTerminator(UChar c) -{ - return c == '\r' || c == '\n' || (c & ~1) == 0x2028; -} - -static inline WTF::String escapedPattern(const WTF::String& pattern, const UChar* characters, size_t length) -{ - bool previousCharacterWasBackslash = false; - bool inBrackets = false; - bool shouldEscape = false; - - // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/', - // and also states that the result must be a valid RegularExpressionLiteral. '//' is - // not a valid RegularExpressionLiteral (since it is a single line comment), and hence - // source cannot ever validly be "". If the source is empty, return a different Pattern - // that would match the same thing. - if (!length) - return "(?:)"_s; - - // early return for strings that don't contain a forwards slash and LineTerminator - for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') { - shouldEscape = true; - break; - } - if (ch == '[') - inBrackets = true; - } - } - - if (is16BitLineTerminator(ch)) { - shouldEscape = true; - break; - } - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - if (!shouldEscape) - return pattern; - - previousCharacterWasBackslash = false; - inBrackets = false; - StringBuilder result; - for (unsigned i = 0; i < length; ++i) { - UChar ch = characters[i]; - if (!previousCharacterWasBackslash) { - if (inBrackets) { - if (ch == ']') - inBrackets = false; - } else { - if (ch == '/') - result.append('\\'); - else if (ch == '[') - inBrackets = true; - } - } - - // escape LineTerminator - if (is16BitLineTerminator(ch)) { - if (!previousCharacterWasBackslash) { - result.append('\\'); - } - - if (ch == '\n') { - result.append('n'); - } else if (ch == '\r') { - result.append('r'); - } else if (ch == 0x2028) { - result.append("u2028"); - } else { - result.append("u2029"); - } - } else - result.append(ch); - - if (previousCharacterWasBackslash) - previousCharacterWasBackslash = false; - else - previousCharacterWasBackslash = ch == '\\'; - } - - return result.toString(); -} - -WTF::String sortRegExpFlags(WTF::String flagsString) -{ - WTF::Vector<UChar> flags = { 'd', 'g', 'i', 'm', 's', 'u', 'y' }; - WTF::StringBuilder result; - - for (auto flag : flags) { - if (flagsString.contains(flag)) { - result.append(flag); - } - } - - return result.toString(); -} - -bool validateRegExpFlags(WTF::StringView flags) -{ - std::map<char16_t, bool> flagsAllowed = { { 'g', false }, { 'i', false }, { 'm', false }, { 's', false }, { 'u', false }, { 'y', false }, { 'd', false } }; - for (auto flag : flags.codeUnits()) { - auto flagItr = flagsAllowed.find(flag); - if (flagItr == flagsAllowed.end() || flagItr->second) { - return false; - } - flagItr->second = true; - } - - return true; -} - -std::once_flag onigurumaEncodingInitFlag; - -static regex_t* createOnigurumaRegExp(JSGlobalObject* globalObject, const WTF::String& patternString, const WTF::String& flagsString, int& errorCode, OnigErrorInfo& errorInfo) -{ - auto& vm = globalObject->vm(); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - OnigEncoding encodings[] = { - ONIG_ENCODING_UTF16_LE, - }; - std::call_once(onigurumaEncodingInitFlag, [&encodings]() { - onig_initialize(encodings, 1); - }); - - OnigOptionType options = 0; - if (flagsString.contains('i')) { - options |= ONIG_OPTION_IGNORECASE; - } - if (flagsString.contains('m')) { - options |= ONIG_OPTION_MULTILINE; - } else { - options |= ONIG_OPTION_SINGLELINE; - } - if (flagsString.contains('s')) { - options |= ONIG_OPTION_MULTILINE; - } - - OnigSyntaxType* syntax = ONIG_SYNTAX_ONIGURUMA; - OnigEncodingType* encoding = encodings[0]; - regex_t* onigRegExp = NULL; - - errorCode = onig_new( - &onigRegExp, - reinterpret_cast<const OnigUChar*>(patternString.characters16()), - reinterpret_cast<const OnigUChar*>(patternString.characters16() + patternString.length()), - options, - encoding, - syntax, - &errorInfo); - - return onigRegExp; -} - -class OnigurumaRegExpPrototype final : public JSC::JSNonFinalObject { -public: - using Base = JSC::JSNonFinalObject; - - static OnigurumaRegExpPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure) - { - OnigurumaRegExpPrototype* ptr = new (NotNull, JSC::allocateCell<OnigurumaRegExpPrototype>(vm)) OnigurumaRegExpPrototype(vm, globalObject, structure); - ptr->finishCreation(vm, globalObject); - return ptr; - } - - DECLARE_INFO; - template<typename CellType, JSC::SubspaceAccess> - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - return &vm.plainObjectSpace(); - } - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - -private: - OnigurumaRegExpPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) - : Base(vm, structure) - { - } - - void finishCreation(JSC::VM&, JSC::JSGlobalObject*); -}; - -const ClassInfo OnigurumaRegExpConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(OnigurumaRegExpConstructor) }; -const ClassInfo OnigurumaRegExpPrototype::s_info = { "Object"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(OnigurumaRegExpPrototype) }; -const ClassInfo OnigurumaRegEx::s_info = { "RegExp"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(OnigurumaRegEx) }; - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterGlobal, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('g'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterDotAll, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('s'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterHasIndices, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('d'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterIgnoreCase, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('i'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterMultiline, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('m'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterSticky, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('y'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterUnicode, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsBoolean(thisValue->flagsString().contains('u'))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterSource, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (!thisValue) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(jsString(globalObject->vm(), escapedPattern(thisValue->patternString(), thisValue->patternString().characters16(), thisValue->patternString().length()))); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterFlags, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (!thisValue) - return JSValue::encode(jsUndefined()); - - return JSValue::encode(jsString(globalObject->vm(), thisValue->flagsString())); -} - -JSC_DEFINE_CUSTOM_GETTER(onigurumaRegExpProtoGetterLastIndex, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - return JSValue::encode(jsNumber(thisValue->m_lastIndex)); -} - -JSC_DEFINE_CUSTOM_SETTER(onigurumaRegExpProtoSetterLastIndex, (JSGlobalObject * globalObject, EncodedJSValue encodedThis, EncodedJSValue encodedValue, PropertyName)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(JSValue::decode(encodedThis)); - if (UNLIKELY(!thisValue)) { - return JSValue::encode(jsUndefined()); - } - auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm()); - JSValue value = JSValue::decode(encodedValue); - if (!value.isAnyInt()) { - throwException(globalObject, throwScope, createTypeError(globalObject, "lastIndex must be an integer"_s)); - return false; - } - int32_t lastIndex = value.toInt32(globalObject); - thisValue->m_lastIndex = lastIndex; - return true; -} - -// compile is deprecated -JSC_DEFINE_HOST_FUNCTION(onigurumaRegExpProtoFuncCompile, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - VM& vm = globalObject->vm(); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - JSValue thisValue = callFrame->thisValue(); - auto* thisRegExp = jsDynamicCast<OnigurumaRegEx*>(callFrame->thisValue()); - if (UNLIKELY(!thisRegExp)) - return JSValue::encode(jsUndefined()); - - if (thisRegExp->globalObject() != globalObject) { - throwScope.throwException(globalObject, createTypeError(globalObject, makeString("RegExp.prototype.compile function's Realm must be the same to |this| RegExp object"_s))); - return JSValue::encode({}); - } - - JSValue arg0 = callFrame->argument(0); - JSValue arg1 = callFrame->argument(1); - - WTF::String patternStringExtended; - if (auto* regExpObject = jsDynamicCast<OnigurumaRegEx*>(arg0)) { - if (!arg1.isUndefined()) { - throwScope.throwException(globalObject, createTypeError(globalObject, makeString("Cannot supply flags when constructing one RegExp from another."_s))); - return JSValue::encode({}); - } - thisRegExp->setPatternString(regExpObject->patternString()); - patternStringExtended = convertToOnigurumaSyntax(thisRegExp->patternString()); - thisRegExp->setFlagsString(regExpObject->flagsString()); - } else { - WTF::String newPatternString = to16Bit(arg0, globalObject, "(?:)"_s); - RETURN_IF_EXCEPTION(scope, {}); - - patternStringExtended = convertToOnigurumaSyntax(newPatternString); - - WTF::String newFlagsString = to16Bit(arg1, globalObject, ""_s); - RETURN_IF_EXCEPTION(scope, {}); - - if (!validateRegExpFlags(newFlagsString)) { - throwScope.throwException(globalObject, createSyntaxError(globalObject, makeString("Invalid flags supplied to RegExp constructor."_s))); - return JSValue::encode({}); - } - - newFlagsString = sortRegExpFlags(newFlagsString); - - thisRegExp->setPatternString(newPatternString); - thisRegExp->setFlagsString(newFlagsString); - } - - // for pattern syntax checking - int errorCode = 0; - OnigErrorInfo errorInfo = { 0 }; - regex_t* onigurumaRegExp = createOnigurumaRegExp(globalObject, convertToOnigurumaSyntax(thisRegExp->patternString()), thisRegExp->flagsString(), errorCode, errorInfo); - if (errorCode != ONIG_NORMAL) { - OnigUChar errorBuff[ONIG_MAX_ERROR_MESSAGE_LEN] = { 0 }; - int length = onig_error_code_to_str(errorBuff, errorCode, &errorInfo); - WTF::StringBuilder errorMessage; - errorMessage.append("Invalid regular expression: "_s); - if (length < 0) { - errorMessage.append("An unknown error occurred."_s); - } else { - errorMessage.appendCharacters(errorBuff, length); - } - if (onigurumaRegExp != nullptr) { - onig_free(onigurumaRegExp); - } - throwScope.throwException(globalObject, createSyntaxError(globalObject, errorMessage.toString())); - return JSValue::encode({}); - } - onig_free(onigurumaRegExp); - - thisRegExp->m_lastIndex = 0; - - return JSValue::encode(thisRegExp); -} - -JSC_DEFINE_HOST_FUNCTION(onigurumaRegExpProtoFuncTest, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(callFrame->thisValue()); - if (!thisValue) - return JSValue::encode(jsUndefined()); - - JSValue arg = callFrame->argument(0); - if (!arg.isString()) { - scope.throwException(globalObject, createTypeError(globalObject, "Argument 0 of RegExp.prototype.test must be a string"_s)); - return JSValue::encode(jsBoolean(false)); - } - - WTF::String string = to16Bit(arg, globalObject, ""_s); - RETURN_IF_EXCEPTION(scope, JSValue::encode({})); - - int errorCode = 0; - OnigErrorInfo errorInfo = { 0 }; - regex_t* onigurumaRegExp = createOnigurumaRegExp(globalObject, convertToOnigurumaSyntax(thisValue->patternString()), thisValue->flagsString(), errorCode, errorInfo); - if (errorCode != ONIG_NORMAL) { - OnigUChar errorBuff[ONIG_MAX_ERROR_MESSAGE_LEN] = { 0 }; - int length = onig_error_code_to_str(errorBuff, errorCode, &errorInfo); - WTF::StringBuilder errorMessage; - errorMessage.append("Invalid regular expression: "_s); - if (length < 0) { - errorMessage.append("An unknown error occurred."_s); - } else { - errorMessage.appendCharacters(errorBuff, length); - } - if (onigurumaRegExp != nullptr) { - onig_free(onigurumaRegExp); - } - throwScope.throwException(globalObject, createSyntaxError(globalObject, errorMessage.toString())); - return JSValue::encode({}); - } - - OnigRegion* region = onig_region_new(); - - const OnigUChar* end = reinterpret_cast<const OnigUChar*>(string.characters16() + string.length()); - const OnigUChar* start = reinterpret_cast<const OnigUChar*>(string.characters16() + thisValue->m_lastIndex); - const OnigUChar* range = end; - - if (thisValue->m_lastIndex >= string.length()) { - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - thisValue->m_lastIndex = 0; - return JSValue::encode(jsBoolean(false)); - } - - int result = onig_search( - onigurumaRegExp, - reinterpret_cast<const OnigUChar*>(string.characters16()), - end, - start, - range, - region, - ONIG_OPTION_DEFAULT); - - if (result < 0) { - thisValue->m_lastIndex = 0; - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - return JSValue::encode(jsBoolean(false)); - } - - if (thisValue->flagsString().contains('y') && region->beg[0] != thisValue->m_lastIndex) { - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - return JSValue::encode(jsBoolean(false)); - } - - if (thisValue->flagsString().contains('g')) { - thisValue->m_lastIndex = region->end[0] / 2; - } else { - thisValue->m_lastIndex = 0; - } - - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - - return JSValue::encode(jsBoolean(true)); -} - -JSC_DEFINE_HOST_FUNCTION(onigurumaRegExpProtoFuncExec, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(callFrame->thisValue()); - if (!thisValue) - return JSValue::encode(jsUndefined()); - - JSValue arg = callFrame->argument(0); - if (!arg || arg.isUndefinedOrNull()) { - thisValue->m_lastIndex = 0; - return JSValue::encode(jsNull()); - } - - WTF::String string = to16Bit(arg, globalObject, ""_s); - RETURN_IF_EXCEPTION(scope, JSValue::encode({})); - - int errorCode = 0; - OnigErrorInfo errorInfo = { 0 }; - regex_t* onigurumaRegExp = createOnigurumaRegExp(globalObject, convertToOnigurumaSyntax(thisValue->patternString()), thisValue->flagsString(), errorCode, errorInfo); - if (errorCode != ONIG_NORMAL) { - OnigUChar errorBuff[ONIG_MAX_ERROR_MESSAGE_LEN] = { 0 }; - int length = onig_error_code_to_str(errorBuff, errorCode, &errorInfo); - WTF::StringBuilder errorMessage; - errorMessage.append("Invalid regular expression: "_s); - if (length < 0) { - errorMessage.append("An unknown error occurred."_s); - } else { - errorMessage.appendCharacters(errorBuff, length); - } - if (onigurumaRegExp != nullptr) { - onig_free(onigurumaRegExp); - } - throwScope.throwException(globalObject, createSyntaxError(globalObject, errorMessage.toString())); - return JSValue::encode({}); - } - - OnigRegion* region = onig_region_new(); - - const OnigUChar* end = reinterpret_cast<const OnigUChar*>(string.characters16() + string.length()); - const OnigUChar* start = reinterpret_cast<const OnigUChar*>(string.characters16() + thisValue->m_lastIndex); - const OnigUChar* range = end; - - int result = onig_search( - onigurumaRegExp, - reinterpret_cast<const OnigUChar*>(string.characters16()), - end, - start, - range, - region, - ONIG_OPTION_DEFAULT); - - if (result < 0) { - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - thisValue->m_lastIndex = 0; - return JSValue::encode(jsNull()); - } - - JSArray* array = constructEmptyArray(globalObject, nullptr, 0); - RETURN_IF_EXCEPTION(scope, JSValue::encode({})); - JSArray* indicesArray = constructEmptyArray(globalObject, nullptr, 0); - RETURN_IF_EXCEPTION(scope, JSValue::encode({})); - - array->putDirect(vm, vm.propertyNames->index, jsNumber(region->beg[0] / 2)); - array->putDirect(vm, vm.propertyNames->input, jsString(vm, string)); - array->putDirect(vm, vm.propertyNames->groups, jsUndefined()); - - for (int i = 0; i < region->num_regs; i++) { - size_t outStringLen = (region->end[i] / 2) - (region->beg[i] / 2); - UChar* ptr; - WTF::String outString; - if (outStringLen > 0) { - outString = WTF::String::createUninitialized(static_cast<unsigned int>(outStringLen), ptr); - if (UNLIKELY(!ptr)) { - throwOutOfMemoryError(globalObject, scope); - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - return JSValue::encode(jsNull()); - } - - memcpy(ptr, (region->beg[i] / 2) + string.characters16(), outStringLen * sizeof(UChar)); - } - - array->putDirectIndex(globalObject, i, jsString(vm, outString)); - - JSArray* indices = constructEmptyArray(globalObject, nullptr, 0); - RETURN_IF_EXCEPTION(scope, JSValue::encode({})); - indices->putDirectIndex(globalObject, 0, jsNumber(region->beg[i] / 2)); - indices->putDirectIndex(globalObject, 1, jsNumber(region->end[i] / 2)); - indicesArray->putDirectIndex(globalObject, i, indices); - } - - if (thisValue->flagsString().contains('d')) { - array->putDirect(vm, vm.propertyNames->indices, indicesArray); - } - - if (thisValue->flagsString().contains('g')) { - thisValue->m_lastIndex = region->end[0] / 2; - } else { - thisValue->m_lastIndex = 0; - } - - onig_region_free(region, 1); - onig_free(onigurumaRegExp); - - return JSValue::encode(array); -} - -JSC_DEFINE_HOST_FUNCTION(onigurumaRegExpProtoFuncToString, (JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto* thisValue = jsDynamicCast<OnigurumaRegEx*>(callFrame->thisValue()); - if (!thisValue) - return JSValue::encode(jsUndefined()); - - WTF::String patternString = escapedPattern(thisValue->patternString(), thisValue->patternString().characters16(), thisValue->patternString().length()); - WTF::String flagsString = thisValue->flagsString(); - - WTF::StringBuilder source; - source.append("/"_s); - source.append(patternString); - source.append("/"_s); - source.append(flagsString); - - return JSValue::encode(jsString(globalObject->vm(), source.toString())); -} - -void OnigurumaRegExpPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - this->putDirectNativeFunction(vm, globalObject, PropertyName(vm.propertyNames->compile), 2, onigurumaRegExpProtoFuncCompile, ImplementationVisibility::Public, NoIntrinsic, static_cast<unsigned>(0)); - this->putDirectNativeFunction(vm, globalObject, PropertyName(vm.propertyNames->exec), 1, onigurumaRegExpProtoFuncExec, ImplementationVisibility::Public, NoIntrinsic, static_cast<unsigned>(0)); - this->putDirectNativeFunction(vm, globalObject, PropertyName(vm.propertyNames->toString), 0, onigurumaRegExpProtoFuncToString, ImplementationVisibility::Public, NoIntrinsic, static_cast<unsigned>(0)); - this->putDirectCustomAccessor(vm, vm.propertyNames->global, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterGlobal, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->dotAll, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterDotAll, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->hasIndices, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterHasIndices, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->ignoreCase, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterIgnoreCase, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->multiline, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterMultiline, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->sticky, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterSticky, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->unicode, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterUnicode, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->source, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterSource, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->flags, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterFlags, nullptr), 0 | PropertyAttribute::CustomAccessor | PropertyAttribute::ReadOnly); - this->putDirectCustomAccessor(vm, vm.propertyNames->lastIndex, JSC::CustomGetterSetter::create(vm, onigurumaRegExpProtoGetterLastIndex, onigurumaRegExpProtoSetterLastIndex), 0 | PropertyAttribute::CustomAccessor); - - this->putDirectNativeFunction(vm, globalObject, PropertyName(vm.propertyNames->test), 1, onigurumaRegExpProtoFuncTest, ImplementationVisibility::Public, NoIntrinsic, static_cast<unsigned>(0)); - - this->putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->matchSymbol, onigurumaRegExpPrototypeMatchCodeGenerator(vm), static_cast<unsigned>(0)); - this->putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->matchAllSymbol, onigurumaRegExpPrototypeMatchAllCodeGenerator(vm), static_cast<unsigned>(0)); - this->putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->replaceSymbol, onigurumaRegExpPrototypeReplaceCodeGenerator(vm), static_cast<unsigned>(0)); - this->putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->searchSymbol, onigurumaRegExpPrototypeSearchCodeGenerator(vm), static_cast<unsigned>(0)); - this->putDirectBuiltinFunction(vm, globalObject, vm.propertyNames->splitSymbol, onigurumaRegExpPrototypeSplitCodeGenerator(vm), static_cast<unsigned>(0)); -} - -JSC::Structure* OnigurumaRegExpConstructor::createClassStructure(JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) -{ - JSC::VM& vm = globalObject->vm(); - return OnigurumaRegEx::createStructure( - vm, - globalObject, - prototype); -} -JSC::JSObject* OnigurumaRegExpConstructor::createPrototype(JSC::JSGlobalObject* globalObject) -{ - return OnigurumaRegExpPrototype::create(globalObject->vm(), globalObject, OnigurumaRegExpPrototype::createStructure(globalObject->vm(), globalObject, globalObject->objectPrototype())); -} - -void OnigurumaRegExpConstructor::finishCreation(VM& vm, JSValue prototype) -{ - - Base::finishCreation(vm, 0, "RegExp"_s, PropertyAdditionMode::WithoutStructureTransition); - putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); - ASSERT(inherits(info())); -} - -OnigurumaRegExpConstructor* OnigurumaRegExpConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSValue prototype) -{ - OnigurumaRegExpConstructor* ptr = new (NotNull, JSC::allocateCell<OnigurumaRegExpConstructor>(vm)) OnigurumaRegExpConstructor(vm, structure, construct); - ptr->finishCreation(vm, prototype); - return ptr; -} - -static JSC::EncodedJSValue constructOrCall(Zig::GlobalObject* globalObject, JSValue arg0, JSValue arg1) -{ - auto& vm = globalObject->vm(); - auto scope = DECLARE_CATCH_SCOPE(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - WTF::String patternString = to16Bit(arg0, globalObject, "(?:)"_s); - RETURN_IF_EXCEPTION(scope, {}); - - WTF::String flagsString = to16Bit(arg1, globalObject, ""_s); - RETURN_IF_EXCEPTION(scope, {}); - - if (!validateRegExpFlags(flagsString)) { - throwScope.throwException(globalObject, createSyntaxError(globalObject, makeString("Invalid flags supplied to RegExp constructor."_s))); - return JSValue::encode({}); - } - - flagsString = sortRegExpFlags(flagsString); - - // create for pattern compilation errors, but need to create another for each exec/test - int errorCode = 0; - OnigErrorInfo errorInfo = { 0 }; - regex_t* onigurumaRegExp = createOnigurumaRegExp(globalObject, convertToOnigurumaSyntax(patternString), flagsString, errorCode, errorInfo); - if (errorCode != ONIG_NORMAL) { - OnigUChar errorBuff[ONIG_MAX_ERROR_MESSAGE_LEN] = { 0 }; - int length = onig_error_code_to_str(errorBuff, errorCode, &errorInfo); - WTF::StringBuilder errorMessage; - errorMessage.append("Invalid regular expression: "_s); - if (length < 0) { - errorMessage.append("An unknown error occurred."_s); - } else { - errorMessage.appendCharacters(errorBuff, length); - } - throwScope.throwException(globalObject, createSyntaxError(globalObject, errorMessage.toString())); - return JSValue::encode({}); - } - onig_free(onigurumaRegExp); - - OnigurumaRegEx* result = OnigurumaRegEx::create(globalObject, WTFMove(patternString), WTFMove(flagsString)); - - return JSValue::encode(result); -} - -JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES OnigurumaRegExpConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame) -{ - Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); - JSC::VM& vm = globalObject->vm(); - JSObject* newTarget = asObject(callFrame->newTarget()); - auto* constructor = globalObject->OnigurumaRegExpConstructor(); - Structure* structure = globalObject->OnigurumaRegExpStructure(); - if (constructor != newTarget) { - auto scope = DECLARE_THROW_SCOPE(vm); - - auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>( - // ShadowRealm functions belong to a different global object. - getFunctionRealm(globalObject, newTarget)); - RETURN_IF_EXCEPTION(scope, {}); - structure = InternalFunction::createSubclassStructure( - globalObject, - newTarget, - functionGlobalObject->OnigurumaRegExpStructure()); - } - - return constructOrCall(globalObject, callFrame->argument(0), callFrame->argument(1)); -} - -} |