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._exception = 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->_exception = 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->_exception = 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 non_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 00759 "abcdefghijklmnopqrstuvwxyz" 00760 "0123456789@*_+-./"; 00761 00762 switch (id) { 00763 case Eval: { // eval() 00764 Value x = args[0]; 00765 if (x.type() != StringType) 00766 return x; 00767 else { 00768 UString s = x.toString(exec); 00769 00770 int errLine; 00771 UString errMsg; 00772 #ifdef KJS_VERBOSE 00773 fprintf(stderr, "eval(): %s\n", s.ascii()); 00774 #endif 00775 SourceCode *source; 00776 FunctionBodyNode *progNode = Parser::parse(s.data(),s.size(),&source,&errLine,&errMsg); 00777 if (progNode) 00778 progNode->setProgram(true); 00779 00780 // notify debugger that source has been parsed 00781 Debugger *dbg = exec->interpreter()->imp()->debugger(); 00782 if (dbg) { 00783 bool cont = dbg->sourceParsed(exec,source->sid,s,errLine); 00784 if (!cont) { 00785 source->deref(); 00786 dbg->imp()->abort(); 00787 if (progNode) 00788 delete progNode; 00789 return Undefined(); 00790 } 00791 } 00792 00793 exec->interpreter()->imp()->addSourceCode(source); 00794 00795 // no program node means a syntax occurred 00796 if (!progNode) { 00797 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine); 00798 err.put(exec,"sid",Number(source->sid)); 00799 exec->setException(err); 00800 source->deref(); 00801 return err; 00802 } 00803 00804 source->deref(); 00805 progNode->ref(); 00806 00807 // enter a new execution context 00808 ContextImp ctx(exec->interpreter()->globalObject(), 00809 exec->interpreter()->imp(), 00810 thisObj, 00811 source->sid, 00812 EvalCode, 00813 exec->context().imp()); 00814 00815 ExecState newExec(exec->interpreter(), &ctx); 00816 newExec.setException(exec->exception()); // could be null 00817 00818 ctx.setLines(progNode->firstLine(),progNode->firstLine()); 00819 if (dbg) { 00820 if (!dbg->enterContext(&newExec)) { 00821 // debugger requested we stop execution 00822 dbg->imp()->abort(); 00823 00824 if (progNode->deref()) 00825 delete progNode; 00826 return Undefined(); 00827 } 00828 } 00829 00830 // execute the code 00831 Completion c = progNode->execute(&newExec); 00832 00833 res = Undefined(); 00834 00835 ctx.setLines(progNode->lastLine(),progNode->lastLine()); 00836 if (dbg && !dbg->exitContext(&newExec,c)) 00837 // debugger requested we stop execution 00838 dbg->imp()->abort(); 00839 else if (newExec.hadException()) // propagate back to parent context 00840 exec->_exception = newExec.exception(); 00841 else if (c.complType() == Throw) 00842 exec->setException(c.value()); 00843 else if (c.isValueCompletion()) 00844 res = c.value(); 00845 00846 if (progNode->deref()) 00847 delete progNode; 00848 00849 return res; 00850 } 00851 break; 00852 } 00853 case ParseInt: { // ECMA 15.1.2.2 00854 CString cstr = args[0].toString(exec).cstring(); 00855 const char* startptr = cstr.c_str(); 00856 while ( *startptr && isspace( *startptr ) ) // first, skip leading spaces 00857 ++startptr; 00858 00859 int base = 0; 00860 if (args.size() > 1) 00861 base = args[1].toInt32(exec); 00862 00863 double sign = 1; 00864 if (*startptr == '-') { 00865 sign = -1; 00866 startptr++; 00867 } 00868 else if (*startptr == '+') { 00869 sign = 1; 00870 startptr++; 00871 } 00872 00873 bool leading0 = false; 00874 if ((base == 0 || base == 16) && 00875 (*startptr == '0' && (startptr[1] == 'x' || startptr[1] == 'X'))) { 00876 startptr += 2; 00877 base = 16; 00878 } 00879 else if (base == 0 && *startptr == '0') { 00880 base = 8; 00881 leading0 = true; 00882 startptr++; 00883 } 00884 else if (base == 0) { 00885 base = 10; 00886 } 00887 00888 if (base < 2 || base > 36) { 00889 res = Number(NaN); 00890 } 00891 else { 00892 long double val = 0; 00893 int index = 0; 00894 for (; *startptr; startptr++) { 00895 int thisval = -1; 00896 if (*startptr >= '0' && *startptr <= '9') 00897 thisval = *startptr - '0'; 00898 else if (*startptr >= 'a' && *startptr <= 'z') 00899 thisval = 10 + *startptr - 'a'; 00900 else if (*startptr >= 'A' && *startptr <= 'Z') 00901 thisval = 10 + *startptr - 'A'; 00902 00903 if (thisval < 0 || thisval >= base) 00904 break; 00905 00906 val *= base; 00907 val += thisval; 00908 index++; 00909 } 00910 00911 if (index == 0 && !leading0) 00912 res = Number(NaN); 00913 else 00914 res = Number(double(val)*sign); 00915 } 00916 break; 00917 } 00918 case ParseFloat: { 00919 UString str = args[0].toString(exec); 00920 // don't allow hex numbers here 00921 bool isHex = false; 00922 if (str.is8Bit()) { 00923 const char *c = str.ascii(); 00924 while (isspace(*c)) 00925 c++; 00926 isHex = (c[0] == '0' && (c[1] == 'x' || c[1] == 'X')); 00927 } 00928 if (isHex) 00929 res = Number(0); 00930 else 00931 res = Number(str.toDouble( true /*tolerant*/, false )); 00932 } 00933 break; 00934 case IsNaN: 00935 res = Boolean(isNaN(args[0].toNumber(exec))); 00936 break; 00937 case IsFinite: { 00938 double n = args[0].toNumber(exec); 00939 res = Boolean(!isNaN(n) && !isInf(n)); 00940 break; 00941 } 00942 case DecodeURI: 00943 res = String(decodeURI(exec,args[0].toString(exec),uriReserved+"#")); 00944 break; 00945 case DecodeURIComponent: 00946 res = String(decodeURI(exec,args[0].toString(exec),"")); 00947 break; 00948 case EncodeURI: 00949 res = String(encodeURI(exec,args[0].toString(exec),uriReserved+uriUnescaped+"#")); 00950 break; 00951 case EncodeURIComponent: 00952 res = String(encodeURI(exec,args[0].toString(exec),uriUnescaped)); 00953 break; 00954 case Escape: { 00955 UString r = "", s, str = args[0].toString(exec); 00956 const UChar *c = str.data(); 00957 for (int k = 0; k < str.size(); k++, c++) { 00958 int u = c->uc; 00959 if (u > 255) { 00960 char tmp[7]; 00961 sprintf(tmp, "%%u%04X", u); 00962 s = UString(tmp); 00963 } else if (strchr(non_escape, (char)u)) { 00964 s = UString(c, 1); 00965 } else { 00966 char tmp[4]; 00967 sprintf(tmp, "%%%02X", u); 00968 s = UString(tmp); 00969 } 00970 r += s; 00971 } 00972 res = String(r); 00973 break; 00974 } 00975 case UnEscape: { 00976 UString s, str = args[0].toString(exec); 00977 int k = 0, len = str.size(); 00978 while (k < len) { 00979 const UChar *c = str.data() + k; 00980 UChar u; 00981 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) { 00982 if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) && 00983 Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) { 00984 u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc, 00985 (c+4)->uc, (c+5)->uc); 00986 c = &u; 00987 k += 5; 00988 } 00989 } else if (*c == UChar('%') && k <= len - 3 && 00990 Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) { 00991 u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc)); 00992 c = &u; 00993 k += 2; 00994 } 00995 k++; 00996 s += UString(c, 1); 00997 } 00998 res = String(s); 00999 break; 01000 } 01001 case KJSPrint: { 01002 #ifndef NDEBUG 01003 UString str = args[0].toString(exec); 01004 puts(str.ascii()); 01005 #endif 01006 break; 01007 } 01008 } 01009 01010 return res; 01011 }
KDE Logo
This file is part of the documentation for kjs Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:18:51 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003