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