File indexing completed on 2024-05-12 15:43:21
0001 // krazy:excludeall=doublequote_chars (UStrings aren't QStrings) 0002 /* 0003 * This file is part of the KDE libraries 0004 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 0005 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Lesser General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Lesser General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Lesser General Public 0018 * License along with this library; if not, write to the Free Software 0019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0020 * 0021 */ 0022 0023 #include "function_object.h" 0024 #include "internal.h" 0025 #include "scriptfunction.h" 0026 #include "array_object.h" 0027 #include "nodes.h" 0028 #include "lexer.h" 0029 #include "debugger.h" 0030 #include "object.h" 0031 0032 #include <assert.h> 0033 #include <stdio.h> 0034 #include <string.h> 0035 0036 using namespace KJS; 0037 0038 // ------------------------------ FunctionPrototype ------------------------- 0039 0040 FunctionPrototype::FunctionPrototype(ExecState *exec) 0041 { 0042 static const Identifier *applyPropertyName = new Identifier("apply"); 0043 static const Identifier *callPropertyName = new Identifier("call"); 0044 static const Identifier *bindPropertyName = new Identifier("bind"); 0045 0046 putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum); 0047 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::ToString, 0, exec->propertyNames().toString), DontEnum); 0048 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Apply, 2, *applyPropertyName), DontEnum); 0049 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Call, 1, *callPropertyName), DontEnum); 0050 putDirectFunction(new FunctionProtoFunc(exec, this, FunctionProtoFunc::Bind, 1, *bindPropertyName), DontEnum); 0051 } 0052 0053 FunctionPrototype::~FunctionPrototype() 0054 { 0055 } 0056 0057 // ECMA 15.3.4 0058 JSValue *FunctionPrototype::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/) 0059 { 0060 return jsUndefined(); 0061 } 0062 0063 // ------------------------------ FunctionProtoFunc ------------------------- 0064 0065 FunctionProtoFunc::FunctionProtoFunc(ExecState *exec, FunctionPrototype *funcProto, int i, int len, const Identifier &name) 0066 : InternalFunctionImp(funcProto, name) 0067 , id(i) 0068 { 0069 putDirect(exec->propertyNames().length, len, DontDelete | ReadOnly | DontEnum); 0070 } 0071 0072 JSValue *FunctionProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) 0073 { 0074 JSValue *result = nullptr; 0075 0076 switch (id) { 0077 case ToString: 0078 if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) { 0079 #ifndef NDEBUG 0080 fprintf(stderr, "attempted toString() call on null or non-function object\n"); 0081 #endif 0082 return throwError(exec, TypeError); 0083 } 0084 if (thisObj->inherits(&FunctionImp::info)) { 0085 return jsString(static_cast<FunctionImp *>(thisObj)->toSource()); 0086 } else if (thisObj->inherits(&InternalFunctionImp::info) && 0087 !static_cast<InternalFunctionImp *>(thisObj)->functionName().isNull()) { 0088 result = jsString("\nfunction " + static_cast<InternalFunctionImp *>(thisObj)->functionName().ustring() + "() {\n" 0089 " [native code]\n}\n"); 0090 } else { 0091 result = jsString("[function]"); 0092 } 0093 break; 0094 case Apply: { 0095 JSValue *thisArg = args[0]; 0096 JSValue *argArray = args[1]; 0097 JSObject *func = thisObj; 0098 0099 if (!func->implementsCall()) { 0100 return throwError(exec, TypeError); 0101 } 0102 0103 JSObject *applyThis; 0104 if (JSValue::isUndefinedOrNull(thisArg)) { 0105 applyThis = exec->dynamicInterpreter()->globalObject(); 0106 } else { 0107 applyThis = JSValue::toObject(thisArg, exec); 0108 } 0109 0110 List applyArgs; 0111 if (!JSValue::isUndefinedOrNull(argArray)) { 0112 if (JSValue::isObject(argArray) && 0113 (static_cast<JSObject *>(argArray)->inherits(&ArrayInstance::info) || 0114 static_cast<JSObject *>(argArray)->inherits(&Arguments::info))) { 0115 0116 JSObject *argArrayObj = static_cast<JSObject *>(argArray); 0117 unsigned int length = JSValue::toUInt32(argArrayObj->get(exec, exec->propertyNames().length), exec); 0118 for (unsigned int i = 0; i < length; i++) { 0119 applyArgs.append(argArrayObj->get(exec, i)); 0120 } 0121 } else { 0122 return throwError(exec, TypeError); 0123 } 0124 } 0125 result = func->call(exec, applyThis, applyArgs); 0126 } 0127 break; 0128 case Call: { 0129 JSValue *thisArg = args[0]; 0130 JSObject *func = thisObj; 0131 0132 if (!func->implementsCall()) { 0133 return throwError(exec, TypeError); 0134 } 0135 0136 JSObject *callThis; 0137 if (JSValue::isUndefinedOrNull(thisArg)) { 0138 callThis = exec->dynamicInterpreter()->globalObject(); 0139 } else { 0140 callThis = JSValue::toObject(thisArg, exec); 0141 } 0142 0143 result = func->call(exec, callThis, args.copyTail()); 0144 } 0145 break; 0146 case Bind: { //ECMA Edition 5.1r6 - 15.3.4.5 0147 JSObject *target(thisObj); 0148 if (!target->implementsCall()) { 0149 return throwError(exec, TypeError, "object is not callable"); 0150 } 0151 0152 List newArgs; 0153 for (int i = 1; i < args.size(); ++i) { 0154 newArgs.append(args[i]); 0155 } 0156 0157 JSObject *boundThis = nullptr; 0158 0159 // As call does not accept JSValue(undefined/null), 0160 // do it like in call and use the global object 0161 if (JSValue::isUndefinedOrNull(args[0])) { 0162 boundThis = exec->dynamicInterpreter()->globalObject(); 0163 } else { 0164 boundThis = JSValue::toObject(args[0], exec); 0165 } 0166 0167 BoundFunction *bfunc = new BoundFunction(exec, target, boundThis, newArgs); 0168 0169 unsigned length; 0170 if (target->inherits(&FunctionImp::info)) { 0171 double L = JSValue::getNumber(target->get(exec, exec->propertyNames().length)) - newArgs.size(); 0172 length = (unsigned)std::max<int>((int)L, 0); 0173 } else { 0174 length = 0; 0175 } 0176 bfunc->put(exec, exec->propertyNames().length, jsNumber(length), ReadOnly | DontEnum | DontDelete); 0177 0178 JSObject *thrower = new Thrower(TypeError); 0179 PropertyDescriptor callerDesc; 0180 0181 GetterSetterImp *gs = new GetterSetterImp(); 0182 gs->setGetter(thrower); 0183 gs->setSetter(thrower); 0184 0185 callerDesc.setPropertyDescriptorValues(exec, gs, DontEnum | DontDelete); 0186 bfunc->defineOwnProperty(exec, exec->propertyNames().caller, callerDesc, false); 0187 0188 PropertyDescriptor argumentsDesc; 0189 argumentsDesc.setPropertyDescriptorValues(exec, gs, DontEnum | DontDelete); 0190 bfunc->defineOwnProperty(exec, exec->propertyNames().arguments, argumentsDesc, false); 0191 0192 return bfunc; 0193 } 0194 break; 0195 } 0196 0197 return result; 0198 } 0199 0200 // ------------------------------ FunctionObjectImp ---------------------------- 0201 0202 FunctionObjectImp::FunctionObjectImp(ExecState *exec, FunctionPrototype *funcProto) 0203 : InternalFunctionImp(funcProto) 0204 { 0205 putDirect(exec->propertyNames().prototype, funcProto, DontEnum | DontDelete | ReadOnly); 0206 0207 // no. of arguments for constructor 0208 putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum); 0209 } 0210 0211 FunctionObjectImp::~FunctionObjectImp() 0212 { 0213 } 0214 0215 bool FunctionObjectImp::implementsConstruct() const 0216 { 0217 return true; 0218 } 0219 0220 // ECMA 15.3.2 The Function Constructor 0221 JSObject *FunctionObjectImp::construct(ExecState *exec, const List &args, const Identifier &functionName, const UString &sourceURL, int lineNumber) 0222 { 0223 UString p(""); 0224 UString body; 0225 int argsSize = args.size(); 0226 if (argsSize == 0) { 0227 body = ""; 0228 } else if (argsSize == 1) { 0229 body = JSValue::toString(args[0], exec); 0230 } else { 0231 p = JSValue::toString(args[0], exec); 0232 for (int k = 1; k < argsSize - 1; k++) { 0233 p += "," + JSValue::toString(args[k], exec); 0234 } 0235 body = JSValue::toString(args[argsSize - 1], exec); 0236 } 0237 0238 // parse the source code 0239 int sourceId; 0240 int errLine; 0241 UString errMsg; 0242 RefPtr<FunctionBodyNode> functionBody = parser().parseFunctionBody(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg); 0243 0244 // notify debugger that source has been parsed 0245 Debugger *dbg = exec->dynamicInterpreter()->debugger(); 0246 if (dbg) { 0247 // make sure to pass in sourceURL, since it's useful for lazy event listeners, and empty for actual function ctor 0248 dbg->reportSourceParsed(exec, functionBody.get(), sourceId, sourceURL, body, lineNumber, errLine, errMsg); 0249 } 0250 0251 // no program node == syntax error - throw a syntax error 0252 if (!functionBody) 0253 // we can't return a Completion(Throw) here, so just set the exception 0254 // and return it 0255 { 0256 return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL); 0257 } 0258 0259 ScopeChain scopeChain; 0260 scopeChain.push(exec->lexicalInterpreter()->globalObject()); 0261 0262 FunctionImp *fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain); 0263 0264 // parse parameter list. throw syntax error on illegal identifiers 0265 int len = p.size(); 0266 const UChar *c = p.data(); 0267 int i = 0, params = 0; 0268 UString param; 0269 while (i < len) { 0270 while (*c == ' ' && i < len) { 0271 c++, i++; 0272 } 0273 if (Lexer::isIdentStart(c->uc)) { // else error 0274 param = UString(c, 1); 0275 c++, i++; 0276 while (i < len && (Lexer::isIdentPart(c->uc))) { 0277 param += UString(c, 1); 0278 c++, i++; 0279 } 0280 while (i < len && *c == ' ') { 0281 c++, i++; 0282 } 0283 if (i == len) { 0284 functionBody->addParam(Identifier(param)); 0285 params++; 0286 break; 0287 } else if (*c == ',') { 0288 functionBody->addParam(Identifier(param)); 0289 params++; 0290 c++, i++; 0291 continue; 0292 } // else error 0293 } 0294 return throwError(exec, SyntaxError, "Syntax error in parameter list"); 0295 } 0296 0297 List consArgs; 0298 0299 JSObject *objCons = exec->lexicalInterpreter()->builtinObject(); 0300 JSObject *prototype = objCons->construct(exec, List::empty()); 0301 prototype->put(exec, exec->propertyNames().constructor, fimp, DontEnum | DontDelete | ReadOnly); 0302 // ECMA Edition 5.1r6 - 15.3.5.2 - [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false 0303 fimp->put(exec, exec->propertyNames().prototype, prototype, Internal | DontDelete | DontEnum); 0304 return fimp; 0305 } 0306 0307 // ECMA 15.3.2 The Function Constructor 0308 JSObject *FunctionObjectImp::construct(ExecState *exec, const List &args) 0309 { 0310 return construct(exec, args, "anonymous", UString(), 0); 0311 } 0312 0313 // ECMA 15.3.1 The Function Constructor Called as a Function 0314 JSValue *FunctionObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args) 0315 { 0316 return construct(exec, args); 0317 }