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