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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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->dynamicInterpreter()->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->dynamicInterpreter()->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->dynamicInterpreter()->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->dynamicInterpreter()->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->lexicalInterpreter()->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 Home | KDE Accessibility Home | Description of Access Keys