예제 #1
0
JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&)
{
    JSString* sVal = thisValue.toThisJSString(exec);
    const UString& s = sVal->value();

    int sSize = s.size();
    if (!sSize)
        return sVal;

    const UChar* sData = s.data();
    Vector<UChar> buffer(sSize);

    UChar ored = 0;
    for (int i = 0; i < sSize; i++) {
        UChar c = sData[i];
        ored |= c;
        buffer[i] = toASCIIUpper(c);
    }
    if (!(ored & ~0x7f))
        return jsString(exec, UString(buffer.releaseBuffer(), sSize, false));

    bool error;
    int length = Unicode::toUpper(buffer.data(), sSize, sData, sSize, &error);
    if (error) {
        buffer.resize(length);
        length = Unicode::toUpper(buffer.data(), length, sData, sSize, &error);
        if (error)
            return sVal;
    }
    if (length == sSize && memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
        return sVal;
    return jsString(exec, UString(buffer.releaseBuffer(), length, false));
}
예제 #2
0
EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState* exec)
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    JSString* stringKey = exec->argument(0).toString(exec);
    RETURN_IF_EXCEPTION(scope, encodedJSValue());
    String string = stringKey->value(exec);
    RETURN_IF_EXCEPTION(scope, encodedJSValue());

    return JSValue::encode(Symbol::create(exec->vm(), exec->vm().symbolRegistry().symbolForKey(string)));
}
예제 #3
0
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));
}
예제 #4
0
inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
{
    if (flags.isUndefined())
        return NoFlags;
    JSString* flagsString = flags.toString(exec);
    if (!flagsString) {
        ASSERT(exec->hadException());
        return InvalidFlags;
    }

    RegExpFlags result = regExpFlags(flagsString->value(exec));
    if (exec->hadException())
        return InvalidFlags;
    if (result == InvalidFlags)
        throwSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor."));
    return result;
}
예제 #5
0
inline RegExpFlags toFlags(ExecState* exec, JSValue flags)
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    if (flags.isUndefined())
        return NoFlags;
    JSString* flagsString = flags.toStringOrNull(exec);
    ASSERT(!!scope.exception() == !flagsString);
    if (UNLIKELY(!flagsString))
        return InvalidFlags;

    RegExpFlags result = regExpFlags(flagsString->value(exec));
    RETURN_IF_EXCEPTION(scope, InvalidFlags);
    if (result == InvalidFlags)
        throwSyntaxError(exec, scope, ASCIILiteral("Invalid flags supplied to RegExp constructor."));
    return result;
}
예제 #6
0
JSValue* stringProtoFuncToLocaleUpperCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
{
    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::toUpper(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    if (error) {
        buffer.resize(length);
        length = Unicode::toUpper(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));
}
예제 #7
0
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));
}
예제 #8
0
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)));
}
// 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
{
    JSGlobalObject* globalObject = exec->callee()->globalObject();

    // Let Target be the this value.
    JSValue target = exec->thisValue();

    // If IsCallable(Target) is false, throw a TypeError exception.
    CallData callData;
    CallType callType = getCallData(target, callData);
    if (callType == CallTypeNone)
        return throwVMTypeError(exec);
    // Primitive values are not callable.
    ASSERT(target.isObject());
    JSObject* targetObject = asObject(target);
    VM& vm = exec->vm();

    // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
    size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
    JSArray* boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithUndecided), numBoundArgs);
    if (!boundArgs)
        return JSValue::encode(throwOutOfMemoryError(exec));

    for (size_t i = 0; i < numBoundArgs; ++i)
        boundArgs->initializeIndex(vm, i, exec->argument(i + 1));

    // If the [[Class]] internal property of Target is "Function", then ...
    // Else set the length own property of F to 0.
    unsigned length = 0;
    if (targetObject->inherits(JSFunction::info())) {
        ASSERT(target.get(exec, exec->propertyNames().length).isNumber());
        // a. Let L be the length property of Target minus the length of A.
        // b. Set the length own property of F to either 0 or L, whichever is larger.
        unsigned targetLength = (unsigned)target.get(exec, exec->propertyNames().length).asNumber();
        if (targetLength > numBoundArgs)
            length = targetLength - numBoundArgs;
    }

    JSString* name = target.get(exec, exec->propertyNames().name).toString(exec);
    return JSValue::encode(JSBoundFunction::create(vm, globalObject, targetObject, exec->argument(0), boundArgs, length, name->value(exec)));
}
예제 #10
0
JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    JSString* sourceVal = thisValue->toThisJSString(exec);
    const UString& source = sourceVal->value();

    JSValue* pattern = args.at(exec, 0);

    JSValue* replacement = args.at(exec, 1);
    UString replacementString;
    CallData callData;
    CallType callType = replacement->getCallData(callData);
    if (callType == CallTypeNone)
        replacementString = replacement->toString(exec);

    if (pattern->isObject(&RegExpObject::info)) {
        RegExp* reg = static_cast<RegExpObject*>(pattern)->regExp();
        bool global = reg->global();

        RegExpConstructor* regExpObj = 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).
        do {
            int matchIndex;
            int matchLen;
            int* ovector;
            regExpObj->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];
                ArgList 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));
            } 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 < source.size())
            sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex));

        UString result = source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size());

        if (result == source)
            return sourceVal;

        return jsString(exec, result);
    }

    // First arg is a string
    UString patternString = pattern->toString(exec);
    int matchPos = source.find(patternString);
    int matchLen = patternString.size();
    // Do the replacement
    if (matchPos == -1)
        return sourceVal;

    if (callType != CallTypeNone) {
        ArgList 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);
    }

    return jsString(exec, source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen));
}