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 < 0x80) 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 = ¶m; 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 }