function_object.cpp Source File (kjs Library)

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:08:22 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001