JSC::JSInternalPromise* JSModuleLoader::resolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleNameValue, JSC::JSValue importerModuleKey) { JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject); // We use a Symbol as a special purpose; It means this module is an inline module. // So there is no correct URL to retrieve the module source code. If the module name // value is a Symbol, it is used directly as a module key. // // FIXME: Using symbols for an inline module is a current implementation details of WebKit. // Once the spec of this part is specified, we will recast these part. if (moduleNameValue.isSymbol()) return deferred->resolve(exec, moduleNameValue); if (!moduleNameValue.isString()) return deferred->reject(exec, JSC::createTypeError(exec, "Module name is not Symbol or String.")); String moduleName = asString(moduleNameValue)->value(exec); // Now, we consider the given moduleName as the same to the `import "..."` in the module code. // We use the completed URL as the unique module key. URL completedUrl; if (importerModuleKey.isSymbol()) completedUrl = m_document.completeURL(moduleName); else if (importerModuleKey.isUndefined()) completedUrl = m_document.completeURL(moduleName); else if (importerModuleKey.isString()) { URL importerModuleUrl(URL(), asString(importerModuleKey)->value(exec)); if (!importerModuleUrl.isValid()) return deferred->reject(exec, JSC::createTypeError(exec, "Importer module key is an invalid URL.")); completedUrl = m_document.completeURL(moduleName, importerModuleUrl); } else return deferred->reject(exec, JSC::createTypeError(exec, "Importer module key is not Symbol or String.")); if (!completedUrl.isValid()) return deferred->reject(exec, JSC::createTypeError(exec, "Module name constructs an invalid URL.")); return deferred->resolve(exec, jsString(exec, completedUrl.string())); }
void RegExpMatchesArray::fillArrayInstance(ExecState* exec) { RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData()); ASSERT(d); unsigned lastNumSubpatterns = d->lastNumSubPatterns; for (unsigned i = 0; i <= lastNumSubpatterns; ++i) { int start = d->lastOvector()[2 * i]; if (start >= 0) JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); else JSArray::put(exec, i, jsUndefined()); } PutPropertySlot slot; JSArray::put(exec, exec->propertyNames().index, jsNumber(d->lastOvector()[0]), slot); JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot); delete d; setSubclassData(0); }
void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(vm, info())); didBecomePrototype(); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, static_cast<unsigned>(PropertyAttribute::DontEnum), 0); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, static_cast<unsigned>(PropertyAttribute::DontEnum), 1); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapHasIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, static_cast<unsigned>(PropertyAttribute::DontEnum), 1, JSMapGetIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().setPrivateName(), mapProtoFuncSet, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, JSMapSetIntrinsic); JSFunction* entries = JSFunction::create(vm, mapPrototypeEntriesCodeGenerator(vm), globalObject); putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPublicName(), entries, static_cast<unsigned>(PropertyAttribute::DontEnum)); putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, static_cast<unsigned>(PropertyAttribute::DontEnum)); putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map"), PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly); JSC_NATIVE_GETTER_WITHOUT_TRANSITION(vm.propertyNames->size, mapProtoFuncSize, PropertyAttribute::DontEnum | PropertyAttribute::Accessor); }
JSValue Compilation::toJS(ExecState* exec) const { JSObject* result = constructEmptyObject(exec); result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); result->putDirect(exec->globalData(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); JSArray* profiledBytecodes = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().profiledBytecodes, profiledBytecodes); JSArray* descriptions = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_descriptions.size(); ++i) descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end(); for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) { JSObject* counterEntry = constructEmptyObject(exec); counterEntry->putDirect(exec->globalData(), exec->propertyNames().origin, iter->key.toJS(exec)); counterEntry->putDirect(exec->globalData(), exec->propertyNames().executionCount, jsNumber(iter->value->count())); counters->push(exec, counterEntry); } result->putDirect(exec->globalData(), exec->propertyNames().counters, counters); JSArray* exitSites = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExitSites.size(); ++i) exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().osrExitSites, exitSites); JSArray* exits = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExits.size(); ++i) exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().osrExits, exits); return result; }
static void addUsagesToJSON(ExecState* exec, JSObject* json, CryptoKeyUsage usages) { JSArray* keyOps = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), 0); unsigned index = 0; if (usages & CryptoKeyUsageSign) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("sign"))); if (usages & CryptoKeyUsageVerify) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("verify"))); if (usages & CryptoKeyUsageEncrypt) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("encrypt"))); if (usages & CryptoKeyUsageDecrypt) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("decrypt"))); if (usages & CryptoKeyUsageWrapKey) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("wrapKey"))); if (usages & CryptoKeyUsageUnwrapKey) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("unwrapKey"))); if (usages & CryptoKeyUsageDeriveKey) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveKey"))); if (usages & CryptoKeyUsageDeriveBits) keyOps->putDirectIndex(exec, index++, jsString(exec, ASCIILiteral("deriveBits"))); json->putDirect(exec->vm(), Identifier(exec, "key_ops"), keyOps); }
JSValue JSCSSStyleDeclaration::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) { JSCSSStyleDeclaration* thisObj = static_cast<JSCSSStyleDeclaration*>(asObject(slotBase)); // Set up pixelOrPos boolean to handle the fact that // pixelTop returns "CSS Top" as number value in unit pixels // posTop returns "CSS top" as number value in unit pixels _if_ its a // positioned element. if it is not a positioned element, return 0 // from MSIE documentation FIXME: IMPLEMENT THAT (Dirk) bool pixelOrPos; String prop = cssPropertyName(propertyName, &pixelOrPos); RefPtr<CSSValue> v = thisObj->impl()->getPropertyCSSValue(prop); if (v) { if (pixelOrPos && v->isPrimitiveValue()) return jsNumber(static_pointer_cast<CSSPrimitiveValue>(v)->getFloatValue(CSSPrimitiveValue::CSS_PX)); return jsStringOrNull(exec, v->cssText()); } // If the property is a shorthand property (such as "padding"), // it can only be accessed using getPropertyValue. return jsString(exec, thisObj->impl()->getPropertyValue(prop)); }
JSValue* stringProtoFuncToLocaleLowerCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&) { // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented. JSString* sVal = thisValue->toThisJSString(exec); const UString& s = sVal->value(); int ssize = s.size(); if (!ssize) return sVal; Vector<UChar> buffer(ssize); bool error; int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error); if (error) { buffer.resize(length); length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const UChar*>(s.data()), ssize, &error); if (error) return sVal; } if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0) return sVal; return jsString(exec, UString(buffer.releaseBuffer(), length, false)); }
JSValue *convertNPVariantToValue(ExecState*, const NPVariant* variant, RootObject* rootObject) { JSLock lock; NPVariantType type = variant->type; if (type == NPVariantType_Bool) return jsBoolean(NPVARIANT_TO_BOOLEAN(*variant)); if (type == NPVariantType_Null) return jsNull(); if (type == NPVariantType_Void) return jsUndefined(); if (type == NPVariantType_Int32) return jsNumber(NPVARIANT_TO_INT32(*variant)); if (type == NPVariantType_Double) return jsNumber(NPVARIANT_TO_DOUBLE(*variant)); if (type == NPVariantType_String) { NPUTF16 *stringValue; unsigned int UTF16Length; convertNPStringToUTF16(&variant->value.stringValue, &stringValue, &UTF16Length); // requires free() of returned memory UString resultString((const UChar *)stringValue,UTF16Length); free(stringValue); return jsString(resultString); } if (type == NPVariantType_Object) { NPObject *obj = variant->value.objectValue; if (obj->_class == NPScriptObjectClass) // Get JSObject from NP_JavaScriptObject. return ((JavaScriptObject *)obj)->imp; // Wrap NPObject in a CInstance. return Instance::createRuntimeObject(Instance::CLanguage, obj, rootObject); } return jsUndefined(); }
JSValue* convertQVariantToValue(ExecState*, const QVariant& variant) { if (variant.isNull()) return jsNull(); QVariant::Type type = variant.type(); if (type == QVariant::Bool) return jsBoolean(variant.toBool()); if (type == QVariant::Invalid) return jsUndefined(); if (type == QVariant::Int || type == QVariant::UInt || type == QVariant::LongLong || type == QVariant::ULongLong || type == QVariant::Double) return jsNumber(variant.toDouble()); QString string = variant.toString(); if (string.isNull()) return jsUndefined(); UString ustring((KJS::UChar*)string.utf16(), string.length()); return jsString(ustring); }
JSValue* JSKeyboardEvent::getValueProperty(ExecState* exec, int token) const { switch (token) { case KeyIdentifierAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsString(exec, imp->keyIdentifier()); } case KeyLocationAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsNumber(exec, imp->keyLocation()); } case CtrlKeyAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsBoolean(imp->ctrlKey()); } case ShiftKeyAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsBoolean(imp->shiftKey()); } case AltKeyAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsBoolean(imp->altKey()); } case MetaKeyAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsBoolean(imp->metaKey()); } case AltGraphKeyAttrNum: { KeyboardEvent* imp = static_cast<KeyboardEvent*>(impl()); return jsBoolean(imp->altGraphKey()); } case ConstructorAttrNum: return getConstructor(exec); } return 0; }
void MapPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(info())); vm.prototypeMap.addPrototype(this); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->clear, mapProtoFuncClear, DontEnum, 0); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->deleteKeyword, mapProtoFuncDelete, DontEnum, 1); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->get, mapProtoFuncGet, DontEnum, 1, JSMapGetIntrinsic); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->has, mapProtoFuncHas, DontEnum, 1, JSMapHasIntrinsic); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->set, mapProtoFuncSet, DontEnum, 2); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().keysPublicName(), mapProtoFuncKeys, DontEnum, 0); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().valuesPublicName(), mapProtoFuncValues, DontEnum, 0); JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().getPrivateName(), mapProtoFuncGet, DontEnum, 1, JSMapGetIntrinsic); JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().setPrivateName(), mapProtoFuncSet, DontEnum, 2); JSFunction* entries = JSFunction::create(vm, globalObject, 0, vm.propertyNames->builtinNames().entriesPublicName().string(), mapProtoFuncEntries); putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().entriesPublicName(), entries, DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->iteratorSymbol, entries, DontEnum); putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "Map"), DontEnum | ReadOnly); JSC_NATIVE_GETTER(vm.propertyNames->size, mapProtoFuncSize, DontEnum | Accessor); }
JSValue jsHTMLElementOuterText(ExecState* exec, JSValue slotBase, const Identifier&) { JSHTMLElement* castedThis = static_cast<JSHTMLElement*>(asObject(slotBase)); UNUSED_PARAM(exec); HTMLElement* imp = static_cast<HTMLElement*>(castedThis->impl()); JSValue result = jsString(exec, imp->outerText()); #if defined(JSC_TAINTED) if (imp->tainted()) { unsigned int tainted = imp->tainted(); result.setTainted(imp->tainted()); TaintedStructure trace_struct; trace_struct.taintedno = tainted; trace_struct.internalfunc = "jsHTMLElementOuterText"; trace_struct.jsfunc = "htmlelement.outerText"; trace_struct.action = "propagate"; trace_struct.value = TaintedUtils::UString2string(result.toString(exec)); TaintedTrace* trace = TaintedTrace::getInstance(); trace->addTaintedTrace(trace_struct); } #endif return result; }
JSValue LiteralParser::parseExpression() { StackGuard guard(this); if (!guard.isSafe()) return abortParse(); switch (m_lexer.currentToken().type) { case TokLBracket: return parseArray(); case TokLBrace: return parseObject(); case TokString: { Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); m_lexer.next(); return jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2)); } case TokNumber: { Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); m_lexer.next(); return jsNumber(m_exec, UString(numberToken.start, numberToken.end - numberToken.start).toDouble()); } default: return JSValue(); } }
JSValue JSDOMWindow::btoa(ExecState* exec, const ArgList& args) { if (args.size() < 1) return throwError(exec, SyntaxError, "Not enough arguments"); JSValue v = args.at(0); if (v.isNull()) return jsEmptyString(exec); UString s = v.toString(exec); if (!s.is8Bit()) { setDOMException(exec, INVALID_CHARACTER_ERR); return jsUndefined(); } Vector<char> in(s.size()); for (int i = 0; i < s.size(); ++i) in[i] = static_cast<char>(s.data()[i]); Vector<char> out; base64Encode(in, out); return jsString(exec, String(out.data(), out.size())); }
JSValue* JSHTMLScriptElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case TextAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->text()); } case HtmlForAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->htmlFor()); } case EventAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->event()); } case CharsetAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->charset()); } case DeferAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsBoolean(imp->defer()); } case SrcAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->src()); } case TypeAttrNum: { HTMLScriptElement* imp = static_cast<HTMLScriptElement*>(impl()); return jsString(imp->type()); } case ConstructorAttrNum: return getConstructor(exec); } return 0; }
JSValuePtr regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot) { return jsString(exec, asRegExpConstructor(slot.slotBase())->input()); }
AJValue LiteralParser::parse(ParserState initialState) { ParserState state = initialState; MarkedArgumentBuffer objectStack; AJValue lastValue; Vector<ParserState, 16> stateStack; Vector<Identifier, 16> identifierStack; while (1) { switch(state) { startParseArray: case StartParseArray: { AJArray* array = constructEmptyArray(m_exec); objectStack.append(array); // fallthrough } doParseArrayStartExpression: case DoParseArrayStartExpression: { TokenType lastToken = m_lexer.currentToken().type; if (m_lexer.next() == TokRBracket) { if (lastToken == TokComma) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } stateStack.append(DoParseArrayEndExpression); goto startParseExpression; } case DoParseArrayEndExpression: { asArray(objectStack.last())->push(m_exec, lastValue); if (m_lexer.currentToken().type == TokComma) goto doParseArrayStartExpression; if (m_lexer.currentToken().type != TokRBracket) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } startParseObject: case StartParseObject: { AJObject* object = constructEmptyObject(m_exec); objectStack.append(object); TokenType type = m_lexer.next(); if (type == TokString) { Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon if (m_lexer.next() != TokColon) return AJValue(); m_lexer.next(); identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); stateStack.append(DoParseObjectEndExpression); goto startParseExpression; } else if (type != TokRBrace) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } doParseObjectStartExpression: case DoParseObjectStartExpression: { TokenType type = m_lexer.next(); if (type != TokString) return AJValue(); Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon if (m_lexer.next() != TokColon) return AJValue(); m_lexer.next(); identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); stateStack.append(DoParseObjectEndExpression); goto startParseExpression; } case DoParseObjectEndExpression: { asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue); identifierStack.removeLast(); if (m_lexer.currentToken().type == TokComma) goto doParseObjectStartExpression; if (m_lexer.currentToken().type != TokRBrace) return AJValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); break; } startParseExpression: case StartParseExpression: { switch (m_lexer.currentToken().type) { case TokLBracket: goto startParseArray; case TokLBrace: goto startParseObject; case TokString: { Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); m_lexer.next(); lastValue = jsString(m_exec, stringToken.stringToken); break; } case TokNumber: { Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); m_lexer.next(); lastValue = jsNumber(m_exec, numberToken.numberToken); break; } case TokNull: m_lexer.next(); lastValue = jsNull(); break; case TokTrue: m_lexer.next(); lastValue = jsBoolean(true); break; case TokFalse: m_lexer.next(); lastValue = jsBoolean(false); break; default: // Error return AJValue(); } break; } case StartParseStatement: { switch (m_lexer.currentToken().type) { case TokLBracket: case TokNumber: case TokString: goto startParseExpression; case TokLParen: { m_lexer.next(); stateStack.append(StartParseStatementEndStatement); goto startParseExpression; } default: return AJValue(); } } case StartParseStatementEndStatement: { ASSERT(stateStack.isEmpty()); if (m_lexer.currentToken().type != TokRParen) return AJValue(); if (m_lexer.next() == TokEnd) return lastValue; return AJValue(); } default: ASSERT_NOT_REACHED(); } if (stateStack.isEmpty()) return lastValue; state = stateStack.last(); stateStack.removeLast(); continue; } }
JSValue* JSSVGMarkerElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case RefXAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedLength> obj = imp->refXAnimated(); return toJS(exec, obj.get(), imp); } case RefYAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedLength> obj = imp->refYAnimated(); return toJS(exec, obj.get(), imp); } case MarkerUnitsAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedEnumeration> obj = imp->markerUnitsAnimated(); return toJS(exec, obj.get(), imp); } case MarkerWidthAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedLength> obj = imp->markerWidthAnimated(); return toJS(exec, obj.get(), imp); } case MarkerHeightAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedLength> obj = imp->markerHeightAnimated(); return toJS(exec, obj.get(), imp); } case OrientTypeAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedEnumeration> obj = imp->orientTypeAnimated(); return toJS(exec, obj.get(), imp); } case OrientAngleAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedAngle> obj = imp->orientAngleAnimated(); return toJS(exec, obj.get(), imp); } case XmllangAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); return jsString(imp->xmllang()); } case XmlspaceAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); return jsString(imp->xmlspace()); } case ExternalResourcesRequiredAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); return toJS(exec, obj.get(), imp); } case ClassNameAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedString> obj = imp->classNameAnimated(); return toJS(exec, obj.get(), imp); } case StyleAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); return toJS(exec, WTF::getPtr(imp->style())); } case ViewBoxAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedRect> obj = imp->viewBoxAnimated(); return toJS(exec, obj.get(), imp); } case PreserveAspectRatioAttrNum: { SVGMarkerElement* imp = static_cast<SVGMarkerElement*>(impl()); RefPtr<SVGAnimatedPreserveAspectRatio> obj = imp->preserveAspectRatioAnimated(); return toJS(exec, obj.get(), imp); } case ConstructorAttrNum: return getConstructor(exec); } return 0; }
// ECMA 15.5.1 static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec) { if (!exec->argumentCount()) return JSValue::encode(jsEmptyString(exec)); return JSValue::encode(jsString(exec, exec->argument(0).toString(exec))); }
JSValue IntlNumberFormat::formatToParts(ExecState& exec, double value) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // FormatNumberToParts (ECMA-402) // https://tc39.github.io/ecma402/#sec-formatnumbertoparts // https://tc39.github.io/ecma402/#sec-partitionnumberpattern if (!m_initializedNumberFormat) return throwTypeError(&exec, scope, "Intl.NumberFormat.prototype.formatToParts called on value that's not an object initialized as a NumberFormat"_s); UErrorCode status = U_ZERO_ERROR; auto fieldItr = std::unique_ptr<UFieldPositionIterator, UFieldPositionIteratorDeleter>(ufieldpositer_open(&status)); if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to open field position iterator"_s); status = U_ZERO_ERROR; Vector<UChar, 32> result(32); auto resultLength = unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), result.size(), fieldItr.get(), &status); if (status == U_BUFFER_OVERFLOW_ERROR) { status = U_ZERO_ERROR; result.grow(resultLength); unum_formatDoubleForFields(m_numberFormat.get(), value, result.data(), resultLength, fieldItr.get(), &status); } if (U_FAILURE(status)) return throwTypeError(&exec, scope, "failed to format a number."_s); int32_t literalFieldType = -1; auto literalField = IntlNumberFormatField(literalFieldType, resultLength); Vector<IntlNumberFormatField> fields(resultLength, literalField); int32_t beginIndex = 0; int32_t endIndex = 0; auto fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex); while (fieldType >= 0) { auto size = endIndex - beginIndex; for (auto i = beginIndex; i < endIndex; ++i) { // Only override previous value if new value is more specific. if (fields[i].size >= size) fields[i] = IntlNumberFormatField(fieldType, size); } fieldType = ufieldpositer_next(fieldItr.get(), &beginIndex, &endIndex); } JSGlobalObject* globalObject = exec.jsCallee()->globalObject(vm); JSArray* parts = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); if (!parts) return throwOutOfMemoryError(&exec, scope); unsigned index = 0; auto resultString = String(result.data(), resultLength); auto typePropertyName = Identifier::fromString(&vm, "type"); auto literalString = jsString(&exec, "literal"_s); int32_t currentIndex = 0; while (currentIndex < resultLength) { auto startIndex = currentIndex; auto fieldType = fields[currentIndex].type; while (currentIndex < resultLength && fields[currentIndex].type == fieldType) ++currentIndex; auto partType = fieldType == literalFieldType ? literalString : jsString(&exec, partTypeString(UNumberFormatFields(fieldType), value)); auto partValue = jsSubstring(&vm, resultString, startIndex, currentIndex - startIndex); JSObject* part = constructEmptyObject(&exec); part->putDirect(vm, typePropertyName, partType); part->putDirect(vm, vm.propertyNames->value, partValue); parts->putDirectIndex(&exec, index++, part); RETURN_IF_EXCEPTION(scope, { }); } return parts; }
JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&) { return jsString(exec, asRegExpConstructor(slotBase)->input()); }
JSValue* JSHTMLTableElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case CaptionAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return toJS(exec, WTF::getPtr(imp->caption())); } case THeadAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return toJS(exec, WTF::getPtr(imp->tHead())); } case TFootAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return toJS(exec, WTF::getPtr(imp->tFoot())); } case RowsAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return toJS(exec, WTF::getPtr(imp->rows())); } case TBodiesAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return toJS(exec, WTF::getPtr(imp->tBodies())); } case AlignAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->align()); } case BgColorAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->bgColor()); } case BorderAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->border()); } case CellPaddingAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->cellPadding()); } case CellSpacingAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->cellSpacing()); } case FrameAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->frame()); } case RulesAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->rules()); } case SummaryAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->summary()); } case WidthAttrNum: { HTMLTableElement* imp = static_cast<HTMLTableElement*>(impl()); return jsString(exec, imp->width()); } case ConstructorAttrNum: return getConstructor(exec); } return 0; }
JSValue QtPixmapInstance::valueOf(ExecState* exec) const { const QString stringValue = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height()); UString ustring((UChar*)stringValue.utf16(), stringValue.length()); return jsString(exec, ustring); }
JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); return jsString(exec, "<tt>" + s + "</tt>"); }
JSValue* JSSVGPolygonElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case RequiredFeaturesAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->requiredFeatures()), imp); } case RequiredExtensionsAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->requiredExtensions()), imp); } case SystemLanguageAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->systemLanguage()), imp); } case XmllangAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return jsString(imp->xmllang()); } case XmlspaceAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return jsString(imp->xmlspace()); } case ExternalResourcesRequiredAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); RefPtr<SVGAnimatedBoolean> obj = imp->externalResourcesRequiredAnimated(); return toJS(exec, obj.get(), imp); } case ClassNameAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); RefPtr<SVGAnimatedString> obj = imp->classNameAnimated(); return toJS(exec, obj.get(), imp); } case StyleAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->style())); } case TransformAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); RefPtr<SVGAnimatedTransformList> obj = imp->transformAnimated(); return toJS(exec, obj.get(), imp); } case NearestViewportElementAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->nearestViewportElement())); } case FarthestViewportElementAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->farthestViewportElement())); } case PointsAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->points()), imp); } case AnimatedPointsAttrNum: { SVGPolygonElement* imp = static_cast<SVGPolygonElement*>(impl()); return toJS(exec, WTF::getPtr(imp->animatedPoints()), imp); } } return 0; }
//-------------------------------------------------------------------------- // JSObjectKJSValue //-------------------------------------------------------------------------- JSValue JSObjectKJSValue(JSUserObject* ptr) { JSGlueAPIEntry entry; JSValue result = jsUndefined(); if (ptr) { bool handled = false; switch (ptr->DataType()) { case kJSUserObjectDataTypeJSValueWrapper: { JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData(); if (wrapper) { result = wrapper->GetValue(); handled = true; } break; } case kJSUserObjectDataTypeCFType: { CFTypeRef cfType = (CFTypeRef*)ptr->GetData(); if (cfType) { CFTypeID typeID = CFGetTypeID(cfType); if (typeID == CFStringGetTypeID()) { result = jsString(getThreadGlobalExecState(), CFStringToUString((CFStringRef)cfType)); handled = true; } else if (typeID == CFNumberGetTypeID()) { double num; CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num); result = jsNumber(num); handled = true; } else if (typeID == CFBooleanGetTypeID()) { result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType)); handled = true; } else if (typeID == CFNullGetTypeID()) { result = jsNull(); handled = true; } } break; } } if (!handled) { ExecState* exec = getThreadGlobalExecState(); result = new (exec) UserObjectImp(getThreadGlobalObject()->userObjectStructure(), ptr); } } return result; }
JSValue* JSHTMLImageElement::getValueProperty(ExecState* exec, int token) const { switch (token) { case NameAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->name()); } case AlignAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->align()); } case AltAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->alt()); } case BorderAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->border()); } case HeightAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->height()); } case HspaceAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->hspace()); } case IsMapAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsBoolean(imp->isMap()); } case LongDescAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->longDesc()); } case SrcAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->src()); } case UseMapAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->useMap()); } case VspaceAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->vspace()); } case WidthAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->width()); } case CompleteAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsBoolean(imp->complete()); } case LowsrcAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsString(exec, imp->lowsrc()); } case NaturalHeightAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->naturalHeight()); } case NaturalWidthAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->naturalWidth()); } case XAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->x()); } case YAttrNum: { HTMLImageElement* imp = static_cast<HTMLImageElement*>(impl()); return jsNumber(exec, imp->y()); } case ConstructorAttrNum: return getConstructor(exec); } return 0; }
JSValue* JSRangePrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) { if (!thisObj->inherits(&JSRange::info)) return throwError(exec, TypeError); Range* imp = static_cast<Range*>(static_cast<JSRange*>(thisObj)->impl()); switch (id) { case JSRange::SetStartFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } imp->setStart(refNode, offset, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } imp->setEnd(refNode, offset, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetStartBeforeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setStartBefore(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetStartAfterFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setStartAfter(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndBeforeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setEndBefore(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndAfterFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setEndAfter(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CollapseFuncNum: { ExceptionCode ec = 0; bool toStart = args[0]->toBoolean(exec); imp->collapse(toStart, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SelectNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->selectNode(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SelectNodeContentsFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->selectNodeContents(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CompareBoundaryPointsFuncNum: { ExceptionCode ec = 0; Range::CompareHow how = static_cast<Range::CompareHow>(args[0]->toInt32(exec)); Range* sourceRange = toRange(args[1]); KJS::JSValue* result = jsNumber(imp->compareBoundaryPoints(how, sourceRange, ec)); setDOMException(exec, ec); return result; } case JSRange::DeleteContentsFuncNum: { ExceptionCode ec = 0; imp->deleteContents(ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::ExtractContentsFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->extractContents(ec))); setDOMException(exec, ec); return result; } case JSRange::CloneContentsFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->cloneContents(ec))); setDOMException(exec, ec); return result; } case JSRange::InsertNodeFuncNum: { ExceptionCode ec = 0; Node* newNode = toNode(args[0]); imp->insertNode(newNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SurroundContentsFuncNum: { ExceptionCode ec = 0; Node* newParent = toNode(args[0]); imp->surroundContents(newParent, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CloneRangeFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->cloneRange(ec))); setDOMException(exec, ec); return result; } case JSRange::ToStringFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = jsString(imp->toString(ec)); setDOMException(exec, ec); return result; } case JSRange::DetachFuncNum: { ExceptionCode ec = 0; imp->detach(ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CreateContextualFragmentFuncNum: { ExceptionCode ec = 0; String html = args[0]->toString(exec); KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->createContextualFragment(html, ec))); setDOMException(exec, ec); return result; } case JSRange::IntersectsNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); KJS::JSValue* result = jsBoolean(imp->intersectsNode(refNode, ec)); setDOMException(exec, ec); return result; } case JSRange::CompareNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); KJS::JSValue* result = jsNumber(imp->compareNode(refNode, ec)); setDOMException(exec, ec); return result; } case JSRange::ComparePointFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } KJS::JSValue* result = jsNumber(imp->comparePoint(refNode, offset, ec)); setDOMException(exec, ec); return result; } case JSRange::IsPointInRangeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } KJS::JSValue* result = jsBoolean(imp->isPointInRange(refNode, offset, ec)); setDOMException(exec, ec); return result; } } return 0; }
static inline JSValue regExpObjectSourceInternal(ExecState* exec, String pattern, const CharacterType* characters, unsigned 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 jsNontrivialString(exec, ASCIILiteral("(?:)")); // early return for strings that don't contain a forwards slash and LineTerminator for (unsigned i = 0; i < length; ++i) { CharacterType ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') inBrackets = false; } else { if (ch == '/') { shouldEscape = true; break; } if (ch == '[') inBrackets = true; } } if (Lexer<CharacterType>::isLineTerminator(ch)) { shouldEscape = true; break; } if (previousCharacterWasBackslash) previousCharacterWasBackslash = false; else previousCharacterWasBackslash = ch == '\\'; } if (!shouldEscape) return jsString(exec, pattern); previousCharacterWasBackslash = false; inBrackets = false; StringBuilder result; for (unsigned i = 0; i < length; ++i) { CharacterType ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') inBrackets = false; } else { if (ch == '/') result.append('\\'); else if (ch == '[') inBrackets = true; } } // escape LineTerminator if (Lexer<CharacterType>::isLineTerminator(ch)) { if (!previousCharacterWasBackslash) result.append('\\'); appendLineTerminatorEscape<CharacterType>(result, ch); } else result.append(ch); if (previousCharacterWasBackslash) previousCharacterWasBackslash = false; else previousCharacterWasBackslash = ch == '\\'; } return jsString(exec, result.toString()); }
JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); const UString& source = sourceVal->value(); JSValue pattern = args.at(0); JSValue replacement = args.at(1); UString replacementString; CallData callData; CallType callType = replacement.getCallData(callData); if (callType == CallTypeNone) replacementString = replacement.toString(exec); if (pattern.isObject(&RegExpObject::info)) { RegExp* reg = asRegExpObject(pattern)->regExp(); bool global = reg->global(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int lastIndex = 0; int startPosition = 0; Vector<UString::Range, 16> sourceRanges; Vector<UString, 16> replacements; // This is either a loop (if global is set) or a one-way (if not). if (global && callType == CallTypeJS) { // reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue int argCount = reg->numSubpatterns() + 1 + 2; JSFunction* func = asFunction(replacement); CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot()); if (exec->hadException()) return jsNull(); while (true) { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); int completeMatchStart = ovector[0]; unsigned i = 0; for (; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) cachedCall.setArgument(i, jsUndefined()); else cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen)); } cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart)); cachedCall.setArgument(i++, sourceVal); cachedCall.setThis(exec->globalThisValue()); replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); if (exec->hadException()) break; lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } } else { do { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); if (callType != CallTypeNone) { int completeMatchStart = ovector[0]; MarkedArgumentBuffer args; for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) args.append(jsUndefined()); else args.append(jsSubstring(exec, source, matchStart, matchLen)); } args.append(jsNumber(exec, completeMatchStart)); args.append(sourceVal); replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec)); if (exec->hadException()) break; } else replacements.append(substituteBackreferences(replacementString, source, ovector, reg)); lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } while (global); } if (!lastIndex && replacements.isEmpty()) return sourceVal; if (lastIndex < source.size()) sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size())); } // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); int matchPos = source.find(patternString); if (matchPos == -1) return sourceVal; int matchLen = patternString.size(); if (callType != CallTypeNone) { MarkedArgumentBuffer args; args.append(jsSubstring(exec, source, matchPos, matchLen)); args.append(jsNumber(exec, matchPos)); args.append(sourceVal); replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec); } int ovector[2] = { matchPos, matchPos + matchLen }; return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0))); }