e33f8ee274acac2ac2fa3ed3e0685e2f28d59461
[WebKit-https.git] / JavaScriptCore / kjs / function.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
5  *  Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
7  *  Copyright (C) 2007 Maks Orlovich
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Library General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Library General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Library General Public License
20  *  along with this library; see the file COPYING.LIB.  If not, write to
21  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "function.h"
28
29 #include "Activation.h"
30 #include "ExecState.h"
31 #include "JSGlobalObject.h"
32 #include "Parser.h"
33 #include "PropertyNameArray.h"
34 #include "debugger.h"
35 #include "dtoa.h"
36 #include "function_object.h"
37 #include "internal.h"
38 #include "lexer.h"
39 #include "nodes.h"
40 #include "operations.h"
41 #include "scope_chain_mark.h"
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <wtf/ASCIICType.h>
47 #include <wtf/Assertions.h>
48 #include <wtf/MathExtras.h>
49 #include <wtf/unicode/UTF8.h>
50
51 using namespace WTF;
52 using namespace Unicode;
53
54 namespace KJS {
55
56 // ----------------------------- FunctionImp ----------------------------------
57
58 const ClassInfo FunctionImp::info = { "Function", &InternalFunctionImp::info, 0 };
59
60 FunctionImp::FunctionImp(ExecState* exec, const Identifier& name, FunctionBodyNode* b, const ScopeChain& sc)
61   : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name)
62   , body(b)
63   , _scope(sc)
64 {
65 }
66
67 void FunctionImp::mark()
68 {
69     InternalFunctionImp::mark();
70     _scope.mark();
71 }
72
73 JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
74 {
75     ExecState newExec(exec->dynamicGlobalObject(), thisObj, body.get(), exec, this, args);
76     JSValue* result = body->execute(&newExec);
77     if (newExec.completionType() == Throw) {
78         exec->setException(result);
79         return result;
80     }
81     if (newExec.completionType() == ReturnValue)
82         return result;
83     return jsUndefined();
84 }
85
86 JSValue* FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
87 {
88   FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
89   
90   for (ExecState* e = exec; e; e = e->callingExecState())
91     if (e->function() == thisObj) {
92       e->dynamicGlobalObject()->tearOffActivation(e, e != exec);
93       return e->activationObject()->get(exec, propertyName);
94     }
95   
96   return jsNull();
97 }
98
99 JSValue* FunctionImp::callerGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
100 {
101     FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
102     ExecState* e = exec;
103     while (e) {
104         if (e->function() == thisObj)
105             break;
106         e = e->callingExecState();
107     }
108
109     if (!e)
110         return jsNull();
111     
112     ExecState* callingExecState = e->callingExecState();
113     if (!callingExecState)
114         return jsNull();
115     
116     FunctionImp* callingFunction = callingExecState->function();
117     if (!callingFunction)
118         return jsNull();
119
120     return callingFunction;
121 }
122
123 JSValue* FunctionImp::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
124 {
125     FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
126     return jsNumber(thisObj->body->parameters().size());
127 }
128
129 bool FunctionImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
130 {
131     // Find the arguments from the closest context.
132     if (propertyName == exec->propertyNames().arguments) {
133         slot.setCustom(this, argumentsGetter);
134         return true;
135     }
136
137     // Compute length of parameters.
138     if (propertyName == exec->propertyNames().length) {
139         slot.setCustom(this, lengthGetter);
140         return true;
141     }
142
143     if (propertyName == exec->propertyNames().caller) {
144         slot.setCustom(this, callerGetter);
145         return true;
146     }
147
148     return InternalFunctionImp::getOwnPropertySlot(exec, propertyName, slot);
149 }
150
151 void FunctionImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
152 {
153     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
154         return;
155     InternalFunctionImp::put(exec, propertyName, value, attr);
156 }
157
158 bool FunctionImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
159 {
160     if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
161         return false;
162     return InternalFunctionImp::deleteProperty(exec, propertyName);
163 }
164
165 /* Returns the parameter name corresponding to the given index. eg:
166  * function f1(x, y, z): getParameterName(0) --> x
167  *
168  * If a name appears more than once, only the last index at which
169  * it appears associates with it. eg:
170  * function f2(x, x): getParameterName(0) --> null
171  */
172 Identifier FunctionImp::getParameterName(int index)
173 {
174     Vector<Identifier>& parameters = body->parameters();
175
176     if (static_cast<size_t>(index) >= body->parameters().size())
177         return CommonIdentifiers::shared()->nullIdentifier;
178   
179     Identifier name = parameters[index];
180
181     // Are there any subsequent parameters with the same name?
182     size_t size = parameters.size();
183     for (size_t i = index + 1; i < size; ++i)
184         if (parameters[i] == name)
185             return CommonIdentifiers::shared()->nullIdentifier;
186
187     return name;
188 }
189
190 // ECMA 13.2.2 [[Construct]]
191 JSObject* FunctionImp::construct(ExecState* exec, const List& args)
192 {
193   JSObject* proto;
194   JSValue* p = get(exec, exec->propertyNames().prototype);
195   if (p->isObject())
196     proto = static_cast<JSObject*>(p);
197   else
198     proto = exec->lexicalGlobalObject()->objectPrototype();
199
200   JSObject* obj(new JSObject(proto));
201
202   JSValue* res = call(exec,obj,args);
203
204   if (res->isObject())
205     return static_cast<JSObject*>(res);
206   else
207     return obj;
208 }
209
210 // ------------------------------ IndexToNameMap ---------------------------------
211
212 // We map indexes in the arguments array to their corresponding argument names. 
213 // Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x"). 
214
215 // Once we have an argument name, we can get and set the argument's value in the 
216 // activation object.
217
218 // We use Identifier::null to indicate that a given argument's value
219 // isn't stored in the activation object.
220
221 IndexToNameMap::IndexToNameMap(FunctionImp* func, const List& args)
222 {
223   _map = new Identifier[args.size()];
224   this->size = args.size();
225   
226   int i = 0;
227   List::const_iterator end = args.end();
228   for (List::const_iterator it = args.begin(); it != end; ++i, ++it)
229     _map[i] = func->getParameterName(i); // null if there is no corresponding parameter
230 }
231
232 IndexToNameMap::~IndexToNameMap() {
233   delete [] _map;
234 }
235
236 bool IndexToNameMap::isMapped(const Identifier& index) const
237 {
238   bool indexIsNumber;
239   int indexAsNumber = index.toUInt32(&indexIsNumber);
240   
241   if (!indexIsNumber)
242     return false;
243   
244   if (indexAsNumber >= size)
245     return false;
246
247   if (_map[indexAsNumber].isNull())
248     return false;
249   
250   return true;
251 }
252
253 void IndexToNameMap::unMap(const Identifier& index)
254 {
255   bool indexIsNumber;
256   int indexAsNumber = index.toUInt32(&indexIsNumber);
257
258   ASSERT(indexIsNumber && indexAsNumber < size);
259   
260   _map[indexAsNumber] = CommonIdentifiers::shared()->nullIdentifier;
261 }
262
263 Identifier& IndexToNameMap::operator[](int index)
264 {
265   return _map[index];
266 }
267
268 Identifier& IndexToNameMap::operator[](const Identifier& index)
269 {
270   bool indexIsNumber;
271   int indexAsNumber = index.toUInt32(&indexIsNumber);
272
273   ASSERT(indexIsNumber && indexAsNumber < size);
274   
275   return (*this)[indexAsNumber];
276 }
277
278 // ------------------------------ Arguments ---------------------------------
279
280 const ClassInfo Arguments::info = { "Arguments", 0, 0 };
281
282 // ECMA 10.1.8
283 Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act)
284 : JSObject(exec->lexicalGlobalObject()->objectPrototype()), 
285 _activationObject(act),
286 indexToNameMap(func, args)
287 {
288   putDirect(exec->propertyNames().callee, func, DontEnum);
289   putDirect(exec->propertyNames().length, args.size(), DontEnum);
290   
291   int i = 0;
292   List::const_iterator end = args.end();
293   for (List::const_iterator it = args.begin(); it != end; ++it, ++i) {
294     if (!indexToNameMap.isMapped(Identifier::from(i))) {
295       JSObject::put(exec, Identifier::from(i), *it, DontEnum);
296     }
297   }
298 }
299
300 void Arguments::mark() 
301 {
302   JSObject::mark();
303   if (_activationObject && !_activationObject->marked())
304     _activationObject->mark();
305 }
306
307 JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
308 {
309   Arguments* thisObj = static_cast<Arguments*>(slot.slotBase());
310   return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]);
311 }
312
313 bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
314 {
315   if (indexToNameMap.isMapped(propertyName)) {
316     slot.setCustom(this, mappedIndexGetter);
317     return true;
318   }
319
320   return JSObject::getOwnPropertySlot(exec, propertyName, slot);
321 }
322
323 void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
324 {
325   if (indexToNameMap.isMapped(propertyName)) {
326     _activationObject->put(exec, indexToNameMap[propertyName], value, attr);
327   } else {
328     JSObject::put(exec, propertyName, value, attr);
329   }
330 }
331
332 bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName) 
333 {
334   if (indexToNameMap.isMapped(propertyName)) {
335     indexToNameMap.unMap(propertyName);
336     return true;
337   } else {
338     return JSObject::deleteProperty(exec, propertyName);
339   }
340 }
341
342 // ------------------------------ ActivationImp --------------------------------
343
344 const ClassInfo ActivationImp::info = { "Activation", 0, 0 };
345
346 ActivationImp::ActivationImp(const ActivationData& oldData, bool leaveRelic)
347 {
348     JSVariableObject::d = new ActivationData(oldData);
349     d()->leftRelic = leaveRelic;
350 }
351
352 ActivationImp::~ActivationImp()
353 {
354     if (!d()->isOnStack)
355         delete d();
356 }
357
358 void ActivationImp::init(ExecState* exec)
359 {
360     d()->symbolTable = &exec->function()->body->symbolTable();
361     d()->exec = exec;
362     d()->function = exec->function();
363     d()->argumentsObject = 0;
364 }
365
366 JSValue* ActivationImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
367 {
368   ActivationImp* thisObj = static_cast<ActivationImp*>(slot.slotBase());
369   
370   if (!thisObj->d()->argumentsObject)
371     thisObj->createArgumentsObject(exec);
372   
373   return thisObj->d()->argumentsObject;
374 }
375
376 PropertySlot::GetValueFunc ActivationImp::getArgumentsGetter()
377 {
378   return ActivationImp::argumentsGetter;
379 }
380
381 bool ActivationImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
382 {
383     if (symbolTableGet(propertyName, slot))
384         return true;
385
386     if (JSValue** location = getDirectLocation(propertyName)) {
387         slot.setValueSlot(this, location);
388         return true;
389     }
390
391     // Only return the built-in arguments object if it wasn't overridden above.
392     if (propertyName == exec->propertyNames().arguments) {
393         for (ExecState* e = exec; e; e = e->callingExecState())
394             if (e->function() == d()->function) {
395                 e->dynamicGlobalObject()->tearOffActivation(e, e != exec);
396                 ActivationImp* newActivation = e->activationObject();
397                 slot.setCustom(newActivation, newActivation->getArgumentsGetter());
398                 return true;
399             }
400         
401         slot.setCustom(this, getArgumentsGetter());
402         return true;
403     }
404
405     // We don't call through to JSObject because there's no way to give an 
406     // activation object getter properties or a prototype.
407     ASSERT(!_prop.hasGetterSetterProperties());
408     ASSERT(prototype() == jsNull());
409     return false;
410 }
411
412 bool ActivationImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
413 {
414     if (propertyName == exec->propertyNames().arguments)
415         return false;
416
417     return JSVariableObject::deleteProperty(exec, propertyName);
418 }
419
420 void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value, int attr)
421 {
422     if (symbolTablePut(propertyName, value, attr))
423         return;
424
425     // We don't call through to JSObject because __proto__ and getter/setter 
426     // properties are non-standard extensions that other implementations do not
427     // expose in the activation object.
428     ASSERT(!_prop.hasGetterSetterProperties());
429     _prop.put(propertyName, value, attr, (attr == None || attr == DontDelete));
430 }
431
432 void ActivationImp::markChildren()
433 {
434     LocalStorage& localStorage = d()->localStorage;
435     size_t size = localStorage.size();
436     
437     for (size_t i = 0; i < size; ++i) {
438         JSValue* value = localStorage[i].value;
439         
440         if (!value->marked())
441             value->mark();
442     }
443     
444     if (!d()->function->marked())
445         d()->function->mark();
446     
447     if (d()->argumentsObject && !d()->argumentsObject->marked())
448         d()->argumentsObject->mark();    
449 }
450
451 void ActivationImp::mark()
452 {
453     JSObject::mark();
454     markChildren();
455 }
456
457 void ActivationImp::createArgumentsObject(ExecState* exec)
458 {
459     // Since "arguments" is only accessible while a function is being called,
460     // we can retrieve our argument list from the ExecState for our function 
461     // call instead of storing the list ourselves.
462     d()->argumentsObject = new Arguments(exec, d()->exec->function(), *d()->exec->arguments(), this);
463 }
464
465 ActivationImp::ActivationData::ActivationData(const ActivationData& old)
466     : JSVariableObjectData(old)
467     , exec(old.exec)
468     , function(old.function)
469     , argumentsObject(old.argumentsObject)
470     , isOnStack(false)
471 {
472 }
473
474 // ------------------------------ GlobalFunc -----------------------------------
475
476
477 GlobalFuncImp::GlobalFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
478   : InternalFunctionImp(funcProto, name)
479   , id(i)
480 {
481   putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
482 }
483
484 static JSValue* encode(ExecState* exec, const List& args, const char* do_not_escape)
485 {
486   UString r = "", s, str = args[0]->toString(exec);
487   CString cstr = str.UTF8String(true);
488   if (!cstr.c_str())
489     return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
490   const char* p = cstr.c_str();
491   for (size_t k = 0; k < cstr.size(); k++, p++) {
492     char c = *p;
493     if (c && strchr(do_not_escape, c)) {
494       r.append(c);
495     } else {
496       char tmp[4];
497       sprintf(tmp, "%%%02X", (unsigned char)c);
498       r += tmp;
499     }
500   }
501   return jsString(r);
502 }
503
504 static JSValue* decode(ExecState* exec, const List& args, const char* do_not_unescape, bool strict)
505 {
506   UString s = "", str = args[0]->toString(exec);
507   int k = 0, len = str.size();
508   const UChar* d = str.data();
509   UChar u;
510   while (k < len) {
511     const UChar* p = d + k;
512     UChar c = *p;
513     if (c == '%') {
514       int charLen = 0;
515       if (k <= len - 3 && isASCIIHexDigit(p[1].uc) && isASCIIHexDigit(p[2].uc)) {
516         const char b0 = Lexer::convertHex(p[1].uc, p[2].uc);
517         const int sequenceLen = UTF8SequenceLength(b0);
518         if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
519           charLen = sequenceLen * 3;
520           char sequence[5];
521           sequence[0] = b0;
522           for (int i = 1; i < sequenceLen; ++i) {
523             const UChar* q = p + i * 3;
524             if (q[0] == '%' && isASCIIHexDigit(q[1].uc) && isASCIIHexDigit(q[2].uc))
525               sequence[i] = Lexer::convertHex(q[1].uc, q[2].uc);
526             else {
527               charLen = 0;
528               break;
529             }
530           }
531           if (charLen != 0) {
532             sequence[sequenceLen] = 0;
533             const int character = decodeUTF8Sequence(sequence);
534             if (character < 0 || character >= 0x110000) {
535               charLen = 0;
536             } else if (character >= 0x10000) {
537               // Convert to surrogate pair.
538               s.append(static_cast<unsigned short>(0xD800 | ((character - 0x10000) >> 10)));
539               u = static_cast<unsigned short>(0xDC00 | ((character - 0x10000) & 0x3FF));
540             } else {
541               u = static_cast<unsigned short>(character);
542             }
543           }
544         }
545       }
546       if (charLen == 0) {
547         if (strict)
548           return throwError(exec, URIError);
549         // The only case where we don't use "strict" mode is the "unescape" function.
550         // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
551         if (k <= len - 6 && p[1] == 'u'
552             && isASCIIHexDigit(p[2].uc) && isASCIIHexDigit(p[3].uc)
553             && isASCIIHexDigit(p[4].uc) && isASCIIHexDigit(p[5].uc)) {
554           charLen = 6;
555           u = Lexer::convertUnicode(p[2].uc, p[3].uc, p[4].uc, p[5].uc);
556         }
557       }
558       if (charLen && (u.uc == 0 || u.uc >= 128 || !strchr(do_not_unescape, u.low()))) {
559         c = u;
560         k += charLen - 1;
561       }
562     }
563     k++;
564     s.append(c);
565   }
566   return jsString(s);
567 }
568
569 static bool isStrWhiteSpace(unsigned short c)
570 {
571     switch (c) {
572         case 0x0009:
573         case 0x000A:
574         case 0x000B:
575         case 0x000C:
576         case 0x000D:
577         case 0x0020:
578         case 0x00A0:
579         case 0x2028:
580         case 0x2029:
581             return true;
582         default:
583             return isSeparatorSpace(c);
584     }
585 }
586
587 static int parseDigit(unsigned short c, int radix)
588 {
589     int digit = -1;
590
591     if (c >= '0' && c <= '9') {
592         digit = c - '0';
593     } else if (c >= 'A' && c <= 'Z') {
594         digit = c - 'A' + 10;
595     } else if (c >= 'a' && c <= 'z') {
596         digit = c - 'a' + 10;
597     }
598
599     if (digit >= radix)
600         return -1;
601     return digit;
602 }
603
604 double parseIntOverflow(const char* s, int length, int radix)
605 {
606     double number = 0.0;
607     double radixMultiplier = 1.0;
608
609     for (const char* p = s + length - 1; p >= s; p--) {
610         if (radixMultiplier == Inf) {
611             if (*p != '0') {
612                 number = Inf;
613                 break;
614             }
615         } else {
616             int digit = parseDigit(*p, radix);
617             number += digit * radixMultiplier;
618         }
619
620         radixMultiplier *= radix;
621     }
622
623     return number;
624 }
625
626 static double parseInt(const UString& s, int radix)
627 {
628     int length = s.size();
629     int p = 0;
630
631     while (p < length && isStrWhiteSpace(s[p].uc)) {
632         ++p;
633     }
634
635     double sign = 1;
636     if (p < length) {
637         if (s[p] == '+') {
638             ++p;
639         } else if (s[p] == '-') {
640             sign = -1;
641             ++p;
642         }
643     }
644
645     if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
646         radix = 16;
647         p += 2;
648     } else if (radix == 0) {
649         if (p < length && s[p] == '0')
650             radix = 8;
651         else
652             radix = 10;
653     }
654
655     if (radix < 2 || radix > 36)
656         return NaN;
657
658     int firstDigitPosition = p;
659     bool sawDigit = false;
660     double number = 0;
661     while (p < length) {
662         int digit = parseDigit(s[p].uc, radix);
663         if (digit == -1)
664             break;
665         sawDigit = true;
666         number *= radix;
667         number += digit;
668         ++p;
669     }
670
671     if (number >= mantissaOverflowLowerBound) {
672         if (radix == 10)
673             number = kjs_strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0);
674         else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
675             number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix);
676     }
677
678     if (!sawDigit)
679         return NaN;
680
681     return sign * number;
682 }
683
684 static double parseFloat(const UString& s)
685 {
686     // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
687     // Need to skip any whitespace and then one + or - sign.
688     int length = s.size();
689     int p = 0;
690     while (p < length && isStrWhiteSpace(s[p].uc)) {
691         ++p;
692     }
693     if (p < length && (s[p] == '+' || s[p] == '-')) {
694         ++p;
695     }
696     if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
697         return 0;
698     }
699
700     return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ );
701 }
702
703 JSValue* GlobalFuncImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
704 {
705   JSValue* res = jsUndefined();
706
707   static const char do_not_escape[] =
708     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
709     "abcdefghijklmnopqrstuvwxyz"
710     "0123456789"
711     "*+-./@_";
712
713   static const char do_not_escape_when_encoding_URI_component[] =
714     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
715     "abcdefghijklmnopqrstuvwxyz"
716     "0123456789"
717     "!'()*-._~";
718   static const char do_not_escape_when_encoding_URI[] =
719     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
720     "abcdefghijklmnopqrstuvwxyz"
721     "0123456789"
722     "!#$&'()*+,-./:;=?@_~";
723   static const char do_not_unescape_when_decoding_URI[] =
724     "#$&+,/:;=?@";
725
726   switch (id) {
727     case Eval: { // eval()
728       JSValue* x = args[0];
729       if (!x->isString())
730         return x;
731       else {
732         UString s = x->toString(exec);
733         
734         int sourceId;
735         int errLine;
736         UString errMsg;
737         RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg);
738
739         Debugger* dbg = exec->dynamicGlobalObject()->debugger();
740         if (dbg) {
741           bool cont = dbg->sourceParsed(exec, sourceId, UString(), s, 0, errLine, errMsg);
742           if (!cont)
743             return jsUndefined();
744         }
745
746         // no program node means a syntax occurred
747         if (!evalNode)
748           return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
749
750         bool switchGlobal = thisObj && thisObj != exec->dynamicGlobalObject() && thisObj->isGlobalObject();
751
752         // enter a new execution context
753         exec->dynamicGlobalObject()->tearOffActivation(exec);
754         JSGlobalObject* globalObject = switchGlobal ? static_cast<JSGlobalObject*>(thisObj) : exec->dynamicGlobalObject();
755         ExecState newExec(globalObject, evalNode.get(), exec);
756           
757         if (switchGlobal) {
758             newExec.pushScope(thisObj);
759             newExec.setVariableObject(static_cast<JSGlobalObject*>(thisObj));
760         }
761         JSValue* value = evalNode->execute(&newExec);
762         if (switchGlobal)
763             newExec.popScope();
764
765         if (newExec.completionType() == Throw) {
766             exec->setException(value);
767             return value;
768         }
769         return value ? value : jsUndefined();
770       }
771     }
772   case ParseInt:
773     res = jsNumber(parseInt(args[0]->toString(exec), args[1]->toInt32(exec)));
774     break;
775   case ParseFloat:
776     res = jsNumber(parseFloat(args[0]->toString(exec)));
777     break;
778   case IsNaN:
779     res = jsBoolean(isnan(args[0]->toNumber(exec)));
780     break;
781   case IsFinite: {
782     double n = args[0]->toNumber(exec);
783     res = jsBoolean(!isnan(n) && !isinf(n));
784     break;
785   }
786   case DecodeURI:
787     res = decode(exec, args, do_not_unescape_when_decoding_URI, true);
788     break;
789   case DecodeURIComponent:
790     res = decode(exec, args, "", true);
791     break;
792   case EncodeURI:
793     res = encode(exec, args, do_not_escape_when_encoding_URI);
794     break;
795   case EncodeURIComponent:
796     res = encode(exec, args, do_not_escape_when_encoding_URI_component);
797     break;
798   case Escape:
799     {
800       UString r = "", s, str = args[0]->toString(exec);
801       const UChar* c = str.data();
802       for (int k = 0; k < str.size(); k++, c++) {
803         int u = c->uc;
804         if (u > 255) {
805           char tmp[7];
806           sprintf(tmp, "%%u%04X", u);
807           s = UString(tmp);
808         } else if (u != 0 && strchr(do_not_escape, (char)u)) {
809           s = UString(c, 1);
810         } else {
811           char tmp[4];
812           sprintf(tmp, "%%%02X", u);
813           s = UString(tmp);
814         }
815         r += s;
816       }
817       res = jsString(r);
818       break;
819     }
820   case UnEscape:
821     {
822       UString s = "", str = args[0]->toString(exec);
823       int k = 0, len = str.size();
824       while (k < len) {
825         const UChar* c = str.data() + k;
826         UChar u;
827         if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
828           if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
829               Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
830           u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
831                                     (c+4)->uc, (c+5)->uc);
832           c = &u;
833           k += 5;
834           }
835         } else if (*c == UChar('%') && k <= len - 3 &&
836                    Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
837           u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
838           c = &u;
839           k += 2;
840         }
841         k++;
842         s += UString(c, 1);
843       }
844       res = jsString(s);
845       break;
846     }
847 #ifndef NDEBUG
848   case KJSPrint:
849     puts(args[0]->toString(exec).ascii());
850     break;
851 #endif
852   }
853
854   return res;
855 }
856
857 // ------------------------------ PrototypeFunction -------------------------------
858
859 PrototypeFunction::PrototypeFunction(ExecState* exec, int len, const Identifier& name, JSMemberFunction function)
860     : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name)
861     , m_function(function)
862 {
863     ASSERT_ARG(function, function);
864     put(exec, exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum);
865 }
866
867 JSValue* PrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
868 {
869     return m_function(exec, thisObj, args);
870 }
871
872 } // namespace KJS