blob: 2f2e270b2107c0e8272acf9acae0292ac1769061 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#include "FunctionObject.h"
#include <kjs/array_object.h>
using namespace KJS;
const ClassInfo FunctionObject::info = {"Function", 0, 0, 0};
class CallFunction : public FunctionObject {
public:
CallFunction(): FunctionObject("call") {
}
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj,
const List &args)
{
// Copied from FunctionProtoFunc::callAsFunction()
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);
}
return func->call(exec, callThis, args.copyTail());
}
};
class ApplyFunction : public FunctionObject {
public:
ApplyFunction(): FunctionObject("apply") {
}
virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj,
const List &args)
{
// Copied from FunctionProtoFunc::callAsFunction()
JSObject *func = thisObj;
if (!func->implementsCall()) {
return throwError(exec, TypeError);
}
JSValue *thisArg = args[0];
JSObject *applyThis;
if (thisArg->isUndefinedOrNull()) {
applyThis = exec->dynamicInterpreter()->globalObject();
} else {
applyThis = thisArg->toObject(exec);
}
JSValue *argArray = args[1];
List applyArgs;
if (!argArray->isUndefinedOrNull()) {
if (!argArray->isObject(&ArrayInstance::info)) {
return throwError(exec, TypeError);
}
JSObject *argArrayObj = static_cast<JSObject *>(argArray);
unsigned int length = argArrayObj->get(exec, lengthPropertyName)
->toUInt32(exec);
for (unsigned int i = 0; i < length; ++i) {
applyArgs.append(argArrayObj->get(exec,i));
}
}
return func->call(exec, applyThis, applyArgs);
}
};
static UString makeFunctionString(const UString& name) {
return "\nfunction " + name + "() {\n [native code]\n}\n";
}
JSValue *FunctionObject::getter(ExecState* exec, JSObject* obj,
const Identifier& propertyName, const PropertySlot& slot)
{
if (propertyName.ustring() == "toString") {
return new ToStringFunction();
} else if (propertyName.ustring() == "call") {
return new CallFunction();
} else if (propertyName.ustring() == "apply") {
return new ApplyFunction();
}
return jsUndefined();
}
FunctionObject::FunctionObject(const UString& name): name(name) {
}
bool FunctionObject::getOwnPropertySlot(ExecState *exec,
const Identifier& propertyName, PropertySlot& slot)
{
if (propertyName.ustring() == "toString") {
slot.setCustom(this, getter);
return true;
}
if (propertyName.ustring() == "call") {
slot.setCustom(this, getter);
return true;
}
if (propertyName.ustring() == "apply") {
slot.setCustom(this, getter);
return true;
}
return false;
}
bool FunctionObject::canPut(ExecState *exec, const Identifier &propertyName)
const
{
return false;
}
void FunctionObject::put(ExecState *exec, const Identifier &propertyName,
JSValue *value, int attr)
{
}
bool FunctionObject::deleteProperty(ExecState *exec,
const Identifier &propertyName)
{
return false;
}
JSValue *FunctionObject::defaultValue(ExecState *exec, JSType hint) const {
return jsString(makeFunctionString(name));
}
bool FunctionObject::implementsCall() const {
return true;
}
// ToStringFunction
ToStringFunction::ToStringFunction(): FunctionObject("toString") {
}
JSValue *ToStringFunction::callAsFunction(ExecState *exec, JSObject *thisObj,
const List &args)
{
if (!thisObj) {
return throwError(exec, TypeError);
}
return jsString(thisObj->toString(exec));
}