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