kjs Library API Documentation

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 }
KDE Logo
This file is part of the documentation for kjs Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 15 10:34:09 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003