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