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