blob: eac04039d432394ef8e115255baa5297d65e1637 [file] [log] [blame]
/*
* Copyright 2006 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));
}