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