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  *
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 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:14 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001