Esempio n. 1
0
JSValue *FunctionProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
{
    JSValue *result = NULL;

    switch (id) {
    case ToString:
        if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) {
#ifndef NDEBUG
            fprintf(stderr, "attempted toString() call on null or non-function object\n");
#endif
            return throwError(exec, TypeError);
        }
        if (thisObj->inherits(&FunctionImp::info)) {
            return jsString(static_cast<FunctionImp *>(thisObj)->toSource());
        } else if (thisObj->inherits(&InternalFunctionImp::info) &&
                   !static_cast<InternalFunctionImp *>(thisObj)->functionName().isNull()) {
            result = jsString("\nfunction " + static_cast<InternalFunctionImp *>(thisObj)->functionName().ustring() + "() {\n"
                              "    [native code]\n}\n");
        } else {
            result = jsString("[function]");
        }
        break;
    case Apply: {
        JSValue *thisArg = args[0];
        JSValue *argArray = args[1];
        JSObject *func = thisObj;

        if (!func->implementsCall()) {
            return throwError(exec, TypeError);
        }

        JSObject *applyThis;
        if (thisArg->isUndefinedOrNull()) {
            applyThis = exec->dynamicInterpreter()->globalObject();
        } else {
            applyThis = thisArg->toObject(exec);
        }

        List applyArgs;
        if (!argArray->isUndefinedOrNull()) {
            if (argArray->isObject() &&
                    (static_cast<JSObject *>(argArray)->inherits(&ArrayInstance::info) ||
                     static_cast<JSObject *>(argArray)->inherits(&Arguments::info))) {

                JSObject *argArrayObj = static_cast<JSObject *>(argArray);
                unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
                for (unsigned int i = 0; i < length; i++) {
                    applyArgs.append(argArrayObj->get(exec, i));
                }
            } else {
                return throwError(exec, TypeError);
            }
        }
        result = func->call(exec, applyThis, applyArgs);
    }
    break;
    case Call: {
        JSValue *thisArg = args[0];
        JSObject *func = thisObj;

        if (!func->implementsCall()) {
            return throwError(exec, TypeError);
        }

        JSObject *callThis;
        if (thisArg->isUndefinedOrNull()) {
            callThis = exec->dynamicInterpreter()->globalObject();
        } else {
            callThis = thisArg->toObject(exec);
        }

        result = func->call(exec, callThis, args.copyTail());
    }
    break;
    case Bind: { //ECMA Edition 5.1r6 - 15.3.4.5
        JSObject *target(thisObj);
        if (!target->implementsCall()) {
            return throwError(exec, TypeError, "object is not callable");
        }

        List newArgs;
        for (int i = 1; i < args.size(); ++i) {
            newArgs.append(args[i]);
        }

        JSObject *boundThis = 0;

        // As call does not accept JSValue(undefined/null),
        // do it like in call and use the global object
        if (args[0]->isUndefinedOrNull()) {
            boundThis = exec->dynamicInterpreter()->globalObject();
        } else {
            boundThis = args[0]->toObject(exec);
        }

        BoundFunction *bfunc = new BoundFunction(exec, target, boundThis, newArgs);

        unsigned length;
        if (target->inherits(&FunctionImp::info)) {
            double L = target->get(exec, exec->propertyNames().length)->getNumber() - newArgs.size();
            length = (unsigned)std::max<int>((int)L, 0);
        } else {
            length = 0;
        }
        bfunc->put(exec, exec->propertyNames().length, jsNumber(length), ReadOnly | DontEnum | DontDelete);

        JSObject *thrower = new Thrower(TypeError);
        PropertyDescriptor callerDesc;

        GetterSetterImp *gs = new GetterSetterImp();
        gs->setGetter(thrower);
        gs->setSetter(thrower);

        callerDesc.setPropertyDescriptorValues(exec, gs, DontEnum | DontDelete);
        bfunc->defineOwnProperty(exec, exec->propertyNames().caller, callerDesc, false);

        PropertyDescriptor argumentsDesc;
        argumentsDesc.setPropertyDescriptorValues(exec, gs, DontEnum | DontDelete);
        bfunc->defineOwnProperty(exec, exec->propertyNames().arguments, argumentsDesc, false);

        return bfunc;
    }
    break;
    }

    return result;
}