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