kjs Library API Documentation

function_object.cpp

00001 // -*- c-basic-offset: 2 -*- 00002 /* 00003 * This file is part of the KDE libraries 00004 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) 00005 * Copyright (C) 2003 Apple Computer, Inc. 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00020 * 00021 */ 00022 00023 #include "function_object.h" 00024 #include "internal.h" 00025 #include "function.h" 00026 #include "array_object.h" 00027 #include "nodes.h" 00028 #include "lexer.h" 00029 #include "debugger.h" 00030 #include "object.h" 00031 00032 #include <assert.h> 00033 #include <stdio.h> 00034 #include <string.h> 00035 00036 using namespace KJS; 00037 00038 // ------------------------------ FunctionPrototypeImp ------------------------- 00039 00040 FunctionPrototypeImp::FunctionPrototypeImp(ExecState *exec) 00041 : InternalFunctionImp((FunctionPrototypeImp*)0) 00042 { 00043 Value protect(this); 00044 putDirect(toStringPropertyName, 00045 new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::ToString, 0, toStringPropertyName), 00046 DontEnum); 00047 static const Identifier applyPropertyName("apply"); 00048 putDirect(applyPropertyName, 00049 new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Apply, 2, applyPropertyName), 00050 DontEnum); 00051 static const Identifier callPropertyName("call"); 00052 putDirect(callPropertyName, 00053 new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Call, 1, callPropertyName), 00054 DontEnum); 00055 putDirect(lengthPropertyName, 0, DontDelete|ReadOnly|DontEnum); 00056 } 00057 00058 FunctionPrototypeImp::~FunctionPrototypeImp() 00059 { 00060 } 00061 00062 bool FunctionPrototypeImp::implementsCall() const 00063 { 00064 return true; 00065 } 00066 00067 // ECMA 15.3.4 00068 Value FunctionPrototypeImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/) 00069 { 00070 return Undefined(); 00071 } 00072 00073 // ------------------------------ FunctionProtoFuncImp ------------------------- 00074 00075 FunctionProtoFuncImp::FunctionProtoFuncImp(ExecState */*exec*/, FunctionPrototypeImp *funcProto, 00076 int i, int len, const Identifier &_ident) 00077 : InternalFunctionImp(funcProto), id(i) 00078 { 00079 Value protect(this); 00080 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum); 00081 ident = _ident; 00082 } 00083 00084 00085 bool FunctionProtoFuncImp::implementsCall() const 00086 { 00087 return true; 00088 } 00089 00090 Value FunctionProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 00091 { 00092 Value result; 00093 00094 switch (id) { 00095 case ToString: { 00096 // ### also make this work for internal functions 00097 if (!thisObj.isValid() || !thisObj.inherits(&InternalFunctionImp::info)) { 00098 #ifndef NDEBUG 00099 fprintf(stderr,"attempted toString() call on null or non-function object\n"); 00100 #endif 00101 Object err = Error::create(exec,TypeError); 00102 exec->setException(err); 00103 return err; 00104 } 00105 00106 if (thisObj.inherits(&DeclaredFunctionImp::info)) { 00107 DeclaredFunctionImp *fi = static_cast<DeclaredFunctionImp*> 00108 (thisObj.imp()); 00109 return String("function " + fi->name().ustring() + "(" + 00110 fi->parameterString() + ") " + fi->body->toCode()); 00111 } else if (thisObj.inherits(&InternalFunctionImp::info) && 00112 !static_cast<InternalFunctionImp*>(thisObj.imp())->name().isNull()) { 00113 result = String("\nfunction " + static_cast<InternalFunctionImp*>(thisObj.imp())->name().ustring() + "() {\n" 00114 " [native code]\n}\n"); 00115 } 00116 else { 00117 result = String("[function]"); 00118 } 00119 } 00120 break; 00121 case Apply: { 00122 Value thisArg = args[0]; 00123 Value argArray = args[1]; 00124 Object func = thisObj; 00125 00126 if (!func.implementsCall()) { 00127 Object err = Error::create(exec,TypeError); 00128 exec->setException(err); 00129 return err; 00130 } 00131 00132 Object applyThis; 00133 if (thisArg.isA(NullType) || thisArg.isA(UndefinedType)) 00134 applyThis = exec->interpreter()->globalObject(); 00135 else 00136 applyThis = thisArg.toObject(exec); 00137 00138 List applyArgs; 00139 if (!argArray.isA(NullType) && !argArray.isA(UndefinedType)) { 00140 if (argArray.isA(ObjectType) && 00141 (Object::dynamicCast(argArray).inherits(&ArrayInstanceImp::info) || 00142 Object::dynamicCast(argArray).inherits(&ArgumentsImp::info))) { 00143 00144 Object argArrayObj = Object::dynamicCast(argArray); 00145 unsigned int length = argArrayObj.get(exec,lengthPropertyName).toUInt32(exec); 00146 for (unsigned int i = 0; i < length; i++) 00147 applyArgs.append(argArrayObj.get(exec,i)); 00148 } 00149 else { 00150 Object err = Error::create(exec,TypeError); 00151 exec->setException(err); 00152 return err; 00153 } 00154 } 00155 result = func.call(exec,applyThis,applyArgs); 00156 } 00157 break; 00158 case Call: { 00159 Value thisArg = args[0]; 00160 Object func = thisObj; 00161 00162 if (!func.implementsCall()) { 00163 Object err = Error::create(exec,TypeError); 00164 exec->setException(err); 00165 return err; 00166 } 00167 00168 Object callThis; 00169 if (thisArg.isA(NullType) || thisArg.isA(UndefinedType)) 00170 callThis = exec->interpreter()->globalObject(); 00171 else 00172 callThis = thisArg.toObject(exec); 00173 00174 result = func.call(exec,callThis,args.copyTail()); 00175 } 00176 break; 00177 } 00178 00179 return result; 00180 } 00181 00182 // ------------------------------ FunctionObjectImp ---------------------------- 00183 00184 FunctionObjectImp::FunctionObjectImp(ExecState */*exec*/, FunctionPrototypeImp *funcProto) 00185 : InternalFunctionImp(funcProto) 00186 { 00187 Value protect(this); 00188 putDirect(prototypePropertyName, funcProto, DontEnum|DontDelete|ReadOnly); 00189 00190 // no. of arguments for constructor 00191 putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum); 00192 } 00193 00194 FunctionObjectImp::~FunctionObjectImp() 00195 { 00196 } 00197 00198 bool FunctionObjectImp::implementsConstruct() const 00199 { 00200 return true; 00201 } 00202 00203 // ECMA 15.3.2 The Function Constructor 00204 Object FunctionObjectImp::construct(ExecState *exec, const List &args) 00205 { 00206 UString p(""); 00207 UString body; 00208 int argsSize = args.size(); 00209 if (argsSize == 0) { 00210 body = ""; 00211 } else if (argsSize == 1) { 00212 body = args[0].toString(exec); 00213 } else { 00214 p = args[0].toString(exec); 00215 for (int k = 1; k < argsSize - 1; k++) 00216 p += "," + args[k].toString(exec); 00217 body = args[argsSize-1].toString(exec); 00218 } 00219 00220 // parse the source code 00221 SourceCode *source; 00222 int errLine; 00223 UString errMsg; 00224 FunctionBodyNode *progNode = Parser::parse(body.data(),body.size(),&source,&errLine,&errMsg); 00225 00226 // notify debugger that source has been parsed 00227 Debugger *dbg = exec->interpreter()->imp()->debugger(); 00228 if (dbg) { 00229 bool cont = dbg->sourceParsed(exec,source->sid,body,errLine); 00230 if (!cont) { 00231 source->deref(); 00232 dbg->imp()->abort(); 00233 if (progNode) 00234 delete progNode; 00235 return Object(new ObjectImp()); 00236 } 00237 } 00238 00239 exec->interpreter()->imp()->addSourceCode(source); 00240 00241 // no program node == syntax error - throw a syntax error 00242 if (!progNode) { 00243 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine); 00244 // we can't return a Completion(Throw) here, so just set the exception 00245 // and return it 00246 exec->setException(err); 00247 source->deref(); 00248 return err; 00249 } 00250 source->deref(); 00251 00252 ScopeChain scopeChain; 00253 scopeChain.push(exec->interpreter()->globalObject().imp()); 00254 FunctionBodyNode *bodyNode = progNode; 00255 00256 FunctionImp *fimp = new DeclaredFunctionImp(exec, Identifier::null(), bodyNode, 00257 scopeChain); 00258 Object ret(fimp); // protect from GC 00259 00260 // parse parameter list. throw syntax error on illegal identifiers 00261 int len = p.size(); 00262 const UChar *c = p.data(); 00263 int i = 0, params = 0; 00264 UString param; 00265 while (i < len) { 00266 while (*c == ' ' && i < len) 00267 c++, i++; 00268 if (Lexer::isIdentLetter(c->uc)) { // else error 00269 param = UString(c, 1); 00270 c++, i++; 00271 while (i < len && (Lexer::isIdentLetter(c->uc) || 00272 Lexer::isDecimalDigit(c->uc))) { 00273 param += UString(c, 1); 00274 c++, i++; 00275 } 00276 while (i < len && *c == ' ') 00277 c++, i++; 00278 if (i == len) { 00279 fimp->addParameter(Identifier(param)); 00280 params++; 00281 break; 00282 } else if (*c == ',') { 00283 fimp->addParameter(Identifier(param)); 00284 params++; 00285 c++, i++; 00286 continue; 00287 } // else error 00288 } 00289 Object err = Error::create(exec,SyntaxError, 00290 I18N_NOOP("Syntax error in parameter list"), 00291 -1); 00292 exec->setException(err); 00293 return err; 00294 } 00295 00296 List consArgs; 00297 00298 Object objCons = exec->interpreter()->builtinObject(); 00299 Object prototype = objCons.construct(exec,List::empty()); 00300 prototype.put(exec, constructorPropertyName, Value(fimp), DontEnum|DontDelete|ReadOnly); 00301 fimp->put(exec, prototypePropertyName, prototype, DontEnum|DontDelete|ReadOnly); 00302 return ret; 00303 } 00304 00305 bool FunctionObjectImp::implementsCall() const 00306 { 00307 return true; 00308 } 00309 00310 // ECMA 15.3.1 The Function Constructor Called as a Function 00311 Value FunctionObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 00312 { 00313 return construct(exec,args); 00314 } 00315
KDE Logo
This file is part of the documentation for kjs Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:55:17 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003