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