# kjs Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# 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

This file is part of the documentation for kjs Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:05 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003