# kjs Library API Documentation

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

# function.cpp

    00001 // -*- c-basic-offset: 2 -*-
    00002 /*
    00003  *  This file is part of the KDE libraries
    00004  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
    00005  *  Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
    00006  *  Copyright (C) 2003 Apple Computer, Inc.
    00007  *
    00008  *  This library is free software; you can redistribute it and/or
    00009  *  modify it under the terms of the GNU Library General Public
    00010  *  License as published by the Free Software Foundation; either
    00011  *  version 2 of the License, or (at your option) any later version.
    00012  *
    00013  *  This library is distributed in the hope that it will be useful,
    00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016  *  Library General Public License for more details.
    00017  *
    00018  *  You should have received a copy of the GNU Library General Public License
    00019  *  along with this library; see the file COPYING.LIB.  If not, write to
    00020  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021  *  Boston, MA 02111-1307, USA.
    00022  *
    00023  */
    00024
    00025 #include "function.h"
    00026
    00027 #include "internal.h"
    00028 #include "function_object.h"
    00029 #include "lexer.h"
    00030 #include "nodes.h"
    00031 #include "operations.h"
    00032 #include "debugger.h"
    00033 #include "context.h"
    00034
    00035 #include <stdio.h>
    00036 #include <stdlib.h>
    00037 #include <assert.h>
    00038 #include <string.h>
    00039 #include <errno.h>
    00040 #include <math.h>
    00041 #include <ctype.h>
    00042
    00043 using namespace KJS;
    00044
    00045 // ------------------------- URI handling functions ---------------------------
    00046
    00047 // ECMA 15.1.3
    00048 UString encodeURI(ExecState *exec, UString string, UString unescapedSet)
    00049 {
    00050   char hexdigits[] = "0123456789ABCDEF";
    00051   int encbufAlloc = 2;
    00052   UChar *encbuf = (UChar*)malloc(encbufAlloc*sizeof(UChar));
    00053   int encbufLen = 0;
    00054
    00055   for (int k = 0; k < string.size(); k++) {
    00056
    00057     UChar C = string[k];
    00058     if (unescapedSet.find(C) >= 0) {
    00059       if (encbufLen+1 >= encbufAlloc)
    00060     encbuf = (UChar*)realloc(encbuf,(encbufAlloc *= 2)*sizeof(UChar));
    00061       encbuf[encbufLen++] = C;
    00062     }
    00063     else {
    00064       unsigned char octets[4];
    00065       int octets_len = 0;
    00066       if (C.uc <= 0x007F) {
    00067     unsigned short zzzzzzz = C.uc;
    00068     octets[0] = zzzzzzz;
    00069     octets_len = 1;
    00070       }
    00071       else if (C.uc <= 0x07FF) {
    00072     unsigned short zzzzzz = C.uc & 0x3F;
    00073     unsigned short yyyyy = (C.uc >> 6) & 0x1F;
    00074     octets[0] = 0xC0 | yyyyy;
    00075     octets[1] = 0x80 | zzzzzz;
    00076     octets_len = 2;
    00077       }
    00078       else if (C.uc >= 0xD800 && C.uc <= 0xDBFF) {
    00079
    00080     if (k == string.size()) {
    00081       Object err = Error::create(exec,URIError);
    00082       exec->setException(err);
    00083       free(encbuf);
    00084       return UString();
    00085     }
    00086
    00087     unsigned short Cnext = UChar(string[++k]).uc;
    00088
    00089     if (Cnext < 0xDC00 || Cnext > 0xDFFF) {
    00090       Object err = Error::create(exec,URIError);
    00091       exec->setException(err);
    00092       free(encbuf);
    00093       return UString();
    00094     }
    00095
    00096     unsigned short zzzzzz = Cnext & 0x3F;
    00097     unsigned short yyyy = (Cnext >> 6) & 0x0F;
    00098     unsigned short xx = C.uc & 0x03;
    00099     unsigned short wwww = (C.uc >> 2) & 0x0F;
    00100     unsigned short vvvv = (C.uc >> 6) & 0x0F;
    00101     unsigned short uuuuu = vvvv+1;
    00102     octets[0] = 0xF0 | (uuuuu >> 2);
    00103     octets[1] = 0x80 | ((uuuuu & 0x03) << 4) | wwww;
    00104     octets[2] = 0x80 | (xx << 4) | yyyy;
    00105     octets[3] = 0x80 | zzzzzz;
    00106     octets_len = 4;
    00107       }
    00108       else if (C.uc >= 0xDC00 && C.uc <= 0xDFFF) {
    00109     Object err = Error::create(exec,URIError);
    00110     exec->setException(err);
    00111     free(encbuf);
    00112     return UString();
    00113       }
    00114       else {
    00115     // 0x0800 - 0xD7FF or 0xE000 - 0xFFFF
    00116     unsigned short zzzzzz = C.uc & 0x3F;
    00117     unsigned short yyyyyy = (C.uc >> 6) & 0x3F;
    00118     unsigned short xxxx = (C.uc >> 12) & 0x0F;
    00119     octets[0] = 0xE0 | xxxx;
    00120     octets[1] = 0x80 | yyyyyy;
    00121     octets[2] = 0x80 | zzzzzz;
    00122     octets_len = 3;
    00123       }
    00124
    00125       while (encbufLen+3*octets_len >= encbufAlloc)
    00126     encbuf = (UChar*)realloc(encbuf,(encbufAlloc *= 2)*sizeof(UChar));
    00127
    00128       for (int j = 0; j < octets_len; j++) {
    00129     encbuf[encbufLen++] = '%';
    00130     encbuf[encbufLen++] = hexdigits[octets[j] >> 4];
    00131     encbuf[encbufLen++] = hexdigits[octets[j] & 0x0F];
    00132       }
    00133     }
    00134   }
    00135
    00136   UString encoded(encbuf,encbufLen);
    00137   free(encbuf);
    00138   return encoded;
    00139 }
    00140
    00141 static bool decodeHex(UChar hi, UChar lo, unsigned short *val)
    00142 {
    00143   *val = 0;
    00144   if (hi.uc >= '0' && hi.uc <= '9')
    00145     *val = (hi.uc-'0') << 4;
    00146   else if (hi.uc >= 'a' && hi.uc <= 'f')
    00147     *val = 10+(hi.uc-'a') << 4;
    00148   else if (hi.uc >= 'A' && hi.uc <= 'F')
    00149     *val = 10+(hi.uc-'A') << 4;
    00150   else
    00151     return false;
    00152
    00153   if (lo.uc >= '0' && lo.uc <= '9')
    00154     *val |= (lo.uc-'0');
    00155   else if (lo.uc >= 'a' && lo.uc <= 'f')
    00156     *val |= 10+(lo.uc-'a');
    00157   else if (lo.uc >= 'A' && lo.uc <= 'F')
    00158     *val |= 10+(lo.uc-'A');
    00159   else
    00160     return false;
    00161
    00162   return true;
    00163 }
    00164
    00165 UString decodeURI(ExecState *exec, UString string, UString reservedSet)
    00166 {
    00167   int decbufAlloc = 2;
    00168   UChar *decbuf = (UChar*)malloc(decbufAlloc*sizeof(UChar));
    00169   int decbufLen = 0;
    00170
    00171   for (int k = 0; k < string.size(); k++) {
    00172     UChar C = string[k];
    00173
    00174     if (C != UChar('%')) {
    00175       // Normal unescaped character
    00176       if (decbufLen+1 >= decbufAlloc)
    00177     decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
    00178       decbuf[decbufLen++] = C;
    00179       continue;
    00180     }
    00181
    00182     // We have % escape sequence... expect at least 2 more characters
    00183     int start = k;
    00184     if (k+2 >= string.size()) {
    00185       Object err = Error::create(exec,URIError);
    00186       exec->setException(err);
    00187       free(decbuf);
    00188       return UString();
    00189     }
    00190
    00191     unsigned short B;
    00192     if (!decodeHex(string[k+1],string[k+2],&B)) {
    00193       Object err = Error::create(exec,URIError);
    00194       exec->setException(err);
    00195       free(decbuf);
    00196       return UString();
    00197     }
    00198
    00199     k += 2;
    00200     if ((B & 0x80) == 0) {
    00201       // Single-byte character
    00202       C = B;
    00203     }
    00204     else {
    00205       // Multi-byte character
    00206       int n = 0;
    00207       while (((B << n) & 0x80) != 0)
    00208     n++;
    00209
    00210       if (n < 2 || n > 4) {
    00211     Object err = Error::create(exec,URIError);
    00212     exec->setException(err);
    00213     free(decbuf);
    00214     return UString();
    00215       }
    00216
    00217       if (k+3*(n-1) >= string.size()) {
    00218     Object err = Error::create(exec,URIError);
    00219     exec->setException(err);
    00220     free(decbuf);
    00221     return UString();
    00222       }
    00223
    00224       unsigned short octets[4];
    00225       octets[0] = B;
    00226       for (int j = 1; j < n; j++) {
    00227     k++;
    00228     if ((UChar(string[k]) != UChar('%')) ||
    00229         !decodeHex(string[k+1],string[k+2],&B) ||
    00230         ((B & 0xC0) != 0x80)) {
    00231       Object err = Error::create(exec,URIError);
    00232       exec->setException(err);
    00233       free(decbuf);
    00234       return UString();
    00235     }
    00236
    00237     k += 2;
    00238     octets[j] = B;
    00239       }
    00240
    00241       // UTF-8 transform
    00242       unsigned long V;
    00243       if (n == 2) {
    00244     unsigned long yyyyy = octets[0] & 0x1F;
    00245     unsigned long zzzzzz = octets[1] & 0x3F;
    00246     V = (yyyyy << 6) | zzzzzz;
    00247     C = UChar((unsigned short)V);
    00248       }
    00249       else if (n == 3) {
    00250     unsigned long xxxx = octets[0] & 0x0F;
    00251     unsigned long yyyyyy = octets[1] & 0x3F;
    00252     unsigned long zzzzzz = octets[2] & 0x3F;
    00253     V = (xxxx << 12) | (yyyyyy << 6) | zzzzzz;
    00254     C = UChar((unsigned short)V);
    00255       }
    00256       else {
    00257     assert(n == 4);
    00258     unsigned long uuuuu = ((octets[0] & 0x07) << 2) | ((octets[1] >> 4) & 0x03);
    00259     unsigned long vvvv = uuuuu-1;
    00260     unsigned long wwww = octets[1] & 0x0F;
    00261     unsigned long xx = (octets[2] >> 4) & 0x03;
    00262     unsigned long yyyy = octets[2] & 0x0F;
    00263     unsigned long zzzzzz = octets[3] & 0x3F;
    00264     unsigned short H = 0xD800 | (vvvv << 6) | (wwww << 2) | xx;
    00265     unsigned short L = 0xDC00 | (yyyy << 6) | zzzzzz;
    00266     decbuf[decbufLen++] = UChar(H);
    00267     decbuf[decbufLen++] = UChar(L);
    00268     continue;
    00269       }
    00270     }
    00271
    00272     if (reservedSet.find(C) < 0) {
    00273       if (decbufLen+1 >= decbufAlloc)
    00274     decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
    00275       decbuf[decbufLen++] = C;
    00276     }
    00277     else {
    00278       while (decbufLen+k-start >= decbufAlloc)
    00279     decbuf = (UChar*)realloc(decbuf,(decbufAlloc *= 2)*sizeof(UChar));
    00280       for (int p = start; p < k; p++)
    00281     decbuf[decbufLen++] = string[p];
    00282     }
    00283   }
    00284
    00285   UString decoded(decbuf,decbufLen);
    00286   free(decbuf);
    00287   return decoded;
    00288 }
    00289
    00290 static UString uriReserved = ";/?:@&=+$,";
    00291 static UString uriAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    00292 static UString DecimalDigit = "0123456789";
    00293 static UString uriMark = "-_.!~*'()";
    00294 static UString uriUnescaped = uriAlpha+DecimalDigit+uriMark;
    00295
    00296 // ----------------------------- FunctionImp ----------------------------------
    00297
    00298 const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
    00299
    00300 namespace KJS {
    00301   class Parameter {
    00302   public:
    00303     Parameter(const Identifier &n) : name(n), next(0L) { }
    00304     ~Parameter() { delete next; }
    00305     Identifier name;
    00306     Parameter *next;
    00307   };
    00308 }
    00309
    00310 FunctionImp::FunctionImp(ExecState *exec, const Identifier &n)
    00311   : InternalFunctionImp(
    00312       static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
    00313       ), param(0L), line0(-1), line1(-1), sid(-1)
    00314 {
    00315   //fprintf(stderr,"FunctionImp::FunctionImp this=%p\n");
    00316   ident = n;
    00317 }
    00318
    00319 FunctionImp::~FunctionImp()
    00320 {
    00321   delete param;
    00322 }
    00323
    00324 bool FunctionImp::implementsCall() const
    00325 {
    00326   return true;
    00327 }
    00328
    00329 Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
    00330 {
    00331   Object &globalObj = exec->interpreter()->globalObject();
    00332
    00333   // enter a new execution context
    00334   ContextImp ctx(globalObj, exec->interpreter()->imp(), thisObj, sid, codeType(),
    00335                  exec->context().imp(), this, &args);
    00336   ExecState newExec(exec->interpreter(), &ctx);
    00337   newExec.setException(exec->exception()); // could be null
    00338
    00339   // assign user supplied arguments to parameters
    00340   processParameters(&newExec, args);
    00341   // add variable declarations (initialized to undefined)
    00342   processVarDecls(&newExec);
    00343
    00344   ctx.setLines(line0,line0);
    00345   Debugger *dbg = exec->interpreter()->imp()->debugger();
    00346   if (dbg) {
    00347     if (!dbg->enterContext(&newExec)) {
    00348       // debugger requested we stop execution
    00349       dbg->imp()->abort();
    00350       return Undefined();
    00351     }
    00352   }
    00353
    00354   Completion comp = execute(&newExec);
    00355
    00356   ctx.setLines(line1,line1);
    00357   if (dbg) {
    00358     Object func(this);
    00359     // ### lineno is inaccurate - we really want the end of the function _body_ here
    00360     // line1 is suppoed to be the end of the function start, just before the body
    00361     if (!dbg->exitContext(&newExec,comp)) {
    00362       // debugger requested we stop execution
    00363       dbg->imp()->abort();
    00364       return Undefined();
    00365     }
    00366   }
    00367
    00368   // if an exception occurred, propogate it back to the previous execution object
    00369   if (newExec.hadException())
    00370     exec->setException(newExec.exception());
    00371
    00372 #ifdef KJS_VERBOSE
    00373   CString n = ident.isEmpty() ? CString("(internal)") : ident.ustring().cstring();
    00374   if (comp.complType() == Throw) {
    00375     n += " throws";
    00376     printInfo(exec, n.c_str(), comp.value());
    00377   } else if (comp.complType() == ReturnValue) {
    00378     n += " returns";
    00379     printInfo(exec, n.c_str(), comp.value());
    00380   } else
    00381     fprintf(stderr, "%s returns: undefined\n", n.c_str());
    00382 #endif
    00383
    00384   if (comp.complType() == Throw) {
    00385     exec->setException(comp.value());
    00386     return comp.value();
    00387   }
    00388   else if (comp.complType() == ReturnValue)
    00389     return comp.value();
    00390   else
    00391     return Undefined();
    00392 }
    00393
    00394 void FunctionImp::addParameter(const Identifier &n)
    00395 {
    00396   Parameter **p = &param;
    00397   while (*p)
    00398     p = &(*p)->next;
    00399
    00400   *p = new Parameter(n);
    00401 }
    00402
    00403 Identifier FunctionImp::parameterProperty(int index) const
    00404 {
    00405   // Find the property name corresponding to the given parameter
    00406   int pos = 0;
    00407   Parameter *p;
    00408   for (p = param; p && pos < index; p = p->next)
    00409     pos++;
    00410
    00411   if (!p)
    00412     return Identifier::null();
    00413
    00414   // Are there any subsequent parameters with the same name?
    00415   Identifier name = p->name;
    00416   for (p = p->next; p; p = p->next)
    00417     if (p->name == name)
    00418       return Identifier::null();
    00419
    00420   return name;
    00421 }
    00422
    00423 UString FunctionImp::parameterString() const
    00424 {
    00425   UString s;
    00426   const Parameter *p = param;
    00427   while (p) {
    00428     if (!s.isEmpty())
    00429         s += ", ";
    00430     s += p->name.ustring();
    00431     p = p->next;
    00432   }
    00433
    00434   return s;
    00435 }
    00436
    00437
    00438 // ECMA 10.1.3q
    00439 void FunctionImp::processParameters(ExecState *exec, const List &args)
    00440 {
    00441   Object variable = exec->context().imp()->variableObject();
    00442
    00443 #ifdef KJS_VERBOSE
    00444   fprintf(stderr, "---------------------------------------------------\n"
    00445       "processing parameters for %s call\n",
    00446       name().isEmpty() ? "(internal)" : name().ascii());
    00447 #endif
    00448
    00449   if (param) {
    00450     ListIterator it = args.begin();
    00451     Parameter *p = param;
    00452     while (p) {
    00453       if (it != args.end()) {
    00454 #ifdef KJS_VERBOSE
    00455     fprintf(stderr, "setting parameter %s ", p->name.ascii());
    00456     printInfo(exec,"to", *it);
    00457 #endif
    00458     variable.put(exec, p->name, *it);
    00459     it++;
    00460       } else
    00461     variable.put(exec, p->name, Undefined());
    00462       p = p->next;
    00463     }
    00464   }
    00465 #ifdef KJS_VERBOSE
    00466   else {
    00467     for (int i = 0; i < args.size(); i++)
    00468       printInfo(exec,"setting argument", args[i]);
    00469   }
    00470 #endif
    00471 }
    00472
    00473 void FunctionImp::processVarDecls(ExecState * /*exec*/)
    00474 {
    00475 }
    00476
    00477 Value FunctionImp::get(ExecState *exec, const Identifier &propertyName) const
    00478 {
    00479     // Find the arguments from the closest context.
    00480     if (propertyName == argumentsPropertyName) {
    00481 // delme
    00482         ContextImp *context = exec->context().imp();
    00483 // fixme
    00484 //         ContextImp *context = exec->_context;
    00485         while (context) {
    00486             if (context->function() == this)
    00487                 return static_cast<ActivationImp *>
    00488                     (context->activationObject())->get(exec, propertyName);
    00489             context = context->callingContext();
    00490         }
    00491         return Null();
    00492     }
    00493
    00494     // Compute length of parameters.
    00495     if (propertyName == lengthPropertyName) {
    00496         const Parameter * p = param;
    00497         int count = 0;
    00498         while (p) {
    00499             ++count;
    00500             p = p->next;
    00501         }
    00502         return Number(count);
    00503     }
    00504
    00505     return InternalFunctionImp::get(exec, propertyName);
    00506 }
    00507
    00508 void FunctionImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
    00509 {
    00510     if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
    00511         return;
    00512     InternalFunctionImp::put(exec, propertyName, value, attr);
    00513 }
    00514
    00515 bool FunctionImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
    00516 {
    00517     if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
    00518         return true;
    00519     return InternalFunctionImp::hasProperty(exec, propertyName);
    00520 }
    00521
    00522 bool FunctionImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
    00523 {
    00524     if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
    00525         return false;
    00526     return InternalFunctionImp::deleteProperty(exec, propertyName);
    00527 }
    00528
    00529 // ------------------------------ DeclaredFunctionImp --------------------------
    00530
    00531 // ### is "Function" correct here?
    00532 const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
    00533
    00534 DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const Identifier &n,
    00535                      FunctionBodyNode *b, const ScopeChain &sc)
    00536   : FunctionImp(exec,n), body(b)
    00537 {
    00538   Value protect(this);
    00539   body->ref();
    00540   setScope(sc);
    00541   line0 = body->firstLine();
    00542   line1 = body->lastLine();
    00543   sid = body->sourceId();
    00544 }
    00545
    00546 DeclaredFunctionImp::~DeclaredFunctionImp()
    00547 {
    00548   if ( body->deref() )
    00549     delete body;
    00550 }
    00551
    00552 bool DeclaredFunctionImp::implementsConstruct() const
    00553 {
    00554   return true;
    00555 }
    00556
    00557 // ECMA 13.2.2 [[Construct]]
    00558 Object DeclaredFunctionImp::construct(ExecState *exec, const List &args)
    00559 {
    00560   Object proto;
    00561   Value p = get(exec,prototypePropertyName);
    00562   if (p.type() == ObjectType)
    00563     proto = Object(static_cast<ObjectImp*>(p.imp()));
    00564   else
    00565     proto = exec->interpreter()->builtinObjectPrototype();
    00566
    00567   Object obj(new ObjectImp(proto));
    00568
    00569   Value res = call(exec,obj,args);
    00570
    00571   if (res.type() == ObjectType)
    00572     return Object::dynamicCast(res);
    00573   else
    00574     return obj;
    00575 }
    00576
    00577 Completion DeclaredFunctionImp::execute(ExecState *exec)
    00578 {
    00579   Completion result = body->execute(exec);
    00580
    00581   if (result.complType() == Throw || result.complType() == ReturnValue)
    00582       return result;
    00583   return Completion(Normal, Undefined()); // TODO: or ReturnValue ?
    00584 }
    00585
    00586 void DeclaredFunctionImp::processVarDecls(ExecState *exec)
    00587 {
    00588   body->processVarDecls(exec);
    00589 }
    00590
    00591 // ------------------------------- ShadowImp -----------------------------------
    00592
    00593 namespace KJS {
    00594
    00595 // Acts as a placeholder value to indicate that the actual value is kept
    00596 // in the activation object
    00597 class ShadowImp : public ObjectImp {
    00598 public:
    00599   ShadowImp(ObjectImp *_obj, Identifier _prop) : obj(_obj), prop(_prop) {}
    00600   virtual void mark();
    00601
    00602   virtual const ClassInfo *classInfo() const { return &info; }
    00603   static const ClassInfo info;
    00604
    00605   ObjectImp *obj;
    00606   Identifier prop;
    00607 };
    00608
    00609 /*KDE_NOEXPORT*/ const ClassInfo ShadowImp::info = {"Shadow", 0, 0, 0};
    00610
    00611 void ShadowImp::mark()
    00612 {
    00613   ObjectImp::mark();
    00614   if (!obj->marked())
    00615     obj->mark();
    00616 }
    00617
    00618 }
    00619
    00620 // ------------------------------ ArgumentsImp ---------------------------------
    00621
    00622 const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
    00623
    00624 // ECMA 10.1.8
    00625 ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args,
    00626                ActivationImp *act)
    00627   : ObjectImp(exec->interpreter()->builtinObjectPrototype()), activation(act)
    00628 {
    00629   Value protect(this);
    00630   putDirect(calleePropertyName, func, DontEnum);
    00631   putDirect(lengthPropertyName, args.size(), DontEnum);
    00632   if (!args.isEmpty()) {
    00633     ListIterator arg = args.begin();
    00634     for (int i = 0; arg != args.end(); arg++, i++) {
    00635       Identifier prop = func->parameterProperty(i);
    00636       if (!prop.isEmpty()) {
    00637     Object shadow(new ShadowImp(act,prop));
    00638     ObjectImp::put(exec,Identifier::from(i), shadow, DontEnum);
    00639       }
    00640       else {
    00641     ObjectImp::put(exec,Identifier::from(i), *arg, DontEnum);
    00642       }
    00643     }
    00644   }
    00645 }
    00646
    00647 void ArgumentsImp::mark()
    00648 {
    00649   ObjectImp::mark();
    00650   if (!activation->marked())
    00651     activation->mark();
    00652 }
    00653
    00654 Value ArgumentsImp::get(ExecState *exec, const Identifier &propertyName) const
    00655 {
    00656   Value val = ObjectImp::get(exec,propertyName);
    00657   assert(SimpleNumber::is(val.imp()) || !val.imp()->isDestroyed());
    00658   Object obj = Object::dynamicCast(val);
    00659   if (obj.isValid() && obj.inherits(&ShadowImp::info)) {
    00660     ShadowImp *shadow = static_cast<ShadowImp*>(val.imp());
    00661     return activation->get(exec,shadow->prop);
    00662   }
    00663   else {
    00664     return val;
    00665   }
    00666 }
    00667
    00668 void ArgumentsImp::put(ExecState *exec, const Identifier &propertyName,
    00669                const Value &value, int attr)
    00670 {
    00671   Value val = ObjectImp::get(exec,propertyName);
    00672   Object obj = Object::dynamicCast(val);
    00673   if (obj.isValid() && obj.inherits(&ShadowImp::info)) {
    00674     ShadowImp *shadow = static_cast<ShadowImp*>(val.imp());
    00675     activation->put(exec,shadow->prop,value,attr);
    00676   }
    00677   else {
    00678     ObjectImp::put(exec,propertyName,value,attr);
    00679   }
    00680 }
    00681
    00682 // ------------------------------ ActivationImp --------------------------------
    00683
    00684 const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
    00685
    00686 // ECMA 10.1.6
    00687 ActivationImp::ActivationImp(FunctionImp *function, const List &arguments)
    00688     : _function(function), _arguments(true), _argumentsObject(0)
    00689 {
    00690   _arguments = arguments.copy();
    00691   // FIXME: Do we need to support enumerating the arguments property?
    00692 }
    00693
    00694 Value ActivationImp::get(ExecState *exec, const Identifier &propertyName) const
    00695 {
    00696   if (propertyName == argumentsPropertyName) {
    00697     ValueImp *imp = getDirect(propertyName);
    00698     if (imp)
    00699       return Value(imp);
    00700
    00701     if (!_argumentsObject)
    00702       _argumentsObject = new ArgumentsImp(exec, _function, _arguments, const_cast<ActivationImp*>(this));
    00703     return Value(_argumentsObject);
    00704   }
    00705   return ObjectImp::get(exec, propertyName);
    00706 }
    00707
    00708 bool ActivationImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
    00709 {
    00710   if (propertyName == argumentsPropertyName)
    00711     return true;
    00712   return ObjectImp::hasProperty(exec, propertyName);
    00713 }
    00714
    00715 bool ActivationImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
    00716 {
    00717   if (propertyName == argumentsPropertyName)
    00718     return false;
    00719   return ObjectImp::deleteProperty(exec, propertyName);
    00720 }
    00721
    00722 void ActivationImp::mark()
    00723 {
    00724   ObjectImp::mark();
    00725   if (_function && !_function->marked())
    00726     _function->mark();
    00727   _arguments.mark();
    00728   if (_argumentsObject && !_argumentsObject->marked())
    00729     _argumentsObject->mark();
    00730 }
    00731
    00732 // ------------------------------ GlobalFunc -----------------------------------
    00733
    00734
    00735 GlobalFuncImp::GlobalFuncImp(ExecState * /*exec*/, FunctionPrototypeImp *funcProto,
    00736                  int i, int len, const Identifier &_ident)
    00737   : InternalFunctionImp(funcProto), id(i)
    00738 {
    00739   Value protect(this);
    00740   putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
    00741   ident = _ident;
    00742 }
    00743
    00744 CodeType GlobalFuncImp::codeType() const
    00745 {
    00746   return id == Eval ? EvalCode : codeType();
    00747 }
    00748
    00749 bool GlobalFuncImp::implementsCall() const
    00750 {
    00751   return true;
    00752 }
    00753
    00754 Value GlobalFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
    00755 {
    00756   Value res;
    00757
    00758   static const char do_not_escape[] =
    00759     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    00760     "abcdefghijklmnopqrstuvwxyz"
    00761     "0123456789"
    00762     "*+-./@_";
    00763
    00764   switch (id) {
    00765   case Eval: { // eval()
    00766     Value x = args[0];
    00767     if (x.type() != StringType)
    00768       return x;
    00769     else {
    00770       UString s = x.toString(exec);
    00771
    00772       int errLine;
    00773       UString errMsg;
    00774 #ifdef KJS_VERBOSE
    00775       fprintf(stderr, "eval(): %s\n", s.ascii());
    00776 #endif
    00777       SourceCode *source;
    00778       FunctionBodyNode *progNode = Parser::parse(s.data(),s.size(),&source,&errLine,&errMsg);
    00779       if (progNode)
    00780     progNode->setProgram(true);
    00781
    00782       // notify debugger that source has been parsed
    00783       Debugger *dbg = exec->interpreter()->imp()->debugger();
    00784       if (dbg) {
    00785     bool cont = dbg->sourceParsed(exec,source->sid,s,errLine);
    00786     if (!cont) {
    00787       source->deref();
    00788       dbg->imp()->abort();
    00789       if (progNode)
    00790         delete progNode;
    00791       return Undefined();
    00792     }
    00793       }
    00794
    00795       exec->interpreter()->imp()->addSourceCode(source);
    00796
    00797       // no program node means a syntax occurred
    00798       if (!progNode) {
    00799     Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
    00800         err.put(exec,"sid",Number(source->sid));
    00801         exec->setException(err);
    00802     source->deref();
    00803         return err;
    00804       }
    00805
    00806       source->deref();
    00807       progNode->ref();
    00808
    00809       // enter a new execution context
    00810       ContextImp ctx(exec->interpreter()->globalObject(),
    00811                      exec->interpreter()->imp(),
    00812                      thisObj,
    00813                      source->sid,
    00814                      EvalCode,
    00815                      exec->context().imp());
    00816
    00817       ExecState newExec(exec->interpreter(), &ctx);
    00818       newExec.setException(exec->exception()); // could be null
    00819
    00820       ctx.setLines(progNode->firstLine(),progNode->firstLine());
    00821       if (dbg) {
    00822     if (!dbg->enterContext(&newExec)) {
    00823       // debugger requested we stop execution
    00824       dbg->imp()->abort();
    00825
    00826       if (progNode->deref())
    00827         delete progNode;
    00828       return Undefined();
    00829     }
    00830       }
    00831
    00832       // execute the code
    00833       Completion c = progNode->execute(&newExec);
    00834
    00835       res = Undefined();
    00836
    00837       ctx.setLines(progNode->lastLine(),progNode->lastLine());
    00838       if (dbg && !dbg->exitContext(&newExec,c))
    00839     // debugger requested we stop execution
    00840     dbg->imp()->abort();
    00841       else if (newExec.hadException()) // propagate back to parent context
    00842     exec->setException(newExec.exception());
    00843       else if (c.complType() == Throw)
    00844     exec->setException(c.value());
    00845       else if (c.isValueCompletion())
    00846     res = c.value();
    00847
    00848       if (progNode->deref())
    00849     delete progNode;
    00850
    00851       return res;
    00852     }
    00853     break;
    00854   }
    00855   case ParseInt: { // ECMA 15.1.2.2
    00856     CString cstr = args[0].toString(exec).cstring();
    00857     const char* startptr = cstr.c_str();
    00858     while ( *startptr && isspace( *startptr ) ) // first, skip leading spaces
    00859       ++startptr;
    00860
    00861     int base = 0;
    00862     if (args.size() > 1)
    00863       base = args[1].toInt32(exec);
    00864
    00865     double sign = 1;
    00866     if (*startptr == '-') {
    00867       sign = -1;
    00868       startptr++;
    00869     }
    00870     else if (*startptr == '+') {
    00871       sign = 1;
    00872       startptr++;
    00873     }
    00874
    00875     bool leading0 = false;
    00876     if ((base == 0 || base == 16) &&
    00877     (*startptr == '0' && (startptr[1] == 'x' || startptr[1] == 'X'))) {
    00878       startptr += 2;
    00879       base = 16;
    00880     }
    00881     else if (base == 0 && *startptr == '0') {
    00882       base = 8;
    00883       leading0 = true;
    00884       startptr++;
    00885     }
    00886     else if (base == 0) {
    00887       base = 10;
    00888     }
    00889
    00890     if (base < 2 || base > 36) {
    00891       res = Number(NaN);
    00892     }
    00893     else {
    00894       long double val = 0;
    00895       int index = 0;
    00896       for (; *startptr; startptr++) {
    00897     int thisval = -1;
    00898     if (*startptr >= '0' && *startptr <= '9')
    00899       thisval = *startptr - '0';
    00900     else if (*startptr >= 'a' && *startptr <= 'z')
    00901       thisval = 10 + *startptr - 'a';
    00902     else if (*startptr >= 'A' && *startptr <= 'Z')
    00903       thisval = 10 + *startptr - 'A';
    00904
    00905     if (thisval < 0 || thisval >= base)
    00906       break;
    00907
    00908     val *= base;
    00909     val += thisval;
    00910     index++;
    00911       }
    00912
    00913       if (index == 0 && !leading0)
    00914     res = Number(NaN);
    00915       else
    00916     res = Number(double(val)*sign);
    00917     }
    00918     break;
    00919   }
    00920   case ParseFloat: {
    00921     UString str = args[0].toString(exec);
    00922     // don't allow hex numbers here
    00923     bool isHex = false;
    00924     if (str.is8Bit()) {
    00925       const char *c = str.ascii();
    00926       while (isspace(*c))
    00927     c++;
    00928       isHex = (c[0] == '0' && (c[1] == 'x' || c[1] == 'X'));
    00929     }
    00930     if (isHex)
    00931       res = Number(0);
    00932     else
    00933       res = Number(str.toDouble( true /*tolerant*/, false ));
    00934     }
    00935     break;
    00936   case IsNaN:
    00937     res = Boolean(isNaN(args[0].toNumber(exec)));
    00938     break;
    00939   case IsFinite: {
    00940     double n = args[0].toNumber(exec);
    00941     res = Boolean(!isNaN(n) && !isInf(n));
    00942     break;
    00943   }
    00944   case DecodeURI:
    00945     res = String(decodeURI(exec,args[0].toString(exec),uriReserved+"#"));
    00946     break;
    00947   case DecodeURIComponent:
    00948     res = String(decodeURI(exec,args[0].toString(exec),""));
    00949     break;
    00950   case EncodeURI:
    00951     res = String(encodeURI(exec,args[0].toString(exec),uriReserved+uriUnescaped+"#"));
    00952     break;
    00953   case EncodeURIComponent:
    00954     res = String(encodeURI(exec,args[0].toString(exec),uriUnescaped));
    00955     break;
    00956   case Escape: {
    00957     UString r = "", s, str = args[0].toString(exec);
    00958     const UChar *c = str.data();
    00959     for (int k = 0; k < str.size(); k++, c++) {
    00960       int u = c->uc;
    00961       if (u > 255) {
    00962     char tmp[7];
    00963     sprintf(tmp, "%%u%04X", u);
    00964     s = UString(tmp);
    00965       } else if (u != 0 && strchr(do_not_escape, (char)u)) {
    00966     s = UString(c, 1);
    00967       } else {
    00968     char tmp[4];
    00969     sprintf(tmp, "%%%02X", u);
    00970     s = UString(tmp);
    00971       }
    00972       r += s;
    00973     }
    00974     res = String(r);
    00975     break;
    00976   }
    00977   case UnEscape: {
    00978     UString s = "", str = args[0].toString(exec);
    00979     int k = 0, len = str.size();
    00980     while (k < len) {
    00981       const UChar *c = str.data() + k;
    00982       UChar u;
    00983       if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
    00984     if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
    00985         Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
    00986       u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
    00987                     (c+4)->uc, (c+5)->uc);
    00988       c = &u;
    00989       k += 5;
    00990     }
    00991       } else if (*c == UChar('%') && k <= len - 3 &&
    00992          Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
    00993     u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
    00994     c = &u;
    00995     k += 2;
    00996       }
    00997       k++;
    00998       s += UString(c, 1);
    00999     }
    01000     res = String(s);
    01001     break;
    01002   }
    01003   case KJSPrint:
    01004 #ifndef NDEBUG
    01005     puts(args[0].toString(exec).ascii());
    01006 #endif
    01007     break;
    01008   }
    01009
    01010   return res;
    01011 }

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