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); }
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); }
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); }