JSValue* regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) { if (!thisValue->isObject(&RegExpObject::info)) return throwError(exec, TypeError); RefPtr<RegExp> regExp; JSValue* arg0 = args.at(exec, 0); JSValue* arg1 = args.at(exec, 1); if (arg0->isObject(&RegExpObject::info)) { if (!arg1->isUndefined()) return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); regExp = asRegExpObject(arg0)->regExp(); } else { UString pattern = args.isEmpty() ? UString("") : arg0->toString(exec); UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec); regExp = RegExp::create(&exec->globalData(), pattern, flags); } if (!regExp->isValid()) return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage())); asRegExpObject(thisValue)->setRegExp(regExp.release()); asRegExpObject(thisValue)->setLastIndex(0); return jsUndefined(); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::info)) return throwVMTypeError(exec); RefPtr<RegExp> regExp; JSValue arg0 = exec->argument(0); JSValue arg1 = exec->argument(1); if (arg0.inherits(&RegExpObject::info)) { if (!arg1.isUndefined()) return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); regExp = asRegExpObject(arg0)->regExp(); } else { UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec); regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); } if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, makeString("Invalid regular expression: ", regExp->errorMessage()))); asRegExpObject(thisValue)->setRegExp(regExp.release()); asRegExpObject(thisValue)->setLastIndex(0); return JSValue::encode(jsUndefined()); }
void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); slot.setCustomProperty(asRegExpObject(cell), slot.isStrictMode() ? regExpObjectSetLastIndexStrict : regExpObjectSetLastIndexNonStrict); return; } Base::put(cell, exec, propertyName, value, slot); }
bool RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { RegExpObject* thisObject = jsCast<RegExpObject*>(cell); if (UNLIKELY(isThisValueAltered(slot, thisObject))) return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()); if (propertyName == exec->propertyNames().lastIndex) { bool result = asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); slot.setCustomValue(asRegExpObject(cell), slot.isStrictMode() ? regExpObjectSetLastIndexStrict : regExpObjectSetLastIndexNonStrict); return result; } return Base::put(cell, exec, propertyName, value, slot); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec))); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::info)) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->exec(exec)); }
bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool shouldThrow) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); if (descriptor.configurablePresent() && descriptor.configurable()) return reject(exec, shouldThrow, "Attempting to change configurable attribute of unconfigurable property."); if (descriptor.enumerablePresent() && descriptor.enumerable()) return reject(exec, shouldThrow, "Attempting to change enumerable attribute of unconfigurable property."); if (descriptor.isAccessorDescriptor()) return reject(exec, shouldThrow, "Attempting to change access mechanism for an unconfigurable property."); if (!regExp->m_lastIndexIsWritable) { if (descriptor.writablePresent() && descriptor.writable()) return reject(exec, shouldThrow, "Attempting to change writable attribute of unconfigurable property."); if (!sameValue(exec, regExp->getLastIndex(), descriptor.value())) return reject(exec, shouldThrow, "Attempting to change value of a readonly property."); return true; } if (descriptor.writablePresent() && !descriptor.writable()) regExp->m_lastIndexIsWritable = false; if (descriptor.value()) regExp->setLastIndex(exec, descriptor.value(), false); return true; } return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->argument(0).toString(exec)))); }
bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (propertyName == vm.propertyNames->lastIndex) { RegExpObject* regExp = asRegExpObject(object); if (descriptor.configurablePresent() && descriptor.configurable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeConfigurabilityError)); if (descriptor.enumerablePresent() && descriptor.enumerable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeEnumerabilityError)); if (descriptor.isAccessorDescriptor()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeAccessMechanismError)); if (!regExp->m_lastIndexIsWritable) { if (descriptor.writablePresent() && descriptor.writable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeWritabilityError)); if (!sameValue(exec, regExp->getLastIndex(), descriptor.value())) return typeError(exec, scope, shouldThrow, ASCIILiteral(ReadonlyPropertyChangeError)); return true; } if (descriptor.value()) { regExp->setLastIndex(exec, descriptor.value(), false); RETURN_IF_EXCEPTION(scope, false); } if (descriptor.writablePresent() && !descriptor.writable()) regExp->m_lastIndexIsWritable = false; return true; } scope.release(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) { if (thisValue.inherits(&RegExpPrototype::s_info)) return JSValue::encode(jsNontrivialString(exec, "//")); return throwVMTypeError(exec); } RegExpObject* thisObject = asRegExpObject(thisValue); StringRecursionChecker checker(exec, thisObject); if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) return earlyReturnValue; char postfix[5] = { '/', 0, 0, 0, 0 }; int index = 1; if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec)) postfix[index++] = 'g'; if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) postfix[index++] = 'i'; if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) postfix[index] = 'm'; UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec); // If source is empty, use "/(?:)/" to avoid colliding with comment syntax return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix)); }
JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, PropertyName) { String pattern = asRegExpObject(slotBase)->regExp()->pattern(); if (pattern.is8Bit()) return regExpObjectSourceInternal(exec, pattern, pattern.characters8(), pattern.length()); return regExpObjectSourceInternal(exec, pattern, pattern.characters16(), pattern.length()); }
EncodedJSValue JSC_HOST_CALL regExpProtoGetterUnicode(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return JSValue::encode(jsUndefined()); return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->unicode())); }
void RegExpObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { asRegExpObject(cell)->setLastIndex(exec, value, slot.isStrictMode()); return; } lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot); }
EncodedJSValue JSC_HOST_CALL regExpProtoGetterMultiline(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->regExp()->multiline())); }
JSValue* regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) { if (!thisValue->isObject(&RegExpObject::info)) { if (thisValue->isObject(&RegExpPrototype::info)) return jsNontrivialString(exec, "//"); return throwError(exec, TypeError); } UString result = "/" + asRegExpObject(thisValue)->get(exec, exec->propertyNames().source)->toString(exec); result.append('/'); if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().global)->toBoolean(exec)) result.append('g'); if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec)) result.append('i'); if (asRegExpObject(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean(exec)) result.append('m'); return jsNontrivialString(exec, result); }
EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) { if (!base->inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); ASSERT(argument->isString() || argument->isObject()); JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); return JSValue::encode(asRegExpObject(base)->exec(exec, input)); }
bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); slot.setValue(regExp, regExp->getLastIndex()); return true; } return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, slot); }
bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); descriptor.setDescriptor(regExp->getLastIndex(), regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly); return true; } return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, descriptor); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncMatchPrivate(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); JSString* string = exec->argument(0).toStringOrNull(exec); if (!string) return JSValue::encode(jsUndefined()); return JSValue::encode(asRegExpObject(thisValue)->matchGlobal(exec, exec->lexicalGlobalObject(), string)); }
bool RegExpObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); unsigned attributes = regExp->m_lastIndexIsWritable ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly; slot.setValue(regExp, attributes, regExp->getLastIndex()); return true; } return Base::getOwnPropertySlot(object, exec, propertyName, slot); }
EncodedJSValue JSC_HOST_CALL regExpProtoGetterSource(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); String pattern = asRegExpObject(thisValue)->regExp()->pattern(); if (pattern.is8Bit()) return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters8(), pattern.length())); return JSValue::encode(regExpProtoGetterSourceInternal(exec, pattern, pattern.characters16(), pattern.length())); }
size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) { if (!base->inherits(&RegExpObject::s_info)) { throwTypeError(exec); return false; } ASSERT(argument->isString() || argument->isObject()); JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); return asRegExpObject(base)->test(exec, input); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); RegExp* regExp; JSValue arg0 = exec->argument(0); JSValue arg1 = exec->argument(1); if (arg0.isSymbolic() || arg1.isSymbolic()) { Statistics::statistics()->accumulate("Concolic::MissingInstrumentation::regExpProtoFuncCompile", 1); } if (arg0.inherits(&RegExpObject::s_info)) { if (!arg1.isUndefined()) return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); regExp = asRegExpObject(arg0)->regExp(); } else { UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); RegExpFlags flags = NoFlags; if (!arg1.isUndefined()) { flags = regExpFlags(arg1.toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (flags == InvalidFlags) return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); } regExp = RegExp::create(exec->globalData(), pattern, flags); } if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); asRegExpObject(thisValue)->setRegExp(exec->globalData(), regExp); asRegExpObject(thisValue)->setLastIndex(exec, 0); return JSValue::encode(jsUndefined()); }
EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); if (!base->inherits(RegExpObject::info())) return throwVMTypeError(exec); ASSERT(argument->isString() || argument->isObject()); JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); return JSValue::encode(asRegExpObject(base)->exec(exec, input)); }
size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); if (!base->inherits(RegExpObject::info())) { throwTypeError(exec); return false; } ASSERT(argument->isString() || argument->isObject()); JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); return asRegExpObject(base)->test(exec, input); }
JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UString s = thisValue.toThisString(exec); JSValue a0 = args.at(0); UString u = s; RefPtr<RegExp> reg; RegExpObject* imp = 0; if (a0.isObject(&RegExpObject::info)) reg = asRegExpObject(a0)->regExp(); else { /* * ECMA 15.5.4.12 String.prototype.search (regexp) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ reg = RegExp::create(&exec->globalData(), a0.toString(exec)); } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; int matchLength; regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); if (!(reg->global())) { // case without 'g' flag is handled like RegExp.prototype.exec if (pos < 0) return jsNull(); return regExpConstructor->arrayOfMatches(exec); } // return array of matches MarkedArgumentBuffer list; int lastIndex = 0; while (pos >= 0) { list.append(jsSubstring(exec, u, pos, matchLength)); lastIndex = pos; pos += matchLength == 0 ? 1 : matchLength; regExpConstructor->performMatch(reg.get(), u, pos, pos, matchLength); } if (imp) imp->setLastIndex(lastIndex); if (list.isEmpty()) { // if there are no matches at all, it's important to return // Null instead of an empty array, because this matches // other browsers and because Null is a false value. return jsNull(); } return constructArray(exec, list); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); RegExp* regExp; JSValue arg0 = exec->argument(0); JSValue arg1 = exec->argument(1); if (arg0.inherits(RegExpObject::info())) { if (!arg1.isUndefined()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Cannot supply flags when constructing one RegExp from another."))); regExp = asRegExpObject(arg0)->regExp(); } else { String pattern = !exec->argumentCount() ? emptyString() : arg0.toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); RegExpFlags flags = NoFlags; if (!arg1.isUndefined()) { flags = regExpFlags(arg1.toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (flags == InvalidFlags) return throwVMError(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."))); } regExp = RegExp::create(exec->vm(), pattern, flags); } if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); asRegExpObject(thisValue)->setRegExp(exec->vm(), regExp); asRegExpObject(thisValue)->setLastIndex(exec, 0); return JSValue::encode(jsUndefined()); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); // TODO(Artemis): In some cases the containing symbolic value is not the same as the symbolic value in the // outer value. We should find a more permanent solution for handling symbolic strings. if (exec->argument(0).isSymbolic() && exec->argument(0).isString()) { exec->argument(0).makeSymbolic((Symbolic::StringExpression*)exec->argument(0).asSymbolic(), exec->globalData()); } return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec))); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncSearch(ExecState* exec) { JSValue thisValue = exec->thisValue(); if (!thisValue.inherits(RegExpObject::info())) return throwVMTypeError(exec); RegExp* regExp = asRegExpObject(thisValue)->regExp(); JSString* string = exec->argument(0).toString(exec); String s = string->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); MatchResult result = regExpConstructor->performMatch(exec->vm(), regExp, string, s, 0); return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1)); }
EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); JSValue arg = exec->argument(0); RegExpObject* reg = asRegExpObject(thisValue); JSValue result = jsBoolean(reg->test(exec, arg.toString(exec))); #ifdef ARTEMIS if (arg.isSymbolic()) { result.makeSymbolic(new Symbolic::StringRegexSubmatch((Symbolic::StringExpression*)arg.asSymbolic(), new std::string(reg->regExp()->pattern().ascii().data())), exec->globalData()); } #endif return JSValue::encode(result); }